@x0k/json-schema-merge 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (39) hide show
  1. package/LICENSE +7 -0
  2. package/README.md +181 -0
  3. package/dist/index.d.ts +1 -0
  4. package/dist/index.js +1 -0
  5. package/dist/lib/array.d.ts +19 -0
  6. package/dist/lib/array.js +133 -0
  7. package/dist/lib/function.d.ts +1 -0
  8. package/dist/lib/function.js +3 -0
  9. package/dist/lib/json-schema/compare/compare.d.ts +9 -0
  10. package/dist/lib/json-schema/compare/compare.js +205 -0
  11. package/dist/lib/json-schema/compare/index.d.ts +1 -0
  12. package/dist/lib/json-schema/compare/index.js +1 -0
  13. package/dist/lib/json-schema/index.d.ts +5 -0
  14. package/dist/lib/json-schema/index.js +5 -0
  15. package/dist/lib/json-schema/json-schema.d.ts +37 -0
  16. package/dist/lib/json-schema/json-schema.js +56 -0
  17. package/dist/lib/json-schema/merge/all-of-merge.d.ts +3 -0
  18. package/dist/lib/json-schema/merge/all-of-merge.js +29 -0
  19. package/dist/lib/json-schema/merge/index.d.ts +3 -0
  20. package/dist/lib/json-schema/merge/index.js +3 -0
  21. package/dist/lib/json-schema/merge/merge.d.ts +91 -0
  22. package/dist/lib/json-schema/merge/merge.js +554 -0
  23. package/dist/lib/json-schema/merge/patterns.d.ts +2 -0
  24. package/dist/lib/json-schema/merge/patterns.js +6 -0
  25. package/dist/lib/json-schema/transform.d.ts +4 -0
  26. package/dist/lib/json-schema/transform.js +72 -0
  27. package/dist/lib/json-schema/traverse.d.ts +26 -0
  28. package/dist/lib/json-schema/traverse.js +1 -0
  29. package/dist/lib/math.d.ts +2 -0
  30. package/dist/lib/math.js +2 -0
  31. package/dist/lib/memoize.d.ts +7 -0
  32. package/dist/lib/memoize.js +11 -0
  33. package/dist/lib/object.d.ts +2 -0
  34. package/dist/lib/object.js +12 -0
  35. package/dist/lib/ord.d.ts +9 -0
  36. package/dist/lib/ord.js +7 -0
  37. package/dist/lib/traverser.d.ts +4 -0
  38. package/dist/lib/traverser.js +1 -0
  39. package/package.json +59 -0
