@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.
@@ -1,286 +1,221 @@
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
- /**
7
- * Keywords `subschemaMatchExpr` reads and enforces. A subschema carrying any
8
- * keyword outside this set (and the annotation set below) cannot be matched
9
- * *exactly*, so the matcher bails to `null` and the generation-time guard turns
10
- * that into a hard error rather than a permissive parser.
11
- */
12
- const HANDLED_KEYWORDS = new Set([
13
- 'type',
14
- 'enum',
15
- 'const',
16
- 'pattern',
17
- 'minLength',
18
- 'maxLength',
19
- 'minimum',
20
- 'maximum',
21
- 'exclusiveMinimum',
22
- 'exclusiveMaximum',
23
- 'multipleOf',
24
- 'minItems',
25
- 'maxItems',
26
- 'uniqueItems',
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
- * Keywords that only annotate (Ajv, our differential oracle, does not assert on
36
- * them under `strict: false`), so their presence never blocks an exact match.
37
- * `format` is annotation-only in 2020-12 by default, matching the oracle.
38
- */
39
- const ANNOTATION_KEYWORDS = new Set([
40
- 'title',
41
- 'description',
42
- '$comment',
43
- '$id',
44
- '$schema',
45
- '$anchor',
46
- '$vocabulary',
47
- '$defs',
48
- 'definitions',
49
- 'examples',
50
- 'default',
51
- 'deprecated',
52
- 'readOnly',
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
- /** True when `additionalProperties` is a constraining (non-boolean) schema. */
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
- const c = [];
71
- if (hasPattern(schema))
72
- c.push(`/${escapeRegexPattern(schema.pattern)}/.test(${acc})`);
73
- if (hasMinLength(schema))
74
- c.push(`${acc}.length >= ${schema.minLength}`);
75
- if (hasMaxLength(schema))
76
- c.push(`${acc}.length <= ${schema.maxLength}`);
77
- return c;
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
- const c = [];
82
- if (integer)
83
- c.push(`Number.isInteger(${acc})`);
84
- if (hasMinimum(schema))
85
- c.push(`${acc} >= ${schema.minimum}`);
86
- if (hasMaximum(schema))
87
- c.push(`${acc} <= ${schema.maximum}`);
88
- if (hasExclusiveMinimum(schema))
89
- c.push(`${acc} > ${schema.exclusiveMinimum}`);
90
- if (hasExclusiveMaximum(schema))
91
- c.push(`${acc} < ${schema.exclusiveMaximum}`);
92
- if (hasMultipleOf(schema))
93
- c.push(multipleOfPassExpr(acc, schema.multipleOf));
94
- return c;
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
- const c = [];
99
- if (hasMinItems(schema))
100
- c.push(`${acc}.length >= ${schema.minItems}`);
101
- if (hasMaxItems(schema))
102
- c.push(`${acc}.length <= ${schema.maxItems}`);
103
- if (hasUniqueItems(schema) && schema.uniqueItems === true) {
104
- c.push(`new Set((${acc} as unknown[]).map((_u) => JSON.stringify(_u))).size === ${acc}.length`);
105
- }
106
- if (hasItems(schema)) {
107
- if (Array.isArray(schema.items))
108
- return null;
109
- const el = `_i${depth}`;
110
- const itemMatch = subschemaMatchExpr(el, schema.items, depth + 1);
111
- if (itemMatch === null)
112
- return null;
113
- if (itemMatch !== 'true')
114
- c.push(`(${acc} as unknown[]).every((${el}) => ${itemMatch})`);
115
- }
116
- return c;
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
- // A schema-valued additionalProperties record would leave record values unproven.
121
- if (hasSchemaAdditionalProperties(schema))
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
- const c = [];
124
- const required = new Set(hasRequired(schema) ? schema.required : []);
125
- if (hasProperties(schema)) {
126
- for (const [key, propSchema] of Object.entries(schema.properties)) {
127
- const propAcc = safeAccessor(acc, key);
128
- const propMatch = subschemaMatchExpr(propAcc, propSchema, depth + 1);
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
- for (const key of required)
143
- c.push(`${JSON.stringify(key)} in ${acc}`);
144
- if (hasMinProperties(schema))
145
- c.push(`Object.keys(${acc}).length >= ${schema.minProperties}`);
146
- if (hasMaxProperties(schema))
147
- c.push(`Object.keys(${acc}).length <= ${schema.maxProperties}`);
148
- if (hasAdditionalProperties(schema) && schema.additionalProperties === false) {
149
- const allowed = JSON.stringify(hasProperties(schema) ? Object.keys(schema.properties) : []);
150
- c.push(`Object.keys(${acc}).every((_k) => ${allowed}.includes(_k))`);
151
- }
152
- return c;
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
- * Builds a boolean expression that is `true` *exactly* when `accessor` matches
156
- * `schema` — sound in **both** directions (true ⇒ valid, false ⇒ invalid) — or
157
- * `null` when the schema uses a form this generator cannot prove inline.
158
- *
159
- * This is deliberately self-contained: it never emits a `$ref` shape-validator
160
- * call (those can be conservative `=> false` stubs, which would break false-
161
- * soundness) and never touches combinators. That keeps the expression usable
162
- * both for *counting* matches (`contains`) and for *rejecting* non-matches
163
- * (`propertyNames`, `dependentSchemas`) in strict mode, where a wrong verdict
164
- * would silently accept or reject a document. Anything richer returns `null`,
165
- * and `assertNoUnsupportedKeywords` turns that into a generation-time error.
166
- *
167
- * Constraint keywords apply per JSON Schema semantics: a `pattern`/`maxLength`
168
- * with no `type` still constrains string instances (and is a no-op for other
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
- // Any keyword we neither handle nor know to be a pure annotation could narrow
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
- // An array-form `type` (multi-type / nullable) is a disjunction we do not
190
- // prove inline here; `hasType` is false for it, so without this it would fall
191
- // through to a permissive result.
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
- const checks = [];
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
- const checks = [];
262
- const strChecks = stringConstraints(accessor, schema);
263
- if (strChecks.length > 0)
264
- checks.push(`(typeof ${accessor} !== "string" || ${joinAnd(strChecks)})`);
265
- const numChecks = numberConstraints(accessor, schema, false);
266
- if (numChecks.length > 0)
267
- checks.push(`(typeof ${accessor} !== "number" || ${joinAnd(numChecks)})`);
268
- const arrChecks = arrayConstraints(accessor, schema, depth);
269
- if (arrChecks === null)
270
- return null;
271
- if (arrChecks.length > 0)
272
- checks.push(`(!Array.isArray(${accessor}) || ${joinAnd(arrChecks)})`);
273
- const objChecks = objectConstraints(accessor, schema, depth);
274
- if (objChecks === null)
275
- return null;
276
- if (objChecks.length > 0)
277
- checks.push(`(!(${isObjectExpr(accessor)}) || ${joinAnd(objChecks)})`);
278
- return checks;
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
- * Merges custom extension properties into a schema's properties based on the
3
- * definition name. Extension properties are added as optional (not included
4
- * in the required array) since they are custom additions that may not always
5
- * be present.
6
- *
7
- * If the schema is not an object, has no matching extensions, or the
8
- * extensions record is empty, the original schema is returned unchanged.
9
- *
10
- * @param schema - The JSON Schema to extend
11
- * @param definitionName - The name of the definition (e.g., "parameter")
12
- * @param extensions - The extensions configuration mapping definition names to properties
13
- * @returns A new schema with extension properties merged in, or the original if unchanged
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
- if (typeof schema !== 'object' || schema === null) {
39
- return schema;
40
- }
41
- const existingProperties = 'properties' in schema && typeof schema.properties === 'object' && schema.properties !== null
42
- ? schema.properties
43
- : {};
44
- return {
45
- ...schema,
46
- properties: {
47
- ...existingProperties,
48
- ...extensionProperties,
49
- },
50
- };
16
+ };
17
+ };
18
+ export {
19
+ applySchemaExtensions
51
20
  };