@sinclair/typebox 0.28.15 → 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.
@@ -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
  }
@@ -199,14 +199,16 @@ var TypeCompiler;
199
199
  yield 'true';
200
200
  }
201
201
  function* Array(schema, references, value) {
202
- const expression = CreateExpression(schema.items, references, 'value');
202
+ yield `Array.isArray(${value})`;
203
203
  if (IsNumber(schema.minItems))
204
204
  yield `${value}.length >= ${schema.minItems}`;
205
205
  if (IsNumber(schema.maxItems))
206
206
  yield `${value}.length <= ${schema.maxItems}`;
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
- yield `Array.isArray(${value}) && ${value}.every(value => ${expression})`;
209
+ const expression = CreateExpression(schema.items, references, 'value');
210
+ const parameter = CreateParameter('value');
211
+ yield `${value}.every((${parameter}) => ${expression})`;
210
212
  }
211
213
  function* BigInt(schema, references, value) {
212
214
  yield `(typeof ${value} === 'bigint')`;
@@ -222,7 +224,7 @@ var TypeCompiler;
222
224
  yield `${value} <= BigInt(${schema.maximum})`;
223
225
  }
224
226
  function* Boolean(schema, references, value) {
225
- yield `typeof ${value} === 'boolean'`;
227
+ yield `(typeof ${value} === 'boolean')`;
226
228
  }
227
229
  function* Constructor(schema, references, value) {
228
230
  yield* Visit(schema.returns, references, `${value}.prototype`);
@@ -239,7 +241,7 @@ var TypeCompiler;
239
241
  yield `${value}.getTime() <= ${schema.maximumTimestamp}`;
240
242
  }
241
243
  function* Function(schema, references, value) {
242
- yield `typeof ${value} === 'function'`;
244
+ yield `(typeof ${value} === 'function')`;
243
245
  }
244
246
  function* Integer(schema, references, value) {
245
247
  yield `(typeof ${value} === 'number' && Number.isInteger(${value}))`;
@@ -259,23 +261,23 @@ var TypeCompiler;
259
261
  if (schema.unevaluatedProperties === false) {
260
262
  const keyCheck = PushLocal(`${new RegExp(Types.KeyResolver.ResolvePattern(schema))};`);
261
263
  const check2 = `Object.getOwnPropertyNames(${value}).every(key => ${keyCheck}.test(key))`;
262
- yield `${check1} && ${check2}`;
264
+ yield `(${check1} && ${check2})`;
263
265
  }
264
266
  else if (Types.TypeGuard.TSchema(schema.unevaluatedProperties)) {
265
267
  const keyCheck = PushLocal(`${new RegExp(Types.KeyResolver.ResolvePattern(schema))};`);
266
268
  const check2 = `Object.getOwnPropertyNames(${value}).every(key => ${keyCheck}.test(key) || ${CreateExpression(schema.unevaluatedProperties, references, `${value}[key]`)})`;
267
- yield `${check1} && ${check2}`;
269
+ yield `(${check1} && ${check2})`;
268
270
  }
269
271
  else {
270
- yield `${check1}`;
272
+ yield `(${check1})`;
271
273
  }
272
274
  }
273
275
  function* Literal(schema, references, value) {
274
276
  if (typeof schema.const === 'number' || typeof schema.const === 'boolean') {
275
- yield `${value} === ${schema.const}`;
277
+ yield `(${value} === ${schema.const})`;
276
278
  }
277
279
  else {
278
- yield `${value} === '${schema.const}'`;
280
+ yield `(${value} === '${schema.const}')`;
279
281
  }
280
282
  }
281
283
  function* Never(schema, references, value) {
@@ -287,7 +289,7 @@ var TypeCompiler;
287
289
  yield `!${left} && ${right}`;
288
290
  }
289
291
  function* Null(schema, references, value) {
290
- yield `${value} === null`;
292
+ yield `(${value} === null)`;
291
293
  }
292
294
  function* Number(schema, references, value) {
293
295
  yield IsNumberCheck(value);
@@ -358,10 +360,10 @@ var TypeCompiler;
358
360
  if (index === -1)
359
361
  throw new TypeCompilerDereferenceError(schema);
360
362
  const target = references[index];
361
- // Reference: If we have seen this reference before we can just yield and return
362
- // the function call. If this isn't the case we defer to visit to generate and
363
- // set the function for subsequent passes. Consider for refactor.
364
- if (state_local_function_names.has(schema.$ref))
363
+ // Reference: If we have seen this reference before we can just yield and
364
+ // return the function call. If this isn't the case we defer to visit to
365
+ // generate and set the function for subsequent passes.
366
+ if (state.functions.has(schema.$ref))
365
367
  return yield `${CreateFunctionName(schema.$ref)}(${value})`;
366
368
  yield* Visit(target, references, value);
367
369
  }
@@ -392,7 +394,7 @@ var TypeCompiler;
392
394
  yield `${func}(${value})`;
393
395
  }
