@amritk/generate-parsers 0.7.1 → 0.8.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.
Files changed (76) hide show
  1. package/README.md +1 -1
  2. package/dist/generators/build-schema.d.ts +0 -1
  3. package/dist/generators/generate-default-from-pattern.d.ts +0 -1
  4. package/dist/generators/generate-discriminated-union-validation.d.ts +0 -1
  5. package/dist/generators/generate-enum-check.d.ts +0 -1
  6. package/dist/generators/generate-files.d.ts +0 -1
  7. package/dist/generators/generate-non-discriminated-union-validation.d.ts +0 -1
  8. package/dist/generators/generate-parser-function.d.ts +3 -3
  9. package/dist/generators/generate-parser-function.js +165 -37
  10. package/dist/generators/generate-schema-checks.d.ts +0 -1
  11. package/dist/generators/generate-schema-checks.js +2 -1
  12. package/dist/generators/generate-strict-assertion.d.ts +0 -1
  13. package/dist/generators/generate-strict-assertion.js +1 -6
  14. package/dist/generators/generate-validation-expression.d.ts +0 -1
  15. package/dist/generators/generate-validation-expression.js +2 -1
  16. package/dist/helpers/apply-schema-extensions.d.ts +0 -1
  17. package/dist/helpers/collect-helpers.d.ts +0 -1
  18. package/dist/helpers/collect-imports.d.ts +0 -1
  19. package/dist/helpers/find-discriminator.d.ts +0 -1
  20. package/dist/helpers/get-default-value.d.ts +0 -1
  21. package/dist/helpers/get-discriminator-value.d.ts +0 -1
  22. package/dist/index.d.ts +0 -1
  23. package/dist/types/schema-extensions.d.ts +0 -1
  24. package/package.json +3 -5
  25. package/dist/generators/build-schema.d.ts.map +0 -1
  26. package/dist/generators/generate-default-from-pattern.d.ts.map +0 -1
  27. package/dist/generators/generate-discriminated-union-validation.d.ts.map +0 -1
  28. package/dist/generators/generate-enum-check.d.ts.map +0 -1
  29. package/dist/generators/generate-files.d.ts.map +0 -1
  30. package/dist/generators/generate-non-discriminated-union-validation.d.ts.map +0 -1
  31. package/dist/generators/generate-parser-function.d.ts.map +0 -1
  32. package/dist/generators/generate-schema-checks.d.ts.map +0 -1
  33. package/dist/generators/generate-strict-assertion.d.ts.map +0 -1
  34. package/dist/generators/generate-validation-expression.d.ts.map +0 -1
  35. package/dist/helpers/apply-schema-extensions.d.ts.map +0 -1
  36. package/dist/helpers/collect-helpers.d.ts.map +0 -1
  37. package/dist/helpers/collect-imports.d.ts.map +0 -1
  38. package/dist/helpers/find-discriminator.d.ts.map +0 -1
  39. package/dist/helpers/get-default-value.d.ts.map +0 -1
  40. package/dist/helpers/get-discriminator-value.d.ts.map +0 -1
  41. package/dist/index.d.ts.map +0 -1
  42. package/dist/types/schema-extensions.d.ts.map +0 -1
  43. package/src/generators/build-schema.test.ts +0 -854
  44. package/src/generators/build-schema.ts +0 -147
  45. package/src/generators/generate-default-from-pattern.test.ts +0 -81
  46. package/src/generators/generate-default-from-pattern.ts +0 -39
  47. package/src/generators/generate-discriminated-union-validation.test.ts +0 -84
  48. package/src/generators/generate-discriminated-union-validation.ts +0 -54
  49. package/src/generators/generate-enum-check.test.ts +0 -45
  50. package/src/generators/generate-enum-check.ts +0 -8
  51. package/src/generators/generate-files.test.ts +0 -448
  52. package/src/generators/generate-files.ts +0 -155
  53. package/src/generators/generate-non-discriminated-union-validation.test.ts +0 -74
  54. package/src/generators/generate-non-discriminated-union-validation.ts +0 -40
  55. package/src/generators/generate-parser-function.test.ts +0 -1794
  56. package/src/generators/generate-parser-function.ts +0 -1348
  57. package/src/generators/generate-schema-checks.test.ts +0 -330
  58. package/src/generators/generate-schema-checks.ts +0 -127
  59. package/src/generators/generate-strict-assertion.test.ts +0 -67
  60. package/src/generators/generate-strict-assertion.ts +0 -249
  61. package/src/generators/generate-validation-expression.test.ts +0 -831
  62. package/src/generators/generate-validation-expression.ts +0 -326
  63. package/src/helpers/apply-schema-extensions.test.ts +0 -194
  64. package/src/helpers/apply-schema-extensions.ts +0 -63
  65. package/src/helpers/collect-helpers.test.ts +0 -115
  66. package/src/helpers/collect-helpers.ts +0 -79
  67. package/src/helpers/collect-imports.test.ts +0 -547
  68. package/src/helpers/collect-imports.ts +0 -275
  69. package/src/helpers/find-discriminator.test.ts +0 -88
  70. package/src/helpers/find-discriminator.ts +0 -39
  71. package/src/helpers/get-default-value.test.ts +0 -139
  72. package/src/helpers/get-default-value.ts +0 -95
  73. package/src/helpers/get-discriminator-value.test.ts +0 -83
  74. package/src/helpers/get-discriminator-value.ts +0 -21
  75. package/src/index.ts +0 -1
  76. package/src/types/schema-extensions.ts +0 -35
