@sinclair/typebox 0.24.9 → 0.24.12
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 +2 -2
- package/compiler/compiler.js +28 -16
- package/package.json +3 -2
- package/readme.md +147 -74
- package/value/cast.js +1 -1
- package/value/check.js +22 -5
- package/value/create.js +13 -5
- package/value/errors.js +20 -5
package/compiler/compiler.d.ts
CHANGED
|
@@ -3,10 +3,10 @@ import * as Types from '../typebox';
|
|
|
3
3
|
export declare type CheckFunction = (value: unknown) => boolean;
|
|
4
4
|
export declare class TypeCheck<T extends Types.TSchema> {
|
|
5
5
|
private readonly schema;
|
|
6
|
-
private readonly
|
|
6
|
+
private readonly references;
|
|
7
7
|
private readonly checkFunc;
|
|
8
8
|
private readonly code;
|
|
9
|
-
constructor(schema: T,
|
|
9
|
+
constructor(schema: T, references: Types.TSchema[], checkFunc: CheckFunction, code: string);
|
|
10
10
|
/** Returns the generated validation code used to validate this type. */
|
|
11
11
|
Code(): string;
|
|
12
12
|
/** Returns an iterator for each error in this value. */
|
package/compiler/compiler.js
CHANGED
|
@@ -35,12 +35,12 @@ const Types = require("../typebox");
|
|
|
35
35
|
// -------------------------------------------------------------------
|
|
36
36
|
class TypeCheck {
|
|
37
37
|
schema;
|
|
38
|
-
|
|
38
|
+
references;
|
|
39
39
|
checkFunc;
|
|
40
40
|
code;
|
|
41
|
-
constructor(schema,
|
|
41
|
+
constructor(schema, references, checkFunc, code) {
|
|
42
42
|
this.schema = schema;
|
|
43
|
-
this.
|
|
43
|
+
this.references = references;
|
|
44
44
|
this.checkFunc = checkFunc;
|
|
45
45
|
this.code = code;
|
|
46
46
|
}
|
|
@@ -50,7 +50,7 @@ class TypeCheck {
|
|
|
50
50
|
}
|
|
51
51
|
/** Returns an iterator for each error in this value. */
|
|
52
52
|
Errors(value) {
|
|
53
|
-
return errors_1.ValueErrors.Errors(this.schema, this.
|
|
53
|
+
return errors_1.ValueErrors.Errors(this.schema, this.references, value);
|
|
54
54
|
}
|
|
55
55
|
/** Returns true if the value matches the given type. */
|
|
56
56
|
Check(value) {
|
|
@@ -71,8 +71,14 @@ var TypeCompiler;
|
|
|
71
71
|
yield '(true)';
|
|
72
72
|
}
|
|
73
73
|
function* Array(schema, value) {
|
|
74
|
-
const
|
|
75
|
-
|
|
74
|
+
const expression = [...Visit(schema.items, `value`)].map((condition) => condition).join(' && ');
|
|
75
|
+
if (schema.minItems !== undefined)
|
|
76
|
+
yield `(${value}.length >= ${schema.minItems})`;
|
|
77
|
+
if (schema.maxItems !== undefined)
|
|
78
|
+
yield `(${value}.length <= ${schema.maxItems})`;
|
|
79
|
+
if (schema.uniqueItems !== undefined)
|
|
80
|
+
yield `(new Set(${value}).size === ${value}.length)`;
|
|
81
|
+
yield `(Array.isArray(${value}) && ${value}.every(value => ${expression}))`;
|
|
76
82
|
}
|
|
77
83
|
function* Boolean(schema, value) {
|
|
78
84
|
yield `(typeof ${value} === 'boolean')`;
|
|
@@ -85,15 +91,15 @@ var TypeCompiler;
|
|
|
85
91
|
}
|
|
86
92
|
function* Integer(schema, value) {
|
|
87
93
|
yield `(typeof ${value} === 'number' && Number.isInteger(${value}))`;
|
|
88
|
-
if (schema.multipleOf)
|
|
94
|
+
if (schema.multipleOf !== undefined)
|
|
89
95
|
yield `(${value} % ${schema.multipleOf} === 0)`;
|
|
90
|
-
if (schema.exclusiveMinimum)
|
|
96
|
+
if (schema.exclusiveMinimum !== undefined)
|
|
91
97
|
yield `(${value} > ${schema.exclusiveMinimum})`;
|
|
92
|
-
if (schema.exclusiveMaximum)
|
|
98
|
+
if (schema.exclusiveMaximum !== undefined)
|
|
93
99
|
yield `(${value} < ${schema.exclusiveMaximum})`;
|
|
94
|
-
if (schema.minimum)
|
|
100
|
+
if (schema.minimum !== undefined)
|
|
95
101
|
yield `(${value} >= ${schema.minimum})`;
|
|
96
|
-
if (schema.maximum)
|
|
102
|
+
if (schema.maximum !== undefined)
|
|
97
103
|
yield `(${value} <= ${schema.maximum})`;
|
|
98
104
|
}
|
|
99
105
|
function* Literal(schema, value) {
|
|
@@ -109,15 +115,15 @@ var TypeCompiler;
|
|
|
109
115
|
}
|
|
110
116
|
function* Number(schema, value) {
|
|
111
117
|
yield `(typeof ${value} === 'number')`;
|
|
112
|
-
if (schema.multipleOf)
|
|
118
|
+
if (schema.multipleOf !== undefined)
|
|
113
119
|
yield `(${value} % ${schema.multipleOf} === 0)`;
|
|
114
|
-
if (schema.exclusiveMinimum)
|
|
120
|
+
if (schema.exclusiveMinimum !== undefined)
|
|
115
121
|
yield `(${value} > ${schema.exclusiveMinimum})`;
|
|
116
|
-
if (schema.exclusiveMaximum)
|
|
122
|
+
if (schema.exclusiveMaximum !== undefined)
|
|
117
123
|
yield `(${value} < ${schema.exclusiveMaximum})`;
|
|
118
|
-
if (schema.minimum)
|
|
124
|
+
if (schema.minimum !== undefined)
|
|
119
125
|
yield `(${value} >= ${schema.minimum})`;
|
|
120
|
-
if (schema.maximum)
|
|
126
|
+
if (schema.maximum !== undefined)
|
|
121
127
|
yield `(${value} <= ${schema.maximum})`;
|
|
122
128
|
}
|
|
123
129
|
function* Object(schema, value) {
|
|
@@ -183,6 +189,12 @@ var TypeCompiler;
|
|
|
183
189
|
}
|
|
184
190
|
function* String(schema, value) {
|
|
185
191
|
yield `(typeof ${value} === 'string')`;
|
|
192
|
+
if (schema.minLength !== undefined) {
|
|
193
|
+
yield `(${value}.length >= ${schema.minLength})`;
|
|
194
|
+
}
|
|
195
|
+
if (schema.maxLength !== undefined) {
|
|
196
|
+
yield `(${value}.length <= ${schema.maxLength})`;
|
|
197
|
+
}
|
|
186
198
|
if (schema.pattern !== undefined) {
|
|
187
199
|
const local = PushLocal(`const local = new RegExp('${schema.pattern}');`);
|
|
188
200
|
yield `(${local}.test(${value}))`;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@sinclair/typebox",
|
|
3
|
-
"version": "0.24.
|
|
3
|
+
"version": "0.24.12",
|
|
4
4
|
"description": "JSONSchema Type Builder with Static Type Resolution for TypeScript",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"json-schema",
|
|
@@ -21,6 +21,7 @@
|
|
|
21
21
|
"format": "hammer task format",
|
|
22
22
|
"start": "hammer task start",
|
|
23
23
|
"test": "hammer task test",
|
|
24
|
+
"benchmark": "hammer task benchmark",
|
|
24
25
|
"build": "hammer task build",
|
|
25
26
|
"publish": "hammer task publish"
|
|
26
27
|
},
|
|
@@ -29,7 +30,7 @@
|
|
|
29
30
|
"@types/chai": "^4.3.0",
|
|
30
31
|
"@types/mocha": "^9.1.0",
|
|
31
32
|
"@types/node": "^17.0.12",
|
|
32
|
-
"ajv": "^8.
|
|
33
|
+
"ajv": "^8.11.0",
|
|
33
34
|
"ajv-formats": "^2.1.1",
|
|
34
35
|
"chai": "^4.3.5",
|
|
35
36
|
"mocha": "^9.2.0",
|
package/readme.md
CHANGED
|
@@ -9,7 +9,9 @@
|
|
|
9
9
|
<br />
|
|
10
10
|
<br />
|
|
11
11
|
|
|
12
|
-
[](https://badge.fury.io/js/%40sinclair%2Ftypebox)
|
|
12
|
+
[](https://badge.fury.io/js/%40sinclair%2Ftypebox)
|
|
13
|
+
[](https://www.npmjs.com/package/%40sinclair%2Ftypebox)
|
|
14
|
+
[](https://github.com/sinclairzx81/typebox/actions)
|
|
13
15
|
|
|
14
16
|
</div>
|
|
15
17
|
|
|
@@ -339,7 +341,7 @@ The following table outlines the TypeBox mappings between TypeScript and JSON sc
|
|
|
339
341
|
```
|
|
340
342
|
<a name="Modifiers"></a>
|
|
341
343
|
|
|
342
|
-
|
|
344
|
+
## Modifiers
|
|
343
345
|
|
|
344
346
|
TypeBox provides modifiers that can be applied to an objects properties. This allows for `optional` and `readonly` to be applied to that property. The following table illustates how they map between TypeScript and JSON Schema.
|
|
345
347
|
|
|
@@ -383,7 +385,7 @@ TypeBox provides modifiers that can be applied to an objects properties. This al
|
|
|
383
385
|
|
|
384
386
|
<a name="Options"></a>
|
|
385
387
|
|
|
386
|
-
|
|
388
|
+
## Options
|
|
387
389
|
|
|
388
390
|
You can pass additional JSON schema options on the last argument of any given type. The following are some examples.
|
|
389
391
|
|
|
@@ -400,7 +402,7 @@ const T = Type.Array(Type.Integer(), { minItems: 5 })
|
|
|
400
402
|
|
|
401
403
|
<a name="Extended-Types"></a>
|
|
402
404
|
|
|
403
|
-
|
|
405
|
+
## Extended Types
|
|
404
406
|
|
|
405
407
|
In addition to JSON schema types, TypeBox provides several extended types that allow for `function` and `constructor` types to be composed. These additional types are not valid JSON Schema and will not validate using typical JSON Schema validation. However, these types can be used to frame JSON schema and describe callable interfaces that may receive JSON validated data. These types are as follows.
|
|
406
408
|
|
|
@@ -464,9 +466,9 @@ In addition to JSON schema types, TypeBox provides several extended types that a
|
|
|
464
466
|
|
|
465
467
|
<a name="Reference-Types"></a>
|
|
466
468
|
|
|
467
|
-
|
|
469
|
+
## Reference Types
|
|
468
470
|
|
|
469
|
-
|
|
471
|
+
Use `Type.Ref(...)` to create referenced types. The target type must specify an `$id`.
|
|
470
472
|
|
|
471
473
|
```typescript
|
|
472
474
|
const T = Type.String({ $id: 'T' }) // const T = {
|
|
@@ -481,13 +483,13 @@ const R = Type.Ref(T) // const R = {
|
|
|
481
483
|
|
|
482
484
|
<a name="Recursive-Types"></a>
|
|
483
485
|
|
|
484
|
-
|
|
486
|
+
## Recursive Types
|
|
485
487
|
|
|
486
|
-
|
|
488
|
+
Use `Type.Recursive(...)` to create recursive types.
|
|
487
489
|
|
|
488
490
|
```typescript
|
|
489
491
|
const Node = Type.Recursive(Node => Type.Object({ // const Node = {
|
|
490
|
-
id:
|
|
492
|
+
id: Type.String(), // $id: "Node",
|
|
491
493
|
nodes: Type.Array(Node), // type: "object",
|
|
492
494
|
}), { $id: 'Node' }) // properties: {
|
|
493
495
|
// id: {
|
|
@@ -508,19 +510,20 @@ const Node = Type.Recursive(Node => Type.Object({ // const Node = {
|
|
|
508
510
|
|
|
509
511
|
type Node = Static<typeof Node> // type Node = {
|
|
510
512
|
// id: string
|
|
511
|
-
// nodes: ...
|
|
513
|
+
// nodes: ...[]
|
|
512
514
|
// }
|
|
513
515
|
|
|
514
|
-
function
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
516
|
+
function test(node: Node) {
|
|
517
|
+
const id = node.nodes[0].nodes[0].nodes[0] // id is string
|
|
518
|
+
.nodes[0].nodes[0].nodes[0]
|
|
519
|
+
.nodes[0].nodes[0].nodes[0]
|
|
520
|
+
.id
|
|
518
521
|
}
|
|
519
522
|
```
|
|
520
523
|
|
|
521
524
|
<a name="Generic-Types"></a>
|
|
522
525
|
|
|
523
|
-
|
|
526
|
+
## Generic Types
|
|
524
527
|
|
|
525
528
|
Generic types can be created using functions. The following creates a generic `Nullable<T>` type.
|
|
526
529
|
|
|
@@ -552,9 +555,9 @@ type U = Static<typeof U> // type U = number | null
|
|
|
552
555
|
|
|
553
556
|
<a name="Unsafe-Types"></a>
|
|
554
557
|
|
|
555
|
-
|
|
558
|
+
## Unsafe Types
|
|
556
559
|
|
|
557
|
-
|
|
560
|
+
Use `Type.Unsafe(...)` to create custom schemas with user defined inference rules.
|
|
558
561
|
|
|
559
562
|
```typescript
|
|
560
563
|
const T = Type.Unsafe<string>({ type: 'number' }) // const T = {
|
|
@@ -564,7 +567,7 @@ const T = Type.Unsafe<string>({ type: 'number' }) // const T = {
|
|
|
564
567
|
type T = Static<typeof T> // type T = string
|
|
565
568
|
```
|
|
566
569
|
|
|
567
|
-
The `Type.Unsafe(...)` function can be
|
|
570
|
+
The `Type.Unsafe(...)` function can be used to create schemas for validators that require specific schema representations. An example of this would be OpenAPI's `nullable` and `enum` schemas which are not provided by TypeBox. The following demonstrates using `Type.Unsafe(...)` to create these types.
|
|
568
571
|
|
|
569
572
|
```typescript
|
|
570
573
|
import { Type, Static, TSchema } from '@sinclair/typebox'
|
|
@@ -605,9 +608,9 @@ type T = Static<typeof T> // type T = 'A' | 'B' | 'C'
|
|
|
605
608
|
|
|
606
609
|
<a name="Values"></a>
|
|
607
610
|
|
|
608
|
-
|
|
611
|
+
## Values
|
|
609
612
|
|
|
610
|
-
|
|
613
|
+
Use `Value.Create(...)` to generate values from types.
|
|
611
614
|
|
|
612
615
|
```typescript
|
|
613
616
|
import { Value } from '@sinclair/typebox/value'
|
|
@@ -623,8 +626,7 @@ const V = Value.Create(T) // const V = {
|
|
|
623
626
|
// y: 0,
|
|
624
627
|
// }
|
|
625
628
|
```
|
|
626
|
-
|
|
627
|
-
|
|
629
|
+
Use `Value.Cast(...)` to cast a value into a given type.
|
|
628
630
|
```typescript
|
|
629
631
|
import { Value } from '@sinclair/typebox/value'
|
|
630
632
|
import { Type } from '@sinclair/typebox'
|
|
@@ -643,28 +645,26 @@ const C = Value.Cast(T, { x: 1, y: 2, z: 3 }) // const C = { x: 1, y: 2
|
|
|
643
645
|
|
|
644
646
|
<a name="Guards"></a>
|
|
645
647
|
|
|
646
|
-
|
|
648
|
+
## Guards
|
|
647
649
|
|
|
648
|
-
|
|
650
|
+
Use a `TypeGuard` to test if a value meets a TypeBox type specification. Guards can be helpful when reflecting types.
|
|
649
651
|
|
|
650
652
|
```typescript
|
|
651
653
|
import { TypeGuard } from '@sinclair/typebox/guard'
|
|
652
654
|
import { Type } from '@sinclair/typebox'
|
|
653
655
|
|
|
654
|
-
const T
|
|
655
|
-
|
|
656
|
-
const { type } = T // unsafe: type is any
|
|
656
|
+
const T = Type.String()
|
|
657
657
|
|
|
658
658
|
if(TypeGuard.TString(T)) {
|
|
659
659
|
|
|
660
|
-
|
|
660
|
+
// T is TString
|
|
661
661
|
}
|
|
662
662
|
|
|
663
663
|
```
|
|
664
664
|
|
|
665
665
|
<a name="Strict"></a>
|
|
666
666
|
|
|
667
|
-
|
|
667
|
+
## Strict
|
|
668
668
|
|
|
669
669
|
TypeBox schemas contain the `Kind` and `Modifier` symbol properties. These properties are provided to enable runtime type reflection on schemas, as well as helping TypeBox internally compose types. These properties are not strictly valid JSON schema; so in some cases it may be desirable to omit them. TypeBox provides a `Type.Strict()` function that will omit these properties if necessary.
|
|
670
670
|
|
|
@@ -693,7 +693,7 @@ const U = Type.Strict(T) // const U = {
|
|
|
693
693
|
|
|
694
694
|
<a name="Validation"></a>
|
|
695
695
|
|
|
696
|
-
|
|
696
|
+
## Validation
|
|
697
697
|
|
|
698
698
|
TypeBox schemas target JSON Schema draft 6 so any validator capable of draft 6 should be fine. A good library to use for validation in JavaScript environments is [AJV](https://www.npmjs.com/package/ajv). The following example shows setting up AJV 7 to work with TypeBox.
|
|
699
699
|
|
|
@@ -745,7 +745,7 @@ const T = Type.Object({
|
|
|
745
745
|
x: Type.Number(),
|
|
746
746
|
y: Type.Number(),
|
|
747
747
|
z: Type.Number(),
|
|
748
|
-
}
|
|
748
|
+
})
|
|
749
749
|
|
|
750
750
|
//--------------------------------------------------------------------------------------------
|
|
751
751
|
//
|
|
@@ -753,73 +753,146 @@ const T = Type.Object({
|
|
|
753
753
|
//
|
|
754
754
|
//--------------------------------------------------------------------------------------------
|
|
755
755
|
|
|
756
|
-
const
|
|
757
|
-
x: 1,
|
|
758
|
-
y: 2,
|
|
759
|
-
z: 3
|
|
760
|
-
}) // -> true
|
|
756
|
+
const R = ajv.validate(T, { x: 1, y: 2, z: 3 }) // const R = true
|
|
761
757
|
```
|
|
762
758
|
|
|
763
759
|
Please refer to the official AJV [documentation](https://ajv.js.org/guide/getting-started.html) for additional information on using AJV.
|
|
764
760
|
|
|
765
761
|
<a name="Compiler"></a>
|
|
766
762
|
|
|
767
|
-
|
|
763
|
+
## Compiler
|
|
768
764
|
|
|
769
|
-
TypeBox
|
|
765
|
+
TypeBox provides an optional high performance runtime type checker that can be used in applications that require extremely fast validation. This type checker is optimized for TypeBox types only whose schematics are known in advance. If defining custom schemas with `Type.Unsafe<T>` please consider AJV.
|
|
766
|
+
|
|
767
|
+
The following demonstrates its use.
|
|
770
768
|
|
|
771
769
|
```typescript
|
|
772
770
|
import { TypeCompiler } from '@sinclair/typebox/compiler'
|
|
773
771
|
import { Type } from '@sinclair/typebox'
|
|
774
772
|
|
|
775
|
-
const
|
|
776
|
-
x: Type.Number(),
|
|
777
|
-
y: Type.Number(),
|
|
778
|
-
z: Type.Number()
|
|
779
|
-
})
|
|
780
|
-
|
|
781
|
-
const C = TypeCompiler.Compile(T)
|
|
773
|
+
const C = TypeCompiler.Compile(Type.Object({ // const C: TypeCheck<TObject<{
|
|
774
|
+
x: Type.Number(), // x: TNumber;
|
|
775
|
+
y: Type.Number(), // y: TNumber;
|
|
776
|
+
z: Type.Number() // z: TNumber;
|
|
777
|
+
})) // }>>
|
|
782
778
|
|
|
783
|
-
const
|
|
784
|
-
x: 1,
|
|
785
|
-
y: 2,
|
|
786
|
-
z: 3
|
|
787
|
-
}) // -> true
|
|
779
|
+
const R = C.Check({ x: 1, y: 2, z: 3 }) // const R = true
|
|
788
780
|
```
|
|
789
|
-
|
|
781
|
+
|
|
782
|
+
Validation errors can be read with the `Errors(...)` function.
|
|
783
|
+
|
|
790
784
|
```typescript
|
|
791
|
-
const C = TypeCompiler.Compile(Type.Object({
|
|
792
|
-
x: Type.Number(),
|
|
793
|
-
y: Type.Number(),
|
|
794
|
-
z: Type.Number()
|
|
795
|
-
}))
|
|
785
|
+
const C = TypeCompiler.Compile(Type.Object({ // const C: TypeCheck<TObject<{
|
|
786
|
+
x: Type.Number(), // x: TNumber;
|
|
787
|
+
y: Type.Number(), // y: TNumber;
|
|
788
|
+
z: Type.Number() // z: TNumber;
|
|
789
|
+
})) // }>>
|
|
790
|
+
|
|
791
|
+
const value = { }
|
|
792
|
+
|
|
793
|
+
const errors = [...C.Errors(value)] // const errors = [{
|
|
794
|
+
// schema: { type: 'number' },
|
|
795
|
+
// path: '/x',
|
|
796
|
+
// value: undefined,
|
|
797
|
+
// message: 'Expected number'
|
|
798
|
+
// }, {
|
|
799
|
+
// schema: { type: 'number' },
|
|
800
|
+
// path: '/y',
|
|
801
|
+
// value: undefined,
|
|
802
|
+
// message: 'Expected number'
|
|
803
|
+
// }, {
|
|
804
|
+
// schema: { type: 'number' },
|
|
805
|
+
// path: '/z',
|
|
806
|
+
// value: undefined,
|
|
807
|
+
// message: 'Expected number'
|
|
808
|
+
// }]
|
|
809
|
+
```
|
|
796
810
|
|
|
797
|
-
|
|
811
|
+
Compiled routines can be inspected with the `.Code()` function.
|
|
798
812
|
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
813
|
+
```typescript
|
|
814
|
+
const C = TypeCompiler.Compile(Type.String()) // const C: TypeCheck<TString>
|
|
815
|
+
|
|
816
|
+
console.log(C.Code()) // return function check(value) {
|
|
817
|
+
// return (
|
|
818
|
+
// (typeof value === 'string')
|
|
819
|
+
// )
|
|
820
|
+
// }
|
|
804
821
|
```
|
|
805
|
-
|
|
822
|
+
|
|
823
|
+
### Benchmarks
|
|
824
|
+
|
|
825
|
+
This project maintains benchmarks that measure TypeBox and AJV compile and validate performance. These benchmarks can be run locally by cloning this repository and running `npm run benchmark`. Results show for AJV version 8.11.0.
|
|
826
|
+
|
|
827
|
+
#### Validate
|
|
828
|
+
|
|
829
|
+
This benchmark measures overall validate performance. You can review this benchmark [here](https://github.com/sinclairzx81/typebox/blob/master/benchmark/check.ts).
|
|
806
830
|
|
|
807
831
|
```typescript
|
|
808
|
-
|
|
832
|
+
┌──────────────────┬────────────┬────────────┬────────────┬────────────────────────┐
|
|
833
|
+
│ (index) │ Iterations │ Ajv │ TypeBox │ Measured │
|
|
834
|
+
├──────────────────┼────────────┼────────────┼────────────┼────────────────────────┤
|
|
835
|
+
│ Number │ 16000000 │ '74ms ' │ '66ms ' │ '1.12 x faster ' │
|
|
836
|
+
│ String │ 16000000 │ '277ms ' │ '154ms ' │ '1.80 x faster ' │
|
|
837
|
+
│ Boolean │ 16000000 │ '263ms ' │ '152ms ' │ '1.73 x faster ' │
|
|
838
|
+
│ Null │ 16000000 │ '275ms ' │ '153ms ' │ '1.80 x faster ' │
|
|
839
|
+
│ RegEx │ 16000000 │ '658ms ' │ '548ms ' │ '1.20 x faster ' │
|
|
840
|
+
│ ObjectA │ 16000000 │ '453ms ' │ '319ms ' │ '1.42 x faster ' │
|
|
841
|
+
│ ObjectB │ 16000000 │ '676ms ' │ '514ms ' │ '1.32 x faster ' │
|
|
842
|
+
│ Tuple │ 16000000 │ '320ms ' │ '193ms ' │ '1.66 x faster ' │
|
|
843
|
+
│ Union │ 16000000 │ '331ms ' │ '211ms ' │ '1.57 x faster ' │
|
|
844
|
+
│ Recursive │ 16000000 │ '6010ms ' │ '2368ms ' │ '2.54 x faster ' │
|
|
845
|
+
│ Vector4 │ 16000000 │ '313ms ' │ '168ms ' │ '1.86 x faster ' │
|
|
846
|
+
│ Matrix4 │ 16000000 │ '604ms ' │ '419ms ' │ '1.44 x faster ' │
|
|
847
|
+
│ Literal_String │ 16000000 │ '281ms ' │ '154ms ' │ '1.82 x faster ' │
|
|
848
|
+
│ Literal_Number │ 16000000 │ '268ms ' │ '150ms ' │ '1.79 x faster ' │
|
|
849
|
+
│ Literal_Boolean │ 16000000 │ '273ms ' │ '149ms ' │ '1.83 x faster ' │
|
|
850
|
+
│ Array_Number │ 16000000 │ '470ms ' │ '235ms ' │ '2.00 x faster ' │
|
|
851
|
+
│ Array_String │ 16000000 │ '462ms ' │ '303ms ' │ '1.52 x faster ' │
|
|
852
|
+
│ Array_Boolean │ 16000000 │ '527ms ' │ '352ms ' │ '1.50 x faster ' │
|
|
853
|
+
│ Array_ObjectA │ 16000000 │ '43852ms ' │ '28042ms ' │ '1.56 x faster ' │
|
|
854
|
+
│ Array_ObjectB │ 16000000 │ '48025ms ' │ '33205ms ' │ '1.45 x faster ' │
|
|
855
|
+
│ Array_Tuple │ 16000000 │ '1424ms ' │ '1095ms ' │ '1.30 x faster ' │
|
|
856
|
+
│ Array_Vector4 │ 16000000 │ '1495ms ' │ '808ms ' │ '1.85 x faster ' │
|
|
857
|
+
│ Array_Matrix4 │ 16000000 │ '6129ms ' │ '4969ms ' │ '1.23 x faster ' │
|
|
858
|
+
└──────────────────┴────────────┴────────────┴────────────┴────────────────────────┘
|
|
859
|
+
```
|
|
809
860
|
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
861
|
+
#### Compile
|
|
862
|
+
|
|
863
|
+
This benchmark measures schema compilation time. You can review this benchmark [here](https://github.com/sinclairzx81/typebox/blob/master/benchmark/compile.ts).
|
|
864
|
+
|
|
865
|
+
```typescript
|
|
866
|
+
┌──────────────────┬────────────┬────────────┬────────────┬────────────────────────┐
|
|
867
|
+
│ (index) │ Iterations │ Ajv │ TypeBox │ Measured │
|
|
868
|
+
├──────────────────┼────────────┼────────────┼────────────┼────────────────────────┤
|
|
869
|
+
│ Number │ 2000 │ '400ms ' │ '8ms ' │ '50.00 x faster ' │
|
|
870
|
+
│ String │ 2000 │ '324ms ' │ '7ms ' │ '46.29 x faster ' │
|
|
871
|
+
│ Boolean │ 2000 │ '325ms ' │ '10ms ' │ '32.50 x faster ' │
|
|
872
|
+
│ Null │ 2000 │ '271ms ' │ '4ms ' │ '67.75 x faster ' │
|
|
873
|
+
│ RegEx │ 2000 │ '493ms ' │ '11ms ' │ '44.82 x faster ' │
|
|
874
|
+
│ ObjectA │ 2000 │ '2998ms ' │ '27ms ' │ '111.04 x faster ' │
|
|
875
|
+
│ ObjectB │ 2000 │ '3058ms ' │ '28ms ' │ '109.21 x faster ' │
|
|
876
|
+
│ Tuple │ 2000 │ '1306ms ' │ '19ms ' │ '68.74 x faster ' │
|
|
877
|
+
│ Union │ 2000 │ '1450ms ' │ '18ms ' │ '80.56 x faster ' │
|
|
878
|
+
│ Vector4 │ 2000 │ '1633ms ' │ '12ms ' │ '136.08 x faster ' │
|
|
879
|
+
│ Matrix4 │ 2000 │ '984ms ' │ '10ms ' │ '98.40 x faster ' │
|
|
880
|
+
│ Literal_String │ 2000 │ '376ms ' │ '5ms ' │ '75.20 x faster ' │
|
|
881
|
+
│ Literal_Number │ 2000 │ '396ms ' │ '7ms ' │ '56.57 x faster ' │
|
|
882
|
+
│ Literal_Boolean │ 2000 │ '383ms ' │ '3ms ' │ '127.67 x faster ' │
|
|
883
|
+
│ Array_Number │ 2000 │ '748ms ' │ '6ms ' │ '124.67 x faster ' │
|
|
884
|
+
│ Array_String │ 2000 │ '774ms ' │ '5ms ' │ '154.80 x faster ' │
|
|
885
|
+
│ Array_Boolean │ 2000 │ '814ms ' │ '8ms ' │ '101.75 x faster ' │
|
|
886
|
+
│ Array_ObjectA │ 2000 │ '3675ms ' │ '24ms ' │ '153.13 x faster ' │
|
|
887
|
+
│ Array_ObjectB │ 2000 │ '4364ms ' │ '30ms ' │ '145.47 x faster ' │
|
|
888
|
+
│ Array_Tuple │ 2000 │ '2236ms ' │ '13ms ' │ '172.00 x faster ' │
|
|
889
|
+
│ Array_Vector4 │ 2000 │ '1772ms ' │ '15ms ' │ '118.13 x faster ' │
|
|
890
|
+
│ Array_Matrix4 │ 2000 │ '1612ms ' │ '10ms ' │ '161.20 x faster ' │
|
|
891
|
+
└──────────────────┴────────────┴────────────┴────────────┴────────────────────────┘
|
|
819
892
|
```
|
|
820
893
|
|
|
821
894
|
<a name="Contribute"></a>
|
|
822
895
|
|
|
823
|
-
|
|
896
|
+
## Contribute
|
|
824
897
|
|
|
825
898
|
TypeBox is open to community contribution. Please ensure you submit an open issue before submitting your pull request. The TypeBox project preferences open community discussion prior to accepting new features.
|
package/value/cast.js
CHANGED
|
@@ -238,7 +238,7 @@ var ValueCast;
|
|
|
238
238
|
case 'Void':
|
|
239
239
|
return Void(anySchema, anyReferences, value);
|
|
240
240
|
default:
|
|
241
|
-
throw Error(`Unknown schema kind '${schema[Types.Kind]}'`);
|
|
241
|
+
throw Error(`ValueCast.Visit: Unknown schema kind '${schema[Types.Kind]}'`);
|
|
242
242
|
}
|
|
243
243
|
}
|
|
244
244
|
ValueCast.Visit = Visit;
|
package/value/check.js
CHANGED
|
@@ -38,6 +38,15 @@ var ValueCheck;
|
|
|
38
38
|
if (!globalThis.Array.isArray(value)) {
|
|
39
39
|
return false;
|
|
40
40
|
}
|
|
41
|
+
if (schema.minItems !== undefined && !(value.length >= schema.minItems)) {
|
|
42
|
+
return false;
|
|
43
|
+
}
|
|
44
|
+
if (schema.maxItems !== undefined && !(value.length <= schema.maxItems)) {
|
|
45
|
+
return false;
|
|
46
|
+
}
|
|
47
|
+
if (schema.uniqueItems === true && !(new Set(value).size === value.length)) {
|
|
48
|
+
return false;
|
|
49
|
+
}
|
|
41
50
|
return value.every((val) => Visit(schema.items, references, val));
|
|
42
51
|
}
|
|
43
52
|
function Boolean(schema, references, value) {
|
|
@@ -56,19 +65,19 @@ var ValueCheck;
|
|
|
56
65
|
if (!globalThis.Number.isInteger(value)) {
|
|
57
66
|
return false;
|
|
58
67
|
}
|
|
59
|
-
if (schema.multipleOf && !(value % schema.multipleOf === 0)) {
|
|
68
|
+
if (schema.multipleOf !== undefined && !(value % schema.multipleOf === 0)) {
|
|
60
69
|
return false;
|
|
61
70
|
}
|
|
62
|
-
if (schema.exclusiveMinimum && !(value > schema.exclusiveMinimum)) {
|
|
71
|
+
if (schema.exclusiveMinimum !== undefined && !(value > schema.exclusiveMinimum)) {
|
|
63
72
|
return false;
|
|
64
73
|
}
|
|
65
|
-
if (schema.exclusiveMaximum && !(value < schema.exclusiveMaximum)) {
|
|
74
|
+
if (schema.exclusiveMaximum !== undefined && !(value < schema.exclusiveMaximum)) {
|
|
66
75
|
return false;
|
|
67
76
|
}
|
|
68
|
-
if (schema.minimum && !(value >= schema.minimum)) {
|
|
77
|
+
if (schema.minimum !== undefined && !(value >= schema.minimum)) {
|
|
69
78
|
return false;
|
|
70
79
|
}
|
|
71
|
-
if (schema.maximum && !(value <= schema.maximum)) {
|
|
80
|
+
if (schema.maximum !== undefined && !(value <= schema.maximum)) {
|
|
72
81
|
return false;
|
|
73
82
|
}
|
|
74
83
|
return true;
|
|
@@ -176,6 +185,14 @@ var ValueCheck;
|
|
|
176
185
|
if (!(typeof value === 'string')) {
|
|
177
186
|
return false;
|
|
178
187
|
}
|
|
188
|
+
if (schema.minLength !== undefined) {
|
|
189
|
+
if (!(value.length >= schema.minLength))
|
|
190
|
+
return false;
|
|
191
|
+
}
|
|
192
|
+
if (schema.maxLength !== undefined) {
|
|
193
|
+
if (!(value.length <= schema.maxLength))
|
|
194
|
+
return false;
|
|
195
|
+
}
|
|
179
196
|
if (schema.pattern !== undefined) {
|
|
180
197
|
const regex = new RegExp(schema.pattern);
|
|
181
198
|
if (!regex.test(value))
|
package/value/create.js
CHANGED
|
@@ -40,7 +40,10 @@ var ValueCreate;
|
|
|
40
40
|
}
|
|
41
41
|
}
|
|
42
42
|
function Array(schema, references) {
|
|
43
|
-
if (schema.default
|
|
43
|
+
if (schema.uniqueItems === true && schema.default === undefined) {
|
|
44
|
+
throw new Error('ValueCreate.Array: Arrays with uniqueItems require a default value');
|
|
45
|
+
}
|
|
46
|
+
else if (schema.default !== undefined) {
|
|
44
47
|
return schema.default;
|
|
45
48
|
}
|
|
46
49
|
else if (schema.minItems !== undefined) {
|
|
@@ -87,7 +90,7 @@ var ValueCreate;
|
|
|
87
90
|
return schema.default;
|
|
88
91
|
}
|
|
89
92
|
else if (schema.anyOf.length === 0) {
|
|
90
|
-
throw new Error('Cannot create default enum value as this enum has no items');
|
|
93
|
+
throw new Error('ValueCreate.Enum: Cannot create default enum value as this enum has no items');
|
|
91
94
|
}
|
|
92
95
|
else {
|
|
93
96
|
return schema.anyOf[0].const;
|
|
@@ -207,6 +210,11 @@ var ValueCreate;
|
|
|
207
210
|
if (schema.default !== undefined) {
|
|
208
211
|
return schema.default;
|
|
209
212
|
}
|
|
213
|
+
else if (schema.minLength !== undefined) {
|
|
214
|
+
return globalThis.Array.from({ length: schema.minLength })
|
|
215
|
+
.map(() => '.')
|
|
216
|
+
.join('');
|
|
217
|
+
}
|
|
210
218
|
else {
|
|
211
219
|
return '';
|
|
212
220
|
}
|
|
@@ -231,7 +239,7 @@ var ValueCreate;
|
|
|
231
239
|
return schema.default;
|
|
232
240
|
}
|
|
233
241
|
else if (schema.anyOf.length === 0) {
|
|
234
|
-
throw new Error('ValueCreate: Cannot create Union with zero variants');
|
|
242
|
+
throw new Error('ValueCreate.Union: Cannot create Union with zero variants');
|
|
235
243
|
}
|
|
236
244
|
else {
|
|
237
245
|
return ValueCreate.Create(schema.anyOf[0], references);
|
|
@@ -241,7 +249,7 @@ var ValueCreate;
|
|
|
241
249
|
if (schema.default !== undefined) {
|
|
242
250
|
return schema.default;
|
|
243
251
|
}
|
|
244
|
-
else if (schema.minByteLength) {
|
|
252
|
+
else if (schema.minByteLength !== undefined) {
|
|
245
253
|
return new globalThis.Uint8Array(schema.minByteLength);
|
|
246
254
|
}
|
|
247
255
|
else {
|
|
@@ -311,7 +319,7 @@ var ValueCreate;
|
|
|
311
319
|
case 'Void':
|
|
312
320
|
return Void(anySchema, anyReferences);
|
|
313
321
|
default:
|
|
314
|
-
throw new Error(`ValueCreate: Unknown schema kind '${schema[Types.Kind]}'`);
|
|
322
|
+
throw new Error(`ValueCreate.Visit: Unknown schema kind '${schema[Types.Kind]}'`);
|
|
315
323
|
}
|
|
316
324
|
}
|
|
317
325
|
ValueCreate.Visit = Visit;
|
package/value/errors.js
CHANGED
|
@@ -36,6 +36,15 @@ var ValueErrors;
|
|
|
36
36
|
if (!globalThis.Array.isArray(value)) {
|
|
37
37
|
return yield { schema, path, value, message: `Expected array` };
|
|
38
38
|
}
|
|
39
|
+
if (schema.minItems !== undefined && !(value.length >= schema.minItems)) {
|
|
40
|
+
yield { schema, path, value, message: `Expected array length to be greater or equal to ${schema.minItems}` };
|
|
41
|
+
}
|
|
42
|
+
if (schema.maxItems !== undefined && !(value.length <= schema.maxItems)) {
|
|
43
|
+
yield { schema, path, value, message: `Expected array length to be less or equal to ${schema.maxItems}` };
|
|
44
|
+
}
|
|
45
|
+
if (schema.uniqueItems === true && !(new Set(value).size === value.length)) {
|
|
46
|
+
yield { schema, path, value, message: `Expected array elements to be unique` };
|
|
47
|
+
}
|
|
39
48
|
for (let i = 0; i < value.length; i++) {
|
|
40
49
|
yield* Visit(schema.items, references, `${path}/${i}`, value[i]);
|
|
41
50
|
}
|
|
@@ -61,19 +70,19 @@ var ValueErrors;
|
|
|
61
70
|
yield { schema, path, value, message: `Expected integer` };
|
|
62
71
|
}
|
|
63
72
|
if (schema.multipleOf && !(value % schema.multipleOf === 0)) {
|
|
64
|
-
yield { schema, path, value, message: `Expected
|
|
73
|
+
yield { schema, path, value, message: `Expected integer to be a multiple of ${schema.multipleOf}` };
|
|
65
74
|
}
|
|
66
75
|
if (schema.exclusiveMinimum && !(value > schema.exclusiveMinimum)) {
|
|
67
|
-
yield { schema, path, value, message: `Expected
|
|
76
|
+
yield { schema, path, value, message: `Expected integer to be greater than ${schema.exclusiveMinimum}` };
|
|
68
77
|
}
|
|
69
78
|
if (schema.exclusiveMaximum && !(value < schema.exclusiveMaximum)) {
|
|
70
|
-
yield { schema, path, value, message: `Expected
|
|
79
|
+
yield { schema, path, value, message: `Expected integer to be less than ${schema.exclusiveMaximum}` };
|
|
71
80
|
}
|
|
72
81
|
if (schema.minimum && !(value >= schema.minimum)) {
|
|
73
|
-
yield { schema, path, value, message: `Expected
|
|
82
|
+
yield { schema, path, value, message: `Expected integer to be greater or equal to ${schema.minimum}` };
|
|
74
83
|
}
|
|
75
84
|
if (schema.maximum && !(value <= schema.maximum)) {
|
|
76
|
-
yield { schema, path, value, message: `Expected
|
|
85
|
+
yield { schema, path, value, message: `Expected integer to be less or equal to ${schema.maximum}` };
|
|
77
86
|
}
|
|
78
87
|
}
|
|
79
88
|
function* Literal(schema, references, path, value) {
|
|
@@ -172,6 +181,12 @@ var ValueErrors;
|
|
|
172
181
|
if (!(typeof value === 'string')) {
|
|
173
182
|
return yield { schema, path, value, message: 'Expected string' };
|
|
174
183
|
}
|
|
184
|
+
if (schema.minLength !== undefined && !(value.length >= schema.minLength)) {
|
|
185
|
+
yield { schema, path, value, message: `Expected string length greater or equal to ${schema.minLength}` };
|
|
186
|
+
}
|
|
187
|
+
if (schema.maxLength !== undefined && !(value.length <= schema.maxLength)) {
|
|
188
|
+
yield { schema, path, value, message: `Expected string length less or equal to ${schema.maxLength}` };
|
|
189
|
+
}
|
|
175
190
|
if (schema.pattern !== undefined) {
|
|
176
191
|
const regex = new RegExp(schema.pattern);
|
|
177
192
|
if (!regex.test(value)) {
|