@amritk/generate-parsers 0.9.0 โ 0.10.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.
- package/README.md +10 -0
- package/dist/generators/build-schema.d.ts +5 -1
- package/dist/generators/build-schema.js +6 -1
- package/dist/generators/generate-files.d.ts +9 -0
- package/dist/generators/generate-files.js +3 -1
- package/dist/generators/generate-parser-function.d.ts +11 -1
- package/dist/generators/generate-parser-function.js +37 -25
- package/package.json +7 -2
package/README.md
CHANGED
|
@@ -134,6 +134,16 @@ Returns: `Promise<GeneratedFile[]>`.
|
|
|
134
134
|
<tr>
|
|
135
135
|
<td colspan="5">Generate parsers that throw on type/shape mismatches (wrong type, missing required property, enum/pattern/min/max violations) instead of coercing invalid input to default values. When a schema sets additionalProperties: false, undeclared keys throw too; otherwise they are still allowed.</td>
|
|
136
136
|
</tr>
|
|
137
|
+
<tr>
|
|
138
|
+
<td>๐งน <code>stripUnknown</code></td>
|
|
139
|
+
<td>โ</td>
|
|
140
|
+
<td><code>boolean</code></td>
|
|
141
|
+
<td align="center">โ</td>
|
|
142
|
+
<td align="center"><code>false</code></td>
|
|
143
|
+
</tr>
|
|
144
|
+
<tr>
|
|
145
|
+
<td colspan="5">Build each parser's result from the schema's declared properties only, silently dropping undeclared input keys at every nesting level (zod's .strip()). Extras are never a validation error, so this composes with strict (which still throws on wrong types and missing required properties) and yields to additionalProperties: false, which rejects rather than strips in strict mode.</td>
|
|
146
|
+
</tr>
|
|
137
147
|
</tbody>
|
|
138
148
|
</table>
|
|
139
149
|
<!-- config-table-end -->
|
|
@@ -38,6 +38,10 @@ export type GeneratedFile = {
|
|
|
38
38
|
* directory while the helper sources are emitted once at the output root.
|
|
39
39
|
* @param readonly - When true, every property, array, and record in the generated type
|
|
40
40
|
* definitions is emitted as `readonly`.
|
|
41
|
+
* @param stripUnknown - When true, the generated parsers build their result from declared
|
|
42
|
+
* properties only, silently dropping undeclared input keys at every nesting level (zod's
|
|
43
|
+
* `.strip()`) without treating extras as a validation error. Composes with `strict` and
|
|
44
|
+
* yields to `additionalProperties: false` (which rejects rather than strips in strict mode).
|
|
41
45
|
* @param typeSuffix - Suffix appended to every type/parser name derived from a `$ref`
|
|
42
46
|
* (e.g. `'Object'` โ `ContactObject`). Defaults to `''` (no suffix). The root type name
|
|
43
47
|
* is used verbatim and is not affected by this suffix.
|
|
@@ -73,4 +77,4 @@ export type GeneratedFile = {
|
|
|
73
77
|
* });
|
|
74
78
|
* ```
|
|
75
79
|
*/
|
|
76
|
-
export declare const buildSchema: (rootSchema: JSONSchema, rootTypeName: string, extensions?: SchemaExtensions, typesOnly?: boolean, logWarnings?: boolean, strict?: boolean, helpersMode?: HelpersMode, helpersImportPrefix?: string, readonly?: boolean, typeSuffix?: string) => Promise<GeneratedFile[]>;
|
|
80
|
+
export declare const buildSchema: (rootSchema: JSONSchema, rootTypeName: string, extensions?: SchemaExtensions, typesOnly?: boolean, logWarnings?: boolean, strict?: boolean, helpersMode?: HelpersMode, helpersImportPrefix?: string, readonly?: boolean, stripUnknown?: boolean, typeSuffix?: string) => Promise<GeneratedFile[]>;
|
|
@@ -43,6 +43,10 @@ const readHelperSource = async (helper) => {
|
|
|
43
43
|
* directory while the helper sources are emitted once at the output root.
|
|
44
44
|
* @param readonly - When true, every property, array, and record in the generated type
|
|
45
45
|
* definitions is emitted as `readonly`.
|
|
46
|
+
* @param stripUnknown - When true, the generated parsers build their result from declared
|
|
47
|
+
* properties only, silently dropping undeclared input keys at every nesting level (zod's
|
|
48
|
+
* `.strip()`) without treating extras as a validation error. Composes with `strict` and
|
|
49
|
+
* yields to `additionalProperties: false` (which rejects rather than strips in strict mode).
|
|
46
50
|
* @param typeSuffix - Suffix appended to every type/parser name derived from a `$ref`
|
|
47
51
|
* (e.g. `'Object'` โ `ContactObject`). Defaults to `''` (no suffix). The root type name
|
|
48
52
|
* is used verbatim and is not affected by this suffix.
|
|
@@ -78,7 +82,7 @@ const readHelperSource = async (helper) => {
|
|
|
78
82
|
* });
|
|
79
83
|
* ```
|
|
80
84
|
*/
|
|
81
|
-
export const buildSchema = async (rootSchema, rootTypeName, extensions, typesOnly, logWarnings, strict, helpersMode = 'package', helpersImportPrefix = './', readonly = false, typeSuffix = '') => {
|
|
85
|
+
export const buildSchema = async (rootSchema, rootTypeName, extensions, typesOnly, logWarnings, strict, helpersMode = 'package', helpersImportPrefix = './', readonly = false, stripUnknown = false, typeSuffix = '') => {
|
|
82
86
|
const files = [];
|
|
83
87
|
const usedHelpers = new Set();
|
|
84
88
|
walkRefGraph(rootSchema, rootTypeName, { typeSuffix }, (node) => {
|
|
@@ -99,6 +103,7 @@ export const buildSchema = async (rootSchema, rootTypeName, extensions, typesOnl
|
|
|
99
103
|
...(node.ref !== undefined ? { selfRef: node.ref } : {}),
|
|
100
104
|
...(logWarnings !== undefined ? { logWarnings } : {}),
|
|
101
105
|
...(strict !== undefined ? { strict } : {}),
|
|
106
|
+
...(stripUnknown ? { stripUnknown } : {}),
|
|
102
107
|
});
|
|
103
108
|
files.push({ filename: `${node.filename}.ts`, content: result.content });
|
|
104
109
|
for (const helper of result.usedHelpers)
|
|
@@ -30,6 +30,15 @@ type GenerateFileOptions = {
|
|
|
30
30
|
* of coercing invalid input to default values.
|
|
31
31
|
*/
|
|
32
32
|
readonly strict?: boolean;
|
|
33
|
+
/**
|
|
34
|
+
* When true, the generated parser builds its result from declared properties
|
|
35
|
+
* only, silently dropping undeclared input keys at every nesting level (zod's
|
|
36
|
+
* `.strip()`), without treating extras as a validation error. Composes with
|
|
37
|
+
* `strict` (still throws on wrong types / missing required properties) and
|
|
38
|
+
* yields to `additionalProperties: false` (which rejects rather than strips in
|
|
39
|
+
* strict mode).
|
|
40
|
+
*/
|
|
41
|
+
readonly stripUnknown?: boolean;
|
|
33
42
|
/**
|
|
34
43
|
* Controls how runtime helpers are referenced.
|
|
35
44
|
* - `'package'` (default): emit imports from `@amritk/helpers/...`.
|
|
@@ -51,13 +51,15 @@ export const generateFile = (schema, typeName, options) => {
|
|
|
51
51
|
}
|
|
52
52
|
return { content: result + typeDefinition, usedHelpers: new Set() };
|
|
53
53
|
}
|
|
54
|
+
const stripUnknown = options?.stripUnknown ?? false;
|
|
54
55
|
const parserFunction = generateParserFunction(schema, typeName, {
|
|
55
56
|
useRefImports: true,
|
|
56
57
|
typeSuffix,
|
|
57
58
|
...(options?.logWarnings !== undefined ? { logWarnings: options.logWarnings } : {}),
|
|
58
59
|
...(options?.strict !== undefined ? { strict: options.strict } : {}),
|
|
60
|
+
...(options?.stripUnknown !== undefined ? { stripUnknown: options.stripUnknown } : {}),
|
|
59
61
|
});
|
|
60
|
-
const shapeValidator = generateShapeValidator(schema, typeName, true, typeSuffix);
|
|
62
|
+
const shapeValidator = generateShapeValidator(schema, typeName, true, typeSuffix, true, stripUnknown);
|
|
61
63
|
const combinedFunctions = `${shapeValidator}\n\n${parserFunction}`;
|
|
62
64
|
const helpers = collectHelpers(combinedFunctions, helpersMode, options?.helpersImportPrefix);
|
|
63
65
|
const imports = [...collectImports(schema, { selfRef, rootSchema, typeSuffix }), ...helpers.imports];
|
|
@@ -21,6 +21,16 @@ type GenerateParserOptions = {
|
|
|
21
21
|
* undeclared keys throw too; otherwise they are still allowed.
|
|
22
22
|
*/
|
|
23
23
|
readonly strict?: boolean;
|
|
24
|
+
/**
|
|
25
|
+
* When true, the generated parser builds its result from the schema's declared
|
|
26
|
+
* properties only, silently dropping any undeclared input key at every nesting
|
|
27
|
+
* level (zod's `.strip()`). Unlike `additionalProperties: false`, extras are
|
|
28
|
+
* never a validation error โ this composes with `strict`: `strict + stripUnknown`
|
|
29
|
+
* still throws on wrong types and missing required properties but strips extras
|
|
30
|
+
* instead of throwing on them. When the schema *also* sets
|
|
31
|
+
* `additionalProperties: false`, rejecting wins over stripping in strict mode.
|
|
32
|
+
*/
|
|
33
|
+
readonly stripUnknown?: boolean;
|
|
24
34
|
/**
|
|
25
35
|
* Suffix appended to every type/parser name derived from a `$ref`. Must match
|
|
26
36
|
* the suffix used when generating the referenced files. Defaults to `''`.
|
|
@@ -55,5 +65,5 @@ export declare const shapeValidatorFunctionName: (typeName: string) => string;
|
|
|
55
65
|
* in additionalProperties). The stub is safe: parents calling it will fall
|
|
56
66
|
* through to the slow path, matching the pre-deep-fast-path behavior.
|
|
57
67
|
*/
|
|
58
|
-
export declare const generateShapeValidator: (schema: JSONSchema, typeName: string, useRefImports: boolean, suffix?: string, exported?: boolean) => string;
|
|
68
|
+
export declare const generateShapeValidator: (schema: JSONSchema, typeName: string, useRefImports: boolean, suffix?: string, exported?: boolean, stripUnknown?: boolean) => string;
|
|
59
69
|
export {};
|
|
@@ -530,7 +530,7 @@ const shouldCacheVariable = (propSchema, _canFastPath, _useRefImports) => {
|
|
|
530
530
|
* - Fast path that returns input directly when all properties are already valid
|
|
531
531
|
* - Slow path with optimized expressions
|
|
532
532
|
*/
|
|
533
|
-
const generateObjectParser = (schema, typeName, useRefImports, suffix, logWarnings, strict, exported = true) => {
|
|
533
|
+
const generateObjectParser = (schema, typeName, useRefImports, suffix, logWarnings, strict, exported = true, stripUnknown = false) => {
|
|
534
534
|
const functionName = generateParserName(typeName);
|
|
535
535
|
const exportPrefix = exported ? 'export ' : '';
|
|
536
536
|
if (!hasProperties(schema)) {
|
|
@@ -549,16 +549,22 @@ const generateObjectParser = (schema, typeName, useRefImports, suffix, logWarnin
|
|
|
549
549
|
for (const [key, subName] of subTypeNames) {
|
|
550
550
|
const propSchema = schema.properties[key];
|
|
551
551
|
preamble.push(`type ${subName} = ${typeName}[${JSON.stringify(key)}];`);
|
|
552
|
-
preamble.push(generateShapeValidator(propSchema, subName, useRefImports, suffix, false));
|
|
553
|
-
preamble.push(generateObjectParser(propSchema, subName, useRefImports, suffix, logWarnings, strict, false));
|
|
552
|
+
preamble.push(generateShapeValidator(propSchema, subName, useRefImports, suffix, false, stripUnknown));
|
|
553
|
+
preamble.push(generateObjectParser(propSchema, subName, useRefImports, suffix, logWarnings, strict, false, stripUnknown));
|
|
554
554
|
}
|
|
555
555
|
// additionalProperties: false โ the per-key "is this undeclared" test inlines
|
|
556
556
|
// `!==` comparisons for a short key list and hoists a Set only for a long one
|
|
557
557
|
// (see unknownKeyCheck). The predicate form is shared by the fast path and the
|
|
558
558
|
// shape validator; strict mode throws with the offending key.
|
|
559
|
+
// `additionalProperties: false` strips *and rejects* extras; `stripUnknown`
|
|
560
|
+
// only strips them. Both build the result from declared properties alone, so
|
|
561
|
+
// they share the same machinery (`stripKeys`): drop the `...input` spread and
|
|
562
|
+
// gate the `{ ...input }` fast path on the known-keys predicate. Only the real
|
|
563
|
+
// `strictKeys` makes an extra a hard error (the throw block further down).
|
|
559
564
|
const strictKeys = hasStrictKeys(schema);
|
|
565
|
+
const stripKeys = strictKeys || stripUnknown;
|
|
560
566
|
const strictKeyCheck = unknownKeyCheck(properties.map(([key]) => key), `_knownKeys${typeName}`);
|
|
561
|
-
if (
|
|
567
|
+
if (stripKeys) {
|
|
562
568
|
for (const declaration of strictKeyCheck.declarations) {
|
|
563
569
|
preamble.push(`${declaration};`);
|
|
564
570
|
}
|
|
@@ -622,10 +628,11 @@ const generateObjectParser = (schema, typeName, useRefImports, suffix, logWarnin
|
|
|
622
628
|
}
|
|
623
629
|
}
|
|
624
630
|
}
|
|
625
|
-
// The fast path returns `{ ...input }`, so
|
|
626
|
-
// it must only fire when no undeclared
|
|
627
|
-
//
|
|
628
|
-
|
|
631
|
+
// The fast path returns `{ ...input }`, which preserves extras โ so when we're
|
|
632
|
+
// stripping it must only fire when no undeclared key is present. The exception
|
|
633
|
+
// is strict + additionalProperties: false, where the throw block above already
|
|
634
|
+
// rejected any extra, so the fast path is safe to take unconditionally.
|
|
635
|
+
if (stripKeys && !(strict && strictKeys)) {
|
|
629
636
|
fastPathChecks.push(`_hasOnlyKnownKeys${typeName}(input)`);
|
|
630
637
|
}
|
|
631
638
|
// Second pass: generate variable declarations only for properties that need them
|
|
@@ -655,10 +662,11 @@ const generateObjectParser = (schema, typeName, useRefImports, suffix, logWarnin
|
|
|
655
662
|
lines.push(` if (${fastPathExpr}) return { ...input } as ${typeName};`);
|
|
656
663
|
}
|
|
657
664
|
// Generate slow-path object construction. The input spread preserves
|
|
658
|
-
// undeclared keys, so it is dropped
|
|
659
|
-
//
|
|
665
|
+
// undeclared keys, so it is dropped whenever we're stripping (either
|
|
666
|
+
// additionalProperties: false or stripUnknown) โ building from the declared
|
|
667
|
+
// properties alone strips the extras from the result.
|
|
660
668
|
const objectLines = [];
|
|
661
|
-
if (!
|
|
669
|
+
if (!stripKeys) {
|
|
662
670
|
objectLines.push(' ...input,');
|
|
663
671
|
}
|
|
664
672
|
// Spread allOf $ref parsers so their field coercions are applied before
|
|
@@ -811,7 +819,7 @@ ${loopLines.join('\n')}
|
|
|
811
819
|
* Generates a parser for schemas that have both properties AND patternProperties.
|
|
812
820
|
* Parses the known properties first, then iterates remaining keys to match patterns.
|
|
813
821
|
*/
|
|
814
|
-
const generateCombinedObjectParser = (schema, typeName, useRefImports, suffix, logWarnings, strict) => {
|
|
822
|
+
const generateCombinedObjectParser = (schema, typeName, useRefImports, suffix, logWarnings, strict, stripUnknown = false) => {
|
|
815
823
|
const functionName = generateParserName(typeName);
|
|
816
824
|
const entries = generatePropertyEntries(schema, useRefImports, suffix);
|
|
817
825
|
// Build the known property lines for the initial object
|
|
@@ -823,7 +831,7 @@ const generateCombinedObjectParser = (schema, typeName, useRefImports, suffix, l
|
|
|
823
831
|
});
|
|
824
832
|
// Find the first pattern with a $ref for parser delegation
|
|
825
833
|
if (!isSchemaObject(schema) || !('patternProperties' in schema)) {
|
|
826
|
-
return generateObjectParser(schema, typeName, useRefImports, suffix, logWarnings, strict);
|
|
834
|
+
return generateObjectParser(schema, typeName, useRefImports, suffix, logWarnings, strict, true, stripUnknown);
|
|
827
835
|
}
|
|
828
836
|
const patternProps = schema.patternProperties;
|
|
829
837
|
const patterns = Object.entries(patternProps);
|
|
@@ -837,7 +845,7 @@ const generateCombinedObjectParser = (schema, typeName, useRefImports, suffix, l
|
|
|
837
845
|
return generateStrictCombinedParser(schema, typeName, functionName, propertyLines, patterns, useRefImports, suffix, strict);
|
|
838
846
|
}
|
|
839
847
|
if (!refPattern || !useRefImports) {
|
|
840
|
-
return generateObjectParser(schema, typeName, useRefImports, suffix, logWarnings, strict);
|
|
848
|
+
return generateObjectParser(schema, typeName, useRefImports, suffix, logWarnings, strict, true, stripUnknown);
|
|
841
849
|
}
|
|
842
850
|
const [pattern, patternSchema] = refPattern;
|
|
843
851
|
const ref = patternSchema.$ref;
|
|
@@ -1016,7 +1024,7 @@ ${notObjectBranch}
|
|
|
1016
1024
|
* This always generates parser calls regardless of useRefImports setting,
|
|
1017
1025
|
* because conditional logic requires delegating to the appropriate parser.
|
|
1018
1026
|
*/
|
|
1019
|
-
const generateConditionalParser = (schema, typeName, suffix) => {
|
|
1027
|
+
const generateConditionalParser = (schema, typeName, suffix, stripUnknown = false) => {
|
|
1020
1028
|
const functionName = generateParserName(typeName);
|
|
1021
1029
|
// Extract the condition and branches
|
|
1022
1030
|
const ifSchema = schema.if;
|
|
@@ -1031,7 +1039,7 @@ const generateConditionalParser = (schema, typeName, suffix) => {
|
|
|
1031
1039
|
// regular object parser from the merged property set.
|
|
1032
1040
|
const mergedSchema = getConditionalObjectSchema(schema);
|
|
1033
1041
|
if (mergedSchema) {
|
|
1034
|
-
return generateObjectParser(mergedSchema, typeName, false, suffix);
|
|
1042
|
+
return generateObjectParser(mergedSchema, typeName, false, suffix, false, false, true, stripUnknown);
|
|
1035
1043
|
}
|
|
1036
1044
|
return generateEmptyObjectParser(typeName);
|
|
1037
1045
|
}
|
|
@@ -1045,7 +1053,7 @@ const generateConditionalParser = (schema, typeName, suffix) => {
|
|
|
1045
1053
|
// Condition is not a $ref check โ flatten into an object parser
|
|
1046
1054
|
const mergedSchema = getConditionalObjectSchema(schema);
|
|
1047
1055
|
if (mergedSchema) {
|
|
1048
|
-
return generateObjectParser(mergedSchema, typeName, false, suffix);
|
|
1056
|
+
return generateObjectParser(mergedSchema, typeName, false, suffix, false, false, true, stripUnknown);
|
|
1049
1057
|
}
|
|
1050
1058
|
return generateEmptyObjectParser(typeName);
|
|
1051
1059
|
}
|
|
@@ -1140,6 +1148,7 @@ const selectParserStrategy = (schema, typeName, options) => {
|
|
|
1140
1148
|
const useRefImports = options?.useRefImports ?? false;
|
|
1141
1149
|
const logWarnings = options?.logWarnings ?? false;
|
|
1142
1150
|
const strict = options?.strict ?? false;
|
|
1151
|
+
const stripUnknown = options?.stripUnknown ?? false;
|
|
1143
1152
|
const suffix = options?.typeSuffix ?? '';
|
|
1144
1153
|
// Special case for the self-referential JSON Schema meta-schema type (e.g.
|
|
1145
1154
|
// `Schema` / `SchemaObject`) - it can be any JSON Schema.
|
|
@@ -1156,24 +1165,24 @@ const selectParserStrategy = (schema, typeName, options) => {
|
|
|
1156
1165
|
// This generates a parser that handles known properties and also iterates
|
|
1157
1166
|
// pattern-matched keys (e.g. responses with "default" + "200", "4XX").
|
|
1158
1167
|
if (hasProperties(schema) && isSchemaObject(schema) && 'patternProperties' in schema) {
|
|
1159
|
-
return generateCombinedObjectParser(schema, typeName, useRefImports, suffix, logWarnings, strict);
|
|
1168
|
+
return generateCombinedObjectParser(schema, typeName, useRefImports, suffix, logWarnings, strict, stripUnknown);
|
|
1160
1169
|
}
|
|
1161
1170
|
// Handle schemas that have explicit properties โ generate a full object parser.
|
|
1162
1171
|
// This intentionally runs before if/then checks so that schemas with both
|
|
1163
1172
|
// properties AND conditional keywords use all declared properties rather than
|
|
1164
1173
|
// only the if/then fragment.
|
|
1165
1174
|
if (hasProperties(schema)) {
|
|
1166
|
-
return generateObjectParser(schema, typeName, useRefImports, suffix, logWarnings, strict);
|
|
1175
|
+
return generateObjectParser(schema, typeName, useRefImports, suffix, logWarnings, strict, true, stripUnknown);
|
|
1167
1176
|
}
|
|
1168
1177
|
// Handle conditional schemas (if/then/else) for schemas without explicit properties.
|
|
1169
1178
|
if (isSchemaObject(schema) && 'if' in schema && 'then' in schema && 'else' in schema) {
|
|
1170
|
-
return generateConditionalParser(schema, typeName, suffix);
|
|
1179
|
+
return generateConditionalParser(schema, typeName, suffix, stripUnknown);
|
|
1171
1180
|
}
|
|
1172
1181
|
// Handle conditional schemas that only define if/then object fragments.
|
|
1173
1182
|
// We flatten the fragments into a regular object parser.
|
|
1174
1183
|
const conditionalObjectSchema = getConditionalObjectSchema(schema);
|
|
1175
1184
|
if (conditionalObjectSchema) {
|
|
1176
|
-
return generateObjectParser(conditionalObjectSchema, typeName, useRefImports, suffix, logWarnings, strict);
|
|
1185
|
+
return generateObjectParser(conditionalObjectSchema, typeName, useRefImports, suffix, logWarnings, strict, true, stripUnknown);
|
|
1177
1186
|
}
|
|
1178
1187
|
// Handle non-object schemas with type-appropriate validation (no properties, no conditionals)
|
|
1179
1188
|
if (!isObjectLikeSchema) {
|
|
@@ -1230,7 +1239,7 @@ export const shapeValidatorFunctionName = (typeName) => shapeValidatorName(typeN
|
|
|
1230
1239
|
* in additionalProperties). The stub is safe: parents calling it will fall
|
|
1231
1240
|
* through to the slow path, matching the pre-deep-fast-path behavior.
|
|
1232
1241
|
*/
|
|
1233
|
-
export const generateShapeValidator = (schema, typeName, useRefImports, suffix = '', exported = true) => {
|
|
1242
|
+
export const generateShapeValidator = (schema, typeName, useRefImports, suffix = '', exported = true, stripUnknown = false) => {
|
|
1234
1243
|
const fnName = shapeValidatorName(typeName);
|
|
1235
1244
|
const exportPrefix = exported ? 'export ' : '';
|
|
1236
1245
|
const stub = `${exportPrefix}const ${fnName} = (_input: unknown): boolean => false;`;
|
|
@@ -1253,9 +1262,12 @@ export const generateShapeValidator = (schema, typeName, useRefImports, suffix =
|
|
|
1253
1262
|
// Same deterministic naming as the parser's sub-parser generation, so the
|
|
1254
1263
|
// referenced private shape predicates exist in the same file.
|
|
1255
1264
|
const subTypeNames = collectInlineObjectProperties(schema, typeName);
|
|
1256
|
-
//
|
|
1257
|
-
//
|
|
1258
|
-
|
|
1265
|
+
// When the parser strips extras (additionalProperties: false or stripUnknown),
|
|
1266
|
+
// an input carrying an undeclared key is *not* fast-path eligible โ the parser
|
|
1267
|
+
// would strip it rather than return `{ ...input }` โ so the shape only matches
|
|
1268
|
+
// when every key is declared. (The `_hasOnlyKnownKeys` predicate this calls is
|
|
1269
|
+
// emitted by the parser under the same `stripKeys` condition.)
|
|
1270
|
+
const strictKeysGuard = hasStrictKeys(schema) || stripUnknown ? `\n if (!_hasOnlyKnownKeys${typeName}(input)) return false;` : '';
|
|
1259
1271
|
const checks = [];
|
|
1260
1272
|
for (const [key, propSchema] of properties) {
|
|
1261
1273
|
// Records of refs require iterating every value โ too expensive for the fast path.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@amritk/generate-parsers",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.10.0",
|
|
4
4
|
"description": "Generate TypeScript parsers and type definitions from JSON Schemas.",
|
|
5
5
|
"module": "./dist/index.js",
|
|
6
6
|
"type": "module",
|
|
@@ -32,7 +32,8 @@
|
|
|
32
32
|
"build": "tsgo -p tsconfig.build.json && tsc-alias -p tsconfig.build.json -f",
|
|
33
33
|
"types:check": "tsgo -p . --noEmit",
|
|
34
34
|
"test": "NODE_ENV=production vitest run --root ../.. generate-parsers",
|
|
35
|
-
"generate-readme": "bun run ./scripts/generate-readme.ts"
|
|
35
|
+
"generate-readme": "bun run ./scripts/generate-readme.ts",
|
|
36
|
+
"bench": "bun --conditions development ./bench/run.ts"
|
|
36
37
|
},
|
|
37
38
|
"imports": {
|
|
38
39
|
"#generators/*": "./src/generators/*.ts",
|
|
@@ -49,5 +50,9 @@
|
|
|
49
50
|
"json-schema-typed": "^8.0.1",
|
|
50
51
|
"@amritk/helpers": "0.10.0",
|
|
51
52
|
"@amritk/generate-markdown": "0.2.4"
|
|
53
|
+
},
|
|
54
|
+
"devDependencies": {
|
|
55
|
+
"@sinclair/typebox": "^0.34.49",
|
|
56
|
+
"zod": "^4.4.3"
|
|
52
57
|
}
|
|
53
58
|
}
|