Skip to content

Commit a14beb2

Browse files
committed
more docs autogeneration
1 parent 0a65741 commit a14beb2

File tree

5 files changed

+205
-74
lines changed

5 files changed

+205
-74
lines changed

site/app/docs/type-safety/page.tsx

Lines changed: 15 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import { CodeBlock } from '@/components/code-block';
22
import { EditPageLink } from '@/components/edit-page-link';
3+
import { EnumsList } from '@/components/enums-list';
34
import { LogStructuresList } from '@/components/log-structures-list';
45
import { RubyCodeExample } from '@/components/ruby-code-example';
56

@@ -27,23 +28,6 @@ export default async function TypeSafetyPage() {
2728
title="Basic Typed Logging Example"
2829
/>
2930

30-
<h2 className="text-2xl font-bold mt-10 mb-4">
31-
Available Log Structures
32-
</h2>
33-
<p className="text-neutral-600 dark:text-neutral-400 mb-4">
34-
LogStruct provides several typed log structures for different use cases:
35-
</p>
36-
37-
{/* Dynamic list of log structures from the JSON data */}
38-
<LogStructuresList />
39-
40-
<h2 className="text-2xl font-bold mt-10 mb-4">Enums and Constants</h2>
41-
<p className="text-neutral-600 dark:text-neutral-400 mb-4">
42-
LogStruct provides typed enums for common values used in logs:
43-
</p>
44-
45-
<RubyCodeExample name="log_enums" title="Log Levels and Enums" />
46-
4731
<h2 className="text-2xl font-bold mt-10 mb-4">
4832
Adding Sorbet to Your Application
4933
</h2>
@@ -105,6 +89,20 @@ gem "sorbet-runtime"
10589
title="Creating Custom Log Structures"
10690
/>
10791

92+
<h1 className="text-4xl font-bold mt-10 mb-4">
93+
Available Log Structures
94+
</h1>
95+
<p className="text-neutral-600 dark:text-neutral-400 mb-4">
96+
LogStruct provides several typed log structures for different use cases:
97+
</p>
98+
<LogStructuresList />
99+
100+
<h1 className="text-4xl font-bold mt-10 mb-4">Enums</h1>
101+
<p className="text-neutral-600 dark:text-neutral-400 mb-4">
102+
LogStruct provides typed enums for common values used in logs:
103+
</p>
104+
<EnumsList />
105+
108106
<EditPageLink />
109107
</div>
110108
);

site/components/enums-list.tsx

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
import { getEnumDescription, getEnumValueDescription } from '@/lib/enum-descriptions';
2+
import { cache } from 'react';
3+
4+
// Interface for the enum data in the JSON file
5+
interface EnumData {
6+
[key: string]: Array<{
7+
name: string;
8+
value: string;
9+
}>;
10+
}
11+
12+
// Function to get enum data from JSON file with caching
13+
const getEnumsData = cache(async (): Promise<EnumData> => {
14+
try {
15+
// Use dynamic import to load the JSON file
16+
const data = await import('@/lib/log-generation/sorbet-enums.json');
17+
return data.default as EnumData;
18+
} catch (error) {
19+
console.error('Error loading enums data:', error);
20+
return {};
21+
}
22+
});
23+
24+
/**
25+
* Component that displays a hierarchical bullet point list of LogStruct enums
26+
* with their descriptions and values
27+
*/
28+
export async function EnumsList() {
29+
// Get the enums data
30+
const enumsData = await getEnumsData();
31+
32+
// Get enum names we want to display (in a specific order)
33+
const enumOrder = [
34+
'LogStruct::LogLevel',
35+
'LogStruct::Source',
36+
'LogStruct::LogEvent',
37+
'LogStruct::ErrorHandlingMode'
38+
];
39+
40+
// Filter and sort enums
41+
const sortedEnums = Object.keys(enumsData)
42+
.filter(enumName => enumOrder.includes(enumName))
43+
.sort((a, b) => enumOrder.indexOf(a) - enumOrder.indexOf(b));
44+
45+
return (
46+
<div className="space-y-6">
47+
{sortedEnums.map(enumName => {
48+
const values = enumsData[enumName];
49+
// Get short name (last part after ::)
50+
const shortName = enumName.split('::').pop() || '';
51+
52+
return (
53+
<div key={enumName} className="mb-4">
54+
<h3 className="text-xl font-bold mb-2">{shortName}</h3>
55+
<p className="text-neutral-600 dark:text-neutral-400 mb-2">
56+
{getEnumDescription(enumName)}
57+
</p>
58+
<ul className="list-disc list-inside space-y-1 text-neutral-600 dark:text-neutral-400 ml-4">
59+
{values.map(({ name, value }) => (
60+
<li key={`${enumName}-${name}`}>
61+
<code className="px-1 py-0.5 bg-neutral-100 dark:bg-neutral-800 rounded">
62+
{shortName}::{name}
63+
</code>{' '}
64+
- {getEnumValueDescription(enumName, name)}
65+
</li>
66+
))}
67+
</ul>
68+
</div>
69+
);
70+
})}
71+
</div>
72+
);
73+
}

