@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.
@@ -1,11 +1,5 @@
1
1
  import * as Types from '../typebox';
2
- export declare type CheckFunction = (value: unknown) => CheckOk | CheckFail;
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
- constructor(schema: T, checkFunc: CheckFunction);
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
- interface Condition {
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
  }
@@ -45,22 +45,23 @@ exports.TypeCheckAssertError = TypeCheckAssertError;
45
45
  class TypeCheck {
46
46
  schema;
47
47
  checkFunc;
48
- constructor(schema, checkFunc) {
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
- const result = this.checkFunc(value);
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
- // The return type for this function should be 'asserts value is Static<T>' but due
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 CreateCondition(schema, path, '(true)');
78
+ yield '(true)';
84
79
  }
85
80
  function* Array(schema, path) {
86
- const expr = [...Visit(schema.items, `value`)].map((condition) => condition.expr).join(' && ');
87
- yield CreateCondition(schema, path, `(Array.isArray(${path}) && ${path}.every(value => ${expr}))`);
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 CreateCondition(schema, path, `(typeof ${path} === 'boolean')`);
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 CreateCondition(schema, path, `(typeof ${path} === 'function')`);
91
+ yield `(typeof ${path} === 'function')`;
97
92
  }
98
93
  function* Integer(schema, path) {
99
- yield CreateCondition(schema, path, `(typeof ${path} === 'number' && Number.isInteger(${path}))`);
94
+ yield `(typeof ${path} === 'number' && Number.isInteger(${path}))`;
100
95
  if (schema.multipleOf)
101
- yield CreateCondition(schema, path, `(${path} % ${schema.multipleOf} === 0)`);
96
+ yield `(${path} % ${schema.multipleOf} === 0)`;
102
97
  if (schema.exclusiveMinimum)
103
- yield CreateCondition(schema, path, `(${path} < ${schema.exclusiveMinimum})`);
98
+ yield `(${path} < ${schema.exclusiveMinimum})`;
104
99
  if (schema.exclusiveMaximum)
105
- yield CreateCondition(schema, path, `(${path} < ${schema.exclusiveMaximum})`);
100
+ yield `(${path} < ${schema.exclusiveMaximum})`;
106
101
  if (schema.minimum)
107
- yield CreateCondition(schema, path, `(${path} >= ${schema.minimum})`);
102
+ yield `(${path} >= ${schema.minimum})`;
108
103
  if (schema.maximum)
109
- yield CreateCondition(schema, path, `(${path} <= ${schema.maximum})`);
104
+ yield `(${path} <= ${schema.maximum})`;
110
105
  }
111
106
  function* Literal(schema, path) {
112
107
  if (typeof schema.const === 'string') {
113
- yield CreateCondition(schema, path, `(${path} === '${schema.const}')`);
108
+ yield `(${path} === '${schema.const}')`;
114
109
  }
115
110
  else {
116
- yield CreateCondition(schema, path, `(${path} === ${schema.const})`);
111
+ yield `(${path} === ${schema.const})`;
117
112
  }
118
113
  }
119
114
  function* Null(schema, path) {
120
- yield CreateCondition(schema, path, `(${path} === null)`);
115
+ yield `(${path} === null)`;
121
116
  }
122
117
  function* Number(schema, path) {
123
- yield CreateCondition(schema, path, `(typeof ${path} === 'number')`);
118
+ yield `(typeof ${path} === 'number')`;
124
119
  if (schema.multipleOf)
125
- yield CreateCondition(schema, path, `(${path} % ${schema.multipleOf} === 0)`);
120
+ yield `(${path} % ${schema.multipleOf} === 0)`;
126
121
  if (schema.exclusiveMinimum)
127
- yield CreateCondition(schema, path, `(${path} < ${schema.exclusiveMinimum})`);
122
+ yield `(${path} < ${schema.exclusiveMinimum})`;
128
123
  if (schema.exclusiveMaximum)
129
- yield CreateCondition(schema, path, `(${path} < ${schema.exclusiveMaximum})`);
124
+ yield `(${path} < ${schema.exclusiveMaximum})`;
130
125
  if (schema.minimum)
131
- yield CreateCondition(schema, path, `(${path} >= ${schema.minimum})`);
126
+ yield `(${path} >= ${schema.minimum})`;
132
127
  if (schema.maximum)
133
- yield CreateCondition(schema, path, `(${path} <= ${schema.maximum})`);
128
+ yield `(${path} <= ${schema.maximum})`;
134
129
  }
135
130
  function* Object(schema, path) {
136
- yield CreateCondition(schema, path, `(typeof ${path} === 'object' && ${path} !== null && !Array.isArray(${path}))`);
131
+ yield `(typeof ${path} === 'object' && ${path} !== null && !Array.isArray(${path}))`;
137
132
  if (schema.minProperties !== undefined)
138
- yield CreateCondition(schema, path, `(Object.keys(${path}).length >= ${schema.minProperties})`);
133
+ yield `(Object.keys(${path}).length >= ${schema.minProperties})`;
139
134
  if (schema.maxProperties !== undefined)
140
- yield CreateCondition(schema, path, `(Object.keys(${path}).length <= ${schema.maxProperties})`);
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 CreateCondition(schema, path, `(Object.keys(${path}).length === ${propertyKeys.length})`);
143
+ yield `(Object.keys(${path}).length === ${propertyKeys.length})`;
149
144
  }
150
145
  else {
151
146
  const keys = `[${propertyKeys.map((key) => `'${key}'`).join(', ')}]`;
152
- yield CreateCondition(schema, path, `(Object.keys(${path}).every(key => ${keys}.includes(key)))`);
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.expr).join(' && ');
162
- yield CreateCondition(schema, `${path}.${propertyKey}`, `(${path}.${propertyKey} === undefined ? true : (${expr}))`);
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 CreateCondition(schema, path, `(typeof value === 'object' && typeof ${path}.then === 'function')`);
162
+ yield `(typeof value === 'object' && typeof ${path}.then === 'function')`;
168
163
  }
