@@ -20,2 +20,11 @@ export interface TSettings { | ||
| /** | ||
| * Specifies the maximum number of instantiations allowed within a top-level generic instantiation | ||
| * context. This setting can be used to bound generic calls to a fixed count, which can be useful if | ||
| * evaluating string-encoded types originating from untrusted sources. Setting this value to 0 will | ||
| * disallow generics entirely, ensuring type instantiation runs linear. | ||
| * | ||
| * @default 128 | ||
| */ | ||
| maxInstantiationCount: number; | ||
| /** | ||
| * Enables or disables the use of runtime code evaluation to accelerate validation. By default, | ||
@@ -22,0 +31,0 @@ * TypeBox checks for `unsafe-eval` support in the environment before attempting to evaluate |
@@ -6,2 +6,3 @@ import { Guard } from '../../guard/index.mjs'; | ||
| maxErrors: 8, | ||
| maxInstantiationCount: 128, | ||
| useAcceleration: true, | ||
@@ -17,2 +18,3 @@ exactOptionalPropertyTypes: false, | ||
| settings.maxErrors = 8; | ||
| settings.maxInstantiationCount = 128; | ||
| settings.useAcceleration = true; | ||
@@ -19,0 +21,0 @@ settings.exactOptionalPropertyTypes = false; |
| import { type TSchema } from '../../types/schema.mjs'; | ||
| import { type TUnion } from '../../types/union.mjs'; | ||
| import { type TDeferred } from '../../types/deferred.mjs'; | ||
| import { type TEnum, type TEnumValue } from '../../types/enum.mjs'; | ||
| import { type TTemplateLiteral } from '../../types/template_literal.mjs'; | ||
| import { type TRef } from '../../types/ref.mjs'; | ||
| import { type TParameter } from '../../types/parameter.mjs'; | ||
| import { type TEvaluateTemplateLiteral } from '../evaluate/evaluate.mjs'; | ||
| import { type TEvaluateEnum } from '../evaluate/evaluate.mjs'; | ||
| 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); | ||
| 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); | ||
| 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); | ||
| type TExpand<Type extends TSchema> = (Type extends TUnion<infer Types extends TSchema[]> ? [...Types] : [Type]); | ||
| type TCanonicalArgument<Type extends TSchema> = (Type extends TTemplateLiteral<infer Pattern extends string> ? TEvaluateTemplateLiteral<Pattern> : Type extends TEnum<infer Values extends TEnumValue[]> ? TEvaluateEnum<Values> : Type); | ||
| type TExpand<Argument extends TSchema, CanonicalArgument extends TSchema = TCanonicalArgument<Argument>> = (CanonicalArgument extends TUnion<infer Types extends TSchema[]> ? [...Types] : [CanonicalArgument]); | ||
| 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,0 +16,0 @@ 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); |
@@ -5,3 +5,10 @@ // deno-fmt-ignore-file | ||
| import { IsDeferred } from '../../types/deferred.mjs'; | ||
| import { IsEnum } from '../../types/enum.mjs'; | ||
| import { IsTemplateLiteral } from '../../types/template_literal.mjs'; | ||
| import { IsRef } from '../../types/ref.mjs'; | ||
| // ------------------------------------------------------------------ | ||
| // Infrastructure | ||
| // ------------------------------------------------------------------ | ||
| import { EvaluateTemplateLiteral } from '../evaluate/evaluate.mjs'; | ||
| import { EvaluateEnum } from '../evaluate/evaluate.mjs'; | ||
| function CollectDistributionNames(expression, result = []) { | ||
@@ -25,6 +32,12 @@ return ( | ||
| } | ||
| function CanonicalArgument(type) { | ||
| return (IsTemplateLiteral(type) ? EvaluateTemplateLiteral(type.pattern) : | ||
| IsEnum(type) ? EvaluateEnum(type.enum) : | ||
| type); | ||
| } | ||
| function Expand(type) { | ||
| return (IsUnion(type) | ||
| ? [...type.anyOf] | ||
| : [type]); | ||
| const canonicalArgument = CanonicalArgument(type); | ||
| return (IsUnion(canonicalArgument) | ||
| ? [...canonicalArgument.anyOf] | ||
| : [canonicalArgument]); | ||
| } | ||
@@ -31,0 +44,0 @@ function Append(current, type) { |
| // deno-fmt-ignore-file | ||
| import { Settings } from '../../../system/settings/index.mjs'; | ||
| import { Guard } from '../../../guard/index.mjs'; | ||
@@ -16,2 +17,22 @@ import { CallConstruct } from '../../types/call.mjs'; | ||
| import { ResolveArgumentsContext } from './resolve_arguments.mjs'; | ||
| // ------------------------------------------------------------------ | ||
| // InstantiationGuard | ||
| // ------------------------------------------------------------------ | ||
| let instantiationDepth = 0; | ||
| let instantiationCount = 0; | ||
| function InstantiationAssert() { | ||
| if (Guard.IsLessThan(instantiationCount, Settings.Get().maxInstantiationCount)) | ||
| return; | ||
| throw Error('Type instantiation is excessively deep and possibly infinite'); | ||
| } | ||
| function InstantiationIncrement() { | ||
| InstantiationAssert(); | ||
| instantiationCount++; | ||
| instantiationDepth++; | ||
| } | ||
| function InstantiationDecrement() { | ||
| instantiationDepth--; | ||
| if (Guard.IsEqual(instantiationDepth, 0)) | ||
| instantiationCount = 0; | ||
| } | ||
| function Peek(state) { | ||
@@ -26,8 +47,17 @@ const result = Guard.IsGreaterThan(state.callstack.length, 0) ? state.callstack[state.callstack.length - 1] : ''; | ||
| function CallDispatch(context, state, target, parameters, expression, arguments_) { | ||
| const argumentsContext = ResolveArgumentsContext(context, state, parameters, arguments_); | ||
| const returnType = InstantiateType(argumentsContext, State([...state['callstack'], target['$ref']], state['visited']), expression); | ||
| return InstantiateType(argumentsContext, State([], []), returnType); | ||
| InstantiationIncrement(); | ||
| try { | ||
| const argumentsContext = ResolveArgumentsContext(context, state, parameters, arguments_); | ||
| const returnType = InstantiateType(argumentsContext, State([...state['callstack'], target['$ref']], state['visited']), expression); | ||
| return InstantiateType(argumentsContext, State([], []), returnType); | ||
| } | ||
| finally { | ||
| InstantiationDecrement(); | ||
| } | ||
| } | ||
| function CallDistributed(context, state, target, parameters, expression, distributedArguments) { | ||
| return distributedArguments.reduce((result, arguments_) => [...result, CallDispatch(context, state, target, parameters, expression, arguments_)], []); | ||
| return distributedArguments.reduce((result, arguments_) => { | ||
| const returnType = CallDispatch(context, state, target, parameters, expression, arguments_); | ||
| return [...result, returnType]; | ||
| }, []); | ||
| } | ||
@@ -34,0 +64,0 @@ function CallImmediate(context, state, target, parameters, expression, arguments_) { |
+1
-1
| { | ||
| "name": "typebox", | ||
| "description": "Json Schema Type Builder with Static Type Resolution for TypeScript", | ||
| "version": "1.3.9", | ||
| "version": "1.3.10", | ||
| "keywords": [ | ||
@@ -6,0 +6,0 @@ "typescript", |
+55
-53
@@ -114,3 +114,3 @@ <div align='center'> | ||
| [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) | ||
| [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) | ||
@@ -124,41 +124,39 @@ 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. | ||
| ```typescript | ||
| // Module | ||
| const { Post } = Type.Script(` | ||
| type User = { | ||
| id: number, | ||
| name: string | ||
| import Type from 'typebox' | ||
| // Math Module | ||
| const Math = Type.Script(` | ||
| type Vector4 = { x: number, y: number, z: number, w: number } | ||
| type Vector3 = { x: number, y: number, z: number } | ||
| type Vector2 = { x: number, y: number } | ||
| `) | ||
| // Graphics Module | ||
| const Graphics = Type.Script(Math, ` | ||
| type Vertex = { | ||
| position: Vector4, | ||
| normal: Vector3, | ||
| uv: Vector2 | ||
| } | ||
| type Comment = { | ||
| id: number, | ||
| text: string, | ||
| author: User | ||
| type Geometry = { | ||
| vertices: Vertex[], | ||
| indices: number[] | ||
| } | ||
| type Post = { | ||
| id: number, | ||
| title: string, | ||
| body: string, | ||
| author: User, | ||
| comments: Comment[] | ||
| type Material = { | ||
| ambient: Vector4, | ||
| diffuse: Vector4, | ||
| specular: Vector4 | ||
| } | ||
| type Mesh = { | ||
| geometry: Geometry, | ||
| material: Material | ||
| } | ||
| `) | ||
| // Reflection | ||
| Post.properties.id | ||
| Post.properties.title | ||
| Post.properties.author.properties.id | ||
| Post.properties.author.properties.name | ||
| Post.properties.comments.items.properties.text | ||
| Post.properties.comments.items.properties.author.properties.id | ||
| Post.properties.comments.items.properties.author.properties.name | ||
| // Inference | ||
| function present(post: Type.Static<typeof Post>) { | ||
| post.id | ||
| post.title | ||
| post.author.id | ||
| post.author.name | ||
| post.comments[0].text | ||
| post.comments[0].author.id | ||
| post.comments[0].author.name | ||
| } | ||
| type Mesh = Type.Static<typeof Graphics['Mesh']> // type Mesh = { | ||
| // geometry: { ... }, | ||
| // material: { ... } | ||
| // } | ||
| ``` | ||
@@ -182,6 +180,9 @@ | ||
| The compiler accepts JSON Schema and returns Validator instances. | ||
| The compiler accepts either TypeBox types or native JSON Schema. | ||
| ```typescript | ||
| const Vector = Schema.Compile(Type.Object({ // const Vector: Validator<TObject<{ | ||
| // Type | ||
| const VectorA = Schema.Compile(Type.Object({ // const VectorA: Validator<TObject<{ | ||
| x: Type.Number(), // x: TNumber | ||
@@ -191,6 +192,6 @@ y: Type.Number(), // y: TNumber | ||
| })) // }>> | ||
| ``` | ||
| With JSON Schema | ||
| ```typescript | ||
| const Vector = Schema.Compile({ // const Vector: Validator<{ | ||
| // Schema | ||
| const VectorB = Schema.Compile({ // const VectorB: Validator<{ | ||
| type: 'object', // type: "object"; | ||
@@ -208,5 +209,8 @@ required: ['x', 'y', 'z'], // required: ["x", "y", "z"]; | ||
| Validator instances provide functions to Check and Parse values. | ||
| Compiled validator instances provide functions to Check and Parse values. | ||
| ```typescript | ||
| // Compile | ||
| const Vector = Schema.Compile(Type.Script(`{ | ||
@@ -218,16 +222,14 @@ x: number | ||
| const valid = Vector.Check({ // const valid: boolean | ||
| x: 1, | ||
| y: 0, | ||
| z: 0 | ||
| }) | ||
| // Check | ||
| const value = Vector.Parse({ // const value: { | ||
| x: 1, // x: number | ||
| y: 0, // y: number | ||
| z: 0 // z: number | ||
| }) // } | ||
| ``` | ||
| const valid = Vector.Check({ x: 1, y: 0, z: 0 }) // const valid: boolean | ||
| // Parse | ||
| const result = Vector.Parse({ x: 1, y: 0, z: 0 }) // const result: { | ||
| // x: number | ||
| // y: number | ||
| // z: number | ||
| // } | ||
| ``` | ||
@@ -234,0 +236,0 @@ ### Coverage |
AI-detected potential code anomaly
Supply chain riskAI has identified unusual behaviors that may pose a security risk.
Found 2 instances
AI-detected potential code anomaly
Supply chain riskAI has identified unusual behaviors that may pose a security risk.
1468277
0.19%16783
0.27%365
0.55%3
50%