site/lib/__tests__/codeExamples.test.ts

Lines changed: 14 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -81,11 +81,13 @@ describe('Code Examples Integration', () => {
8181
// Check that we have the expected code structure
8282
// The actual indentation may vary based on the current test/code_examples files
8383
expect(lines[0]).toMatch(/LogStruct\.configure do \|config\|/);
84-
84+
8585
// Check that relative indentation is preserved (don't check exact content)
8686
if (lines.length > 2) {
8787
// Find a line with indentation
88-
const indentedLine = lines.find(line => line.trim().length > 0 && line.startsWith(' '));
88+
const indentedLine = lines.find(
89+
(line) => line.trim().length > 0 && line.startsWith(' '),
90+
);
8991
if (indentedLine) {
9092
expect(indentedLine.startsWith(' ')).toBe(true);
9193
}
@@ -107,7 +109,9 @@ console.log(example);
107109
`;
108110

109111
const extracted = extractCodeExample(content, 'basic_example');
110-
expect(extracted).toBe('const example = "Hello, world!";\nconsole.log(example);');
112+
expect(extracted).toBe(
113+
'const example = "Hello, world!";\nconsole.log(example);',
114+
);
111115
});
112116

113117
it('supports replace directives', () => {
@@ -159,7 +163,9 @@ const result = compute();
159163
`;
160164

161165
const extracted = extractCodeExample(content, 'complex_replace');
162-
expect(extracted).toBe('const value = 42;\n// value\n// "testing"\nconst result = compute();');
166+
expect(extracted).toBe(
167+
'const value = 42;\n// value\n// "testing"\nconst result = compute();',
168+
);
163169
});
164170

165171
it('preserves indentation after replacements', () => {
@@ -180,10 +186,12 @@ function calculate() {
180186
`;
181187

182188
const extracted = extractCodeExample(content, 'indentation_example');
183-
expect(extracted).toBe('function calculate() {\n const result = sum(1, 2);\n if (result > 0) {\n return sum(result, 3);\n }\n return 0;\n}');
189+
expect(extracted).toBe(
190+
'function calculate() {\n const result = sum(1, 2);\n if (result > 0) {\n return sum(result, 3);\n }\n return 0;\n}',
191+
);
184192
});
185193

186-
it('handles the enum case from type_safety_test.rb', () => {
194+
it('handles replace directives', () => {
187195
const content = `
188196
# ----------------------------------------------------------
189197
# BEGIN CODE EXAMPLE: log_enums, replace: /enums << /, ""
@@ -194,21 +202,6 @@ enums << LogStruct::LogLevel::Info
194202
enums << LogStruct::LogLevel::Warn
195203
enums << LogStruct::LogLevel::Error
196204
enums << LogStruct::LogLevel::Fatal
197-
198-
# Log sources
199-
enums << LogStruct::Source::Rails
200-
enums << LogStruct::Source::App
201-
enums << LogStruct::Source::Job
202-
enums << LogStruct::Source::Mailer
203-
enums << LogStruct::Source::Security
204-
enums << LogStruct::Source::TypeChecking
205-
206-
# Error handling modes
207-
enums << LogStruct::ErrorHandlingMode::Ignore # Completely ignore errors
208-
enums << LogStruct::ErrorHandlingMode::Log # Log errors but don't report them
209-
enums << LogStruct::ErrorHandlingMode::LogProduction # Log in production, raise in development
210-
enums << LogStruct::ErrorHandlingMode::Report # Log and report errors to error service
211-
enums << LogStruct::ErrorHandlingMode::Raise # Always raise errors
212205
# ----------------------------------------------------------
213206
# END CODE EXAMPLE: log_enums
214207
# ----------------------------------------------------------

site/lib/enum-descriptions.ts

Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,103 @@
1+
/**
2+
* Descriptions for each LogStruct enum class
3+
* These are used in the documentation to explain what each enum is for
4+
*/
5+
export const ENUM_DESCRIPTIONS: Record<string, string> = {
6+
"LogStruct::LogLevel": "Log severity levels for different types of log messages",
7+
"LogStruct::Source": "Sources of log messages to identify which part of the system generated them",
8+
"LogStruct::LogEvent": "Event types for different kinds of operations and activities",
9+
"LogStruct::ErrorHandlingMode": "Error handling strategies for different types of errors"
10+
};
11+
12+
/**
13+
* Get the description for an enum class
14+
* @param enumName The full name of the enum class (e.g., "LogStruct::LogLevel")
15+
* @returns The description of the enum
16+
* @throws Error if no description is found for the enum
17+
*/
18+
export function getEnumDescription(enumName: string): string {
19+
const description = ENUM_DESCRIPTIONS[enumName];
20+
if (!description) {
21+
throw new Error(`No description found for enum: ${enumName}`);
22+
}
23+
return description;
24+
}
25+
26+
/**
27+
* Value descriptions for specific enum values
28+
* These provide context for what each enum value means
29+
*/
30+
export const ENUM_VALUE_DESCRIPTIONS: Record<string, Record<string, string>> = {
31+
"LogStruct::LogLevel": {
32+
"Debug": "Detailed debugging information",
33+
"Info": "General informational messages",
34+
"Warn": "Warning conditions that should be noted",
35+
"Error": "Error conditions that affect operation",
36+
"Fatal": "Severe error conditions that cause the application to terminate",
37+
"Unknown": "Used when a log level cannot be determined"
38+
},
39+
"LogStruct::Source": {
40+
"Rails": "Core Rails framework components",
41+
"App": "Application-specific code",
42+
"Job": "Background job processing",
43+
"Mailer": "Email delivery and processing",
44+
"Security": "Security-related events and checks",
45+
"TypeChecking": "Type checking errors (Sorbet)",
46+
"LogStruct": "Errors from LogStruct itself",
47+
"Storage": "ActiveStorage logs and errors",
48+
"Shrine": "Shrine file upload logs and errors",
49+
"CarrierWave": "CarrierWave file upload logs and errors",
50+
"Sidekiq": "Sidekiq background job logs and errors"
51+
},
52+
"LogStruct::ErrorHandlingMode": {
53+
"Ignore": "Completely ignore errors",
54+
"Log": "Log errors but don't report them",
55+
"LogProduction": "Log in production, raise in development",
56+
"Report": "Log and report errors to error service",
57+
"ReportProduction": "Report in production without crashing, raise during dev/test",
58+
"Raise": "Always raise the error (reported by tracking service)"
59+
},
60+
"LogStruct::LogEvent": {
61+
"Log": "Standard log message",
62+
"Request": "HTTP request",
63+
"Enqueue": "Job added to queue",
64+
"Schedule": "Job scheduled for future processing",
65+
"Start": "Job processing started",
66+
"Finish": "Job processing completed",
67+
"Upload": "File upload operation",
68+
"Download": "File download operation",
69+
"Delete": "File deletion operation",
70+
"Metadata": "File metadata operation",
71+
"Exist": "File existence check operation",
72+
"Stream": "File streaming operation",
73+
"Url": "File URL generation operation",
74+
"Delivery": "Email preparation for delivery",
75+
"Delivered": "Email successfully delivered",
76+
"IPSpoof": "IP spoofing attack attempt",
77+
"CSRFViolation": "Cross-Site Request Forgery violation",
78+
"BlockedHost": "Access attempt from blocked host",
79+
"Error": "Error occurrence",
80+
"Unknown": "Unclassified event type"
81+
}
82+
};
83+
84+
/**
85+
* Get the description for a specific enum value
86+
* @param enumName The full name of the enum class (e.g., "LogStruct::LogLevel")
87+
* @param valueName The name of the enum value (e.g., "Debug")
88+
* @returns The description of the enum value
89+
* @throws Error if no description is found for the enum value
90+
*/
91+
export function getEnumValueDescription(enumName: string, valueName: string): string {
92+
const enumValues = ENUM_VALUE_DESCRIPTIONS[enumName];
93+
if (!enumValues) {
94+
throw new Error(`No values found for enum: ${enumName}`);
95+
}
96+
97+
const description = enumValues[valueName];
98+
if (!description) {
99+
throw new Error(`No description found for enum value: ${enumName}::${valueName}`);
100+
}
101+
102+
return description;
103+
}

test/code_examples/type_safety_test.rb

Lines changed: 0 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -47,42 +47,6 @@ def test_basic_typed_logging
4747
assert_equal "An error occurred during processing", error_log.message
4848
end
4949

50-
def test_log_enums
51-
enums = T.let([], T::Array[T.any(LogStruct::LogLevel, LogStruct::Source, LogStruct::ErrorHandlingMode)])
52-
# ----------------------------------------------------------
53-
# BEGIN CODE EXAMPLE: log_enums, replace: /enums << /, ""
54-
# ----------------------------------------------------------
55-
# Log levels
56-
enums << LogStruct::LogLevel::Debug
57-
enums << LogStruct::LogLevel::Info
58-
enums << LogStruct::LogLevel::Warn
59-
enums << LogStruct::LogLevel::Error
60-
enums << LogStruct::LogLevel::Fatal
61-
62-
# Log sources
63-
enums << LogStruct::Source::Rails
64-
enums << LogStruct::Source::App
65-
enums << LogStruct::Source::Job
66-
enums << LogStruct::Source::Mailer
67-
enums << LogStruct::Source::Security
68-
enums << LogStruct::Source::TypeChecking
69-
70-
# Error handling modes
71-
enums << LogStruct::ErrorHandlingMode::Ignore # Completely ignore errors
72-
enums << LogStruct::ErrorHandlingMode::Log # Log errors but don't report them
73-
enums << LogStruct::ErrorHandlingMode::LogProduction # Log in production, raise in development
74-
enums << LogStruct::ErrorHandlingMode::Report # Log and report errors to error service
75-
enums << LogStruct::ErrorHandlingMode::Raise # Always raise errors
76-
# ----------------------------------------------------------
77-
# END CODE EXAMPLE: log_enums
78-
# ----------------------------------------------------------
79-
# rubocop:enable Lint/Void
80-
81-
assert_includes(enums, LogStruct::LogLevel::Debug)
82-
assert_includes(enums, LogStruct::Source::App)
83-
assert_includes(enums, LogStruct::ErrorHandlingMode::Ignore)
84-
end
85-
8650
# Custom log structure must be defined at module level, not inside a method
8751
# ----------------------------------------------------------
8852
# BEGIN CODE EXAMPLE: custom_log_structure

0 commit comments

Comments
 (0)