@@ -1,79 +0,0 @@
1
- /** Names (without `.ts`) of runtime helpers that can be embedded into generated output. */
2
- export type RuntimeHelperName = 'is-object' | 'validate-array' | 'validate-record' | 'has-ref'
3
-
4
- /** Controls how generated parsers reference their runtime helpers. */
5
- export type HelpersMode = 'package' | 'embedded'
6
-
7
- export type CollectedHelpers = {
8
- /** Import lines to splice into the generated file. */
9
- readonly imports: string[]
10
- /**
11
- * Helper names that need to ship alongside the generated file in embedded mode.
12
- * Includes transitive deps (e.g. `validate-record` pulls in `is-object`) so the
13
- * orchestrator can emit a complete `_helpers/` directory.
14
- */
15
- readonly used: Set<RuntimeHelperName>
16
- }
17
-
18
- const PACKAGE_IMPORTS: Record<RuntimeHelperName, string> = {
19
- 'is-object': "import { isObject } from '@amritk/helpers/is-object';",
20
- 'validate-array': "import { validateArray } from '@amritk/helpers/validate-array';",
21
- 'validate-record': "import { validateRecord } from '@amritk/helpers/validate-record';",
22
- // hasRef has historically lived in the schema-guards subpath; preserve that for package mode.
23
- 'has-ref': "import { hasRef } from '@amritk/helpers/schema-guards';",
24
- }
25
-
26
- const EMBEDDED_NAMED_EXPORTS: Record<RuntimeHelperName, string> = {
27
- 'is-object': 'isObject',
28
- 'validate-array': 'validateArray',
29
- 'validate-record': 'validateRecord',
30
- 'has-ref': 'hasRef',
31
- }
32
-
33
- const embeddedImport = (helper: RuntimeHelperName, prefix: string): string =>
34
- `import { ${EMBEDDED_NAMED_EXPORTS[helper]} } from '${prefix}_helpers/${helper}';`
35
-
36
- /**
37
- * Detects which runtime helpers a generated parser body references.
38
- *
39
- * @param helpersImportPrefix - Relative path prefix to the shared `_helpers/`
40
- * directory in embedded mode. Defaults to `'./'`. The recursive multi-schema
41
- * build passes `'../'`, `'../../'`, etc. so nested parsers can reach a single
42
- * `_helpers/` directory at the output root.
43
- */
44
- export const collectHelpers = (
45
- parserFunction: string,
46
- mode: HelpersMode,
47
- helpersImportPrefix = './',
48
- ): CollectedHelpers => {
49
- const imports: string[] = []
50
- const used = new Set<RuntimeHelperName>()
51
- const importFor = (helper: RuntimeHelperName): string =>
52
- mode === 'embedded' ? embeddedImport(helper, helpersImportPrefix) : PACKAGE_IMPORTS[helper]
53
-
54
- if (parserFunction.includes('validateArray')) {
55
- imports.push(importFor('validate-array'))
56
- used.add('validate-array')
57
- }
58
-
59
- if (parserFunction.includes('validateRecord')) {
60
- imports.push(importFor('validate-record'))
61
- used.add('validate-record')
62
- // The embedded validate-record.ts imports is-object, so it must be shipped too —
63
- // but only the `validate-record` line is needed in the parser file unless the
64
- // parser body itself references `isObject` (handled below).
65
- used.add('is-object')
66
- }
67
-
68
- if (parserFunction.includes('isObject')) {
69
- imports.push(importFor('is-object'))
70
- used.add('is-object')
71
- }
72
-
73
- if (parserFunction.includes('hasRef(')) {
74
- imports.push(importFor('has-ref'))
75
- used.add('has-ref')
76
- }
77
-
78
- return { imports, used }
79
- }
@@ -1,547 +0,0 @@
1
- import type { JSONSchema } from 'json-schema-typed/draft-2020-12'
2
- import { describe, expect, it } from 'vitest'
3
-
4
- import { collectImports } from './collect-imports'
5
-
6
- describe('collect-imports', () => {
7
- it('collects imports from properties with $ref', () => {
8
- const schema: JSONSchema = {
9
- type: 'object',
10
- properties: {
11
- contact: { $ref: '#/$defs/contact' },
12
- server: { $ref: '#/$defs/server' },
13
- },
14
- }
15
-
16
- const result = collectImports(schema)
17
-
18
- expect(result).toEqual([
19
- "import { type Contact, parseContact, validateContactShape } from './contact';",
20
- "import { type Server, parseServer, validateServerShape } from './server';",
21
- ])
22
- })
23
-
24
- it('collects imports from array items with $ref', () => {
25
- const schema: JSONSchema = {
26
- type: 'object',
27
- properties: {
28
- servers: {
29
- type: 'array',
30
- items: { $ref: '#/$defs/server' },
31
- },
32
- },
33
- }
34
-
35
- const result = collectImports(schema)
36
-
37
- expect(result).toEqual(["import { type Server, parseServer, validateServerShape } from './server';"])
38
- })
39
-
40
- it('collects imports from additionalProperties with $ref', () => {
41
- const schema: JSONSchema = {
42
- type: 'object',
43
- properties: {
44
- webhooks: {
45
- type: 'object',
46
- additionalProperties: { $ref: '#/$defs/path-item' },
47
- },
48
- },
49
- }
50
-
51
- const result = collectImports(schema)
52
-
53
- expect(result).toEqual(["import { type PathItem, parsePathItem, validatePathItemShape } from './path-item';"])
54
- })
55
-
56
- it('collects imports from non-extension patternProperties with $ref', () => {
57
- const schema: JSONSchema = {
58
- type: 'object',
59
- patternProperties: {
60
- '^/': { $ref: '#/$defs/path-item' },
61
- },
62
- }
63
-
64
- const result = collectImports(schema)
65
-
66
- expect(result).toEqual(["import { type PathItem, parsePathItem, validatePathItemShape } from './path-item';"])
67
- })
68
-
69
- it('collects imports from patternProperties with $ref', () => {
70
- const schema: JSONSchema = {
71
- type: 'object',
72
- patternProperties: {
73
- '^/': { $ref: '#/$defs/path-item' },
74
- },
75
- }
76
-
77
- const result = collectImports(schema)
78
-
79
- expect(result).toEqual(["import { type PathItem, parsePathItem, validatePathItemShape } from './path-item';"])
80
- })
81
-
82
- it('collects imports from oneOf with $ref', () => {
83
- const schema: JSONSchema = {
84
- type: 'object',
85
- properties: {
86
- response: {
87
- oneOf: [{ $ref: '#/$defs/response' }, { $ref: '#/$defs/reference' }],
88
- },
89
- },
90
- }
91
-
92
- const result = collectImports(schema)
93
-
94
- expect(result).toEqual([
95
- "import { type Reference, parseReference, validateReferenceShape } from './reference';",
96
- "import { type Response, parseResponse, validateResponseShape } from './response';",
97
- ])
98
- })
99
-
100
- it('collects imports from anyOf with $ref', () => {
101
- const schema: JSONSchema = {
102
- type: 'object',
103
- properties: {
104
- value: {
105
- anyOf: [{ $ref: '#/$defs/string-value' }, { $ref: '#/$defs/number-value' }],
106
- },
107
- },
108
- }
109
-
110
- const result = collectImports(schema)
111
-
112
- expect(result).toEqual([
113
- "import { type NumberValue, parseNumberValue, validateNumberValueShape } from './number-value';",
114
- "import { type StringValue, parseStringValue, validateStringValueShape } from './string-value';",
115
- ])
116
- })
117
-
118
- it('collects imports from allOf with $ref', () => {
119
- const schema: JSONSchema = {
120
- type: 'object',
121
- properties: {
122
- combined: {
123
- allOf: [{ $ref: '#/$defs/base' }, { $ref: '#/$defs/extension' }],
124
- },
125
- },
126
- }
127
-
128
- const result = collectImports(schema)
129
-
130
- expect(result).toEqual([
131
- "import { type Base, parseBase, validateBaseShape } from './base';",
132
- "import { type Extension, parseExtension, validateExtensionShape } from './extension';",
133
- ])
134
- })
135
-
136
- it('deduplicates imports by filename', () => {
137
- const schema: JSONSchema = {
138
- type: 'object',
139
- properties: {
140
- contact1: { $ref: '#/$defs/contact' },
141
- contact2: { $ref: '#/$defs/contact' },
142
- },
143
- }
144
-
145
- const result = collectImports(schema)
146
-
147
- expect(result).toEqual(["import { type Contact, parseContact, validateContactShape } from './contact';"])
148
- })
149
-
150
- it('collects imports from $ref properties', () => {
151
- const schema: JSONSchema = {
152
- type: 'object',
153
- properties: {
154
- response: { $ref: '#/$defs/response' },
155
- },
156
- }
157
-
158
- const result = collectImports(schema)
159
-
160
- expect(result).toEqual(["import { type Response, parseResponse, validateResponseShape } from './response';"])
161
- })
162
-
163
- it('handles nested refs in complex schemas', () => {
164
- const schema: JSONSchema = {
165
- type: 'object',
166
- properties: {
167
- servers: {
168
- type: 'array',
169
- items: { $ref: '#/$defs/server' },
170
- },
171
- callbacks: {
172
- type: 'object',
173
- additionalProperties: { $ref: '#/$defs/callback' },
174
- },
175
- },
176
- }
177
-
178
- const result = collectImports(schema)
179
-
180
- expect(result).toEqual([
181
- "import { type Callback, parseCallback, validateCallbackShape } from './callback';",
182
- "import { type Server, parseServer, validateServerShape } from './server';",
183
- ])
184
- })
185
-
186
- it('collects imports from root-level additionalProperties', () => {
187
- const schema: JSONSchema = {
188
- type: 'object',
189
- additionalProperties: { $ref: '#/$defs/path-item' },
190
- }
191
-
192
- const result = collectImports(schema)
193
-
194
- expect(result).toEqual(["import { type PathItem, parsePathItem, validatePathItemShape } from './path-item';"])
195
- })
196
-
197
- it('imports Schema parser and type from generated schema.ts', () => {
198
- const schema: JSONSchema = {
199
- type: 'object',
200
- properties: {
201
- schema: { $ref: '#/$defs/schema' },
202
- },
203
- }
204
-
205
- const result = collectImports(schema)
206
-
207
- expect(result).toEqual(["import { type Schema, parseSchema, validateSchemaShape } from './schema';"])
208
- })
209
-
210
- it('handles empty schema', () => {
211
- const schema: JSONSchema = {
212
- type: 'object',
213
- }
214
-
215
- const result = collectImports(schema)
216
-
217
- expect(result).toEqual([])
218
- })
219
-
220
- it('handles schema without properties', () => {
221
- const schema: JSONSchema = {
222
- type: 'string',
223
- }
224
-
225
- const result = collectImports(schema)
226
-
227
- expect(result).toEqual([])
228
- })
229
-
230
- it('collects imports from root-level allOf refs', () => {
231
- const schema: JSONSchema = {
232
- type: 'object',
233
- allOf: [
234
- { $ref: '#/$defs/security-scheme/$defs/type-apikey' },
235
- { $ref: '#/$defs/security-scheme/$defs/type-http' },
236
- ],
237
- }
238
-
239
- const result = collectImports(schema)
240
-
241
- expect(result).toEqual([
242
- "import { type TypeApikey, parseTypeApikey, validateTypeApikeyShape } from './type-apikey';",
243
- "import { type TypeHttp, parseTypeHttp, validateTypeHttpShape } from './type-http';",
244
- ])
245
- })
246
-
247
- it('collects imports from all allOf $ref entries', () => {
248
- const schema: JSONSchema = {
249
- type: 'object',
250
- properties: {
251
- contentType: { type: 'string' },
252
- },
253
- allOf: [{ $ref: '#/$defs/base-schema' }, { $ref: '#/$defs/styles-for-form' }],
254
- }
255
-
256
- const result = collectImports(schema)
257
-
258
- expect(result).toEqual([
259
- "import { type BaseSchema, parseBaseSchema, validateBaseSchemaShape } from './base-schema';",
260
- "import { type StylesForForm, parseStylesForForm, validateStylesForFormShape } from './styles-for-form';",
261
- ])
262
- })
263
-
264
- it('generates type-only imports when typesOnly is true', () => {
265
- const schema: JSONSchema = {
266
- type: 'object',
267
- properties: {
268
- contact: { $ref: '#/$defs/contact' },
269
- server: { $ref: '#/$defs/server' },
270
- },
271
- }
272
-
273
- const result = collectImports(schema, { typesOnly: true })
274
-
275
- expect(result).toEqual(["import type { Contact } from './contact';", "import type { Server } from './server';"])
276
- })
277
-
278
- it('does not include parser names in type-only imports', () => {
279
- const schema: JSONSchema = {
280
- type: 'object',
281
- properties: {
282
- contact: { $ref: '#/$defs/contact' },
283
- },
284
- }
285
-
286
- const result = collectImports(schema, { typesOnly: true })
287
-
288
- expect(result).toEqual(["import type { Contact } from './contact';"])
289
- expect(result[0]).not.toContain('parseContact')
290
- })
291
-
292
- it('collects type-only imports from $ref properties in typesOnly mode', () => {
293
- const schema: JSONSchema = {
294
- type: 'object',
295
- properties: {
296
- response: { $ref: '#/$defs/response' },
297
- },
298
- }
299
-
300
- const result = collectImports(schema, { typesOnly: true })
301
-
302
- expect(result).toEqual(["import type { Response } from './response';"])
303
- })
304
-
305
- it('generates type-only imports from array items $ref in typesOnly mode', () => {
306
- const schema: JSONSchema = {
307
- type: 'object',
308
- properties: {
309
- servers: {
310
- type: 'array',
311
- items: { $ref: '#/$defs/server' },
312
- },
313
- },
314
- }
315
-
316
- const result = collectImports(schema, { typesOnly: true })
317
-
318
- expect(result).toEqual(["import type { Server } from './server';"])
319
- })
320
-
321
- it('generates type-only imports from additionalProperties $ref in typesOnly mode', () => {
322
- const schema: JSONSchema = {
323
- type: 'object',
324
- additionalProperties: { $ref: '#/$defs/path-item' },
325
- }
326
-
327
- const result = collectImports(schema, { typesOnly: true })
328
-
329
- expect(result).toEqual(["import type { PathItem } from './path-item';"])
330
- })
331
-
332
- it('generates type-only imports from anyOf $ref in typesOnly mode', () => {
333
- const schema: JSONSchema = {
334
- type: 'object',
335
- properties: {
336
- value: {
337
- anyOf: [{ $ref: '#/$defs/string-value' }, { $ref: '#/$defs/number-value' }],
338
- },
339
- },
340
- }
341
-
342
- const result = collectImports(schema, { typesOnly: true })
343
-
344
- expect(result).toEqual([
345
- "import type { NumberValue } from './number-value';",
346
- "import type { StringValue } from './string-value';",
347
- ])
348
- })
349
-
350
- it('generates type-only imports from allOf $ref in typesOnly mode', () => {
351
- const schema: JSONSchema = {
352
- type: 'object',
353
- allOf: [{ $ref: '#/$defs/base' }, { $ref: '#/$defs/extension' }],
354
- }
355
-
356
- const result = collectImports(schema, { typesOnly: true })
357
-
358
- expect(result).toEqual(["import type { Base } from './base';", "import type { Extension } from './extension';"])
359
- })
360
-
361
- it('deduplicates type-only imports by filename', () => {
362
- const schema: JSONSchema = {
363
- type: 'object',
364
- properties: {
365
- contact1: { $ref: '#/$defs/contact' },
366
- contact2: { $ref: '#/$defs/contact' },
367
- },
368
- }
369
-
370
- const result = collectImports(schema, { typesOnly: true })
371
-
372
- expect(result).toEqual(["import type { Contact } from './contact';"])
373
- })
374
-
375
- it('returns empty array for schema with no $ref in typesOnly mode', () => {
376
- const schema: JSONSchema = {
377
- type: 'object',
378
- properties: {
379
- name: { type: 'string' },
380
- age: { type: 'number' },
381
- },
382
- }
383
-
384
- const result = collectImports(schema, { typesOnly: true })
385
-
386
- expect(result).toEqual([])
387
- })
388
-
389
- it('collects imports from root-level array items with $ref', () => {
390
- const schema: JSONSchema = {
391
- type: 'array',
392
- items: { $ref: '#/$defs/server' },
393
- }
394
-
395
- const result = collectImports(schema)
396
-
397
- expect(result).toEqual(["import { type Server, parseServer, validateServerShape } from './server';"])
398
- })
399
-
400
- it('collects imports from root-level array items $ref in typesOnly mode', () => {
401
- const schema: JSONSchema = {
402
- type: 'array',
403
- items: { $ref: '#/$defs/parameter' },
404
- }
405
-
406
- const result = collectImports(schema, { typesOnly: true })
407
-
408
- expect(result).toEqual(["import type { Parameter } from './parameter';"])
409
- })
410
-
411
- it('collects imports from root-level oneOf refs', () => {
412
- const schema: JSONSchema = {
413
- type: 'object',
414
- oneOf: [{ $ref: '#/$defs/contact' }, { $ref: '#/$defs/server' }],
415
- }
416
-
417
- const result = collectImports(schema)
418
-
419
- expect(result).toContain("import { type Contact, parseContact, validateContactShape } from './contact';")
420
- expect(result).toContain("import { type Server, parseServer, validateServerShape } from './server';")
421
- })
422
-
423
- it('collects imports from root-level anyOf refs', () => {
424
- const schema: JSONSchema = {
425
- type: 'object',
426
- anyOf: [{ $ref: '#/$defs/contact' }, { $ref: '#/$defs/server' }],
427
- }
428
-
429
- const result = collectImports(schema)
430
-
431
- expect(result).toContain("import { type Contact, parseContact, validateContactShape } from './contact';")
432
- expect(result).toContain("import { type Server, parseServer, validateServerShape } from './server';")
433
- })
434
-
435
- it('collects imports from root-level if branch', () => {
436
- const schema: JSONSchema = {
437
- if: { $ref: '#/$defs/contact' },
438
- then: { type: 'object' },
439
- }
440
-
441
- const result = collectImports(schema)
442
-
443
- expect(result).toContain("import { type Contact, parseContact, validateContactShape } from './contact';")
444
- })
445
-
446
- it('collects imports from root-level then branch', () => {
447
- const schema: JSONSchema = {
448
- if: { type: 'object' },
449
- then: { $ref: '#/$defs/server' },
450
- }
451
-
452
- const result = collectImports(schema)
453
-
454
- expect(result).toContain("import { type Server, parseServer, validateServerShape } from './server';")
455
- })
456
-
457
- it('collects imports from root-level else branch', () => {
458
- const schema: JSONSchema = {
459
- if: { type: 'object' },
460
- else: { $ref: '#/$defs/contact' },
461
- }
462
-
463
- const result = collectImports(schema)
464
-
465
- expect(result).toContain("import { type Contact, parseContact, validateContactShape } from './contact';")
466
- })
467
-
468
- it('does not generate a self-import when a schema references its own $defs key via a property', () => {
469
- // Mirrors the encoding schema: encoding.ts has a property `itemEncoding` that is a direct
470
- // $ref back to #/$defs/encoding. Generating `import ... from './encoding'` inside encoding.ts
471
- // would be a circular self-import that crashes at runtime.
472
- const schema: JSONSchema = {
473
- type: 'object',
474
- properties: {
475
- itemEncoding: { $ref: '#/$defs/encoding' },
476
- header: { $ref: '#/$defs/header' },
477
- },
478
- }
479
-
480
- const result = collectImports(schema, { selfRef: '#/$defs/encoding' })
481
-
482
- expect(result).not.toContain("'./encoding'")
483
- expect(result).toContain("import { type Header, parseHeader, validateHeaderShape } from './header';")
484
- })
485
-
486
- it('does not generate a self-import when a schema references its own $defs key via additionalProperties', () => {
487
- const schema: JSONSchema = {
488
- type: 'object',
489
- properties: {
490
- encoding: {
491
- type: 'object',
492
- additionalProperties: { $ref: '#/$defs/encoding' },
493
- },
494
- },
495
- }
496
-
497
- const result = collectImports(schema, { selfRef: '#/$defs/encoding' })
498
-
499
- expect(result).not.toContain("'./encoding'")
500
- })
501
-
502
- it('does not generate a self-import when a schema references its own $defs key via array items', () => {
503
- const schema: JSONSchema = {
504
- type: 'object',
505
- properties: {
506
- prefixEncoding: {
507
- type: 'array',
508
- items: { $ref: '#/$defs/encoding' },
509
- },
510
- },
511
- }
512
-
513
- const result = collectImports(schema, { selfRef: '#/$defs/encoding' })
514
-
515
- expect(result).not.toContain("'./encoding'")
516
- })
517
-
518
- it('does not collect imports for external $refs', () => {
519
- // External refs (e.g. from draft-04 schemas) cannot be resolved locally and have no generated file.
520
- const schema: JSONSchema = {
521
- type: 'object',
522
- properties: {
523
- maximum: { $ref: 'http://json-schema.org/draft-04/schema#/properties/maximum' },
524
- name: { type: 'string' },
525
- },
526
- }
527
-
528
- const result = collectImports(schema)
529
-
530
- expect(result).toEqual([])
531
- })
532
-
533
- it('does not generate a self-import in types-only mode', () => {
534
- const schema: JSONSchema = {
535
- type: 'object',
536
- properties: {
537
- itemEncoding: { $ref: '#/$defs/encoding' },
538
- header: { $ref: '#/$defs/header' },
539
- },
540
- }
541
-
542
- const result = collectImports(schema, { typesOnly: true, selfRef: '#/$defs/encoding' })
543
-
544
- expect(result).not.toContain("'./encoding'")
545
- expect(result).toContain("import type { Header } from './header';")
546
- })
547
- })