@amritk/generate-parsers 0.24.0 → 0.25.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 (51) hide show
  1. package/README.md +37 -463
  2. package/dist/index.d.ts +22 -2
  3. package/dist/index.js +18 -1
  4. package/package.json +15 -40
  5. package/AI.md +0 -52
  6. package/dist/generators/assert-supported-keywords.d.ts +0 -30
  7. package/dist/generators/assert-supported-keywords.js +0 -87
  8. package/dist/generators/build-schema.d.ts +0 -111
  9. package/dist/generators/build-schema.js +0 -74
  10. package/dist/generators/generate-deep-equal-check.d.ts +0 -24
  11. package/dist/generators/generate-deep-equal-check.js +0 -35
  12. package/dist/generators/generate-default-from-pattern.d.ts +0 -26
  13. package/dist/generators/generate-default-from-pattern.js +0 -223
  14. package/dist/generators/generate-discriminated-union-validation.d.ts +0 -15
  15. package/dist/generators/generate-discriminated-union-validation.js +0 -28
  16. package/dist/generators/generate-enum-check.d.ts +0 -35
  17. package/dist/generators/generate-enum-check.js +0 -31
  18. package/dist/generators/generate-files.d.ts +0 -138
  19. package/dist/generators/generate-files.js +0 -89
  20. package/dist/generators/generate-non-discriminated-union-validation.d.ts +0 -6
  21. package/dist/generators/generate-non-discriminated-union-validation.js +0 -26
  22. package/dist/generators/generate-parser-function.d.ts +0 -120
  23. package/dist/generators/generate-parser-function.js +0 -1973
  24. package/dist/generators/generate-schema-checks.d.ts +0 -5
  25. package/dist/generators/generate-schema-checks.js +0 -260
  26. package/dist/generators/generate-strict-assertion.d.ts +0 -155
  27. package/dist/generators/generate-strict-assertion.js +0 -759
  28. package/dist/generators/generate-type-checks.d.ts +0 -148
  29. package/dist/generators/generate-type-checks.js +0 -454
  30. package/dist/generators/generate-unique-items-check.d.ts +0 -16
  31. package/dist/generators/generate-unique-items-check.js +0 -32
  32. package/dist/generators/generate-validation-expression.d.ts +0 -79
  33. package/dist/generators/generate-validation-expression.js +0 -416
  34. package/dist/generators/subschema-match.d.ts +0 -48
  35. package/dist/generators/subschema-match.js +0 -485
  36. package/dist/generators/unevaluated-match.d.ts +0 -19
  37. package/dist/generators/unevaluated-match.js +0 -206
  38. package/dist/helpers/apply-schema-extensions.d.ts +0 -35
  39. package/dist/helpers/apply-schema-extensions.js +0 -20
  40. package/dist/helpers/collect-helpers.d.ts +0 -15
  41. package/dist/helpers/collect-helpers.js +0 -64
  42. package/dist/helpers/collect-imports.d.ts +0 -104
  43. package/dist/helpers/collect-imports.js +0 -227
  44. package/dist/helpers/find-discriminator.d.ts +0 -6
  45. package/dist/helpers/find-discriminator.js +0 -27
  46. package/dist/helpers/get-default-value.d.ts +0 -7
  47. package/dist/helpers/get-default-value.js +0 -155
  48. package/dist/helpers/get-discriminator-value.d.ts +0 -6
  49. package/dist/helpers/get-discriminator-value.js +0 -18
  50. package/dist/types/schema-extensions.d.ts +0 -34
  51. package/dist/types/schema-extensions.js +0 -0
