@beff/client 0.0.113 → 0.0.115
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/CHANGELOG.md +16 -0
- package/dist/cjs/b.d.ts.map +1 -1
- package/dist/cjs/b.js +24 -204
- package/dist/cjs/codegen-v2.d.ts +221 -0
- package/dist/cjs/codegen-v2.d.ts.map +1 -0
- package/dist/cjs/codegen-v2.js +1254 -0
- package/dist/cjs/hash.d.ts +20 -0
- package/dist/cjs/hash.d.ts.map +1 -0
- package/dist/cjs/hash.js +47 -0
- package/dist/cjs/types.d.ts +3 -0
- package/dist/cjs/types.d.ts.map +1 -1
- package/dist/esm/b.d.ts.map +1 -1
- package/dist/esm/b.js +24 -204
- package/dist/esm/codegen-v2.d.ts +221 -0
- package/dist/esm/codegen-v2.d.ts.map +1 -0
- package/dist/esm/codegen-v2.js +1230 -0
- package/dist/esm/hash.d.ts +20 -0
- package/dist/esm/hash.d.ts.map +1 -0
- package/dist/esm/hash.js +42 -0
- package/dist/esm/types.d.ts +3 -0
- package/dist/esm/types.d.ts.map +1 -1
- package/dist/tsconfig.cjs.tsbuildinfo +1 -1
- package/dist/tsconfig.esm.tsbuildinfo +1 -1
- package/dist/tsconfig.types.tsbuildinfo +1 -1
- package/dist/types/b.d.ts.map +1 -1
- package/dist/types/codegen-v2.d.ts +221 -0
- package/dist/types/codegen-v2.d.ts.map +1 -0
- package/dist/types/hash.d.ts +20 -0
- package/dist/types/hash.d.ts.map +1 -0
- package/dist/types/types.d.ts +3 -0
- package/dist/types/types.d.ts.map +1 -1
- package/package.json +8 -2
- package/tsconfig.json +1 -1
|
@@ -0,0 +1,1230 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { generateHashFromString, generateHashFromNumbers, unknownHash, stringHash, numberHash, booleanHash, nullishHash, undefinedHash, arrayHash, objectHash, dateHash, bigintHash, stringWithFormatHash, numberWithFormatHash, anyOfConstsHash, tupleHash, allOfHash, anyOfHash, optionalFieldHash, } from "./hash";
|
|
3
|
+
import { printErrors } from "./err";
|
|
4
|
+
const JSON_PROTO = Object.getPrototypeOf({});
|
|
5
|
+
function deepmergeConstructor(options) {
|
|
6
|
+
function isNotPrototypeKey(value) {
|
|
7
|
+
return value !== "constructor" && value !== "prototype" && value !== "__proto__";
|
|
8
|
+
}
|
|
9
|
+
function cloneArray(value) {
|
|
10
|
+
let i = 0;
|
|
11
|
+
const il = value.length;
|
|
12
|
+
const result = new Array(il);
|
|
13
|
+
for (i; i < il; ++i) {
|
|
14
|
+
result[i] = clone(value[i]);
|
|
15
|
+
}
|
|
16
|
+
return result;
|
|
17
|
+
}
|
|
18
|
+
function cloneObject(target) {
|
|
19
|
+
const result = {};
|
|
20
|
+
if (cloneProtoObject && Object.getPrototypeOf(target) !== JSON_PROTO) {
|
|
21
|
+
return cloneProtoObject(target);
|
|
22
|
+
}
|
|
23
|
+
const targetKeys = getKeys(target);
|
|
24
|
+
let i, il, key;
|
|
25
|
+
for (i = 0, il = targetKeys.length; i < il; ++i) {
|
|
26
|
+
//@ts-ignore
|
|
27
|
+
isNotPrototypeKey((key = targetKeys[i])) && (result[key] = clone(target[key]));
|
|
28
|
+
}
|
|
29
|
+
return result;
|
|
30
|
+
}
|
|
31
|
+
function concatArrays(target, source) {
|
|
32
|
+
const tl = target.length;
|
|
33
|
+
const sl = source.length;
|
|
34
|
+
let i = 0;
|
|
35
|
+
const result = new Array(tl + sl);
|
|
36
|
+
for (i; i < tl; ++i) {
|
|
37
|
+
result[i] = clone(target[i]);
|
|
38
|
+
}
|
|
39
|
+
for (i = 0; i < sl; ++i) {
|
|
40
|
+
result[i + tl] = clone(source[i]);
|
|
41
|
+
}
|
|
42
|
+
return result;
|
|
43
|
+
}
|
|
44
|
+
const propertyIsEnumerable = Object.prototype.propertyIsEnumerable;
|
|
45
|
+
function getSymbolsAndKeys(value) {
|
|
46
|
+
const result = Object.keys(value);
|
|
47
|
+
const keys = Object.getOwnPropertySymbols(value);
|
|
48
|
+
for (let i = 0, il = keys.length; i < il; ++i) {
|
|
49
|
+
//@ts-ignore
|
|
50
|
+
propertyIsEnumerable.call(value, keys[i]) && result.push(keys[i]);
|
|
51
|
+
}
|
|
52
|
+
return result;
|
|
53
|
+
}
|
|
54
|
+
const getKeys = options?.symbols ? getSymbolsAndKeys : Object.keys;
|
|
55
|
+
const cloneProtoObject = typeof options?.cloneProtoObject === "function" ? options.cloneProtoObject : undefined;
|
|
56
|
+
function isMergeableObject(value) {
|
|
57
|
+
return (typeof value === "object" && value !== null && !(value instanceof RegExp) && !(value instanceof Date));
|
|
58
|
+
}
|
|
59
|
+
function isPrimitive(value) {
|
|
60
|
+
return typeof value !== "object" || value === null;
|
|
61
|
+
}
|
|
62
|
+
const isPrimitiveOrBuiltIn =
|
|
63
|
+
// @ts-ignore
|
|
64
|
+
typeof Buffer !== "undefined"
|
|
65
|
+
? (value) => typeof value !== "object" ||
|
|
66
|
+
value === null ||
|
|
67
|
+
value instanceof RegExp ||
|
|
68
|
+
value instanceof Date ||
|
|
69
|
+
// @ts-ignore
|
|
70
|
+
value instanceof Buffer
|
|
71
|
+
: (value) => typeof value !== "object" || value === null || value instanceof RegExp || value instanceof Date;
|
|
72
|
+
const mergeArray = options && typeof options.mergeArray === "function"
|
|
73
|
+
? options.mergeArray({ clone, deepmerge: _deepmerge, getKeys, isMergeableObject })
|
|
74
|
+
: concatArrays;
|
|
75
|
+
function clone(entry) {
|
|
76
|
+
return isMergeableObject(entry) ? (Array.isArray(entry) ? cloneArray(entry) : cloneObject(entry)) : entry;
|
|
77
|
+
}
|
|
78
|
+
function mergeObject(target, source) {
|
|
79
|
+
const result = {};
|
|
80
|
+
const targetKeys = getKeys(target);
|
|
81
|
+
const sourceKeys = getKeys(source);
|
|
82
|
+
let i, il, key;
|
|
83
|
+
for (i = 0, il = targetKeys.length; i < il; ++i) {
|
|
84
|
+
isNotPrototypeKey((key = targetKeys[i])) &&
|
|
85
|
+
sourceKeys.indexOf(key) === -1 &&
|
|
86
|
+
// @ts-ignore
|
|
87
|
+
(result[key] = clone(target[key]));
|
|
88
|
+
}
|
|
89
|
+
for (i = 0, il = sourceKeys.length; i < il; ++i) {
|
|
90
|
+
if (!isNotPrototypeKey((key = sourceKeys[i]))) {
|
|
91
|
+
continue;
|
|
92
|
+
}
|
|
93
|
+
if (key in target) {
|
|
94
|
+
if (targetKeys.indexOf(key) !== -1) {
|
|
95
|
+
if (cloneProtoObject &&
|
|
96
|
+
isMergeableObject(source[key]) &&
|
|
97
|
+
Object.getPrototypeOf(source[key]) !== JSON_PROTO) {
|
|
98
|
+
// @ts-ignore
|
|
99
|
+
result[key] = cloneProtoObject(source[key]);
|
|
100
|
+
}
|
|
101
|
+
else {
|
|
102
|
+
// @ts-ignore
|
|
103
|
+
result[key] = _deepmerge(target[key], source[key]);
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
else {
|
|
108
|
+
// @ts-ignore
|
|
109
|
+
result[key] = clone(source[key]);
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
return result;
|
|
113
|
+
}
|
|
114
|
+
function _deepmerge(target, source) {
|
|
115
|
+
const sourceIsArray = Array.isArray(source);
|
|
116
|
+
const targetIsArray = Array.isArray(target);
|
|
117
|
+
if (isPrimitive(source)) {
|
|
118
|
+
return source;
|
|
119
|
+
}
|
|
120
|
+
else if (isPrimitiveOrBuiltIn(target)) {
|
|
121
|
+
return clone(source);
|
|
122
|
+
}
|
|
123
|
+
else if (sourceIsArray && targetIsArray) {
|
|
124
|
+
return mergeArray(target, source);
|
|
125
|
+
}
|
|
126
|
+
else if (sourceIsArray !== targetIsArray) {
|
|
127
|
+
return clone(source);
|
|
128
|
+
}
|
|
129
|
+
else {
|
|
130
|
+
return mergeObject(target, source);
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
function _deepmergeAll() {
|
|
134
|
+
switch (arguments.length) {
|
|
135
|
+
case 0:
|
|
136
|
+
return {};
|
|
137
|
+
case 1:
|
|
138
|
+
return clone(arguments[0]);
|
|
139
|
+
case 2:
|
|
140
|
+
return _deepmerge(arguments[0], arguments[1]);
|
|
141
|
+
}
|
|
142
|
+
let result;
|
|
143
|
+
for (let i = 0, il = arguments.length; i < il; ++i) {
|
|
144
|
+
result = _deepmerge(result, arguments[i]);
|
|
145
|
+
}
|
|
146
|
+
return result;
|
|
147
|
+
}
|
|
148
|
+
return _deepmergeAll;
|
|
149
|
+
}
|
|
150
|
+
function deepmergeArray(options) {
|
|
151
|
+
const deepmerge = options.deepmerge;
|
|
152
|
+
const clone = options.clone;
|
|
153
|
+
return function (target, source) {
|
|
154
|
+
let i = 0;
|
|
155
|
+
//const tl = target.length;
|
|
156
|
+
const sl = source.length;
|
|
157
|
+
const il = Math.max(target.length, source.length);
|
|
158
|
+
const result = new Array(il);
|
|
159
|
+
for (i = 0; i < il; ++i) {
|
|
160
|
+
if (i < sl) {
|
|
161
|
+
result[i] = deepmerge(target[i], source[i]);
|
|
162
|
+
}
|
|
163
|
+
else {
|
|
164
|
+
result[i] = clone(target[i]);
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
return result;
|
|
168
|
+
};
|
|
169
|
+
}
|
|
170
|
+
const deepmerge = deepmergeConstructor({ mergeArray: deepmergeArray });
|
|
171
|
+
function buildUnionError(ctx, errors, received) {
|
|
172
|
+
return [
|
|
173
|
+
{
|
|
174
|
+
path: [...ctx.path],
|
|
175
|
+
received,
|
|
176
|
+
errors,
|
|
177
|
+
isUnionError: true,
|
|
178
|
+
},
|
|
179
|
+
];
|
|
180
|
+
}
|
|
181
|
+
function buildError(ctx, message, received) {
|
|
182
|
+
return [
|
|
183
|
+
{
|
|
184
|
+
message,
|
|
185
|
+
path: [...ctx.path],
|
|
186
|
+
received,
|
|
187
|
+
},
|
|
188
|
+
];
|
|
189
|
+
}
|
|
190
|
+
function pushPath(ctx, key) {
|
|
191
|
+
ctx.path.push(key);
|
|
192
|
+
}
|
|
193
|
+
function popPath(ctx) {
|
|
194
|
+
ctx.path.pop();
|
|
195
|
+
}
|
|
196
|
+
function printPath(ctx) {
|
|
197
|
+
return ctx.path.join(".");
|
|
198
|
+
}
|
|
199
|
+
function buildSchemaErrorMessage(ctx, message) {
|
|
200
|
+
return `Failed to print schema. At ${printPath(ctx)}: ${message}`;
|
|
201
|
+
}
|
|
202
|
+
const limitedCommaJoinJson = (arr) => {
|
|
203
|
+
const limit = 3;
|
|
204
|
+
if (arr.length < limit) {
|
|
205
|
+
return arr.map((it) => JSON.stringify(it)).join(", ");
|
|
206
|
+
}
|
|
207
|
+
return (arr
|
|
208
|
+
.slice(0, limit)
|
|
209
|
+
.map((it) => JSON.stringify(it))
|
|
210
|
+
.join(", ") + `...`);
|
|
211
|
+
};
|
|
212
|
+
const stringFormatters = {};
|
|
213
|
+
export function registerStringFormatter(name, validator) {
|
|
214
|
+
stringFormatters[name] = validator;
|
|
215
|
+
}
|
|
216
|
+
const numberFormatters = {};
|
|
217
|
+
export function registerNumberFormatter(name, validator) {
|
|
218
|
+
numberFormatters[name] = validator;
|
|
219
|
+
}
|
|
220
|
+
export class TypeofRuntype {
|
|
221
|
+
typeName;
|
|
222
|
+
constructor(typeName) {
|
|
223
|
+
this.typeName = typeName;
|
|
224
|
+
}
|
|
225
|
+
describe(_ctx) {
|
|
226
|
+
return this.typeName;
|
|
227
|
+
}
|
|
228
|
+
schema(_ctx) {
|
|
229
|
+
return { type: this.typeName };
|
|
230
|
+
}
|
|
231
|
+
validate(_ctx, input) {
|
|
232
|
+
return typeof input === this.typeName;
|
|
233
|
+
}
|
|
234
|
+
parseAfterValidation(_ctx, input) {
|
|
235
|
+
return input;
|
|
236
|
+
}
|
|
237
|
+
reportDecodeError(ctx, input) {
|
|
238
|
+
return buildError(ctx, "expected " + this.typeName, input);
|
|
239
|
+
}
|
|
240
|
+
hash(_ctx) {
|
|
241
|
+
switch (this.typeName) {
|
|
242
|
+
case "string":
|
|
243
|
+
return stringHash;
|
|
244
|
+
case "number":
|
|
245
|
+
return numberHash;
|
|
246
|
+
case "boolean":
|
|
247
|
+
return booleanHash;
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
export class AnyRuntype {
|
|
252
|
+
describe(_ctx) {
|
|
253
|
+
return "any";
|
|
254
|
+
}
|
|
255
|
+
schema(_ctx) {
|
|
256
|
+
return {};
|
|
257
|
+
}
|
|
258
|
+
validate(_ctx, _input) {
|
|
259
|
+
return true;
|
|
260
|
+
}
|
|
261
|
+
parseAfterValidation(_ctx, input) {
|
|
262
|
+
return input;
|
|
263
|
+
}
|
|
264
|
+
reportDecodeError(ctx, input) {
|
|
265
|
+
return buildError(ctx, "expected any", input);
|
|
266
|
+
}
|
|
267
|
+
hash(_ctx) {
|
|
268
|
+
return unknownHash;
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
export class NullishRuntype {
|
|
272
|
+
description;
|
|
273
|
+
constructor(description) {
|
|
274
|
+
this.description = description;
|
|
275
|
+
}
|
|
276
|
+
describe(_ctx) {
|
|
277
|
+
return this.description;
|
|
278
|
+
}
|
|
279
|
+
schema(_ctx) {
|
|
280
|
+
return { type: "null" };
|
|
281
|
+
}
|
|
282
|
+
validate(_ctx, input) {
|
|
283
|
+
return input == null;
|
|
284
|
+
}
|
|
285
|
+
parseAfterValidation(_ctx, input) {
|
|
286
|
+
return input;
|
|
287
|
+
}
|
|
288
|
+
reportDecodeError(ctx, input) {
|
|
289
|
+
return buildError(ctx, "expected nullish value", input);
|
|
290
|
+
}
|
|
291
|
+
hash(_ctx) {
|
|
292
|
+
return nullishHash;
|
|
293
|
+
}
|
|
294
|
+
}
|
|
295
|
+
export class NeverRuntype {
|
|
296
|
+
describe(_ctx) {
|
|
297
|
+
return "never";
|
|
298
|
+
}
|
|
299
|
+
schema(_ctx) {
|
|
300
|
+
return { anyOf: [] };
|
|
301
|
+
}
|
|
302
|
+
validate(_ctx, _input) {
|
|
303
|
+
return false;
|
|
304
|
+
}
|
|
305
|
+
parseAfterValidation(_ctx, _input) {
|
|
306
|
+
throw new Error("unreachable");
|
|
307
|
+
}
|
|
308
|
+
reportDecodeError(ctx, input) {
|
|
309
|
+
return buildError(ctx, "expected never", input);
|
|
310
|
+
}
|
|
311
|
+
hash(_ctx) {
|
|
312
|
+
return undefinedHash;
|
|
313
|
+
}
|
|
314
|
+
}
|
|
315
|
+
export class ConstRuntype {
|
|
316
|
+
value;
|
|
317
|
+
constructor(value) {
|
|
318
|
+
this.value = value ?? null;
|
|
319
|
+
}
|
|
320
|
+
describe(_ctx) {
|
|
321
|
+
return JSON.stringify(this.value);
|
|
322
|
+
}
|
|
323
|
+
schema(_ctx) {
|
|
324
|
+
return { const: this.value };
|
|
325
|
+
}
|
|
326
|
+
validate(_ctx, input) {
|
|
327
|
+
if (this.value == null) {
|
|
328
|
+
return input == this.value;
|
|
329
|
+
}
|
|
330
|
+
return input === this.value;
|
|
331
|
+
}
|
|
332
|
+
parseAfterValidation(_ctx, input) {
|
|
333
|
+
return input;
|
|
334
|
+
}
|
|
335
|
+
reportDecodeError(ctx, input) {
|
|
336
|
+
return buildError(ctx, `expected ${JSON.stringify(this.value)}`, input);
|
|
337
|
+
}
|
|
338
|
+
hash(_ctx) {
|
|
339
|
+
if (this.value == null) {
|
|
340
|
+
return nullishHash;
|
|
341
|
+
}
|
|
342
|
+
switch (typeof this.value) {
|
|
343
|
+
case "string":
|
|
344
|
+
return generateHashFromString(this.value);
|
|
345
|
+
case "number":
|
|
346
|
+
return generateHashFromNumbers([this.value]);
|
|
347
|
+
case "boolean":
|
|
348
|
+
return generateHashFromString(this.value ? "true" : "false");
|
|
349
|
+
}
|
|
350
|
+
}
|
|
351
|
+
}
|
|
352
|
+
export class RegexRuntype {
|
|
353
|
+
regex;
|
|
354
|
+
description;
|
|
355
|
+
constructor(regex, description) {
|
|
356
|
+
this.regex = regex;
|
|
357
|
+
this.description = description;
|
|
358
|
+
}
|
|
359
|
+
describe(_ctx) {
|
|
360
|
+
return this.description;
|
|
361
|
+
}
|
|
362
|
+
schema(_ctx) {
|
|
363
|
+
return { type: "string", pattern: this.description };
|
|
364
|
+
}
|
|
365
|
+
validate(_ctx, input) {
|
|
366
|
+
if (typeof input === "string") {
|
|
367
|
+
return this.regex.test(input);
|
|
368
|
+
}
|
|
369
|
+
return false;
|
|
370
|
+
}
|
|
371
|
+
parseAfterValidation(_ctx, input) {
|
|
372
|
+
return input;
|
|
373
|
+
}
|
|
374
|
+
reportDecodeError(ctx, input) {
|
|
375
|
+
return buildError(ctx, `expected string matching ${this.description}`, input);
|
|
376
|
+
}
|
|
377
|
+
hash(_ctx) {
|
|
378
|
+
return generateHashFromString(this.description);
|
|
379
|
+
}
|
|
380
|
+
}
|
|
381
|
+
export class DateRuntype {
|
|
382
|
+
describe(_ctx) {
|
|
383
|
+
return "Date";
|
|
384
|
+
}
|
|
385
|
+
schema(ctx) {
|
|
386
|
+
throw new Error(buildSchemaErrorMessage(ctx, "Cannot generate JSON Schema for Date"));
|
|
387
|
+
}
|
|
388
|
+
validate(_ctx, input) {
|
|
389
|
+
return input instanceof Date;
|
|
390
|
+
}
|
|
391
|
+
parseAfterValidation(_ctx, input) {
|
|
392
|
+
return input;
|
|
393
|
+
}
|
|
394
|
+
reportDecodeError(ctx, input) {
|
|
395
|
+
return buildError(ctx, `expected Date`, input);
|
|
396
|
+
}
|
|
397
|
+
hash(_ctx) {
|
|
398
|
+
return dateHash;
|
|
399
|
+
}
|
|
400
|
+
}
|
|
401
|
+
export class BigIntRuntype {
|
|
402
|
+
describe(_ctx) {
|
|
403
|
+
return "BigInt";
|
|
404
|
+
}
|
|
405
|
+
schema(ctx) {
|
|
406
|
+
throw new Error(buildSchemaErrorMessage(ctx, "Cannot generate JSON Schema for BigInt"));
|
|
407
|
+
}
|
|
408
|
+
validate(_ctx, input) {
|
|
409
|
+
return typeof input === "bigint";
|
|
410
|
+
}
|
|
411
|
+
parseAfterValidation(_ctx, input) {
|
|
412
|
+
return input;
|
|
413
|
+
}
|
|
414
|
+
reportDecodeError(ctx, input) {
|
|
415
|
+
return buildError(ctx, `expected BigInt`, input);
|
|
416
|
+
}
|
|
417
|
+
hash(_ctx) {
|
|
418
|
+
return bigintHash;
|
|
419
|
+
}
|
|
420
|
+
}
|
|
421
|
+
export class StringWithFormatRuntype {
|
|
422
|
+
formats;
|
|
423
|
+
constructor(formats) {
|
|
424
|
+
this.formats = formats;
|
|
425
|
+
}
|
|
426
|
+
describe(_ctx) {
|
|
427
|
+
if (this.formats.length === 0) {
|
|
428
|
+
throw new Error("INTERNAL ERROR: No formats provided");
|
|
429
|
+
}
|
|
430
|
+
const [first, ...rest] = this.formats;
|
|
431
|
+
let acc = `StringFormat<"${first}">`;
|
|
432
|
+
for (const r of rest) {
|
|
433
|
+
acc = `StringFormatExtends<${acc}, "${r}">`;
|
|
434
|
+
}
|
|
435
|
+
return acc;
|
|
436
|
+
}
|
|
437
|
+
schema(_ctx) {
|
|
438
|
+
return {
|
|
439
|
+
type: "string",
|
|
440
|
+
format: this.formats.join(" and "),
|
|
441
|
+
};
|
|
442
|
+
}
|
|
443
|
+
validate(_ctx, input) {
|
|
444
|
+
if (typeof input !== "string") {
|
|
445
|
+
return false;
|
|
446
|
+
}
|
|
447
|
+
for (const f of this.formats) {
|
|
448
|
+
const validator = stringFormatters[f];
|
|
449
|
+
if (validator == null) {
|
|
450
|
+
return false;
|
|
451
|
+
}
|
|
452
|
+
if (!validator(input)) {
|
|
453
|
+
return false;
|
|
454
|
+
}
|
|
455
|
+
}
|
|
456
|
+
return true;
|
|
457
|
+
}
|
|
458
|
+
parseAfterValidation(_ctx, input) {
|
|
459
|
+
return input;
|
|
460
|
+
}
|
|
461
|
+
reportDecodeError(ctx, input) {
|
|
462
|
+
return buildError(ctx, `expected string with format "${this.formats.join(" and ")}"`, input);
|
|
463
|
+
}
|
|
464
|
+
hash(_ctx) {
|
|
465
|
+
let acc = [stringWithFormatHash];
|
|
466
|
+
for (const f of [...this.formats].sort()) {
|
|
467
|
+
acc.push(generateHashFromString(f));
|
|
468
|
+
}
|
|
469
|
+
return generateHashFromNumbers(acc);
|
|
470
|
+
}
|
|
471
|
+
}
|
|
472
|
+
export class NumberWithFormatRuntype {
|
|
473
|
+
formats;
|
|
474
|
+
constructor(formats) {
|
|
475
|
+
this.formats = formats;
|
|
476
|
+
}
|
|
477
|
+
describe(_ctx) {
|
|
478
|
+
if (this.formats.length === 0) {
|
|
479
|
+
throw new Error("INTERNAL ERROR: No formats provided");
|
|
480
|
+
}
|
|
481
|
+
const [first, ...rest] = this.formats;
|
|
482
|
+
let acc = `NumberFormat<"${first}">`;
|
|
483
|
+
for (const r of rest) {
|
|
484
|
+
acc = `NumberFormatExtends<${acc}, "${r}">`;
|
|
485
|
+
}
|
|
486
|
+
return acc;
|
|
487
|
+
}
|
|
488
|
+
schema(_ctx) {
|
|
489
|
+
return {
|
|
490
|
+
type: "number",
|
|
491
|
+
format: this.formats.join(" and "),
|
|
492
|
+
};
|
|
493
|
+
}
|
|
494
|
+
validate(_ctx, input) {
|
|
495
|
+
if (typeof input !== "number") {
|
|
496
|
+
return false;
|
|
497
|
+
}
|
|
498
|
+
for (const f of this.formats) {
|
|
499
|
+
const validator = numberFormatters[f];
|
|
500
|
+
if (validator == null) {
|
|
501
|
+
return false;
|
|
502
|
+
}
|
|
503
|
+
if (!validator(input)) {
|
|
504
|
+
return false;
|
|
505
|
+
}
|
|
506
|
+
}
|
|
507
|
+
return true;
|
|
508
|
+
}
|
|
509
|
+
parseAfterValidation(_ctx, input) {
|
|
510
|
+
return input;
|
|
511
|
+
}
|
|
512
|
+
reportDecodeError(ctx, input) {
|
|
513
|
+
return buildError(ctx, `expected number with format "${this.formats.join(" and ")}"`, input);
|
|
514
|
+
}
|
|
515
|
+
hash(_ctx) {
|
|
516
|
+
let acc = [numberWithFormatHash];
|
|
517
|
+
for (const f of [...this.formats].sort()) {
|
|
518
|
+
acc.push(generateHashFromString(f));
|
|
519
|
+
}
|
|
520
|
+
return generateHashFromNumbers(acc);
|
|
521
|
+
}
|
|
522
|
+
}
|
|
523
|
+
export class AnyOfConstsRuntype {
|
|
524
|
+
values;
|
|
525
|
+
constructor(values) {
|
|
526
|
+
this.values = values;
|
|
527
|
+
}
|
|
528
|
+
describe(_ctx) {
|
|
529
|
+
const parts = this.values.map((it) => JSON.stringify(it));
|
|
530
|
+
const inner = parts.join(" | ");
|
|
531
|
+
return `(${inner})`;
|
|
532
|
+
}
|
|
533
|
+
schema(_ctx) {
|
|
534
|
+
return {
|
|
535
|
+
enum: this.values,
|
|
536
|
+
};
|
|
537
|
+
}
|
|
538
|
+
validate(_ctx, input) {
|
|
539
|
+
if (input == null) {
|
|
540
|
+
if (this.values.includes(null)) {
|
|
541
|
+
return true;
|
|
542
|
+
}
|
|
543
|
+
}
|
|
544
|
+
return this.values.includes(input);
|
|
545
|
+
}
|
|
546
|
+
parseAfterValidation(_ctx, input) {
|
|
547
|
+
return input;
|
|
548
|
+
}
|
|
549
|
+
reportDecodeError(ctx, input) {
|
|
550
|
+
return buildError(ctx, `expected one of ${limitedCommaJoinJson(this.values)}`, input);
|
|
551
|
+
}
|
|
552
|
+
hash(_ctx) {
|
|
553
|
+
let acc = [anyOfConstsHash];
|
|
554
|
+
for (const v of [...this.values].sort()) {
|
|
555
|
+
if (v == null) {
|
|
556
|
+
acc.push(nullishHash);
|
|
557
|
+
}
|
|
558
|
+
else {
|
|
559
|
+
switch (typeof v) {
|
|
560
|
+
case "string":
|
|
561
|
+
acc.push(generateHashFromString(v));
|
|
562
|
+
break;
|
|
563
|
+
case "number":
|
|
564
|
+
acc.push(generateHashFromNumbers([v]));
|
|
565
|
+
break;
|
|
566
|
+
case "boolean":
|
|
567
|
+
acc.push(generateHashFromString(v ? "true" : "false"));
|
|
568
|
+
break;
|
|
569
|
+
}
|
|
570
|
+
}
|
|
571
|
+
}
|
|
572
|
+
return generateHashFromNumbers(acc);
|
|
573
|
+
}
|
|
574
|
+
}
|
|
575
|
+
export class TupleRuntype {
|
|
576
|
+
prefix;
|
|
577
|
+
rest;
|
|
578
|
+
constructor(prefix, rest) {
|
|
579
|
+
this.prefix = prefix;
|
|
580
|
+
this.rest = rest;
|
|
581
|
+
}
|
|
582
|
+
describe(ctx) {
|
|
583
|
+
const prefix = this.prefix.map((it) => it.describe(ctx)).join(", ");
|
|
584
|
+
const rest = this.rest != null ? `...Array<${this.rest.describe(ctx)}>` : null;
|
|
585
|
+
const inner = [prefix, rest].filter((it) => it != null && it.length > 0).join(", ");
|
|
586
|
+
return `[${inner}]`;
|
|
587
|
+
}
|
|
588
|
+
schema(ctx) {
|
|
589
|
+
pushPath(ctx, "[]");
|
|
590
|
+
const prefixItems = this.prefix.map((it) => it.schema(ctx));
|
|
591
|
+
const items = this.rest != null ? this.rest.schema(ctx) : false;
|
|
592
|
+
popPath(ctx);
|
|
593
|
+
return {
|
|
594
|
+
type: "array",
|
|
595
|
+
prefixItems,
|
|
596
|
+
items,
|
|
597
|
+
};
|
|
598
|
+
}
|
|
599
|
+
validate(ctx, input) {
|
|
600
|
+
if (Array.isArray(input)) {
|
|
601
|
+
let idx = 0;
|
|
602
|
+
for (const prefixItem of this.prefix) {
|
|
603
|
+
if (!prefixItem.validate(ctx, input[idx])) {
|
|
604
|
+
return false;
|
|
605
|
+
}
|
|
606
|
+
idx++;
|
|
607
|
+
}
|
|
608
|
+
if (this.rest != null) {
|
|
609
|
+
for (let i = idx; i < input.length; i++) {
|
|
610
|
+
if (!this.rest.validate(ctx, input[i])) {
|
|
611
|
+
return false;
|
|
612
|
+
}
|
|
613
|
+
}
|
|
614
|
+
}
|
|
615
|
+
else {
|
|
616
|
+
if (input.length > idx) {
|
|
617
|
+
return false;
|
|
618
|
+
}
|
|
619
|
+
}
|
|
620
|
+
return true;
|
|
621
|
+
}
|
|
622
|
+
return false;
|
|
623
|
+
}
|
|
624
|
+
parseAfterValidation(ctx, input) {
|
|
625
|
+
let idx = 0;
|
|
626
|
+
let acc = [];
|
|
627
|
+
for (const prefixItem of this.prefix) {
|
|
628
|
+
acc.push(prefixItem.parseAfterValidation(ctx, input[idx]));
|
|
629
|
+
idx++;
|
|
630
|
+
}
|
|
631
|
+
if (this.rest != null) {
|
|
632
|
+
for (let i = idx; i < input.length; i++) {
|
|
633
|
+
acc.push(this.rest.parseAfterValidation(ctx, input[i]));
|
|
634
|
+
}
|
|
635
|
+
}
|
|
636
|
+
return acc;
|
|
637
|
+
}
|
|
638
|
+
reportDecodeError(ctx, input) {
|
|
639
|
+
if (!Array.isArray(input)) {
|
|
640
|
+
return buildError(ctx, "expected tuple", input);
|
|
641
|
+
}
|
|
642
|
+
let idx = 0;
|
|
643
|
+
let acc = [];
|
|
644
|
+
for (const prefixItem of this.prefix) {
|
|
645
|
+
const ok = prefixItem.validate(ctx, input[idx]);
|
|
646
|
+
if (!ok) {
|
|
647
|
+
pushPath(ctx, `[${idx}]`);
|
|
648
|
+
const errors = prefixItem.reportDecodeError(ctx, input[idx]);
|
|
649
|
+
acc.push(...errors);
|
|
650
|
+
popPath(ctx);
|
|
651
|
+
}
|
|
652
|
+
idx++;
|
|
653
|
+
}
|
|
654
|
+
if (this.rest != null) {
|
|
655
|
+
for (let i = idx; i < input.length; i++) {
|
|
656
|
+
const ok = this.rest.validate(ctx, input[i]);
|
|
657
|
+
if (!ok) {
|
|
658
|
+
pushPath(ctx, `[${i}]`);
|
|
659
|
+
const errors = this.rest.reportDecodeError(ctx, input[i]);
|
|
660
|
+
acc.push(...errors);
|
|
661
|
+
popPath(ctx);
|
|
662
|
+
}
|
|
663
|
+
}
|
|
664
|
+
}
|
|
665
|
+
return acc;
|
|
666
|
+
}
|
|
667
|
+
hash(ctx) {
|
|
668
|
+
let acc = [tupleHash];
|
|
669
|
+
for (const p of this.prefix) {
|
|
670
|
+
acc.push(p.hash(ctx));
|
|
671
|
+
}
|
|
672
|
+
if (this.rest != null) {
|
|
673
|
+
acc.push(this.rest.hash(ctx));
|
|
674
|
+
}
|
|
675
|
+
else {
|
|
676
|
+
acc.push(0);
|
|
677
|
+
}
|
|
678
|
+
return generateHashFromNumbers(acc);
|
|
679
|
+
}
|
|
680
|
+
}
|
|
681
|
+
export class AllOfRuntype {
|
|
682
|
+
schemas;
|
|
683
|
+
constructor(schemas) {
|
|
684
|
+
this.schemas = schemas;
|
|
685
|
+
}
|
|
686
|
+
describe(ctx) {
|
|
687
|
+
return `(${this.schemas.map((it) => it.describe(ctx)).join(" & ")})`;
|
|
688
|
+
}
|
|
689
|
+
schema(ctx) {
|
|
690
|
+
return {
|
|
691
|
+
allOf: this.schemas.map((it) => it.schema(ctx)),
|
|
692
|
+
};
|
|
693
|
+
}
|
|
694
|
+
validate(ctx, input) {
|
|
695
|
+
for (const it of this.schemas) {
|
|
696
|
+
const isObj = typeof input === "object";
|
|
697
|
+
if (!isObj) {
|
|
698
|
+
return false;
|
|
699
|
+
}
|
|
700
|
+
if (!it.validate(ctx, input)) {
|
|
701
|
+
return false;
|
|
702
|
+
}
|
|
703
|
+
}
|
|
704
|
+
return true;
|
|
705
|
+
}
|
|
706
|
+
parseAfterValidation(ctx, input) {
|
|
707
|
+
let acc = {};
|
|
708
|
+
for (const it of this.schemas) {
|
|
709
|
+
const parsed = it.parseAfterValidation(ctx, input);
|
|
710
|
+
if (typeof parsed !== "object") {
|
|
711
|
+
throw new Error("INTERNAL ERROR: AllOfParser: Expected object");
|
|
712
|
+
}
|
|
713
|
+
acc = { ...acc, ...parsed };
|
|
714
|
+
}
|
|
715
|
+
return acc;
|
|
716
|
+
}
|
|
717
|
+
reportDecodeError(ctx, input) {
|
|
718
|
+
const acc = [];
|
|
719
|
+
for (const v of this.schemas) {
|
|
720
|
+
const errors = v.reportDecodeError(ctx, input);
|
|
721
|
+
acc.push(...errors);
|
|
722
|
+
}
|
|
723
|
+
return acc;
|
|
724
|
+
}
|
|
725
|
+
hash(ctx) {
|
|
726
|
+
let acc = [allOfHash];
|
|
727
|
+
for (const s of this.schemas) {
|
|
728
|
+
acc.push(s.hash(ctx));
|
|
729
|
+
}
|
|
730
|
+
return generateHashFromNumbers(acc);
|
|
731
|
+
}
|
|
732
|
+
}
|
|
733
|
+
export class AnyOfRuntype {
|
|
734
|
+
schemas;
|
|
735
|
+
constructor(schemas) {
|
|
736
|
+
this.schemas = schemas;
|
|
737
|
+
}
|
|
738
|
+
schema(ctx) {
|
|
739
|
+
return {
|
|
740
|
+
anyOf: this.schemas.map((it) => it.schema(ctx)),
|
|
741
|
+
};
|
|
742
|
+
}
|
|
743
|
+
validate(ctx, input) {
|
|
744
|
+
for (const it of this.schemas) {
|
|
745
|
+
if (it.validate(ctx, input)) {
|
|
746
|
+
return true;
|
|
747
|
+
}
|
|
748
|
+
}
|
|
749
|
+
return false;
|
|
750
|
+
}
|
|
751
|
+
parseAfterValidation(ctx, input) {
|
|
752
|
+
const items = [];
|
|
753
|
+
for (const it of this.schemas) {
|
|
754
|
+
if (it.validate(ctx, input)) {
|
|
755
|
+
items.push(it.parseAfterValidation(ctx, input));
|
|
756
|
+
}
|
|
757
|
+
}
|
|
758
|
+
return deepmerge(...items);
|
|
759
|
+
}
|
|
760
|
+
reportDecodeError(ctx, input) {
|
|
761
|
+
const acc = [];
|
|
762
|
+
const oldPaths = ctx.path;
|
|
763
|
+
ctx.path = [];
|
|
764
|
+
for (const v of this.schemas) {
|
|
765
|
+
const errors = v.reportDecodeError(ctx, input);
|
|
766
|
+
acc.push(...errors);
|
|
767
|
+
}
|
|
768
|
+
ctx.path = oldPaths;
|
|
769
|
+
return buildUnionError(ctx, acc, input);
|
|
770
|
+
}
|
|
771
|
+
describe(ctx) {
|
|
772
|
+
return `(${this.schemas.map((it) => it.describe(ctx)).join(" | ")})`;
|
|
773
|
+
}
|
|
774
|
+
hash(ctx) {
|
|
775
|
+
let acc = [anyOfHash];
|
|
776
|
+
for (const s of this.schemas) {
|
|
777
|
+
acc.push(s.hash(ctx));
|
|
778
|
+
}
|
|
779
|
+
return generateHashFromNumbers(acc);
|
|
780
|
+
}
|
|
781
|
+
}
|
|
782
|
+
export class ArrayRuntype {
|
|
783
|
+
itemParser;
|
|
784
|
+
constructor(itemParser) {
|
|
785
|
+
this.itemParser = itemParser;
|
|
786
|
+
}
|
|
787
|
+
schema(ctx) {
|
|
788
|
+
pushPath(ctx, "[]");
|
|
789
|
+
const items = this.itemParser.schema(ctx);
|
|
790
|
+
popPath(ctx);
|
|
791
|
+
return {
|
|
792
|
+
type: "array",
|
|
793
|
+
items,
|
|
794
|
+
};
|
|
795
|
+
}
|
|
796
|
+
validate(ctx, input) {
|
|
797
|
+
if (Array.isArray(input)) {
|
|
798
|
+
for (let i = 0; i < input.length; i++) {
|
|
799
|
+
const v = input[i];
|
|
800
|
+
const ok = this.itemParser.validate(ctx, v);
|
|
801
|
+
if (!ok) {
|
|
802
|
+
return false;
|
|
803
|
+
}
|
|
804
|
+
}
|
|
805
|
+
return true;
|
|
806
|
+
}
|
|
807
|
+
return false;
|
|
808
|
+
}
|
|
809
|
+
parseAfterValidation(ctx, input) {
|
|
810
|
+
return input.map((v) => this.itemParser.parseAfterValidation(ctx, v));
|
|
811
|
+
}
|
|
812
|
+
reportDecodeError(ctx, input) {
|
|
813
|
+
if (!Array.isArray(input)) {
|
|
814
|
+
return buildError(ctx, "expected array", input);
|
|
815
|
+
}
|
|
816
|
+
let acc = [];
|
|
817
|
+
for (let i = 0; i < input.length; i++) {
|
|
818
|
+
const ok = this.itemParser.validate(ctx, input[i]);
|
|
819
|
+
if (!ok) {
|
|
820
|
+
pushPath(ctx, `[${i}]`);
|
|
821
|
+
const v = input[i];
|
|
822
|
+
const arr2 = this.itemParser.reportDecodeError(ctx, v);
|
|
823
|
+
acc.push(...arr2);
|
|
824
|
+
popPath(ctx);
|
|
825
|
+
}
|
|
826
|
+
}
|
|
827
|
+
return acc;
|
|
828
|
+
}
|
|
829
|
+
describe(ctx) {
|
|
830
|
+
return `Array<${this.itemParser.describe(ctx)}>`;
|
|
831
|
+
}
|
|
832
|
+
hash(ctx) {
|
|
833
|
+
return generateHashFromNumbers([arrayHash, this.itemParser.hash(ctx)]);
|
|
834
|
+
}
|
|
835
|
+
}
|
|
836
|
+
export class AnyOfDiscriminatedRuntype {
|
|
837
|
+
schemas;
|
|
838
|
+
discriminator;
|
|
839
|
+
mapping;
|
|
840
|
+
constructor(schemas, discriminator, mapping) {
|
|
841
|
+
this.schemas = schemas;
|
|
842
|
+
this.discriminator = discriminator;
|
|
843
|
+
this.mapping = mapping;
|
|
844
|
+
}
|
|
845
|
+
schema(ctx) {
|
|
846
|
+
return {
|
|
847
|
+
anyOf: this.schemas.map((it) => it.schema(ctx)),
|
|
848
|
+
};
|
|
849
|
+
}
|
|
850
|
+
validate(ctx, input) {
|
|
851
|
+
if (typeof input !== "object" || input == null) {
|
|
852
|
+
return false;
|
|
853
|
+
}
|
|
854
|
+
const d = input[this.discriminator];
|
|
855
|
+
if (d == null) {
|
|
856
|
+
return false;
|
|
857
|
+
}
|
|
858
|
+
const v = this.mapping[d];
|
|
859
|
+
if (v == null) {
|
|
860
|
+
return false;
|
|
861
|
+
}
|
|
862
|
+
return v.validate(ctx, input);
|
|
863
|
+
}
|
|
864
|
+
parseAfterValidation(ctx, input) {
|
|
865
|
+
const parser = this.mapping[input[this.discriminator]];
|
|
866
|
+
if (parser == null) {
|
|
867
|
+
throw new Error("INTERNAL ERROR: Missing parser for discriminator " + JSON.stringify(input[this.discriminator]));
|
|
868
|
+
}
|
|
869
|
+
return {
|
|
870
|
+
...parser.parseAfterValidation(ctx, input),
|
|
871
|
+
[this.discriminator]: input[this.discriminator],
|
|
872
|
+
};
|
|
873
|
+
}
|
|
874
|
+
reportDecodeError(ctx, input) {
|
|
875
|
+
if (input == null || typeof input !== "object") {
|
|
876
|
+
return buildError(ctx, "expected object", input);
|
|
877
|
+
}
|
|
878
|
+
const d = input[this.discriminator];
|
|
879
|
+
if (d == null) {
|
|
880
|
+
return buildError(ctx, "expected discriminator key " + JSON.stringify(this.discriminator), input);
|
|
881
|
+
}
|
|
882
|
+
const v = this.mapping[d];
|
|
883
|
+
if (v == null) {
|
|
884
|
+
pushPath(ctx, this.discriminator);
|
|
885
|
+
const errs = buildError(ctx, "expected one of " +
|
|
886
|
+
Object.keys(this.mapping)
|
|
887
|
+
.map((it) => JSON.stringify(it))
|
|
888
|
+
.join(", "), d);
|
|
889
|
+
popPath(ctx);
|
|
890
|
+
return errs;
|
|
891
|
+
}
|
|
892
|
+
return v.reportDecodeError(ctx, input);
|
|
893
|
+
}
|
|
894
|
+
describe(ctx) {
|
|
895
|
+
return `(${this.schemas.map((it) => it.describe(ctx)).join(" | ")})`;
|
|
896
|
+
}
|
|
897
|
+
hash(ctx) {
|
|
898
|
+
let acc = [anyOfHash];
|
|
899
|
+
for (const s of this.schemas) {
|
|
900
|
+
acc.push(s.hash(ctx));
|
|
901
|
+
}
|
|
902
|
+
return generateHashFromNumbers(acc);
|
|
903
|
+
}
|
|
904
|
+
}
|
|
905
|
+
export class OptionalFieldRuntype {
|
|
906
|
+
t;
|
|
907
|
+
constructor(t) {
|
|
908
|
+
this.t = t;
|
|
909
|
+
}
|
|
910
|
+
schema(ctx) {
|
|
911
|
+
const inner = this.t.schema(ctx);
|
|
912
|
+
return {
|
|
913
|
+
anyOf: [inner, { type: "null" }],
|
|
914
|
+
};
|
|
915
|
+
}
|
|
916
|
+
validate(ctx, input) {
|
|
917
|
+
if (input == null) {
|
|
918
|
+
return true;
|
|
919
|
+
}
|
|
920
|
+
return this.t.validate(ctx, input);
|
|
921
|
+
}
|
|
922
|
+
parseAfterValidation(ctx, input) {
|
|
923
|
+
if (input == null) {
|
|
924
|
+
return input;
|
|
925
|
+
}
|
|
926
|
+
return this.t.parseAfterValidation(ctx, input);
|
|
927
|
+
}
|
|
928
|
+
reportDecodeError(ctx, input) {
|
|
929
|
+
const acc = [];
|
|
930
|
+
acc.push(...buildError(ctx, "expected nullish value", input));
|
|
931
|
+
return [...acc, ...this.t.reportDecodeError(ctx, input)];
|
|
932
|
+
}
|
|
933
|
+
describe(ctx) {
|
|
934
|
+
return this.t.describe(ctx);
|
|
935
|
+
}
|
|
936
|
+
hash(ctx) {
|
|
937
|
+
let acc = [optionalFieldHash, this.t.hash(ctx)];
|
|
938
|
+
return generateHashFromNumbers(acc);
|
|
939
|
+
}
|
|
940
|
+
}
|
|
941
|
+
export class ObjectRuntype {
|
|
942
|
+
properties;
|
|
943
|
+
indexedPropertiesParser;
|
|
944
|
+
constructor(properties, indexedPropertiesParser) {
|
|
945
|
+
this.properties = properties;
|
|
946
|
+
this.indexedPropertiesParser = indexedPropertiesParser;
|
|
947
|
+
}
|
|
948
|
+
describe(ctx) {
|
|
949
|
+
const sortedKeys = Object.keys(this.properties).sort();
|
|
950
|
+
const props = sortedKeys
|
|
951
|
+
.map((k) => {
|
|
952
|
+
const it = this.properties[k];
|
|
953
|
+
const optionalMark = it instanceof OptionalFieldRuntype ? "?" : "";
|
|
954
|
+
return `${k}${optionalMark}: ${it.describe(ctx)}`;
|
|
955
|
+
})
|
|
956
|
+
.join(", ");
|
|
957
|
+
const indexPropsParats = this.indexedPropertiesParser.map(({ key, value }) => {
|
|
958
|
+
return `[K in ${key.describe(ctx)}]: ${value.describe(ctx)}`;
|
|
959
|
+
});
|
|
960
|
+
const rest = indexPropsParats.join(", ");
|
|
961
|
+
const content = [props, rest].filter((it) => it != null && it.length > 0).join(", ");
|
|
962
|
+
return `{ ${content} }`;
|
|
963
|
+
}
|
|
964
|
+
schema(ctx) {
|
|
965
|
+
const properties = {};
|
|
966
|
+
for (const k in this.properties) {
|
|
967
|
+
pushPath(ctx, k);
|
|
968
|
+
const item = this.properties[k];
|
|
969
|
+
properties[k] = item.schema(ctx);
|
|
970
|
+
popPath(ctx);
|
|
971
|
+
}
|
|
972
|
+
const required = Object.keys(this.properties);
|
|
973
|
+
const base = {
|
|
974
|
+
type: "object",
|
|
975
|
+
properties,
|
|
976
|
+
required,
|
|
977
|
+
};
|
|
978
|
+
const indexSchemas = this.indexedPropertiesParser.map(({ key, value }) => {
|
|
979
|
+
pushPath(ctx, "[key]");
|
|
980
|
+
const keySchema = key.schema(ctx);
|
|
981
|
+
popPath(ctx);
|
|
982
|
+
pushPath(ctx, "[value]");
|
|
983
|
+
const valueSchema = value.schema(ctx);
|
|
984
|
+
popPath(ctx);
|
|
985
|
+
return {
|
|
986
|
+
type: "object",
|
|
987
|
+
additionalProperties: valueSchema,
|
|
988
|
+
propertyNames: keySchema,
|
|
989
|
+
};
|
|
990
|
+
});
|
|
991
|
+
if (indexSchemas.length === 0) {
|
|
992
|
+
return { ...base, additionalProperties: false };
|
|
993
|
+
}
|
|
994
|
+
return {
|
|
995
|
+
allOf: [base, ...indexSchemas],
|
|
996
|
+
};
|
|
997
|
+
}
|
|
998
|
+
validate(ctx, input) {
|
|
999
|
+
if (typeof input === "object" && !Array.isArray(input) && input !== null) {
|
|
1000
|
+
const configKeys = Object.keys(this.properties);
|
|
1001
|
+
for (const k of configKeys) {
|
|
1002
|
+
const validator = this.properties[k];
|
|
1003
|
+
if (!validator.validate(ctx, input[k])) {
|
|
1004
|
+
return false;
|
|
1005
|
+
}
|
|
1006
|
+
}
|
|
1007
|
+
if (this.indexedPropertiesParser.length > 0) {
|
|
1008
|
+
const inputKeys = Object.keys(input);
|
|
1009
|
+
const extraKeys = inputKeys.filter((k) => !configKeys.includes(k));
|
|
1010
|
+
for (const k of extraKeys) {
|
|
1011
|
+
let isValid = false;
|
|
1012
|
+
for (const p of this.indexedPropertiesParser) {
|
|
1013
|
+
if (!p.key.validate(ctx, k)) {
|
|
1014
|
+
continue;
|
|
1015
|
+
}
|
|
1016
|
+
const v = input[k];
|
|
1017
|
+
if (!p.value.validate(ctx, v)) {
|
|
1018
|
+
continue;
|
|
1019
|
+
}
|
|
1020
|
+
isValid = true;
|
|
1021
|
+
break;
|
|
1022
|
+
}
|
|
1023
|
+
if (!isValid) {
|
|
1024
|
+
return false;
|
|
1025
|
+
}
|
|
1026
|
+
}
|
|
1027
|
+
}
|
|
1028
|
+
else {
|
|
1029
|
+
if (ctx.disallowExtraProperties) {
|
|
1030
|
+
const inputKeys = Object.keys(input);
|
|
1031
|
+
const extraKeys = inputKeys.filter((k) => !configKeys.includes(k));
|
|
1032
|
+
if (extraKeys.length > 0) {
|
|
1033
|
+
return false;
|
|
1034
|
+
}
|
|
1035
|
+
}
|
|
1036
|
+
}
|
|
1037
|
+
return true;
|
|
1038
|
+
}
|
|
1039
|
+
return false;
|
|
1040
|
+
}
|
|
1041
|
+
parseAfterValidation(ctx, input) {
|
|
1042
|
+
let acc = {};
|
|
1043
|
+
const inputKeys = Object.keys(input);
|
|
1044
|
+
for (const k of inputKeys) {
|
|
1045
|
+
const v = input[k];
|
|
1046
|
+
if (k in this.properties) {
|
|
1047
|
+
const itemParsed = this.properties[k].parseAfterValidation(ctx, v);
|
|
1048
|
+
acc[k] = itemParsed;
|
|
1049
|
+
}
|
|
1050
|
+
else if (this.indexedPropertiesParser.length > 0) {
|
|
1051
|
+
for (const p of this.indexedPropertiesParser) {
|
|
1052
|
+
const isValid = p.key.validate(ctx, k) && p.value.validate(ctx, v);
|
|
1053
|
+
if (isValid) {
|
|
1054
|
+
const itemParsed = p.value.parseAfterValidation(ctx, v);
|
|
1055
|
+
const keyParsed = p.key.parseAfterValidation(ctx, k);
|
|
1056
|
+
acc[keyParsed] = itemParsed;
|
|
1057
|
+
}
|
|
1058
|
+
}
|
|
1059
|
+
}
|
|
1060
|
+
}
|
|
1061
|
+
return acc;
|
|
1062
|
+
}
|
|
1063
|
+
reportDecodeError(ctx, input) {
|
|
1064
|
+
if (typeof input !== "object" || Array.isArray(input) || input === null) {
|
|
1065
|
+
return buildError(ctx, "expected object", input);
|
|
1066
|
+
}
|
|
1067
|
+
let acc = [];
|
|
1068
|
+
const configKeys = Object.keys(this.properties);
|
|
1069
|
+
for (const k of configKeys) {
|
|
1070
|
+
const ok = this.properties[k].validate(ctx, input[k]);
|
|
1071
|
+
if (!ok) {
|
|
1072
|
+
pushPath(ctx, k);
|
|
1073
|
+
const arr2 = this.properties[k].reportDecodeError(ctx, input[k]);
|
|
1074
|
+
acc.push(...arr2);
|
|
1075
|
+
popPath(ctx);
|
|
1076
|
+
}
|
|
1077
|
+
}
|
|
1078
|
+
if (this.indexedPropertiesParser.length > 0) {
|
|
1079
|
+
const inputKeys = Object.keys(input);
|
|
1080
|
+
const extraKeys = inputKeys.filter((k) => !configKeys.includes(k));
|
|
1081
|
+
for (const k of extraKeys) {
|
|
1082
|
+
for (const p of this.indexedPropertiesParser) {
|
|
1083
|
+
const keyOk = p.key.validate(ctx, k);
|
|
1084
|
+
const valueOk = p.value.validate(ctx, input[k]);
|
|
1085
|
+
const ok = keyOk && valueOk;
|
|
1086
|
+
if (!ok) {
|
|
1087
|
+
pushPath(ctx, k);
|
|
1088
|
+
if (!keyOk) {
|
|
1089
|
+
const keyReported = p.key.reportDecodeError(ctx, k);
|
|
1090
|
+
acc.push(...keyReported);
|
|
1091
|
+
}
|
|
1092
|
+
if (!valueOk) {
|
|
1093
|
+
const valueReported = p.value.reportDecodeError(ctx, input[k]);
|
|
1094
|
+
acc.push(...valueReported);
|
|
1095
|
+
}
|
|
1096
|
+
popPath(ctx);
|
|
1097
|
+
}
|
|
1098
|
+
}
|
|
1099
|
+
}
|
|
1100
|
+
}
|
|
1101
|
+
else {
|
|
1102
|
+
if (ctx.disallowExtraProperties) {
|
|
1103
|
+
const inputKeys = Object.keys(input);
|
|
1104
|
+
const extraKeys = inputKeys.filter((k) => !configKeys.includes(k));
|
|
1105
|
+
if (extraKeys.length > 0) {
|
|
1106
|
+
return extraKeys
|
|
1107
|
+
.map((k) => {
|
|
1108
|
+
pushPath(ctx, k);
|
|
1109
|
+
const err = buildError(ctx, `extra property`, input[k]);
|
|
1110
|
+
popPath(ctx);
|
|
1111
|
+
return err;
|
|
1112
|
+
})
|
|
1113
|
+
.reduce((a, b) => a.concat(b), []);
|
|
1114
|
+
}
|
|
1115
|
+
}
|
|
1116
|
+
}
|
|
1117
|
+
return acc;
|
|
1118
|
+
}
|
|
1119
|
+
hash(ctx) {
|
|
1120
|
+
let acc = [objectHash];
|
|
1121
|
+
for (const key of Object.keys(this.properties).sort()) {
|
|
1122
|
+
acc.push(generateHashFromString(key));
|
|
1123
|
+
const parser = this.properties[key];
|
|
1124
|
+
acc.push(parser.hash(ctx));
|
|
1125
|
+
}
|
|
1126
|
+
if (this.indexedPropertiesParser.length > 0) {
|
|
1127
|
+
for (const p of this.indexedPropertiesParser) {
|
|
1128
|
+
acc.push(p.key.hash(ctx));
|
|
1129
|
+
acc.push(p.value.hash(ctx));
|
|
1130
|
+
}
|
|
1131
|
+
}
|
|
1132
|
+
return generateHashFromNumbers(acc);
|
|
1133
|
+
}
|
|
1134
|
+
}
|
|
1135
|
+
export const buildParserFromRuntype = (runtype, name, isB) => {
|
|
1136
|
+
const validate = ((input, options) => {
|
|
1137
|
+
const disallowExtraProperties = options?.disallowExtraProperties ?? false;
|
|
1138
|
+
const ctx = { disallowExtraProperties };
|
|
1139
|
+
const ok = runtype.validate(ctx, input);
|
|
1140
|
+
if (typeof ok !== "boolean") {
|
|
1141
|
+
throw new Error("INTERNAL ERROR: Expected boolean");
|
|
1142
|
+
}
|
|
1143
|
+
return ok;
|
|
1144
|
+
});
|
|
1145
|
+
const schema = () => {
|
|
1146
|
+
const ctx = {
|
|
1147
|
+
path: [],
|
|
1148
|
+
seen: {},
|
|
1149
|
+
};
|
|
1150
|
+
return runtype.schema(ctx);
|
|
1151
|
+
};
|
|
1152
|
+
const hash = () => {
|
|
1153
|
+
const ctx = {
|
|
1154
|
+
seen: {},
|
|
1155
|
+
};
|
|
1156
|
+
return runtype.hash(ctx);
|
|
1157
|
+
};
|
|
1158
|
+
const describe = () => {
|
|
1159
|
+
const ctx = {
|
|
1160
|
+
deps: {},
|
|
1161
|
+
deps_counter: {},
|
|
1162
|
+
measure: true,
|
|
1163
|
+
};
|
|
1164
|
+
let out = runtype.describe(ctx);
|
|
1165
|
+
ctx["deps"] = {};
|
|
1166
|
+
ctx["measure"] = false;
|
|
1167
|
+
out = runtype.describe(ctx);
|
|
1168
|
+
let sortedDepsKeys = Object.keys(ctx.deps).sort();
|
|
1169
|
+
// if sorted deps includes k, make it last
|
|
1170
|
+
// if (sortedDepsKeys.includes(k)) {
|
|
1171
|
+
// sortedDepsKeys = sortedDepsKeys.filter(it => it !== k).concat([k]);
|
|
1172
|
+
// }
|
|
1173
|
+
const depsPart = sortedDepsKeys
|
|
1174
|
+
.map((key) => {
|
|
1175
|
+
return `type ${key} = ${ctx.deps[key]};`;
|
|
1176
|
+
})
|
|
1177
|
+
.join("\n\n");
|
|
1178
|
+
if (isB) {
|
|
1179
|
+
return [depsPart, out].filter((it) => it != null && it.length > 0).join("\n\n");
|
|
1180
|
+
}
|
|
1181
|
+
// if (k in ctx.deps) {
|
|
1182
|
+
// return depsPart;
|
|
1183
|
+
// }
|
|
1184
|
+
const outPart = `type Codec${name} = ${out};`;
|
|
1185
|
+
return [depsPart, outPart].filter((it) => it != null && it.length > 0).join("\n\n");
|
|
1186
|
+
};
|
|
1187
|
+
const safeParse = (input, options) => {
|
|
1188
|
+
const disallowExtraProperties = options?.disallowExtraProperties ?? false;
|
|
1189
|
+
const ok = validate(input, options);
|
|
1190
|
+
if (ok) {
|
|
1191
|
+
let ctx = { disallowExtraProperties };
|
|
1192
|
+
const parsed = runtype.parseAfterValidation(ctx, input);
|
|
1193
|
+
return { success: true, data: parsed };
|
|
1194
|
+
}
|
|
1195
|
+
let ctx = { path: [], disallowExtraProperties };
|
|
1196
|
+
return {
|
|
1197
|
+
success: false,
|
|
1198
|
+
errors: runtype.reportDecodeError(ctx, input).slice(0, 10),
|
|
1199
|
+
};
|
|
1200
|
+
};
|
|
1201
|
+
const parse = (input, options) => {
|
|
1202
|
+
const safe = safeParse(input, options);
|
|
1203
|
+
if (safe.success) {
|
|
1204
|
+
return safe.data;
|
|
1205
|
+
}
|
|
1206
|
+
const explained = printErrors(safe.errors, []);
|
|
1207
|
+
throw new Error(`Failed to parse ${name} - ${explained}`);
|
|
1208
|
+
};
|
|
1209
|
+
const zod = () => {
|
|
1210
|
+
//@ts-ignore
|
|
1211
|
+
return z.custom((data) => validate(data),
|
|
1212
|
+
//@ts-ignore
|
|
1213
|
+
(val) => {
|
|
1214
|
+
const errors = runtype.reportDecodeError({ path: [], disallowExtraProperties: false }, val);
|
|
1215
|
+
return printErrors(errors, []);
|
|
1216
|
+
});
|
|
1217
|
+
};
|
|
1218
|
+
const it = {
|
|
1219
|
+
validate,
|
|
1220
|
+
schema,
|
|
1221
|
+
describe,
|
|
1222
|
+
safeParse,
|
|
1223
|
+
parse,
|
|
1224
|
+
zod,
|
|
1225
|
+
name: name,
|
|
1226
|
+
hash,
|
|
1227
|
+
_runtype: runtype,
|
|
1228
|
+
};
|
|
1229
|
+
return it;
|
|
1230
|
+
};
|