@sinclair/typebox 0.24.0 → 0.24.3
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 +6 -14
- package/compiler/compiler.js +64 -69
- package/package.json +1 -1
- package/typebox.d.ts +5 -11
- package/typebox.js +1 -1
package/compiler/compiler.d.ts
CHANGED
|
@@ -1,11 +1,5 @@
|
|
|
1
1
|
import * as Types from '../typebox';
|
|
2
|
-
export declare type CheckFunction = (value: unknown) =>
|
|
3
|
-
export interface CheckOk {
|
|
4
|
-
ok: true;
|
|
5
|
-
}
|
|
6
|
-
export interface CheckFail {
|
|
7
|
-
ok: false;
|
|
8
|
-
}
|
|
2
|
+
export declare type CheckFunction = (value: unknown) => boolean;
|
|
9
3
|
export declare class TypeCheckAssertError extends Error {
|
|
10
4
|
readonly schema: Types.TSchema;
|
|
11
5
|
readonly value: unknown;
|
|
@@ -14,18 +8,16 @@ export declare class TypeCheckAssertError extends Error {
|
|
|
14
8
|
export declare class TypeCheck<T extends Types.TSchema> {
|
|
15
9
|
private readonly schema;
|
|
16
10
|
private readonly checkFunc;
|
|
17
|
-
|
|
11
|
+
private readonly code;
|
|
12
|
+
constructor(schema: T, checkFunc: CheckFunction, code: string);
|
|
13
|
+
/** Returns the compiled validation code used to check this type. */
|
|
14
|
+
Code(): string;
|
|
18
15
|
/** Returns true if the value is valid. */
|
|
19
16
|
Check(value: unknown): value is Types.Static<T>;
|
|
20
17
|
/** Asserts the given value and throws a TypeCheckAssertError if invalid. */
|
|
21
18
|
Assert(value: unknown): void;
|
|
22
19
|
}
|
|
23
20
|
export declare namespace TypeCompiler {
|
|
24
|
-
|
|
25
|
-
schema: Types.TSchema;
|
|
26
|
-
expr: string;
|
|
27
|
-
path: string;
|
|
28
|
-
}
|
|
29
|
-
/** Compiles a type into validation function */
|
|
21
|
+
/** Compiles the given type for runtime type checking. This compiler only accepts known TypeBox types non-inclusive of unsafe types. */
|
|
30
22
|
function Compile<T extends Types.TSchema>(schema: T, additional?: Types.TSchema[]): TypeCheck<T>;
|
|
31
23
|
}
|
package/compiler/compiler.js
CHANGED
|
@@ -45,22 +45,23 @@ exports.TypeCheckAssertError = TypeCheckAssertError;
|
|
|
45
45
|
class TypeCheck {
|
|
46
46
|
schema;
|
|
47
47
|
checkFunc;
|
|
48
|
-
|
|
48
|
+
code;
|
|
49
|
+
constructor(schema, checkFunc, code) {
|
|
49
50
|
this.schema = schema;
|
|
50
51
|
this.checkFunc = checkFunc;
|
|
52
|
+
this.code = code;
|
|
53
|
+
}
|
|
54
|
+
/** Returns the compiled validation code used to check this type. */
|
|
55
|
+
Code() {
|
|
56
|
+
return this.code;
|
|
51
57
|
}
|
|
52
58
|
/** Returns true if the value is valid. */
|
|
53
59
|
Check(value) {
|
|
54
|
-
|
|
55
|
-
return result.ok;
|
|
60
|
+
return this.checkFunc(value);
|
|
56
61
|
}
|
|
57
62
|
/** Asserts the given value and throws a TypeCheckAssertError if invalid. */
|
|
58
63
|
Assert(value) {
|
|
59
|
-
|
|
60
|
-
// to a limitation in TypeScript, this currently isn't possible. See issue below.
|
|
61
|
-
// https://github.com/microsoft/TypeScript/issues/36931
|
|
62
|
-
const result = this.checkFunc(value);
|
|
63
|
-
if (!result.ok)
|
|
64
|
+
if (!this.checkFunc(value))
|
|
64
65
|
throw new TypeCheckAssertError(this.schema, value);
|
|
65
66
|
}
|
|
66
67
|
}
|
|
@@ -70,74 +71,68 @@ exports.TypeCheck = TypeCheck;
|
|
|
70
71
|
// -------------------------------------------------------------------
|
|
71
72
|
var TypeCompiler;
|
|
72
73
|
(function (TypeCompiler) {
|
|
73
|
-
// -------------------------------------------------------------------
|
|
74
|
-
// Condition
|
|
75
|
-
// -------------------------------------------------------------------
|
|
76
|
-
function CreateCondition(schema, path, expr) {
|
|
77
|
-
return { schema, path, expr };
|
|
78
|
-
}
|
|
79
74
|
// -------------------------------------------------------------------
|
|
80
75
|
// Schemas
|
|
81
76
|
// -------------------------------------------------------------------
|
|
82
77
|
function* Any(schema, path) {
|
|
83
|
-
yield
|
|
78
|
+
yield '(true)';
|
|
84
79
|
}
|
|
85
80
|
function* Array(schema, path) {
|
|
86
|
-
const expr = [...Visit(schema.items, `value`)].map((condition) => condition
|
|
87
|
-
yield
|
|
81
|
+
const expr = [...Visit(schema.items, `value`)].map((condition) => condition).join(' && ');
|
|
82
|
+
yield `(Array.isArray(${path}) && ${path}.every(value => ${expr}))`;
|
|
88
83
|
}
|
|
89
84
|
function* Boolean(schema, path) {
|
|
90
|
-
yield
|
|
85
|
+
yield `(typeof ${path} === 'boolean')`;
|
|
91
86
|
}
|
|
92
87
|
function* Constructor(schema, path) {
|
|
93
88
|
yield* Visit(schema.yields, path);
|
|
94
89
|
}
|
|
95
90
|
function* Function(schema, path) {
|
|
96
|
-
yield
|
|
91
|
+
yield `(typeof ${path} === 'function')`;
|
|
97
92
|
}
|
|
98
93
|
function* Integer(schema, path) {
|
|
99
|
-
yield
|
|
94
|
+
yield `(typeof ${path} === 'number' && Number.isInteger(${path}))`;
|
|
100
95
|
if (schema.multipleOf)
|
|
101
|
-
yield
|
|
96
|
+
yield `(${path} % ${schema.multipleOf} === 0)`;
|
|
102
97
|
if (schema.exclusiveMinimum)
|
|
103
|
-
yield
|
|
98
|
+
yield `(${path} < ${schema.exclusiveMinimum})`;
|
|
104
99
|
if (schema.exclusiveMaximum)
|
|
105
|
-
yield
|
|
100
|
+
yield `(${path} < ${schema.exclusiveMaximum})`;
|
|
106
101
|
if (schema.minimum)
|
|
107
|
-
yield
|
|
102
|
+
yield `(${path} >= ${schema.minimum})`;
|
|
108
103
|
if (schema.maximum)
|
|
109
|
-
yield
|
|
104
|
+
yield `(${path} <= ${schema.maximum})`;
|
|
110
105
|
}
|
|
111
106
|
function* Literal(schema, path) {
|
|
112
107
|
if (typeof schema.const === 'string') {
|
|
113
|
-
yield
|
|
108
|
+
yield `(${path} === '${schema.const}')`;
|
|
114
109
|
}
|
|
115
110
|
else {
|
|
116
|
-
yield
|
|
111
|
+
yield `(${path} === ${schema.const})`;
|
|
117
112
|
}
|
|
118
113
|
}
|
|
119
114
|
function* Null(schema, path) {
|
|
120
|
-
yield
|
|
115
|
+
yield `(${path} === null)`;
|
|
121
116
|
}
|
|
122
117
|
function* Number(schema, path) {
|
|
123
|
-
yield
|
|
118
|
+
yield `(typeof ${path} === 'number')`;
|
|
124
119
|
if (schema.multipleOf)
|
|
125
|
-
yield
|
|
120
|
+
yield `(${path} % ${schema.multipleOf} === 0)`;
|
|
126
121
|
if (schema.exclusiveMinimum)
|
|
127
|
-
yield
|
|
122
|
+
yield `(${path} < ${schema.exclusiveMinimum})`;
|
|
128
123
|
if (schema.exclusiveMaximum)
|
|
129
|
-
yield
|
|
124
|
+
yield `(${path} < ${schema.exclusiveMaximum})`;
|
|
130
125
|
if (schema.minimum)
|
|
131
|
-
yield
|
|
126
|
+
yield `(${path} >= ${schema.minimum})`;
|
|
132
127
|
if (schema.maximum)
|
|
133
|
-
yield
|
|
128
|
+
yield `(${path} <= ${schema.maximum})`;
|
|
134
129
|
}
|
|
135
130
|
function* Object(schema, path) {
|
|
136
|
-
yield
|
|
131
|
+
yield `(typeof ${path} === 'object' && ${path} !== null && !Array.isArray(${path}))`;
|
|
137
132
|
if (schema.minProperties !== undefined)
|
|
138
|
-
yield
|
|
133
|
+
yield `(Object.keys(${path}).length >= ${schema.minProperties})`;
|
|
139
134
|
if (schema.maxProperties !== undefined)
|
|
140
|
-
yield
|
|
135
|
+
yield `(Object.keys(${path}).length <= ${schema.maxProperties})`;
|
|
141
136
|
const propertyKeys = globalThis.Object.keys(schema.properties);
|
|
142
137
|
if (schema.additionalProperties === false) {
|
|
143
138
|
// optimization: If the property key length matches the required keys length
|
|
@@ -145,11 +140,11 @@ var TypeCompiler;
|
|
|
145
140
|
// of the property key length. This is because exhaustive testing for values
|
|
146
141
|
// will occur in subsequent property tests.
|
|
147
142
|
if (schema.required && schema.required.length === propertyKeys.length) {
|
|
148
|
-
yield
|
|
143
|
+
yield `(Object.keys(${path}).length === ${propertyKeys.length})`;
|
|
149
144
|
}
|
|
150
145
|
else {
|
|
151
146
|
const keys = `[${propertyKeys.map((key) => `'${key}'`).join(', ')}]`;
|
|
152
|
-
yield
|
|
147
|
+
yield `(Object.keys(${path}).every(key => ${keys}.includes(key)))`;
|
|
153
148
|
}
|
|
154
149
|
}
|
|
155
150
|
for (const propertyKey of propertyKeys) {
|
|
@@ -158,21 +153,21 @@ var TypeCompiler;
|
|
|
158
153
|
yield* Visit(propertySchema, `${path}.${propertyKey}`);
|
|
159
154
|
}
|
|
160
155
|
else {
|
|
161
|
-
const expr = [...Visit(propertySchema, `${path}.${propertyKey}`)].map((condition) => condition
|
|
162
|
-
yield
|
|
156
|
+
const expr = [...Visit(propertySchema, `${path}.${propertyKey}`)].map((condition) => condition).join(' && ');
|
|
157
|
+
yield `(${path}.${propertyKey} === undefined ? true : (${expr}))`;
|
|
163
158
|
}
|
|
164
159
|
}
|
|
165
160
|
}
|
|
166
161
|
function* Promise(schema, path) {
|
|
167
|
-
yield
|
|
162
|
+
yield `(typeof value === 'object' && typeof ${path}.then === 'function')`;
|
|
168
163
|
}
|
|
169
164
|
function* Record(schema, path) {
|
|
170
|
-
yield
|
|
165
|
+
yield `(typeof ${path} === 'object' && ${path} !== null && !Array.isArray(${path}))`;
|
|
171
166
|
const [keyPattern, valueSchema] = globalThis.Object.entries(schema.patternProperties)[0];
|
|
172
167
|
const local = PushLocal(`const local = new RegExp(/${keyPattern}/)`);
|
|
173
|
-
yield
|
|
174
|
-
const expr = [...Visit(valueSchema, 'value')].map((
|
|
175
|
-
yield
|
|
168
|
+
yield `(Object.keys(${path}).every(key => ${local}.test(key)))`;
|
|
169
|
+
const expr = [...Visit(valueSchema, 'value')].map((condition) => condition).join(' && ');
|
|
170
|
+
yield `(Object.values(${path}).every(value => ${expr}))`;
|
|
176
171
|
}
|
|
177
172
|
function* Ref(schema, path) {
|
|
178
173
|
// reference: referenced schemas can originate from either additional
|
|
@@ -187,48 +182,48 @@ var TypeCompiler;
|
|
|
187
182
|
PushLocal(body);
|
|
188
183
|
}
|
|
189
184
|
const func = CreateFunctionName(schema.$ref);
|
|
190
|
-
yield
|
|
185
|
+
yield `(${func}(${path}))`;
|
|
191
186
|
}
|
|
192
187
|
function* Self(schema, path) {
|
|
193
188
|
const func = CreateFunctionName(schema.$ref);
|
|
194
|
-
yield
|
|
189
|
+
yield `(${func}(${path}))`;
|
|
195
190
|
}
|
|
196
191
|
function* String(schema, path) {
|
|
197
|
-
yield
|
|
192
|
+
yield `(typeof ${path} === 'string')`;
|
|
198
193
|
if (schema.pattern !== undefined) {
|
|
199
194
|
const local = PushLocal(`const local = new RegExp('${schema.pattern}');`);
|
|
200
|
-
yield
|
|
195
|
+
yield `(${local}.test(${path}))`;
|
|
201
196
|
}
|
|
202
197
|
}
|
|
203
198
|
function* Tuple(schema, path) {
|
|
204
|
-
yield
|
|
199
|
+
yield `(Array.isArray(${path}))`;
|
|
205
200
|
if (schema.items === undefined)
|
|
206
|
-
return yield
|
|
207
|
-
yield
|
|
201
|
+
return yield `(${path}.length === 0)`;
|
|
202
|
+
yield `(${path}.length === ${schema.maxItems})`;
|
|
208
203
|
for (let i = 0; i < schema.items.length; i++) {
|
|
209
|
-
const expr = [...Visit(schema.items[i], `${path}[${i}]`)].map((condition) => condition
|
|
210
|
-
yield
|
|
204
|
+
const expr = [...Visit(schema.items[i], `${path}[${i}]`)].map((condition) => condition).join(' && ');
|
|
205
|
+
yield `(${expr})`;
|
|
211
206
|
}
|
|
212
207
|
}
|
|
213
208
|
function* Undefined(schema, path) {
|
|
214
|
-
yield
|
|
209
|
+
yield `${path} === undefined`;
|
|
215
210
|
}
|
|
216
211
|
function* Union(schema, path) {
|
|
217
|
-
const exprs = schema.anyOf.map((schema) => [...Visit(schema, path)].map((
|
|
218
|
-
yield
|
|
212
|
+
const exprs = schema.anyOf.map((schema) => [...Visit(schema, path)].map((condition) => condition).join(' && '));
|
|
213
|
+
yield `(${exprs.join(' || ')})`;
|
|
219
214
|
}
|
|
220
215
|
function* Uint8Array(schema, path) {
|
|
221
|
-
yield
|
|
216
|
+
yield `(${path} instanceof Uint8Array)`;
|
|
222
217
|
if (schema.maxByteLength)
|
|
223
|
-
yield
|
|
218
|
+
yield `(${path}.length <= ${schema.maxByteLength})`;
|
|
224
219
|
if (schema.minByteLength)
|
|
225
|
-
yield
|
|
220
|
+
yield `(${path}.length >= ${schema.minByteLength})`;
|
|
226
221
|
}
|
|
227
222
|
function* Unknown(schema, path) {
|
|
228
|
-
yield
|
|
223
|
+
yield '(true)';
|
|
229
224
|
}
|
|
230
225
|
function* Void(schema, path) {
|
|
231
|
-
yield
|
|
226
|
+
yield `(${path} === null)`;
|
|
232
227
|
}
|
|
233
228
|
function* Visit(schema, path) {
|
|
234
229
|
// reference: referenced schemas can originate from either additional
|
|
@@ -240,7 +235,7 @@ var TypeCompiler;
|
|
|
240
235
|
const name = CreateFunctionName(schema.$id);
|
|
241
236
|
const body = CreateFunction(name, conditions);
|
|
242
237
|
PushLocal(body);
|
|
243
|
-
yield
|
|
238
|
+
yield `(${name}(${path}))`;
|
|
244
239
|
return;
|
|
245
240
|
}
|
|
246
241
|
const anySchema = schema;
|
|
@@ -326,11 +321,11 @@ var TypeCompiler;
|
|
|
326
321
|
return `check_${$id.replace(/-/g, '_')}`;
|
|
327
322
|
}
|
|
328
323
|
function CreateFunction(name, conditions) {
|
|
329
|
-
const
|
|
330
|
-
return `function ${name}(value) {\n
|
|
324
|
+
const expression = conditions.map((condition) => ` ${condition}`).join(' &&\n');
|
|
325
|
+
return `function ${name}(value) {\n return (\n${expression}\n )\n}`;
|
|
331
326
|
}
|
|
332
327
|
// -------------------------------------------------------------------
|
|
333
|
-
//
|
|
328
|
+
// Compile
|
|
334
329
|
// -------------------------------------------------------------------
|
|
335
330
|
function Build(schema, additional = []) {
|
|
336
331
|
ClearLocals();
|
|
@@ -339,11 +334,11 @@ var TypeCompiler;
|
|
|
339
334
|
const locals = GetLocals();
|
|
340
335
|
return `${locals.join('\n')}\nreturn ${CreateFunction('check', conditions)}`;
|
|
341
336
|
}
|
|
342
|
-
/** Compiles
|
|
337
|
+
/** Compiles the given type for runtime type checking. This compiler only accepts known TypeBox types non-inclusive of unsafe types. */
|
|
343
338
|
function Compile(schema, additional = []) {
|
|
344
339
|
const code = Build(schema, additional);
|
|
345
340
|
const func = globalThis.Function(code);
|
|
346
|
-
return new TypeCheck(schema, func());
|
|
341
|
+
return new TypeCheck(schema, func(), code);
|
|
347
342
|
}
|
|
348
343
|
TypeCompiler.Compile = Compile;
|
|
349
344
|
})(TypeCompiler = exports.TypeCompiler || (exports.TypeCompiler = {}));
|
package/package.json
CHANGED
package/typebox.d.ts
CHANGED
|
@@ -84,15 +84,6 @@ export interface TEnum<T extends Record<string, string | number> = Record<string
|
|
|
84
84
|
static: T[keyof T];
|
|
85
85
|
anyOf: TLiteral<string | number>[];
|
|
86
86
|
}
|
|
87
|
-
export interface TExclude<T extends TUnion, U extends TUnion> extends TUnion {
|
|
88
|
-
[Kind]: 'Union';
|
|
89
|
-
static: Exclude<Static<T, this['params']>, Static<U, this['params']>>;
|
|
90
|
-
}
|
|
91
|
-
export interface TExtract<T extends TSchema, U extends TUnion> extends TUnion {
|
|
92
|
-
[Kind]: 'Union';
|
|
93
|
-
static: Extract<Static<T, this['params']>, Static<U, this['params']>>;
|
|
94
|
-
}
|
|
95
|
-
export declare type TExtends<T extends TSchema, U extends TSchema, X extends TSchema, Y extends TSchema> = T extends TAny ? (U extends TUnknown ? X : U extends TAny ? X : TUnion<[X, Y]>) : T extends U ? X : Y;
|
|
96
87
|
export declare type TFunctionParameters<T extends readonly TSchema[], P extends unknown[]> = [...{
|
|
97
88
|
[K in keyof T]: T[K] extends TSchema ? Static<T[K], P> : never;
|
|
98
89
|
}];
|
|
@@ -275,8 +266,11 @@ export interface TUnknown extends TSchema {
|
|
|
275
266
|
[Kind]: 'Unknown';
|
|
276
267
|
static: unknown;
|
|
277
268
|
}
|
|
269
|
+
export interface UnsafeOptions extends SchemaOptions {
|
|
270
|
+
[Kind]?: string;
|
|
271
|
+
}
|
|
278
272
|
export interface TUnsafe<T> extends TSchema {
|
|
279
|
-
[Kind]:
|
|
273
|
+
[Kind]: string;
|
|
280
274
|
static: T;
|
|
281
275
|
}
|
|
282
276
|
export interface TVoid extends TSchema {
|
|
@@ -356,7 +350,7 @@ export declare class TypeBuilder {
|
|
|
356
350
|
/** Creates an unknown type */
|
|
357
351
|
Unknown(options?: SchemaOptions): TUnknown;
|
|
358
352
|
/** Creates a user defined schema that infers as type T */
|
|
359
|
-
Unsafe<T>(options?:
|
|
353
|
+
Unsafe<T>(options?: UnsafeOptions): TUnsafe<T>;
|
|
360
354
|
/** Creates a void type */
|
|
361
355
|
Void(options?: SchemaOptions): TVoid;
|
|
362
356
|
/** Use this function to return TSchema with static and params omitted */
|
package/typebox.js
CHANGED
|
@@ -293,7 +293,7 @@ class TypeBuilder {
|
|
|
293
293
|
}
|
|
294
294
|
/** Creates a user defined schema that infers as type T */
|
|
295
295
|
Unsafe(options = {}) {
|
|
296
|
-
return this.Create({ ...options, [exports.Kind]: '
|
|
296
|
+
return this.Create({ ...options, [exports.Kind]: options[exports.Kind] || 'Unsafe' });
|
|
297
297
|
}
|
|
298
298
|
/** Creates a void type */
|
|
299
299
|
Void(options = {}) {
|