@sinclair/typebox 0.24.2 → 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 +5 -7
- package/compiler/compiler.js +62 -65
- package/package.json +1 -1
package/compiler/compiler.d.ts
CHANGED
|
@@ -8,18 +8,16 @@ export declare class TypeCheckAssertError extends Error {
|
|
|
8
8
|
export declare class TypeCheck<T extends Types.TSchema> {
|
|
9
9
|
private readonly schema;
|
|
10
10
|
private readonly checkFunc;
|
|
11
|
-
|
|
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;
|
|
12
15
|
/** Returns true if the value is valid. */
|
|
13
16
|
Check(value: unknown): value is Types.Static<T>;
|
|
14
17
|
/** Asserts the given value and throws a TypeCheckAssertError if invalid. */
|
|
15
18
|
Assert(value: unknown): void;
|
|
16
19
|
}
|
|
17
20
|
export declare namespace TypeCompiler {
|
|
18
|
-
|
|
19
|
-
schema: Types.TSchema;
|
|
20
|
-
expr: string;
|
|
21
|
-
path: string;
|
|
22
|
-
}
|
|
23
|
-
/** 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. */
|
|
24
22
|
function Compile<T extends Types.TSchema>(schema: T, additional?: Types.TSchema[]): TypeCheck<T>;
|
|
25
23
|
}
|
package/compiler/compiler.js
CHANGED
|
@@ -45,9 +45,15 @@ 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) {
|
|
@@ -55,9 +61,6 @@ class TypeCheck {
|
|
|
55
61
|
}
|
|
56
62
|
/** Asserts the given value and throws a TypeCheckAssertError if invalid. */
|
|
57
63
|
Assert(value) {
|
|
58
|
-
// The return type for this function should be 'asserts value is Static<T>' but due
|
|
59
|
-
// to a limitation in TypeScript, this currently isn't possible. See issue below.
|
|
60
|
-
// https://github.com/microsoft/TypeScript/issues/36931
|
|
61
64
|
if (!this.checkFunc(value))
|
|
62
65
|
throw new TypeCheckAssertError(this.schema, value);
|
|
63
66
|
}
|
|
@@ -68,74 +71,68 @@ exports.TypeCheck = TypeCheck;
|
|
|
68
71
|
// -------------------------------------------------------------------
|
|
69
72
|
var TypeCompiler;
|
|
70
73
|
(function (TypeCompiler) {
|
|
71
|
-
// -------------------------------------------------------------------
|
|
72
|
-
// Condition
|
|
73
|
-
// -------------------------------------------------------------------
|
|
74
|
-
function CreateCondition(schema, path, expr) {
|
|
75
|
-
return { schema, path, expr };
|
|
76
|
-
}
|
|
77
74
|
// -------------------------------------------------------------------
|
|
78
75
|
// Schemas
|
|
79
76
|
// -------------------------------------------------------------------
|
|
80
77
|
function* Any(schema, path) {
|
|
81
|
-
yield
|
|
78
|
+
yield '(true)';
|
|
82
79
|
}
|
|
83
80
|
function* Array(schema, path) {
|
|
84
|
-
const expr = [...Visit(schema.items, `value`)].map((condition) => condition
|
|
85
|
-
yield
|
|
81
|
+
const expr = [...Visit(schema.items, `value`)].map((condition) => condition).join(' && ');
|
|
82
|
+
yield `(Array.isArray(${path}) && ${path}.every(value => ${expr}))`;
|
|
86
83
|
}
|
|
87
84
|
function* Boolean(schema, path) {
|
|
88
|
-
yield
|
|
85
|
+
yield `(typeof ${path} === 'boolean')`;
|
|
89
86
|
}
|
|
90
87
|
function* Constructor(schema, path) {
|
|
91
88
|
yield* Visit(schema.yields, path);
|
|
92
89
|
}
|
|
93
90
|
function* Function(schema, path) {
|
|
94
|
-
yield
|
|
91
|
+
yield `(typeof ${path} === 'function')`;
|
|
95
92
|
}
|
|
96
93
|
function* Integer(schema, path) {
|
|
97
|
-
yield
|
|
94
|
+
yield `(typeof ${path} === 'number' && Number.isInteger(${path}))`;
|
|
98
95
|
if (schema.multipleOf)
|
|
99
|
-
yield
|
|
96
|
+
yield `(${path} % ${schema.multipleOf} === 0)`;
|
|
100
97
|
if (schema.exclusiveMinimum)
|
|
101
|
-
yield
|
|
98
|
+
yield `(${path} < ${schema.exclusiveMinimum})`;
|
|
102
99
|
if (schema.exclusiveMaximum)
|
|
103
|
-
yield
|
|
100
|
+
yield `(${path} < ${schema.exclusiveMaximum})`;
|
|
104
101
|
if (schema.minimum)
|
|
105
|
-
yield
|
|
102
|
+
yield `(${path} >= ${schema.minimum})`;
|
|
106
103
|
if (schema.maximum)
|
|
107
|
-
yield
|
|
104
|
+
yield `(${path} <= ${schema.maximum})`;
|
|
108
105
|
}
|
|
109
106
|
function* Literal(schema, path) {
|
|
110
107
|
if (typeof schema.const === 'string') {
|
|
111
|
-
yield
|
|
108
|
+
yield `(${path} === '${schema.const}')`;
|
|
112
109
|
}
|
|
113
110
|
else {
|
|
114
|
-
yield
|
|
111
|
+
yield `(${path} === ${schema.const})`;
|
|
115
112
|
}
|
|
116
113
|
}
|
|
117
114
|
function* Null(schema, path) {
|
|
118
|
-
yield
|
|
115
|
+
yield `(${path} === null)`;
|
|
119
116
|
}
|
|
120
117
|
function* Number(schema, path) {
|
|
121
|
-
yield
|
|
118
|
+
yield `(typeof ${path} === 'number')`;
|
|
122
119
|
if (schema.multipleOf)
|
|
123
|
-
yield
|
|
120
|
+
yield `(${path} % ${schema.multipleOf} === 0)`;
|
|
124
121
|
if (schema.exclusiveMinimum)
|
|
125
|
-
yield
|
|
122
|
+
yield `(${path} < ${schema.exclusiveMinimum})`;
|
|
126
123
|
if (schema.exclusiveMaximum)
|
|
127
|
-
yield
|
|
124
|
+
yield `(${path} < ${schema.exclusiveMaximum})`;
|
|
128
125
|
if (schema.minimum)
|
|
129
|
-
yield
|
|
126
|
+
yield `(${path} >= ${schema.minimum})`;
|
|
130
127
|
if (schema.maximum)
|
|
131
|
-
yield
|
|
128
|
+
yield `(${path} <= ${schema.maximum})`;
|
|
132
129
|
}
|
|
133
130
|
function* Object(schema, path) {
|
|
134
|
-
yield
|
|
131
|
+
yield `(typeof ${path} === 'object' && ${path} !== null && !Array.isArray(${path}))`;
|
|
135
132
|
if (schema.minProperties !== undefined)
|
|
136
|
-
yield
|
|
133
|
+
yield `(Object.keys(${path}).length >= ${schema.minProperties})`;
|
|
137
134
|
if (schema.maxProperties !== undefined)
|
|
138
|
-
yield
|
|
135
|
+
yield `(Object.keys(${path}).length <= ${schema.maxProperties})`;
|
|
139
136
|
const propertyKeys = globalThis.Object.keys(schema.properties);
|
|
140
137
|
if (schema.additionalProperties === false) {
|
|
141
138
|
// optimization: If the property key length matches the required keys length
|
|
@@ -143,11 +140,11 @@ var TypeCompiler;
|
|
|
143
140
|
// of the property key length. This is because exhaustive testing for values
|
|
144
141
|
// will occur in subsequent property tests.
|
|
145
142
|
if (schema.required && schema.required.length === propertyKeys.length) {
|
|
146
|
-
yield
|
|
143
|
+
yield `(Object.keys(${path}).length === ${propertyKeys.length})`;
|
|
147
144
|
}
|
|
148
145
|
else {
|
|
149
146
|
const keys = `[${propertyKeys.map((key) => `'${key}'`).join(', ')}]`;
|
|
150
|
-
yield
|
|
147
|
+
yield `(Object.keys(${path}).every(key => ${keys}.includes(key)))`;
|
|
151
148
|
}
|
|
152
149
|
}
|
|
153
150
|
for (const propertyKey of propertyKeys) {
|
|
@@ -156,21 +153,21 @@ var TypeCompiler;
|
|
|
156
153
|
yield* Visit(propertySchema, `${path}.${propertyKey}`);
|
|
157
154
|
}
|
|
158
155
|
else {
|
|
159
|
-
const expr = [...Visit(propertySchema, `${path}.${propertyKey}`)].map((condition) => condition
|
|
160
|
-
yield
|
|
156
|
+
const expr = [...Visit(propertySchema, `${path}.${propertyKey}`)].map((condition) => condition).join(' && ');
|
|
157
|
+
yield `(${path}.${propertyKey} === undefined ? true : (${expr}))`;
|
|
161
158
|
}
|
|
162
159
|
}
|
|
163
160
|
}
|
|
164
161
|
function* Promise(schema, path) {
|
|
165
|
-
yield
|
|
162
|
+
yield `(typeof value === 'object' && typeof ${path}.then === 'function')`;
|
|
166
163
|
}
|
|
167
164
|
function* Record(schema, path) {
|
|
168
|
-
yield
|
|
165
|
+
yield `(typeof ${path} === 'object' && ${path} !== null && !Array.isArray(${path}))`;
|
|
169
166
|
const [keyPattern, valueSchema] = globalThis.Object.entries(schema.patternProperties)[0];
|
|
170
167
|
const local = PushLocal(`const local = new RegExp(/${keyPattern}/)`);
|
|
171
|
-
yield
|
|
172
|
-
const expr = [...Visit(valueSchema, 'value')].map((
|
|
173
|
-
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}))`;
|
|
174
171
|
}
|
|
175
172
|
function* Ref(schema, path) {
|
|
176
173
|
// reference: referenced schemas can originate from either additional
|
|
@@ -185,48 +182,48 @@ var TypeCompiler;
|
|
|
185
182
|
PushLocal(body);
|
|
186
183
|
}
|
|
187
184
|
const func = CreateFunctionName(schema.$ref);
|
|
188
|
-
yield
|
|
185
|
+
yield `(${func}(${path}))`;
|
|
189
186
|
}
|
|
190
187
|
function* Self(schema, path) {
|
|
191
188
|
const func = CreateFunctionName(schema.$ref);
|
|
192
|
-
yield
|
|
189
|
+
yield `(${func}(${path}))`;
|
|
193
190
|
}
|
|
194
191
|
function* String(schema, path) {
|
|
195
|
-
yield
|
|
192
|
+
yield `(typeof ${path} === 'string')`;
|
|
196
193
|
if (schema.pattern !== undefined) {
|
|
197
194
|
const local = PushLocal(`const local = new RegExp('${schema.pattern}');`);
|
|
198
|
-
yield
|
|
195
|
+
yield `(${local}.test(${path}))`;
|
|
199
196
|
}
|
|
200
197
|
}
|
|
201
198
|
function* Tuple(schema, path) {
|
|
202
|
-
yield
|
|
199
|
+
yield `(Array.isArray(${path}))`;
|
|
203
200
|
if (schema.items === undefined)
|
|
204
|
-
return yield
|
|
205
|
-
yield
|
|
201
|
+
return yield `(${path}.length === 0)`;
|
|
202
|
+
yield `(${path}.length === ${schema.maxItems})`;
|
|
206
203
|
for (let i = 0; i < schema.items.length; i++) {
|
|
207
|
-
const expr = [...Visit(schema.items[i], `${path}[${i}]`)].map((condition) => condition
|
|
208
|
-
yield
|
|
204
|
+
const expr = [...Visit(schema.items[i], `${path}[${i}]`)].map((condition) => condition).join(' && ');
|
|
205
|
+
yield `(${expr})`;
|
|
209
206
|
}
|
|
210
207
|
}
|
|
211
208
|
function* Undefined(schema, path) {
|
|
212
|
-
yield
|
|
209
|
+
yield `${path} === undefined`;
|
|
213
210
|
}
|
|
214
211
|
function* Union(schema, path) {
|
|
215
|
-
const exprs = schema.anyOf.map((schema) => [...Visit(schema, path)].map((
|
|
216
|
-
yield
|
|
212
|
+
const exprs = schema.anyOf.map((schema) => [...Visit(schema, path)].map((condition) => condition).join(' && '));
|
|
213
|
+
yield `(${exprs.join(' || ')})`;
|
|
217
214
|
}
|
|
218
215
|
function* Uint8Array(schema, path) {
|
|
219
|
-
yield
|
|
216
|
+
yield `(${path} instanceof Uint8Array)`;
|
|
220
217
|
if (schema.maxByteLength)
|
|
221
|
-
yield
|
|
218
|
+
yield `(${path}.length <= ${schema.maxByteLength})`;
|
|
222
219
|
if (schema.minByteLength)
|
|
223
|
-
yield
|
|
220
|
+
yield `(${path}.length >= ${schema.minByteLength})`;
|
|
224
221
|
}
|
|
225
222
|
function* Unknown(schema, path) {
|
|
226
|
-
yield
|
|
223
|
+
yield '(true)';
|
|
227
224
|
}
|
|
228
225
|
function* Void(schema, path) {
|
|
229
|
-
yield
|
|
226
|
+
yield `(${path} === null)`;
|
|
230
227
|
}
|
|
231
228
|
function* Visit(schema, path) {
|
|
232
229
|
// reference: referenced schemas can originate from either additional
|
|
@@ -238,7 +235,7 @@ var TypeCompiler;
|
|
|
238
235
|
const name = CreateFunctionName(schema.$id);
|
|
239
236
|
const body = CreateFunction(name, conditions);
|
|
240
237
|
PushLocal(body);
|
|
241
|
-
yield
|
|
238
|
+
yield `(${name}(${path}))`;
|
|
242
239
|
return;
|
|
243
240
|
}
|
|
244
241
|
const anySchema = schema;
|
|
@@ -324,11 +321,11 @@ var TypeCompiler;
|
|
|
324
321
|
return `check_${$id.replace(/-/g, '_')}`;
|
|
325
322
|
}
|
|
326
323
|
function CreateFunction(name, conditions) {
|
|
327
|
-
const
|
|
328
|
-
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}`;
|
|
329
326
|
}
|
|
330
327
|
// -------------------------------------------------------------------
|
|
331
|
-
//
|
|
328
|
+
// Compile
|
|
332
329
|
// -------------------------------------------------------------------
|
|
333
330
|
function Build(schema, additional = []) {
|
|
334
331
|
ClearLocals();
|
|
@@ -337,11 +334,11 @@ var TypeCompiler;
|
|
|
337
334
|
const locals = GetLocals();
|
|
338
335
|
return `${locals.join('\n')}\nreturn ${CreateFunction('check', conditions)}`;
|
|
339
336
|
}
|
|
340
|
-
/** Compiles
|
|
337
|
+
/** Compiles the given type for runtime type checking. This compiler only accepts known TypeBox types non-inclusive of unsafe types. */
|
|
341
338
|
function Compile(schema, additional = []) {
|
|
342
339
|
const code = Build(schema, additional);
|
|
343
340
|
const func = globalThis.Function(code);
|
|
344
|
-
return new TypeCheck(schema, func());
|
|
341
|
+
return new TypeCheck(schema, func(), code);
|
|
345
342
|
}
|
|
346
343
|
TypeCompiler.Compile = Compile;
|
|
347
344
|
})(TypeCompiler = exports.TypeCompiler || (exports.TypeCompiler = {}));
|