Skip to content

Commit c4fad5f

Browse files
committed
fixed all issues
1 parent 4799a2b commit c4fad5f

File tree

5 files changed

+47
-29
lines changed

5 files changed

+47
-29
lines changed

.rubocop.yml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ AllCops:
1818
- sorbet/rbi/dsl/**/*
1919
- sorbet/rbi/gems/**/*
2020
- sorbet/rbi/annotations/**/*
21+
- rails_test_app/logstruct_test_app/bin/**/*
2122

2223
Layout/MultilineHashKeyLineBreaks:
2324
Enabled: true
@@ -40,6 +41,8 @@ Rails/Output:
4041
Enabled: false
4142
Rails/NegateInclude:
4243
Enabled: false
44+
Rails/RefuteMethods:
45+
Enabled: false
4346

4447
Performance/OpenStruct:
4548
Exclude:

site/app/page.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -136,8 +136,8 @@ export default function Home() {
136136
<h3 className="text-xl font-semibold">Type-safe with Sorbet</h3>
137137
</div>
138138
<p className="text-neutral-600 dark:text-neutral-400">
139-
LogStruct is fully type-checked with Sorbet so your logs are
140-
always structured correctly and have the right data.
139+
LogStruct is fully type-checked with Sorbet. Your logs are
140+
guaranteed to have the correct structure and valid data.
141141
</p>
142142
</div>
143143
<div className="rounded-lg border border-neutral-200 p-6 dark:border-neutral-800">

site/lib/log-generation/log-generator.ts

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -211,8 +211,8 @@ export class LogGenerator extends RandomDataGenerator {
211211
private generateActiveJobLog(
212212
log: Partial<ActiveJobLog>,
213213
): Partial<ActiveJobLog> {
214-
// Add specific fields for ActiveJobLog
215-
const jobLog: Partial<ActiveJobLog> = {
214+
// Create the basic job log without duration
215+
const baseJobLog: Partial<ActiveJobLog> = {
216216
...log,
217217
job_id: this.randomHex(8),
218218
job_class: this.sample(SampleData.JOB_CLASSES),
@@ -223,14 +223,18 @@ export class LogGenerator extends RandomDataGenerator {
223223
this.randomInt(1, 100),
224224
{ action: this.sample(['create', 'update', 'process']) },
225225
],
226-
// Only set duration if it's a FINISH event
227-
duration: log.event === LogEvent.FINISH ? this.randomDuration() : 0,
228226
data: {
229227
retries: this.randomInt(0, 3),
230228
scheduled_at: this.randomTimestamp(),
231229
},
232230
};
233231

232+
// Only add duration if it's a FINISH event
233+
const jobLog: Partial<ActiveJobLog> =
234+
log.event === LogEvent.FINISH
235+
? { ...baseJobLog, duration: this.randomDuration() }
236+
: baseJobLog;
237+
234238
return jobLog;
235239
}
236240

@@ -437,7 +441,6 @@ export class LogGenerator extends RandomDataGenerator {
437441
job_class: jobClass,
438442
queue_name: queueName,
439443
arguments: args,
440-
duration: 0,
441444
data,
442445
};
443446

@@ -455,7 +458,6 @@ export class LogGenerator extends RandomDataGenerator {
455458
job_class: jobClass,
456459
queue_name: queueName,
457460
arguments: args,
458-
duration: 0,
459461
data,
460462
};
461463

test/tools/log_types_exporter_test.rb

Lines changed: 23 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -184,6 +184,7 @@ def test_security_log_event_union_type
184184
# Verify we extracted the correct enum values - sort both arrays to avoid order issues
185185
expected_values = ["IPSpoof", "CSRFViolation", "BlockedHost"].sort
186186
extracted_values = type_info[:enum_values].sort
187+
187188
assert_equal expected_values, extracted_values, "Should extract the correct enum values"
188189

189190
# Test the resulting TypeScript type
@@ -203,9 +204,11 @@ def test_security_log_event_union_type
203204
# Check that the SecurityLog interface has the event field with a union type
204205
# We don't check the exact string since the order may vary
205206
security_log_section = content.match(/export interface SecurityLog \{.*?\}/m)
207+
206208
assert security_log_section, "Should find SecurityLog interface in the generated TypeScript"
207209

208210
event_line = security_log_section[0].lines.find { |line| line.strip.start_with?("event:") }
211+
209212
assert event_line, "SecurityLog interface should have an event field"
210213

211214
# Verify that the event line contains all three enum values and union operators
@@ -229,61 +232,72 @@ def test_single_enum_value_restriction
229232

230233
# Test the resulting TypeScript type
231234
ts_type = @exporter.typescript_type_for(type_info)
235+
232236
assert_equal "Source.JOB", ts_type, "TypeScript type should be the specific enum value"
233237

234238
# Now check that the full TypeScript generation includes this restricted type
235239
content = @exporter.generate_typescript_definitions
236240

237241
# Find the ActiveJobLog interface section
238242
job_log_section = content.match(/export interface ActiveJobLog \{.*?\}/m)
243+
239244
assert job_log_section, "Should find ActiveJobLog interface in the generated TypeScript"
240245

241246
# Extract the source line and check if it has the specific enum value
242247
source_line = job_log_section[0].lines.find { |line| line.strip.start_with?("source:") }
248+
243249
assert source_line, "ActiveJobLog interface should have a source field"
244250

245251
# The source field should be a specific enum value, not a generic Source enum
246-
assert_equal "source: Source.JOB;", source_line.strip,
252+
assert_equal "source: Source.JOB;",
253+
source_line.strip,
247254
"source field should be Source.JOB specifically, not just Source"
248255
refute_includes source_line, "Source;", "source field should not be the general Source enum"
249256
end
250-
257+
251258
def test_exports_log_event_type_arrays
252259
# Test that we export valid event type arrays for each log type
253260
content = @exporter.generate_typescript_definitions
254-
261+
255262
# Check Security log events array
256263
security_array_match = content.match(/export const SecurityLogEvents: Array<(.*?)> = \[(.*?)\]/m)
264+
257265
assert security_array_match, "Should export a SecurityLogEvents array"
258-
266+
259267
# Check the union type for the array
260268
security_type = security_array_match[1]
269+
261270
["LogEvent.BLOCKED_HOST", "LogEvent.CSRF_VIOLATION", "LogEvent.IP_SPOOF"].each do |event|
262271
assert_includes security_type, event, "SecurityLogEvents type should contain #{event}"
263272
end
264-
273+
265274
# Check the array content
266275
security_array_content = security_array_match[2]
276+
267277
["LogEvent.BLOCKED_HOST", "LogEvent.CSRF_VIOLATION", "LogEvent.IP_SPOOF"].each do |event|
268278
assert_includes security_array_content, event, "SecurityLogEvents array should contain #{event}"
269279
end
270-
280+
271281
# Check ActiveJob log events array
272282
activejob_array_match = content.match(/export const ActiveJobLogEvents: Array<(.*?)> = \[(.*?)\]/m)
283+
273284
assert activejob_array_match, "Should export an ActiveJobLogEvents array"
274-
285+
275286
# Check the array content
276287
activejob_array_content = activejob_array_match[2]
288+
277289
["LogEvent.ENQUEUE", "LogEvent.START", "LogEvent.FINISH", "LogEvent.SCHEDULE"].each do |event|
278290
assert_includes activejob_array_content, event, "ActiveJobLogEvents array should contain #{event}"
279291
end
280-
292+
281293
# Check ActiveStorage log events array
282294
storage_array_match = content.match(/export const ActiveStorageLogEvents: Array<(.*?)> = \[(.*?)\]/m)
295+
283296
assert storage_array_match, "Should export an ActiveStorageLogEvents array"
284-
297+
285298
# Check the array content
286299
storage_array_content = storage_array_match[2]
300+
287301
["LogEvent.UPLOAD", "LogEvent.DOWNLOAD", "LogEvent.DELETE", "LogEvent.STREAM"].each do |event|
288302
assert_includes storage_array_content, event, "ActiveStorageLogEvents array should contain #{event}"
289303
end

tools/log_types_exporter.rb

Lines changed: 11 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -146,32 +146,32 @@ def generate_typescript(data)
146146

147147
# Add interface for each log type
148148
ts_content << "// Log Interfaces"
149-
149+
150150
# Collect all event union types to generate arrays later
151151
log_event_arrays = {}
152-
152+
153153
data[:logs].each do |log_type, log_info|
154154
ts_content << "export interface #{log_type}Log {"
155-
155+
156156
# Collect valid event types if this log has an enum_union for events
157157
event_field_info = log_info[:fields][:event]
158-
if event_field_info &&
159-
event_field_info[:type] == "enum_union" &&
160-
event_field_info[:base_enum] == "LogEvent" &&
161-
event_field_info[:enum_values]&.any?
162-
158+
if event_field_info &&
159+
event_field_info[:type] == "enum_union" &&
160+
event_field_info[:base_enum] == "LogEvent" &&
161+
event_field_info[:enum_values]&.any?
162+
163163
log_event_arrays[log_type] = event_field_info[:enum_values].map do |value|
164164
# Map Ruby enum names to TypeScript enum values (e.g., "IPSpoof" -> "LogEvent.IP_SPOOF")
165165
case value
166166
when "IPSpoof" then "LogEvent.IP_SPOOF"
167-
when "CSRFViolation" then "LogEvent.CSRF_VIOLATION"
167+
when "CSRFViolation" then "LogEvent.CSRF_VIOLATION"
168168
else
169169
# Default conversion of StudlyCaps to SCREAMING_SNAKE_CASE
170170
"LogEvent.#{value.gsub(/([a-z])([A-Z])/, '\1_\2').upcase}"
171171
end
172172
end
173173
end
174-
174+
175175
# Output all fields with types
176176
log_info[:fields].each do |field_name, field_info|
177177
type_str = typescript_type_for(field_info)
@@ -189,7 +189,7 @@ def generate_typescript(data)
189189
ts_content << log_types.join("\n")
190190
ts_content << ";"
191191
ts_content << ""
192-
192+
193193
# Add event arrays for each log type that has an enum_union
194194
ts_content << "// Event type arrays for log types"
195195
log_event_arrays.each do |log_type, event_values|
@@ -452,7 +452,6 @@ def typescript_type_for(field_info)
452452
when "LogEvent" then LogStruct::LogEvent
453453
when "LogLevel" then LogStruct::LogLevel
454454
when "Source" then LogStruct::Source
455-
else nil
456455
end
457456

458457
if enum_class

0 commit comments

Comments
 (0)