169
164
  function* Record(schema, path) {
170
- yield CreateCondition(schema, path, `(typeof ${path} === 'object' && ${path} !== null && !Array.isArray(${path}))`);
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 CreateCondition(schema, path, `(Object.keys(${path}).every(key => ${local}.test(key)))`);
174
- const expr = [...Visit(valueSchema, 'value')].map((cond) => cond.expr).join(' && ');
175
- yield CreateCondition(schema, path, `(Object.values(${path}).every(value => ${expr}))`);
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 CreateCondition(schema, path, `(${func}(${path}).ok)`);
185
+ yield `(${func}(${path}))`;
191
186
  }
192
187
  function* Self(schema, path) {
193
188
  const func = CreateFunctionName(schema.$ref);
194
- yield CreateCondition(schema, path, `(${func}(${path}).ok)`);
189
+ yield `(${func}(${path}))`;
195
190
  }
196
191
  function* String(schema, path) {
197
- yield CreateCondition(schema, path, `(typeof ${path} === 'string')`);
192
+ yield `(typeof ${path} === 'string')`;
198
193
  if (schema.pattern !== undefined) {
199
194
  const local = PushLocal(`const local = new RegExp('${schema.pattern}');`);
200
- yield CreateCondition(schema, path, `(${local}.test(${path}))`);
195
+ yield `(${local}.test(${path}))`;
201
196
  }
202
197
  }
203
198
  function* Tuple(schema, path) {
204
- yield CreateCondition(schema, path, `(Array.isArray(${path}))`);
199
+ yield `(Array.isArray(${path}))`;
205
200
  if (schema.items === undefined)
206
- return yield CreateCondition(schema, path, `(${path}.length === 0)`);
207
- yield CreateCondition(schema, path, `(${path}.length === ${schema.maxItems})`);
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.expr).join(' && ');
210
- yield CreateCondition(schema, path, `(${expr})`);
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 CreateCondition(schema, path, `${path} === undefined`);
209
+ yield `${path} === undefined`;
215
210
  }
216
211
  function* Union(schema, path) {
217
- const exprs = schema.anyOf.map((schema) => [...Visit(schema, path)].map((cond) => cond.expr).join(' && '));
218
- yield CreateCondition(schema, path, `(${exprs.join(' || ')})`);
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 CreateCondition(schema, path, `(${path} instanceof Uint8Array)`);
216
+ yield `(${path} instanceof Uint8Array)`;
222
217
  if (schema.maxByteLength)
223
- yield CreateCondition(schema, path, `(${path}.length <= ${schema.maxByteLength})`);
218
+ yield `(${path}.length <= ${schema.maxByteLength})`;
224
219
  if (schema.minByteLength)
225
- yield CreateCondition(schema, path, `(${path}.length >= ${schema.minByteLength})`);
220
+ yield `(${path}.length >= ${schema.minByteLength})`;
226
221
  }
227
222
  function* Unknown(schema, path) {
228
- yield CreateCondition(schema, path, '(true)');
223
+ yield '(true)';
229
224
  }
230
225
  function* Void(schema, path) {
231
- yield CreateCondition(schema, path, `(${path} === null)`);
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 CreateCondition(schema, path, `(${name}(${path}).ok)`);
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 statements = conditions.map((condition, index) => ` if(!${condition.expr}) { return { ok: false } }`);
330
- return `function ${name}(value) {\n${statements.join('\n')}\n return { ok: true }\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
- // Compiler
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 a type into validation function */
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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sinclair/typebox",
3
- "version": "0.24.0",
3
+ "version": "0.24.3",
4
4
  "description": "JSONSchema Type Builder with Static Type Resolution for TypeScript",
5
5
  "keywords": [
6
6
  "json-schema",
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]: 'Unknown';
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?: SchemaOptions): TUnsafe<T>;
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]: 'Unknown' });
296
+ return this.Create({ ...options, [exports.Kind]: options[exports.Kind] || 'Unsafe' });
297
297
  }
298
298
  /** Creates a void type */
299
299
  Void(options = {}) {