@orpc/json-schema 2.0.0-beta.4 → 2.0.0-beta.41
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/README.md +97 -94
- package/dist/index.d.mts +87 -11
- package/dist/index.d.ts +87 -11
- package/dist/index.mjs +323 -322
- package/package.json +19 -10
package/dist/index.mjs
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
|
-
import { get, isPlainObject,
|
|
2
|
-
export { Format as JsonSchemaFormat, TypeName as JsonSchemaType } from 'json-schema-typed/draft-2020-12';
|
|
1
|
+
import { setOwn, get, isPlainObject, tryOrUndefined, getOwn, toArray, isDeepEqual, omit, isTypescriptObject } from '@orpc/shared';
|
|
3
2
|
import { ORPCError, cloneORPCError } from '@orpc/client';
|
|
4
3
|
import { getProcedureContractOrThrow } from '@orpc/contract';
|
|
5
4
|
|
|
@@ -59,6 +58,28 @@ function encodeJsonPointerSegment(segment) {
|
|
|
59
58
|
function decodeJsonPointerSegment(segment) {
|
|
60
59
|
return segment.replaceAll("~1", "/").replaceAll("~0", "~");
|
|
61
60
|
}
|
|
61
|
+
function visitJsonSchemaRefs(value, visit, schemaLevel = true, seen = /* @__PURE__ */ new Set()) {
|
|
62
|
+
if (!value || typeof value !== "object" || seen.has(value)) {
|
|
63
|
+
return;
|
|
64
|
+
}
|
|
65
|
+
seen.add(value);
|
|
66
|
+
if (Array.isArray(value)) {
|
|
67
|
+
for (const item of value) {
|
|
68
|
+
visitJsonSchemaRefs(item, visit, schemaLevel, seen);
|
|
69
|
+
}
|
|
70
|
+
return;
|
|
71
|
+
}
|
|
72
|
+
for (const key of Object.keys(value)) {
|
|
73
|
+
const val = value[key];
|
|
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
|
+
}
|
|
62
83
|
function mapJsonSchemaRefs(value, map, schemaLevel = true, path = []) {
|
|
63
84
|
if (!value || typeof value !== "object") {
|
|
64
85
|
return value;
|
|
@@ -67,15 +88,16 @@ function mapJsonSchemaRefs(value, map, schemaLevel = true, path = []) {
|
|
|
67
88
|
return value.map((item, index) => mapJsonSchemaRefs(item, map, schemaLevel, [...path, index]));
|
|
68
89
|
}
|
|
69
90
|
const result = {};
|
|
70
|
-
for (const
|
|
91
|
+
for (const key of Object.keys(value)) {
|
|
92
|
+
const val = value[key];
|
|
71
93
|
if (key === "$ref" && typeof val === "string") {
|
|
72
|
-
result
|
|
94
|
+
setOwn(result, key, map(val, [...path, key]));
|
|
73
95
|
} else if (!schemaLevel) {
|
|
74
|
-
result
|
|
96
|
+
setOwn(result, key, mapJsonSchemaRefs(val, map, true, [...path, key]));
|
|
75
97
|
} else if (JSON_SCHEMA_LOGIC_KEYWORDS.has(key) || JSON_SCHEMA_RECORD_KEYWORDS.has(key)) {
|
|
76
|
-
result
|
|
98
|
+
setOwn(result, key, mapJsonSchemaRefs(val, map, !JSON_SCHEMA_RECORD_KEYWORDS.has(key), [...path, key]));
|
|
77
99
|
} else {
|
|
78
|
-
result
|
|
100
|
+
setOwn(result, key, val);
|
|
79
101
|
}
|
|
80
102
|
}
|
|
81
103
|
return result;
|
|
@@ -84,20 +106,19 @@ function hoistRecursiveRefToDef(schema) {
|
|
|
84
106
|
if (typeof schema !== "object") {
|
|
85
107
|
return schema;
|
|
86
108
|
}
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
return `#/$defs/${encodeJsonPointerSegment(defName)}${ref.slice(1)}`;
|
|
92
|
-
}
|
|
93
|
-
return ref;
|
|
109
|
+
const isRootRef = (ref) => ref === "#" || ref.startsWith("#/") && !ref.startsWith("#/$defs/") && get(schema, ref.slice(2).split("/").map(decodeJsonPointerSegment)) !== void 0;
|
|
110
|
+
let hasRootRef = false;
|
|
111
|
+
visitJsonSchemaRefs(schema, (ref) => {
|
|
112
|
+
hasRootRef ||= isRootRef(ref);
|
|
94
113
|
});
|
|
95
|
-
if (
|
|
114
|
+
if (!hasRootRef) {
|
|
96
115
|
return schema;
|
|
97
116
|
}
|
|
98
|
-
const
|
|
117
|
+
const defName = findRecursiveJsonSchemaDefName(schema.$defs);
|
|
118
|
+
const defRef = `#/$defs/${encodeJsonPointerSegment(defName)}`;
|
|
119
|
+
const { $defs, ...rest } = mapJsonSchemaRefs(schema, (ref) => isRootRef(ref) ? `${defRef}${ref.slice(1)}` : ref);
|
|
99
120
|
return {
|
|
100
|
-
$ref:
|
|
121
|
+
$ref: defRef,
|
|
101
122
|
$defs: {
|
|
102
123
|
...$defs,
|
|
103
124
|
[defName]: rest
|
|
@@ -114,21 +135,24 @@ function resolveJsonSchemaRootLocalRef(schema, $defs) {
|
|
|
114
135
|
if (!$defs) {
|
|
115
136
|
return schema;
|
|
116
137
|
}
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
138
|
+
const followedRefs = /* @__PURE__ */ new Set();
|
|
139
|
+
let current = schema;
|
|
140
|
+
while (typeof current.$ref === "string" && current.$ref.startsWith("#/$defs/") && !followedRefs.has(current.$ref)) {
|
|
141
|
+
followedRefs.add(current.$ref);
|
|
142
|
+
const resolved = get($defs, current.$ref.slice("#/$defs/".length).split("/").map(decodeJsonPointerSegment));
|
|
143
|
+
if (resolved === void 0) {
|
|
144
|
+
return current;
|
|
145
|
+
}
|
|
146
|
+
if (typeof resolved !== "object") {
|
|
147
|
+
return resolved;
|
|
148
|
+
}
|
|
149
|
+
const { $ref: _ref, ...rest } = current;
|
|
150
|
+
current = {
|
|
151
|
+
...rest,
|
|
152
|
+
...resolved
|
|
153
|
+
};
|
|
126
154
|
}
|
|
127
|
-
|
|
128
|
-
return resolveJsonSchemaRootLocalRef({
|
|
129
|
-
...rest,
|
|
130
|
-
...resolved
|
|
131
|
-
});
|
|
155
|
+
return current;
|
|
132
156
|
}
|
|
133
157
|
function findRecursiveJsonSchemaDefName(defs) {
|
|
134
158
|
let index = 0;
|
|
@@ -138,9 +162,40 @@ function findRecursiveJsonSchemaDefName(defs) {
|
|
|
138
162
|
return `__schema${index}`;
|
|
139
163
|
}
|
|
140
164
|
|
|
165
|
+
var JsonSchemaType = /* @__PURE__ */ ((JsonSchemaType2) => {
|
|
166
|
+
JsonSchemaType2["Array"] = "array";
|
|
167
|
+
JsonSchemaType2["Boolean"] = "boolean";
|
|
168
|
+
JsonSchemaType2["Integer"] = "integer";
|
|
169
|
+
JsonSchemaType2["Null"] = "null";
|
|
170
|
+
JsonSchemaType2["Number"] = "number";
|
|
171
|
+
JsonSchemaType2["Object"] = "object";
|
|
172
|
+
JsonSchemaType2["String"] = "string";
|
|
173
|
+
return JsonSchemaType2;
|
|
174
|
+
})(JsonSchemaType || {});
|
|
175
|
+
var JsonSchemaFormat = /* @__PURE__ */ ((JsonSchemaFormat2) => {
|
|
176
|
+
JsonSchemaFormat2["Date"] = "date";
|
|
177
|
+
JsonSchemaFormat2["DateTime"] = "date-time";
|
|
178
|
+
JsonSchemaFormat2["Duration"] = "duration";
|
|
179
|
+
JsonSchemaFormat2["Email"] = "email";
|
|
180
|
+
JsonSchemaFormat2["Hostname"] = "hostname";
|
|
181
|
+
JsonSchemaFormat2["IDNEmail"] = "idn-email";
|
|
182
|
+
JsonSchemaFormat2["IDNHostname"] = "idn-hostname";
|
|
183
|
+
JsonSchemaFormat2["IPv4"] = "ipv4";
|
|
184
|
+
JsonSchemaFormat2["IPv6"] = "ipv6";
|
|
185
|
+
JsonSchemaFormat2["IRI"] = "iri";
|
|
186
|
+
JsonSchemaFormat2["IRIReference"] = "iri-reference";
|
|
187
|
+
JsonSchemaFormat2["JSONPointer"] = "json-pointer";
|
|
188
|
+
JsonSchemaFormat2["RegEx"] = "regex";
|
|
189
|
+
JsonSchemaFormat2["RelativeJSONPointer"] = "relative-json-pointer";
|
|
190
|
+
JsonSchemaFormat2["Time"] = "time";
|
|
191
|
+
JsonSchemaFormat2["URI"] = "uri";
|
|
192
|
+
JsonSchemaFormat2["URIReference"] = "uri-reference";
|
|
193
|
+
JsonSchemaFormat2["URITemplate"] = "uri-template";
|
|
194
|
+
JsonSchemaFormat2["UUID"] = "uuid";
|
|
195
|
+
return JsonSchemaFormat2;
|
|
196
|
+
})(JsonSchemaFormat || {});
|
|
141
197
|
var JsonSchemaXNativeType = /* @__PURE__ */ ((JsonSchemaXNativeType2) => {
|
|
142
198
|
JsonSchemaXNativeType2["BigInt"] = "bigint";
|
|
143
|
-
JsonSchemaXNativeType2["RegExp"] = "regexp";
|
|
144
199
|
JsonSchemaXNativeType2["Date"] = "date";
|
|
145
200
|
JsonSchemaXNativeType2["Url"] = "url";
|
|
146
201
|
JsonSchemaXNativeType2["Set"] = "set";
|
|
@@ -148,7 +203,41 @@ var JsonSchemaXNativeType = /* @__PURE__ */ ((JsonSchemaXNativeType2) => {
|
|
|
148
203
|
return JsonSchemaXNativeType2;
|
|
149
204
|
})(JsonSchemaXNativeType || {});
|
|
150
205
|
|
|
151
|
-
const
|
|
206
|
+
const UNSATISFIED = 0;
|
|
207
|
+
const LOOSELY_SATISFIED = 1;
|
|
208
|
+
const SATISFIED = 2;
|
|
209
|
+
const NATIVE_TYPES = /* @__PURE__ */ new Map([
|
|
210
|
+
[JsonSchemaXNativeType.Date, {
|
|
211
|
+
types: ["string"],
|
|
212
|
+
is: (value) => value instanceof Date,
|
|
213
|
+
coerce: (value) => typeof value === "string" ? stringToDate(value) : value
|
|
214
|
+
}],
|
|
215
|
+
[JsonSchemaXNativeType.BigInt, {
|
|
216
|
+
types: ["string", "integer", "number"],
|
|
217
|
+
is: (value) => typeof value === "bigint",
|
|
218
|
+
coerce: (value) => typeof value === "string" ? stringToBigInt(value) : typeof value === "number" ? numberToBigInt(value) : value
|
|
219
|
+
}],
|
|
220
|
+
[JsonSchemaXNativeType.Url, {
|
|
221
|
+
types: ["string"],
|
|
222
|
+
is: (value) => value instanceof URL,
|
|
223
|
+
coerce: (value) => typeof value === "string" ? stringToURL(value) : value
|
|
224
|
+
}],
|
|
225
|
+
[JsonSchemaXNativeType.Set, {
|
|
226
|
+
types: ["array"],
|
|
227
|
+
is: (value) => value instanceof Set,
|
|
228
|
+
coerce: (value) => Array.isArray(value) ? arrayToSet(value) : value,
|
|
229
|
+
afterTypeCheck: true
|
|
230
|
+
}],
|
|
231
|
+
[JsonSchemaXNativeType.Map, {
|
|
232
|
+
types: ["array"],
|
|
233
|
+
is: (value) => value instanceof Map,
|
|
234
|
+
coerce: (value) => Array.isArray(value) ? arrayToMap(value) : value,
|
|
235
|
+
afterTypeCheck: true
|
|
236
|
+
}]
|
|
237
|
+
]);
|
|
238
|
+
function minSatisfaction(a, b) {
|
|
239
|
+
return a < b ? a : b;
|
|
240
|
+
}
|
|
152
241
|
class JsonSchemaCoercer {
|
|
153
242
|
coerce([schema, optional], value) {
|
|
154
243
|
if (optional && value === void 0) {
|
|
@@ -157,25 +246,29 @@ class JsonSchemaCoercer {
|
|
|
157
246
|
const [, coerced] = this.coerceInternal(schema, schema, value);
|
|
158
247
|
return coerced;
|
|
159
248
|
}
|
|
160
|
-
coerceInternal(rootSchema, schema, value) {
|
|
249
|
+
coerceInternal(rootSchema, schema, value, appliedRefs) {
|
|
161
250
|
if (typeof schema === "boolean") {
|
|
162
|
-
return [schema, value];
|
|
251
|
+
return [schema ? SATISFIED : UNSATISFIED, value];
|
|
163
252
|
}
|
|
164
253
|
if (Array.isArray(schema.type)) {
|
|
165
254
|
return this.coerceInternal(
|
|
166
255
|
rootSchema,
|
|
167
256
|
{ anyOf: schema.type.map((type) => ({ ...schema, type })) },
|
|
168
|
-
value
|
|
257
|
+
value,
|
|
258
|
+
appliedRefs
|
|
169
259
|
);
|
|
170
260
|
}
|
|
171
261
|
let coerced = value;
|
|
172
|
-
let satisfied =
|
|
262
|
+
let satisfied = SATISFIED;
|
|
173
263
|
if (typeof schema.$ref === "string") {
|
|
174
264
|
const resolved = schema.$ref.startsWith("#/") ? get(rootSchema, schema.$ref.slice("#/".length).split("/").map(decodeJsonPointerSegment)) : schema.$ref === "#" ? rootSchema : void 0;
|
|
175
|
-
if (resolved !== void 0) {
|
|
176
|
-
|
|
265
|
+
if (resolved !== void 0 && !appliedRefs?.has(resolved)) {
|
|
266
|
+
appliedRefs ??= /* @__PURE__ */ new Set();
|
|
267
|
+
appliedRefs.add(resolved);
|
|
268
|
+
const [subSatisfied, subCoerced] = this.coerceInternal(rootSchema, resolved, coerced, appliedRefs);
|
|
269
|
+
appliedRefs.delete(resolved);
|
|
177
270
|
coerced = subCoerced;
|
|
178
|
-
satisfied = subSatisfied;
|
|
271
|
+
satisfied = minSatisfaction(satisfied, subSatisfied);
|
|
179
272
|
}
|
|
180
273
|
}
|
|
181
274
|
const enumValues = schema.const !== void 0 ? [schema.const] : schema.enum;
|
|
@@ -189,24 +282,29 @@ class JsonSchemaCoercer {
|
|
|
189
282
|
if (enumValues.includes(booleanValue)) {
|
|
190
283
|
coerced = booleanValue;
|
|
191
284
|
} else {
|
|
192
|
-
satisfied =
|
|
285
|
+
satisfied = UNSATISFIED;
|
|
193
286
|
}
|
|
194
287
|
}
|
|
195
288
|
} else {
|
|
196
|
-
satisfied =
|
|
289
|
+
satisfied = UNSATISFIED;
|
|
197
290
|
}
|
|
198
291
|
}
|
|
199
|
-
|
|
292
|
+
const declaredNativeType = NATIVE_TYPES.get(schema["x-native-type"]);
|
|
293
|
+
const nativeType = schema.type === void 0 || declaredNativeType?.types.includes(schema.type) ? declaredNativeType : void 0;
|
|
294
|
+
if (nativeType && !nativeType.afterTypeCheck) {
|
|
295
|
+
coerced = nativeType.coerce(coerced);
|
|
296
|
+
}
|
|
297
|
+
if (schema.type && !nativeType?.is(coerced)) {
|
|
200
298
|
switch (schema.type) {
|
|
201
299
|
case "null": {
|
|
202
300
|
if (coerced !== null) {
|
|
203
|
-
satisfied =
|
|
301
|
+
satisfied = UNSATISFIED;
|
|
204
302
|
}
|
|
205
303
|
break;
|
|
206
304
|
}
|
|
207
305
|
case "string": {
|
|
208
306
|
if (typeof coerced !== "string") {
|
|
209
|
-
satisfied =
|
|
307
|
+
satisfied = UNSATISFIED;
|
|
210
308
|
}
|
|
211
309
|
break;
|
|
212
310
|
}
|
|
@@ -215,7 +313,7 @@ class JsonSchemaCoercer {
|
|
|
215
313
|
coerced = stringToNumber(coerced);
|
|
216
314
|
}
|
|
217
315
|
if (typeof coerced !== "number") {
|
|
218
|
-
satisfied =
|
|
316
|
+
satisfied = UNSATISFIED;
|
|
219
317
|
}
|
|
220
318
|
break;
|
|
221
319
|
}
|
|
@@ -224,7 +322,7 @@ class JsonSchemaCoercer {
|
|
|
224
322
|
coerced = stringToInteger(coerced);
|
|
225
323
|
}
|
|
226
324
|
if (typeof coerced !== "number" || !Number.isInteger(coerced)) {
|
|
227
|
-
satisfied =
|
|
325
|
+
satisfied = UNSATISFIED;
|
|
228
326
|
}
|
|
229
327
|
break;
|
|
230
328
|
}
|
|
@@ -233,7 +331,7 @@ class JsonSchemaCoercer {
|
|
|
233
331
|
coerced = stringToBoolean(coerced);
|
|
234
332
|
}
|
|
235
333
|
if (typeof coerced !== "boolean") {
|
|
236
|
-
satisfied =
|
|
334
|
+
satisfied = UNSATISFIED;
|
|
237
335
|
}
|
|
238
336
|
break;
|
|
239
337
|
}
|
|
@@ -245,26 +343,24 @@ class JsonSchemaCoercer {
|
|
|
245
343
|
const coercedItems = coerced.map((item, i) => {
|
|
246
344
|
const subSchema = prefixItemSchemas[i] ?? itemSchema;
|
|
247
345
|
if (subSchema === void 0) {
|
|
248
|
-
satisfied =
|
|
346
|
+
satisfied = minSatisfaction(satisfied, LOOSELY_SATISFIED);
|
|
249
347
|
return item;
|
|
250
348
|
}
|
|
251
349
|
const [subSatisfied, subCoerced] = this.coerceInternal(rootSchema, subSchema, item);
|
|
252
|
-
|
|
253
|
-
satisfied = false;
|
|
254
|
-
}
|
|
350
|
+
satisfied = minSatisfaction(satisfied, subSatisfied);
|
|
255
351
|
if (subCoerced !== item) {
|
|
256
352
|
shouldUseCoercedItems = true;
|
|
257
353
|
}
|
|
258
354
|
return subCoerced;
|
|
259
355
|
});
|
|
260
|
-
if (coercedItems.length <
|
|
261
|
-
satisfied =
|
|
356
|
+
if (typeof schema.minItems === "number" && coercedItems.length < schema.minItems) {
|
|
357
|
+
satisfied = UNSATISFIED;
|
|
262
358
|
}
|
|
263
359
|
if (shouldUseCoercedItems) {
|
|
264
360
|
coerced = coercedItems;
|
|
265
361
|
}
|
|
266
362
|
} else {
|
|
267
|
-
satisfied =
|
|
363
|
+
satisfied = UNSATISFIED;
|
|
268
364
|
}
|
|
269
365
|
break;
|
|
270
366
|
}
|
|
@@ -274,153 +370,123 @@ class JsonSchemaCoercer {
|
|
|
274
370
|
}
|
|
275
371
|
if (isPlainObject(coerced)) {
|
|
276
372
|
let shouldUseCoercedItems = false;
|
|
277
|
-
const coercedItems = {};
|
|
278
|
-
const patternProperties = Object.entries(schema.patternProperties ?? {}).
|
|
279
|
-
|
|
373
|
+
const coercedItems = { ...coerced };
|
|
374
|
+
const patternProperties = Object.entries(schema.patternProperties ?? {}).flatMap(([key, value2]) => {
|
|
375
|
+
const pattern = tryOrUndefined(() => new RegExp(key));
|
|
376
|
+
return pattern ? [[pattern, value2]] : [];
|
|
377
|
+
});
|
|
378
|
+
const propertySchemas = schema.properties ?? {};
|
|
379
|
+
for (const key of Object.keys(coerced)) {
|
|
280
380
|
const value2 = coerced[key];
|
|
281
|
-
const subSchema =
|
|
282
|
-
if (value2
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
}
|
|
293
|
-
if (subCoerced !== value2) {
|
|
294
|
-
shouldUseCoercedItems = true;
|
|
381
|
+
const subSchema = getOwn(propertySchemas, key) ?? patternProperties.find(([pattern]) => pattern.test(key))?.[1] ?? schema.additionalProperties;
|
|
382
|
+
if (value2 !== void 0 || schema.required?.includes(key)) {
|
|
383
|
+
if (subSchema === void 0) {
|
|
384
|
+
satisfied = minSatisfaction(satisfied, LOOSELY_SATISFIED);
|
|
385
|
+
} else {
|
|
386
|
+
const [subSatisfied, subCoerced] = this.coerceInternal(rootSchema, subSchema, value2);
|
|
387
|
+
coercedItems[key] = subCoerced;
|
|
388
|
+
satisfied = minSatisfaction(satisfied, subSatisfied);
|
|
389
|
+
if (subCoerced !== value2) {
|
|
390
|
+
shouldUseCoercedItems = true;
|
|
391
|
+
}
|
|
295
392
|
}
|
|
296
393
|
}
|
|
297
394
|
}
|
|
298
395
|
if (schema.required?.some((key) => !Object.hasOwn(coercedItems, key))) {
|
|
299
|
-
satisfied =
|
|
396
|
+
satisfied = UNSATISFIED;
|
|
300
397
|
}
|
|
301
398
|
if (shouldUseCoercedItems) {
|
|
302
399
|
coerced = coercedItems;
|
|
303
400
|
}
|
|
304
401
|
} else {
|
|
305
|
-
satisfied =
|
|
402
|
+
satisfied = UNSATISFIED;
|
|
306
403
|
}
|
|
307
404
|
break;
|
|
308
405
|
}
|
|
309
406
|
}
|
|
310
407
|
}
|
|
311
|
-
if (
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
if (!(coerced instanceof Date)) {
|
|
318
|
-
satisfied = false;
|
|
319
|
-
}
|
|
320
|
-
break;
|
|
321
|
-
}
|
|
322
|
-
case JsonSchemaXNativeType.BigInt: {
|
|
323
|
-
switch (typeof coerced) {
|
|
324
|
-
case "string":
|
|
325
|
-
coerced = stringToBigInt(coerced);
|
|
326
|
-
break;
|
|
327
|
-
case "number":
|
|
328
|
-
coerced = numberToBigInt(coerced);
|
|
329
|
-
break;
|
|
330
|
-
}
|
|
331
|
-
if (typeof coerced !== "bigint") {
|
|
332
|
-
satisfied = false;
|
|
333
|
-
}
|
|
334
|
-
break;
|
|
335
|
-
}
|
|
336
|
-
case JsonSchemaXNativeType.RegExp: {
|
|
337
|
-
if (typeof coerced === "string") {
|
|
338
|
-
coerced = stringToRegExp(coerced);
|
|
339
|
-
}
|
|
340
|
-
if (!(coerced instanceof RegExp)) {
|
|
341
|
-
satisfied = false;
|
|
342
|
-
}
|
|
343
|
-
break;
|
|
344
|
-
}
|
|
345
|
-
case JsonSchemaXNativeType.Url: {
|
|
346
|
-
if (typeof coerced === "string") {
|
|
347
|
-
coerced = stringToURL(coerced);
|
|
348
|
-
}
|
|
349
|
-
if (!(coerced instanceof URL)) {
|
|
350
|
-
satisfied = false;
|
|
351
|
-
}
|
|
352
|
-
break;
|
|
353
|
-
}
|
|
354
|
-
case JsonSchemaXNativeType.Set: {
|
|
355
|
-
if (Array.isArray(coerced)) {
|
|
356
|
-
coerced = arrayToSet(coerced);
|
|
357
|
-
}
|
|
358
|
-
if (!(coerced instanceof Set)) {
|
|
359
|
-
satisfied = false;
|
|
360
|
-
}
|
|
361
|
-
break;
|
|
362
|
-
}
|
|
363
|
-
case JsonSchemaXNativeType.Map: {
|
|
364
|
-
if (Array.isArray(coerced)) {
|
|
365
|
-
coerced = arrayToMap(coerced);
|
|
366
|
-
}
|
|
367
|
-
if (!(coerced instanceof Map)) {
|
|
368
|
-
satisfied = false;
|
|
369
|
-
}
|
|
370
|
-
break;
|
|
371
|
-
}
|
|
408
|
+
if (nativeType) {
|
|
409
|
+
if (nativeType.afterTypeCheck) {
|
|
410
|
+
coerced = nativeType.coerce(coerced);
|
|
411
|
+
}
|
|
412
|
+
if (!nativeType.is(coerced)) {
|
|
413
|
+
satisfied = UNSATISFIED;
|
|
372
414
|
}
|
|
373
415
|
}
|
|
374
416
|
if (schema.allOf) {
|
|
375
417
|
for (const subSchema of schema.allOf) {
|
|
376
|
-
const [subSatisfied, subCoerced] = this.coerceInternal(rootSchema, subSchema, coerced);
|
|
418
|
+
const [subSatisfied, subCoerced] = this.coerceInternal(rootSchema, subSchema, coerced, appliedRefs);
|
|
377
419
|
coerced = subCoerced;
|
|
378
|
-
|
|
379
|
-
satisfied = false;
|
|
380
|
-
}
|
|
420
|
+
satisfied = minSatisfaction(satisfied, subSatisfied);
|
|
381
421
|
}
|
|
382
422
|
}
|
|
383
423
|
for (const key of ["anyOf", "oneOf"]) {
|
|
384
424
|
if (schema[key]) {
|
|
385
|
-
let
|
|
425
|
+
let best;
|
|
386
426
|
for (const subSchema of schema[key]) {
|
|
387
|
-
const [subSatisfied, subCoerced] = this.coerceInternal(rootSchema, subSchema, coerced);
|
|
388
|
-
if (subSatisfied) {
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
}
|
|
427
|
+
const [subSatisfied, subCoerced] = this.coerceInternal(rootSchema, subSchema, coerced, appliedRefs);
|
|
428
|
+
if (subSatisfied === UNSATISFIED) {
|
|
429
|
+
continue;
|
|
430
|
+
}
|
|
431
|
+
if (subCoerced === coerced) {
|
|
432
|
+
best = { satisfied: subSatisfied, value: subCoerced };
|
|
433
|
+
break;
|
|
395
434
|
}
|
|
435
|
+
if (!best || subSatisfied > best.satisfied) {
|
|
436
|
+
best = { satisfied: subSatisfied, value: subCoerced };
|
|
437
|
+
}
|
|
438
|
+
}
|
|
439
|
+
if (best) {
|
|
440
|
+
coerced = best.value;
|
|
441
|
+
satisfied = minSatisfaction(satisfied, best.satisfied);
|
|
442
|
+
} else {
|
|
443
|
+
satisfied = UNSATISFIED;
|
|
396
444
|
}
|
|
397
|
-
coerced = bestOptions ? bestOptions.coerced : coerced;
|
|
398
|
-
satisfied = bestOptions ? bestOptions.satisfied : false;
|
|
399
445
|
}
|
|
400
446
|
}
|
|
401
447
|
if (typeof schema.not !== "undefined") {
|
|
402
|
-
const [notSatisfied] = this.coerceInternal(rootSchema, schema.not, coerced);
|
|
403
|
-
if (notSatisfied) {
|
|
404
|
-
satisfied =
|
|
448
|
+
const [notSatisfied] = this.coerceInternal(rootSchema, schema.not, coerced, appliedRefs);
|
|
449
|
+
if (notSatisfied !== UNSATISFIED) {
|
|
450
|
+
satisfied = UNSATISFIED;
|
|
405
451
|
}
|
|
406
452
|
}
|
|
407
453
|
return [satisfied, coerced];
|
|
408
454
|
}
|
|
409
455
|
}
|
|
456
|
+
const NUMBER_PATTERN = /^-?(?:0|[1-9]\d*)(?:\.\d+)?$/;
|
|
410
457
|
function stringToNumber(value) {
|
|
411
|
-
|
|
412
|
-
|
|
458
|
+
if (!NUMBER_PATTERN.test(value)) {
|
|
459
|
+
return value;
|
|
460
|
+
}
|
|
461
|
+
const num = Number(value);
|
|
462
|
+
if (num < Number.MIN_SAFE_INTEGER || num > Number.MAX_SAFE_INTEGER) {
|
|
413
463
|
return value;
|
|
414
464
|
}
|
|
415
465
|
return num;
|
|
416
466
|
}
|
|
467
|
+
const INTEGER_PATTERN = /^-?(?:0|[1-9]\d*)$/;
|
|
417
468
|
function stringToInteger(value) {
|
|
418
|
-
|
|
419
|
-
|
|
469
|
+
if (!INTEGER_PATTERN.test(value)) {
|
|
470
|
+
return value;
|
|
471
|
+
}
|
|
472
|
+
const num = Number(value);
|
|
473
|
+
if (!Number.isSafeInteger(num)) {
|
|
420
474
|
return value;
|
|
421
475
|
}
|
|
422
476
|
return num;
|
|
423
477
|
}
|
|
478
|
+
function stringToBigInt(value) {
|
|
479
|
+
if (!INTEGER_PATTERN.test(value)) {
|
|
480
|
+
return value;
|
|
481
|
+
}
|
|
482
|
+
return BigInt(value);
|
|
483
|
+
}
|
|
484
|
+
function numberToBigInt(value) {
|
|
485
|
+
if (!Number.isInteger(value)) {
|
|
486
|
+
return value;
|
|
487
|
+
}
|
|
488
|
+
return BigInt(value);
|
|
489
|
+
}
|
|
424
490
|
function stringToBoolean(value) {
|
|
425
491
|
const lower = value.toLowerCase();
|
|
426
492
|
if (lower === "false" || lower === "off") {
|
|
@@ -431,26 +497,29 @@ function stringToBoolean(value) {
|
|
|
431
497
|
}
|
|
432
498
|
return value;
|
|
433
499
|
}
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
}
|
|
437
|
-
function numberToBigInt(value) {
|
|
438
|
-
return tryOrUndefined(() => BigInt(value)) ?? value;
|
|
439
|
-
}
|
|
500
|
+
const DATE_TIME_PATTERN = /^(?!-0{6})(?:[+-]\d{2})?\d{4}-\d{2}-\d{2}(?:[T ].*)?$/;
|
|
501
|
+
const DAYS_IN_MONTH = [31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31];
|
|
440
502
|
function stringToDate(value) {
|
|
503
|
+
if (!DATE_TIME_PATTERN.test(value)) {
|
|
504
|
+
return value;
|
|
505
|
+
}
|
|
506
|
+
const yearEnd = value.indexOf("-", 1);
|
|
507
|
+
const month = readTwoDigits(value, yearEnd + 1);
|
|
508
|
+
const day = readTwoDigits(value, yearEnd + 4);
|
|
509
|
+
if (day < 1 || day > (DAYS_IN_MONTH[month - 1] ?? 0) || month === 2 && day === 29 && !isLeapYear(Number(value.slice(0, yearEnd)))) {
|
|
510
|
+
return value;
|
|
511
|
+
}
|
|
441
512
|
const date = new Date(value);
|
|
442
|
-
if (Number.isNaN(date.getTime())
|
|
513
|
+
if (Number.isNaN(date.getTime())) {
|
|
443
514
|
return value;
|
|
444
515
|
}
|
|
445
516
|
return date;
|
|
446
517
|
}
|
|
447
|
-
function
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
}
|
|
453
|
-
return value;
|
|
518
|
+
function readTwoDigits(value, index) {
|
|
519
|
+
return (value.charCodeAt(index) - 48) * 10 + value.charCodeAt(index + 1) - 48;
|
|
520
|
+
}
|
|
521
|
+
function isLeapYear(year) {
|
|
522
|
+
return year % 4 === 0 && (year % 100 !== 0 || year % 400 === 0);
|
|
454
523
|
}
|
|
455
524
|
function stringToURL(value) {
|
|
456
525
|
return tryOrUndefined(() => new URL(value)) ?? value;
|
|
@@ -513,148 +582,85 @@ function ensureJsonSchemaObject(schema) {
|
|
|
513
582
|
return schema;
|
|
514
583
|
}
|
|
515
584
|
|
|
585
|
+
function promoteJsonSchemaDefs(schema, mergedDefs, basePath) {
|
|
586
|
+
const { $defs, ...rootBody } = schema;
|
|
587
|
+
const renameMap = /* @__PURE__ */ new Map();
|
|
588
|
+
const mapRef = (ref) => {
|
|
589
|
+
if (ref === "#") {
|
|
590
|
+
return basePath;
|
|
591
|
+
}
|
|
592
|
+
if (ref.startsWith("#/$defs/")) {
|
|
593
|
+
const [encodedName, ...segments] = ref.slice("#/$defs/".length).split("/");
|
|
594
|
+
const newName = renameMap.get(decodeJsonPointerSegment(encodedName));
|
|
595
|
+
return newName === void 0 ? ref : ["#/$defs", encodeJsonPointerSegment(newName), ...segments].join("/");
|
|
596
|
+
}
|
|
597
|
+
if (ref.startsWith("#/") && get(rootBody, ref.slice(2).split("/").map(decodeJsonPointerSegment)) !== void 0) {
|
|
598
|
+
return `${basePath}/${ref.slice(2)}`;
|
|
599
|
+
}
|
|
600
|
+
return ref;
|
|
601
|
+
};
|
|
602
|
+
const defs = Object.entries($defs ?? {}).filter(([, def]) => def !== void 0);
|
|
603
|
+
if (defs.length > 0) {
|
|
604
|
+
const promoted = /* @__PURE__ */ new Map();
|
|
605
|
+
const reserved = /* @__PURE__ */ new Set([...mergedDefs.keys(), ...defs.map(([name]) => name)]);
|
|
606
|
+
for (let changed = true; changed; ) {
|
|
607
|
+
changed = false;
|
|
608
|
+
for (const [name, def] of defs) {
|
|
609
|
+
const body = mapJsonSchemaRefs(def, mapRef);
|
|
610
|
+
promoted.set(name, body);
|
|
611
|
+
if (renameMap.has(name) || !mergedDefs.has(name) || isDeepEqual(mergedDefs.get(name), body)) {
|
|
612
|
+
continue;
|
|
613
|
+
}
|
|
614
|
+
let counter = 2;
|
|
615
|
+
while (reserved.has(`${name}${counter}`)) {
|
|
616
|
+
counter++;
|
|
617
|
+
}
|
|
618
|
+
reserved.add(`${name}${counter}`);
|
|
619
|
+
renameMap.set(name, `${name}${counter}`);
|
|
620
|
+
changed = true;
|
|
621
|
+
}
|
|
622
|
+
}
|
|
623
|
+
for (const [name, body] of promoted) {
|
|
624
|
+
mergedDefs.set(renameMap.get(name) ?? name, body);
|
|
625
|
+
}
|
|
626
|
+
}
|
|
627
|
+
return mapJsonSchemaRefs(rootBody, mapRef);
|
|
628
|
+
}
|
|
516
629
|
function combineJsonSchemasWithComposition(keyword, schemas) {
|
|
517
630
|
if (schemas.length <= 1) {
|
|
518
631
|
return schemas[0] ?? true;
|
|
519
632
|
}
|
|
520
|
-
const mergedDefs =
|
|
633
|
+
const mergedDefs = /* @__PURE__ */ new Map();
|
|
521
634
|
const compositionBranches = [];
|
|
522
635
|
for (let i = 0; i < schemas.length; i++) {
|
|
523
636
|
const schema = schemas[i];
|
|
524
|
-
|
|
525
|
-
compositionBranches.push(schema);
|
|
526
|
-
continue;
|
|
527
|
-
}
|
|
528
|
-
const { $defs, ...rest } = schema;
|
|
529
|
-
const renameMap = {};
|
|
530
|
-
const promotedNames = /* @__PURE__ */ new Set();
|
|
531
|
-
if ($defs) {
|
|
532
|
-
for (const [name, def] of Object.entries($defs)) {
|
|
533
|
-
if (def === void 0)
|
|
534
|
-
continue;
|
|
535
|
-
promotedNames.add(name);
|
|
536
|
-
if (name in mergedDefs) {
|
|
537
|
-
if (isDeepEqual(mergedDefs[name], def)) {
|
|
538
|
-
continue;
|
|
539
|
-
}
|
|
540
|
-
let counter = 2;
|
|
541
|
-
let newName = `${name}${counter}`;
|
|
542
|
-
while (newName in mergedDefs) {
|
|
543
|
-
counter++;
|
|
544
|
-
newName = `${name}${counter}`;
|
|
545
|
-
}
|
|
546
|
-
mergedDefs[newName] = def;
|
|
547
|
-
renameMap[name] = newName;
|
|
548
|
-
} else {
|
|
549
|
-
mergedDefs[name] = def;
|
|
550
|
-
}
|
|
551
|
-
}
|
|
552
|
-
}
|
|
553
|
-
compositionBranches.push(mapJsonSchemaRefs(
|
|
554
|
-
rest,
|
|
555
|
-
(ref) => {
|
|
556
|
-
if (ref === "#") {
|
|
557
|
-
return `#/${keyword}/${i}`;
|
|
558
|
-
}
|
|
559
|
-
if (ref.startsWith("#/$defs/")) {
|
|
560
|
-
const afterPrefix = ref.slice("#/$defs/".length);
|
|
561
|
-
const slashIdx = afterPrefix.indexOf("/");
|
|
562
|
-
const encodedSegment = slashIdx === -1 ? afterPrefix : afterPrefix.slice(0, slashIdx);
|
|
563
|
-
const rest2 = slashIdx === -1 ? "" : afterPrefix.slice(slashIdx);
|
|
564
|
-
const defName = decodeJsonPointerSegment(encodedSegment);
|
|
565
|
-
if (!promotedNames.has(defName)) {
|
|
566
|
-
return ref;
|
|
567
|
-
}
|
|
568
|
-
if (defName in renameMap) {
|
|
569
|
-
return `#/$defs/${encodeJsonPointerSegment(renameMap[defName])}${rest2}`;
|
|
570
|
-
}
|
|
571
|
-
return ref;
|
|
572
|
-
}
|
|
573
|
-
if (ref.startsWith("#/") && get(rest, ref.slice(2).split("/").map(decodeJsonPointerSegment)) !== void 0) {
|
|
574
|
-
return `#/${keyword}/${i}/${ref.slice(2)}`;
|
|
575
|
-
}
|
|
576
|
-
return ref;
|
|
577
|
-
}
|
|
578
|
-
));
|
|
637
|
+
compositionBranches.push(typeof schema === "boolean" ? schema : promoteJsonSchemaDefs(schema, mergedDefs, `#/${keyword}/${i}`));
|
|
579
638
|
}
|
|
580
639
|
const result = { [keyword]: compositionBranches };
|
|
581
|
-
if (
|
|
582
|
-
result.$defs = mergedDefs;
|
|
640
|
+
if (mergedDefs.size > 0) {
|
|
641
|
+
result.$defs = Object.fromEntries(mergedDefs);
|
|
583
642
|
}
|
|
584
643
|
return result;
|
|
585
644
|
}
|
|
586
645
|
function combineJsonObjectSchemaEntries(entries) {
|
|
587
|
-
const properties =
|
|
646
|
+
const properties = /* @__PURE__ */ new Map();
|
|
588
647
|
const required = [];
|
|
589
|
-
const mergedDefs =
|
|
648
|
+
const mergedDefs = /* @__PURE__ */ new Map();
|
|
590
649
|
for (const [name, propertySchema, optional] of entries) {
|
|
591
650
|
if (!optional) {
|
|
592
651
|
required.push(name);
|
|
593
652
|
}
|
|
594
|
-
|
|
595
|
-
properties[name] = propertySchema;
|
|
596
|
-
continue;
|
|
597
|
-
}
|
|
598
|
-
const { $defs, ...rest } = propertySchema;
|
|
599
|
-
const renameMap = {};
|
|
600
|
-
const promotedNames = /* @__PURE__ */ new Set();
|
|
601
|
-
if ($defs) {
|
|
602
|
-
for (const [defName, def] of Object.entries($defs)) {
|
|
603
|
-
if (def === void 0) {
|
|
604
|
-
continue;
|
|
605
|
-
}
|
|
606
|
-
promotedNames.add(defName);
|
|
607
|
-
if (defName in mergedDefs) {
|
|
608
|
-
if (isDeepEqual(mergedDefs[defName], def)) {
|
|
609
|
-
continue;
|
|
610
|
-
}
|
|
611
|
-
let counter = 2;
|
|
612
|
-
let newName = `${defName}${counter}`;
|
|
613
|
-
while (newName in mergedDefs) {
|
|
614
|
-
counter++;
|
|
615
|
-
newName = `${defName}${counter}`;
|
|
616
|
-
}
|
|
617
|
-
mergedDefs[newName] = def;
|
|
618
|
-
renameMap[defName] = newName;
|
|
619
|
-
} else {
|
|
620
|
-
mergedDefs[defName] = def;
|
|
621
|
-
}
|
|
622
|
-
}
|
|
623
|
-
}
|
|
624
|
-
const propertyPathPrefix = `#/properties/${encodeJsonPointerSegment(name)}`;
|
|
625
|
-
properties[name] = mapJsonSchemaRefs(rest, (ref) => {
|
|
626
|
-
if (ref.startsWith("#/$defs/")) {
|
|
627
|
-
const afterPrefix = ref.slice("#/$defs/".length);
|
|
628
|
-
const slashIdx = afterPrefix.indexOf("/");
|
|
629
|
-
const encodedSegment = slashIdx === -1 ? afterPrefix : afterPrefix.slice(0, slashIdx);
|
|
630
|
-
const refRest = slashIdx === -1 ? "" : afterPrefix.slice(slashIdx);
|
|
631
|
-
const defName = decodeJsonPointerSegment(encodedSegment);
|
|
632
|
-
if (!promotedNames.has(defName)) {
|
|
633
|
-
return ref;
|
|
634
|
-
}
|
|
635
|
-
if (defName in renameMap) {
|
|
636
|
-
return `#/$defs/${encodeJsonPointerSegment(renameMap[defName])}${refRest}`;
|
|
637
|
-
}
|
|
638
|
-
return ref;
|
|
639
|
-
}
|
|
640
|
-
if (ref === "#") {
|
|
641
|
-
return propertyPathPrefix;
|
|
642
|
-
}
|
|
643
|
-
if (ref.startsWith("#/") && get(rest, ref.slice(2).split("/").map(decodeJsonPointerSegment)) !== void 0) {
|
|
644
|
-
return `${propertyPathPrefix}/${ref.slice(2)}`;
|
|
645
|
-
}
|
|
646
|
-
return ref;
|
|
647
|
-
});
|
|
653
|
+
properties.set(name, typeof propertySchema === "boolean" ? propertySchema : promoteJsonSchemaDefs(propertySchema, mergedDefs, `#/properties/${encodeJsonPointerSegment(name)}`));
|
|
648
654
|
}
|
|
649
655
|
const schema = {
|
|
650
656
|
type: "object",
|
|
651
|
-
properties
|
|
657
|
+
properties: Object.fromEntries(properties)
|
|
652
658
|
};
|
|
653
659
|
if (required.length > 0) {
|
|
654
660
|
schema.required = required;
|
|
655
661
|
}
|
|
656
|
-
if (
|
|
657
|
-
schema.$defs = mergedDefs;
|
|
662
|
+
if (mergedDefs.size > 0) {
|
|
663
|
+
schema.$defs = Object.fromEntries(mergedDefs);
|
|
658
664
|
}
|
|
659
665
|
return schema;
|
|
660
666
|
}
|
|
@@ -755,7 +761,7 @@ function extractJsonObjectSchemaEntriesInternal(schema, $defs, resolvingRefs) {
|
|
|
755
761
|
return [
|
|
756
762
|
name,
|
|
757
763
|
schemas.length === 1 ? schemas[0] : { allOf: schemas },
|
|
758
|
-
|
|
764
|
+
!schema.required?.includes(name) && [entries.allOf, entries.anyOf, entries.oneOf].every((entry) => entry === void 0 || entry[2])
|
|
759
765
|
];
|
|
760
766
|
}),
|
|
761
767
|
objectLike
|
|
@@ -774,7 +780,7 @@ function flattenJsonUnionSchemaInternal(schema, resolvingRefs) {
|
|
|
774
780
|
}
|
|
775
781
|
const resolved = resolveJsonSchemaRootLocalRef(schema);
|
|
776
782
|
if (resolved !== schema) {
|
|
777
|
-
const result = flattenJsonUnionSchemaInternal(resolved, resolvingRefs.add(schema.$ref));
|
|
783
|
+
const result = flattenJsonUnionSchemaInternal(resolved, new Set(resolvingRefs).add(schema.$ref));
|
|
778
784
|
if (result.length > 1) {
|
|
779
785
|
return result;
|
|
780
786
|
}
|
|
@@ -844,26 +850,29 @@ class DelegatingJsonSchemaConverter {
|
|
|
844
850
|
constructor(converters = []) {
|
|
845
851
|
this.converters = converters;
|
|
846
852
|
}
|
|
847
|
-
|
|
853
|
+
convert(schema, direction) {
|
|
848
854
|
for (const converter of this.converters) {
|
|
849
|
-
if (
|
|
855
|
+
if (converter.condition(schema, direction)) {
|
|
850
856
|
return converter.convert(schema, direction);
|
|
851
857
|
}
|
|
852
858
|
}
|
|
853
|
-
|
|
854
|
-
if (schema && "jsonSchema" in schema["~standard"] && schema["~standard"].jsonSchema) {
|
|
855
|
-
try {
|
|
856
|
-
return [
|
|
857
|
-
schema["~standard"].jsonSchema[direction](),
|
|
858
|
-
optional
|
|
859
|
-
];
|
|
860
|
-
} catch {
|
|
861
|
-
}
|
|
862
|
-
}
|
|
863
|
-
return [{}, optional];
|
|
859
|
+
return [{}, true];
|
|
864
860
|
}
|
|
865
861
|
}
|
|
866
862
|
|
|
863
|
+
function isStandardSchemaOptional(schema, direction) {
|
|
864
|
+
try {
|
|
865
|
+
const result = schema["~standard"].validate(void 0);
|
|
866
|
+
if (result instanceof Promise) {
|
|
867
|
+
result.catch(() => {
|
|
868
|
+
});
|
|
869
|
+
return false;
|
|
870
|
+
}
|
|
871
|
+
return !result.issues && (direction === "input" || result.value === void 0);
|
|
872
|
+
} catch {
|
|
873
|
+
return false;
|
|
874
|
+
}
|
|
875
|
+
}
|
|
867
876
|
class StandardJsonSchemaConverter {
|
|
868
877
|
condition(schema, _direction) {
|
|
869
878
|
return Boolean(
|
|
@@ -876,15 +885,7 @@ class StandardJsonSchemaConverter {
|
|
|
876
885
|
convertInternal(schema, direction) {
|
|
877
886
|
try {
|
|
878
887
|
const jsonSchema = direction === "input" ? schema["~standard"].jsonSchema.input({ target: "draft-2020-12" }) : schema["~standard"].jsonSchema.output({ target: "draft-2020-12" });
|
|
879
|
-
|
|
880
|
-
try {
|
|
881
|
-
const result = schema["~standard"].validate(void 0);
|
|
882
|
-
if (!(result instanceof Promise) && !result.issues) {
|
|
883
|
-
optional = direction === "input" ? true : result.value === void 0;
|
|
884
|
-
}
|
|
885
|
-
} catch {
|
|
886
|
-
}
|
|
887
|
-
return [jsonSchema, optional];
|
|
888
|
+
return [jsonSchema, isStandardSchemaOptional(schema, direction)];
|
|
888
889
|
} catch {
|
|
889
890
|
return [{}, true];
|
|
890
891
|
}
|
|
@@ -907,23 +908,23 @@ class SmartCoercionHandlerPlugin {
|
|
|
907
908
|
return {
|
|
908
909
|
...options,
|
|
909
910
|
clientInterceptors: [
|
|
910
|
-
|
|
911
|
+
({ next, input, ...interceptorOptions }) => {
|
|
911
912
|
const inputSchemas = interceptorOptions.procedure["~orpc"].inputSchemas;
|
|
912
913
|
if (!inputSchemas) {
|
|
913
914
|
return next();
|
|
914
915
|
}
|
|
915
|
-
const coercedInput =
|
|
916
|
+
const coercedInput = this.coerceValue(inputSchemas, input);
|
|
916
917
|
return next({ ...interceptorOptions, input: coercedInput });
|
|
917
918
|
},
|
|
918
919
|
...toArray(options.clientInterceptors)
|
|
919
920
|
]
|
|
920
921
|
};
|
|
921
922
|
}
|
|
922
|
-
|
|
923
|
+
coerceValue(schemas, value) {
|
|
923
924
|
for (const schema of schemas) {
|
|
924
925
|
let converted = this.cache.get(schema);
|
|
925
926
|
if (!converted) {
|
|
926
|
-
converted =
|
|
927
|
+
converted = this.converter.convert(schema, "input");
|
|
927
928
|
this.cache.set(schema, converted);
|
|
928
929
|
}
|
|
929
930
|
value = this.coercer.coerce(converted, value);
|
|
@@ -962,30 +963,30 @@ class SmartCoercionLinkPlugin {
|
|
|
962
963
|
if (!outputSchemas) {
|
|
963
964
|
return output;
|
|
964
965
|
}
|
|
965
|
-
const coercedOutput =
|
|
966
|
+
const coercedOutput = this.coerceValue(outputSchemas, output);
|
|
966
967
|
return coercedOutput;
|
|
967
968
|
} catch (error) {
|
|
968
969
|
if (!(error instanceof ORPCError) || !error.defined) {
|
|
969
970
|
throw error;
|
|
970
971
|
}
|
|
971
972
|
const errorMap = procedure["~orpc"].errorMap;
|
|
972
|
-
const dataSchema = errorMap
|
|
973
|
+
const dataSchema = getOwn(errorMap, error.code)?.data;
|
|
973
974
|
if (!dataSchema) {
|
|
974
975
|
throw error;
|
|
975
976
|
}
|
|
976
977
|
const cloned = cloneORPCError(error);
|
|
977
|
-
cloned.data =
|
|
978
|
+
cloned.data = this.coerceValue([dataSchema], cloned.data);
|
|
978
979
|
throw cloned;
|
|
979
980
|
}
|
|
980
981
|
}
|
|
981
982
|
]
|
|
982
983
|
};
|
|
983
984
|
}
|
|
984
|
-
|
|
985
|
+
coerceValue(schemas, value) {
|
|
985
986
|
for (const schema of schemas) {
|
|
986
987
|
let converted = this.cache.get(schema);
|
|
987
988
|
if (!converted) {
|
|
988
|
-
converted =
|
|
989
|
+
converted = this.converter.convert(schema, "output");
|
|
989
990
|
this.cache.set(schema, converted);
|
|
990
991
|
}
|
|
991
992
|
value = this.coercer.coerce(converted, value);
|
|
@@ -994,4 +995,4 @@ class SmartCoercionLinkPlugin {
|
|
|
994
995
|
}
|
|
995
996
|
}
|
|
996
997
|
|
|
997
|
-
export { DelegatingJsonSchemaConverter, JsonSchemaCoercer, JsonSchemaXNativeType, SmartCoercionHandlerPlugin, SmartCoercionLinkPlugin, StandardJsonSchemaConverter, combineJsonObjectSchemaEntries, combineJsonSchemasWithComposition, decodeJsonPointerSegment, deduplicateJsonSchemas, encodeJsonPointerSegment, ensureJsonSchemaObject, extractJsonObjectSchemaEntries, flattenJsonUnionSchema, hoistRecursiveRefToDef, isJsonArraySchema, isJsonFileSchema, isJsonObjectSchema, isJsonPrimitiveSchema, isUnconstrainedSchema, mapJsonSchemaRefs, matchArrayableJsonSchema, resolveJsonSchemaRootLocalRef };
|
|
998
|
+
export { DelegatingJsonSchemaConverter, JsonSchemaCoercer, JsonSchemaFormat, JsonSchemaType, JsonSchemaXNativeType, SmartCoercionHandlerPlugin, SmartCoercionLinkPlugin, StandardJsonSchemaConverter, combineJsonObjectSchemaEntries, combineJsonSchemasWithComposition, decodeJsonPointerSegment, deduplicateJsonSchemas, encodeJsonPointerSegment, ensureJsonSchemaObject, extractJsonObjectSchemaEntries, flattenJsonUnionSchema, hoistRecursiveRefToDef, isJsonArraySchema, isJsonFileSchema, isJsonObjectSchema, isJsonPrimitiveSchema, isStandardSchemaOptional, isUnconstrainedSchema, mapJsonSchemaRefs, matchArrayableJsonSchema, resolveJsonSchemaRootLocalRef, visitJsonSchemaRefs };
|