@orpc/json-schema 1.14.10 → 1.14.11

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/index.mjs CHANGED
@@ -1,5 +1,163 @@
1
- import { isObject, NullProtoObj, toArray, guard } from '@orpc/shared';
2
- import { CompositeSchemaConverter } from '@orpc/openapi';
1
+ import { get, isPlainObject, tryOrUndefined, toArray, isDeepEqual, omit, isTypescriptObject } from '@orpc/shared';
2
+ export { Format as JsonSchemaFormat, TypeName as JsonSchemaType } from 'json-schema-typed/draft-2020-12';
3
+ import { ORPCError, cloneORPCError } from '@orpc/client';
4
+ import { getProcedureContractOrThrow } from '@orpc/contract';
5
+
6
+ const JSON_SCHEMA_LOGIC_KEYWORDS = /* @__PURE__ */ new Set([
7
+ "$dynamicRef",
8
+ "$ref",
9
+ "additionalItems",
10
+ "additionalProperties",
11
+ "allOf",
12
+ "anyOf",
13
+ "const",
14
+ "contains",
15
+ "contentEncoding",
16
+ "contentMediaType",
17
+ "contentSchema",
18
+ "dependencies",
19
+ "dependentRequired",
20
+ "dependentSchemas",
21
+ "else",
22
+ "enum",
23
+ "exclusiveMaximum",
24
+ "exclusiveMinimum",
25
+ "format",
26
+ "if",
27
+ "items",
28
+ "maxContains",
29
+ "maximum",
30
+ "maxItems",
31
+ "maxLength",
32
+ "maxProperties",
33
+ "minContains",
34
+ "minimum",
35
+ "minItems",
36
+ "minLength",
37
+ "minProperties",
38
+ "multipleOf",
39
+ "not",
40
+ "oneOf",
41
+ "pattern",
42
+ "patternProperties",
43
+ "prefixItems",
44
+ "properties",
45
+ "propertyNames",
46
+ "required",
47
+ "then",
48
+ "type",
49
+ "unevaluatedItems",
50
+ "unevaluatedProperties",
51
+ "uniqueItems"
52
+ ]);
53
+ const JSON_SCHEMA_PRIMITIVE_TYPES = /* @__PURE__ */ new Set(["string", "number", "integer", "boolean", "null"]);
54
+ const JSON_SCHEMA_RECORD_KEYWORDS = /* @__PURE__ */ new Set(["properties", "patternProperties", "dependentSchemas", "dependencies", "$defs"]);
55
+
56
+ function encodeJsonPointerSegment(segment) {
57
+ return segment.replaceAll("~", "~0").replaceAll("/", "~1");
58
+ }
59
+ function decodeJsonPointerSegment(segment) {
60
+ return segment.replaceAll("~1", "/").replaceAll("~0", "~");
61
+ }
62
+ function visitJsonSchemaRefs(value, visit, schemaLevel = true, seen = /* @__PURE__ */ new Set()) {
63
+ if (!value || typeof value !== "object" || seen.has(value)) {
64
+ return;
65
+ }
66
+ seen.add(value);
67
+ if (Array.isArray(value)) {
68
+ for (const item of value) {
69
+ visitJsonSchemaRefs(item, visit, schemaLevel, seen);
70
+ }
71
+ return;
72
+ }
73
+ for (const [key, val] of Object.entries(value)) {
74
+ if (key === "$ref" && typeof val === "string") {
75
+ visit(val);
76
+ } else if (!schemaLevel) {
77
+ visitJsonSchemaRefs(val, visit, true, seen);
78
+ } else if (JSON_SCHEMA_LOGIC_KEYWORDS.has(key) || JSON_SCHEMA_RECORD_KEYWORDS.has(key)) {
79
+ visitJsonSchemaRefs(val, visit, !JSON_SCHEMA_RECORD_KEYWORDS.has(key), seen);
80
+ }
81
+ }
82
+ }
83
+ function mapJsonSchemaRefs(value, map, schemaLevel = true, path = []) {
84
+ if (!value || typeof value !== "object") {
85
+ return value;
86
+ }
87
+ if (Array.isArray(value)) {
88
+ return value.map((item, index) => mapJsonSchemaRefs(item, map, schemaLevel, [...path, index]));
89
+ }
90
+ const result = {};
91
+ for (const [key, val] of Object.entries(value)) {
92
+ if (key === "$ref" && typeof val === "string") {
93
+ result[key] = map(val, [...path, key]);
94
+ } else if (!schemaLevel) {
95
+ result[key] = mapJsonSchemaRefs(val, map, true, [...path, key]);
96
+ } else if (JSON_SCHEMA_LOGIC_KEYWORDS.has(key) || JSON_SCHEMA_RECORD_KEYWORDS.has(key)) {
97
+ result[key] = mapJsonSchemaRefs(val, map, !JSON_SCHEMA_RECORD_KEYWORDS.has(key), [...path, key]);
98
+ } else {
99
+ result[key] = val;
100
+ }
101
+ }
102
+ return result;
103
+ }
104
+ function hoistRecursiveRefToDef(schema) {
105
+ if (typeof schema !== "object") {
106
+ return schema;
107
+ }
108
+ let defName;
109
+ const rewritten = mapJsonSchemaRefs(schema, (ref) => {
110
+ if (ref === "#" || ref.startsWith("#/") && !ref.startsWith("#/$defs/") && get(schema, ref.slice(2).split("/").map(decodeJsonPointerSegment)) !== void 0) {
111
+ defName ??= findRecursiveJsonSchemaDefName(schema.$defs);
112
+ return `#/$defs/${encodeJsonPointerSegment(defName)}${ref.slice(1)}`;
113
+ }
114
+ return ref;
115
+ });
116
+ if (defName === void 0) {
117
+ return schema;
118
+ }
119
+ const { $defs, ...rest } = rewritten;
120
+ return {
121
+ $ref: `#/$defs/${encodeJsonPointerSegment(defName)}`,
122
+ $defs: {
123
+ ...$defs,
124
+ [defName]: rest
125
+ }
126
+ };
127
+ }
128
+ function resolveJsonSchemaRootLocalRef(schema, $defs) {
129
+ if (typeof schema === "boolean") {
130
+ return schema;
131
+ }
132
+ if (arguments.length === 1) {
133
+ $defs = schema.$defs;
134
+ }
135
+ if (!$defs) {
136
+ return schema;
137
+ }
138
+ if (typeof schema.$ref !== "string" || !schema.$ref.startsWith("#/$defs/")) {
139
+ return schema;
140
+ }
141
+ const resolved = get($defs, schema.$ref.slice("#/$defs/".length).split("/").map(decodeJsonPointerSegment));
142
+ if (resolved === void 0) {
143
+ return schema;
144
+ }
145
+ if (typeof resolved !== "object") {
146
+ return resolved;
147
+ }
148
+ const { $ref: _ref, ...rest } = schema;
149
+ return resolveJsonSchemaRootLocalRef({
150
+ ...rest,
151
+ ...resolved
152
+ });
153
+ }
154
+ function findRecursiveJsonSchemaDefName(defs) {
155
+ let index = 0;
156
+ while (defs?.[`__schema${index}`] !== void 0) {
157
+ index++;
158
+ }
159
+ return `__schema${index}`;
160
+ }
3
161
 
