@amritk/generate-parsers 0.16.3 → 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/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 +4 -4
|
@@ -1,286 +1,221 @@
|
|
|
1
|
-
import { escapeRegexPattern } from
|
|
2
|
-
import { multipleOfPassExpr } from
|
|
3
|
-
import { safeAccessor } from
|
|
4
|
-
import { hasAdditionalProperties, hasConst, hasEnum, hasExclusiveMaximum, hasExclusiveMinimum, hasItems, hasMaxItems, hasMaximum, hasMaxLength, hasMaxProperties, hasMinItems, hasMinimum, hasMinLength, hasMinProperties, hasMultipleOf, hasPattern, hasProperties, hasRequired, hasType, hasUniqueItems, isSchemaObject
|
|
5
|
-
import { generateEnumCheck } from
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
'items',
|
|
28
|
-
'required',
|
|
29
|
-
'properties',
|
|
30
|
-
'minProperties',
|
|
31
|
-
'maxProperties',
|
|
32
|
-
'additionalProperties',
|
|
1
|
+
import { escapeRegexPattern } from "@amritk/helpers/escape-regex-pattern";
|
|
2
|
+
import { multipleOfPassExpr } from "@amritk/helpers/multiple-of-check";
|
|
3
|
+
import { safeAccessor } from "@amritk/helpers/safe-accessor";
|
|
4
|
+
import { hasAdditionalProperties, hasConst, hasEnum, hasExclusiveMaximum, hasExclusiveMinimum, hasItems, hasMaxItems, hasMaximum, hasMaxLength, hasMaxProperties, hasMinItems, hasMinimum, hasMinLength, hasMinProperties, hasMultipleOf, hasPattern, hasProperties, hasRequired, hasType, hasUniqueItems, isSchemaObject } from "@amritk/helpers/schema-guards";
|
|
5
|
+
import { generateEnumCheck } from "./generate-enum-check.js";
|
|
6
|
+
const HANDLED_KEYWORDS = /* @__PURE__ */ new Set([
|
|
7
|
+
"type",
|
|
8
|
+
"enum",
|
|
9
|
+
"const",
|
|
10
|
+
"pattern",
|
|
11
|
+
"minLength",
|
|
12
|
+
"maxLength",
|
|
13
|
+
"minimum",
|
|
14
|
+
"maximum",
|
|
15
|
+
"exclusiveMinimum",
|
|
16
|
+
"exclusiveMaximum",
|
|
17
|
+
"multipleOf",
|
|
18
|
+
"minItems",
|
|
19
|
+
"maxItems",
|
|
20
|
+
"uniqueItems",
|
|
21
|
+
"items",
|
|
22
|
+
"required",
|
|
23
|
+
"properties",
|
|
24
|
+
"minProperties",
|
|
25
|
+
"maxProperties",
|
|
26
|
+
"additionalProperties"
|
|
33
27
|
]);
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
'writeOnly',
|
|
54
|
-
'format',
|
|
55
|
-
'contentMediaType',
|
|
56
|
-
'contentEncoding',
|
|
57
|
-
'contentSchema',
|
|
28
|
+
const ANNOTATION_KEYWORDS = /* @__PURE__ */ new Set([
|
|
29
|
+
"title",
|
|
30
|
+
"description",
|
|
31
|
+
"$comment",
|
|
32
|
+
"$id",
|
|
33
|
+
"$schema",
|
|
34
|
+
"$anchor",
|
|
35
|
+
"$vocabulary",
|
|
36
|
+
"$defs",
|
|
37
|
+
"definitions",
|
|
38
|
+
"examples",
|
|
39
|
+
"default",
|
|
40
|
+
"deprecated",
|
|
41
|
+
"readOnly",
|
|
42
|
+
"writeOnly",
|
|
43
|
+
"format",
|
|
44
|
+
"contentMediaType",
|
|
45
|
+
"contentEncoding",
|
|
46
|
+
"contentSchema"
|
|
58
47
|
]);
|
|
59
48
|
const isObjectExpr = (acc) => `typeof ${acc} === "object" && ${acc} !== null && !Array.isArray(${acc})`;
|
|
60
|
-
|
|
61
|
-
const hasSchemaAdditionalProperties = (schema) => hasAdditionalProperties(schema) &&
|
|
62
|
-
typeof schema.additionalProperties !== 'boolean';
|
|
63
|
-
/**
|
|
64
|
-
* String-family constraint checks (no type assertion). Every JSON Schema string
|
|
65
|
-
* keyword only asserts on string instances, so these are combined with a
|
|
66
|
-
* `typeof === "string"` — either as the assertion (a `type: 'string'` schema) or
|
|
67
|
-
* as a guard (`typeof !== "string" || …` for a type-less schema).
|
|
68
|
-
*/
|
|
49
|
+
const hasSchemaAdditionalProperties = (schema) => hasAdditionalProperties(schema) && typeof schema.additionalProperties !== "boolean";
|
|
69
50
|
const stringConstraints = (acc, schema) => {
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
51
|
+
const c = [];
|
|
52
|
+
if (hasPattern(schema))
|
|
53
|
+
c.push(`/${escapeRegexPattern(schema.pattern)}/.test(${acc})`);
|
|
54
|
+
if (hasMinLength(schema))
|
|
55
|
+
c.push(`${acc}.length >= ${schema.minLength}`);
|
|
56
|
+
if (hasMaxLength(schema))
|
|
57
|
+
c.push(`${acc}.length <= ${schema.maxLength}`);
|
|
58
|
+
return c;
|
|
78
59
|
};
|
|
79
|
-
/** Number-family constraint checks (no type assertion). `integer` requires an explicit type. */
|
|
80
60
|
const numberConstraints = (acc, schema, integer) => {
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
61
|
+
const c = [];
|
|
62
|
+
if (integer)
|
|
63
|
+
c.push(`Number.isInteger(${acc})`);
|
|
64
|
+
if (hasMinimum(schema))
|
|
65
|
+
c.push(`${acc} >= ${schema.minimum}`);
|
|
66
|
+
if (hasMaximum(schema))
|
|
67
|
+
c.push(`${acc} <= ${schema.maximum}`);
|
|
68
|
+
if (hasExclusiveMinimum(schema))
|
|
69
|
+
c.push(`${acc} > ${schema.exclusiveMinimum}`);
|
|
70
|
+
if (hasExclusiveMaximum(schema))
|
|
71
|
+
c.push(`${acc} < ${schema.exclusiveMaximum}`);
|
|
72
|
+
if (hasMultipleOf(schema))
|
|
73
|
+
c.push(multipleOfPassExpr(acc, schema.multipleOf));
|
|
74
|
+
return c;
|
|
95
75
|
};
|
|
96
|
-
/** Array-family constraint checks (no `Array.isArray` assertion). `null` when an item schema is unprovable. */
|
|
97
76
|
const arrayConstraints = (acc, schema, depth) => {
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
77
|
+
const c = [];
|
|
78
|
+
if (hasMinItems(schema))
|
|
79
|
+
c.push(`${acc}.length >= ${schema.minItems}`);
|
|
80
|
+
if (hasMaxItems(schema))
|
|
81
|
+
c.push(`${acc}.length <= ${schema.maxItems}`);
|
|
82
|
+
if (hasUniqueItems(schema) && schema.uniqueItems === true) {
|
|
83
|
+
c.push(`new Set((${acc} as unknown[]).map((_u) => JSON.stringify(_u))).size === ${acc}.length`);
|
|
84
|
+
}
|
|
85
|
+
if (hasItems(schema)) {
|
|
86
|
+
if (Array.isArray(schema.items))
|
|
87
|
+
return null;
|
|
88
|
+
const el = `_i${depth}`;
|
|
89
|
+
const itemMatch = subschemaMatchExpr(el, schema.items, depth + 1);
|
|
90
|
+
if (itemMatch === null)
|
|
91
|
+
return null;
|
|
92
|
+
if (itemMatch !== "true")
|
|
93
|
+
c.push(`(${acc} as unknown[]).every((${el}) => ${itemMatch})`);
|
|
94
|
+
}
|
|
95
|
+
return c;
|
|
117
96
|
};
|
|
118
|
-
/** Object-family constraint checks (no object-type assertion). `null` when a property schema is unprovable. */
|
|
119
97
|
const objectConstraints = (acc, schema, depth) => {
|
|
120
|
-
|
|
121
|
-
|
|
98
|
+
if (hasSchemaAdditionalProperties(schema))
|
|
99
|
+
return null;
|
|
100
|
+
const c = [];
|
|
101
|
+
const required = new Set(hasRequired(schema) ? schema.required : []);
|
|
102
|
+
if (hasProperties(schema)) {
|
|
103
|
+
for (const [key, propSchema] of Object.entries(schema.properties)) {
|
|
104
|
+
const propAcc = safeAccessor(acc, key);
|
|
105
|
+
const propMatch = subschemaMatchExpr(propAcc, propSchema, depth + 1);
|
|
106
|
+
if (propMatch === null)
|
|
122
107
|
return null;
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
if (propMatch === null)
|
|
130
|
-
return null;
|
|
131
|
-
if (required.has(key)) {
|
|
132
|
-
c.push(propMatch === 'true'
|
|
133
|
-
? `${JSON.stringify(key)} in ${acc}`
|
|
134
|
-
: `(${JSON.stringify(key)} in ${acc} && ${propMatch})`);
|
|
135
|
-
}
|
|
136
|
-
else if (propMatch !== 'true') {
|
|
137
|
-
c.push(`(${propAcc} === undefined || ${propMatch})`);
|
|
138
|
-
}
|
|
139
|
-
required.delete(key);
|
|
140
|
-
}
|
|
108
|
+
if (required.has(key)) {
|
|
109
|
+
c.push(propMatch === "true" ? `${JSON.stringify(key)} in ${acc}` : `(${JSON.stringify(key)} in ${acc} && ${propMatch})`);
|
|
110
|
+
} else if (propMatch !== "true") {
|
|
111
|
+
c.push(`(${propAcc} === undefined || ${propMatch})`);
|
|
112
|
+
}
|
|
113
|
+
required.delete(key);
|
|
141
114
|
}
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
}
|
|
152
|
-
|
|
115
|
+
}
|
|
116
|
+
for (const key of required)
|
|
117
|
+
c.push(`${JSON.stringify(key)} in ${acc}`);
|
|
118
|
+
if (hasMinProperties(schema))
|
|
119
|
+
c.push(`Object.keys(${acc}).length >= ${schema.minProperties}`);
|
|
120
|
+
if (hasMaxProperties(schema))
|
|
121
|
+
c.push(`Object.keys(${acc}).length <= ${schema.maxProperties}`);
|
|
122
|
+
if (hasAdditionalProperties(schema) && schema.additionalProperties === false) {
|
|
123
|
+
const allowed = JSON.stringify(hasProperties(schema) ? Object.keys(schema.properties) : []);
|
|
124
|
+
c.push(`Object.keys(${acc}).every((_k) => ${allowed}.includes(_k))`);
|
|
125
|
+
}
|
|
126
|
+
return c;
|
|
127
|
+
};
|
|
128
|
+
const subschemaMatchExpr = (accessor, schema, depth = 0) => {
|
|
129
|
+
if (schema === true)
|
|
130
|
+
return "true";
|
|
131
|
+
if (schema === false)
|
|
132
|
+
return "false";
|
|
133
|
+
if (!isSchemaObject(schema))
|
|
134
|
+
return null;
|
|
135
|
+
for (const key of Object.keys(schema)) {
|
|
136
|
+
if (!HANDLED_KEYWORDS.has(key) && !ANNOTATION_KEYWORDS.has(key))
|
|
137
|
+
return null;
|
|
138
|
+
}
|
|
139
|
+
if ("type" in schema && typeof schema.type !== "string")
|
|
140
|
+
return null;
|
|
141
|
+
const checks = [];
|
|
142
|
+
if (hasConst(schema)) {
|
|
143
|
+
const c = schema.const;
|
|
144
|
+
if (c !== null && typeof c === "object")
|
|
145
|
+
return null;
|
|
146
|
+
checks.push(`${accessor} === ${JSON.stringify(c)}`);
|
|
147
|
+
}
|
|
148
|
+
if (hasEnum(schema)) {
|
|
149
|
+
if (schema.enum.length === 0)
|
|
150
|
+
return null;
|
|
151
|
+
checks.push(generateEnumCheck(accessor, schema.enum));
|
|
152
|
+
}
|
|
153
|
+
if (hasType(schema)) {
|
|
154
|
+
const typeChecks = buildTypedChecks(accessor, schema, depth);
|
|
155
|
+
if (typeChecks === null)
|
|
156
|
+
return null;
|
|
157
|
+
checks.push(...typeChecks);
|
|
158
|
+
} else {
|
|
159
|
+
const typeless = buildTypelessChecks(accessor, schema, depth);
|
|
160
|
+
if (typeless === null)
|
|
161
|
+
return null;
|
|
162
|
+
checks.push(...typeless);
|
|
163
|
+
}
|
|
164
|
+
if (checks.length === 0)
|
|
165
|
+
return "true";
|
|
166
|
+
return checks.length === 1 ? checks[0] : `(${checks.join(" && ")})`;
|
|
153
167
|
};
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
* types), so a type-less schema guards each family by its runtime type rather
|
|
170
|
-
* than ignoring it — the subtlety `propertyNames: { maxLength: 3 }` depends on.
|
|
171
|
-
*
|
|
172
|
-
* `depth` seeds the `.every` element variable so nested array matches never
|
|
173
|
-
* shadow one another.
|
|
174
|
-
*/
|
|
175
|
-
export const subschemaMatchExpr = (accessor, schema, depth = 0) => {
|
|
176
|
-
// Boolean schemas: `true` matches everything, `false` matches nothing.
|
|
177
|
-
if (schema === true)
|
|
178
|
-
return 'true';
|
|
179
|
-
if (schema === false)
|
|
180
|
-
return 'false';
|
|
181
|
-
if (!isSchemaObject(schema))
|
|
168
|
+
const buildTypedChecks = (accessor, schema, depth) => {
|
|
169
|
+
switch (schema.type) {
|
|
170
|
+
case "string":
|
|
171
|
+
return [`typeof ${accessor} === "string"`, ...stringConstraints(accessor, schema)];
|
|
172
|
+
case "number":
|
|
173
|
+
return [`typeof ${accessor} === "number"`, ...numberConstraints(accessor, schema, false)];
|
|
174
|
+
case "integer":
|
|
175
|
+
return [`typeof ${accessor} === "number"`, ...numberConstraints(accessor, schema, true)];
|
|
176
|
+
case "boolean":
|
|
177
|
+
return [`typeof ${accessor} === "boolean"`];
|
|
178
|
+
case "null":
|
|
179
|
+
return [`${accessor} === null`];
|
|
180
|
+
case "array": {
|
|
181
|
+
const constraints = arrayConstraints(accessor, schema, depth);
|
|
182
|
+
if (constraints === null)
|
|
182
183
|
return null;
|
|
183
|
-
|
|
184
|
-
// the value set; matching would then be unsound, so bail.
|
|
185
|
-
for (const key of Object.keys(schema)) {
|
|
186
|
-
if (!HANDLED_KEYWORDS.has(key) && !ANNOTATION_KEYWORDS.has(key))
|
|
187
|
-
return null;
|
|
184
|
+
return [`Array.isArray(${accessor})`, ...constraints];
|
|
188
185
|
}
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
if ('type' in schema && typeof schema.type !== 'string')
|
|
186
|
+
case "object": {
|
|
187
|
+
const constraints = objectConstraints(accessor, schema, depth);
|
|
188
|
+
if (constraints === null)
|
|
193
189
|
return null;
|
|
194
|
-
|
|
195
|
-
// `const` — a single exact value. Primitives compare with `===`; a structural
|
|
196
|
-
// const would need deep equality, which this flat matcher does not attempt.
|
|
197
|
-
if (hasConst(schema)) {
|
|
198
|
-
const c = schema.const;
|
|
199
|
-
if (c !== null && typeof c === 'object')
|
|
200
|
-
return null;
|
|
201
|
-
checks.push(`${accessor} === ${JSON.stringify(c)}`);
|
|
202
|
-
}
|
|
203
|
-
// `enum` — membership in a fixed set (generateEnumCheck is exact).
|
|
204
|
-
if (hasEnum(schema)) {
|
|
205
|
-
if (schema.enum.length === 0)
|
|
206
|
-
return null;
|
|
207
|
-
checks.push(generateEnumCheck(accessor, schema.enum));
|
|
208
|
-
}
|
|
209
|
-
if (hasType(schema)) {
|
|
210
|
-
const typeChecks = buildTypedChecks(accessor, schema, depth);
|
|
211
|
-
if (typeChecks === null)
|
|
212
|
-
return null;
|
|
213
|
-
checks.push(...typeChecks);
|
|
214
|
-
}
|
|
215
|
-
else {
|
|
216
|
-
const typeless = buildTypelessChecks(accessor, schema, depth);
|
|
217
|
-
if (typeless === null)
|
|
218
|
-
return null;
|
|
219
|
-
checks.push(...typeless);
|
|
220
|
-
}
|
|
221
|
-
// A schema with no proven constraint matches every value.
|
|
222
|
-
if (checks.length === 0)
|
|
223
|
-
return 'true';
|
|
224
|
-
return checks.length === 1 ? checks[0] : `(${checks.join(' && ')})`;
|
|
225
|
-
};
|
|
226
|
-
/** Type assertion plus that type's constraints, for a single-`type` schema. */
|
|
227
|
-
const buildTypedChecks = (accessor, schema, depth) => {
|
|
228
|
-
switch (schema.type) {
|
|
229
|
-
case 'string':
|
|
230
|
-
return [`typeof ${accessor} === "string"`, ...stringConstraints(accessor, schema)];
|
|
231
|
-
case 'number':
|
|
232
|
-
return [`typeof ${accessor} === "number"`, ...numberConstraints(accessor, schema, false)];
|
|
233
|
-
case 'integer':
|
|
234
|
-
return [`typeof ${accessor} === "number"`, ...numberConstraints(accessor, schema, true)];
|
|
235
|
-
case 'boolean':
|
|
236
|
-
return [`typeof ${accessor} === "boolean"`];
|
|
237
|
-
case 'null':
|
|
238
|
-
return [`${accessor} === null`];
|
|
239
|
-
case 'array': {
|
|
240
|
-
const constraints = arrayConstraints(accessor, schema, depth);
|
|
241
|
-
if (constraints === null)
|
|
242
|
-
return null;
|
|
243
|
-
return [`Array.isArray(${accessor})`, ...constraints];
|
|
244
|
-
}
|
|
245
|
-
case 'object': {
|
|
246
|
-
const constraints = objectConstraints(accessor, schema, depth);
|
|
247
|
-
if (constraints === null)
|
|
248
|
-
return null;
|
|
249
|
-
return [isObjectExpr(accessor), ...constraints];
|
|
250
|
-
}
|
|
251
|
-
default:
|
|
252
|
-
return null;
|
|
190
|
+
return [isObjectExpr(accessor), ...constraints];
|
|
253
191
|
}
|
|
192
|
+
default:
|
|
193
|
+
return null;
|
|
194
|
+
}
|
|
254
195
|
};
|
|
255
|
-
/**
|
|
256
|
-
* Constraints on a schema with no `type`: each family only asserts on instances
|
|
257
|
-
* of its type, so guard each present family by its runtime type. A value of a
|
|
258
|
-
* different type satisfies the family vacuously.
|
|
259
|
-
*/
|
|
260
196
|
const buildTypelessChecks = (accessor, schema, depth) => {
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
197
|
+
const checks = [];
|
|
198
|
+
const strChecks = stringConstraints(accessor, schema);
|
|
199
|
+
if (strChecks.length > 0)
|
|
200
|
+
checks.push(`(typeof ${accessor} !== "string" || ${joinAnd(strChecks)})`);
|
|
201
|
+
const numChecks = numberConstraints(accessor, schema, false);
|
|
202
|
+
if (numChecks.length > 0)
|
|
203
|
+
checks.push(`(typeof ${accessor} !== "number" || ${joinAnd(numChecks)})`);
|
|
204
|
+
const arrChecks = arrayConstraints(accessor, schema, depth);
|
|
205
|
+
if (arrChecks === null)
|
|
206
|
+
return null;
|
|
207
|
+
if (arrChecks.length > 0)
|
|
208
|
+
checks.push(`(!Array.isArray(${accessor}) || ${joinAnd(arrChecks)})`);
|
|
209
|
+
const objChecks = objectConstraints(accessor, schema, depth);
|
|
210
|
+
if (objChecks === null)
|
|
211
|
+
return null;
|
|
212
|
+
if (objChecks.length > 0)
|
|
213
|
+
checks.push(`(!(${isObjectExpr(accessor)}) || ${joinAnd(objChecks)})`);
|
|
214
|
+
return checks;
|
|
215
|
+
};
|
|
216
|
+
const joinAnd = (checks) => checks.length === 1 ? checks[0] : `(${checks.join(" && ")})`;
|
|
217
|
+
const canMatchSubschema = (schema) => subschemaMatchExpr("_x", schema) !== null;
|
|
218
|
+
export {
|
|
219
|
+
canMatchSubschema,
|
|
220
|
+
subschemaMatchExpr
|
|
279
221
|
};
|
|
280
|
-
const joinAnd = (checks) => (checks.length === 1 ? checks[0] : `(${checks.join(' && ')})`);
|
|
281
|
-
/**
|
|
282
|
-
* Whether {@link subschemaMatchExpr} can build an exact matcher for `schema`.
|
|
283
|
-
* The generation-time guard uses this to decide whether a `contains`,
|
|
284
|
-
* `propertyNames`, or `dependentSchemas` subschema is enforceable.
|
|
285
|
-
*/
|
|
286
|
-
export const canMatchSubschema = (schema) => subschemaMatchExpr('_x', schema) !== null;
|
|
@@ -1,51 +1,20 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
* @example
|
|
16
|
-
* ```typescript
|
|
17
|
-
* const schema = {
|
|
18
|
-
* type: 'object',
|
|
19
|
-
* properties: { name: { type: 'string' } },
|
|
20
|
-
* required: ['name'],
|
|
21
|
-
* }
|
|
22
|
-
*
|
|
23
|
-
* const extensions = {
|
|
24
|
-
* parameter: {
|
|
25
|
-
* 'x-enabled': { type: 'boolean' },
|
|
26
|
-
* },
|
|
27
|
-
* }
|
|
28
|
-
*
|
|
29
|
-
* const extended = applySchemaExtensions(schema, 'parameter', extensions)
|
|
30
|
-
* // extended.properties now includes 'x-enabled' alongside 'name'
|
|
31
|
-
* ```
|
|
32
|
-
*/
|
|
33
|
-
export const applySchemaExtensions = (schema, definitionName, extensions) => {
|
|
34
|
-
const extensionProperties = extensions[definitionName];
|
|
35
|
-
if (!extensionProperties || Object.keys(extensionProperties).length === 0) {
|
|
36
|
-
return schema;
|
|
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
|
|
37
15
|
}
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
? schema.properties
|
|
43
|
-
: {};
|
|
44
|
-
return {
|
|
45
|
-
...schema,
|
|
46
|
-
properties: {
|
|
47
|
-
...existingProperties,
|
|
48
|
-
...extensionProperties,
|
|
49
|
-
},
|
|
50
|
-
};
|
|
16
|
+
};
|
|
17
|
+
};
|
|
18
|
+
export {
|
|
19
|
+
applySchemaExtensions
|
|
51
20
|
};
|