@@ -1,206 +0,0 @@
1
- import { regexLiteral } from "@amritk/helpers/escape-regex-pattern";
2
- import { resolveRef } from "@amritk/helpers/resolve-ref";
3
- import { isSchemaObject } from "@amritk/helpers/schema-guards";
4
- const NONE = { all: false, terms: [] };
5
- const orJoin = (terms) => terms.length === 1 ? terms[0] : `(${terms.join(" || ")})`;
6
- const depthOf = (ctx) => ctx.depth ?? 0;
7
- const nest = (ctx) => ({ ...ctx, depth: depthOf(ctx) + 1 });
8
- const conditioned = (coverage, cond) => {
9
- if (coverage.all)
10
- return { all: false, terms: [cond] };
11
- if (coverage.terms.length === 0)
12
- return NONE;
13
- return { all: false, terms: [`(${cond} && ${orJoin(coverage.terms)})`] };
14
- };
15
- const merge = (into, from) => into.all || from.all ? { all: true, terms: [] } : { all: false, terms: [...into.terms, ...from.terms] };
16
- const ownPropertyCoverage = (schema, keyVar, ignoreOwnUnevaluated) => {
17
- if ("additionalProperties" in schema)
18
- return { all: true, terms: [] };
19
- if (!ignoreOwnUnevaluated && "unevaluatedProperties" in schema && schema["unevaluatedProperties"] !== false) {
20
- return { all: true, terms: [] };
21
- }
22
- const terms = [];
23
- const properties = schema["properties"];
24
- if (typeof properties === "object" && properties !== null && !Array.isArray(properties)) {
25
- const keys = Object.keys(properties);
26
- if (keys.length > 0)
27
- terms.push(`${JSON.stringify(keys)}.includes(${keyVar})`);
28
- }
29
- const patterns = schema["patternProperties"];
30
- if (typeof patterns === "object" && patterns !== null && !Array.isArray(patterns)) {
31
- for (const pattern of Object.keys(patterns)) {
32
- terms.push(`${regexLiteral(pattern)}.test(${keyVar})`);
33
- }
34
- }
35
- return { all: false, terms };
36
- };
37
- const ownItemCoverage = (schema, indexVar, ignoreOwnUnevaluated) => {
38
- const tupleItems = Array.isArray(schema["items"]);
39
- if (!tupleItems && "items" in schema)
40
- return { all: true, terms: [] };
41
- if (tupleItems && "additionalItems" in schema)
42
- return { all: true, terms: [] };
43
- if (!ignoreOwnUnevaluated && "unevaluatedItems" in schema && schema["unevaluatedItems"] !== false) {
44
- return { all: true, terms: [] };
45
- }
46
- const terms = [];
47
- const prefix = Array.isArray(schema["prefixItems"]) ? schema["prefixItems"] : tupleItems ? schema["items"] : null;
48
- if (prefix && prefix.length > 0)
49
- terms.push(`${indexVar} < ${prefix.length}`);
50
- return { all: false, terms };
51
- };
52
- const containsCoverage = (schema, indexVar, acc, ctx, match) => {
53
- if (!("contains" in schema))
54
- return NONE;
55
- const itemMatch = match(`(${acc} as any[])[${indexVar}]`, schema["contains"], nest(ctx));
56
- if (itemMatch === null)
57
- return null;
58
- if (itemMatch === "true")
59
- return { all: true, terms: [] };
60
- return { all: false, terms: [itemMatch] };
61
- };
62
- const coverageOf = (kind, schema, varName, acc, ctx, match, ignoreOwnUnevaluated = false) => {
63
- if (typeof schema === "boolean")
64
- return NONE;
65
- if (!isSchemaObject(schema))
66
- return null;
67
- if (depthOf(ctx) > 8)
68
- return null;
69
- const s = schema;
70
- let coverage = kind === "properties" ? ownPropertyCoverage(s, varName, ignoreOwnUnevaluated) : ownItemCoverage(s, varName, ignoreOwnUnevaluated);
71
- if (kind === "items") {
72
- const contains = containsCoverage(s, varName, acc, ctx, match);
73
- if (contains === null)
74
- return null;
75
- coverage = merge(coverage, contains);
76
- }
77
- const ref = s["$ref"];
78
- if (typeof ref === "string") {
79
- if (ctx.rootSchema === void 0 || ctx.seen?.has(ref))
80
- return null;
81
- const target = resolveRef(ref, ctx.rootSchema);
82
- if (target === void 0)
83
- return null;
84
- const seen = new Set(ctx.seen ?? []);
85
- seen.add(ref);
86
- const refCoverage = coverageOf(kind, target, varName, acc, { ...nest(ctx), seen }, match);
87
- if (refCoverage === null)
88
- return null;
89
- coverage = merge(coverage, refCoverage);
90
- }
91
- if (Array.isArray(s["allOf"])) {
92
- for (const member of s["allOf"]) {
93
- const memberCoverage = coverageOf(kind, member, varName, acc, nest(ctx), match);
94
- if (memberCoverage === null)
95
- return null;
96
- coverage = merge(coverage, memberCoverage);
97
- }
98
- }
99
- for (const keyword of ["anyOf", "oneOf"]) {
100
- if (!Array.isArray(s[keyword]))
101
- continue;
102
- for (const branch of s[keyword]) {
103
- const branchCoverage = coverageOf(kind, branch, varName, acc, nest(ctx), match);
104
- if (branchCoverage === null)
105
- return null;
106
- if (branchCoverage.all === false && branchCoverage.terms.length === 0)
107
- continue;
108
- const branchMatch = match(acc, branch, nest(ctx));
109
- if (branchMatch === null)
110
- return null;
111
- coverage = merge(coverage, conditioned(branchCoverage, branchMatch));
112
- }
113
- }
114
- if ("if" in s) {
115
- const ifMatch = match(acc, s["if"], nest(ctx));
116
- if (ifMatch === null)
117
- return null;
118
- for (const [keyword, cond] of [
119
- ["if", ifMatch],
120
- ["then", ifMatch],
121
- ["else", `!(${ifMatch})`]
122
- ]) {
123
- if (!(keyword in s))
124
- continue;
125
- const branchCoverage = coverageOf(kind, s[keyword], varName, acc, nest(ctx), match);
126
- if (branchCoverage === null)
127
- return null;
128
- coverage = merge(coverage, conditioned(branchCoverage, cond));
129
- }
130
- }
131
- const dependentSchemas = s["dependentSchemas"];
132
- if (typeof dependentSchemas === "object" && dependentSchemas !== null && !Array.isArray(dependentSchemas)) {
133
- for (const [trigger, sub] of Object.entries(dependentSchemas)) {
134
- const subCoverage = coverageOf(kind, sub, varName, acc, nest(ctx), match);
135
- if (subCoverage === null)
136
- return null;
137
- coverage = merge(coverage, conditioned(subCoverage, `${JSON.stringify(trigger)} in (${acc} as object)`));
138
- }
139
- }
140
- return coverage;
141
- };
142
- const unevaluatedPropertiesExpr = (acc, schema, ctx, match) => {
143
- if (!isSchemaObject(schema))
144
- return void 0;
145
- const s = schema;
146
- if (!("unevaluatedProperties" in s))
147
- return void 0;
148
- const unevaluated = s["unevaluatedProperties"];
149
- if (unevaluated === true)
150
- return void 0;
151
- const d = depthOf(ctx);
152
- const keyVar = `_uk${d}`;
153
- const coverage = coverageOf("properties", schema, keyVar, acc, ctx, match, true);
154
- if (coverage === null)
155
- return null;
156
- if (coverage.all)
157
- return void 0;
158
- const rec = `(${acc} as Record<string, unknown>)`;
159
- const covered = coverage.terms.length > 0 ? orJoin(coverage.terms) : null;
160
- if (unevaluated === false) {
161
- if (covered === null)
162
- return `Object.keys(${rec}).length === 0`;
163
- return `Object.keys(${rec}).every((${keyVar}) => ${covered})`;
164
- }
165
- const valueMatch = match(`${rec}[${keyVar}]`, unevaluated, nest(ctx));
166
- if (valueMatch === null)
167
- return null;
168
- if (valueMatch === "true")
169
- return void 0;
170
- return covered === null ? `Object.keys(${rec}).every((${keyVar}) => ${valueMatch})` : `Object.keys(${rec}).every((${keyVar}) => ${covered} || ${valueMatch})`;
171
- };
172
- const unevaluatedItemsExpr = (acc, schema, ctx, match) => {
173
- if (!isSchemaObject(schema))
174
- return void 0;
175
- const s = schema;
176
- if (!("unevaluatedItems" in s))
177
- return void 0;
178
- const unevaluated = s["unevaluatedItems"];
179
- if (unevaluated === true)
180
- return void 0;
181
- const d = depthOf(ctx);
182
- const indexVar = `_un${d}`;
183
- const itemVar = `_ue${d}`;
184
- const coverage = coverageOf("items", schema, indexVar, acc, ctx, match, true);
185
- if (coverage === null)
186
- return null;
187
- if (coverage.all)
188
- return void 0;
189
- const elements = `(${acc} as any[])`;
190
- const covered = coverage.terms.length > 0 ? orJoin(coverage.terms) : null;
191
- if (unevaluated === false) {
192
- if (covered === null)
193
- return `${acc}.length === 0`;
194
- return `${elements}.every((_, ${indexVar}) => ${covered})`;
195
- }
196
- const valueMatch = match(itemVar, unevaluated, nest(ctx));
197
- if (valueMatch === null)
198
- return null;
199
- if (valueMatch === "true")
200
- return void 0;
201
- return covered === null ? `${elements}.every((${itemVar}) => ${valueMatch})` : `${elements}.every((${itemVar}, ${indexVar}) => ${covered} || ${valueMatch})`;
202
- };
203
- export {
204
- unevaluatedItemsExpr,
205
- unevaluatedPropertiesExpr
206
- };
@@ -1,35 +0,0 @@
1
- import type { JSONSchema } from 'json-schema-typed/draft-2020-12';
2
- import type { SchemaExtensions } from '../types/schema-extensions.js';
3
- /**
4
- * Merges custom extension properties into a schema's properties based on the
5
- * definition name. Extension properties are added as optional (not included
6
- * in the required array) since they are custom additions that may not always
7
- * be present.
8
- *
9
- * If the schema is not an object, has no matching extensions, or the
10
- * extensions record is empty, the original schema is returned unchanged.
11
- *
12
- * @param schema - The JSON Schema to extend
13
- * @param definitionName - The name of the definition (e.g., "parameter")
14
- * @param extensions - The extensions configuration mapping definition names to properties
15
- * @returns A new schema with extension properties merged in, or the original if unchanged
16
- *
17
- * @example
18
- * ```typescript
19
- * const schema = {
20
- * type: 'object',
21
- * properties: { name: { type: 'string' } },
22
- * required: ['name'],
23
- * }
24
- *
25
- * const extensions = {
26
- * parameter: {
27
- * 'x-enabled': { type: 'boolean' },
28
- * },
29
- * }
30
- *
31
- * const extended = applySchemaExtensions(schema, 'parameter', extensions)
32
- * // extended.properties now includes 'x-enabled' alongside 'name'
33
- * ```
34
- */
35
- export declare const applySchemaExtensions: (schema: JSONSchema, definitionName: string, extensions: SchemaExtensions) => JSONSchema;
@@ -1,20 +0,0 @@
1
- const applySchemaExtensions = (schema, definitionName, extensions) => {
2
- const extensionProperties = extensions[definitionName];
3
- if (!extensionProperties || Object.keys(extensionProperties).length === 0) {
4
- return schema;
5
- }
6
- if (typeof schema !== "object" || schema === null) {
7
- return schema;
8
- }
9
- const existingProperties = "properties" in schema && typeof schema.properties === "object" && schema.properties !== null ? schema.properties : {};
10
- return {
11
- ...schema,
12
- properties: {
13
- ...existingProperties,
14
- ...extensionProperties
15
- }
16
- };
17
- };
18
- export {
19
- applySchemaExtensions
20
- };
@@ -1,15 +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
- /** Controls how generated parsers reference their runtime helpers. */
4
- export type HelpersMode = 'package' | 'embedded';
5
- export type CollectedHelpers = {
6
- /** Import lines to splice into the generated file. */
7
- readonly imports: string[];
8
- /**
9
- * Helper names that need to ship alongside the generated file in embedded mode.
10
- * Includes transitive deps (e.g. `validate-record` pulls in `is-object`) so the
11
- * orchestrator can emit a complete `_helpers/` directory.
12
- */
13
- readonly used: Set<RuntimeHelperName>;
14
- };
15
- export declare const collectHelpers: (parserFunction: string, mode: HelpersMode, helpersImportPrefix?: string, importExt?: 'js' | 'ts') => CollectedHelpers;
@@ -1,64 +0,0 @@
1
- const PACKAGE_IMPORTS = {
2
- "is-object": "import { isObject } from '@amritk/helpers/is-object';",
3
- "validate-array": "import { validateArray } from '@amritk/helpers/validate-array';",
4
- "validate-record": "import { validateRecord } from '@amritk/helpers/validate-record';",
5
- // hasRef has historically lived in the schema-guards subpath; preserve that for package mode.
6
- "has-ref": "import { hasRef } from '@amritk/helpers/schema-guards';"
7
- };
8
- const EMBEDDED_NAMED_EXPORTS = {
9
- "is-object": "isObject",
10
- "validate-array": "validateArray",
11
- "validate-record": "validateRecord",
12
- "has-ref": "hasRef"
13
- };
14
- const embeddedImport = (helper, prefix, ext) => (
15
- // An explicit extension so the embedded-helper import resolves under Node ESM, not only Bun.
16
- `import { ${EMBEDDED_NAMED_EXPORTS[helper]} } from '${prefix}_helpers/${helper}.${ext}';`
17
- );
18
- const HELPER_USAGE = /validateArray|validateRecord|isObject|hasRef\(/g;
19
- const collectHelpers = (parserFunction, mode, helpersImportPrefix = "./", importExt = "js") => {
20
- const imports = [];
21
- const used = /* @__PURE__ */ new Set();
22
- const importFor = (helper) => mode === "embedded" ? embeddedImport(helper, helpersImportPrefix, importExt) : PACKAGE_IMPORTS[helper];
23
- let sawValidateArray = false;
24
- let sawValidateRecord = false;
25
- let sawIsObject = false;
26
- let sawHasRef = false;
27
- HELPER_USAGE.lastIndex = 0;
28
- let match = HELPER_USAGE.exec(parserFunction);
29
- while (match !== null) {
30
- const token = match[0];
31
- if (token === "validateArray")
32
- sawValidateArray = true;
33
- else if (token === "validateRecord")
34
- sawValidateRecord = true;
35
- else if (token === "isObject")
36
- sawIsObject = true;
37
- else
38
- sawHasRef = true;
39
- if (sawValidateArray && sawValidateRecord && sawIsObject && sawHasRef)
40
- break;
41
- match = HELPER_USAGE.exec(parserFunction);
42
- }
43
- if (sawValidateArray) {
44
- imports.push(importFor("validate-array"));
45
- used.add("validate-array");
46
- }
47
- if (sawValidateRecord) {
48
- imports.push(importFor("validate-record"));
49
- used.add("validate-record");
50
- used.add("is-object");
51
- }
52
- if (sawIsObject) {
53
- imports.push(importFor("is-object"));
54
- used.add("is-object");
55
- }
56
- if (sawHasRef) {
57
- imports.push(importFor("has-ref"));
58
- used.add("has-ref");
59
- }
60
- return { imports, used };
61
- };
62
- export {
63
- collectHelpers
64
- };
@@ -1,104 +0,0 @@
1
- import type { JSONSchema } from 'json-schema-typed/draft-2020-12';
2
- /** Extension emitted on every relative import specifier in generated code. */
3
- export type ImportExtension = 'js' | 'ts';
4
- /**
5
- * Options for controlling how imports are collected.
6
- */
7
- type CollectImportsOptions = {
8
- /**
9
- * When true, only generate type-only imports (no parser function imports).
10
- * Use this when generating types-only files that do not include parser functions.
11
- */
12
- readonly typesOnly?: boolean;
13
- /**
14
- * The $ref path of the schema being generated (e.g. `#/$defs/encoding`).
15
- * When provided, any $ref that resolves to the same filename is excluded from
16
- * the import list, preventing a file from importing itself.
17
- */
18
- readonly selfRef?: string | undefined;
19
- /**
20
- * The filename this file is being written as, without extension. Takes
21
- * precedence over `selfRef` for self-import detection, and covers the case
22
- * `selfRef` cannot: the root document has no ref of its own, so a definition
23
- * whose name collides with the root type name (root `Contact` + `$defs.contact`)
24
- * used to make the root file import its own type from itself.
25
- */
26
- readonly selfFilename?: string | undefined;
27
- /**
28
- * The root schema document. When provided, URI refs that cannot be resolved
29
- * within the root schema's $defs are excluded from the import list, preventing
30
- * imports for external schemas that were never generated as files.
31
- */
32
- readonly rootSchema?: Record<string, unknown> | undefined;
33
- /**
34
- * Suffix appended to every type name derived from a `$ref`. Must match the
35
- * suffix used when generating the referenced files so imports resolve.
36
- * Defaults to `''` (no suffix).
37
- */
38
- readonly typeSuffix?: string;
39
- /**
40
- * Extension used on every relative import specifier. Defaults to `'js'`
41
- * (the TS NodeNext form); `'ts'` makes the output runnable under Node's
42
- * type stripping.
43
- */
44
- readonly importExt?: ImportExtension;
45
- /**
46
- * The file body this import list is being written above. When given, only the
47
- * `$ref` imports whose names the body actually spells are emitted, and one
48
- * whose parser is never called is narrowed to a type-only import.
49
- *
50
- * The walk below can only approximate what the emitters wrote: it stops at a
51
- * `$ref` the type emitter inlines *through*, and it cannot see a branch that
52
- * folded away. Asking the emitted text settles both directions, the way
53
- * `collectHelpers` already settles which runtime helpers a file needs.
54
- */
55
- readonly usedIn?: string | undefined;
56
- };
57
- /**
58
- * Collects all import statements needed for a schema by finding $ref references
59
- * that are directly used in the type definition (from properties, items, etc.).
60
- * Does not include refs from nested schema definitions.
61
- *
62
- * Generates both type imports and parser function imports for each $ref.
63
- * The parser imports allow validators to delegate validation to the referenced
64
- * schema's parser instead of inlining the validation logic.
65
- *
66
- * Also detects when helper functions (isObject) and validators (validateRecord,
67
- * validateArray) are needed based on the schema structure.
68
- *
69
- * @param schema - The JSON Schema to collect imports from
70
- * @param options - Optional settings to control import generation
71
- * @returns An array of import statements
72
- *
73
- * @example
74
- * ```ts
75
- * const schema = {
76
- * type: 'object',
77
- * properties: {
78
- * contact: { $ref: '#/$defs/contact' },
79
- * server: { $ref: '#/$defs/server' }
80
- * }
81
- * }
82
- * const imports = collectImports(schema)
83
- * // imports = [
84
- * // "import { type Contact, parseContact } from './contact';",
85
- * // "import { type Server, parseServer } from './server';"
86
- * // ]
87
- *
88
- * // With typesOnly, only type imports are generated:
89
- * const typeImports = collectImports(schema, { typesOnly: true })
90
- * // typeImports = [
91
- * // "import type { Contact } from './contact';",
92
- * // "import type { Server } from './server';"
93
- * // ]
94
- * ```
95
- */
96
- export declare const collectImports: (schema: JSONSchema, options?: CollectImportsOptions) => string[];
97
- /**
98
- * The type names a generated file will import for its `$ref`s — the same
99
- * dedup/skip rules as {@link collectImports}. Generators seed their private
100
- * sub-type naming with this set so a synthesized name (e.g. a root array's
101
- * `FooItem`) can never shadow an imported identifier.
102
- */
103
- export declare const collectImportTypeNames: (schema: JSONSchema, options?: CollectImportsOptions) => Set<string>;
104
- export {};
@@ -1,227 +0,0 @@
1
- import { identifierMentions } from "@amritk/helpers/identifier-mentions";
2
- import { readKey } from "@amritk/helpers/read-key";
3
- import { refToFilename } from "@amritk/helpers/ref-to-filename";
4
- import { refToName } from "@amritk/helpers/ref-to-name";
5
- import { referencedConditional } from "@amritk/helpers/referenced-conditional";
6
- import { resolveRef } from "@amritk/helpers/resolve-ref";
7
- import { hasAdditionalProperties, hasAllOf, hasAnyOf, hasItems, hasOneOf, hasRef, isSchemaObject } from "@amritk/helpers/schema-guards";
8
- const getImportPathForFilename = (filename, ext) => `./${filename}.${ext}`;
9
- const collectImports = (schema, options) => {
10
- const typesOnly = options?.typesOnly === true;
11
- const importExt = options?.importExt ?? "js";
12
- const importMap = /* @__PURE__ */ new Map();
13
- const mentions = options?.usedIn === void 0 ? () => true : identifierMentions(options.usedIn);
14
- for (const [filename, { typeName, typeOnly }] of collectImportTargets(schema, options)) {
15
- const importPath = getImportPathForFilename(filename, importExt);
16
- const values = typesOnly || typeOnly ? [] : [`parse${typeName}`, `validate${typeName}Shape`].filter((name) => mentions(name));
17
- const named = mentions(typeName);
18
- if (values.length === 0) {
19
- if (!named)
20
- continue;
21
- importMap.set(filename, `import type { ${typeName} } from '${importPath}';`);
22
- continue;
23
- }
24
- const specifiers = named ? [`type ${typeName}`, ...values] : values;
25
- importMap.set(filename, `import { ${specifiers.join(", ")} } from '${importPath}';`);
26
- }
27
- return Array.from(importMap.values()).sort();
28
- };
29
- const collectImportTypeNames = (schema, options) => {
30
- const names = /* @__PURE__ */ new Set();
31
- for (const [, target] of collectImportTargets(schema, options))
32
- names.add(target.typeName);
33
- return names;
34
- };
35
- const collectImportTargets = (schema, options) => {
36
- const selfFilename = options?.selfFilename ?? (options?.selfRef ? refToFilename(options.selfRef) : void 0);
37
- const rootSchema = options?.rootSchema;
38
- const typeSuffix = options?.typeSuffix;
39
- const refs = /* @__PURE__ */ new Set();
40
- const valueRefs = /* @__PURE__ */ new Set();
41
- let typeOnlyDepth = 0;
42
- const inlinedRefs = /* @__PURE__ */ new Set();
43
- const collectRefsFromAllOfMember = (entry) => {
44
- collectRefsFromValue(entry);
45
- const ref = isSchemaObject(entry) ? readKey(entry, "$ref") : void 0;
46
- if (typeof ref === "string" && inlinedRefs.has(ref))
47
- return;
48
- const inlined = referencedConditional(entry, rootSchema);
49
- if (inlined === void 0)
50
- return;
51
- if (typeof ref === "string")
52
- inlinedRefs.add(ref);
53
- typeOnlyDepth++;
54
- for (const arm of ["if", "then", "else"]) {
55
- if (Object.hasOwn(inlined, arm))
56
- collectRefsFromValue(readKey(inlined, arm));
57
- }
58
- typeOnlyDepth--;
59
- };
60
- const collectRefsFromValue = (value) => {
61
- if (typeof value !== "object" || value === null) {
62
- return;
63
- }
64
- if (Array.isArray(value)) {
65
- for (const item of value) {
66
- collectRefsFromValue(item);
67
- }
68
- return;
69
- }
70
- const record = value;
71
- if (hasRef(record)) {
72
- const ref = record.$ref;
73
- const isInternal = ref.startsWith("#");
74
- const isUri = ref.startsWith("http://") || ref.startsWith("https://");
75
- const isPropertyFragment = isUri && ref.includes("#/properties/");
76
- if (isInternal || isUri && !isPropertyFragment) {
77
- refs.add(ref);
78
- if (typeOnlyDepth === 0)
79
- valueRefs.add(ref);
80
- }
81
- return;
82
- }
83
- for (const keyword of ["prefixItems", "items"]) {
84
- const positions = Object.hasOwn(record, keyword) ? record[keyword] : void 0;
85
- if (!Array.isArray(positions))
86
- continue;
87
- typeOnlyDepth++;
88
- for (const item of positions) {
89
- collectRefsFromValue(item);
90
- }
91
- if (Object.hasOwn(record, "additionalItems"))
92
- collectRefsFromValue(record["additionalItems"]);
93
- typeOnlyDepth--;
94
- }
95
- if (hasAdditionalProperties(record) && hasRef(record.additionalProperties)) {
96
- collectRefsFromValue(record.additionalProperties);
97
- return;
98
- }
99
- if (record.type === "array" && hasItems(record) && !Array.isArray(record.items) && hasRef(record.items)) {
100
- collectRefsFromValue(record.items);
101
- return;
102
- }
103
- if (Object.hasOwn(record, "properties") && typeof record.properties === "object" && record.properties !== null) {
104
- for (const value2 of Object.values(record.properties)) {
105
- collectRefsFromValue(value2);
106
- }
107
- }
108
- if (hasOneOf(record)) {
109
- for (const item of record.oneOf) {
110
- collectRefsFromValue(item);
111
- }
112
- }
113
- if (hasAnyOf(record)) {
114
- for (const item of record.anyOf) {
115
- collectRefsFromValue(item);
116
- }
117
- }
118
- if (hasAllOf(record)) {
119
- for (const item of record.allOf) {
120
- collectRefsFromAllOfMember(item);
121
- }
122
- }
123
- if (hasItems(record) && !Array.isArray(record.items)) {
124
- collectRefsFromValue(record.items);
125
- }
126
- if (hasAdditionalProperties(record)) {
127
- collectRefsFromValue(record.additionalProperties);
128
- }
129
- if (Object.hasOwn(record, "patternProperties") && typeof record.patternProperties === "object" && record.patternProperties !== null) {
130
- for (const value2 of Object.values(record.patternProperties)) {
131
- collectRefsFromValue(value2);
132
- }
133
- }
134
- if (Object.hasOwn(record, "if")) {
135
- collectRefsFromValue(record.if);
136
- }
137
- if (Object.hasOwn(record, "then")) {
138
- collectRefsFromValue(record.then);
139
- }
140
- if (Object.hasOwn(record, "else")) {
141
- collectRefsFromValue(record.else);
142
- }
143
- };
144
- if (typeof schema === "object" && schema !== null && hasRef(schema)) {
145
- const ref = schema.$ref;
146
- const isInternal = ref.startsWith("#");
147
- const isUri = ref.startsWith("http://") || ref.startsWith("https://");
148
- const isPropertyFragment = isUri && ref.includes("#/properties/");
149
- if (isInternal || isUri && !isPropertyFragment) {
150
- refs.add(ref);
151
- valueRefs.add(ref);
152
- }
153
- }
154
- if (typeof schema === "object" && schema !== null && Object.hasOwn(schema, "properties") && typeof schema.properties === "object" && schema.properties !== null) {
155
- for (const value of Object.values(schema.properties)) {
156
- collectRefsFromValue(value);
157
- }
158
- }
159
- if (typeof schema === "object" && schema !== null && Object.hasOwn(schema, "additionalProperties")) {
160
- collectRefsFromValue(schema.additionalProperties);
161
- }
162
- if (typeof schema === "object" && schema !== null && Object.hasOwn(schema, "patternProperties") && typeof schema.patternProperties === "object" && schema.patternProperties !== null) {
163
- for (const value of Object.values(schema.patternProperties)) {
164
- collectRefsFromValue(value);
165
- }
166
- }
167
- if (typeof schema === "object" && schema !== null && hasItems(schema) && !Array.isArray(schema.items)) {
168
- collectRefsFromValue(schema.items);
169
- }
170
- if (typeof schema === "object" && schema !== null) {
171
- const record = schema;
172
- for (const keyword of ["prefixItems", "items"]) {
173
- const positions = Object.hasOwn(record, keyword) ? record[keyword] : void 0;
174
- if (!Array.isArray(positions))
175
- continue;
176
- typeOnlyDepth++;
177
- for (const item of positions)
178
- collectRefsFromValue(item);
179
- if (Object.hasOwn(record, "additionalItems"))
180
- collectRefsFromValue(record["additionalItems"]);
181
- typeOnlyDepth--;
182
- }
183
- }
184
- if (typeof schema === "object" && schema !== null && hasOneOf(schema)) {
185
- for (const item of schema.oneOf) {
186
- collectRefsFromValue(item);
187
- }
188
- }
189
- if (typeof schema === "object" && schema !== null && hasAnyOf(schema)) {
190
- for (const item of schema.anyOf) {
191
- collectRefsFromValue(item);
192
- }
193
- }
194
- if (typeof schema === "object" && schema !== null && hasAllOf(schema)) {
195
- for (const item of schema.allOf) {
196
- collectRefsFromAllOfMember(item);
197
- }
198
- }
199
- if (typeof schema === "object" && schema !== null && Object.hasOwn(schema, "if")) {
200
- collectRefsFromValue(schema.if);
201
- }
202
- if (typeof schema === "object" && schema !== null && Object.hasOwn(schema, "then")) {
203
- collectRefsFromValue(schema.then);
204
- }
205
- if (typeof schema === "object" && schema !== null && Object.hasOwn(schema, "else")) {
206
- collectRefsFromValue(schema.else);
207
- }
208
- const targets = /* @__PURE__ */ new Map();
209
- for (const ref of refs) {
210
- if (rootSchema !== void 0 && (ref.startsWith("http://") || ref.startsWith("https://"))) {
211
- if (!resolveRef(ref, rootSchema))
212
- continue;
213
- }
214
- const typeName = refToName(ref, typeSuffix);
215
- const filename = refToFilename(ref);
216
- if (selfFilename !== void 0 && filename === selfFilename) {
217
- continue;
218
- }
219
- const typeOnly = !valueRefs.has(ref) && (targets.get(filename)?.typeOnly ?? true);
220
- targets.set(filename, { typeName, typeOnly });
221
- }
222
- return targets;
223
- };
224
- export {
225
- collectImportTypeNames,
226
- collectImports
227
- };
@@ -1,6 +0,0 @@
1
- import type { JSONSchema } from 'json-schema-typed/draft-2020-12';
2
- /**
3
- * Attempts to find a discriminator property that can be used to distinguish between union types.
4
- * Returns the property name if a suitable discriminator is found, otherwise null.
5
- */
6
- export declare const findDiscriminator: (schemas: readonly JSONSchema[]) => string | null;