4
162
  var JsonSchemaXNativeType = /* @__PURE__ */ ((JsonSchemaXNativeType2) => {
5
163
  JsonSchemaXNativeType2["BigInt"] = "bigint";
@@ -11,87 +169,101 @@ var JsonSchemaXNativeType = /* @__PURE__ */ ((JsonSchemaXNativeType2) => {
11
169
  return JsonSchemaXNativeType2;
12
170
  })(JsonSchemaXNativeType || {});
13
171
 
14
- const FLEXIBLE_DATE_FORMAT_REGEX = /^[^-]+-[^-]+-[^-]+$/;
172
+ const UNSATISFIED = 0;
173
+ const LOOSELY_SATISFIED = 1;
174
+ const SATISFIED = 2;
175
+ function minSatisfaction(a, b) {
176
+ return a < b ? a : b;
177
+ }
15
178
  class JsonSchemaCoercer {
16
- coerce(schema, value, options = {}) {
17
- const [, coerced] = this.#coerce(schema, value, options);
179
+ coerce([schema, optional], value) {
180
+ if (optional && value === void 0) {
181
+ return value;
182
+ }
183
+ const [, coerced] = this.coerceInternal(schema, schema, value);
18
184
  return coerced;
19
185
  }
20
- #coerce(schema, originalValue, options) {
186
+ coerceInternal(rootSchema, schema, value, appliedRefs) {
21
187
  if (typeof schema === "boolean") {
22
- return [schema, originalValue];
188
+ return [schema ? SATISFIED : UNSATISFIED, value];
23
189
  }
24
190
  if (Array.isArray(schema.type)) {
25
- return this.#coerce({
26
- anyOf: schema.type.map((type) => ({ ...schema, type }))
27
- }, originalValue, options);
191
+ return this.coerceInternal(
192
+ rootSchema,
193
+ { anyOf: schema.type.map((type) => ({ ...schema, type })) },
194
+ value,
195
+ appliedRefs
196
+ );
28
197
  }
29
- let coerced = originalValue;
30
- let satisfied = true;
198
+ let coerced = value;
199
+ let satisfied = SATISFIED;
31
200
  if (typeof schema.$ref === "string") {
32
- const refSchema = options?.components?.[schema.$ref];
33
- if (refSchema !== void 0) {
34
- const [subSatisfied, subCoerced] = this.#coerce(refSchema, coerced, options);
201
+ const resolved = schema.$ref.startsWith("#/") ? get(rootSchema, schema.$ref.slice("#/".length).split("/").map(decodeJsonPointerSegment)) : schema.$ref === "#" ? rootSchema : void 0;
202
+ if (resolved !== void 0 && !appliedRefs?.has(resolved)) {
203
+ appliedRefs ??= /* @__PURE__ */ new Set();
204
+ appliedRefs.add(resolved);
205
+ const [subSatisfied, subCoerced] = this.coerceInternal(rootSchema, resolved, coerced, appliedRefs);
206
+ appliedRefs.delete(resolved);
35
207
  coerced = subCoerced;
36
- satisfied = subSatisfied;
208
+ satisfied = minSatisfaction(satisfied, subSatisfied);
37
209
  }
38
210
  }
39
211
  const enumValues = schema.const !== void 0 ? [schema.const] : schema.enum;
40
212
  if (enumValues !== void 0 && !enumValues.includes(coerced)) {
41
213
  if (typeof coerced === "string") {
42
- const numberValue = this.#stringToNumber(coerced);
214
+ const numberValue = stringToNumber(coerced);
43
215
  if (enumValues.includes(numberValue)) {
44
216
  coerced = numberValue;
45
217
  } else {
46
- const booleanValue = this.#stringToBoolean(coerced);
218
+ const booleanValue = stringToBoolean(coerced);
47
219
  if (enumValues.includes(booleanValue)) {
48
220
  coerced = booleanValue;
49
221
  } else {
50
- satisfied = false;
222
+ satisfied = UNSATISFIED;
51
223
  }
52
224
  }
53
225
  } else {
54
- satisfied = false;
226
+ satisfied = UNSATISFIED;
55
227
  }
56
228
  }
57
- if (typeof schema.type === "string") {
229
+ if (schema.type) {
58
230
  switch (schema.type) {
59
231
  case "null": {
60
232
  if (coerced !== null) {
61
- satisfied = false;
233
+ satisfied = UNSATISFIED;
62
234
  }
63
235
  break;
64
236
  }
65
237
  case "string": {
66
238
  if (typeof coerced !== "string") {
67
- satisfied = false;
239
+ satisfied = UNSATISFIED;
68
240
  }
69
241
  break;
70
242
  }
71
243
  case "number": {
72
244
  if (typeof coerced === "string") {
73
- coerced = this.#stringToNumber(coerced);
245
+ coerced = stringToNumber(coerced);
74
246
  }
75
247
  if (typeof coerced !== "number") {
76
- satisfied = false;
248
+ satisfied = UNSATISFIED;
77
249
  }
78
250
  break;
79
251
  }
80
252
  case "integer": {
81
253
  if (typeof coerced === "string") {
82
- coerced = this.#stringToInteger(coerced);
254
+ coerced = stringToInteger(coerced);
83
255
  }
84
256
  if (typeof coerced !== "number" || !Number.isInteger(coerced)) {
85
- satisfied = false;
257
+ satisfied = UNSATISFIED;
86
258
  }
87
259
  break;
88
260
  }
89
261
  case "boolean": {
90
262
  if (typeof coerced === "string") {
91
- coerced = this.#stringToBoolean(coerced);
263
+ coerced = stringToBoolean(coerced);
92
264
  }
93
265
  if (typeof coerced !== "boolean") {
94
- satisfied = false;
266
+ satisfied = UNSATISFIED;
95
267
  }
96
268
  break;
97
269
  }
@@ -103,26 +275,24 @@ class JsonSchemaCoercer {
103
275
  const coercedItems = coerced.map((item, i) => {
104
276
  const subSchema = prefixItemSchemas[i] ?? itemSchema;
105
277
  if (subSchema === void 0) {
106
- satisfied = false;
278
+ satisfied = minSatisfaction(satisfied, LOOSELY_SATISFIED);
107
279
  return item;
108
280
  }
109
- const [subSatisfied, subCoerced] = this.#coerce(subSchema, item, options);
110
- if (!subSatisfied) {
111
- satisfied = false;
112
- }
281
+ const [subSatisfied, subCoerced] = this.coerceInternal(rootSchema, subSchema, item);
282
+ satisfied = minSatisfaction(satisfied, subSatisfied);
113
283
  if (subCoerced !== item) {
114
284
  shouldUseCoercedItems = true;
115
285
  }
116
286
  return subCoerced;
117
287
  });
118
288
  if (coercedItems.length < prefixItemSchemas.length) {
119
- satisfied = false;
289
+ satisfied = UNSATISFIED;
120
290
  }
121
291
  if (shouldUseCoercedItems) {
122
292
  coerced = coercedItems;
123
293
  }
124
294
  } else {
125
- satisfied = false;
295
+ satisfied = UNSATISFIED;
126
296
  }
127
297
  break;
128
298
  }
@@ -130,37 +300,38 @@ class JsonSchemaCoercer {
130
300
  if (Array.isArray(coerced)) {
131
301
  coerced = { ...coerced };
132
302
  }
133
- if (isObject(coerced)) {
303
+ if (isPlainObject(coerced)) {
134
304
  let shouldUseCoercedItems = false;
135
- const coercedItems = new NullProtoObj();
136
- const patternProperties = Object.entries(schema.patternProperties ?? {}).map(([key, value]) => [new RegExp(key), value]);
305
+ const coercedItems = { ...coerced };
306
+ const patternProperties = Object.entries(schema.patternProperties ?? {}).flatMap(([key, value2]) => {
307
+ const pattern = tryOrUndefined(() => new RegExp(key));
308
+ return pattern ? [[pattern, value2]] : [];
309
+ });
310
+ const propertySchemas = schema.properties;
137
311
  for (const key in coerced) {
138
- const value = coerced[key];
139
- const subSchema = (schema.properties !== void 0 && Object.hasOwn(schema.properties, key) ? schema.properties[key] : void 0) ?? patternProperties.find(([pattern]) => pattern.test(key))?.[1] ?? schema.additionalProperties;
140
- if (value === void 0 && !schema.required?.includes(key)) {
141
- coercedItems[key] = value;
142
- } else if (subSchema === void 0) {
143
- coercedItems[key] = value;
144
- satisfied = false;
145
- } else {
146
- const [subSatisfied, subCoerced] = this.#coerce(subSchema, value, options);
147
- coercedItems[key] = subCoerced;
148
- if (!subSatisfied) {
149
- satisfied = false;
150
- }
151
- if (subCoerced !== value) {
152
- shouldUseCoercedItems = true;
312
+ const value2 = coerced[key];
313
+ const subSchema = (propertySchemas !== void 0 && Object.hasOwn(propertySchemas, key) ? propertySchemas[key] : void 0) ?? patternProperties.find(([pattern]) => pattern.test(key))?.[1] ?? schema.additionalProperties;
314
+ if (value2 !== void 0 || schema.required?.includes(key)) {
315
+ if (subSchema === void 0) {
316
+ satisfied = minSatisfaction(satisfied, LOOSELY_SATISFIED);
317
+ } else {
318
+ const [subSatisfied, subCoerced] = this.coerceInternal(rootSchema, subSchema, value2);
319
+ coercedItems[key] = subCoerced;
320
+ satisfied = minSatisfaction(satisfied, subSatisfied);
321
+ if (subCoerced !== value2) {
322
+ shouldUseCoercedItems = true;
323
+ }
153
324
  }
154
325
  }
155
326
  }
156
327
  if (schema.required?.some((key) => !Object.hasOwn(coercedItems, key))) {
157
- satisfied = false;
328
+ satisfied = UNSATISFIED;
158
329
  }
159
330
  if (shouldUseCoercedItems) {
160
331
  coerced = coercedItems;
161
332
  }
162
333
  } else {
163
- satisfied = false;
334
+ satisfied = UNSATISFIED;
164
335
  }
165
336
  break;
166
337
  }
@@ -170,60 +341,60 @@ class JsonSchemaCoercer {
170
341
  switch (schema["x-native-type"]) {
171
342
  case JsonSchemaXNativeType.Date: {
172
343
  if (typeof coerced === "string") {
173
- coerced = this.#stringToDate(coerced);
344
+ coerced = stringToDate(coerced);
174
345
  }
175
346
  if (!(coerced instanceof Date)) {
176
- satisfied = false;
347
+ satisfied = UNSATISFIED;
177
348
  }
178
349
  break;
179
350
  }
180
351
  case JsonSchemaXNativeType.BigInt: {
181
352
  switch (typeof coerced) {
182
353
  case "string":
183
- coerced = this.#stringToBigInt(coerced);
354
+ coerced = stringToBigInt(coerced);
184
355
  break;
185
356
  case "number":
186
- coerced = this.#numberToBigInt(coerced);
357
+ coerced = numberToBigInt(coerced);
187
358
  break;
188
359
  }
189
360
  if (typeof coerced !== "bigint") {
190
- satisfied = false;
361
+ satisfied = UNSATISFIED;
191
362
  }
192
363
  break;
193
364
  }
194
365
  case JsonSchemaXNativeType.RegExp: {
195
366
  if (typeof coerced === "string") {
196
- coerced = this.#stringToRegExp(coerced);
367
+ coerced = stringToRegExp(coerced);
197
368
  }
198
369
  if (!(coerced instanceof RegExp)) {
199
- satisfied = false;
370
+ satisfied = UNSATISFIED;
200
371
  }
201
372
  break;
202
373
  }
203
374
  case JsonSchemaXNativeType.Url: {
204
375
  if (typeof coerced === "string") {
205
- coerced = this.#stringToURL(coerced);
376
+ coerced = stringToURL(coerced);
206
377
  }
207
378
  if (!(coerced instanceof URL)) {
208
- satisfied = false;
379
+ satisfied = UNSATISFIED;
209
380
  }
210
381
  break;
211
382
  }
212
383
  case JsonSchemaXNativeType.Set: {
213
384
  if (Array.isArray(coerced)) {
214
- coerced = this.#arrayToSet(coerced);
385
+ coerced = arrayToSet(coerced);
215
386
  }
216
387
  if (!(coerced instanceof Set)) {
217
- satisfied = false;
388
+ satisfied = UNSATISFIED;
218
389
  }
219
390
  break;
220
391
  }
221
392
  case JsonSchemaXNativeType.Map: {
222
393
  if (Array.isArray(coerced)) {
223
- coerced = this.#arrayToMap(coerced);
394
+ coerced = arrayToMap(coerced);
224
395
  }
225
396
  if (!(coerced instanceof Map)) {
226
- satisfied = false;
397
+ satisfied = UNSATISFIED;
227
398
  }
228
399
  break;
229
400
  }
@@ -231,133 +402,649 @@ class JsonSchemaCoercer {
231
402
  }
232
403
  if (schema.allOf) {
233
404
  for (const subSchema of schema.allOf) {
234
- const [subSatisfied, subCoerced] = this.#coerce(subSchema, coerced, options);
405
+ const [subSatisfied, subCoerced] = this.coerceInternal(rootSchema, subSchema, coerced, appliedRefs);
235
406
  coerced = subCoerced;
236
- if (!subSatisfied) {
237
- satisfied = false;
238
- }
407
+ satisfied = minSatisfaction(satisfied, subSatisfied);
239
408
  }
240
409
  }
241
410
  for (const key of ["anyOf", "oneOf"]) {
242
411
  if (schema[key]) {
243
- let bestOptions;
412
+ let best;
244
413
  for (const subSchema of schema[key]) {
245
- const [subSatisfied, subCoerced] = this.#coerce(subSchema, coerced, options);
246
- if (subSatisfied) {
247
- if (!bestOptions || subCoerced === coerced) {
248
- bestOptions = { coerced: subCoerced, satisfied: subSatisfied };
249
- }
250
- if (subCoerced === coerced) {
251
- break;
252
- }
414
+ const [subSatisfied, subCoerced] = this.coerceInternal(rootSchema, subSchema, coerced, appliedRefs);
415
+ if (subSatisfied === UNSATISFIED) {
416
+ continue;
417
+ }
418
+ if (subCoerced === coerced) {
419
+ best = { satisfied: subSatisfied, value: subCoerced };
420
+ break;
253
421
  }
422
+ if (!best || subSatisfied > best.satisfied) {
423
+ best = { satisfied: subSatisfied, value: subCoerced };
424
+ }
425
+ }
426
+ if (best) {
427
+ coerced = best.value;
428
+ satisfied = minSatisfaction(satisfied, best.satisfied);
429
+ } else {
430
+ satisfied = UNSATISFIED;
254
431
  }
255
- coerced = bestOptions ? bestOptions.coerced : coerced;
256
- satisfied = bestOptions ? bestOptions.satisfied : false;
257
432
  }
258
433
  }
259
434
  if (typeof schema.not !== "undefined") {
260
- const [notSatisfied] = this.#coerce(schema.not, coerced, options);
261
- if (notSatisfied) {
262
- satisfied = false;
435
+ const [notSatisfied] = this.coerceInternal(rootSchema, schema.not, coerced, appliedRefs);
436
+ if (notSatisfied !== UNSATISFIED) {
437
+ satisfied = UNSATISFIED;
263
438
  }
264
439
  }
265
440
  return [satisfied, coerced];
266
441
  }
267
- #stringToNumber(value) {
268
- const num = Number.parseFloat(value);
269
- if (Number.isNaN(num) || num !== Number(value)) {
270
- return value;
442
+ }
443
+ const NUMBER_PATTERN = /^-?(?:0|[1-9]\d*)(?:\.\d+)?$/;
444
+ function stringToNumber(value) {
445
+ if (!NUMBER_PATTERN.test(value)) {
446
+ return value;
447
+ }
448
+ const num = Number(value);
449
+ if (num < Number.MIN_SAFE_INTEGER || num > Number.MAX_SAFE_INTEGER) {
450
+ return value;
451
+ }
452
+ return num;
453
+ }
454
+ const INTEGER_PATTERN = /^-?(?:0|[1-9]\d*)$/;
455
+ function stringToInteger(value) {
456
+ if (!INTEGER_PATTERN.test(value)) {
457
+ return value;
458
+ }
459
+ const num = Number(value);
460
+ if (!Number.isSafeInteger(num)) {
461
+ return value;
462
+ }
463
+ return num;
464
+ }
465
+ function stringToBigInt(value) {
466
+ if (!INTEGER_PATTERN.test(value)) {
467
+ return value;
468
+ }
469
+ return BigInt(value);
470
+ }
471
+ function numberToBigInt(value) {
472
+ if (!Number.isInteger(value)) {
473
+ return value;
474
+ }
475
+ return BigInt(value);
476
+ }
477
+ function stringToBoolean(value) {
478
+ const lower = value.toLowerCase();
479
+ if (lower === "false" || lower === "off") {
480
+ return false;
481
+ }
482
+ if (lower === "true" || lower === "on") {
483
+ return true;
484
+ }
485
+ return value;
486
+ }
487
+ const DATE_TIME_PATTERN = /^[+-]?\d{4,6}-\d{1,2}-\d{1,2}(?:[T ].*)?$/;
488
+ function stringToDate(value) {
489
+ if (!DATE_TIME_PATTERN.test(value)) {
490
+ return value;
491
+ }
492
+ const date = new Date(value);
493
+ if (Number.isNaN(date.getTime())) {
494
+ return value;
495
+ }
496
+ return date;
497
+ }
498
+ const REGEXP_PATTERN = /^\/([\s\S]*)\/([a-z]*)$/;
499
+ function stringToRegExp(value) {
500
+ const match = value.match(REGEXP_PATTERN);
501
+ if (match) {
502
+ const [, pattern, flags] = match;
503
+ return tryOrUndefined(() => new RegExp(pattern, flags)) ?? value;
504
+ }
505
+ return value;
506
+ }
507
+ function stringToURL(value) {
508
+ return tryOrUndefined(() => new URL(value)) ?? value;
509
+ }
510
+ function arrayToSet(value) {
511
+ const set = new Set(value);
512
+ if (set.size !== value.length) {
513
+ return value;
514
+ }
515
+ return set;
516
+ }
517
+ function arrayToMap(value) {
518
+ if (value.some((item) => !Array.isArray(item) || item.length !== 2)) {
519
+ return value;
520
+ }
521
+ const result = new Map(value);
522
+ if (result.size !== value.length) {
523
+ return value;
524
+ }
525
+ return result;
526
+ }
527
+
528
+ function isJsonPrimitiveSchema(schema) {
529
+ if (typeof schema === "boolean") {
530
+ return false;
531
+ }
532
+ if (typeof schema.type === "string" && JSON_SCHEMA_PRIMITIVE_TYPES.has(schema.type)) {
533
+ return true;
534
+ }
535
+ if (schema.const !== void 0) {
536
+ return true;
537
+ }
538
+ if (schema.enum !== void 0) {
539
+ return true;
540
+ }
541
+ return false;
542
+ }
543
+ function isJsonFileSchema(schema) {
544
+ return typeof schema !== "boolean" && schema.type === "string" && (typeof schema.contentMediaType === "string" || schema.format === "binary" || schema.contentEncoding === "binary");
545
+ }
546
+ function isJsonObjectSchema(schema) {
547
+ return typeof schema !== "boolean" && schema.type === "object";
548
+ }
549
+ function isJsonArraySchema(schema) {
550
+ return typeof schema !== "boolean" && schema.type === "array";
551
+ }
552
+ function isUnconstrainedSchema(schema) {
553
+ if (typeof schema === "boolean") {
554
+ return schema;
555
+ }
556
+ if (Object.keys(schema).every((k) => !JSON_SCHEMA_LOGIC_KEYWORDS.has(k))) {
557
+ return true;
558
+ }
559
+ return false;
560
+ }
561
+ function ensureJsonSchemaObject(schema) {
562
+ if (typeof schema === "boolean") {
563
+ return schema ? {} : { not: {} };
564
+ }
565
+ return schema;
566
+ }
567
+
568
+ function combineJsonSchemasWithComposition(keyword, schemas) {
569
+ if (schemas.length <= 1) {
570
+ return schemas[0] ?? true;
571
+ }
572
+ const mergedDefs = {};
573
+ const compositionBranches = [];
574
+ for (let i = 0; i < schemas.length; i++) {
575
+ const schema = schemas[i];
576
+ if (typeof schema === "boolean") {
577
+ compositionBranches.push(schema);
578
+ continue;
579
+ }
580
+ const { $defs, ...rest } = schema;
581
+ const renameMap = {};
582
+ const promotedNames = /* @__PURE__ */ new Set();
583
+ if ($defs) {
584
+ for (const [name, def] of Object.entries($defs)) {
585
+ if (def === void 0)
586
+ continue;
587
+ promotedNames.add(name);
588
+ if (name in mergedDefs) {
589
+ if (isDeepEqual(mergedDefs[name], def)) {
590
+ continue;
591
+ }
592
+ let counter = 2;
593
+ let newName = `${name}${counter}`;
594
+ while (newName in mergedDefs) {
595
+ counter++;
596
+ newName = `${name}${counter}`;
597
+ }
598
+ mergedDefs[newName] = def;
599
+ renameMap[name] = newName;
600
+ } else {
601
+ mergedDefs[name] = def;
602
+ }
603
+ }
271
604
  }
272
- return num;
605
+ compositionBranches.push(mapJsonSchemaRefs(
606
+ rest,
607
+ (ref) => {
608
+ if (ref === "#") {
609
+ return `#/${keyword}/${i}`;
610
+ }
611
+ if (ref.startsWith("#/$defs/")) {
612
+ const afterPrefix = ref.slice("#/$defs/".length);
613
+ const slashIdx = afterPrefix.indexOf("/");
614
+ const encodedSegment = slashIdx === -1 ? afterPrefix : afterPrefix.slice(0, slashIdx);
615
+ const rest2 = slashIdx === -1 ? "" : afterPrefix.slice(slashIdx);
616
+ const defName = decodeJsonPointerSegment(encodedSegment);
617
+ if (!promotedNames.has(defName)) {
618
+ return ref;
619
+ }
620
+ if (defName in renameMap) {
621
+ return `#/$defs/${encodeJsonPointerSegment(renameMap[defName])}${rest2}`;
622
+ }
623
+ return ref;
624
+ }
625
+ if (ref.startsWith("#/") && get(rest, ref.slice(2).split("/").map(decodeJsonPointerSegment)) !== void 0) {
626
+ return `#/${keyword}/${i}/${ref.slice(2)}`;
627
+ }
628
+ return ref;
629
+ }
630
+ ));
273
631
  }
274
- #stringToInteger(value) {
275
- const num = Number.parseInt(value);
276
- if (Number.isNaN(num) || num !== Number(value)) {
277
- return value;
632
+ const result = { [keyword]: compositionBranches };
633
+ if (Object.keys(mergedDefs).length > 0) {
634
+ result.$defs = mergedDefs;
635
+ }
636
+ return result;
637
+ }
638
+ function combineJsonObjectSchemaEntries(entries) {
639
+ const properties = {};
640
+ const required = [];
641
+ const mergedDefs = {};
642
+ for (const [name, propertySchema, optional] of entries) {
643
+ if (!optional) {
644
+ required.push(name);
645
+ }
646
+ if (typeof propertySchema === "boolean") {
647
+ properties[name] = propertySchema;
648
+ continue;
649
+ }
650
+ const { $defs, ...rest } = propertySchema;
651
+ const renameMap = {};
652
+ const promotedNames = /* @__PURE__ */ new Set();
653
+ if ($defs) {
654
+ for (const [defName, def] of Object.entries($defs)) {
655
+ if (def === void 0) {
656
+ continue;
657
+ }
658
+ promotedNames.add(defName);
659
+ if (defName in mergedDefs) {
660
+ if (isDeepEqual(mergedDefs[defName], def)) {
661
+ continue;
662
+ }
663
+ let counter = 2;
664
+ let newName = `${defName}${counter}`;
665
+ while (newName in mergedDefs) {
666
+ counter++;
667
+ newName = `${defName}${counter}`;
668
+ }
669
+ mergedDefs[newName] = def;
670
+ renameMap[defName] = newName;
671
+ } else {
672
+ mergedDefs[defName] = def;
673
+ }
674
+ }
278
675
  }
279
- return num;
676
+ const propertyPathPrefix = `#/properties/${encodeJsonPointerSegment(name)}`;
677
+ properties[name] = mapJsonSchemaRefs(rest, (ref) => {
678
+ if (ref.startsWith("#/$defs/")) {
679
+ const afterPrefix = ref.slice("#/$defs/".length);
680
+ const slashIdx = afterPrefix.indexOf("/");
681
+ const encodedSegment = slashIdx === -1 ? afterPrefix : afterPrefix.slice(0, slashIdx);
682
+ const refRest = slashIdx === -1 ? "" : afterPrefix.slice(slashIdx);
683
+ const defName = decodeJsonPointerSegment(encodedSegment);
684
+ if (!promotedNames.has(defName)) {
685
+ return ref;
686
+ }
687
+ if (defName in renameMap) {
688
+ return `#/$defs/${encodeJsonPointerSegment(renameMap[defName])}${refRest}`;
689
+ }
690
+ return ref;
691
+ }
692
+ if (ref === "#") {
693
+ return propertyPathPrefix;
694
+ }
695
+ if (ref.startsWith("#/") && get(rest, ref.slice(2).split("/").map(decodeJsonPointerSegment)) !== void 0) {
696
+ return `${propertyPathPrefix}/${ref.slice(2)}`;
697
+ }
698
+ return ref;
699
+ });
700
+ }
701
+ const schema = {
702
+ type: "object",
703
+ properties
704
+ };
705
+ if (required.length > 0) {
706
+ schema.required = required;
707
+ }
708
+ if (Object.keys(mergedDefs).length > 0) {
709
+ schema.$defs = mergedDefs;
710
+ }
711
+ return schema;
712
+ }
713
+ function extractJsonObjectSchemaEntries(schema) {
714
+ schema = hoistRecursiveRefToDef(schema);
715
+ if (typeof schema !== "object") {
716
+ return void 0;
280
717
  }
281
- #stringToBoolean(value) {
282
- const lower = value.toLowerCase();
283
- if (lower === "false" || lower === "off") {
284
- return false;
718
+ const result = extractJsonObjectSchemaEntriesInternal(omit(schema, ["$defs"]), schema.$defs, /* @__PURE__ */ new Set());
719
+ if (!result.objectLike) {
720
+ return void 0;
721
+ }
722
+ return result.entries.map(([n, s, ...r]) => [n, withRootDefs(s, schema.$defs), ...r]);
723
+ }
724
+ function extractJsonObjectSchemaEntriesInternal(schema, $defs, resolvingRefs) {
725
+ if (typeof schema !== "object") {
726
+ return { entries: [], objectLike: false };
727
+ }
728
+ if (typeof schema.$ref === "string") {
729
+ if (resolvingRefs.has(schema.$ref)) {
730
+ return { entries: [], objectLike: true };
285
731
  }
286
- if (lower === "true" || lower === "on") {
287
- return true;
732
+ const resolved = resolveJsonSchemaRootLocalRef(schema, $defs);
733
+ if (resolved !== schema) {
734
+ return extractJsonObjectSchemaEntriesInternal(resolved, $defs, new Set(resolvingRefs).add(schema.$ref));
288
735
  }
289
- return value;
290
736
  }
291
- #stringToBigInt(value) {
292
- return guard(() => BigInt(value)) ?? value;
737
+ const sources = [];
738
+ if (schema.properties) {
739
+ sources.push({
740
+ entries: Object.entries(schema.properties).map(([name, propertySchema]) => {
741
+ return [
742
+ name,
743
+ propertySchema,
744
+ !schema.required?.includes(name)
745
+ ];
746
+ }),
747
+ source: "direct"
748
+ });
293
749
  }
294
- #numberToBigInt(value) {
295
- return guard(() => BigInt(value)) ?? value;
750
+ let objectLike = schema.type === "object" || schema.properties !== void 0 || schema.required !== void 0 || schema.additionalProperties !== void 0;
751
+ for (const keyword of ["anyOf", "oneOf", "allOf"]) {
752
+ const branches = schema[keyword];
753
+ if (branches === void 0) {
754
+ continue;
755
+ }
756
+ const branchResults = branches.map((branch) => extractJsonObjectSchemaEntriesInternal(branch, $defs, resolvingRefs));
757
+ if (branchResults.some((result) => !result.objectLike)) {
758
+ return { entries: [], objectLike: false };
759
+ }
760
+ const entriesByName = /* @__PURE__ */ new Map();
761
+ for (const result of branchResults) {
762
+ for (const entry of result.entries) {
763
+ const entries = entriesByName.get(entry[0]);
764
+ if (entries) {
765
+ entries.push(entry);
766
+ } else {
767
+ entriesByName.set(entry[0], [entry]);
768
+ }
769
+ }
770
+ }
771
+ objectLike = true;
772
+ sources.push({
773
+ entries: Array.from(entriesByName.entries()).map(([name, entries]) => {
774
+ const schemas = deduplicateJsonSchemas(entries.map((entry) => entry[1]));
775
+ const required = keyword === "allOf" ? entries.some((entry) => !entry[2]) : branchResults.every((result) => {
776
+ const entry = result.entries.find((item) => item[0] === name);
777
+ return entry !== void 0 && !entry[2];
778
+ });
779
+ return [
780
+ name,
781
+ schemas.length === 1 ? schemas[0] : keyword === "allOf" ? { allOf: schemas } : { anyOf: schemas },
782
+ !required
783
+ ];
784
+ }),
785
+ source: keyword
786
+ });
296
787
  }
297
- #stringToDate(value) {
298
- const date = new Date(value);
299
- if (Number.isNaN(date.getTime()) || !FLEXIBLE_DATE_FORMAT_REGEX.test(value)) {
300
- return value;
788
+ const sourceEntries = /* @__PURE__ */ new Map();
789
+ for (const { entries, source } of sources) {
790
+ for (const entry of entries) {
791
+ const existing = sourceEntries.get(entry[0]);
792
+ if (existing) {
793
+ existing[source] = entry;
794
+ } else {
795
+ sourceEntries.set(entry[0], { [source]: entry });
796
+ }
301
797
  }
302
- return date;
303
798
  }
304
- #stringToRegExp(value) {
305
- const match = value.match(/^\/(.*)\/([a-z]*)$/);
306
- if (match) {
307
- const [, pattern, flags] = match;
308
- return guard(() => new RegExp(pattern, flags)) ?? value;
799
+ return {
800
+ entries: Array.from(sourceEntries.entries()).map(([name, entries]) => {
801
+ const schemas = deduplicateJsonSchemas([
802
+ entries.direct?.[1],
803
+ entries.allOf?.[1],
804
+ entries.anyOf?.[1],
805
+ entries.oneOf?.[1]
806
+ ].filter((schema2) => schema2 !== void 0));
807
+ return [
808
+ name,
809
+ schemas.length === 1 ? schemas[0] : { allOf: schemas },
810
+ [entries.direct, entries.allOf, entries.anyOf, entries.oneOf].every((entry) => entry === void 0 || entry[2])
811
+ ];
812
+ }),
813
+ objectLike
814
+ };
815
+ }
816
+ function flattenJsonUnionSchema(schema) {
817
+ return deduplicateJsonSchemas(flattenJsonUnionSchemaInternal(schema, /* @__PURE__ */ new Set()));
818
+ }
819
+ function flattenJsonUnionSchemaInternal(schema, resolvingRefs) {
820
+ if (typeof schema !== "object") {
821
+ return [schema];
822
+ }
823
+ if (typeof schema.$ref === "string") {
824
+ if (resolvingRefs.has(schema.$ref)) {
825
+ return [];
826
+ }
827
+ const resolved = resolveJsonSchemaRootLocalRef(schema);
828
+ if (resolved !== schema) {
829
+ const result = flattenJsonUnionSchemaInternal(resolved, resolvingRefs.add(schema.$ref));
830
+ if (result.length > 1) {
831
+ return result;
832
+ }
309
833
  }
310
- return value;
311
834
  }
312
- #stringToURL(value) {
313
- return guard(() => new URL(value)) ?? value;
835
+ const { anyOf: _anyOf, oneOf: _oneOf, ...rest } = schema;
836
+ const entries = Object.entries(rest).filter(([, val]) => val !== void 0);
837
+ for (const keyword of ["anyOf", "oneOf"]) {
838
+ if (schema[keyword]) {
839
+ return schema[keyword].flatMap((s) => {
840
+ s = ensureJsonSchemaObject(s);
841
+ const mergedSchema = {
842
+ ...s,
843
+ ...Object.fromEntries(entries.filter(([key]) => s[key] === void 0)),
844
+ $defs: schema.$defs
845
+ };
846
+ const conflicts = entries.filter(([key]) => s[key] !== void 0);
847
+ if (conflicts.length) {
848
+ mergedSchema.allOf = [...toArray(mergedSchema.allOf), Object.fromEntries(conflicts)];
849
+ }
850
+ return flattenJsonUnionSchemaInternal(mergedSchema, resolvingRefs);
851
+ });
852
+ }
314
853
  }
315
- #arrayToSet(value) {
316
- const set = new Set(value);
317
- if (set.size !== value.length) {
318
- return value;
854
+ return [schema];
855
+ }
856
+ function matchArrayableJsonSchema(schema) {
857
+ const schemas = flattenJsonUnionSchema(schema);
858
+ if (schemas.length !== 2) {
859
+ return void 0;
860
+ }
861
+ const arraySchema = schemas.find(isJsonArraySchema);
862
+ if (arraySchema === void 0) {
863
+ return void 0;
864
+ }
865
+ const items1 = arraySchema.items ?? true;
866
+ const items2 = schemas.find((s) => s !== arraySchema);
867
+ const logicItem1 = Object.fromEntries(
868
+ Object.entries(ensureJsonSchemaObject(items1)).filter(([key]) => JSON_SCHEMA_LOGIC_KEYWORDS.has(key))
869
+ );
870
+ const logicItem2 = Object.fromEntries(
871
+ Object.entries(ensureJsonSchemaObject(items2)).filter(([key]) => JSON_SCHEMA_LOGIC_KEYWORDS.has(key))
872
+ );
873
+ if (!isDeepEqual(logicItem1, logicItem2)) {
874
+ return void 0;
875
+ }
876
+ return [items2, arraySchema];
877
+ }
878
+ function deduplicateJsonSchemas(schemas) {
879
+ const result = [];
880
+ for (const schema of schemas) {
881
+ if (result.some((i) => isDeepEqual(i, schema))) {
882
+ continue;
319
883
  }
320
- return set;
884
+ result.push(schema);
321
885
  }
322
- #arrayToMap(value) {
323
- if (value.some((item) => !Array.isArray(item) || item.length !== 2)) {
324
- return value;
886
+ return result;
887
+ }
888
+ function withRootDefs(schema, $defs) {
889
+ if (typeof schema === "boolean" || !$defs) {
890
+ return schema;
891
+ }
892
+ return { ...schema, $defs };
893
+ }
894
+
895
+ class DelegatingJsonSchemaConverter {
896
+ constructor(converters = []) {
897
+ this.converters = converters;
898
+ }
899
+ convert(schema, direction) {
900
+ for (const converter of this.converters) {
901
+ if (converter.condition(schema, direction)) {
902
+ return converter.convert(schema, direction);
903
+ }
325
904
  }
326
- const result = new Map(value);
327
- if (result.size !== value.length) {
328
- return value;
905
+ const result = schema?.["~standard"].validate(void 0);
906
+ const optional = result instanceof Promise ? false : !result?.issues?.length;
907
+ if (schema && "jsonSchema" in schema["~standard"] && schema["~standard"].jsonSchema) {
908
+ try {
909
+ return [
910
+ schema["~standard"].jsonSchema[direction](),
911
+ optional
912
+ ];
913
+ } catch {
914
+ }
329
915
  }
330
- return result;
916
+ return [{}, optional];
331
917
  }
332
918
  }
333
919
 
334
- class SmartCoercionPlugin {
920
+ class StandardJsonSchemaConverter {
921
+ condition(schema, _direction) {
922
+ return Boolean(
923
+ schema && "jsonSchema" in schema["~standard"] && isTypescriptObject(schema["~standard"].jsonSchema) && "input" in schema["~standard"].jsonSchema && typeof schema["~standard"].jsonSchema.input === "function" && "output" in schema["~standard"].jsonSchema && typeof schema["~standard"].jsonSchema.output === "function"
924
+ );
925
+ }
926
+ convert(schema, direction) {
927
+ return this.convertInternal(schema, direction);
928
+ }
929
+ convertInternal(schema, direction) {
930
+ try {
931
+ const jsonSchema = direction === "input" ? schema["~standard"].jsonSchema.input({ target: "draft-2020-12" }) : schema["~standard"].jsonSchema.output({ target: "draft-2020-12" });
932
+ let optional = false;
933
+ try {
934
+ const result = schema["~standard"].validate(void 0);
935
+ if (!(result instanceof Promise) && !result.issues) {
936
+ optional = direction === "input" ? true : result.value === void 0;
937
+ }
938
+ } catch {
939
+ }
940
+ return [jsonSchema, optional];
941
+ } catch {
942
+ return [{}, true];
943
+ }
944
+ }
945
+ }
946
+
947
+ class SmartCoercionHandlerPlugin {
948
+ name = "~smart-coercion";
335
949
  converter;
336
950
  coercer;
337
951
  cache = /* @__PURE__ */ new WeakMap();
338
952
  constructor(options = {}) {
339
- this.converter = new CompositeSchemaConverter(toArray(options.schemaConverters));
953
+ this.converter = new DelegatingJsonSchemaConverter([
954
+ ...toArray(options.converters),
955
+ new StandardJsonSchemaConverter()
956
+ ]);
340
957
  this.coercer = new JsonSchemaCoercer();
341
958
  }
342
959
  init(options) {
343
- options.clientInterceptors ??= [];
344
- options.clientInterceptors.unshift(async (options2) => {
345
- const inputSchema = options2.procedure["~orpc"].inputSchema;
346
- if (!inputSchema) {
347
- return options2.next();
960
+ return {
961
+ ...options,
962
+ clientInterceptors: [
963
+ ({ next, input, ...interceptorOptions }) => {
964
+ const inputSchemas = interceptorOptions.procedure["~orpc"].inputSchemas;
965
+ if (!inputSchemas) {
966
+ return next();
967
+ }
968
+ const coercedInput = this.coerceValue(inputSchemas, input);
969
+ return next({ ...interceptorOptions, input: coercedInput });
970
+ },
971
+ ...toArray(options.clientInterceptors)
972
+ ]
973
+ };
974
+ }
975
+ coerceValue(schemas, value) {
976
+ for (const schema of schemas) {
977
+ let converted = this.cache.get(schema);
978
+ if (!converted) {
979
+ converted = this.converter.convert(schema, "input");
980
+ this.cache.set(schema, converted);
348
981
  }
349
- const coercedInput = await this.#coerce(inputSchema, options2.input);
350
- return options2.next({ ...options2, input: coercedInput });
351
- });
982
+ value = this.coercer.coerce(converted, value);
983
+ }
984
+ return value;
985
+ }
986
+ }
987
+
988
+ class SmartCoercionLinkPlugin {
989
+ constructor(contract, options = {}) {
990
+ this.contract = contract;
991
+ this.converter = new DelegatingJsonSchemaConverter([
992
+ ...toArray(options.converters),
993
+ new StandardJsonSchemaConverter()
994
+ ]);
995
+ this.coercer = new JsonSchemaCoercer();
352
996
  }
353
- async #coerce(schema, value) {
354
- let jsonSchema = this.cache.get(schema);
355
- if (!jsonSchema) {
356
- jsonSchema = (await this.converter.convert(schema, { strategy: "input" }))[1];
357
- this.cache.set(schema, jsonSchema);
997
+ name = "~smart-coercion";
998
+ /**
999
+ * Output and error values should be coerced before validation.
1000
+ */
1001
+ after = ["~response-validation"];
1002
+ converter;
1003
+ coercer;
1004
+ cache = /* @__PURE__ */ new WeakMap();
1005
+ init(options) {
1006
+ return {
1007
+ ...options,
1008
+ interceptors: [
1009
+ ...toArray(options.interceptors),
1010
+ async ({ next, path }) => {
1011
+ const procedure = getProcedureContractOrThrow(this.contract, path);
1012
+ try {
1013
+ const output = await next();
1014
+ const outputSchemas = procedure["~orpc"].outputSchemas;
1015
+ if (!outputSchemas) {
1016
+ return output;
1017
+ }
1018
+ const coercedOutput = this.coerceValue(outputSchemas, output);
1019
+ return coercedOutput;
1020
+ } catch (error) {
1021
+ if (!(error instanceof ORPCError) || !error.defined) {
1022
+ throw error;
1023
+ }
1024
+ const errorMap = procedure["~orpc"].errorMap;
1025
+ const dataSchema = errorMap[error.code]?.data;
1026
+ if (!dataSchema) {
1027
+ throw error;
1028
+ }
1029
+ const cloned = cloneORPCError(error);
1030
+ cloned.data = this.coerceValue([dataSchema], cloned.data);
1031
+ throw cloned;
1032
+ }
1033
+ }
1034
+ ]
1035
+ };
1036
+ }
1037
+ coerceValue(schemas, value) {
1038
+ for (const schema of schemas) {
1039
+ let converted = this.cache.get(schema);
1040
+ if (!converted) {
1041
+ converted = this.converter.convert(schema, "output");
1042
+ this.cache.set(schema, converted);
1043
+ }
1044
+ value = this.coercer.coerce(converted, value);
358
1045
  }
359
- return this.coercer.coerce(jsonSchema, value);
1046
+ return value;
360
1047
  }
361
1048
  }
362
1049
 
363
- export { JsonSchemaCoercer, JsonSchemaXNativeType, SmartCoercionPlugin };
1050
+ export { DelegatingJsonSchemaConverter, JsonSchemaCoercer, JsonSchemaXNativeType, SmartCoercionHandlerPlugin, SmartCoercionLinkPlugin, StandardJsonSchemaConverter, combineJsonObjectSchemaEntries, combineJsonSchemasWithComposition, decodeJsonPointerSegment, deduplicateJsonSchemas, encodeJsonPointerSegment, ensureJsonSchemaObject, extractJsonObjectSchemaEntries, flattenJsonUnionSchema, hoistRecursiveRefToDef, isJsonArraySchema, isJsonFileSchema, isJsonObjectSchema, isJsonPrimitiveSchema, isUnconstrainedSchema, mapJsonSchemaRefs, matchArrayableJsonSchema, resolveJsonSchemaRootLocalRef, visitJsonSchemaRefs };