@amritk/generate-parsers 0.16.2 → 0.17.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/LICENSE +21 -0
- package/dist/generators/assert-supported-keywords.js +45 -72
- package/dist/generators/build-schema.js +56 -168
- package/dist/generators/generate-default-from-pattern.js +24 -31
- package/dist/generators/generate-discriminated-union-validation.js +27 -47
- package/dist/generators/generate-enum-check.js +27 -61
- package/dist/generators/generate-files.js +54 -83
- package/dist/generators/generate-non-discriminated-union-validation.js +24 -26
- package/dist/generators/generate-parser-function.d.ts +12 -0
- package/dist/generators/generate-parser-function.js +1132 -1711
- package/dist/generators/generate-schema-checks.js +216 -250
- package/dist/generators/generate-strict-assertion.js +311 -447
- package/dist/generators/generate-type-checks.js +287 -460
- package/dist/generators/generate-validation-expression.js +300 -439
- package/dist/generators/subschema-match.js +201 -266
- package/dist/helpers/apply-schema-extensions.js +18 -49
- package/dist/helpers/collect-helpers.js +58 -71
- package/dist/helpers/collect-imports.js +161 -237
- package/dist/helpers/find-discriminator.js +23 -29
- package/dist/helpers/get-default-value.js +76 -96
- package/dist/helpers/get-discriminator-value.js +16 -17
- package/dist/index.js +4 -1
- package/package.json +6 -6
|
@@ -1,487 +1,351 @@
|
|
|
1
|
-
import { escapeRegexPattern } from
|
|
2
|
-
import { getMjstInstanceOf, getMjstPrimitive } from
|
|
3
|
-
import { multipleOfFailExpr } from
|
|
4
|
-
import { quoteJsString } from
|
|
5
|
-
import { resolveRef } from
|
|
6
|
-
import { safeAccessor } from
|
|
7
|
-
import { hasConst, hasDependentRequired, hasEnum, hasExclusiveMaximum, hasExclusiveMinimum, hasItems, hasMaxItems, hasMaximum, hasMaxLength, hasMinItems, hasMinimum, hasMinLength, hasMultipleOf, hasPattern, hasProperties, hasPropertyNames, hasRef, hasRequired, hasType, hasUniqueItems, isSchemaObject
|
|
8
|
-
import { generateEnumCheck } from
|
|
9
|
-
import { canEnforceUnion, generateUnionCheck, getUnionBranches, isInlineObjectProperty } from
|
|
10
|
-
import { getPrefixItems, prefixItemsCapsLength, scalarItemTypeCheck } from
|
|
11
|
-
import { subschemaMatchExpr } from
|
|
12
|
-
/**
|
|
13
|
-
* Returns the inline condition that is true when `accessor` is the wrong type
|
|
14
|
-
* for the given JSON Schema primitive type.
|
|
15
|
-
*/
|
|
1
|
+
import { escapeRegexPattern } from "@amritk/helpers/escape-regex-pattern";
|
|
2
|
+
import { getMjstInstanceOf, getMjstPrimitive } from "@amritk/helpers/mjst-extension";
|
|
3
|
+
import { multipleOfFailExpr } from "@amritk/helpers/multiple-of-check";
|
|
4
|
+
import { quoteJsString } from "@amritk/helpers/quote-js-string";
|
|
5
|
+
import { resolveRef } from "@amritk/helpers/resolve-ref";
|
|
6
|
+
import { safeAccessor } from "@amritk/helpers/safe-accessor";
|
|
7
|
+
import { hasConst, hasDependentRequired, hasEnum, hasExclusiveMaximum, hasExclusiveMinimum, hasItems, hasMaxItems, hasMaximum, hasMaxLength, hasMinItems, hasMinimum, hasMinLength, hasMultipleOf, hasPattern, hasProperties, hasPropertyNames, hasRef, hasRequired, hasType, hasUniqueItems, isSchemaObject } from "@amritk/helpers/schema-guards";
|
|
8
|
+
import { generateEnumCheck } from "./generate-enum-check.js";
|
|
9
|
+
import { canEnforceUnion, generateUnionCheck, getUnionBranches, isInlineObjectProperty } from "./generate-type-checks.js";
|
|
10
|
+
import { getPrefixItems, prefixItemsCapsLength, scalarItemTypeCheck } from "./generate-validation-expression.js";
|
|
11
|
+
import { subschemaMatchExpr } from "./subschema-match.js";
|
|
16
12
|
const wrongTypeCondition = (accessor, type) => {
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
return `!isObject(${accessor})`;
|
|
36
|
-
default:
|
|
37
|
-
return null;
|
|
38
|
-
}
|
|
13
|
+
switch (type) {
|
|
14
|
+
case "string":
|
|
15
|
+
return `typeof ${accessor} !== "string"`;
|
|
16
|
+
case "number":
|
|
17
|
+
return `typeof ${accessor} !== "number"`;
|
|
18
|
+
case "integer":
|
|
19
|
+
return `(typeof ${accessor} !== "number" || !Number.isInteger(${accessor}))`;
|
|
20
|
+
case "boolean":
|
|
21
|
+
return `typeof ${accessor} !== "boolean"`;
|
|
22
|
+
case "null":
|
|
23
|
+
return `${accessor} !== null`;
|
|
24
|
+
case "array":
|
|
25
|
+
return `!Array.isArray(${accessor})`;
|
|
26
|
+
case "object":
|
|
27
|
+
return `!isObject(${accessor})`;
|
|
28
|
+
default:
|
|
29
|
+
return null;
|
|
30
|
+
}
|
|
39
31
|
};
|
|
40
|
-
|
|
41
|
-
* Maps a JSON Schema type to the label used in error messages.
|
|
42
|
-
* `integer` collapses to `number` since both are validated via `typeof === "number"`.
|
|
43
|
-
*/
|
|
44
|
-
const typeLabel = (type) => (type === 'integer' ? 'number' : type);
|
|
45
|
-
/**
|
|
46
|
-
* Emits `throw new Error(<message>[ + <suffixExpr>])`. The static message may
|
|
47
|
-
* contain schema-controlled text (property names, patterns, enum values), so
|
|
48
|
-
* it goes through the shared {@link quoteJsString} escape-or-quote decision.
|
|
49
|
-
* `suffixExpr`, when given, is a runtime expression appended to the message
|
|
50
|
-
* (e.g. `typeof input`).
|
|
51
|
-
*/
|
|
32
|
+
const typeLabel = (type) => type === "integer" ? "number" : type;
|
|
52
33
|
const throwError = (message, suffixExpr) => {
|
|
53
|
-
|
|
54
|
-
|
|
34
|
+
const literal = quoteJsString(message);
|
|
35
|
+
return suffixExpr ? `throw new Error(${literal} + (${suffixExpr}))` : `throw new Error(${literal})`;
|
|
55
36
|
};
|
|
56
|
-
/**
|
|
57
|
-
* Generates strict-mode constraint checks for a typed property
|
|
58
|
-
* (pattern, length, min/max, multipleOf).
|
|
59
|
-
*/
|
|
60
37
|
const generateConstraintChecks = (acc, propSchema, field, context = {}) => {
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
}
|
|
70
|
-
if (hasMinLength(propSchema)) {
|
|
71
|
-
lines.push(` if (typeof ${acc} === "string" && ${acc}.length < ${propSchema.minLength}) ${throwError(`${field} must have at least ${propSchema.minLength} characters`)};`);
|
|
72
|
-
}
|
|
73
|
-
if (hasMaxLength(propSchema)) {
|
|
74
|
-
lines.push(` if (typeof ${acc} === "string" && ${acc}.length > ${propSchema.maxLength}) ${throwError(`${field} must have at most ${propSchema.maxLength} characters`)};`);
|
|
75
|
-
}
|
|
38
|
+
if (!isSchemaObject(propSchema) || !hasType(propSchema))
|
|
39
|
+
return [];
|
|
40
|
+
const t = propSchema.type;
|
|
41
|
+
const lines = [];
|
|
42
|
+
if (t === "string") {
|
|
43
|
+
if (hasPattern(propSchema)) {
|
|
44
|
+
const pattern = escapeRegexPattern(propSchema.pattern);
|
|
45
|
+
lines.push(` if (typeof ${acc} === "string" && !/${pattern}/.test(${acc})) ${throwError(`${field} must match pattern ${propSchema.pattern}`)};`);
|
|
76
46
|
}
|
|
77
|
-
if (
|
|
78
|
-
|
|
79
|
-
lines.push(` if (typeof ${acc} === "number" && ${acc} < ${propSchema.minimum}) ${throwError(`${field} must be >= ${propSchema.minimum}`)};`);
|
|
80
|
-
}
|
|
81
|
-
if (hasMaximum(propSchema)) {
|
|
82
|
-
lines.push(` if (typeof ${acc} === "number" && ${acc} > ${propSchema.maximum}) ${throwError(`${field} must be <= ${propSchema.maximum}`)};`);
|
|
83
|
-
}
|
|
84
|
-
if (hasExclusiveMinimum(propSchema)) {
|
|
85
|
-
lines.push(` if (typeof ${acc} === "number" && ${acc} <= ${propSchema.exclusiveMinimum}) ${throwError(`${field} must be > ${propSchema.exclusiveMinimum}`)};`);
|
|
86
|
-
}
|
|
87
|
-
if (hasExclusiveMaximum(propSchema)) {
|
|
88
|
-
lines.push(` if (typeof ${acc} === "number" && ${acc} >= ${propSchema.exclusiveMaximum}) ${throwError(`${field} must be < ${propSchema.exclusiveMaximum}`)};`);
|
|
89
|
-
}
|
|
90
|
-
if (hasMultipleOf(propSchema)) {
|
|
91
|
-
lines.push(` if (typeof ${acc} === "number" && ${multipleOfFailExpr(acc, propSchema.multipleOf)}) ${throwError(`${field} must be a multiple of ${propSchema.multipleOf}`)};`);
|
|
92
|
-
}
|
|
47
|
+
if (hasMinLength(propSchema)) {
|
|
48
|
+
lines.push(` if (typeof ${acc} === "string" && ${acc}.length < ${propSchema.minLength}) ${throwError(`${field} must have at least ${propSchema.minLength} characters`)};`);
|
|
93
49
|
}
|
|
94
|
-
if (
|
|
95
|
-
|
|
96
|
-
lines.push(` if (Array.isArray(${acc}) && ${acc}.length < ${propSchema.minItems}) ${throwError(`${field} must have at least ${propSchema.minItems} items`)};`);
|
|
97
|
-
}
|
|
98
|
-
if (hasMaxItems(propSchema)) {
|
|
99
|
-
lines.push(` if (Array.isArray(${acc}) && ${acc}.length > ${propSchema.maxItems}) ${throwError(`${field} must have at most ${propSchema.maxItems} items`)};`);
|
|
100
|
-
}
|
|
101
|
-
if (hasUniqueItems(propSchema) && propSchema.uniqueItems === true) {
|
|
102
|
-
// Deep-equality dedupe via JSON keys, matching the interpreter's semantics —
|
|
103
|
-
// a plain `new Set` would only catch primitive duplicates, not equal objects.
|
|
104
|
-
lines.push(` if (Array.isArray(${acc}) && new Set(${acc}.map((_u) => JSON.stringify(_u))).size !== ${acc}.length) ${throwError(`${field} must NOT have duplicate items`)};`);
|
|
105
|
-
}
|
|
106
|
-
// Item types: the fast path proves them via `.every`, but this slow path
|
|
107
|
-
// used to check only length/uniqueness, letting e.g. a number slip into a
|
|
108
|
-
// declared `string[]`. Enforce scalar and enum item schemas here; richer
|
|
109
|
-
// item schemas ($refs, objects) are validated by their own parsers.
|
|
110
|
-
const itemCheck = generateItemCheck(propSchema);
|
|
111
|
-
if (itemCheck) {
|
|
112
|
-
lines.push(` if (Array.isArray(${acc}) && !${acc}.every((_it) => ${itemCheck.check})) ${throwError(`${field} ${itemCheck.message}`)};`);
|
|
113
|
-
}
|
|
114
|
-
// Tuple `prefixItems`: assert each position and cap length under items:false.
|
|
115
|
-
lines.push(...generatePrefixItemsAssertion(acc, field, propSchema, context.rootSchema));
|
|
50
|
+
if (hasMaxLength(propSchema)) {
|
|
51
|
+
lines.push(` if (typeof ${acc} === "string" && ${acc}.length > ${propSchema.maxLength}) ${throwError(`${field} must have at most ${propSchema.maxLength} characters`)};`);
|
|
116
52
|
}
|
|
117
|
-
|
|
53
|
+
}
|
|
54
|
+
if (t === "number" || t === "integer") {
|
|
55
|
+
if (hasMinimum(propSchema)) {
|
|
56
|
+
lines.push(` if (typeof ${acc} === "number" && ${acc} < ${propSchema.minimum}) ${throwError(`${field} must be >= ${propSchema.minimum}`)};`);
|
|
57
|
+
}
|
|
58
|
+
if (hasMaximum(propSchema)) {
|
|
59
|
+
lines.push(` if (typeof ${acc} === "number" && ${acc} > ${propSchema.maximum}) ${throwError(`${field} must be <= ${propSchema.maximum}`)};`);
|
|
60
|
+
}
|
|
61
|
+
if (hasExclusiveMinimum(propSchema)) {
|
|
62
|
+
lines.push(` if (typeof ${acc} === "number" && ${acc} <= ${propSchema.exclusiveMinimum}) ${throwError(`${field} must be > ${propSchema.exclusiveMinimum}`)};`);
|
|
63
|
+
}
|
|
64
|
+
if (hasExclusiveMaximum(propSchema)) {
|
|
65
|
+
lines.push(` if (typeof ${acc} === "number" && ${acc} >= ${propSchema.exclusiveMaximum}) ${throwError(`${field} must be < ${propSchema.exclusiveMaximum}`)};`);
|
|
66
|
+
}
|
|
67
|
+
if (hasMultipleOf(propSchema)) {
|
|
68
|
+
lines.push(` if (typeof ${acc} === "number" && ${multipleOfFailExpr(acc, propSchema.multipleOf)}) ${throwError(`${field} must be a multiple of ${propSchema.multipleOf}`)};`);
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
if (t === "array") {
|
|
72
|
+
if (hasMinItems(propSchema)) {
|
|
73
|
+
lines.push(` if (Array.isArray(${acc}) && ${acc}.length < ${propSchema.minItems}) ${throwError(`${field} must have at least ${propSchema.minItems} items`)};`);
|
|
74
|
+
}
|
|
75
|
+
if (hasMaxItems(propSchema)) {
|
|
76
|
+
lines.push(` if (Array.isArray(${acc}) && ${acc}.length > ${propSchema.maxItems}) ${throwError(`${field} must have at most ${propSchema.maxItems} items`)};`);
|
|
77
|
+
}
|
|
78
|
+
if (hasUniqueItems(propSchema) && propSchema.uniqueItems === true) {
|
|
79
|
+
lines.push(` if (Array.isArray(${acc}) && new Set(${acc}.map((_u) => JSON.stringify(_u))).size !== ${acc}.length) ${throwError(`${field} must NOT have duplicate items`)};`);
|
|
80
|
+
}
|
|
81
|
+
const itemCheck = generateItemCheck(propSchema);
|
|
82
|
+
if (itemCheck) {
|
|
83
|
+
lines.push(` if (Array.isArray(${acc}) && !${acc}.every((_it) => ${itemCheck.check})) ${throwError(`${field} ${itemCheck.message}`)};`);
|
|
84
|
+
}
|
|
85
|
+
lines.push(...generatePrefixItemsAssertion(acc, field, propSchema, context.rootSchema));
|
|
86
|
+
}
|
|
87
|
+
return lines;
|
|
118
88
|
};
|
|
119
|
-
/**
|
|
120
|
-
* Boolean per-item check (bound to `_it`) for an array schema's `items`, with
|
|
121
|
-
* the error-message fragment describing what was expected. Only scalar types
|
|
122
|
-
* and enums are checked — returns null for anything richer.
|
|
123
|
-
*/
|
|
124
89
|
const generateItemCheck = (schema) => {
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
90
|
+
if (!isSchemaObject(schema) || !hasItems(schema) || Array.isArray(schema.items))
|
|
91
|
+
return null;
|
|
92
|
+
const items = schema.items;
|
|
93
|
+
if (isSchemaObject(items) && hasEnum(items) && items.enum.length > 0) {
|
|
94
|
+
const label = items.enum.map((v) => JSON.stringify(v)).join(", ");
|
|
95
|
+
return { check: generateEnumCheck("_it", items.enum), message: `items must be one of: ${label}` };
|
|
96
|
+
}
|
|
97
|
+
const scalarCheck = scalarItemTypeCheck(items, "_it");
|
|
98
|
+
if (scalarCheck === null || !isSchemaObject(items) || !hasType(items))
|
|
99
|
+
return null;
|
|
100
|
+
return { check: scalarCheck, message: `items expected ${typeLabel(items.type)}` };
|
|
136
101
|
};
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
return [];
|
|
156
|
-
const min = typeof sp['minContains'] === 'number' ? sp['minContains'] : 1;
|
|
157
|
-
const max = typeof sp['maxContains'] === 'number' ? sp['maxContains'] : undefined;
|
|
158
|
-
const bound = max !== undefined ? `_cn < ${min} || _cn > ${max}` : `_cn < ${min}`;
|
|
159
|
-
return [
|
|
160
|
-
` if (Array.isArray(${acc})) {`,
|
|
161
|
-
` const _cn = (${acc} as unknown[]).filter((_c) => ${match}).length;`,
|
|
162
|
-
` if (${bound}) ${throwError(`${label} array does not contain the required matching items`)};`,
|
|
163
|
-
` }`,
|
|
164
|
-
];
|
|
102
|
+
const generateContainsCheck = (acc, schema, label) => {
|
|
103
|
+
if (!isSchemaObject(schema))
|
|
104
|
+
return [];
|
|
105
|
+
const sp = schema;
|
|
106
|
+
if (!("contains" in sp))
|
|
107
|
+
return [];
|
|
108
|
+
const match = subschemaMatchExpr("_c", sp["contains"]);
|
|
109
|
+
if (match === null)
|
|
110
|
+
return [];
|
|
111
|
+
const min = typeof sp["minContains"] === "number" ? sp["minContains"] : 1;
|
|
112
|
+
const max = typeof sp["maxContains"] === "number" ? sp["maxContains"] : void 0;
|
|
113
|
+
const bound = max !== void 0 ? `_cn < ${min} || _cn > ${max}` : `_cn < ${min}`;
|
|
114
|
+
return [
|
|
115
|
+
` if (Array.isArray(${acc})) {`,
|
|
116
|
+
` const _cn = (${acc} as unknown[]).filter((_c) => ${match}).length;`,
|
|
117
|
+
` if (${bound}) ${throwError(`${label} array does not contain the required matching items`)};`,
|
|
118
|
+
` }`
|
|
119
|
+
];
|
|
165
120
|
};
|
|
166
|
-
/**
|
|
167
|
-
* Strict-mode `dependentRequired`: when a trigger key is present, every declared
|
|
168
|
-
* dependency key must be present too.
|
|
169
|
-
*/
|
|
170
121
|
const generateDependentRequiredChecks = (obj, schema, label) => {
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
}
|
|
122
|
+
if (!hasDependentRequired(schema))
|
|
123
|
+
return [];
|
|
124
|
+
const lines = [];
|
|
125
|
+
for (const [trigger, deps] of Object.entries(schema.dependentRequired)) {
|
|
126
|
+
if (!Array.isArray(deps))
|
|
127
|
+
continue;
|
|
128
|
+
for (const dep of deps) {
|
|
129
|
+
lines.push(` if (${JSON.stringify(trigger)} in ${obj} && !(${JSON.stringify(dep)} in ${obj})) ${throwError(`${label} must have property '${dep}' when '${trigger}' is present`)};`);
|
|
180
130
|
}
|
|
181
|
-
|
|
131
|
+
}
|
|
132
|
+
return lines;
|
|
182
133
|
};
|
|
183
|
-
/**
|
|
184
|
-
* Strict-mode `dependentSchemas` (2020-12): when a trigger property is present,
|
|
185
|
-
* the *whole object* must also match the associated subschema. A `true`
|
|
186
|
-
* subschema is a no-op; a `false` subschema makes the trigger's presence always
|
|
187
|
-
* invalid. Object subschemas are enforced via {@link subschemaMatchExpr}; a
|
|
188
|
-
* subschema it cannot match inline is rejected at generation time by the guard.
|
|
189
|
-
*/
|
|
190
134
|
const generateDependentSchemasChecks = (obj, schema, label) => {
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
}
|
|
202
|
-
const match = subschemaMatchExpr(obj, sub);
|
|
203
|
-
if (match === null || match === 'true')
|
|
204
|
-
continue;
|
|
205
|
-
lines.push(` if (${JSON.stringify(trigger)} in ${obj} && !(${match})) ${throwError(`${label} does not satisfy the schema required when '${trigger}' is present`)};`);
|
|
135
|
+
const dep = schema["dependentSchemas"];
|
|
136
|
+
if (typeof dep !== "object" || dep === null || Array.isArray(dep))
|
|
137
|
+
return [];
|
|
138
|
+
const lines = [];
|
|
139
|
+
for (const [trigger, sub] of Object.entries(dep)) {
|
|
140
|
+
if (sub === true)
|
|
141
|
+
continue;
|
|
142
|
+
if (sub === false) {
|
|
143
|
+
lines.push(` if (${JSON.stringify(trigger)} in ${obj}) ${throwError(`${label} must NOT have property '${trigger}'`)};`);
|
|
144
|
+
continue;
|
|
206
145
|
}
|
|
207
|
-
|
|
146
|
+
const match = subschemaMatchExpr(obj, sub);
|
|
147
|
+
if (match === null || match === "true")
|
|
148
|
+
continue;
|
|
149
|
+
lines.push(` if (${JSON.stringify(trigger)} in ${obj} && !(${match})) ${throwError(`${label} does not satisfy the schema required when '${trigger}' is present`)};`);
|
|
150
|
+
}
|
|
151
|
+
return lines;
|
|
208
152
|
};
|
|
209
|
-
/**
|
|
210
|
-
* Resolves a tuple position's schema through a single `$ref` (via `rootSchema`)
|
|
211
|
-
* so the assertion can read its `type`/`enum`. A `$ref` with no resolvable target
|
|
212
|
-
* (or no root document) is returned as-is, leaving the position unasserted.
|
|
213
|
-
*/
|
|
214
153
|
const resolvePositionSchema = (pos, rootSchema) => {
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
154
|
+
if (isSchemaObject(pos) && hasRef(pos) && rootSchema) {
|
|
155
|
+
const resolved = resolveRef(pos.$ref, rootSchema);
|
|
156
|
+
if (resolved)
|
|
157
|
+
return resolved;
|
|
158
|
+
}
|
|
159
|
+
return pos;
|
|
221
160
|
};
|
|
222
|
-
/**
|
|
223
|
-
* Strict-mode assertion lines for a tuple `prefixItems`: each present position is
|
|
224
|
-
* asserted against its subschema (a scalar type, an enum, or a `$ref`/inline
|
|
225
|
-
* schema resolved to one via `rootSchema`), and a sibling `items: false` /
|
|
226
|
-
* `additionalItems: false` rejects any extra element. `acc` is the array
|
|
227
|
-
* accessor and `field` the error-message prefix (`[Type] field 'k'` or
|
|
228
|
-
* `[Type]`). Mirrors the validators' tuple pass, but throws on the first
|
|
229
|
-
* violation instead of collecting errors. Positions whose schema is richer than
|
|
230
|
-
* a scalar/enum are left to their own downstream handling (like array `items`).
|
|
231
|
-
*/
|
|
232
161
|
const generatePrefixItemsAssertion = (acc, field, schema, rootSchema) => {
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
lines.push(` if (${present} && !(${allowed} as readonly unknown[]).includes(${el})) ${throwError(`${field}[${i}] must be one of: ${label}`)};`);
|
|
247
|
-
continue;
|
|
248
|
-
}
|
|
249
|
-
if (isSchemaObject(pos) && hasType(pos)) {
|
|
250
|
-
const pt = pos.type;
|
|
251
|
-
const wrong = wrongTypeCondition(el, pt);
|
|
252
|
-
if (wrong) {
|
|
253
|
-
lines.push(` if (${present} && (${wrong})) ${throwError(`${field}[${i}] expected ${typeLabel(pt)}, got `, `typeof ${el}`)};`);
|
|
254
|
-
}
|
|
255
|
-
}
|
|
162
|
+
const prefix = getPrefixItems(schema);
|
|
163
|
+
if (!prefix)
|
|
164
|
+
return [];
|
|
165
|
+
const lines = [];
|
|
166
|
+
for (let i = 0; i < prefix.length; i++) {
|
|
167
|
+
const pos = resolvePositionSchema(prefix[i], rootSchema);
|
|
168
|
+
const el = `${acc}[${i}]`;
|
|
169
|
+
const present = `Array.isArray(${acc}) && ${acc}.length > ${i}`;
|
|
170
|
+
if (isSchemaObject(pos) && hasEnum(pos) && pos.enum.length > 0) {
|
|
171
|
+
const allowed = JSON.stringify(pos.enum);
|
|
172
|
+
const label = pos.enum.map((v) => JSON.stringify(v)).join(", ");
|
|
173
|
+
lines.push(` if (${present} && !(${allowed} as readonly unknown[]).includes(${el})) ${throwError(`${field}[${i}] must be one of: ${label}`)};`);
|
|
174
|
+
continue;
|
|
256
175
|
}
|
|
257
|
-
if (
|
|
258
|
-
|
|
176
|
+
if (isSchemaObject(pos) && hasType(pos)) {
|
|
177
|
+
const pt = pos.type;
|
|
178
|
+
const wrong = wrongTypeCondition(el, pt);
|
|
179
|
+
if (wrong) {
|
|
180
|
+
lines.push(` if (${present} && (${wrong})) ${throwError(`${field}[${i}] expected ${typeLabel(pt)}, got `, `typeof ${el}`)};`);
|
|
181
|
+
}
|
|
259
182
|
}
|
|
260
|
-
|
|
183
|
+
}
|
|
184
|
+
if (prefixItemsCapsLength(schema)) {
|
|
185
|
+
lines.push(` if (Array.isArray(${acc}) && ${acc}.length > ${prefix.length}) ${throwError(`${field} must NOT have more than ${prefix.length} items`)};`);
|
|
186
|
+
}
|
|
187
|
+
return lines;
|
|
261
188
|
};
|
|
262
|
-
/**
|
|
263
|
-
* Strict-mode `propertyNames`: every own key of the object (keys are always
|
|
264
|
-
* strings) must satisfy the name subschema. A trivially-true matcher imposes no
|
|
265
|
-
* constraint, so no loop is emitted; an unmatchable subschema is rejected at
|
|
266
|
-
* generation time by the guard.
|
|
267
|
-
*/
|
|
268
189
|
const generatePropertyNameChecks = (obj, schema, label) => {
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
190
|
+
if (!hasPropertyNames(schema) || !isSchemaObject(schema.propertyNames))
|
|
191
|
+
return [];
|
|
192
|
+
const match = subschemaMatchExpr("_name", schema.propertyNames);
|
|
193
|
+
if (match === null || match === "true")
|
|
194
|
+
return [];
|
|
195
|
+
return [
|
|
196
|
+
` for (const _name of Object.keys(${obj})) {`,
|
|
197
|
+
` if (!(${match})) ${throwError(`${label} invalid property name: `, "_name")};`,
|
|
198
|
+
` }`
|
|
199
|
+
];
|
|
279
200
|
};
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
...generateDependentRequiredChecks(obj, schema, label),
|
|
294
|
-
...generateDependentSchemasChecks(obj, schema, label),
|
|
295
|
-
...generatePropertyNameChecks(obj, schema, label),
|
|
296
|
-
];
|
|
297
|
-
if (inner.length === 0)
|
|
298
|
-
return [];
|
|
299
|
-
if (!guard)
|
|
300
|
-
return inner;
|
|
301
|
-
return [` if (isObject(${obj})) {`, ...inner.map((line) => ` ${line}`), ` }`];
|
|
201
|
+
const generateObjectKeywordChecks = (obj, schema, label, guard) => {
|
|
202
|
+
if (!isSchemaObject(schema))
|
|
203
|
+
return [];
|
|
204
|
+
const inner = [
|
|
205
|
+
...generateDependentRequiredChecks(obj, schema, label),
|
|
206
|
+
...generateDependentSchemasChecks(obj, schema, label),
|
|
207
|
+
...generatePropertyNameChecks(obj, schema, label)
|
|
208
|
+
];
|
|
209
|
+
if (inner.length === 0)
|
|
210
|
+
return [];
|
|
211
|
+
if (!guard)
|
|
212
|
+
return inner;
|
|
213
|
+
return [` if (isObject(${obj})) {`, ...inner.map((line) => ` ${line}`), ` }`];
|
|
302
214
|
};
|
|
303
|
-
/**
|
|
304
|
-
* Generates strict-mode lines for a single property of an object schema.
|
|
305
|
-
* Properties with a `$ref` are skipped here — the nested parser handles its own
|
|
306
|
-
* strict check when called from the parent's slow path.
|
|
307
|
-
*/
|
|
308
215
|
const generatePropertyAssertion = (key, propSchema, isRequired, typeName, context = {}) => {
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
if (!
|
|
326
|
-
|
|
327
|
-
if (check !== null) {
|
|
328
|
-
const failure = throwError(`${field} does not match any allowed variant`);
|
|
329
|
-
lines.push(isRequired ? ` if (!(${check})) ${failure};` : ` if (${acc} !== undefined && !(${check})) ${failure};`);
|
|
330
|
-
}
|
|
331
|
-
}
|
|
332
|
-
return lines;
|
|
333
|
-
}
|
|
334
|
-
const instanceOf = getMjstInstanceOf(propSchema);
|
|
335
|
-
if (instanceOf) {
|
|
336
|
-
if (isRequired) {
|
|
337
|
-
lines.push(` if (!(${acc} instanceof ${instanceOf})) ${throwError(`${field} must be ${instanceOf}`)};`);
|
|
338
|
-
}
|
|
339
|
-
else {
|
|
340
|
-
lines.push(` if (${acc} !== undefined && !(${acc} instanceof ${instanceOf})) ${throwError(`${field} must be ${instanceOf}`)};`);
|
|
341
|
-
}
|
|
342
|
-
return lines;
|
|
343
|
-
}
|
|
344
|
-
const primitive = getMjstPrimitive(propSchema);
|
|
345
|
-
if (primitive) {
|
|
346
|
-
if (isRequired) {
|
|
347
|
-
lines.push(` if (typeof ${acc} !== "${primitive}") ${throwError(`${field} must be ${primitive}`)};`);
|
|
348
|
-
}
|
|
349
|
-
else {
|
|
350
|
-
lines.push(` if (${acc} !== undefined && typeof ${acc} !== "${primitive}") ${throwError(`${field} must be ${primitive}`)};`);
|
|
351
|
-
}
|
|
352
|
-
return lines;
|
|
353
|
-
}
|
|
354
|
-
if (hasEnum(propSchema)) {
|
|
355
|
-
const allowed = JSON.stringify(propSchema.enum);
|
|
356
|
-
const label = propSchema.enum.map((v) => JSON.stringify(v)).join(', ');
|
|
357
|
-
if (isRequired) {
|
|
358
|
-
lines.push(` if (!(${allowed} as readonly unknown[]).includes(${acc})) ${throwError(`${field} must be one of: ${label}`)};`);
|
|
359
|
-
}
|
|
360
|
-
else {
|
|
361
|
-
lines.push(` if (${acc} !== undefined && !(${allowed} as readonly unknown[]).includes(${acc})) ${throwError(`${field} must be one of: ${label}`)};`);
|
|
362
|
-
}
|
|
363
|
-
return lines;
|
|
364
|
-
}
|
|
365
|
-
if (hasType(propSchema)) {
|
|
366
|
-
const t = propSchema.type;
|
|
367
|
-
const wrongType = wrongTypeCondition(acc, t);
|
|
368
|
-
if (wrongType) {
|
|
369
|
-
const expected = throwError(`${field} expected ${typeLabel(t)}, got `, `typeof ${acc}`);
|
|
370
|
-
if (isRequired) {
|
|
371
|
-
lines.push(` if (${wrongType}) ${expected};`);
|
|
372
|
-
}
|
|
373
|
-
else {
|
|
374
|
-
lines.push(` if (${acc} !== undefined && (${wrongType})) ${expected};`);
|
|
375
|
-
}
|
|
376
|
-
}
|
|
377
|
-
lines.push(...generateConstraintChecks(acc, propSchema, field, context));
|
|
216
|
+
const acc = safeAccessor("input", key);
|
|
217
|
+
const field = `[${typeName}] field '${key}'`;
|
|
218
|
+
const lines = [];
|
|
219
|
+
if (isRequired) {
|
|
220
|
+
lines.push(` if (!(${JSON.stringify(key)} in input)) ${throwError(`[${typeName}] missing required property '${key}'`)};`);
|
|
221
|
+
}
|
|
222
|
+
if (!isSchemaObject(propSchema))
|
|
223
|
+
return lines;
|
|
224
|
+
if (hasRef(propSchema))
|
|
225
|
+
return lines;
|
|
226
|
+
const unionBranches = getUnionBranches(propSchema);
|
|
227
|
+
if (unionBranches) {
|
|
228
|
+
if (!context.stripUnknown && canEnforceUnion(unionBranches, context.rootSchema)) {
|
|
229
|
+
const check = generateUnionCheck(acc, unionBranches, context.useRefImports ?? false, context.suffix ?? "");
|
|
230
|
+
if (check !== null) {
|
|
231
|
+
const failure = throwError(`${field} does not match any allowed variant`);
|
|
232
|
+
lines.push(isRequired ? ` if (!(${check})) ${failure};` : ` if (${acc} !== undefined && !(${check})) ${failure};`);
|
|
233
|
+
}
|
|
378
234
|
}
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
if (isSchemaObject(propSchema)) {
|
|
388
|
-
const r = propSchema;
|
|
389
|
-
if ('contains' in r)
|
|
390
|
-
lines.push(...generateContainsCheck(acc, propSchema, field));
|
|
391
|
-
if (('dependentRequired' in r || 'dependentSchemas' in r || 'propertyNames' in r) &&
|
|
392
|
-
!isInlineObjectProperty(propSchema)) {
|
|
393
|
-
lines.push(...generateObjectKeywordChecks(acc, propSchema, field, true));
|
|
394
|
-
}
|
|
235
|
+
return lines;
|
|
236
|
+
}
|
|
237
|
+
const instanceOf = getMjstInstanceOf(propSchema);
|
|
238
|
+
if (instanceOf) {
|
|
239
|
+
if (isRequired) {
|
|
240
|
+
lines.push(` if (!(${acc} instanceof ${instanceOf})) ${throwError(`${field} must be ${instanceOf}`)};`);
|
|
241
|
+
} else {
|
|
242
|
+
lines.push(` if (${acc} !== undefined && !(${acc} instanceof ${instanceOf})) ${throwError(`${field} must be ${instanceOf}`)};`);
|
|
395
243
|
}
|
|
396
244
|
return lines;
|
|
397
|
-
}
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
* - enum / pattern / length / min / max / multipleOf violations
|
|
405
|
-
*
|
|
406
|
-
* Properties with a `$ref` are validated by the nested parser's own strict
|
|
407
|
-
* check when that parser is invoked downstream.
|
|
408
|
-
*/
|
|
409
|
-
export const generateObjectStrictAssertion = (schema, typeName, context = {}) => {
|
|
410
|
-
const lines = [];
|
|
411
|
-
lines.push(` if (!isObject(input)) ${throwError(`[${typeName}] expected object, got `, 'input === null ? "null" : typeof input')};`);
|
|
412
|
-
if (!isSchemaObject(schema))
|
|
413
|
-
return lines;
|
|
414
|
-
if (hasProperties(schema)) {
|
|
415
|
-
const required = new Set(hasRequired(schema) ? schema.required : []);
|
|
416
|
-
const props = schema.properties;
|
|
417
|
-
for (const key in props) {
|
|
418
|
-
lines.push(...generatePropertyAssertion(key, props[key], required.has(key), typeName, context));
|
|
419
|
-
}
|
|
245
|
+
}
|
|
246
|
+
const primitive = getMjstPrimitive(propSchema);
|
|
247
|
+
if (primitive) {
|
|
248
|
+
if (isRequired) {
|
|
249
|
+
lines.push(` if (typeof ${acc} !== "${primitive}") ${throwError(`${field} must be ${primitive}`)};`);
|
|
250
|
+
} else {
|
|
251
|
+
lines.push(` if (${acc} !== undefined && typeof ${acc} !== "${primitive}") ${throwError(`${field} must be ${primitive}`)};`);
|
|
420
252
|
}
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
253
|
+
return lines;
|
|
254
|
+
}
|
|
255
|
+
if (hasEnum(propSchema)) {
|
|
256
|
+
const allowed = JSON.stringify(propSchema.enum);
|
|
257
|
+
const label = propSchema.enum.map((v) => JSON.stringify(v)).join(", ");
|
|
258
|
+
if (isRequired) {
|
|
259
|
+
lines.push(` if (!(${allowed} as readonly unknown[]).includes(${acc})) ${throwError(`${field} must be one of: ${label}`)};`);
|
|
260
|
+
} else {
|
|
261
|
+
lines.push(` if (${acc} !== undefined && !(${allowed} as readonly unknown[]).includes(${acc})) ${throwError(`${field} must be one of: ${label}`)};`);
|
|
429
262
|
}
|
|
430
263
|
return lines;
|
|
431
|
-
}
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
264
|
+
}
|
|
265
|
+
if (hasType(propSchema)) {
|
|
266
|
+
const t = propSchema.type;
|
|
267
|
+
const wrongType = wrongTypeCondition(acc, t);
|
|
268
|
+
if (wrongType) {
|
|
269
|
+
const expected = throwError(`${field} expected ${typeLabel(t)}, got `, `typeof ${acc}`);
|
|
270
|
+
if (isRequired) {
|
|
271
|
+
lines.push(` if (${wrongType}) ${expected};`);
|
|
272
|
+
} else {
|
|
273
|
+
lines.push(` if (${acc} !== undefined && (${wrongType})) ${expected};`);
|
|
274
|
+
}
|
|
441
275
|
}
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
276
|
+
lines.push(...generateConstraintChecks(acc, propSchema, field, context));
|
|
277
|
+
}
|
|
278
|
+
if (isSchemaObject(propSchema)) {
|
|
279
|
+
const r = propSchema;
|
|
280
|
+
if ("contains" in r)
|
|
281
|
+
lines.push(...generateContainsCheck(acc, propSchema, field));
|
|
282
|
+
if (("dependentRequired" in r || "dependentSchemas" in r || "propertyNames" in r) && !isInlineObjectProperty(propSchema)) {
|
|
283
|
+
lines.push(...generateObjectKeywordChecks(acc, propSchema, field, true));
|
|
445
284
|
}
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
285
|
+
}
|
|
286
|
+
return lines;
|
|
287
|
+
};
|
|
288
|
+
const generateObjectStrictAssertion = (schema, typeName, context = {}) => {
|
|
289
|
+
const lines = [];
|
|
290
|
+
lines.push(` if (!isObject(input)) ${throwError(`[${typeName}] expected object, got `, 'input === null ? "null" : typeof input')};`);
|
|
291
|
+
if (!isSchemaObject(schema))
|
|
292
|
+
return lines;
|
|
293
|
+
if (hasProperties(schema)) {
|
|
294
|
+
const required = new Set(hasRequired(schema) ? schema.required : []);
|
|
295
|
+
const props = schema.properties;
|
|
296
|
+
for (const key in props) {
|
|
297
|
+
lines.push(...generatePropertyAssertion(key, props[key], required.has(key), typeName, context));
|
|
457
298
|
}
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
299
|
+
}
|
|
300
|
+
const sr = schema;
|
|
301
|
+
if ("dependentRequired" in sr || "dependentSchemas" in sr || "propertyNames" in sr) {
|
|
302
|
+
lines.push(...generateObjectKeywordChecks("input", schema, `[${typeName}]`, false));
|
|
303
|
+
}
|
|
304
|
+
return lines;
|
|
305
|
+
};
|
|
306
|
+
const generateScalarStrictAssertion = (schema, typeName, rootSchema) => {
|
|
307
|
+
const got = 'input === null ? "null" : typeof input';
|
|
308
|
+
const instanceOf = getMjstInstanceOf(schema);
|
|
309
|
+
if (instanceOf) {
|
|
310
|
+
return ` if (!(input instanceof ${instanceOf})) ${throwError(`[${typeName}] expected ${instanceOf}, got `, got)};`;
|
|
311
|
+
}
|
|
312
|
+
const primitive = getMjstPrimitive(schema);
|
|
313
|
+
if (primitive) {
|
|
314
|
+
return ` if (typeof input !== "${primitive}") ${throwError(`[${typeName}] expected ${primitive}, got `, got)};`;
|
|
315
|
+
}
|
|
316
|
+
if (!isSchemaObject(schema))
|
|
317
|
+
return null;
|
|
318
|
+
const label = `[${typeName}]`;
|
|
319
|
+
const lines = [];
|
|
320
|
+
if (hasConst(schema)) {
|
|
321
|
+
const wanted = JSON.stringify(JSON.stringify(schema.const));
|
|
322
|
+
lines.push(` if (JSON.stringify(input) !== ${wanted}) ${throwError(`${label} must be ${JSON.stringify(schema.const)}`)};`);
|
|
323
|
+
} else if (hasEnum(schema)) {
|
|
324
|
+
const allowed = JSON.stringify(schema.enum);
|
|
325
|
+
const enumLabel = schema.enum.map((v) => JSON.stringify(v)).join(", ");
|
|
326
|
+
lines.push(` if (!(${allowed} as readonly unknown[]).includes(input)) ${throwError(`${label} must be one of: ${enumLabel}`)};`);
|
|
327
|
+
}
|
|
328
|
+
if (hasType(schema)) {
|
|
329
|
+
const t = schema.type;
|
|
330
|
+
const wrongType = wrongTypeCondition("input", t);
|
|
331
|
+
if (wrongType) {
|
|
332
|
+
lines.push(` if (${wrongType}) ${throwError(`${label} expected ${typeLabel(t)}, got `, got)};`);
|
|
462
333
|
}
|
|
463
|
-
if (
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
if (
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
// property path closes in generateConstraintChecks — plus `contains`.
|
|
471
|
-
if (t === 'array') {
|
|
472
|
-
const itemCheck = generateItemCheck(schema);
|
|
473
|
-
if (itemCheck) {
|
|
474
|
-
lines.push(` if (!(input as readonly unknown[]).every((_it) => ${itemCheck.check})) ${throwError(`${label} ${itemCheck.message}`)};`);
|
|
475
|
-
}
|
|
476
|
-
lines.push(...generateContainsCheck('input', schema, label));
|
|
477
|
-
// Tuple `prefixItems`: assert each position and cap length under items:false.
|
|
478
|
-
lines.push(...generatePrefixItemsAssertion('input', label, schema, rootSchema));
|
|
479
|
-
}
|
|
480
|
-
// String (pattern, min/maxLength), number/integer (bounds, multipleOf) and
|
|
481
|
-
// array (length, uniqueItems) constraints — previously enforced only for
|
|
482
|
-
// named properties, so a root scalar accepted e.g. `{type:'string',minLength:5}`
|
|
483
|
-
// violations.
|
|
484
|
-
lines.push(...generateConstraintChecks('input', schema, label, rootSchema ? { rootSchema } : {}));
|
|
334
|
+
if (t === "array") {
|
|
335
|
+
const itemCheck = generateItemCheck(schema);
|
|
336
|
+
if (itemCheck) {
|
|
337
|
+
lines.push(` if (!(input as readonly unknown[]).every((_it) => ${itemCheck.check})) ${throwError(`${label} ${itemCheck.message}`)};`);
|
|
338
|
+
}
|
|
339
|
+
lines.push(...generateContainsCheck("input", schema, label));
|
|
340
|
+
lines.push(...generatePrefixItemsAssertion("input", label, schema, rootSchema));
|
|
485
341
|
}
|
|
486
|
-
|
|
342
|
+
lines.push(...generateConstraintChecks("input", schema, label, rootSchema ? { rootSchema } : {}));
|
|
343
|
+
}
|
|
344
|
+
return lines.length > 0 ? lines.join("\n") : null;
|
|
345
|
+
};
|
|
346
|
+
export {
|
|
347
|
+
generateContainsCheck,
|
|
348
|
+
generateObjectKeywordChecks,
|
|
349
|
+
generateObjectStrictAssertion,
|
|
350
|
+
generateScalarStrictAssertion
|
|
487
351
|
};
|