@sinclair/typebox 0.28.16 → 0.28.17
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 +4 -1
- package/compiler/compiler.js +44 -34
- package/package.json +1 -1
package/compiler/compiler.d.ts
CHANGED
|
@@ -26,10 +26,13 @@ export declare class TypeCompilerTypeGuardError extends Error {
|
|
|
26
26
|
readonly schema: Types.TSchema;
|
|
27
27
|
constructor(schema: Types.TSchema);
|
|
28
28
|
}
|
|
29
|
+
export interface TypeCompilerOptions {
|
|
30
|
+
language: 'typescript' | 'javascript';
|
|
31
|
+
}
|
|
29
32
|
/** Compiles Types for Runtime Type Checking */
|
|
30
33
|
export declare namespace TypeCompiler {
|
|
31
34
|
/** Returns the generated assertion code used to validate this type. */
|
|
32
|
-
function Code<T extends Types.TSchema>(schema: T, references?: Types.TSchema[]): string;
|
|
35
|
+
function Code<T extends Types.TSchema>(schema: T, references?: Types.TSchema[], options?: TypeCompilerOptions): string;
|
|
33
36
|
/** Compiles the given type for runtime type checking. This compiler only accepts known TypeBox types non-inclusive of unsafe types. */
|
|
34
37
|
function Compile<T extends Types.TSchema>(schema: T, references?: Types.TSchema[]): TypeCheck<T>;
|
|
35
38
|
}
|
package/compiler/compiler.js
CHANGED
|
@@ -207,7 +207,8 @@ var TypeCompiler;
|
|
|
207
207
|
if (schema.uniqueItems === true)
|
|
208
208
|
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 })())`;
|
|
209
209
|
const expression = CreateExpression(schema.items, references, 'value');
|
|
210
|
-
|
|
210
|
+
const parameter = CreateParameter('value');
|
|
211
|
+
yield `${value}.every((${parameter}) => ${expression})`;
|
|
211
212
|
}
|
|
212
213
|
function* BigInt(schema, references, value) {
|
|
213
214
|
yield `(typeof ${value} === 'bigint')`;
|
|
@@ -223,7 +224,7 @@ var TypeCompiler;
|
|
|
223
224
|
yield `${value} <= BigInt(${schema.maximum})`;
|
|
224
225
|
}
|
|
225
226
|
function* Boolean(schema, references, value) {
|
|
226
|
-
yield `typeof ${value} === 'boolean'`;
|
|
227
|
+
yield `(typeof ${value} === 'boolean')`;
|
|
227
228
|
}
|
|
228
229
|
function* Constructor(schema, references, value) {
|
|
229
230
|
yield* Visit(schema.returns, references, `${value}.prototype`);
|
|
@@ -240,7 +241,7 @@ var TypeCompiler;
|
|
|
240
241
|
yield `${value}.getTime() <= ${schema.maximumTimestamp}`;
|
|
241
242
|
}
|
|
242
243
|
function* Function(schema, references, value) {
|
|
243
|
-
yield `typeof ${value} === 'function'`;
|
|
244
|
+
yield `(typeof ${value} === 'function')`;
|
|
244
245
|
}
|
|
245
246
|
function* Integer(schema, references, value) {
|
|
246
247
|
yield `(typeof ${value} === 'number' && Number.isInteger(${value}))`;
|
|
@@ -260,23 +261,23 @@ var TypeCompiler;
|
|
|
260
261
|
if (schema.unevaluatedProperties === false) {
|
|
261
262
|
const keyCheck = PushLocal(`${new RegExp(Types.KeyResolver.ResolvePattern(schema))};`);
|
|
262
263
|
const check2 = `Object.getOwnPropertyNames(${value}).every(key => ${keyCheck}.test(key))`;
|
|
263
|
-
yield
|
|
264
|
+
yield `(${check1} && ${check2})`;
|
|
264
265
|
}
|
|
265
266
|
else if (Types.TypeGuard.TSchema(schema.unevaluatedProperties)) {
|
|
266
267
|
const keyCheck = PushLocal(`${new RegExp(Types.KeyResolver.ResolvePattern(schema))};`);
|
|
267
268
|
const check2 = `Object.getOwnPropertyNames(${value}).every(key => ${keyCheck}.test(key) || ${CreateExpression(schema.unevaluatedProperties, references, `${value}[key]`)})`;
|
|
268
|
-
yield
|
|
269
|
+
yield `(${check1} && ${check2})`;
|
|
269
270
|
}
|
|
270
271
|
else {
|
|
271
|
-
yield
|
|
272
|
+
yield `(${check1})`;
|
|
272
273
|
}
|
|
273
274
|
}
|
|
274
275
|
function* Literal(schema, references, value) {
|
|
275
276
|
if (typeof schema.const === 'number' || typeof schema.const === 'boolean') {
|
|
276
|
-
yield
|
|
277
|
+
yield `(${value} === ${schema.const})`;
|
|
277
278
|
}
|
|
278
279
|
else {
|
|
279
|
-
yield
|
|
280
|
+
yield `(${value} === '${schema.const}')`;
|
|
280
281
|
}
|
|
281
282
|
}
|
|
282
283
|
function* Never(schema, references, value) {
|
|
@@ -288,7 +289,7 @@ var TypeCompiler;
|
|
|
288
289
|
yield `!${left} && ${right}`;
|
|
289
290
|
}
|
|
290
291
|
function* Null(schema, references, value) {
|
|
291
|
-
yield
|
|
292
|
+
yield `(${value} === null)`;
|
|
292
293
|
}
|
|
293
294
|
function* Number(schema, references, value) {
|
|
294
295
|
yield IsNumberCheck(value);
|
|
@@ -362,7 +363,7 @@ var TypeCompiler;
|
|
|
362
363
|
// Reference: If we have seen this reference before we can just yield and
|
|
363
364
|
// return the function call. If this isn't the case we defer to visit to
|
|
364
365
|
// generate and set the function for subsequent passes.
|
|
365
|
-
if (
|
|
366
|
+
if (state.functions.has(schema.$ref))
|
|
366
367
|
return yield `${CreateFunctionName(schema.$ref)}(${value})`;
|
|
367
368
|
yield* Visit(target, references, value);
|
|
368
369
|
}
|
|
@@ -423,8 +424,8 @@ var TypeCompiler;
|
|
|
423
424
|
yield IsVoidCheck(value);
|
|
424
425
|
}
|
|
425
426
|
function* UserDefined(schema, references, value) {
|
|
426
|
-
const schema_key = `schema_key_${
|
|
427
|
-
|
|
427
|
+
const schema_key = `schema_key_${state.customs.size}`;
|
|
428
|
+
state.customs.set(schema_key, schema);
|
|
428
429
|
yield `custom('${schema[Types.Kind]}', '${schema_key}', ${value})`;
|
|
429
430
|
}
|
|
430
431
|
function* Visit(schema, references, value, root = false) {
|
|
@@ -439,8 +440,8 @@ var TypeCompiler;
|
|
|
439
440
|
// by refactoring the logic below. Consider for review.
|
|
440
441
|
if (IsString(schema.$id)) {
|
|
441
442
|
const name = CreateFunctionName(schema.$id);
|
|
442
|
-
if (!
|
|
443
|
-
|
|
443
|
+
if (!state.functions.has(schema.$id)) {
|
|
444
|
+
state.functions.add(schema.$id);
|
|
444
445
|
const body = CreateFunction(name, schema, references, 'value');
|
|
445
446
|
PushFunction(body);
|
|
446
447
|
}
|
|
@@ -513,49 +514,58 @@ var TypeCompiler;
|
|
|
513
514
|
// -------------------------------------------------------------------
|
|
514
515
|
// Compiler State
|
|
515
516
|
// -------------------------------------------------------------------
|
|
516
|
-
|
|
517
|
-
const
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
}
|
|
517
|
+
// prettier-ignore
|
|
518
|
+
const state = {
|
|
519
|
+
language: 'javascript',
|
|
520
|
+
variables: new Set(),
|
|
521
|
+
functions: new Set(),
|
|
522
|
+
customs: new Map(), // custom type data
|
|
523
|
+
};
|
|
524
524
|
function CreateExpression(schema, references, value) {
|
|
525
525
|
return `(${[...Visit(schema, references, value)].join(' && ')})`;
|
|
526
526
|
}
|
|
527
527
|
function CreateFunctionName($id) {
|
|
528
528
|
return `check_${Identifier.Encode($id)}`;
|
|
529
529
|
}
|
|
530
|
+
function CreateParameter(name) {
|
|
531
|
+
const annotation = state.language === 'typescript' ? ': any' : '';
|
|
532
|
+
return `${name}${annotation}`;
|
|
533
|
+
}
|
|
530
534
|
function CreateFunction(name, schema, references, value) {
|
|
531
535
|
const expression = [...Visit(schema, references, value, true)].map((condition) => ` ${condition}`).join(' &&\n');
|
|
532
|
-
|
|
536
|
+
const parameter = CreateParameter('value');
|
|
537
|
+
return `function ${name}(${parameter}) {\n return (\n${expression}\n )\n}`;
|
|
533
538
|
}
|
|
534
539
|
function PushFunction(functionBody) {
|
|
535
|
-
|
|
540
|
+
state.variables.add(functionBody);
|
|
536
541
|
}
|
|
537
542
|
function PushLocal(expression) {
|
|
538
|
-
const local = `local_${
|
|
539
|
-
|
|
543
|
+
const local = `local_${state.variables.size}`;
|
|
544
|
+
state.variables.add(`const ${local} = ${expression}`);
|
|
540
545
|
return local;
|
|
541
546
|
}
|
|
542
547
|
function GetLocals() {
|
|
543
|
-
return [...
|
|
548
|
+
return [...state.variables.values()];
|
|
544
549
|
}
|
|
545
550
|
// -------------------------------------------------------------------
|
|
546
551
|
// Compile
|
|
547
552
|
// -------------------------------------------------------------------
|
|
548
553
|
function Build(schema, references) {
|
|
549
|
-
ResetCompiler();
|
|
550
554
|
const check = CreateFunction('check', schema, references, 'value'); // interior visit
|
|
551
555
|
const locals = GetLocals();
|
|
556
|
+
const parameter = CreateParameter('value');
|
|
552
557
|
// prettier-ignore
|
|
553
558
|
return IsString(schema.$id) // ensure top level schemas with $id's are hoisted
|
|
554
|
-
? `${locals.join('\n')}\nreturn function check(
|
|
559
|
+
? `${locals.join('\n')}\nreturn function check(${parameter}) {\n return ${CreateFunctionName(schema.$id)}(value)\n}`
|
|
555
560
|
: `${locals.join('\n')}\nreturn ${check}`;
|
|
556
561
|
}
|
|
557
562
|
/** Returns the generated assertion code used to validate this type. */
|
|
558
|
-
function Code(schema, references = []) {
|
|
563
|
+
function Code(schema, references = [], options = { language: 'javascript' }) {
|
|
564
|
+
// compiler-reset
|
|
565
|
+
state.language = options.language;
|
|
566
|
+
state.variables.clear();
|
|
567
|
+
state.functions.clear();
|
|
568
|
+
state.customs.clear();
|
|
559
569
|
if (!Types.TypeGuard.TSchema(schema))
|
|
560
570
|
throw new TypeCompilerTypeGuardError(schema);
|
|
561
571
|
for (const schema of references)
|
|
@@ -566,13 +576,13 @@ var TypeCompiler;
|
|
|
566
576
|
TypeCompiler.Code = Code;
|
|
567
577
|
/** Compiles the given type for runtime type checking. This compiler only accepts known TypeBox types non-inclusive of unsafe types. */
|
|
568
578
|
function Compile(schema, references = []) {
|
|
569
|
-
const code = Code(schema, references);
|
|
570
|
-
const
|
|
579
|
+
const code = Code(schema, references, { language: 'javascript' });
|
|
580
|
+
const customs = new Map(state.customs);
|
|
571
581
|
const compiledFunction = globalThis.Function('custom', 'format', 'hash', code);
|
|
572
582
|
const checkFunction = compiledFunction((kind, schema_key, value) => {
|
|
573
|
-
if (!Types.TypeRegistry.Has(kind) || !
|
|
583
|
+
if (!Types.TypeRegistry.Has(kind) || !customs.has(schema_key))
|
|
574
584
|
return false;
|
|
575
|
-
const schema =
|
|
585
|
+
const schema = customs.get(schema_key);
|
|
576
586
|
const func = Types.TypeRegistry.Get(kind);
|
|
577
587
|
return func(schema, value);
|
|
578
588
|
}, (format, value) => {
|