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.
@@ -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 TExpand<Type extends TSchema> = (Type extends TUnion<infer Types extends TSchema[]> ? [...Types] : [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
- return (IsUnion(type)
26
- ? [...type.anyOf]
27
- : [type]);
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
- const argumentsContext = ResolveArgumentsContext(context, state, parameters, arguments_);
26
- const returnType = InstantiateType(argumentsContext, State([...state['callstack'], target['$ref']], state['visited']), expression);
27
- return InstantiateType(argumentsContext, State([], []), returnType);
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_) => [...result, CallDispatch(context, state, target, parameters, expression, 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
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "typebox",
3
3
  "description": "Json Schema Type Builder with Static Type Resolution for TypeScript",
4
- "version": "1.3.9",
4
+ "version": "1.3.10",
5
5
  "keywords": [
6
6
  "typescript",
7
7
  "jsonschema"
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/JYWwDg9gTgLgBAFQJ5gKZwGZQiOByGFVAIwgA88AoSgehrgFkIATAVwBtVKBjCAOwDO8AN5wAChCFwAvnAC8iIgDoAytyjAwMABQADSnDiE0cAKoDUUeXGEHDcYMwBccPqxDFLAGjuG+AQxBUFyENPgBzO2k7Y3QAYRwgvngFW3sHZ1d3TygfdJhUMhgQmDDwvPt-VhgAC2gXc0somKJxSRSbXwyXNw9vLphgGE4SsorDUmYkUeAI8bgq2vqzC1yu3hAkmAEXBM3UZIBtAF1m3QBKajo4ACVUDE5uQf5KCSElMGw0WGBUASVHK92h8vpZBn8lINhlw3jAQRBvuD-os6lB4Yjfv9AbD0WDMUoUdBcT8IQEgkD3p8EXiIRstliCiB-lSMRCCkUKXCWTT-nSDtsAYzmaCScjqqjiUiAcxOZL8XzkgzUEy5RDCWjuaKlGSuLR6ABJPgYSwHbhcDCsPhPYD8OCfP787SQIQuZBoVQwfyDbgAHliEAwbSEAD5zp1DM64YCI8CoZw7JGCeKidG7cD1drAlwY+8FdtDgAGY6QwowBPAvMCQvFjOpxOV6tJpZonWUaRAA) | [Example 2](https://www.typescriptlang.org/play/?target=99&module=7#code/JYWwDg9gTgLgBAFQJ5gKZwGZQiOByGFVAIwgA88AoSgehrgFkIATAVwBtVKBjCAOwDO8AKoDUUOAF5ERAHQB5YgCtU3GAAoA3pThxgzAFwy0sgHKsQxceoCUAGh1w+AQxCojyEwGUYUYHwBzW0oAXxsefiE4AGEcNz54aU9UBWVVDW1dfQ85c0tre0cYVDIYHO9ffyDC3WdWGAALaCNRcVDw3kF4AAUIKKS5RRU1LUds4xS8qyhbB10YYBhOcpSfP0DZx1JmJBXZNarN2vqmqBaxKDm4XhB4mAE9gEEoKGckdVjb1ATwsOo6OAAJVQGE4amA-EovSEsjA2DQsGAqAEsn0UL6MFh8PEC2RsgWSy40MxcIgCNxKLqjWgWLJOKRKLRxNp5IZsippxZ9LxLjc6JhpNZeJud0ZxRAKMF3JRxVK-JJ2MRwri33uqPFksVFPZJxpUqVjOY8q5BtkItVYtQEpN2o5eq1bN5XFo9AAknwMOJvtwuBhWHxwfw4HDkar1JAhHsfM4FtwADyENAQDBwYkAPhscEywYxqKNugjmIJnEchZ11KgedLubtlad1Zh5oSAgA2gAGAC6+JKMAbmKb93bXdrVYLuYHrc75c59ZCQA) | [Challenge](test/typescript/readme.md)
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
- // Module
124
- const { Post } = Type.Script(`
125
- type User = {
126
- id: number,
127
- name: string
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 Comment = {
130
- id: number,
131
- text: string,
132
- author: User
145
+ type Material = {
146
+ ambient: Vector4,
147
+ diffuse: Vector4,
148
+ specular: Vector4
133
149
  }
134
- type Post = {
135
- id: number,
136
- title: string,
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
- // Reflection
144
- Post.properties.id
145
- Post.properties.title
146
- Post.properties.author.properties.id
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 JSON Schema and returns Validator instances.
178
+ The compiler accepts either TypeBox types or native JSON Schema.
181
179
 
182
180
  ```typescript
183
- const Vector = Schema.Compile(Type.Object({ // const Vector: Validator<TObject<{
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
- With JSON Schema
190
- ```typescript
191
- const Vector = Schema.Compile({ // const Vector: Validator<{
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
- Validator instances provide functions to Check and Parse values.
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
- const valid = Vector.Check({ // const valid: boolean
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