klasik 2.3.0 → 2.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,280 +0,0 @@
1
- # JSDoc Escaping Strategy
2
-
3
- This document describes the JSDoc/TSDoc escaping strategy used in Klasik to prevent malformed comments in generated code.
4
-
5
- ## Overview
6
-
7
- JSDoc comments in generated TypeScript code need careful handling of special characters to avoid breaking the comment syntax while preserving readability and functionality.
8
-
9
- ## Escaping Rules
10
-
11
- ### Characters That Are Escaped
12
-
13
- 1. **Comment Delimiters**
14
- - `*/` → `*\/` - Closing comment delimiter (prevents premature comment termination)
15
- - `/*` → `/\*` - Opening comment delimiter (prevents nested comment issues)
16
-
17
- 2. **At Symbol (Context-Aware)**
18
- - `@` at start of line or after whitespace → `\@` - Prevents false JSDoc tags
19
- - `@` in middle of text (e.g., `user@example.com`) → Preserved
20
-
21
- 3. **Newlines**
22
- - `\n` → `\n * ` - Adds proper JSDoc line prefix for multiline comments
23
-
24
- ### Characters That Are Preserved
25
-
26
- These characters are intentionally **not escaped** because they're essential for JSDoc functionality and readability:
27
-
28
- 1. **Backticks** (`)
29
- - Used for inline code examples: `` `const foo = "bar"` ``
30
- - Preserved for markdown-style code formatting
31
-
32
- 2. **Quotes** (`"` and `'`)
33
- - Used in descriptions and examples
34
- - No escaping needed within JSDoc comments
35
-
36
- 3. **Angle Brackets** (`<` and `>`)
37
- - Used for generic type references: `Array<string>`, `Map<K, V>`
38
- - Essential for TypeScript type documentation
39
-
40
- 4. **Curly Braces** (`{` and `}`)
41
- - Used in JSDoc type annotations: `@type {string}`
42
- - Used in object descriptions: `{key: value}`
43
-
44
- 5. **Slashes** (`/`)
45
- - Only escaped when part of comment delimiters (`/*` or `*/`)
46
- - Regular slashes preserved for paths and regex patterns
47
-
48
- 6. **Asterisks** (`*`)
49
- - Only escaped when part of comment delimiters (`*/`)
50
- - Regular asterisks preserved for emphasis
51
-
52
- ## Implementation
53
-
54
- ### Files
55
-
56
- The escaping logic is implemented in two files:
57
-
58
- 1. **`src/generators/tsdoc-generator.ts`**
59
- - `escapeJSDoc()` method
60
- - Used for property docs, method docs, parameter docs
61
-
62
- 2. **`src/builders/class-builder.ts`**
63
- - `escapeJsDocText()` method
64
- - Used for class descriptions
65
-
66
- Both implementations use the **same escaping logic** to ensure consistency.
67
-
68
- ### Code Example
69
-
70
- ```typescript
71
- /**
72
- * Escape JSDoc special characters
73
- *
74
- * Handles special characters that could break JSDoc syntax:
75
- * - Comment delimiters: */ and /*
76
- * - Newlines: adds proper JSDoc line prefix
77
- *
78
- * Characters preserved for JSDoc functionality:
79
- * - Backticks (`) for inline code
80
- * - Angle brackets (<>) for type references
81
- * - Curly braces ({}) for @type tags
82
- * - @ symbol (context-aware escaping)
83
- */
84
- private escapeJSDoc(text: string): string {
85
- if (!text) return text;
86
-
87
- return text
88
- // Escape closing comment delimiter (MUST be first to avoid double-escaping)
89
- .replace(/\*\//g, '*\\/')
90
- // Escape opening comment delimiter
91
- .replace(/\/\*/g, '/\\*')
92
- // Escape @ at start of line to prevent false JSDoc tags
93
- // Only escape @ when it's at the start of a line or after whitespace
94
- .replace(/(^|\n)\s*@/g, '$1\\@')
95
- // Handle newlines by adding JSDoc line prefix
96
- .replace(/\n/g, '\n * ');
97
- }
98
- ```
99
-
100
- ## Examples
101
-
102
- ### Example 1: Comment Delimiters
103
-
104
- **Input:**
105
- ```javascript
106
- description: "This function /* does something */ important"
107
- ```
108
-
109
- **Output:**
110
- ```javascript
111
- /**
112
- * This function /\* does something *\/ important
113
- */
114
- ```
115
-
116
- ### Example 2: Inline Code with Backticks
117
-
118
- **Input:**
119
- ```javascript
120
- description: "Use `const foo = "bar"` for constants"
121
- ```
122
-
123
- **Output:**
124
- ```javascript
125
- /**
126
- * Use `const foo = "bar"` for constants
127
- */
128
- ```
129
-
130
- ### Example 3: Type References
131
-
132
- **Input:**
133
- ```javascript
134
- description: "Returns Array<User> or Map<string, User>"
135
- ```
136
-
137
- **Output:**
138
- ```javascript
139
- /**
140
- * Returns Array<User> or Map<string, User>
141
- */
142
- ```
143
-
144
- ### Example 4: Email Addresses
145
-
146
- **Input:**
147
- ```javascript
148
- description: "Email like @username or user@example.com"
149
- ```
150
-
151
- **Output:**
152
- ```javascript
153
- /**
154
- * Email like \@username or user@example.com
155
- */
156
- ```
157
- (Note: `@username` at start is escaped, but `user@example.com` is preserved)
158
-
159
- ### Example 5: Multiline Descriptions
160
-
161
- **Input:**
162
- ```javascript
163
- description: "Line 1\nLine 2 with `code`\nLine 3"
164
- ```
165
-
166
- **Output:**
167
- ```javascript
168
- /**
169
- * Line 1
170
- * Line 2 with `code`
171
- * Line 3
172
- */
173
- ```
174
-
175
- ### Example 6: Complex Example
176
-
177
- **Input:**
178
- ```javascript
179
- description: "Example: `const regex = /pattern/;` creates /* comment */ with types like Array<T>"
180
- ```
181
-
182
- **Output:**
183
- ```javascript
184
- /**
185
- * Example: `const regex = /pattern/;` creates /\* comment *\/ with types like Array<T>
186
- */
187
- ```
188
-
189
- ## Design Rationale
190
-
191
- ### Why Not Escape Everything?
192
-
193
- We could escape all special characters, but this would harm readability:
194
-
195
- ❌ **Over-Escaping Approach:**
196
- ```javascript
197
- /**
198
- * Use \`backticks\` for code like Array\<string\> with \{key: value\}
199
- */
200
- ```
201
-
202
- ✅ **Our Approach:**
203
- ```javascript
204
- /**
205
- * Use `backticks` for code like Array<string> with {key: value}
206
- */
207
- ```
208
-
209
- ### Escape Order Matters
210
-
211
- The order of replacements is critical:
212
-
213
- 1. **`*/` must be escaped FIRST** - Otherwise, escaping `/*` could create `*\/` which might be further processed
214
- 2. **`/*` escaping** - After closing delimiter is safe
215
- 3. **`@` escaping** - Context-aware, only at line start
216
- 4. **Newlines** - Last, adds JSDoc line prefix
217
-
218
- ### Context-Aware Escaping
219
-
220
- The `@` symbol is only escaped when it could be mistaken for a JSDoc tag:
221
-
222
- - `@param` at line start → escaped to `\@param`
223
- - `user@example.com` in text → preserved
224
- - `@username` at start → escaped to `\@username`
225
-
226
- ## Testing
227
-
228
- Comprehensive test coverage ensures the escaping works correctly:
229
-
230
- ### Test Files
231
-
232
- 1. **`src/generators/__tests__/tsdoc-generator.test.ts`**
233
- - 45 tests covering all property and method doc scenarios
234
- - Tests for all special characters and edge cases
235
-
236
- 2. **`src/builders/__tests__/class-builder.test.ts`**
237
- - 45 tests covering class-level documentation
238
- - Tests for escaping in class descriptions
239
-
240
- ### Test Coverage
241
-
242
- - ✅ Comment delimiters (`/*` and `*/`)
243
- - ✅ Backticks for inline code
244
- - ✅ Single and double quotes
245
- - ✅ Angle brackets for types
246
- - ✅ Curly braces
247
- - ✅ At symbols (@)
248
- - ✅ Multiline descriptions
249
- - ✅ Complex combinations
250
- - ✅ Pattern constraints
251
- - ✅ Example values
252
- - ✅ Default values
253
- - ✅ Parameter descriptions
254
- - ✅ Request body descriptions
255
-
256
- ## Maintenance
257
-
258
- When modifying the escaping logic:
259
-
260
- 1. **Update both files** - `tsdoc-generator.ts` and `class-builder.ts` must use identical logic
261
- 2. **Update tests** - Add test cases for new scenarios
262
- 3. **Verify generated code** - Run generation and inspect output
263
- 4. **Check TypeScript compilation** - Ensure generated code compiles without errors
264
- 5. **Update this document** - Keep documentation in sync with implementation
265
-
266
- ## Related Issues
267
-
268
- This implementation addresses the following concerns:
269
-
270
- - Prevents malformed JSDoc comments that break TypeScript compilation
271
- - Maintains readability of generated documentation
272
- - Preserves JSDoc functionality (tags, types, inline code)
273
- - Handles edge cases like nested structures and multiline text
274
- - Consistent behavior across all generated code (models, APIs, properties)
275
-
276
- ## References
277
-
278
- - [TSDoc Specification](https://tsdoc.org/)
279
- - [JSDoc Documentation](https://jsdoc.app/)
280
- - [TypeScript JSDoc Reference](https://www.typescriptlang.org/docs/handbook/jsdoc-supported-types.html)
@@ -1,353 +0,0 @@
1
- # JSON Schema Support Matrix
2
-
3
- This document outlines which JSON Schema features are supported by Klasik for generating TypeScript models.
4
-
5
- ## Overview
6
-
7
- Klasik provides solid support for common JSON Schema Draft 7 features but lacks support for some advanced patterns like `patternProperties`, `not`, and `dependencies`. This affects complex real-world schemas like GitHub Workflow but works well for most standard schemas.
8
-
9
- ## Supported Features
10
-
11
- ### Type System
12
-
13
- | Feature | Support | Notes |
14
- |---------|---------|-------|
15
- | **Primitive types** | ✅ Full | `string`, `number`, `integer`, `boolean`, `null` |
16
- | **object** | ✅ Full | With `properties`, `required`, `additionalProperties` |
17
- | **array** | ✅ Full | With `items`, `minItems`, `maxItems`, `uniqueItems` |
18
- | **enum** | ✅ Full | Generates enum or union types |
19
- | **const** | ✅ Full | Draft 6+ single-value enum |
20
- | **nullable** | ✅ Full | TypeScript optional (`?`) or union with `null` |
21
-
22
- ### Schema Composition
23
-
24
- | Feature | Support | Notes |
25
- |---------|---------|-------|
26
- | **oneOf** | ✅ Full | Converted to TypeScript union types |
27
- | **anyOf** | ✅ Full | Converted to TypeScript union types |
28
- | **allOf** | ⚠️ Partial | Merged as union in complex cases; simple cases work well |
29
- | **$ref** (internal) | ✅ Full | References to `#/definitions/*` or `#/$defs/*` |
30
- | **$ref** (external) | ✅ Full | Use `--resolve-refs` flag to resolve external references |
31
- | **definitions** | ✅ Full | Draft 4-7 reusable schemas |
32
- | **$defs** | ✅ Full | Draft 2019-09+ reusable schemas |
33
-
34
- ### Validation Keywords
35
-
36
- | Feature | Support | Generated As | Notes |
37
- |---------|---------|--------------|-------|
38
- | **required** | ✅ Full | Required properties | TypeScript required vs optional |
39
- | **properties** | ✅ Full | Class properties | With decorators |
40
- | **additionalProperties** | ✅ Full | `Record<string, T>` | Object or boolean forms |
41
- | **minLength / maxLength** | ✅ Full | `@MinLength()`, `@MaxLength()` | class-validator |
42
- | **minimum / maximum** | ✅ Full | `@Min()`, `@Max()` | class-validator |
43
- | **exclusiveMinimum / exclusiveMaximum** | ✅ Full | Both boolean (Draft 4) and number forms | |
44
- | **pattern** | ✅ Full | `@Matches()` | Regex validation |
45
- | **minItems / maxItems** | ✅ Full | `@ArrayMinSize()`, `@ArrayMaxSize()` | class-validator |
46
- | **uniqueItems** | ✅ Full | `@ArrayUnique()` | class-validator |
47
- | **multipleOf** | ✅ Full | Constraint metadata | |
48
- | **format** | ✅ Full | `@IsEmail()`, `@IsUrl()`, `@IsUUID()`, etc. | Preserved for validation |
49
-
50
- ### Object Constraints
51
-
52
- | Feature | Support | Notes |
53
- |---------|---------|-------|
54
- | **minProperties / maxProperties** | ⚠️ Metadata | Preserved but not enforced in TypeScript |
55
- | **propertyNames** | ❌ No | Pattern validation of property names |
56
- | **patternProperties** | ❌ No | **CRITICAL GAP** - Pattern-based property matching |
57
- | **dependencies** | ❌ No | Property dependencies not enforced |
58
-
59
- ### Conditional & Logic
60
-
61
- | Feature | Support | Notes |
62
- |---------|---------|-------|
63
- | **if/then/else** | ❌ No | Draft 7+ conditional schemas |
64
- | **not** | ❌ No | Schema negation for mutual exclusivity |
65
- | **dependentSchemas** | ❌ No | Draft 2019-09+ schema-based dependencies |
66
-
67
- ### Metadata & Annotations
68
-
69
- | Feature | Support | Usage |
70
- |---------|---------|-------|
71
- | **title** | ✅ Full | Class name if no explicit name |
72
- | **description** | ✅ Full | JSDoc comments |
73
- | **default** | ✅ Full | Property metadata |
74
- | **examples** | ✅ Full | Property metadata |
75
- | **deprecated** | ⚠️ Metadata | Preserved but not marked as `@deprecated` |
76
- | **readOnly / writeOnly** | ⚠️ Metadata | Preserved but not enforced |
77
- | **$comment** | ⚠️ Metadata | Preserved in schema metadata |
78
- | **Vendor extensions** | ✅ Full | All `x-*` properties preserved |
79
-
80
- ## Unsupported Features (Critical Gaps)
81
-
82
- ### 1. patternProperties (CRITICAL)
83
-
84
- **Status:** ❌ Not Supported
85
-
86
- **What it does:**
87
- ```json
88
- {
89
- "patternProperties": {
90
- "^[_a-zA-Z][a-zA-Z0-9_-]*$": {
91
- "type": "object",
92
- "properties": {
93
- "name": { "type": "string" }
94
- }
95
- }
96
- }
97
- }
98
- ```
99
-
100
- **Use cases:**
101
- - Job IDs in GitHub Actions workflows
102
- - Service names in Docker Compose schemas
103
- - Variable names in configuration schemas
104
- - Dynamic property names matching a pattern
105
-
106
- **Impact:** HIGH
107
- - Schemas with dynamic property names cannot be properly typed
108
- - Falls back to `Record<string, any>` or `unknown`
109
- - Loss of type safety for the most important parts of many schemas
110
-
111
- **Workaround:**
112
- - Current: Falls back to `additionalProperties` behavior
113
- - TypeScript limitation: Can't express pattern-based keys
114
- - Best effort: Could generate `Record<string, Type>` for pattern properties
115
-
116
- **Example schemas affected:**
117
- - GitHub Workflow (job definitions)
118
- - Docker Compose (service definitions)
119
- - Kubernetes Custom Resources (arbitrary property names)
120
-
121
- ---
122
-
123
- ### 2. not Keyword
124
-
125
- **Status:** ❌ Not Supported
126
-
127
- **What it does:**
128
- ```json
129
- {
130
- "properties": {
131
- "branches": { "type": "array" },
132
- "branches-ignore": { "type": "array" }
133
- },
134
- "not": {
135
- "required": ["branches", "branches-ignore"]
136
- }
137
- }
138
- ```
139
-
140
- **Use cases:**
141
- - Mutual exclusivity constraints (A XOR B)
142
- - Forbidden property combinations
143
- - Type constraints by negation
144
-
145
- **Impact:** MEDIUM-HIGH
146
- - Both mutually exclusive properties generated as optional
147
- - No enforcement of XOR logic
148
- - Runtime validation may fail for invalid combinations
149
-
150
- **Workaround:**
151
- - Option 1: Generate union types for mutually exclusive branches
152
- - Option 2: Add JSDoc comments warning about mutual exclusivity
153
- - Option 3: Custom validation decorators (future)
154
-
155
- **Example schemas affected:**
156
- - GitHub Workflow (branches vs branches-ignore)
157
- - Many schemas with exclusive alternatives
158
-
159
- ---
160
-
161
- ### 3. dependencies Keyword
162
-
163
- **Status:** ❌ Not Supported
164
-
165
- **What it does:**
166
- ```json
167
- {
168
- "properties": {
169
- "run": { "type": "string" },
170
- "working-directory": { "type": "string" }
171
- },
172
- "dependencies": {
173
- "working-directory": ["run"]
174
- }
175
- }
176
- ```
177
-
178
- **Use cases:**
179
- - Conditional property requirements
180
- - Property A requires property B to also be present
181
-
182
- **Impact:** MEDIUM
183
- - All properties generated independently
184
- - Conditional requirements not enforced
185
- - May allow invalid object construction
186
-
187
- **Workaround:**
188
- - Document in JSDoc comments
189
- - Could generate conditional validation decorators (future)
190
-
191
- **Example schemas affected:**
192
- - GitHub Workflow (working-directory depends on run)
193
- - Configuration schemas with related settings
194
-
195
- ---
196
-
197
- ### 4. External $ref
198
-
199
- **Status:** ✅ Fully Supported (with --resolve-refs flag)
200
-
201
- **What it does:**
202
- ```json
203
- {
204
- "$ref": "https://example.com/schemas/user.json"
205
- }
206
- ```
207
-
208
- **Use cases:**
209
- - Cross-file schema references
210
- - Shared schema libraries
211
- - Remote schema imports
212
- - Local file references
213
-
214
- **Usage:**
215
-
216
- **CLI:**
217
- ```bash
218
- klasik generate --input api.yaml --output ./generated --resolve-refs
219
- ```
220
-
221
- **Programmatic:**
222
- ```typescript
223
- const loader = new SpecLoader();
224
- const spec = await loader.loadWithRefs({
225
- url: './api.yaml',
226
- resolveRefs: true,
227
- maxDepth: 10 // Optional: max recursion depth (default: 10)
228
- });
229
- ```
230
-
231
- **Supported Formats:**
232
- - ✅ Relative paths: `./schemas/User.yaml`
233
- - ✅ Absolute paths: `/path/to/schema.yaml`
234
- - ✅ Remote URLs: `https://api.example.com/schemas/User.yaml`
235
- - ✅ With fragments: `./schemas/User.yaml#/definitions/User`
236
- - ✅ Nested refs (ref within ref)
237
- - ✅ Circular reference detection
238
-
239
- **Advanced Options:**
240
- ```bash
241
- # With custom timeout
242
- klasik generate --input api.yaml --output ./out --resolve-refs --timeout 60000
243
-
244
- # With authentication headers
245
- klasik generate --input https://api.example.com/spec.yaml \
246
- --output ./out \
247
- --resolve-refs \
248
- --header "Authorization: Bearer TOKEN"
249
- ```
250
-
251
- **How It Works:**
252
- 1. Spec loader discovers all external `$ref` recursively
253
- 2. Downloads referenced files (with auth headers if provided)
254
- 3. Inlines refs into main spec before parsing
255
- 4. Generates code from fully resolved spec
256
-
257
- **Impact:** ✅ NONE - Fully transparent
258
- - All external refs are downloaded and inlined automatically
259
- - Generated code has no external dependencies
260
- - Works with all existing features (decorators, validation, etc.)
261
-
262
- ---
263
-
264
- ## Draft Support Matrix
265
-
266
- | JSON Schema Draft | Basic Support | Advanced Features |
267
- |-------------------|---------------|-------------------|
268
- | **Draft 4** | ✅ Full | ⚠️ Most (missing patternProperties, not, dependencies) |
269
- | **Draft 6** | ✅ Full | ⚠️ Most (adds const, propertyNames - const supported) |
270
- | **Draft 7** | ✅ Full | ⚠️ Most (adds if/then/else - not supported) |
271
- | **Draft 2019-09** | ⚠️ Partial | ❌ Limited (missing unevaluatedProperties, dependentSchemas) |
272
- | **Draft 2020-12** | ⚠️ Partial | ❌ Limited (same gaps as 2019-09) |
273
-
274
- ## Tested Schemas
275
-
276
- ### ✅ Working Well
277
-
278
- | Schema | Complexity | Notes |
279
- |--------|------------|-------|
280
- | **Kustomization** | Low-Medium | Simple properties, some oneOf/anyOf |
281
- | **ArgoCD Application CRD** | High | 298 models, extensive nesting, works great |
282
- | **Package.json** | Medium | Standard structure, good results |
283
-
284
- ### ⚠️ Partial Support
285
-
286
- | Schema | Complexity | Limitations |
287
- |--------|------------|-------------|
288
- | **GitHub Workflow** | Very High | patternProperties for jobs, not for XOR filters |
289
- | **Docker Compose** | High | patternProperties for services |
290
-
291
- ## Best Practices
292
-
293
- ### When Klasik Works Best
294
-
295
- 1. **Standard object schemas** with fixed property names
296
- 2. **CRD-style schemas** with defined properties and nested objects
297
- 3. **Configuration schemas** without dynamic property names
298
- 4. **Schemas using oneOf/anyOf/allOf** for type unions
299
- 5. **Well-defined validation rules** (length, format, patterns)
300
-
301
- ### Workarounds for Unsupported Features
302
-
303
- #### patternProperties
304
- - **Option 1:** Use `additionalProperties` with explicit typing
305
- - **Option 2:** Define a `Record<string, Type>` property manually
306
- - **Option 3:** Pre-process schema to convert patternProperties to explicit properties
307
-
308
- #### not Keyword
309
- - **Option 1:** Split into separate schemas with clear names
310
- - **Option 2:** Add JSDoc warnings about mutual exclusivity
311
- - **Option 3:** Validate at runtime with custom validators
312
-
313
- #### dependencies
314
- - **Option 1:** Document requirements in JSDoc
315
- - **Option 2:** Add runtime validation in your code
316
- - **Option 3:** Use TypeScript utility types for conditional properties
317
-
318
- ## Future Enhancements
319
-
320
- ### Planned (High Priority)
321
-
322
- - [ ] **patternProperties** support - Generate `Record<string, Type>` for pattern-based properties
323
- - [ ] **not** keyword support - Generate union types or validation decorators
324
- - [ ] **dependencies** support - Track dependencies in IR and generate validation
325
-
326
- ### Under Consideration
327
-
328
- - [ ] **if/then/else** conditional schemas
329
- - [ ] **dependentSchemas** (Draft 2019-09+)
330
- - [ ] **unevaluatedProperties** (Draft 2019-09+)
331
- - [ ] **propertyNames** pattern validation
332
-
333
- ### Long Term
334
-
335
- - [ ] Full Draft 2019-09 support
336
- - [ ] Full Draft 2020-12 support
337
- - [ ] Custom keyword extensions
338
- - [ ] Plugin system for custom schema features
339
-
340
- ## Contributing
341
-
342
- If you need support for a specific unsupported feature, please:
343
- 1. Open an issue with your use case
344
- 2. Provide example schemas that demonstrate the need
345
- 3. Describe the expected TypeScript output
346
- 4. Indicate if you're willing to contribute an implementation
347
-
348
- ## References
349
-
350
- - [JSON Schema Specification](https://json-schema.org/specification.html)
351
- - [JSON Schema Draft 7](https://json-schema.org/draft-07/json-schema-release-notes.html)
352
- - [JSON Schema Draft 2020-12](https://json-schema.org/draft/2020-12/json-schema-core.html)
353
- - [SchemaStore.org](https://www.schemastore.org/) - Collection of JSON schemas for testing