394
396
  function* Tuple(schema, references, value) {
395
- yield `(Array.isArray(${value}))`;
397
+ yield `Array.isArray(${value})`;
396
398
  if (schema.items === undefined)
397
399
  return yield `${value}.length === 0`;
398
400
  yield `(${value}.length === ${schema.maxItems})`;
@@ -422,21 +424,24 @@ var TypeCompiler;
422
424
  yield IsVoidCheck(value);
423
425
  }
424
426
  function* UserDefined(schema, references, value) {
425
- const schema_key = `schema_key_${state_remote_custom_types.size}`;
426
- state_remote_custom_types.set(schema_key, schema);
427
+ const schema_key = `schema_key_${state.customs.size}`;
428
+ state.customs.set(schema_key, schema);
427
429
  yield `custom('${schema[Types.Kind]}', '${schema_key}', ${value})`;
428
430
  }
429
431
  function* Visit(schema, references, value, root = false) {
430
432
  const references_ = IsString(schema.$id) ? [...references, schema] : references;
431
433
  const schema_ = schema;
432
- // Rule: Types with identifiers are hoisted into their own functions. The following will generate a function for the schema
433
- // and yield the call to that function. This call is only made if NOT the root type which allows the generated function to
434
- // yield its expression. The root argument is only true when making calls via CreateFunction(). Note there is potential to
435
- // omit the root argument and conditional by refactoring the logic below. Consider for review.
434
+ // Rule: Types with identifiers are hoisted into their own functions.
435
+ // The following will generate a function for the schema and yield the
436
+ // call to that function. This call is only made if NOT the root type
437
+ // which allows the generated function to yield its expression. The
438
+ // root argument is only true when making calls via CreateFunction().
439
+ // Note there is potential to omit the root argument and conditional
440
+ // by refactoring the logic below. Consider for review.
436
441
  if (IsString(schema.$id)) {
437
442
  const name = CreateFunctionName(schema.$id);
438
- if (!state_local_function_names.has(schema.$id)) {
439
- state_local_function_names.add(schema.$id);
443
+ if (!state.functions.has(schema.$id)) {
444
+ state.functions.add(schema.$id);
440
445
  const body = CreateFunction(name, schema, references, 'value');
441
446
  PushFunction(body);
442
447
  }
@@ -509,49 +514,58 @@ var TypeCompiler;
509
514
  // -------------------------------------------------------------------
510
515
  // Compiler State
511
516
  // -------------------------------------------------------------------
512
- const state_local_variables = new Set(); // local variables and functions
513
- const state_local_function_names = new Set(); // local function names used call ref validators
514
- const state_remote_custom_types = new Map(); // remote custom types used during compilation
515
- function ResetCompiler() {
516
- state_local_variables.clear();
517
- state_local_function_names.clear();
518
- state_remote_custom_types.clear();
519
- }
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
+ };
520
524
  function CreateExpression(schema, references, value) {
521
525
  return `(${[...Visit(schema, references, value)].join(' && ')})`;
522
526
  }
523
527
  function CreateFunctionName($id) {
524
528
  return `check_${Identifier.Encode($id)}`;
525
529
  }
530
+ function CreateParameter(name) {
531
+ const annotation = state.language === 'typescript' ? ': any' : '';
532
+ return `${name}${annotation}`;
533
+ }
526
534
  function CreateFunction(name, schema, references, value) {
527
535
  const expression = [...Visit(schema, references, value, true)].map((condition) => ` ${condition}`).join(' &&\n');
528
- return `function ${name}(value) {\n return (\n${expression}\n )\n}`;
536
+ const parameter = CreateParameter('value');
537
+ return `function ${name}(${parameter}) {\n return (\n${expression}\n )\n}`;
529
538
  }
530
539
  function PushFunction(functionBody) {
531
- state_local_variables.add(functionBody);
540
+ state.variables.add(functionBody);
532
541
  }
533
542
  function PushLocal(expression) {
534
- const local = `local_${state_local_variables.size}`;
535
- state_local_variables.add(`const ${local} = ${expression}`);
543
+ const local = `local_${state.variables.size}`;
544
+ state.variables.add(`const ${local} = ${expression}`);
536
545
  return local;
537
546
  }
538
547
  function GetLocals() {
539
- return [...state_local_variables.values()];
548
+ return [...state.variables.values()];
540
549
  }
541
550
  // -------------------------------------------------------------------
542
551
  // Compile
543
552
  // -------------------------------------------------------------------
544
553
  function Build(schema, references) {
545
- ResetCompiler();
546
554
  const check = CreateFunction('check', schema, references, 'value'); // interior visit
547
555
  const locals = GetLocals();
556
+ const parameter = CreateParameter('value');
548
557
  // prettier-ignore
549
558
  return IsString(schema.$id) // ensure top level schemas with $id's are hoisted
550
- ? `${locals.join('\n')}\nreturn function check(value) {\n return ${CreateFunctionName(schema.$id)}(value)\n}`
559
+ ? `${locals.join('\n')}\nreturn function check(${parameter}) {\n return ${CreateFunctionName(schema.$id)}(value)\n}`
551
560
  : `${locals.join('\n')}\nreturn ${check}`;
552
561
  }
553
562
  /** Returns the generated assertion code used to validate this type. */
554
- 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();
555
569
  if (!Types.TypeGuard.TSchema(schema))
556
570
  throw new TypeCompilerTypeGuardError(schema);
557
571
  for (const schema of references)
@@ -562,13 +576,13 @@ var TypeCompiler;
562
576
  TypeCompiler.Code = Code;
563
577
  /** Compiles the given type for runtime type checking. This compiler only accepts known TypeBox types non-inclusive of unsafe types. */
564
578
  function Compile(schema, references = []) {
565
- const code = Code(schema, references);
566
- const custom_schemas = new Map(state_remote_custom_types);
579
+ const code = Code(schema, references, { language: 'javascript' });
580
+ const customs = new Map(state.customs);
567
581
  const compiledFunction = globalThis.Function('custom', 'format', 'hash', code);
568
582
  const checkFunction = compiledFunction((kind, schema_key, value) => {
569
- if (!Types.TypeRegistry.Has(kind) || !custom_schemas.has(schema_key))
583
+ if (!Types.TypeRegistry.Has(kind) || !customs.has(schema_key))
570
584
  return false;
571
- const schema = custom_schemas.get(schema_key);
585
+ const schema = customs.get(schema_key);
572
586
  const func = Types.TypeRegistry.Get(kind);
573
587
  return func(schema, value);
574
588
  }, (format, value) => {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sinclair/typebox",
3
- "version": "0.28.15",
3
+ "version": "0.28.17",
4
4
  "description": "JSONSchema Type Builder with Static Type Resolution for TypeScript",
5
5
  "keywords": [
6
6
  "typescript",
package/readme.md CHANGED
@@ -483,7 +483,7 @@ The following table lists the Standard TypeBox types. These types are fully comp
483
483
  │ ]) │ │ ], │
484
484
  │ const T = Type.Tuple([ │ │ additionalItems: false, │
485
485
  | ...Type.Rest(A), │ │ minItems: 4, │
486
- | ...Type.Test(B) │ │ maxItems: 4 │
486
+ | ...Type.Rest(B) │ │ maxItems: 4 │
487
487
  │ ]) │ │ } │
488
488
  │ │ │ │
489
489
  ├────────────────────────────────┼─────────────────────────────┼────────────────────────────────┤
@@ -870,7 +870,7 @@ const T = Type.Object({ // const T = {
870
870
  z: Type.Boolean() // properties: {
871
871
  }) // x: { type: 'number' },
872
872
  // y: { type: 'string' },
873
- // z: { type: 'string' },
873
+ // z: { type: 'string' }
874
874
  // }
875
875
  // }
876
876
 
@@ -896,7 +896,7 @@ const C = Type.Index(T, Type.KeyOf(T)) // const C = {
896
896
 
897
897
  ### Rest Types
898
898
 
899
- Rest parameters are supported with `Type.Rest`. This function is used to extract interior type elements from tuples which enables them to compose with the JavaScript spread operator `...`. This type can be used for tuple concatination as well as for variadic functions.
899
+ Rest parameters are supported with `Type.Rest`. This function is used to extract interior type elements from tuples which enables them to compose with the JavaScript spread operator `...`. This type can be used for tuple concatenation as well as for variadic functions.
900
900
 
901
901
  ```typescript
902
902
  // TypeScript
@@ -908,14 +908,14 @@ type C = [...T, number] // type C = [number, number
908
908
  type F = (...param: C) => void // type F = (
909
909
  // param0: number,
910
910
  // param1: number,
911
- // param2: number,
911
+ // param2: number
912
912
  // ) => void
913
913
 
914
914
  // TypeBox
915
915
 
916
916
  const T = Type.Tuple([ // const T: TTuple<[
917
917
  Type.Number(), // TNumber,
918
- Type.Number() // TNumber,
918
+ Type.Number() // TNumber
919
919
  ]) // ]>
920
920
 
921
921
  const C = Type.Tuple([ // const C: TTuple<[
@@ -1335,7 +1335,7 @@ console.log(C.Code()) // return function check(va
1335
1335
 
1336
1336
  ## TypeSystem
1337
1337
 
1338
- The TypeBox TypeSystem module provides functionality to define types above and beyond the Standard and Extended type sets as well as control various assertion polices. Configurations made to the TypeSystem module are observed by both `TypeCompiler` and `Value` modules.
1338
+ The TypeBox TypeSystem module provides functionality to define types above and beyond the Standard and Extended type sets as well as control various assertion policies. Configurations made to the TypeSystem module are observed by both `TypeCompiler` and `Value` modules.
1339
1339
 
1340
1340
  The TypeSystem module is provided as an optional import.
1341
1341