@sinclair/typebox 0.26.0-dev.4 → 0.26.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/compiler/compiler.d.ts +9 -4
- package/compiler/compiler.js +135 -108
- package/errors/errors.d.ts +5 -1
- package/errors/errors.js +173 -157
- package/package.json +1 -1
- package/readme.md +114 -101
- package/system/system.d.ts +4 -0
- package/system/system.js +15 -2
- package/typebox.d.ts +27 -36
- package/typebox.js +108 -173
- package/value/cast.d.ts +6 -2
- package/value/cast.js +130 -111
- package/value/check.d.ts +5 -1
- package/value/check.js +168 -154
- package/value/convert.d.ts +6 -6
- package/value/convert.js +83 -74
- package/value/create.d.ts +6 -2
- package/value/create.js +102 -77
- package/value/value.d.ts +10 -0
- package/value/value.js +15 -15
package/compiler/compiler.d.ts
CHANGED
|
@@ -3,9 +3,10 @@ import { ValueErrorIterator } from '../errors/index';
|
|
|
3
3
|
export type CheckFunction = (value: unknown) => boolean;
|
|
4
4
|
export declare class TypeCheck<T extends Types.TSchema> {
|
|
5
5
|
private readonly schema;
|
|
6
|
+
private readonly references;
|
|
6
7
|
private readonly checkFunc;
|
|
7
8
|
private readonly code;
|
|
8
|
-
constructor(schema: T, checkFunc: CheckFunction, code: string);
|
|
9
|
+
constructor(schema: T, references: Types.TSchema[], checkFunc: CheckFunction, code: string);
|
|
9
10
|
/** Returns the generated assertion code used to validate this type. */
|
|
10
11
|
Code(): string;
|
|
11
12
|
/** Returns an iterator for each error in this value. */
|
|
@@ -20,14 +21,18 @@ export declare class TypeCompilerUnknownTypeError extends Error {
|
|
|
20
21
|
readonly schema: Types.TSchema;
|
|
21
22
|
constructor(schema: Types.TSchema);
|
|
22
23
|
}
|
|
23
|
-
export declare class
|
|
24
|
+
export declare class TypeCompilerDereferenceError extends Error {
|
|
25
|
+
readonly schema: Types.TRef;
|
|
26
|
+
constructor(schema: Types.TRef);
|
|
27
|
+
}
|
|
28
|
+
export declare class TypeCompilerTypeGuardError extends Error {
|
|
24
29
|
readonly schema: Types.TSchema;
|
|
25
30
|
constructor(schema: Types.TSchema);
|
|
26
31
|
}
|
|
27
32
|
/** Compiles Types for Runtime Type Checking */
|
|
28
33
|
export declare namespace TypeCompiler {
|
|
29
34
|
/** Returns the generated assertion code used to validate this type. */
|
|
30
|
-
function Code<T extends Types.TSchema>(schema: T): string;
|
|
35
|
+
function Code<T extends Types.TSchema>(schema: T, references?: Types.TSchema[]): string;
|
|
31
36
|
/** Compiles the given type for runtime type checking. This compiler only accepts known TypeBox types non-inclusive of unsafe types. */
|
|
32
|
-
function Compile<T extends Types.TSchema>(schema: T): TypeCheck<T>;
|
|
37
|
+
function Compile<T extends Types.TSchema>(schema: T, references?: Types.TSchema[]): TypeCheck<T>;
|
|
33
38
|
}
|
package/compiler/compiler.js
CHANGED
|
@@ -27,7 +27,7 @@ THE SOFTWARE.
|
|
|
27
27
|
|
|
28
28
|
---------------------------------------------------------------------------*/
|
|
29
29
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
30
|
-
exports.TypeCompiler = exports.
|
|
30
|
+
exports.TypeCompiler = exports.TypeCompilerTypeGuardError = exports.TypeCompilerDereferenceError = exports.TypeCompilerUnknownTypeError = exports.MemberExpression = exports.TypeCheck = void 0;
|
|
31
31
|
const Types = require("../typebox");
|
|
32
32
|
const index_1 = require("../errors/index");
|
|
33
33
|
const index_2 = require("../system/index");
|
|
@@ -36,8 +36,9 @@ const hash_1 = require("../value/hash");
|
|
|
36
36
|
// TypeCheck
|
|
37
37
|
// -------------------------------------------------------------------
|
|
38
38
|
class TypeCheck {
|
|
39
|
-
constructor(schema, checkFunc, code) {
|
|
39
|
+
constructor(schema, references, checkFunc, code) {
|
|
40
40
|
this.schema = schema;
|
|
41
|
+
this.references = references;
|
|
41
42
|
this.checkFunc = checkFunc;
|
|
42
43
|
this.code = code;
|
|
43
44
|
}
|
|
@@ -47,7 +48,7 @@ class TypeCheck {
|
|
|
47
48
|
}
|
|
48
49
|
/** Returns an iterator for each error in this value. */
|
|
49
50
|
Errors(value) {
|
|
50
|
-
return index_1.ValueErrors.Errors(this.schema, value);
|
|
51
|
+
return index_1.ValueErrors.Errors(this.schema, this.references, value);
|
|
51
52
|
}
|
|
52
53
|
/** Returns true if the value matches the compiled type. */
|
|
53
54
|
Check(value) {
|
|
@@ -134,13 +135,20 @@ class TypeCompilerUnknownTypeError extends Error {
|
|
|
134
135
|
}
|
|
135
136
|
}
|
|
136
137
|
exports.TypeCompilerUnknownTypeError = TypeCompilerUnknownTypeError;
|
|
137
|
-
class
|
|
138
|
+
class TypeCompilerDereferenceError extends Error {
|
|
138
139
|
constructor(schema) {
|
|
139
|
-
super(
|
|
140
|
+
super(`TypeCompiler: Unable to dereference schema with $id '${schema.$ref}'`);
|
|
140
141
|
this.schema = schema;
|
|
141
142
|
}
|
|
142
143
|
}
|
|
143
|
-
exports.
|
|
144
|
+
exports.TypeCompilerDereferenceError = TypeCompilerDereferenceError;
|
|
145
|
+
class TypeCompilerTypeGuardError extends Error {
|
|
146
|
+
constructor(schema) {
|
|
147
|
+
super('TypeCompiler: Preflight validation check failed to guard for the given schema');
|
|
148
|
+
this.schema = schema;
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
exports.TypeCompilerTypeGuardError = TypeCompilerTypeGuardError;
|
|
144
152
|
/** Compiles Types for Runtime Type Checking */
|
|
145
153
|
var TypeCompiler;
|
|
146
154
|
(function (TypeCompiler) {
|
|
@@ -153,14 +161,34 @@ var TypeCompiler;
|
|
|
153
161
|
function IsNumber(value) {
|
|
154
162
|
return typeof value === 'number' && globalThis.Number.isFinite(value);
|
|
155
163
|
}
|
|
164
|
+
function IsString(value) {
|
|
165
|
+
return typeof value === 'string';
|
|
166
|
+
}
|
|
167
|
+
// -------------------------------------------------------------------
|
|
168
|
+
// Overrides
|
|
169
|
+
// -------------------------------------------------------------------
|
|
170
|
+
function IsNumberCheck(value) {
|
|
171
|
+
return !index_2.TypeSystem.AllowNaN ? `(typeof ${value} === 'number' && Number.isFinite(${value}))` : `typeof ${value} === 'number'`;
|
|
172
|
+
}
|
|
173
|
+
function IsObjectCheck(value) {
|
|
174
|
+
return !index_2.TypeSystem.AllowArrayObjects ? `(typeof ${value} === 'object' && ${value} !== null && !Array.isArray(${value}))` : `(typeof ${value} === 'object' && ${value} !== null)`;
|
|
175
|
+
}
|
|
176
|
+
function IsRecordCheck(value) {
|
|
177
|
+
return !index_2.TypeSystem.AllowArrayObjects
|
|
178
|
+
? `(typeof ${value} === 'object' && ${value} !== null && !Array.isArray(${value}) && !(${value} instanceof Date) && !(${value} instanceof Uint8Array))`
|
|
179
|
+
: `(typeof ${value} === 'object' && ${value} !== null && !(${value} instanceof Date) && !(${value} instanceof Uint8Array))`;
|
|
180
|
+
}
|
|
181
|
+
function IsVoidCheck(value) {
|
|
182
|
+
return index_2.TypeSystem.AllowVoidNull ? `(${value} === undefined || ${value} === null)` : `${value} === undefined`;
|
|
183
|
+
}
|
|
156
184
|
// -------------------------------------------------------------------
|
|
157
185
|
// Types
|
|
158
186
|
// -------------------------------------------------------------------
|
|
159
|
-
function* Any(schema, value) {
|
|
187
|
+
function* Any(schema, references, value) {
|
|
160
188
|
yield 'true';
|
|
161
189
|
}
|
|
162
|
-
function* Array(schema, value) {
|
|
163
|
-
const expression = CreateExpression(schema.items, 'value');
|
|
190
|
+
function* Array(schema, references, value) {
|
|
191
|
+
const expression = CreateExpression(schema.items, references, 'value');
|
|
164
192
|
yield `Array.isArray(${value}) && ${value}.every(value => ${expression})`;
|
|
165
193
|
if (IsNumber(schema.minItems))
|
|
166
194
|
yield `${value}.length >= ${schema.minItems}`;
|
|
@@ -169,7 +197,7 @@ var TypeCompiler;
|
|
|
169
197
|
if (schema.uniqueItems === true)
|
|
170
198
|
yield `((function() { const set = new Set(); for(const element of ${value}) { const hashed = hash(element); if(set.has(hashed)) { return false } else { set.add(hashed) } } return true })())`;
|
|
171
199
|
}
|
|
172
|
-
function* BigInt(schema, value) {
|
|
200
|
+
function* BigInt(schema, references, value) {
|
|
173
201
|
yield `(typeof ${value} === 'bigint')`;
|
|
174
202
|
if (IsBigInt(schema.multipleOf))
|
|
175
203
|
yield `(${value} % BigInt(${schema.multipleOf})) === 0`;
|
|
@@ -182,13 +210,13 @@ var TypeCompiler;
|
|
|
182
210
|
if (IsBigInt(schema.maximum))
|
|
183
211
|
yield `${value} <= BigInt(${schema.maximum})`;
|
|
184
212
|
}
|
|
185
|
-
function* Boolean(schema, value) {
|
|
213
|
+
function* Boolean(schema, references, value) {
|
|
186
214
|
yield `typeof ${value} === 'boolean'`;
|
|
187
215
|
}
|
|
188
|
-
function* Constructor(schema, value) {
|
|
189
|
-
yield* Visit(schema.returns, `${value}.prototype`);
|
|
216
|
+
function* Constructor(schema, references, value) {
|
|
217
|
+
yield* Visit(schema.returns, references, `${value}.prototype`);
|
|
190
218
|
}
|
|
191
|
-
function* Date(schema, value) {
|
|
219
|
+
function* Date(schema, references, value) {
|
|
192
220
|
yield `(${value} instanceof Date) && Number.isFinite(${value}.getTime())`;
|
|
193
221
|
if (IsNumber(schema.exclusiveMinimumTimestamp))
|
|
194
222
|
yield `${value}.getTime() > ${schema.exclusiveMinimumTimestamp}`;
|
|
@@ -199,10 +227,10 @@ var TypeCompiler;
|
|
|
199
227
|
if (IsNumber(schema.maximumTimestamp))
|
|
200
228
|
yield `${value}.getTime() <= ${schema.maximumTimestamp}`;
|
|
201
229
|
}
|
|
202
|
-
function* Function(schema, value) {
|
|
230
|
+
function* Function(schema, references, value) {
|
|
203
231
|
yield `typeof ${value} === 'function'`;
|
|
204
232
|
}
|
|
205
|
-
function* Integer(schema, value) {
|
|
233
|
+
function* Integer(schema, references, value) {
|
|
206
234
|
yield `(typeof ${value} === 'number' && Number.isInteger(${value}))`;
|
|
207
235
|
if (IsNumber(schema.multipleOf))
|
|
208
236
|
yield `(${value} % ${schema.multipleOf}) === 0`;
|
|
@@ -215,28 +243,28 @@ var TypeCompiler;
|
|
|
215
243
|
if (IsNumber(schema.maximum))
|
|
216
244
|
yield `${value} <= ${schema.maximum}`;
|
|
217
245
|
}
|
|
218
|
-
function* Intersect(schema, value) {
|
|
246
|
+
function* Intersect(schema, references, value) {
|
|
219
247
|
if (schema.unevaluatedProperties === undefined) {
|
|
220
|
-
const expressions = schema.allOf.map((schema) => CreateExpression(schema, value));
|
|
248
|
+
const expressions = schema.allOf.map((schema) => CreateExpression(schema, references, value));
|
|
221
249
|
yield `${expressions.join(' && ')}`;
|
|
222
250
|
}
|
|
223
251
|
else if (schema.unevaluatedProperties === false) {
|
|
224
252
|
// prettier-ignore
|
|
225
253
|
const schemaKeys = Types.KeyResolver.Resolve(schema).map((key) => `'${key}'`).join(', ');
|
|
226
|
-
const expressions = schema.allOf.map((schema) => CreateExpression(schema, value));
|
|
254
|
+
const expressions = schema.allOf.map((schema) => CreateExpression(schema, references, value));
|
|
227
255
|
const expression1 = `Object.getOwnPropertyNames(${value}).every(key => [${schemaKeys}].includes(key))`;
|
|
228
256
|
yield `${expressions.join(' && ')} && ${expression1}`;
|
|
229
257
|
}
|
|
230
258
|
else if (typeof schema.unevaluatedProperties === 'object') {
|
|
231
259
|
// prettier-ignore
|
|
232
260
|
const schemaKeys = Types.KeyResolver.Resolve(schema).map((key) => `'${key}'`).join(', ');
|
|
233
|
-
const expressions = schema.allOf.map((schema) => CreateExpression(schema, value));
|
|
234
|
-
const expression1 = CreateExpression(schema.unevaluatedProperties, 'value[key]');
|
|
261
|
+
const expressions = schema.allOf.map((schema) => CreateExpression(schema, references, value));
|
|
262
|
+
const expression1 = CreateExpression(schema.unevaluatedProperties, references, 'value[key]');
|
|
235
263
|
const expression2 = `Object.getOwnPropertyNames(${value}).every(key => [${schemaKeys}].includes(key) || ${expression1})`;
|
|
236
264
|
yield `${expressions.join(' && ')} && ${expression2}`;
|
|
237
265
|
}
|
|
238
266
|
}
|
|
239
|
-
function* Literal(schema, value) {
|
|
267
|
+
function* Literal(schema, references, value) {
|
|
240
268
|
if (typeof schema.const === 'number' || typeof schema.const === 'boolean') {
|
|
241
269
|
yield `${value} === ${schema.const}`;
|
|
242
270
|
}
|
|
@@ -244,21 +272,19 @@ var TypeCompiler;
|
|
|
244
272
|
yield `${value} === '${schema.const}'`;
|
|
245
273
|
}
|
|
246
274
|
}
|
|
247
|
-
function* Never(schema, value) {
|
|
275
|
+
function* Never(schema, references, value) {
|
|
248
276
|
yield `false`;
|
|
249
277
|
}
|
|
250
|
-
function* Not(schema, value) {
|
|
251
|
-
const left = CreateExpression(schema.allOf[0].not, value);
|
|
252
|
-
const right = CreateExpression(schema.allOf[1], value);
|
|
278
|
+
function* Not(schema, references, value) {
|
|
279
|
+
const left = CreateExpression(schema.allOf[0].not, references, value);
|
|
280
|
+
const right = CreateExpression(schema.allOf[1], references, value);
|
|
253
281
|
yield `!${left} && ${right}`;
|
|
254
282
|
}
|
|
255
|
-
function* Null(schema, value) {
|
|
283
|
+
function* Null(schema, references, value) {
|
|
256
284
|
yield `${value} === null`;
|
|
257
285
|
}
|
|
258
|
-
function* Number(schema, value) {
|
|
259
|
-
yield
|
|
260
|
-
if (!index_2.TypeSystem.AllowNaN)
|
|
261
|
-
yield `Number.isFinite(${value})`;
|
|
286
|
+
function* Number(schema, references, value) {
|
|
287
|
+
yield IsNumberCheck(value);
|
|
262
288
|
if (IsNumber(schema.multipleOf))
|
|
263
289
|
yield `(${value} % ${schema.multipleOf}) === 0`;
|
|
264
290
|
if (IsNumber(schema.exclusiveMinimum))
|
|
@@ -270,8 +296,8 @@ var TypeCompiler;
|
|
|
270
296
|
if (IsNumber(schema.maximum))
|
|
271
297
|
yield `${value} <= ${schema.maximum}`;
|
|
272
298
|
}
|
|
273
|
-
function* Object(schema, value) {
|
|
274
|
-
yield
|
|
299
|
+
function* Object(schema, references, value) {
|
|
300
|
+
yield IsObjectCheck(value);
|
|
275
301
|
if (!index_2.TypeSystem.AllowArrayObjects)
|
|
276
302
|
yield `!Array.isArray(${value})`;
|
|
277
303
|
if (IsNumber(schema.minProperties))
|
|
@@ -283,12 +309,12 @@ var TypeCompiler;
|
|
|
283
309
|
const memberExpression = MemberExpression.Encode(value, schemaKey);
|
|
284
310
|
const property = schema.properties[schemaKey];
|
|
285
311
|
if (schema.required && schema.required.includes(schemaKey)) {
|
|
286
|
-
yield* Visit(property, memberExpression);
|
|
312
|
+
yield* Visit(property, references, memberExpression);
|
|
287
313
|
if (Types.ExtendsUndefined.Check(property))
|
|
288
314
|
yield `('${schemaKey}' in ${value})`;
|
|
289
315
|
}
|
|
290
316
|
else {
|
|
291
|
-
const expression = CreateExpression(property, memberExpression);
|
|
317
|
+
const expression = CreateExpression(property, references, memberExpression);
|
|
292
318
|
yield `('${schemaKey}' in ${value} ? ${expression} : true)`;
|
|
293
319
|
}
|
|
294
320
|
}
|
|
@@ -302,37 +328,39 @@ var TypeCompiler;
|
|
|
302
328
|
}
|
|
303
329
|
}
|
|
304
330
|
if (typeof schema.additionalProperties === 'object') {
|
|
305
|
-
const expression = CreateExpression(schema.additionalProperties, 'value[key]');
|
|
331
|
+
const expression = CreateExpression(schema.additionalProperties, references, 'value[key]');
|
|
306
332
|
const keys = `[${schemaKeys.map((key) => `'${key}'`).join(', ')}]`;
|
|
307
333
|
yield `(Object.getOwnPropertyNames(${value}).every(key => ${keys}.includes(key) || ${expression}))`;
|
|
308
334
|
}
|
|
309
335
|
}
|
|
310
|
-
function* Promise(schema, value) {
|
|
336
|
+
function* Promise(schema, references, value) {
|
|
311
337
|
yield `(typeof value === 'object' && typeof ${value}.then === 'function')`;
|
|
312
338
|
}
|
|
313
|
-
function* Record(schema, value) {
|
|
314
|
-
yield
|
|
315
|
-
if (!index_2.TypeSystem.AllowArrayObjects)
|
|
316
|
-
yield `!Array.isArray(${value})`;
|
|
339
|
+
function* Record(schema, references, value) {
|
|
340
|
+
yield IsRecordCheck(value);
|
|
317
341
|
const [keyPattern, valueSchema] = globalThis.Object.entries(schema.patternProperties)[0];
|
|
318
342
|
const local = PushLocal(`new RegExp(/${keyPattern}/)`);
|
|
319
343
|
yield `(Object.getOwnPropertyNames(${value}).every(key => ${local}.test(key)))`;
|
|
320
|
-
const expression = CreateExpression(valueSchema, 'value');
|
|
344
|
+
const expression = CreateExpression(valueSchema, references, 'value');
|
|
321
345
|
yield `Object.values(${value}).every(value => ${expression})`;
|
|
322
346
|
}
|
|
323
|
-
function* Ref(schema, value) {
|
|
347
|
+
function* Ref(schema, references, value) {
|
|
348
|
+
const index = references.findIndex((foreign) => foreign.$id === schema.$ref);
|
|
349
|
+
if (index === -1)
|
|
350
|
+
throw new TypeCompilerDereferenceError(schema);
|
|
351
|
+
const target = references[index];
|
|
324
352
|
// Reference: If we have seen this reference before we can just yield and return
|
|
325
353
|
// the function call. If this isn't the case we defer to visit to generate and
|
|
326
354
|
// set the function for subsequent passes. Consider for refactor.
|
|
327
355
|
if (state_local_function_names.has(schema.$ref))
|
|
328
356
|
return yield `${CreateFunctionName(schema.$ref)}(${value})`;
|
|
329
|
-
yield* Visit(
|
|
357
|
+
yield* Visit(target, references, value);
|
|
330
358
|
}
|
|
331
|
-
function* Self(schema, value) {
|
|
359
|
+
function* Self(schema, references, value) {
|
|
332
360
|
const func = CreateFunctionName(schema.$ref);
|
|
333
361
|
yield `${func}(${value})`;
|
|
334
362
|
}
|
|
335
|
-
function* String(schema, value) {
|
|
363
|
+
function* String(schema, references, value) {
|
|
336
364
|
yield `(typeof ${value} === 'string')`;
|
|
337
365
|
if (IsNumber(schema.minLength))
|
|
338
366
|
yield `${value}.length >= ${schema.minLength}`;
|
|
@@ -346,121 +374,117 @@ var TypeCompiler;
|
|
|
346
374
|
yield `format('${schema.format}', ${value})`;
|
|
347
375
|
}
|
|
348
376
|
}
|
|
349
|
-
function* Symbol(schema, value) {
|
|
377
|
+
function* Symbol(schema, references, value) {
|
|
350
378
|
yield `(typeof ${value} === 'symbol')`;
|
|
351
379
|
}
|
|
352
|
-
function* Tuple(schema, value) {
|
|
380
|
+
function* Tuple(schema, references, value) {
|
|
353
381
|
yield `(Array.isArray(${value}))`;
|
|
354
382
|
if (schema.items === undefined)
|
|
355
383
|
return yield `${value}.length === 0`;
|
|
356
384
|
yield `(${value}.length === ${schema.maxItems})`;
|
|
357
385
|
for (let i = 0; i < schema.items.length; i++) {
|
|
358
|
-
const expression = CreateExpression(schema.items[i], `${value}[${i}]`);
|
|
386
|
+
const expression = CreateExpression(schema.items[i], references, `${value}[${i}]`);
|
|
359
387
|
yield `${expression}`;
|
|
360
388
|
}
|
|
361
389
|
}
|
|
362
|
-
function* Undefined(schema, value) {
|
|
390
|
+
function* Undefined(schema, references, value) {
|
|
363
391
|
yield `${value} === undefined`;
|
|
364
392
|
}
|
|
365
|
-
function* Union(schema, value) {
|
|
366
|
-
const expressions = schema.anyOf.map((schema) => CreateExpression(schema, value));
|
|
393
|
+
function* Union(schema, references, value) {
|
|
394
|
+
const expressions = schema.anyOf.map((schema) => CreateExpression(schema, references, value));
|
|
367
395
|
yield `(${expressions.join(' || ')})`;
|
|
368
396
|
}
|
|
369
|
-
function* Uint8Array(schema, value) {
|
|
397
|
+
function* Uint8Array(schema, references, value) {
|
|
370
398
|
yield `${value} instanceof Uint8Array`;
|
|
371
399
|
if (IsNumber(schema.maxByteLength))
|
|
372
400
|
yield `(${value}.length <= ${schema.maxByteLength})`;
|
|
373
401
|
if (IsNumber(schema.minByteLength))
|
|
374
402
|
yield `(${value}.length >= ${schema.minByteLength})`;
|
|
375
403
|
}
|
|
376
|
-
function* Unknown(schema, value) {
|
|
404
|
+
function* Unknown(schema, references, value) {
|
|
377
405
|
yield 'true';
|
|
378
406
|
}
|
|
379
|
-
function* Void(schema, value) {
|
|
380
|
-
|
|
381
|
-
yield `(${value} === undefined || ${value} === null)`;
|
|
382
|
-
}
|
|
383
|
-
else {
|
|
384
|
-
yield `${value} === undefined`;
|
|
385
|
-
}
|
|
407
|
+
function* Void(schema, references, value) {
|
|
408
|
+
yield IsVoidCheck(value);
|
|
386
409
|
}
|
|
387
|
-
function* UserDefined(schema, value) {
|
|
410
|
+
function* UserDefined(schema, references, value) {
|
|
388
411
|
const schema_key = `schema_key_${state_remote_custom_types.size}`;
|
|
389
412
|
state_remote_custom_types.set(schema_key, schema);
|
|
390
413
|
yield `custom('${schema[Types.Kind]}', '${schema_key}', ${value})`;
|
|
391
414
|
}
|
|
392
|
-
function* Visit(schema, value) {
|
|
415
|
+
function* Visit(schema, references, value) {
|
|
416
|
+
const references_ = IsString(schema.$id) ? [...references, schema] : references;
|
|
417
|
+
const schema_ = schema;
|
|
393
418
|
// Reference: Referenced schemas can originate from either additional schemas
|
|
394
419
|
// or inline in the schema itself. Ideally the recursive path should align to
|
|
395
420
|
// reference path. Consider for refactor.
|
|
396
|
-
if (schema.$id && !state_local_function_names.has(schema.$id)) {
|
|
421
|
+
if (IsString(schema.$id) && !state_local_function_names.has(schema.$id)) {
|
|
397
422
|
state_local_function_names.add(schema.$id);
|
|
398
423
|
const name = CreateFunctionName(schema.$id);
|
|
399
|
-
const body = CreateFunction(name, schema, 'value');
|
|
424
|
+
const body = CreateFunction(name, schema, references, 'value');
|
|
400
425
|
PushFunction(body);
|
|
401
426
|
yield `${name}(${value})`;
|
|
402
427
|
return;
|
|
403
428
|
}
|
|
404
|
-
|
|
405
|
-
switch (anySchema[Types.Kind]) {
|
|
429
|
+
switch (schema_[Types.Kind]) {
|
|
406
430
|
case 'Any':
|
|
407
|
-
return yield* Any(
|
|
431
|
+
return yield* Any(schema_, references_, value);
|
|
408
432
|
case 'Array':
|
|
409
|
-
return yield* Array(
|
|
433
|
+
return yield* Array(schema_, references_, value);
|
|
410
434
|
case 'BigInt':
|
|
411
|
-
return yield* BigInt(
|
|
435
|
+
return yield* BigInt(schema_, references_, value);
|
|
412
436
|
case 'Boolean':
|
|
413
|
-
return yield* Boolean(
|
|
437
|
+
return yield* Boolean(schema_, references_, value);
|
|
414
438
|
case 'Constructor':
|
|
415
|
-
return yield* Constructor(
|
|
439
|
+
return yield* Constructor(schema_, references_, value);
|
|
416
440
|
case 'Date':
|
|
417
|
-
return yield* Date(
|
|
441
|
+
return yield* Date(schema_, references_, value);
|
|
418
442
|
case 'Function':
|
|
419
|
-
return yield* Function(
|
|
443
|
+
return yield* Function(schema_, references_, value);
|
|
420
444
|
case 'Integer':
|
|
421
|
-
return yield* Integer(
|
|
445
|
+
return yield* Integer(schema_, references_, value);
|
|
422
446
|
case 'Intersect':
|
|
423
|
-
return yield* Intersect(
|
|
447
|
+
return yield* Intersect(schema_, references_, value);
|
|
424
448
|
case 'Literal':
|
|
425
|
-
return yield* Literal(
|
|
449
|
+
return yield* Literal(schema_, references_, value);
|
|
426
450
|
case 'Never':
|
|
427
|
-
return yield* Never(
|
|
451
|
+
return yield* Never(schema_, references_, value);
|
|
428
452
|
case 'Not':
|
|
429
|
-
return yield* Not(
|
|
453
|
+
return yield* Not(schema_, references_, value);
|
|
430
454
|
case 'Null':
|
|
431
|
-
return yield* Null(
|
|
455
|
+
return yield* Null(schema_, references_, value);
|
|
432
456
|
case 'Number':
|
|
433
|
-
return yield* Number(
|
|
457
|
+
return yield* Number(schema_, references_, value);
|
|
434
458
|
case 'Object':
|
|
435
|
-
return yield* Object(
|
|
459
|
+
return yield* Object(schema_, references_, value);
|
|
436
460
|
case 'Promise':
|
|
437
|
-
return yield* Promise(
|
|
461
|
+
return yield* Promise(schema_, references_, value);
|
|
438
462
|
case 'Record':
|
|
439
|
-
return yield* Record(
|
|
463
|
+
return yield* Record(schema_, references_, value);
|
|
440
464
|
case 'Ref':
|
|
441
|
-
return yield* Ref(
|
|
465
|
+
return yield* Ref(schema_, references_, value);
|
|
442
466
|
case 'Self':
|
|
443
|
-
return yield* Self(
|
|
467
|
+
return yield* Self(schema_, references_, value);
|
|
444
468
|
case 'String':
|
|
445
|
-
return yield* String(
|
|
469
|
+
return yield* String(schema_, references_, value);
|
|
446
470
|
case 'Symbol':
|
|
447
|
-
return yield* Symbol(
|
|
471
|
+
return yield* Symbol(schema_, references_, value);
|
|
448
472
|
case 'Tuple':
|
|
449
|
-
return yield* Tuple(
|
|
473
|
+
return yield* Tuple(schema_, references_, value);
|
|
450
474
|
case 'Undefined':
|
|
451
|
-
return yield* Undefined(
|
|
475
|
+
return yield* Undefined(schema_, references_, value);
|
|
452
476
|
case 'Union':
|
|
453
|
-
return yield* Union(
|
|
477
|
+
return yield* Union(schema_, references_, value);
|
|
454
478
|
case 'Uint8Array':
|
|
455
|
-
return yield* Uint8Array(
|
|
479
|
+
return yield* Uint8Array(schema_, references_, value);
|
|
456
480
|
case 'Unknown':
|
|
457
|
-
return yield* Unknown(
|
|
481
|
+
return yield* Unknown(schema_, references_, value);
|
|
458
482
|
case 'Void':
|
|
459
|
-
return yield* Void(
|
|
483
|
+
return yield* Void(schema_, references_, value);
|
|
460
484
|
default:
|
|
461
|
-
if (!Types.TypeRegistry.Has(
|
|
485
|
+
if (!Types.TypeRegistry.Has(schema_[Types.Kind]))
|
|
462
486
|
throw new TypeCompilerUnknownTypeError(schema);
|
|
463
|
-
return yield* UserDefined(
|
|
487
|
+
return yield* UserDefined(schema_, references_, value);
|
|
464
488
|
}
|
|
465
489
|
}
|
|
466
490
|
// -------------------------------------------------------------------
|
|
@@ -474,14 +498,14 @@ var TypeCompiler;
|
|
|
474
498
|
state_local_function_names.clear();
|
|
475
499
|
state_remote_custom_types.clear();
|
|
476
500
|
}
|
|
477
|
-
function CreateExpression(schema, value) {
|
|
478
|
-
return `(${[...Visit(schema, value)].join(' && ')})`;
|
|
501
|
+
function CreateExpression(schema, references, value) {
|
|
502
|
+
return `(${[...Visit(schema, references, value)].join(' && ')})`;
|
|
479
503
|
}
|
|
480
504
|
function CreateFunctionName($id) {
|
|
481
505
|
return `check_${Identifier.Encode($id)}`;
|
|
482
506
|
}
|
|
483
|
-
function CreateFunction(name, schema, value) {
|
|
484
|
-
const expression = [...Visit(schema, value)].map((condition) => ` ${condition}`).join(' &&\n');
|
|
507
|
+
function CreateFunction(name, schema, references, value) {
|
|
508
|
+
const expression = [...Visit(schema, references, value)].map((condition) => ` ${condition}`).join(' &&\n');
|
|
485
509
|
return `function ${name}(value) {\n return (\n${expression}\n )\n}`;
|
|
486
510
|
}
|
|
487
511
|
function PushFunction(functionBody) {
|
|
@@ -498,22 +522,25 @@ var TypeCompiler;
|
|
|
498
522
|
// -------------------------------------------------------------------
|
|
499
523
|
// Compile
|
|
500
524
|
// -------------------------------------------------------------------
|
|
501
|
-
function Build(schema) {
|
|
525
|
+
function Build(schema, references) {
|
|
502
526
|
ResetCompiler();
|
|
503
|
-
const check = CreateFunction('check', schema, 'value');
|
|
527
|
+
const check = CreateFunction('check', schema, references, 'value');
|
|
504
528
|
const locals = GetLocals();
|
|
505
529
|
return `${locals.join('\n')}\nreturn ${check}`;
|
|
506
530
|
}
|
|
507
531
|
/** Returns the generated assertion code used to validate this type. */
|
|
508
|
-
function Code(schema) {
|
|
532
|
+
function Code(schema, references = []) {
|
|
509
533
|
if (!Types.TypeGuard.TSchema(schema))
|
|
510
|
-
throw new
|
|
511
|
-
|
|
534
|
+
throw new TypeCompilerTypeGuardError(schema);
|
|
535
|
+
for (const schema of references)
|
|
536
|
+
if (!Types.TypeGuard.TSchema(schema))
|
|
537
|
+
throw new TypeCompilerTypeGuardError(schema);
|
|
538
|
+
return Build(schema, references);
|
|
512
539
|
}
|
|
513
540
|
TypeCompiler.Code = Code;
|
|
514
541
|
/** Compiles the given type for runtime type checking. This compiler only accepts known TypeBox types non-inclusive of unsafe types. */
|
|
515
|
-
function Compile(schema) {
|
|
516
|
-
const code = Code(schema);
|
|
542
|
+
function Compile(schema, references = []) {
|
|
543
|
+
const code = Code(schema, references);
|
|
517
544
|
const custom_schemas = new Map(state_remote_custom_types);
|
|
518
545
|
const compiledFunction = globalThis.Function('custom', 'format', 'hash', code);
|
|
519
546
|
const checkFunction = compiledFunction((kind, schema_key, value) => {
|
|
@@ -530,7 +557,7 @@ var TypeCompiler;
|
|
|
530
557
|
}, (value) => {
|
|
531
558
|
return hash_1.ValueHash.Create(value);
|
|
532
559
|
});
|
|
533
|
-
return new TypeCheck(schema, checkFunction, code);
|
|
560
|
+
return new TypeCheck(schema, references, checkFunction, code);
|
|
534
561
|
}
|
|
535
562
|
TypeCompiler.Compile = Compile;
|
|
536
563
|
})(TypeCompiler = exports.TypeCompiler || (exports.TypeCompiler = {}));
|
package/errors/errors.d.ts
CHANGED
|
@@ -78,7 +78,11 @@ export declare class ValueErrorsUnknownTypeError extends Error {
|
|
|
78
78
|
readonly schema: Types.TSchema;
|
|
79
79
|
constructor(schema: Types.TSchema);
|
|
80
80
|
}
|
|
81
|
+
export declare class ValueErrorsDereferenceError extends Error {
|
|
82
|
+
readonly schema: Types.TRef | Types.TSelf;
|
|
83
|
+
constructor(schema: Types.TRef | Types.TSelf);
|
|
84
|
+
}
|
|
81
85
|
/** Provides functionality to generate a sequence of errors against a TypeBox type. */
|
|
82
86
|
export declare namespace ValueErrors {
|
|
83
|
-
function Errors<T extends Types.TSchema>(schema: T, value: any): ValueErrorIterator;
|
|
87
|
+
function Errors<T extends Types.TSchema>(schema: T, references: Types.TSchema[], value: any): ValueErrorIterator;
|
|
84
88
|
}
|