@@ -0,0 +1,554 @@
1
+ import { intersection, union, } from "../../array.js";
2
+ import { identity } from "../../function.js";
3
+ import { lcm } from "../../math.js";
4
+ import { isAllowAnySchema } from "../json-schema.js";
5
+ import { simplePatternsMerger } from "./patterns.js";
6
+ function* createPairCombinations(l, r, action) {
7
+ const ll = l.length;
8
+ const rl = r.length;
9
+ if (ll > 0 && rl > 0) {
10
+ for (let i = 0; i < ll; i++) {
11
+ const lv = l[i];
12
+ for (let j = 0; j < rl; j++) {
13
+ yield action(lv, r[j]);
14
+ }
15
+ }
16
+ }
17
+ }
18
+ function mergeBooleans(l, r) {
19
+ return l || r;
20
+ }
21
+ function createRecordsMerge(merge) {
22
+ return (left, right) => {
23
+ const target = { ...left };
24
+ const keys = Object.keys(right);
25
+ const l = keys.length;
26
+ for (let i = 0; i < l; i++) {
27
+ const key = keys[i];
28
+ target[key] =
29
+ left[key] === undefined ? right[key] : merge(left[key], right[key]);
30
+ }
31
+ return target;
32
+ };
33
+ }
34
+ function createMap(items) {
35
+ const map = new Map();
36
+ for (const pair of items) {
37
+ for (const key of pair[0]) {
38
+ map.set(key, pair[1]);
39
+ }
40
+ }
41
+ return map;
42
+ }
43
+ function assignSchemaDefinitionOrRecordOfSchemaDefinitions(target, key, value) {
44
+ if (value === undefined || isAllowAnySchema(value)) {
45
+ delete target[key];
46
+ }
47
+ else {
48
+ target[key] = value;
49
+ }
50
+ }
51
+ const PROPERTIES_ASSIGNER_KEYS = [
52
+ "properties",
53
+ "patternProperties",
54
+ "additionalProperties",
55
+ ];
56
+ function compilePatterns(patterns) {
57
+ const keys = Object.keys(patterns);
58
+ const l = keys.length;
59
+ const result = [];
60
+ for (let i = 0; i < l; i++) {
61
+ const source = keys[i];
62
+ result.push({
63
+ regExp: new RegExp(source),
64
+ schema: patterns[source],
65
+ });
66
+ }
67
+ return [result, keys];
68
+ }
69
+ const EMPTY_PATTERNS_AND_KEYS = [[], []];
70
+ /**
71
+ * @returns `true` when `false` schema occurred
72
+ */
73
+ function appendKeyConstraints(target, key, patterns) {
74
+ const l = patterns.length;
75
+ for (let i = 0; i < l; i++) {
76
+ const p = patterns[i];
77
+ if (!p.regExp.test(key)) {
78
+ continue;
79
+ }
80
+ const s = p.schema;
81
+ if (s === false) {
82
+ return true;
83
+ }
84
+ target.push(s);
85
+ }
86
+ return false;
87
+ }
88
+ const ITEMS_ASSIGNER_KEYS = [
89
+ "items",
90
+ "additionalItems",
91
+ ];
92
+ const CONDITION_ASSIGNER_KEYS = [
93
+ "if",
94
+ "then",
95
+ "else",
96
+ ];
97
+ function assignCondition(target, source) {
98
+ if (source.if !== undefined) {
99
+ target.if = source.if;
100
+ }
101
+ if (source.then !== undefined) {
102
+ target.then = source.then;
103
+ }
104
+ if (source.else !== undefined) {
105
+ target.else = source.else;
106
+ }
107
+ return target;
108
+ }
109
+ function intersectSchemaTypes(a, b) {
110
+ if (a === b) {
111
+ return a;
112
+ }
113
+ switch (a) {
114
+ case "number": {
115
+ if (b === "integer") {
116
+ return "integer";
117
+ }
118
+ }
119
+ // eslint-disable-next-line no-fallthrough
120
+ case "integer": {
121
+ if (b === "number") {
122
+ return "integer";
123
+ }
124
+ }
125
+ // eslint-disable-next-line no-fallthrough
126
+ default:
127
+ return undefined;
128
+ }
129
+ }
130
+ export function check(a, b, check) {
131
+ return [a, b, check];
132
+ }
133
+ function createChecksMap(checks) {
134
+ const map = new Map();
135
+ for (const [a, b, check] of checks) {
136
+ const fn = (target) => {
137
+ if (!check(target)) {
138
+ throw new Error(`Schema keys '${a}' and '${b}' are conflicting (${a}: ${JSON.stringify(target[a])}, ${b}: ${JSON.stringify(target[b])})`);
139
+ }
140
+ };
141
+ for (const k of [
142
+ [a, b],
143
+ [b, a],
144
+ ]) {
145
+ let arr = map.get(k[0]);
146
+ if (arr === undefined) {
147
+ arr = [];
148
+ map.set(k[0], arr);
149
+ }
150
+ arr.push({ oppositeKey: k[1], check: fn });
151
+ }
152
+ }
153
+ return map;
154
+ }
155
+ export const DEFAULT_CHECKS = [
156
+ check("minimum", "maximum", (t) => t.maximum >= t.minimum),
157
+ check("exclusiveMinimum", "maximum", (t) => t.maximum > t.exclusiveMinimum),
158
+ check("minimum", "exclusiveMaximum", (t) => t.exclusiveMaximum > t.minimum),
159
+ check("exclusiveMinimum", "exclusiveMaximum", (t) => t.exclusiveMaximum > t.exclusiveMinimum),
160
+ check("minLength", "maxLength", (t) => t.maxLength >= t.minLength),
161
+ check("minItems", "maxItems", (t) => t.maxItems >= t.minItems),
162
+ check("minProperties", "maxProperties", (t) => t.maxProperties >= t.minProperties),
163
+ ];
164
+ export function createMerger({ mergePatterns = simplePatternsMerger, isSubRegExp = Object.is, intersectJson = intersection, deduplicateJsonSchemaDef = identity, defaultMerger = identity, assigners = [], checks = DEFAULT_CHECKS, mergers, } = {}) {
165
+ function mergeArrayOfSchemaDefinitions(schemas) {
166
+ const l = schemas.length;
167
+ let result = schemas[0];
168
+ for (let i = 1; i < l; i++) {
169
+ const r = mergeSchemaDefinitions(result, schemas[i]);
170
+ if (r === false) {
171
+ return false;
172
+ }
173
+ if (isAllowAnySchema(r)) {
174
+ continue;
175
+ }
176
+ result = r;
177
+ }
178
+ return result;
179
+ }
180
+ function createProperty(constraints, key, value, patterns, oppositeValue, oppositePatterns, oppositeAdditional) {
181
+ constraints.length = 0;
182
+ if (value === false) {
183
+ return false;
184
+ }
185
+ constraints.push(value);
186
+ const isOppositeValueDefined = oppositeValue !== undefined;
187
+ if (isOppositeValueDefined) {
188
+ if (oppositeValue === false) {
189
+ return false;
190
+ }
191
+ constraints.push(oppositeValue);
192
+ }
193
+ if (appendKeyConstraints(constraints, key, oppositePatterns)) {
194
+ return false;
195
+ }
196
+ const isNotYetAllowed = constraints.length < 2;
197
+ if (oppositeAdditional === false) {
198
+ // There are no allowing constraints from opposite side -> drop property
199
+ if (isNotYetAllowed) {
200
+ return undefined;
201
+ }
202
+ // Applying patterns of current schema cause they may disappear
203
+ if (appendKeyConstraints(constraints, key, patterns)) {
204
+ return false;
205
+ }
206
+ }
207
+ else if (isNotYetAllowed && oppositeAdditional !== undefined) {
208
+ constraints.push(oppositeAdditional);
209
+ }
210
+ const l = constraints.length;
211
+ if (l === 1) {
212
+ return constraints[0];
213
+ }
214
+ return mergeArrayOfSchemaDefinitions(constraints);
215
+ }
216
+ function assignPatternPropertiesAndAdditionalPropertiesMerge(target, patterns, patternKeys, matchedPatterns, oppositeAdditional, isOppositeTruthy) {
217
+ const l = patternKeys.length;
218
+ if (l > 0 && oppositeAdditional !== false) {
219
+ if (isOppositeTruthy) {
220
+ // TODO: in some cases we can just assign new value instead of copying
221
+ Object.assign(target, patterns);
222
+ }
223
+ else {
224
+ for (let i = 0; i < l; i++) {
225
+ const pattern = patternKeys[i];
226
+ if (matchedPatterns.has(pattern)) {
227
+ continue;
228
+ }
229
+ target[pattern] = mergeSchemaDefinitions(patterns[pattern], oppositeAdditional);
230
+ }
231
+ }
232
+ }
233
+ return target;
234
+ }
235
+ const propertiesAssigner = (target, { properties: lProps = {}, patternProperties: lPatterns, additionalProperties: lAdditional = true, }, { properties: rProps = {}, patternProperties: rPatterns, additionalProperties: rAdditional = true, }) => {
236
+ // Special case
237
+ const isLAddTruthy = isAllowAnySchema(lAdditional);
238
+ const isRAddTruthy = isAllowAnySchema(rAdditional);
239
+ if (isLAddTruthy && isRAddTruthy) {
240
+ assignSchemaDefinitionOrRecordOfSchemaDefinitions(target, "properties", mergeRecordsOfSchemaDefinitions(lProps, rProps));
241
+ assignSchemaDefinitionOrRecordOfSchemaDefinitions(target, "patternProperties", lPatterns && rPatterns
242
+ ? mergeRecordsOfSchemaDefinitions(lPatterns, rPatterns)
243
+ : (lPatterns ?? rPatterns));
244
+ delete target.additionalProperties;
245
+ return target;
246
+ }
247
+ // Additional Properties
248
+ const additionalProperties = mergeSchemaDefinitions(lAdditional, rAdditional);
249
+ assignSchemaDefinitionOrRecordOfSchemaDefinitions(target, "additionalProperties", additionalProperties);
250
+ // Properties
251
+ const properties = {};
252
+ const lKeys = Object.keys(lProps);
253
+ const lKeysLen = lKeys.length;
254
+ const [lCompiledPatterns, lPatternKeys] = lPatterns
255
+ ? compilePatterns(lPatterns)
256
+ : EMPTY_PATTERNS_AND_KEYS;
257
+ const [rCompiledPatterns, rPatternKeys] = rPatterns
258
+ ? compilePatterns(rPatterns)
259
+ : EMPTY_PATTERNS_AND_KEYS;
260
+ const constraints = [];
261
+ const lKeysSet = new Set();
262
+ const mappedRAdditional = isRAddTruthy ? undefined : rAdditional;
263
+ for (let i = 0; i < lKeysLen; i++) {
264
+ const key = lKeys[i];
265
+ lKeysSet.add(key);
266
+ const prop = createProperty(constraints, key, lProps[key], lCompiledPatterns, rProps[key], rCompiledPatterns, mappedRAdditional);
267
+ if (prop !== undefined) {
268
+ properties[key] = prop;
269
+ }
270
+ }
271
+ const rKeys = Object.keys(rProps);
272
+ const rKeysLen = rKeys.length;
273
+ const mappedLAdditional = isLAddTruthy ? undefined : lAdditional;
274
+ for (let i = 0; i < rKeysLen; i++) {
275
+ const key = rKeys[i];
276
+ if (lKeysSet.has(key)) {
277
+ continue;
278
+ }
279
+ const prop = createProperty(constraints, key, rProps[key], rCompiledPatterns, undefined, lCompiledPatterns, mappedLAdditional);
280
+ if (prop !== undefined) {
281
+ properties[key] = prop;
282
+ }
283
+ }
284
+ assignSchemaDefinitionOrRecordOfSchemaDefinitions(target, "properties", properties);
285
+ // Pattern Properties
286
+ // (lPatterns and rPatterns) or (lPatterns and rAdditional) or (rPatterns and lAdditional)
287
+ let patterns = {};
288
+ const matchedPatterns = new Set();
289
+ if (lPatternKeys.length > 0 && rPatternKeys.length > 0) {
290
+ const gen = createPairCombinations(lPatternKeys, rPatternKeys, (lKey, rKey) => {
291
+ if (isSubRegExp(lKey, rKey)) {
292
+ matchedPatterns.add(lKey);
293
+ }
294
+ if (isSubRegExp(rKey, lKey)) {
295
+ matchedPatterns.add(rKey);
296
+ }
297
+ patterns[mergePatterns(lKey, rKey)] = mergeSchemaDefinitions(lPatterns[lKey], rPatterns[rKey]);
298
+ });
299
+ while (!gen.next().done) {
300
+ /* empty */
301
+ }
302
+ }
303
+ patterns = assignPatternPropertiesAndAdditionalPropertiesMerge(patterns, lPatterns, lPatternKeys, matchedPatterns, rAdditional, isRAddTruthy);
304
+ patterns = assignPatternPropertiesAndAdditionalPropertiesMerge(patterns, rPatterns, rPatternKeys, matchedPatterns, lAdditional, isLAddTruthy);
305
+ assignSchemaDefinitionOrRecordOfSchemaDefinitions(target, "patternProperties", patterns);
306
+ return target;
307
+ };
308
+ const itemsAssigner = (target,
309
+ // NOTE: Schema that has `additionalItems` without an `items` keyword is invalid
310
+ // so the assigner should be triggered only be colliding `items` properties
311
+ // so default values are used only for type narrowing
312
+ { items: lItems = [], additionalItems: lAdditional }, { items: rItems = [], additionalItems: rAdditional }) => {
313
+ const isLArr = Array.isArray(lItems);
314
+ const isRArr = Array.isArray(rItems);
315
+ const itemsArray = [];
316
+ target.items = itemsArray;
317
+ if (isLArr && isRArr) {
318
+ const [l, additional, tail] = lItems.length < rItems.length
319
+ ? [lItems.length, lAdditional, rItems]
320
+ : [rItems.length, rAdditional, lItems];
321
+ let i = 0;
322
+ for (; i < l; i++) {
323
+ itemsArray.push(mergeSchemaDefinitions(lItems[i], rItems[i]));
324
+ }
325
+ if (additional === false) {
326
+ target.additionalItems = false;
327
+ }
328
+ else {
329
+ const isAdditionalTruthy = additional === undefined || isAllowAnySchema(additional);
330
+ for (; i < tail.length; i++) {
331
+ itemsArray.push(isAdditionalTruthy
332
+ ? tail[i]
333
+ : mergeSchemaDefinitions(tail[i], additional));
334
+ }
335
+ assignSchemaDefinitionOrRecordOfSchemaDefinitions(target, "additionalItems", lAdditional !== undefined && rAdditional !== undefined
336
+ ? mergeSchemaDefinitions(lAdditional, rAdditional)
337
+ : (lAdditional ?? rAdditional));
338
+ }
339
+ }
340
+ else if (isLArr || isRArr) {
341
+ const [arr, item, additional] = (isLArr ? [lItems, rItems, lAdditional] : [rItems, lItems, rAdditional]);
342
+ assignSchemaDefinitionOrRecordOfSchemaDefinitions(target, "additionalItems", additional && mergeSchemaDefinitions(additional, item));
343
+ for (let i = 0; i < arr.length; i++) {
344
+ itemsArray.push(mergeSchemaDefinitions(arr[i], item));
345
+ }
346
+ }
347
+ else {
348
+ delete target.additionalItems;
349
+ target.items = mergeSchemaDefinitions(lItems, rItems);
350
+ }
351
+ return target;
352
+ };
353
+ const conditionAssigner = (target, l, r) => {
354
+ assignCondition(target, l);
355
+ const cond = assignCondition({}, r);
356
+ if (target.allOf === undefined) {
357
+ target.allOf = [cond];
358
+ }
359
+ else {
360
+ target.allOf = target.allOf.concat(cond);
361
+ }
362
+ return target;
363
+ };
364
+ function mergeArraysOfSchemaDefinition(l, r) {
365
+ return deduplicateJsonSchemaDef(Array.from(createPairCombinations(l, r, mergeSchemaDefinitions)));
366
+ }
367
+ const ASSIGNERS_MAP = createMap([
368
+ [PROPERTIES_ASSIGNER_KEYS, propertiesAssigner],
369
+ [ITEMS_ASSIGNER_KEYS, itemsAssigner],
370
+ [CONDITION_ASSIGNER_KEYS, conditionAssigner],
371
+ ...assigners,
372
+ ]);
373
+ const CHECKS_MAP = createChecksMap(checks);
374
+ function mergeSchemaDefinitions(left, right) {
375
+ if (left === false || right === false) {
376
+ return false;
377
+ }
378
+ if (isAllowAnySchema(left)) {
379
+ if (isAllowAnySchema(right)) {
380
+ return true;
381
+ }
382
+ return right;
383
+ }
384
+ if (isAllowAnySchema(right)) {
385
+ return left;
386
+ }
387
+ let target = { ...left };
388
+ const assigners = new Set();
389
+ const checks = new Set();
390
+ const rKeys = Object.keys(right);
391
+ const l = rKeys.length;
392
+ for (let i = 0; i < l; i++) {
393
+ const rKey = rKeys[i];
394
+ const rv = right[rKey];
395
+ if (rv === undefined) {
396
+ continue;
397
+ }
398
+ const checkData = CHECKS_MAP.get(rKey);
399
+ if (checkData !== undefined) {
400
+ const l = checkData.length;
401
+ for (let j = 0; j < l; j++) {
402
+ const item = checkData[j];
403
+ if (left[item.oppositeKey] !== undefined) {
404
+ checks.add(item.check);
405
+ }
406
+ }
407
+ }
408
+ const lv = left[rKey];
409
+ if (lv === undefined) {
410
+ // @ts-expect-error too complex
411
+ target[rKey] = rv;
412
+ continue;
413
+ }
414
+ const assign = ASSIGNERS_MAP.get(rKey);
415
+ if (assign) {
416
+ assigners.add(assign);
417
+ continue;
418
+ }
419
+ const merge = MERGERS[rKey] ?? defaultMerger;
420
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
421
+ target[rKey] = merge(lv, rv);
422
+ }
423
+ for (const assign of assigners) {
424
+ target = assign(target, left, right);
425
+ }
426
+ for (const check of checks) {
427
+ check(target);
428
+ }
429
+ return target;
430
+ }
431
+ const mergeRecordsOfSchemaDefinitions = createRecordsMerge(mergeSchemaDefinitions);
432
+ const MERGERS = {
433
+ $id: defaultMerger,
434
+ $ref: defaultMerger,
435
+ $schema: defaultMerger,
436
+ $comment: defaultMerger,
437
+ $defs: mergeRecordsOfSchemaDefinitions,
438
+ definitions: mergeRecordsOfSchemaDefinitions,
439
+ type: (a, b) => {
440
+ if (a === b) {
441
+ return a;
442
+ }
443
+ const isAArr = Array.isArray(a);
444
+ const isBArr = Array.isArray(b);
445
+ if (!isAArr && !isBArr) {
446
+ const intersection = intersectSchemaTypes(a, b);
447
+ if (intersection !== undefined) {
448
+ return intersection;
449
+ }
450
+ }
451
+ else if (isAArr || isBArr) {
452
+ const r = new Set();
453
+ if (isAArr && isBArr) {
454
+ for (const intersection of createPairCombinations(a, b, intersectSchemaTypes)) {
455
+ if (intersection !== undefined) {
456
+ r.add(intersection);
457
+ }
458
+ }
459
+ }
460
+ else {
461
+ const arr = (isAArr ? a : b);
462
+ const el = (isAArr ? b : a);
463
+ const l = arr.length;
464
+ for (let i = 0; i < l; i++) {
465
+ const intersection = intersectSchemaTypes(el, arr[i]);
466
+ if (intersection !== undefined) {
467
+ r.add(intersection);
468
+ }
469
+ }
470
+ }
471
+ const s = r.size;
472
+ if (s === 1) {
473
+ return r.values().next().value;
474
+ }
475
+ if (s > 1) {
476
+ return Array.from(r);
477
+ }
478
+ }
479
+ throw new Error(`It is not possible to create an intersection of the following incompatible types: ${a.toString()}, ${b.toString()}`);
480
+ },
481
+ default: defaultMerger,
482
+ description: defaultMerger,
483
+ title: defaultMerger,
484
+ const: defaultMerger,
485
+ format: defaultMerger,
486
+ contentEncoding: defaultMerger,
487
+ contentMediaType: defaultMerger,
488
+ not: (a, b) => {
489
+ const items = deduplicateJsonSchemaDef([a, b]);
490
+ return items.length === 1 ? items[0] : { anyOf: items };
491
+ },
492
+ pattern: mergePatterns,
493
+ readOnly: mergeBooleans,
494
+ writeOnly: mergeBooleans,
495
+ enum: (a, b) => {
496
+ const data = intersectJson(a, b);
497
+ if (data.length === 0) {
498
+ throw new Error(`Intersection of the following enums is empty: "${JSON.stringify(a)}", "${JSON.stringify(b)}"`);
499
+ }
500
+ return data;
501
+ },
502
+ anyOf: mergeArraysOfSchemaDefinition,
503
+ oneOf: mergeArraysOfSchemaDefinition,
504
+ allOf: (l, r) => deduplicateJsonSchemaDef(l.concat(r)),
505
+ propertyNames: mergeSchemaDefinitions,
506
+ contains: mergeSchemaDefinitions,
507
+ dependencies: createRecordsMerge((a, b) => {
508
+ if (Array.isArray(a)) {
509
+ if (Array.isArray(b)) {
510
+ return union(a, b);
511
+ }
512
+ return mergeSchemaDefinitions(b, { required: a });
513
+ }
514
+ if (Array.isArray(b)) {
515
+ return mergeSchemaDefinitions(a, { required: b });
516
+ }
517
+ return mergeSchemaDefinitions(a, b);
518
+ }),
519
+ examples: (l, r) => {
520
+ // https://datatracker.ietf.org/doc/html/draft-handrews-json-schema-validation-01#section-10.4
521
+ if (!Array.isArray(l) || !Array.isArray(r)) {
522
+ throw new Error(`Value of the 'examples' field should be an array, but got "${JSON.stringify(l)}" and "${JSON.stringify(r)}"`);
523
+ }
524
+ // TODO: Proper deduplication
525
+ return union(l, r);
526
+ },
527
+ multipleOf: (a, b) => {
528
+ let factor = 1;
529
+ while (!Number.isInteger(a) || !Number.isInteger(b)) {
530
+ factor *= 10;
531
+ a *= 10;
532
+ b *= 10;
533
+ }
534
+ return lcm(a, b) / factor;
535
+ },
536
+ exclusiveMaximum: Math.min,
537
+ maximum: Math.min,
538
+ maxItems: Math.min,
539
+ maxLength: Math.min,
540
+ maxProperties: Math.min,
541
+ exclusiveMinimum: Math.max,
542
+ minimum: Math.max,
543
+ minItems: Math.max,
544
+ minLength: Math.max,
545
+ minProperties: Math.max,
546
+ uniqueItems: mergeBooleans,
547
+ required: union,
548
+ ...mergers,
549
+ };
550
+ return {
551
+ mergeSchemaDefinitions,
552
+ mergeArrayOfSchemaDefinitions,
553
+ };
554
+ }
@@ -0,0 +1,2 @@
1
+ export declare function legacyPatternsMerger(a: string, b: string): string;
2
+ export declare function simplePatternsMerger(a: string, b: string): string;
@@ -0,0 +1,6 @@
1
+ export function legacyPatternsMerger(a, b) {
2
+ return a === b ? a : `(?=${a})(?=${b})`;
3
+ }
4
+ export function simplePatternsMerger(a, b) {
5
+ return a === b ? a : `^(?=.*(?:${a}))(?=.*(?:${b})).*$`;
6
+ }
@@ -0,0 +1,4 @@
1
+ import type { JSONSchema7 as Schema, JSONSchema7Definition as SchemaDefinition } from "json-schema";
2
+ import { type AnySubSchemaKey, type TransformedSchemaDefinition } from "./json-schema.ts";
3
+ import type { SchemaTraverserContext } from "./traverse.ts";
4
+ export declare function transformSchemaDefinition<R>(schema: SchemaDefinition, transform: (shallowCopy: TransformedSchemaDefinition<R, Schema>, ctx: SchemaTraverserContext<AnySubSchemaKey>) => R, ctx?: SchemaTraverserContext<AnySubSchemaKey>): R;
@@ -0,0 +1,72 @@
1
+ import { SUB_SCHEMAS, RECORDS_OF_SUB_SCHEMAS, ARRAYS_OF_SUB_SCHEMAS, isSchemaObject, } from "./json-schema.js";
2
+ export function transformSchemaDefinition(schema, transform, ctx = { type: "root", path: [] }) {
3
+ if (!isSchemaObject(schema)) {
4
+ return transform(schema, ctx);
5
+ }
6
+ const shallowCopy = {
7
+ ...schema,
8
+ };
9
+ for (const key of ARRAYS_OF_SUB_SCHEMAS) {
10
+ const array = schema[key];
11
+ if (array === undefined || !Array.isArray(array)) {
12
+ continue;
13
+ }
14
+ const c = {
15
+ type: "array",
16
+ parent: schema,
17
+ key,
18
+ index: 0,
19
+ path: ctx.path.concat(key, 0),
20
+ };
21
+ shallowCopy[key] = array.map((item, index) => {
22
+ c.index = index;
23
+ c.path[c.path.length - 1] = index;
24
+ return transformSchemaDefinition(item, transform, c);
25
+ });
26
+ }
27
+ const map = new Map();
28
+ for (const key of RECORDS_OF_SUB_SCHEMAS) {
29
+ const record = schema[key];
30
+ if (record === undefined) {
31
+ continue;
32
+ }
33
+ const c = {
34
+ type: "record",
35
+ parent: schema,
36
+ key,
37
+ property: "",
38
+ path: ctx.path.concat(key, ""),
39
+ };
40
+ const keys = Object.keys(record);
41
+ const keysLen = keys.length;
42
+ for (let i = 0; i < keysLen; i++) {
43
+ const property = keys[i];
44
+ const value = record[property];
45
+ if (Array.isArray(value)) {
46
+ map.set(property, value);
47
+ continue;
48
+ }
49
+ c.property = property;
50
+ c.path[c.path.length - 1] = property;
51
+ map.set(property, transformSchemaDefinition(value, transform, c));
52
+ }
53
+ shallowCopy[key] = Object.fromEntries(map);
54
+ map.clear();
55
+ }
56
+ const c = {
57
+ type: "sub",
58
+ parent: schema,
59
+ key: "items",
60
+ path: ctx.path.concat(""),
61
+ };
62
+ for (const key of SUB_SCHEMAS) {
63
+ const value = schema[key];
64
+ if (value === undefined || Array.isArray(value)) {
65
+ continue;
66
+ }
67
+ c.key = key;
68
+ c.path[c.path.length - 1] = key;
69
+ shallowCopy[key] = transformSchemaDefinition(value, transform, c);
70
+ }
71
+ return transform(shallowCopy, ctx);
72
+ }
@@ -0,0 +1,26 @@
1
+ import type { JSONSchema7 as Schema, JSONSchema7Definition as SchemaDefinition } from "json-schema";
2
+ import type { Visitor } from "../traverser.ts";
3
+ import type { AnySubSchemaKey, SubSchemaKey, SubSchemasArrayKey, SubSchemasRecordKey } from "./json-schema.ts";
4
+ export type SchemaTraverserContextType = "array" | "record" | "sub" | "root";
5
+ export interface AbstractSchemaTraverserContext<T extends SchemaTraverserContextType, K extends AnySubSchemaKey> {
6
+ type: T;
7
+ path: SubSchemasArrayKey extends K ? Array<string | number> : string[];
8
+ }
9
+ export interface ArraySchemaTraverserContext<K extends AnySubSchemaKey> extends AbstractSchemaTraverserContext<"array", K> {
10
+ parent: Schema;
11
+ key: SubSchemasArrayKey & K;
12
+ index: number;
13
+ }
14
+ export interface RecordSchemaTraverserContext<K extends AnySubSchemaKey> extends AbstractSchemaTraverserContext<"record", K> {
15
+ parent: Schema;
16
+ key: SubSchemasRecordKey & K;
17
+ property: string;
18
+ }
19
+ export interface SubSchemaTraverserContext<K extends AnySubSchemaKey> extends AbstractSchemaTraverserContext<"sub", K> {
20
+ parent: Schema;
21
+ key: SubSchemaKey & K;
22
+ }
23
+ export interface RootSchemaTraverserContext<K extends AnySubSchemaKey> extends AbstractSchemaTraverserContext<"root", K> {
24
+ }
25
+ export type SchemaTraverserContext<K extends AnySubSchemaKey> = ArraySchemaTraverserContext<K> | RecordSchemaTraverserContext<K> | SubSchemaTraverserContext<K> | RootSchemaTraverserContext<K>;
26
+ export type SchemaDefinitionVisitor<K extends AnySubSchemaKey, R> = Visitor<SchemaDefinition, SchemaTraverserContext<K>, R>;
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,2 @@
1
+ export declare const gcd: (a: number, b: number) => number;
2
+ export declare const lcm: (a: number, b: number) => number;
@@ -0,0 +1,2 @@
1
+ export const gcd = (a, b) => (a ? gcd(b % a, a) : b);
2
+ export const lcm = (a, b) => Math.abs(a * b) / gcd(a, b);
@@ -0,0 +1,7 @@
1
+ export interface MapLike<K, V> {
2
+ has(key: K): boolean;
3
+ get(key: K): V | undefined;
4
+ set(key: K, value: V): void;
5
+ }
6
+ export declare function memoize<Arg, Return>(cache: MapLike<Arg, Return>, func: (arg: Arg) => Return): (arg: Arg) => Return;
7
+ export declare const weakMemoize: <Arg extends object, Return>(cache: WeakMap<Arg, Return>, fn: (arg: Arg) => Return) => (arg: Arg) => Return;