typebox 1.3.9 → 1.3.10
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/build/system/settings/settings.d.mts +9 -0
- package/build/system/settings/settings.mjs +2 -0
- package/build/type/engine/call/distribute_arguments.d.mts +6 -1
- package/build/type/engine/call/distribute_arguments.mjs +16 -3
- package/build/type/engine/call/instantiate.mjs +34 -4
- package/package.json +1 -1
- package/readme.md +56 -54
|
@@ -16,6 +16,15 @@ export interface TSettings {
|
|
|
16
16
|
* @default 8
|
|
17
17
|
*/
|
|
18
18
|
maxErrors: number;
|
|
19
|
+
/**
|
|
20
|
+
* Specifies the maximum number of instantiations allowed within a top-level generic instantiation
|
|
21
|
+
* context. This setting can be used to bound generic calls to a fixed count, which can be useful if
|
|
22
|
+
* evaluating string-encoded types originating from untrusted sources. Setting this value to 0 will
|
|
23
|
+
* disallow generics entirely, ensuring type instantiation runs linear.
|
|
24
|
+
*
|
|
25
|
+
* @default 128
|
|
26
|
+
*/
|
|
27
|
+
maxInstantiationCount: number;
|
|
19
28
|
/**
|
|
20
29
|
* Enables or disables the use of runtime code evaluation to accelerate validation. By default,
|
|
21
30
|
* TypeBox checks for `unsafe-eval` support in the environment before attempting to evaluate
|
|
@@ -3,6 +3,7 @@ import { Guard } from '../../guard/index.mjs';
|
|
|
3
3
|
const settings = {
|
|
4
4
|
immutableTypes: false,
|
|
5
5
|
maxErrors: 8,
|
|
6
|
+
maxInstantiationCount: 128,
|
|
6
7
|
useAcceleration: true,
|
|
7
8
|
exactOptionalPropertyTypes: false,
|
|
8
9
|
enumerableKind: false,
|
|
@@ -13,6 +14,7 @@ const settings = {
|
|
|
13
14
|
export function Reset() {
|
|
14
15
|
settings.immutableTypes = false;
|
|
15
16
|
settings.maxErrors = 8;
|
|
17
|
+
settings.maxInstantiationCount = 128;
|
|
16
18
|
settings.useAcceleration = true;
|
|
17
19
|
settings.exactOptionalPropertyTypes = false;
|
|
18
20
|
settings.enumerableKind = false;
|
|
@@ -1,12 +1,17 @@
|
|
|
1
1
|
import { type TSchema } from '../../types/schema.mjs';
|
|
2
2
|
import { type TUnion } from '../../types/union.mjs';
|
|
3
3
|
import { type TDeferred } from '../../types/deferred.mjs';
|
|
4
|
+
import { type TEnum, type TEnumValue } from '../../types/enum.mjs';
|
|
5
|
+
import { type TTemplateLiteral } from '../../types/template_literal.mjs';
|
|
4
6
|
import { type TRef } from '../../types/ref.mjs';
|
|
5
7
|
import { type TParameter } from '../../types/parameter.mjs';
|
|
8
|
+
import { type TEvaluateTemplateLiteral } from '../evaluate/evaluate.mjs';
|
|
9
|
+
import { type TEvaluateEnum } from '../evaluate/evaluate.mjs';
|
|
6
10
|
type TCollectDistributionNames<Expression extends TSchema, Result extends string[] = []> = (Expression extends TDeferred<'Conditional', [infer Left extends TSchema, infer _Right extends TSchema, infer True extends TSchema, infer False extends TSchema]> ? Left extends TRef ? TCollectDistributionNames<True, TCollectDistributionNames<False, [...Result, Left['$ref']]>> : TCollectDistributionNames<True, TCollectDistributionNames<False, Result>> : Expression extends TDeferred<'Mapped', [infer _Identifier extends TSchema, infer Type extends TSchema, infer _As extends TSchema, infer _Property extends TSchema]> ? (Type extends TDeferred<'KeyOf', [infer Ref extends TRef]> ? [...Result, Ref['$ref']] : Result) : Result);
|
|
7
11
|
type TBuildDistributionArray<Parameters extends TParameter[], Names extends string[], Result extends boolean[] = []> = (Parameters extends [infer Left extends TParameter, ...infer Right extends TParameter[]] ? Left['name'] extends Names[number] ? TBuildDistributionArray<Right, Names, [...Result, true]> : TBuildDistributionArray<Right, Names, [...Result, false]> : Result);
|
|
8
12
|
type TZipDistributionArray<Arguments extends TSchema[], DistributionArray extends boolean[], Result extends [boolean, TSchema][] = []> = (Arguments extends [infer ArgumentLeft extends TSchema, ...infer ArgumentRight extends TSchema[]] ? DistributionArray extends [infer BooleanLeft extends boolean, ...infer BooleanRight extends boolean[]] ? TZipDistributionArray<ArgumentRight, BooleanRight, [...Result, [BooleanLeft, ArgumentLeft]]> : Result : Result);
|
|
9
|
-
type
|
|
13
|
+
type TCanonicalArgument<Type extends TSchema> = (Type extends TTemplateLiteral<infer Pattern extends string> ? TEvaluateTemplateLiteral<Pattern> : Type extends TEnum<infer Values extends TEnumValue[]> ? TEvaluateEnum<Values> : Type);
|
|
14
|
+
type TExpand<Argument extends TSchema, CanonicalArgument extends TSchema = TCanonicalArgument<Argument>> = (CanonicalArgument extends TUnion<infer Types extends TSchema[]> ? [...Types] : [CanonicalArgument]);
|
|
10
15
|
type TAppend<Current extends TSchema[][], Type extends TSchema, Result extends TSchema[][] = []> = (Current extends [infer Left extends TSchema[], ...infer Right extends TSchema[][]] ? TAppend<Right, Type, [...Result, [...Left, Type]]> : Result);
|
|
11
16
|
type TCross<Current extends TSchema[][], Variants extends TSchema[], Result extends TSchema[][] = []> = (Variants extends [infer Left extends TSchema, ...infer Right extends TSchema[]] ? TCross<Current, Right, [...Result, ...TAppend<Current, Left>]> : Result);
|
|
12
17
|
type TDistribute<ZippedArguments extends [boolean, TSchema][], Result extends TSchema[][] = [[]]> = (ZippedArguments extends [infer Left extends [boolean, TSchema], ...infer Right extends [boolean, TSchema][]] ? Left[0] extends true ? TDistribute<Right, TCross<Result, TExpand<Left[1]>>> : TDistribute<Right, TCross<Result, [Left[1]]>> : Result);
|
|
@@ -2,7 +2,14 @@
|
|
|
2
2
|
import { Guard } from '../../../guard/index.mjs';
|
|
3
3
|
import { IsUnion } from '../../types/union.mjs';
|
|
4
4
|
import { IsDeferred } from '../../types/deferred.mjs';
|
|
5
|
+
import { IsEnum } from '../../types/enum.mjs';
|
|
6
|
+
import { IsTemplateLiteral } from '../../types/template_literal.mjs';
|
|
5
7
|
import { IsRef } from '../../types/ref.mjs';
|
|
8
|
+
// ------------------------------------------------------------------
|
|
9
|
+
// Infrastructure
|
|
10
|
+
// ------------------------------------------------------------------
|
|
11
|
+
import { EvaluateTemplateLiteral } from '../evaluate/evaluate.mjs';
|
|
12
|
+
import { EvaluateEnum } from '../evaluate/evaluate.mjs';
|
|
6
13
|
function CollectDistributionNames(expression, result = []) {
|
|
7
14
|
return (
|
|
8
15
|
// Conditional
|
|
@@ -21,10 +28,16 @@ function BuildDistributionArray(parameters, names) {
|
|
|
21
28
|
function ZipDistributionArray(arguments_, distributionArray, result = []) {
|
|
22
29
|
return Guard.ShiftLeft(arguments_, (argumentLeft, argumentRight) => Guard.ShiftLeft(distributionArray, (booleanLeft, booleanRight) => ZipDistributionArray(argumentRight, booleanRight, [...result, [booleanLeft, argumentLeft]]), () => result), () => result);
|
|
23
30
|
}
|
|
31
|
+
function CanonicalArgument(type) {
|
|
32
|
+
return (IsTemplateLiteral(type) ? EvaluateTemplateLiteral(type.pattern) :
|
|
33
|
+
IsEnum(type) ? EvaluateEnum(type.enum) :
|
|
34
|
+
type);
|
|
35
|
+
}
|
|
24
36
|
function Expand(type) {
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
37
|
+
const canonicalArgument = CanonicalArgument(type);
|
|
38
|
+
return (IsUnion(canonicalArgument)
|
|
39
|
+
? [...canonicalArgument.anyOf]
|
|
40
|
+
: [canonicalArgument]);
|
|
28
41
|
}
|
|
29
42
|
function Append(current, type) {
|
|
30
43
|
return current.reduce((result, left) => [...result, [...left, type]], []);
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
// deno-fmt-ignore-file
|
|
2
|
+
import { Settings } from '../../../system/settings/index.mjs';
|
|
2
3
|
import { Guard } from '../../../guard/index.mjs';
|
|
3
4
|
import { CallConstruct } from '../../types/call.mjs';
|
|
4
5
|
import { Ref } from '../../types/ref.mjs';
|
|
@@ -13,6 +14,26 @@ import { State } from '../instantiate.mjs';
|
|
|
13
14
|
import { DistributeArguments } from './distribute_arguments.mjs';
|
|
14
15
|
import { ResolveTarget } from './resolve_target.mjs';
|
|
15
16
|
import { ResolveArgumentsContext } from './resolve_arguments.mjs';
|
|
17
|
+
// ------------------------------------------------------------------
|
|
18
|
+
// InstantiationGuard
|
|
19
|
+
// ------------------------------------------------------------------
|
|
20
|
+
let instantiationDepth = 0;
|
|
21
|
+
let instantiationCount = 0;
|
|
22
|
+
function InstantiationAssert() {
|
|
23
|
+
if (Guard.IsLessThan(instantiationCount, Settings.Get().maxInstantiationCount))
|
|
24
|
+
return;
|
|
25
|
+
throw Error('Type instantiation is excessively deep and possibly infinite');
|
|
26
|
+
}
|
|
27
|
+
function InstantiationIncrement() {
|
|
28
|
+
InstantiationAssert();
|
|
29
|
+
instantiationCount++;
|
|
30
|
+
instantiationDepth++;
|
|
31
|
+
}
|
|
32
|
+
function InstantiationDecrement() {
|
|
33
|
+
instantiationDepth--;
|
|
34
|
+
if (Guard.IsEqual(instantiationDepth, 0))
|
|
35
|
+
instantiationCount = 0;
|
|
36
|
+
}
|
|
16
37
|
function Peek(state) {
|
|
17
38
|
const result = Guard.IsGreaterThan(state.callstack.length, 0) ? state.callstack[state.callstack.length - 1] : '';
|
|
18
39
|
return result;
|
|
@@ -22,12 +43,21 @@ function IsTailCall(state, name) {
|
|
|
22
43
|
return result;
|
|
23
44
|
}
|
|
24
45
|
function CallDispatch(context, state, target, parameters, expression, arguments_) {
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
46
|
+
InstantiationIncrement();
|
|
47
|
+
try {
|
|
48
|
+
const argumentsContext = ResolveArgumentsContext(context, state, parameters, arguments_);
|
|
49
|
+
const returnType = InstantiateType(argumentsContext, State([...state['callstack'], target['$ref']], state['visited']), expression);
|
|
50
|
+
return InstantiateType(argumentsContext, State([], []), returnType);
|
|
51
|
+
}
|
|
52
|
+
finally {
|
|
53
|
+
InstantiationDecrement();
|
|
54
|
+
}
|
|
28
55
|
}
|
|
29
56
|
function CallDistributed(context, state, target, parameters, expression, distributedArguments) {
|
|
30
|
-
return distributedArguments.reduce((result, arguments_) =>
|
|
57
|
+
return distributedArguments.reduce((result, arguments_) => {
|
|
58
|
+
const returnType = CallDispatch(context, state, target, parameters, expression, arguments_);
|
|
59
|
+
return [...result, returnType];
|
|
60
|
+
}, []);
|
|
31
61
|
}
|
|
32
62
|
function CallImmediate(context, state, target, parameters, expression, arguments_) {
|
|
33
63
|
const distributedArguments = DistributeArguments(parameters, arguments_, expression);
|
package/package.json
CHANGED
package/readme.md
CHANGED
|
@@ -111,7 +111,7 @@ type User = Type.Static<typeof User> // type User = {
|
|
|
111
111
|
|
|
112
112
|
## Script
|
|
113
113
|
|
|
114
|
-
[Documentation](https://sinclairzx81.github.io/typebox/#/docs/script/overview) | [Example 1](https://www.typescriptlang.org/play/?target=99&module=7#code/
|
|
114
|
+
[Documentation](https://sinclairzx81.github.io/typebox/#/docs/script/overview) | [Example 1](https://www.typescriptlang.org/play/?target=99&module=7#code/JYWwDg9gTgLgBAFQJ5gKZwGZQiOByGFVAIwgA88AoSgehrgFkBDGAC0YgBMBXAG1WoBjCADsAzvGZs4AXkREAdAGVBUYGBgAKAAaU4cQmjgA1VIJjQALLLgBvOGQBccEdxDFUUADRwkz1+6ePgBe-m4e3nAA7mGBUHAAvnoGRCZmFlAAzDb2Ti7hQb6xESHFnonJhuim5tAATDkOZZF++XEV2gCU1HRwAOJQTGCswIJiHDz8QqIS-YPDo+NyyGjKqupaUqw+uvpVabCoZDnJ+pBiwDDAos41GZZepy7QIEy8t+nQmY-6+twAbh9alA6skkntUn1UDhUDAoEgTr84P9PFdBKgxB9DmQANoAXR+v2AIk4owxzXxYMqqSknmAb0RvyY7mAqBEMCB90J+lJGAw3DEqE5Vm5cDEaEEfCYUGFUEsVIhRgYGPYclsTwA5tCQLD4c4oTC4UhRa8YHS3s5aWo3lSutR9sqxKr5KslDAWKMADxVCAYOZDEZjHF4R2sPB4gB8+l6DpVjKRCcTSeTKZTvX0WsNerscAUecSotTReLJfTcFN5veObzCgqJfrDeTvQSQA) | [Example 2](https://www.typescriptlang.org/play/?target=99&module=7#code/JYWwDg9gTgLgBAFQJ5gKZwGZQiOByGFVAIwgA88AoSgehrgFkBDGAC0YgBMBXAG1WoBjCADsAzvABqqQTGgAWOAF5ERAHQB5YgCsZMABQBvOGQBcqtGoBy3EMVRR9ASgA0cJOeSWbdh87cAXp7qPvaOrnAA7sHetmHOcAC+TpTC4lJ60ADMyhaomjp6RiYx+aF+ER551nEVgaU1vuFJKWkScNKy0ABMuV75WrqyxWbV5eFuVf2N8U4t1HRwAOJQTGCswIJiHDz8QqLt0rCoZH3qg0WGlHBwkGLAMMCi5p1yUPIu13Ai0CBMvC9MlAsp8btwAG6ArpQbqUZKpA7wJaoHCoGBQJBnSwXYZXG7ghyPQSoMQNACCUFWSH0RxgJ1cX2AIk4mxJ5MpTGp03GzhS8La8GYdKgwH+WIGhVxXyYdmAqBEMChbw+XxZGAw3DEqCVClBcDEaEEfCYUB170+-MRjBJ7BU0xxBjxcAA5iiQGiMeZkaj0Ug9X9haKAYwWA4g3CUpRCGhrWJbdUAMowFibAA80ZRGFjrAAfDd8wXC4sM9nck7CxXK1XqzX84sbq6fZ64MY1G2knra13u1363AA2H-uZW+3El8exPJ3X6IkgA)
|
|
115
115
|
|
|
116
116
|
TypeBox includes a runtime TypeScript engine that can transform TypeScript definitions to JSON Schema. The engine is fully type-safe and supports many programmable constructs including Conditional, Mapped, Indexed, Generics, Distributive Generics, and more.
|
|
117
117
|
|
|
@@ -120,45 +120,43 @@ TypeBox includes a runtime TypeScript engine that can transform TypeScript defin
|
|
|
120
120
|
Syntax highlighting is available via the [Visual Studio Marketplace](https://marketplace.visualstudio.com/items?itemName=sinclairzx81.typebox-script)
|
|
121
121
|
|
|
122
122
|
```typescript
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
123
|
+
import Type from 'typebox'
|
|
124
|
+
|
|
125
|
+
// Math Module
|
|
126
|
+
|
|
127
|
+
const Math = Type.Script(`
|
|
128
|
+
type Vector4 = { x: number, y: number, z: number, w: number }
|
|
129
|
+
type Vector3 = { x: number, y: number, z: number }
|
|
130
|
+
type Vector2 = { x: number, y: number }
|
|
131
|
+
`)
|
|
132
|
+
|
|
133
|
+
// Graphics Module
|
|
134
|
+
|
|
135
|
+
const Graphics = Type.Script(Math, `
|
|
136
|
+
type Vertex = {
|
|
137
|
+
position: Vector4,
|
|
138
|
+
normal: Vector3,
|
|
139
|
+
uv: Vector2
|
|
140
|
+
}
|
|
141
|
+
type Geometry = {
|
|
142
|
+
vertices: Vertex[],
|
|
143
|
+
indices: number[]
|
|
128
144
|
}
|
|
129
|
-
type
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
145
|
+
type Material = {
|
|
146
|
+
ambient: Vector4,
|
|
147
|
+
diffuse: Vector4,
|
|
148
|
+
specular: Vector4
|
|
133
149
|
}
|
|
134
|
-
type
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
body: string,
|
|
138
|
-
author: User,
|
|
139
|
-
comments: Comment[]
|
|
150
|
+
type Mesh = {
|
|
151
|
+
geometry: Geometry,
|
|
152
|
+
material: Material
|
|
140
153
|
}
|
|
141
154
|
`)
|
|
142
155
|
|
|
143
|
-
//
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
Post.properties.author.properties.name
|
|
148
|
-
Post.properties.comments.items.properties.text
|
|
149
|
-
Post.properties.comments.items.properties.author.properties.id
|
|
150
|
-
Post.properties.comments.items.properties.author.properties.name
|
|
151
|
-
|
|
152
|
-
// Inference
|
|
153
|
-
function present(post: Type.Static<typeof Post>) {
|
|
154
|
-
post.id
|
|
155
|
-
post.title
|
|
156
|
-
post.author.id
|
|
157
|
-
post.author.name
|
|
158
|
-
post.comments[0].text
|
|
159
|
-
post.comments[0].author.id
|
|
160
|
-
post.comments[0].author.name
|
|
161
|
-
}
|
|
156
|
+
type Mesh = Type.Static<typeof Graphics['Mesh']> // type Mesh = {
|
|
157
|
+
// geometry: { ... },
|
|
158
|
+
// material: { ... }
|
|
159
|
+
// }
|
|
162
160
|
```
|
|
163
161
|
|
|
164
162
|
<a name="Schema"></a>
|
|
@@ -177,18 +175,21 @@ import Schema from 'typebox/schema'
|
|
|
177
175
|
|
|
178
176
|
### Compile
|
|
179
177
|
|
|
180
|
-
The compiler accepts
|
|
178
|
+
The compiler accepts either TypeBox types or native JSON Schema.
|
|
181
179
|
|
|
182
180
|
```typescript
|
|
183
|
-
|
|
181
|
+
|
|
182
|
+
// Type
|
|
183
|
+
|
|
184
|
+
const VectorA = Schema.Compile(Type.Object({ // const VectorA: Validator<TObject<{
|
|
184
185
|
x: Type.Number(), // x: TNumber
|
|
185
186
|
y: Type.Number(), // y: TNumber
|
|
186
187
|
z: Type.Number() // z: TNumber
|
|
187
188
|
})) // }>>
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
const
|
|
189
|
+
|
|
190
|
+
// Schema
|
|
191
|
+
|
|
192
|
+
const VectorB = Schema.Compile({ // const VectorB: Validator<{
|
|
192
193
|
type: 'object', // type: "object";
|
|
193
194
|
required: ['x', 'y', 'z'], // required: ["x", "y", "z"];
|
|
194
195
|
properties: { // properties: { ... };
|
|
@@ -201,29 +202,30 @@ const Vector = Schema.Compile({ // const Vector: Validator<{
|
|
|
201
202
|
|
|
202
203
|
### Validate
|
|
203
204
|
|
|
204
|
-
|
|
205
|
+
Compiled validator instances provide functions to Check and Parse values.
|
|
205
206
|
|
|
206
207
|
```typescript
|
|
208
|
+
|
|
209
|
+
// Compile
|
|
210
|
+
|
|
207
211
|
const Vector = Schema.Compile(Type.Script(`{
|
|
208
212
|
x: number
|
|
209
213
|
y: number
|
|
210
214
|
z: number
|
|
211
215
|
}`))
|
|
212
216
|
|
|
213
|
-
|
|
214
|
-
x: 1,
|
|
215
|
-
y: 0,
|
|
216
|
-
z: 0
|
|
217
|
-
})
|
|
218
|
-
|
|
219
|
-
const value = Vector.Parse({ // const value: {
|
|
220
|
-
x: 1, // x: number
|
|
221
|
-
y: 0, // y: number
|
|
222
|
-
z: 0 // z: number
|
|
223
|
-
}) // }
|
|
224
|
-
```
|
|
217
|
+
// Check
|
|
225
218
|
|
|
219
|
+
const valid = Vector.Check({ x: 1, y: 0, z: 0 }) // const valid: boolean
|
|
226
220
|
|
|
221
|
+
// Parse
|
|
222
|
+
|
|
223
|
+
const result = Vector.Parse({ x: 1, y: 0, z: 0 }) // const result: {
|
|
224
|
+
// x: number
|
|
225
|
+
// y: number
|
|
226
|
+
// z: number
|
|
227
|
+
// }
|
|
228
|
+
```
|
|
227
229
|
|
|
228
230
|
### Coverage
|
|
229
231
|
|