@sinclair/typebox
Advanced tools
Comparing version 0.23.5 to 0.24.0
{ | ||
"name": "@sinclair/typebox", | ||
"version": "0.23.5", | ||
"version": "0.24.0", | ||
"description": "JSONSchema Type Builder with Static Type Resolution for TypeScript", | ||
@@ -21,8 +21,7 @@ "keywords": [ | ||
"clean": "hammer task clean", | ||
"format": "hammer task format", | ||
"start": "hammer task start", | ||
"test": "hammer task test", | ||
"build": "hammer task build", | ||
"example": "hammer task example", | ||
"spec": "hammer task spec", | ||
"spec:types": "hammer task spec_types", | ||
"spec:schemas": "hammer task spec_schemas", | ||
"test": "npm run spec" | ||
"publish": "hammer task publish" | ||
}, | ||
@@ -38,2 +37,3 @@ "devDependencies": { | ||
"mocha": "^9.2.0", | ||
"prettier": "^2.7.1", | ||
"tsd": "^0.19.1", | ||
@@ -40,0 +40,0 @@ "typescript": "^4.5.5" |
723
readme.md
@@ -37,3 +37,3 @@ <div align='center'> | ||
const T = Type.String() // const T = { "type": "string" } | ||
const T = Type.String() // const T = { type: 'string' } | ||
@@ -47,8 +47,6 @@ type T = Static<typeof T> // type T = string | ||
TypeBox is a library that creates in-memory JSON Schema objects that can be statically inferred as TypeScript types. The schemas produced by this library are designed to match the static type checking rules of the TypeScript compiler. TypeBox allows one to create a unified type that can be both statically asserted by the TypeScript compiler and runtime asserted using standard JSON Schema validation. | ||
TypeBox is a type builder library that creates in-memory JSON Schema objects that can be statically inferred as TypeScript types. The schemas produced by this library are designed to match the static type checking rules of the TypeScript compiler. TypeBox allows one to compose unified types that can be statically asserted by the TypeScript compiler as well as runtime asserted using standard JSON Schema validation. | ||
TypeBox can be used as a simple tool to build up complex schemas or integrated into RPC or REST services to help validate JSON data received over the wire. TypeBox does not provide any JSON schema validation. Please use libraries such as AJV to validate schemas built with this library. | ||
TypeBox can be used as a simple tool to build up complex schemas or integrated into RPC or REST services to help validate JSON data received over the wire. It can be used in both TypeScript and JavaScript environments. | ||
Requires TypeScript 4.3.5 and above. | ||
License MIT | ||
@@ -63,9 +61,12 @@ | ||
- [Options](#Options) | ||
- [Generic Types](#Generic-Types) | ||
- [Extended Types](#Extended-Types) | ||
- [Reference Types](#Reference-Types) | ||
- [Recursive Types](#Recursive-Types) | ||
- [Extended Types](#Extended-Types) | ||
- [Generic Types](#Generic-Types) | ||
- [Unsafe Types](#Unsafe-Types) | ||
- [Values](#Values) | ||
- [Strict](#Strict) | ||
- [Validation](#Validation) | ||
- [OpenAPI](#OpenAPI) | ||
- [Compiler](#Compiler) | ||
- [Contribute](#Contribute) | ||
@@ -89,5 +90,5 @@ <a name="Example"></a> | ||
type T = { | ||
id: string, | ||
name: string, | ||
timestamp: number | ||
id: string, | ||
name: string, | ||
timestamp: number | ||
} | ||
@@ -101,21 +102,21 @@ | ||
const T = Type.Object({ // const T = { | ||
id: Type.String(), // type: 'object', | ||
name: Type.String(), // properties: { | ||
timestamp: Type.Integer() // id: { | ||
}) // type: 'string' | ||
// }, | ||
// name: { | ||
// type: 'string' | ||
// }, | ||
// timestamp: { | ||
// type: 'integer' | ||
// } | ||
// }, | ||
// required: [ | ||
// "id", | ||
// "name", | ||
// "timestamp" | ||
// ] | ||
// } | ||
const T = Type.Object({ // const T = { | ||
id: Type.String(), // type: 'object', | ||
name: Type.String(), // properties: { | ||
timestamp: Type.Integer() // id: { | ||
}) // type: 'string' | ||
// }, | ||
// name: { | ||
// type: 'string' | ||
// }, | ||
// timestamp: { | ||
// type: 'integer' | ||
// } | ||
// }, | ||
// required: [ | ||
// "id", | ||
// "name", | ||
// "timestamp" | ||
// ] | ||
// } | ||
@@ -128,7 +129,7 @@ //-------------------------------------------------------------------------------------------- | ||
type T = Static<typeof T> // type T = { | ||
// id: string, | ||
// name: string, | ||
// timestamp: number | ||
// } | ||
type T = Static<typeof T> // type T = { | ||
// id: string, | ||
// name: string, | ||
// timestamp: number | ||
// } | ||
@@ -141,8 +142,7 @@ //-------------------------------------------------------------------------------------------- | ||
function receive(value: T) { // ... as a Type | ||
function receive(value: T) { // ... as a Type | ||
if(JSON.validate(T, value)) { // ... as a Schema | ||
if(JSON.validate(T, value)) { // ... as a Schema | ||
// ok... | ||
} | ||
} | ||
} | ||
@@ -169,3 +169,3 @@ ``` | ||
│ const T = Type.String() │ type T = string │ const T = { │ | ||
│ │ │ type: 'string' │ | ||
│ │ │ type: 'string' │ | ||
│ │ │ } │ | ||
@@ -175,3 +175,3 @@ │ │ │ │ | ||
│ const T = Type.Number() │ type T = number │ const T = { │ | ||
│ │ │ type: 'number' │ | ||
│ │ │ type: 'number' │ | ||
│ │ │ } │ | ||
@@ -181,3 +181,3 @@ │ │ │ │ | ||
│ const T = Type.Integer() │ type T = number │ const T = { │ | ||
│ │ │ type: 'integer' │ | ||
│ │ │ type: 'integer' │ | ||
│ │ │ } │ | ||
@@ -187,3 +187,3 @@ │ │ │ │ | ||
│ const T = Type.Boolean() │ type T = boolean │ const T = { │ | ||
│ │ │ type: 'boolean' │ | ||
│ │ │ type: 'boolean' │ | ||
│ │ │ } │ | ||
@@ -210,6 +210,6 @@ │ │ │ │ | ||
│ const T = Type.Array( │ type T = number[] │ const T = { │ | ||
│ Type.Number() │ │ type: 'array', │ | ||
│ ) │ │ items: { │ | ||
│ │ │ type: 'number' │ | ||
│ │ │ } │ | ||
│ Type.Number() │ │ type: 'array', │ | ||
│ ) │ │ items: { │ | ||
│ │ │ type: 'number' │ | ||
│ │ │ } │ | ||
│ │ │ } │ | ||
@@ -219,4 +219,4 @@ │ │ │ │ | ||
│ const T = Type.Object({ │ type T = { │ const T = { │ | ||
│ x: Type.Number(), │ x: number, │ type: 'object', │ | ||
│ y: Type.Number() │ y: number │ properties: { │ | ||
│ x: Type.Number(), │ x: number, │ type: 'object', │ | ||
│ y: Type.Number() │ y: number │ properties: { │ | ||
│ }) │ } │ x: { │ | ||
@@ -234,10 +234,8 @@ │ │ │ type: 'number' │ | ||
│ const T = Type.Tuple([ │ type T = [number, number] │ const T = { │ | ||
│ Type.Number(), │ │ type: 'array', │ | ||
│ Type.Number() │ │ items: [ │ | ||
│ ]) │ │ { │ | ||
│ │ │ type: 'number' │ | ||
│ │ │ }, { │ | ||
│ │ │ type: 'number' │ | ||
│ │ │ } │ | ||
│ │ │ ], │ | ||
│ Type.Number(), │ │ type: 'array', │ | ||
│ Type.Number() │ │ items: [{ │ | ||
│ ]) │ │ type: 'number' │ | ||
│ │ │ }, { │ | ||
│ │ │ type: 'number' │ | ||
│ │ │ }], │ | ||
│ │ │ additionalItems: false, │ | ||
@@ -248,2 +246,3 @@ │ │ │ minItems: 2, │ | ||
│ │ │ │ | ||
│ │ │ │ | ||
├────────────────────────────────┼─────────────────────────────┼────────────────────────────────┤ | ||
@@ -262,15 +261,18 @@ │ enum Foo { │ enum Foo { │ const T = { │ | ||
│ const T = Type.KeyOf( │ type T = keyof { │ const T = { │ | ||
│ Type.Object({ │ x: number, │ enum: ['x', 'y'], │ | ||
│ x: Type.Number(), │ y: number │ type: 'string' │ | ||
│ y: Type.Number() │ } │ } │ | ||
│ }) │ │ │ | ||
│ ) │ │ │ | ||
│ Type.Object({ │ x: number, │ anyOf: [{ │ | ||
│ x: Type.Number(), │ y: number │ type: 'string', │ | ||
│ y: Type.Number() │ } │ const: 'x' │ | ||
│ }) │ │ }, { │ | ||
│ ) │ │ type: 'string', │ | ||
│ │ │ const: 'y', │ | ||
│ │ │ }] │ | ||
│ │ │ } │ | ||
│ │ │ │ | ||
├────────────────────────────────┼─────────────────────────────┼────────────────────────────────┤ | ||
│ const T = Type.Union([ │ type T = string | number │ const T = { │ | ||
│ Type.String(), │ │ anyOf: [{ │ | ||
│ Type.Number() │ │ type: 'string' │ | ||
│ ]) │ │ }, { │ | ||
│ │ │ type: 'number' │ | ||
│ │ │ }] │ | ||
│ Type.String(), │ │ anyOf: [{ │ | ||
│ Type.Number() │ │ type: 'string' │ | ||
│ ]) │ │ }, { │ | ||
│ │ │ type: 'number' │ | ||
│ │ │ }] │ | ||
│ │ │ } │ | ||
@@ -280,29 +282,22 @@ │ │ │ │ | ||
│ const T = Type.Intersect([ │ type T = { │ const T = { │ | ||
│ Type.Object({ │ x: number │ allOf: [{ │ | ||
│ x: Type.Number() │ } & { │ type: 'object', │ | ||
│ }), │ y: number │ properties: { │ | ||
│ Type.Object({ │ } │ x: { │ | ||
│ y: Type.Number() │ │ type: 'number' │ | ||
│ }) │ │ } │ | ||
│ ]) │ │ }, │ | ||
│ │ │ required: ['x'] │ | ||
│ │ │ }, { │ | ||
│ │ │ type: 'object', │ | ||
│ │ │ properties: { │ | ||
│ │ │ y: { │ | ||
│ │ │ type: 'number' │ | ||
│ │ │ } │ | ||
│ │ │ }, │ | ||
│ │ │ required: ['y'] │ | ||
│ │ │ }] │ | ||
│ Type.Object({ │ x: number │ type: 'object', │ | ||
│ x: Type.Number() │ } & { │ properties: { │ | ||
│ }), │ y: number │ x: { │ | ||
│ Type.Object({ │ } │ type: 'number' │ | ||
│ y: Type.Number() │ │ }, │ | ||
│ }) │ │ y: { │ | ||
│ ]) │ │ type: 'number' │ | ||
│ │ │ } │ | ||
│ │ │ }, │ | ||
│ │ │ required: ['x', 'y'] │ | ||
│ │ │ } │ | ||
│ │ │ │ | ||
├────────────────────────────────┼─────────────────────────────┼────────────────────────────────┤ | ||
│ const T = Type.Record( │ type T = { │ const T = { │ | ||
│ Type.String(), │ [key: string]: number │ type: 'object', │ | ||
│ Type.Number() │ } │ patternProperties: { │ | ||
│ ) │ │ '^.*$': { │ | ||
│ │ │ type: 'number' │ | ||
│ │ │ } │ | ||
│ │ │ } │ | ||
│ const T = Type.Record( │ type T = Record< │ const T = { │ | ||
│ Type.String(), │ string, │ type: 'object', │ | ||
│ Type.Number() │ number, │ patternProperties: { │ | ||
│ ) │ > │ '^.*$': { │ | ||
│ │ │ type: 'number' │ | ||
│ │ │ } │ | ||
│ │ │ } │ | ||
│ │ │ } │ | ||
@@ -312,9 +307,9 @@ │ │ │ │ | ||
│ const T = Type.Partial( │ type T = Partial<{ │ const T = { │ | ||
│ Type.Object({ │ x: number, │ type: 'object', │ | ||
│ x: Type.Number(), │ y: number │ properties: { │ | ||
│ y: Type.Number() | }> │ x: { │ | ||
│ }) │ │ type: 'number' │ | ||
│ Type.Object({ │ x: number, │ type: 'object', │ | ||
│ x: Type.Number(), │ y: number │ properties: { │ | ||
│ y: Type.Number() | }> │ x: { │ | ||
│ }) │ │ type: 'number' │ | ||
│ ) │ │ }, │ | ||
│ │ │ y: { │ | ||
│ │ │ type: 'number' │ | ||
│ │ │ type: 'number' │ | ||
│ │ │ } │ | ||
@@ -326,10 +321,10 @@ │ │ │ } │ | ||
│ const T = Type.Required( │ type T = Required<{ │ const T = { │ | ||
│ Type.Object({ │ x?: number, │ type: 'object', │ | ||
│ x: Type.Optional( │ y?: number │ properties: { │ | ||
│ Type.Number() | }> │ x: { │ | ||
│ ), │ │ type: 'number' │ | ||
│ y: Type.Optional( │ │ }, │ | ||
│ Type.Number() │ │ y: { │ | ||
│ ) │ │ type: 'number' │ | ||
│ }) │ │ } │ | ||
│ Type.Object({ │ x?: number, │ type: 'object', │ | ||
│ x: Type.Optional( │ y?: number │ properties: { │ | ||
│ Type.Number() | }> │ x: { │ | ||
│ ), │ │ type: 'number' │ | ||
│ y: Type.Optional( │ │ }, │ | ||
│ Type.Number() │ │ y: { │ | ||
│ ) │ │ type: 'number' │ | ||
│ }) │ │ } │ | ||
│ ) │ │ }, │ | ||
@@ -341,6 +336,6 @@ │ │ │ required: ['x', 'y'] │ | ||
│ const T = Type.Pick( │ type T = Pick<{ │ const T = { │ | ||
│ Type.Object({ │ x: number, │ type: 'object', │ | ||
│ x: Type.Number(), │ y: number │ properties: { │ | ||
│ y: Type.Number(), | }, 'x'> │ x: { │ | ||
│ }), ['x'] │ │ type: 'number' │ | ||
│ Type.Object({ │ x: number, │ type: 'object', │ | ||
│ x: Type.Number(), │ y: number │ properties: { │ | ||
│ y: Type.Number(), | }, 'x'> │ x: { │ | ||
│ }), ['x'] │ │ type: 'number' │ | ||
│ ) │ │ } │ | ||
@@ -353,6 +348,6 @@ │ │ │ }, │ | ||
│ const T = Type.Omit( │ type T = Omit<{ │ const T = { │ | ||
│ Type.Object({ │ x: number, │ type: 'object', │ | ||
│ x: Type.Number(), │ y: number │ properties: { │ | ||
│ y: Type.Number(), | }, 'x'> │ y: { │ | ||
│ }), ['x'] │ │ type: 'number' │ | ||
│ Type.Object({ │ x: number, │ type: 'object', │ | ||
│ x: Type.Number(), │ y: number │ properties: { │ | ||
│ y: Type.Number(), | }, 'x'> │ y: { │ | ||
│ }), ['x'] │ │ type: 'number' │ | ||
│ ) │ │ } │ | ||
@@ -377,4 +372,4 @@ │ │ │ }, │ | ||
│ const T = Type.Object({ │ type T = { │ const T = { │ | ||
│ name: Type.Optional( │ name?: string, │ type: 'object', │ | ||
│ Type.String(), │ } │ properties: { │ | ||
│ name: Type.Optional( │ name?: string, │ type: 'object', │ | ||
│ Type.String(), │ } │ properties: { │ | ||
│ ) │ │ name: { │ | ||
@@ -388,7 +383,7 @@ │ }) │ │ type: 'string' │ | ||
│ const T = Type.Object({ │ type T = { │ const T = { │ | ||
│ name: Type.Readonly( │ readonly name: string, │ type: 'object', │ | ||
│ Type.String(), │ } │ properties: { │ | ||
│ ) │ │ name: { │ | ||
│ }) │ │ type: 'string' │ | ||
│ │ │ } │ | ||
│ name: Type.Readonly( │ readonly name: string, │ type: 'object', │ | ||
│ Type.String(), │ } │ properties: { │ | ||
│ ) │ │ name: { │ | ||
│ }) │ │ type: 'string' │ | ||
│ │ │ } │ | ||
│ │ │ }, │ | ||
@@ -400,7 +395,7 @@ │ │ │ required: ['name'] │ | ||
│ const T = Type.Object({ │ type T = { │ const T = { │ | ||
│ name: Type.ReadonlyOptional( │ readonly name?: string, │ type: 'object', │ | ||
│ Type.String(), │ } │ properties: { │ | ||
│ ) │ │ name: { │ | ||
│ }) │ │ type: 'string' │ | ||
│ │ │ } │ | ||
│ name: Type.ReadonlyOptional( │ readonly name?: string │ type: 'object', │ | ||
│ Type.String(), │ } │ properties: { │ | ||
│ ) │ │ name: { │ | ||
│ }) │ │ type: 'string' │ | ||
│ │ │ } │ | ||
│ │ │ } │ | ||
@@ -428,139 +423,3 @@ │ │ │ } │ | ||
``` | ||
<a name="Generic-Types"></a> | ||
### Generic Types | ||
Generic types can be created using functions. The following creates a generic `Nullable<T>` type. | ||
```typescript | ||
import { Type, Static, TSchema } from '@sinclair/typebox' | ||
// type Nullable<T> = T | null | ||
const Nullable = <T extends TSchema>(type: T) => Type.Union([type, Type.Null()]) | ||
const T = Nullable(Type.String()) // const T = { | ||
// "anyOf": [{ | ||
// type: 'string' | ||
// }, { | ||
// type: 'null' | ||
// }] | ||
// } | ||
type T = Static<typeof T> // type T = string | null | ||
const U = Nullable(Type.Number()) // const U = { | ||
// "anyOf": [{ | ||
// type: 'number' | ||
// }, { | ||
// type: 'null' | ||
// }] | ||
// } | ||
type U = Static<typeof U> // type U = number | null | ||
``` | ||
<a name="Reference-Types"></a> | ||
### Reference Types | ||
Types can be referenced with `Type.Ref(...)`. To reference a type, the target type must specify an `$id`. | ||
```typescript | ||
const T = Type.String({ $id: 'T' }) // const T = { | ||
// $id: 'T', | ||
// type: 'string' | ||
// } | ||
const R = Type.Ref(T) // const R = { | ||
// $ref: 'T' | ||
// } | ||
``` | ||
It can sometimes be helpful to organize shared referenced types under a common namespace. The `Type.Namespace(...)` function can be used to create a shared definition container for related types. The following creates a `Math3D` container and a `Vertex` structure that references types in the container. | ||
```typescript | ||
const Math3D = Type.Namespace({ // const Math3D = { | ||
Vector4: Type.Object({ // $id: 'Math3D', | ||
x: Type.Number(), // $defs: { | ||
y: Type.Number(), // Vector4: { | ||
z: Type.Number(), // type: 'object', | ||
w: Type.Number() // properties: { | ||
}), // x: { type: 'number' }, | ||
Vector3: Type.Object({ // y: { type: 'number' }, | ||
x: Type.Number(), // z: { type: 'number' }, | ||
y: Type.Number(), // w: { type: 'number' } | ||
z: Type.Number() // }, | ||
}), // required: ['x', 'y', 'z', 'w'] | ||
Vector2: Type.Object({ // }, | ||
x: Type.Number(), // Vector3: { | ||
y: Type.Number() // type: 'object', | ||
}) // properties: { | ||
}, { $id: 'Math3D' }) // x: { 'type': 'number' }, | ||
// y: { 'type': 'number' }, | ||
// z: { 'type': 'number' } | ||
// }, | ||
// required: ['x', 'y', 'z'] | ||
// }, | ||
// Vector2: { | ||
// type: 'object', | ||
// properties: { | ||
// x: { 'type': 'number' }, | ||
// y: { 'type': 'number' }, | ||
// }, | ||
// required: ['x', 'y'] | ||
// } | ||
// } | ||
// } | ||
const Vertex = Type.Object({ // const Vertex = { | ||
position: Type.Ref(Math3D, 'Vector4'), // type: 'object', | ||
normal: Type.Ref(Math3D, 'Vector3'), // properties: { | ||
uv: Type.Ref(Math3D, 'Vector2') // position: { $ref: 'Math3D#/$defs/Vector4' }, | ||
}) // normal: { $ref: 'Math3D#/$defs/Vector3' }, | ||
// uv: { $ref: 'Math3D#/$defs/Vector2' } | ||
// }, | ||
// required: ['position', 'normal', 'uv'] | ||
// } | ||
``` | ||
<a name="Recursive-Types"></a> | ||
### Recursive Types | ||
Recursive types can be created with the `Type.Rec(...)` function. The following creates a `Node` type that contains an array of inner Nodes. Note that due to current restrictions on TypeScript inference, it is not possible for TypeBox to statically infer for recursive types. TypeBox will infer the inner recursive type as `any`. | ||
```typescript | ||
const Node = Type.Rec(Self => Type.Object({ // const Node = { | ||
id: Type.String(), // $id: 'Node', | ||
nodes: Type.Array(Self), // $ref: 'Node#/$defs/self', | ||
}), { $id: 'Node' }) // $defs: { | ||
// self: { | ||
// type: 'object', | ||
// properties: { | ||
// id: { | ||
// type: 'string' | ||
// }, | ||
// nodes: { | ||
// type: 'array', | ||
// items: { | ||
// $ref: 'Node#/$defs/self' | ||
// } | ||
// } | ||
// } | ||
// } | ||
// } | ||
type Node = Static<typeof Node> // type Node = { | ||
// id: string | ||
// nodes: any[] | ||
// } | ||
function visit(node: Node) { | ||
for(const inner of node.nodes) { | ||
visit(inner as Node) // Assert inner as Node | ||
} | ||
} | ||
``` | ||
<a name="Extended-Types"></a> | ||
@@ -578,10 +437,10 @@ | ||
│ const T = Type.Constructor([ │ type T = new ( │ const T = { │ | ||
│ Type.String(), │ arg0: string, │ type: 'constructor' │ | ||
│ Type.Number(), │ arg1: number │ arguments: [{ │ | ||
│ ], Type.Boolean()) │ ) => boolean │ type: 'string' │ | ||
│ Type.String(), │ arg0: string, │ type: 'constructor' │ | ||
│ Type.Number() │ arg1: number │ arguments: [{ │ | ||
│ ], Type.Boolean()) │ ) => boolean │ type: 'string' │ | ||
│ │ │ }, { │ | ||
│ │ │ type: 'number' │ | ||
│ │ │ type: 'number' │ | ||
│ │ │ }], │ | ||
│ │ │ returns: { │ | ||
│ │ │ type: 'boolean' │ | ||
│ │ │ type: 'boolean' │ | ||
│ │ │ } │ | ||
@@ -592,10 +451,10 @@ │ │ │ } │ | ||
│ const T = Type.Function([ │ type T = ( │ const T = { │ | ||
| Type.String(), │ arg0: string, │ type : 'function', │ | ||
│ Type.Number(), │ arg1: number │ arguments: [{ │ | ||
│ ], Type.Boolean()) │ ) => boolean │ type: 'string' │ | ||
| Type.String(), │ arg0: string, │ type : 'function', │ | ||
│ Type.Number() │ arg1: number │ arguments: [{ │ | ||
│ ], Type.Boolean()) │ ) => boolean │ type: 'string' │ | ||
│ │ │ }, { │ | ||
│ │ │ type: 'number' │ | ||
│ │ │ type: 'number' │ | ||
│ │ │ }], │ | ||
│ │ │ returns: { │ | ||
│ │ │ type: 'boolean' │ | ||
│ │ │ type: 'boolean' │ | ||
│ │ │ } │ | ||
@@ -605,6 +464,12 @@ │ │ │ } │ | ||
├────────────────────────────────┼─────────────────────────────┼────────────────────────────────┤ | ||
│ const T = Type.Uint8Array() │ type T = Uint8Array │ const T = { │ | ||
│ │ │ type: 'Uint8Array', │ | ||
│ │ │ specialized: 'Uint8Array' │ | ||
│ │ │ } │ | ||
│ │ │ │ | ||
├────────────────────────────────┼─────────────────────────────┼────────────────────────────────┤ | ||
│ const T = Type.Promise( │ type T = Promise<string> │ const T = { │ | ||
│ Type.String() │ │ type: 'promise', │ | ||
│ Type.String() │ │ type: 'promise', │ | ||
│ ) │ │ item: { │ | ||
│ │ │ type: 'string' │ | ||
│ │ │ type: 'string' │ | ||
│ │ │ } │ | ||
@@ -620,3 +485,3 @@ │ │ │ } │ | ||
│ const T = Type.Void() │ type T = void │ const T = { │ | ||
│ │ │ type: 'void' │ | ||
│ │ │ type: 'null' │ | ||
│ │ │ } │ | ||
@@ -627,2 +492,165 @@ │ │ │ │ | ||
<a name="Reference-Types"></a> | ||
### Reference Types | ||
Types can be referenced with `Type.Ref(...)`. To reference a type, the target type must specify an `$id`. | ||
```typescript | ||
const T = Type.String({ $id: 'T' }) // const T = { | ||
// $id: 'T', | ||
// type: 'string' | ||
// } | ||
const R = Type.Ref(T) // const R = { | ||
// $ref: 'T' | ||
// } | ||
``` | ||
<a name="Recursive-Types"></a> | ||
### Recursive Types | ||
Recursive types can be created with the `Type.Recursive(...)` function. | ||
```typescript | ||
const Node = Type.Recursive(Node => Type.Object({ // const Node = { | ||
id: Type.String(), // $id: "Node", | ||
nodes: Type.Array(Node), // type: "object", | ||
}), { $id: 'Node' }) // properties: { | ||
// id: { | ||
// "type": "string" | ||
// }, | ||
// nodes: { | ||
// type: "array", | ||
// items: { | ||
// $ref: "Node" | ||
// } | ||
// } | ||
// }, | ||
// required: [ | ||
// "id", | ||
// "nodes" | ||
// ] | ||
// } | ||
type Node = Static<typeof Node> // type Node = { | ||
// id: string | ||
// nodes: ... | ||
// } | ||
function visit(node: Node) { | ||
for(const inner of node.nodes) { | ||
visit(inner) | ||
} | ||
} | ||
``` | ||
<a name="Generic-Types"></a> | ||
### Generic Types | ||
Generic types can be created using functions. The following creates a generic `Nullable<T>` type. | ||
```typescript | ||
import { Type, Static, TSchema } from '@sinclair/typebox' | ||
const Nullable = <T extends TSchema>(type: T) => Type.Union([type, Type.Null()]) | ||
const T = Nullable(Type.String()) // const T = { | ||
// anyOf: [{ | ||
// type: 'string' | ||
// }, { | ||
// type: 'null' | ||
// }] | ||
// } | ||
type T = Static<typeof T> // type T = string | null | ||
const U = Nullable(Type.Number()) // const U = { | ||
// anyOf: [{ | ||
// type: 'number' | ||
// }, { | ||
// type: 'null' | ||
// }] | ||
// } | ||
type U = Static<typeof U> // type U = number | null | ||
``` | ||
<a name="Unsafe-Types"></a> | ||
### Unsafe Types | ||
In some cases, you may need schema definitions that are not provided by TypeBox. In these scenarios, it's common to want to define your own schema and static type inference rules. The `Type.Unsafe(...)` function provides this functionality, allowing you to specify both schema representation and a static type to infer. Consider the following which defines a `number` schema, but will infer as a `string`. | ||
```typescript | ||
const T = Type.Unsafe<string>({ type: 'number' }) // const T = { | ||
// type: 'number' | ||
// } | ||
type T = Static<typeof T> // type T = string | ||
``` | ||
The `Type.Unsafe(...)` function can be used with function generics to create custom schema representations for validators requiring specific schema representations. An example of which would be OpenAPI's `nullable` and `string-enum` representations which are not provided by TypeBox by default. The following demonstrates creating these schemas using the `Type.Unsafe(...)` function. | ||
```typescript | ||
import { Type, Static, TSchema } from '@sinclair/typebox' | ||
//-------------------------------------------------------------------------------------------- | ||
// | ||
// Nullable<T> | ||
// | ||
//-------------------------------------------------------------------------------------------- | ||
function Nullable<T extends TSchema>(schema: T) { | ||
return Type.Unsafe<Static<T> | null>({ ...schema, nullable: true }) | ||
} | ||
const T = Nullable(Type.String()) // const T = { | ||
// type: 'string', | ||
// nullable: true | ||
// } | ||
type T = Static<typeof T> // type T = string | null | ||
//-------------------------------------------------------------------------------------------- | ||
// | ||
// StringUnion<[...]> | ||
// | ||
//-------------------------------------------------------------------------------------------- | ||
function StringEnum<T extends string[]>(values: [...T]) { | ||
return Type.Unsafe<T[number]>({ enum: values }) | ||
} | ||
const T = StringEnum(['A', 'B', 'C']) // const T = { | ||
// enum: ['A', 'B', 'C'] | ||
// } | ||
type T = Static<typeof T> // type T = 'A' | 'B' | 'C' | ||
``` | ||
<a name="Values"></a> | ||
### Values | ||
TypeBox can construct default values for types. TypeBox will create reasonable defaults for any given type, or produce values based on the schemas the `default` value if specified. | ||
```typescript | ||
import { Value } from '@sinclair/typebox/value' | ||
import { Type } from '@sinclair/typebox' | ||
const T = Type.Object({ | ||
x: Type.Number({ default: 1 }), | ||
y: Type.Number({ default: 2 }), | ||
z: Type.Number() | ||
}) | ||
const V = Value.Create(T) // const V = { | ||
// x: 1, | ||
// y: 2, | ||
// z: 0 | ||
// } | ||
``` | ||
<a name="Strict"></a> | ||
@@ -632,25 +660,25 @@ | ||
TypeBox schemas contain the properties `kind` and `modifier`. These properties are provided to enable runtime type reflection on schemas, as well as helping TypeBox apply the appropriate static type inference rules. 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. | ||
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. | ||
```typescript | ||
const T = Type.Object({ // const T = { | ||
name: Type.Optional(Type.String()) // kind: Symbol(ObjectKind), | ||
}) // type: 'object', | ||
// properties: { | ||
// name: { | ||
// kind: Symbol(StringKind), | ||
// type: 'string', | ||
// modifier: Symbol(OptionalModifier) | ||
// } | ||
// } | ||
// } | ||
const T = Type.Object({ // const T = { | ||
name: Type.Optional(Type.String()) // [Kind]: 'Object', | ||
}) // type: 'object', | ||
// properties: { | ||
// name: { | ||
// [Kind]: 'String', | ||
// type: 'string', | ||
// [Modifier]: 'Optional' | ||
// } | ||
// } | ||
// } | ||
const U = Type.Strict(T) // const U = { | ||
// type: 'object', | ||
// properties: { | ||
// name: { | ||
// type: 'string' | ||
// } | ||
// } | ||
// } | ||
const U = Type.Strict(T) // const U = { | ||
// type: 'object', | ||
// properties: { | ||
// name: { | ||
// type: 'string' | ||
// } | ||
// } | ||
// } | ||
``` | ||
@@ -662,3 +690,3 @@ | ||
TypeBox does not provide JSON schema validation so users will need to select an appropriate JSON Schema validator for their needs. TypeBox schemas target JSON Schema draft `2019-09` so any validator capable of draft `2019-09` 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. | ||
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. | ||
@@ -672,3 +700,3 @@ ```bash | ||
// | ||
// Import the 2019 compliant validator from AJV | ||
// Import TypeBox and AJV | ||
// | ||
@@ -679,3 +707,3 @@ //-------------------------------------------------------------------------------------------- | ||
import addFormats from 'ajv-formats' | ||
import Ajv from 'ajv/dist/2019' | ||
import Ajv from 'ajv' | ||
@@ -689,18 +717,17 @@ //-------------------------------------------------------------------------------------------- | ||
const ajv = addFormats(new Ajv({}), [ | ||
'date-time', | ||
'time', | ||
'date', | ||
'email', | ||
'hostname', | ||
'ipv4', | ||
'ipv6', | ||
'uri', | ||
'uri-reference', | ||
'uuid', | ||
'uri-template', | ||
'json-pointer', | ||
'relative-json-pointer', | ||
'regex' | ||
]).addKeyword('kind') | ||
.addKeyword('modifier') | ||
'date-time', | ||
'time', | ||
'date', | ||
'email', | ||
'hostname', | ||
'ipv4', | ||
'ipv6', | ||
'uri', | ||
'uri-reference', | ||
'uuid', | ||
'uri-template', | ||
'json-pointer', | ||
'relative-json-pointer', | ||
'regex' | ||
]) | ||
@@ -713,6 +740,6 @@ //-------------------------------------------------------------------------------------------- | ||
const User = Type.Object({ | ||
userId: Type.String({ format: 'uuid' }), | ||
email: Type.String({ format: 'email' }), | ||
online: Type.Boolean(), | ||
const Vector = Type.Object({ | ||
x: Type.Number(), | ||
y: Type.Number(), | ||
z: Type.Number(), | ||
}, { additionalProperties: false }) | ||
@@ -726,7 +753,7 @@ | ||
const ok = ajv.validate(User, { | ||
userId: '68b4b1d8-0db6-468d-b551-02069a692044', | ||
email: 'dave@domain.com', | ||
online: true | ||
}) // -> ok | ||
const OK = ajv.validate(Vector, { | ||
x: 1, | ||
y: 2, | ||
z: 3 | ||
}) // -> true | ||
``` | ||
@@ -736,43 +763,31 @@ | ||
### OpenAPI | ||
<a name="Compiler"></a> | ||
TypeBox can be used to create schemas for OpenAPI, however users should be mindful of some disparities between the JSON Schema and OpenAPI for versions prior to OpenAPI 3.1. Two common instances where OpenAPI diverges is the handling nullable and string enum schemas types. The following shows how you can use TypeBox to construct these types. | ||
### Compiler | ||
TypeBox provides an optional type compiler that can be used as a runtime type checker in absense of a JSON Schema validator. Please note that this compiler is not fully JSON Schema compliant and only permits compilation of TypeBox types only (where the schema representation is known in advance). The `TypeCompiler` contains a `TypeCompiler.Compile(T)` method that returns a `TypeCheck<T>` object that can be used to test the validity of a value. | ||
```typescript | ||
import { Type, Static, TNull, TLiteral, TUnion, TSchema } from '@sinclair/typebox' | ||
import { TypeCompiler } from '@sinclair/typebox/compiler' | ||
import { Type } from '@sinclair/typebox' | ||
//-------------------------------------------------------------------------------------------- | ||
// | ||
// Nullable<T> | ||
// | ||
//-------------------------------------------------------------------------------------------- | ||
const T = Type.Object({ | ||
x: Type.Number(), | ||
y: Type.Number(), | ||
z: Type.Number() | ||
}) | ||
function Nullable<T extends TSchema>(schema: T): TUnion<[T, TNull]> { | ||
return { ...schema, nullable: true } as any | ||
} | ||
const C = TypeCompiler.Compile(T) | ||
const T = Nullable(Type.String()) // const T = { | ||
// type: 'string', | ||
// nullable: true | ||
// } | ||
const OK = C.Check({ | ||
x: 1, | ||
y: 2, | ||
z: 3 | ||
}) // -> true | ||
``` | ||
type T = Static<typeof T> // type T = string | null | ||
<a name="Contribute"></a> | ||
//-------------------------------------------------------------------------------------------- | ||
// | ||
// StringUnion<[...]> | ||
// | ||
//-------------------------------------------------------------------------------------------- | ||
### Contribute | ||
type IntoStringUnion<T> = {[K in keyof T]: T[K] extends string ? TLiteral<T[K]>: never } | ||
function StringUnion<T extends string[]>(values: [...T]): TUnion<IntoStringUnion<T>> { | ||
return { enum: values } as any | ||
} | ||
const T = StringUnion(['A', 'B', 'C']) // const T = { | ||
// enum: ['A', 'B', 'C'] | ||
// } | ||
type T = Static<typeof T> // type T = 'A' | 'B' | 'C' | ||
``` | ||
TypeBox is open to community contribution, however please ensure you submit an open issue before submitting your pull request. The TypeBox project does preference open community discussion prior to accepting new features. |
608
typebox.d.ts
@@ -1,55 +0,41 @@ | ||
export declare const ReadonlyOptionalModifier: unique symbol; | ||
export declare const OptionalModifier: unique symbol; | ||
export declare const ReadonlyModifier: unique symbol; | ||
export declare const Kind: unique symbol; | ||
export declare const Modifier: unique symbol; | ||
export declare type TModifier = TReadonlyOptional<TSchema> | TOptional<TSchema> | TReadonly<TSchema>; | ||
export declare type TReadonlyOptional<T extends TSchema> = T & { | ||
modifier: typeof ReadonlyOptionalModifier; | ||
export declare type TReadonly<T extends TSchema> = T & { | ||
[Modifier]: 'Readonly'; | ||
}; | ||
export declare type TOptional<T extends TSchema> = T & { | ||
modifier: typeof OptionalModifier; | ||
[Modifier]: 'Optional'; | ||
}; | ||
export declare type TReadonly<T extends TSchema> = T & { | ||
modifier: typeof ReadonlyModifier; | ||
export declare type TReadonlyOptional<T extends TSchema> = T & { | ||
[Modifier]: 'ReadonlyOptional'; | ||
}; | ||
export declare const NamespaceKind: unique symbol; | ||
export declare const KeyOfKind: unique symbol; | ||
export declare const IntersectKind: unique symbol; | ||
export declare const UnionKind: unique symbol; | ||
export declare const TupleKind: unique symbol; | ||
export declare const ObjectKind: unique symbol; | ||
export declare const RecordKind: unique symbol; | ||
export declare const ArrayKind: unique symbol; | ||
export declare const EnumKind: unique symbol; | ||
export declare const LiteralKind: unique symbol; | ||
export declare const StringKind: unique symbol; | ||
export declare const NumberKind: unique symbol; | ||
export declare const IntegerKind: unique symbol; | ||
export declare const BooleanKind: unique symbol; | ||
export declare const NullKind: unique symbol; | ||
export declare const UnknownKind: unique symbol; | ||
export declare const AnyKind: unique symbol; | ||
export declare const RefKind: unique symbol; | ||
export interface CustomOptions { | ||
export interface DesignType { | ||
type: string; | ||
[props: string]: any; | ||
} | ||
export interface SchemaOptions { | ||
$schema?: string; | ||
/** Id for this schema */ | ||
$id?: string; | ||
/** Title of this schema */ | ||
title?: string; | ||
/** Description of this schema */ | ||
description?: string; | ||
/** Default value hint for this schema */ | ||
default?: any; | ||
/** Example values matching this schema. */ | ||
examples?: any; | ||
/** Design metadata for this schema */ | ||
design?: DesignType; | ||
[prop: string]: any; | ||
} | ||
export declare type StringFormatOption = 'date-time' | 'time' | 'date' | 'email' | 'idn-email' | 'hostname' | 'idn-hostname' | 'ipv4' | 'ipv6' | 'uri' | 'uri-reference' | 'iri' | 'uuid' | 'iri-reference' | 'uri-template' | 'json-pointer' | 'relative-json-pointer' | 'regex'; | ||
export declare type StringOptions<TFormat extends string> = { | ||
minLength?: number; | ||
maxLength?: number; | ||
pattern?: string; | ||
format?: TFormat; | ||
contentEncoding?: '7bit' | '8bit' | 'binary' | 'quoted-printable' | 'base64'; | ||
contentMediaType?: string; | ||
} & CustomOptions; | ||
export declare type ArrayOptions = { | ||
uniqueItems?: boolean; | ||
minItems?: number; | ||
maxItems?: number; | ||
} & CustomOptions; | ||
export declare type NumberOptions = { | ||
export interface TSchema extends SchemaOptions { | ||
[Kind]: string; | ||
[Modifier]?: string; | ||
params: unknown[]; | ||
static: unknown; | ||
} | ||
export declare type TAnySchema = TSchema | TAny | TArray | TBoolean | TConstructor | TEnum | TFunction | TInteger | TLiteral | TNull | TNumber | TObject | TPromise | TRecord | TSelf | TRef | TString | TTuple | TUndefined | TUnion | TUint8Array | TUnknown | TVoid; | ||
export interface NumericOptions extends SchemaOptions { | ||
exclusiveMaximum?: number; | ||
@@ -60,52 +46,134 @@ exclusiveMinimum?: number; | ||
multipleOf?: number; | ||
} & CustomOptions; | ||
export declare type IntersectOptions = { | ||
unevaluatedProperties?: boolean; | ||
} & CustomOptions; | ||
export declare type ObjectOptions = { | ||
additionalProperties?: boolean; | ||
minProperties?: number; | ||
maxProperties?: number; | ||
} & CustomOptions; | ||
export declare type TDefinitions = { | ||
[key: string]: TSchema; | ||
}; | ||
export declare type TNamespace<T extends TDefinitions> = { | ||
kind: typeof NamespaceKind; | ||
$defs: T; | ||
} & CustomOptions; | ||
export interface TSchema { | ||
$static: unknown; | ||
} | ||
export declare type TEnumType = Record<string, string | number>; | ||
export declare type TKey = string | number | symbol; | ||
export declare type TValue = string | number | boolean; | ||
export declare type TRecordKey = TString | TNumber | TKeyOf<any> | TUnion<any>; | ||
export declare type TEnumKey<T = TKey> = { | ||
export declare type TNumeric = TInteger | TNumber; | ||
export interface TAny extends TSchema { | ||
[Kind]: 'Any'; | ||
static: any; | ||
} | ||
export interface ArrayOptions extends SchemaOptions { | ||
uniqueItems?: boolean; | ||
minItems?: number; | ||
maxItems?: number; | ||
} | ||
export interface TArray<T extends TSchema = TSchema> extends TSchema, ArrayOptions { | ||
[Kind]: 'Array'; | ||
static: Array<Static<T, this['params']>>; | ||
type: 'array'; | ||
items: T; | ||
} | ||
export interface TBoolean extends TSchema { | ||
[Kind]: 'Boolean'; | ||
static: boolean; | ||
type: 'boolean'; | ||
} | ||
export declare type TContructorParameters<T extends readonly TSchema[], P extends unknown[]> = [...{ | ||
[K in keyof T]: T[K] extends TSchema ? Static<T[K], P> : never; | ||
}]; | ||
export interface TConstructor<T extends TSchema[] = TSchema[], U extends TSchema = TSchema> extends TSchema { | ||
[Kind]: 'Constructor'; | ||
static: new (...param: TContructorParameters<T, this['params']>) => Static<U, this['params']>; | ||
type: 'constructor'; | ||
parameters: T; | ||
returns: U; | ||
} | ||
export interface TEnumOption<T> { | ||
type: 'number' | 'string'; | ||
const: T; | ||
} | ||
export interface TEnum<T extends Record<string, string | number> = Record<string, string | number>> extends TSchema { | ||
[Kind]: 'Union'; | ||
static: T[keyof T]; | ||
anyOf: TLiteral<string | number>[]; | ||
} | ||
export interface TExclude<T extends TUnion, U extends TUnion> extends TUnion { | ||
[Kind]: 'Union'; | ||
static: Exclude<Static<T, this['params']>, Static<U, this['params']>>; | ||
} | ||
export interface TExtract<T extends TSchema, U extends TUnion> extends TUnion { | ||
[Kind]: 'Union'; | ||
static: Extract<Static<T, this['params']>, Static<U, this['params']>>; | ||
} | ||
export declare type TExtends<T extends TSchema, U extends TSchema, X extends TSchema, Y extends TSchema> = T extends TAny ? (U extends TUnknown ? X : U extends TAny ? X : TUnion<[X, Y]>) : T extends U ? X : Y; | ||
export declare type TFunctionParameters<T extends readonly TSchema[], P extends unknown[]> = [...{ | ||
[K in keyof T]: T[K] extends TSchema ? Static<T[K], P> : never; | ||
}]; | ||
export interface TFunction<T extends readonly TSchema[] = TSchema[], U extends TSchema = TSchema> extends TSchema { | ||
[Kind]: 'Function'; | ||
static: (...param: TFunctionParameters<T, this['params']>) => Static<U, this['params']>; | ||
type: 'function'; | ||
parameters: T; | ||
returns: U; | ||
} | ||
export interface TInteger extends TSchema, NumericOptions { | ||
[Kind]: 'Integer'; | ||
static: number; | ||
type: 'integer'; | ||
} | ||
export declare type IntersectEvaluate<T extends readonly TSchema[], P extends unknown[]> = { | ||
[K in keyof T]: T[K] extends TSchema ? Static<T[K], P> : never; | ||
}; | ||
export declare type IntersectReduce<I extends unknown, T extends readonly any[]> = T extends [infer A, ...infer B] ? IntersectReduce<I & A, B> : I extends object ? I : {}; | ||
export interface TIntersect<T extends TObject[] = TObject[]> extends TObject { | ||
static: IntersectReduce<unknown, IntersectEvaluate<T, this['params']>>; | ||
properties: Record<keyof IntersectReduce<unknown, IntersectEvaluate<T, this['params']>>, TSchema>; | ||
} | ||
declare type UnionToIntersect<U> = (U extends unknown ? (arg: U) => 0 : never) extends (arg: infer I) => 0 ? I : never; | ||
declare type UnionLast<U> = UnionToIntersect<U extends unknown ? (x: U) => 0 : never> extends (x: infer L) => 0 ? L : never; | ||
declare type UnionToTuple<U, L = UnionLast<U>> = [U] extends [never] ? [] : [...UnionToTuple<Exclude<U, L>>, L]; | ||
export declare type TKeyOf<T extends TObject> = { | ||
[K in ObjectPropertyKeys<T>]: TLiteral<K>; | ||
} extends infer R ? UnionToTuple<R[keyof R]> : never; | ||
export declare type TLiteralValue = string | number | boolean; | ||
export interface TLiteral<T extends TLiteralValue = TLiteralValue> extends TSchema { | ||
[Kind]: 'Literal'; | ||
static: T; | ||
const: T; | ||
} | ||
export interface TNull extends TSchema { | ||
[Kind]: 'Null'; | ||
static: null; | ||
type: 'null'; | ||
} | ||
export interface TNumber extends TSchema, NumericOptions { | ||
[Kind]: 'Number'; | ||
static: number; | ||
type: 'number'; | ||
} | ||
export declare type ReadonlyOptionalPropertyKeys<T extends TProperties> = { | ||
[K in keyof T]: T[K] extends TReadonlyOptional<TSchema> ? K : never; | ||
}[keyof T]; | ||
export declare type ReadonlyPropertyKeys<T extends TProperties> = { | ||
[K in keyof T]: T[K] extends TReadonly<TSchema> ? K : never; | ||
}[keyof T]; | ||
export declare type OptionalPropertyKeys<T extends TProperties> = { | ||
[K in keyof T]: T[K] extends TOptional<TSchema> ? K : never; | ||
}[keyof T]; | ||
export declare type RequiredPropertyKeys<T extends TProperties> = keyof Omit<T, ReadonlyOptionalPropertyKeys<T> | ReadonlyPropertyKeys<T> | OptionalPropertyKeys<T>>; | ||
export declare type PropertiesReduce<T extends TProperties, P extends unknown[]> = { | ||
readonly [K in ReadonlyOptionalPropertyKeys<T>]?: Static<T[K], P>; | ||
} & { | ||
readonly [K in ReadonlyPropertyKeys<T>]: Static<T[K], P>; | ||
} & { | ||
[K in OptionalPropertyKeys<T>]?: Static<T[K], P>; | ||
} & { | ||
[K in RequiredPropertyKeys<T>]: Static<T[K], P>; | ||
} extends infer R ? { | ||
[K in keyof R]: R[K]; | ||
} : never; | ||
export declare type TRecordProperties<K extends TUnion<TLiteral[]>, T extends TSchema> = Static<K> extends string ? { | ||
[X in Static<K>]: T; | ||
} : never; | ||
export interface TProperties { | ||
[key: string]: TSchema; | ||
} | ||
export interface TRecord<K extends TRecordKey, T extends TSchema> extends TSchema, ObjectOptions { | ||
$static: StaticRecord<K, T>; | ||
kind: typeof RecordKind; | ||
type: 'object'; | ||
patternProperties: { | ||
[pattern: string]: T; | ||
}; | ||
export declare type ObjectProperties<T> = T extends TObject<infer U> ? U : never; | ||
export declare type ObjectPropertyKeys<T> = T extends TObject<infer U> ? keyof U : never; | ||
export interface ObjectOptions extends SchemaOptions { | ||
additionalProperties?: boolean; | ||
minProperties?: number; | ||
maxProperties?: number; | ||
} | ||
export interface TTuple<T extends TSchema[]> extends TSchema, CustomOptions { | ||
$static: StaticTuple<T>; | ||
kind: typeof TupleKind; | ||
type: 'array'; | ||
items?: T; | ||
additionalItems?: false; | ||
minItems: number; | ||
maxItems: number; | ||
} | ||
export interface TObject<T extends TProperties> extends TSchema, ObjectOptions { | ||
$static: StaticObject<T>; | ||
kind: typeof ObjectKind; | ||
export interface TObject<T extends TProperties = TProperties> extends TSchema, ObjectOptions { | ||
[Kind]: 'Object'; | ||
static: PropertiesReduce<T, this['params']>; | ||
type: 'object'; | ||
@@ -115,239 +183,189 @@ properties: T; | ||
} | ||
export interface TUnion<T extends TSchema[]> extends TSchema, CustomOptions { | ||
$static: StaticUnion<T>; | ||
kind: typeof UnionKind; | ||
anyOf: T; | ||
export interface TOmit<T extends TObject, Properties extends ObjectPropertyKeys<T>[]> extends TObject, ObjectOptions { | ||
static: Omit<Static<T, this['params']>, Properties[number]>; | ||
properties: T extends TObject ? Omit<T['properties'], Properties[number]> : never; | ||
} | ||
export interface TIntersect<T extends TSchema[]> extends TSchema, IntersectOptions { | ||
$static: StaticIntersect<T>; | ||
kind: typeof IntersectKind; | ||
type: 'object'; | ||
allOf: T; | ||
export interface TPartial<T extends TObject> extends TObject { | ||
static: Partial<Static<T, this['params']>>; | ||
} | ||
export interface TKeyOf<T extends TKey[]> extends TSchema, CustomOptions { | ||
$static: StaticKeyOf<T>; | ||
kind: typeof KeyOfKind; | ||
type: 'string'; | ||
enum: T; | ||
export interface TPick<T extends TObject, Properties extends ObjectPropertyKeys<T>[]> extends TObject, ObjectOptions { | ||
static: Pick<Static<T, this['params']>, Properties[number]>; | ||
properties: ObjectProperties<T>; | ||
} | ||
export interface TArray<T extends TSchema> extends TSchema, ArrayOptions { | ||
$static: StaticArray<T>; | ||
kind: typeof ArrayKind; | ||
type: 'array'; | ||
items: T; | ||
export interface TPromise<T extends TSchema = TSchema> extends TSchema { | ||
[Kind]: 'Promise'; | ||
static: Promise<Static<T, this['params']>>; | ||
type: 'promise'; | ||
item: TSchema; | ||
} | ||
export interface TLiteral<T extends TValue> extends TSchema, CustomOptions { | ||
$static: StaticLiteral<T>; | ||
kind: typeof LiteralKind; | ||
const: T; | ||
export declare type TRecordKey = TString | TNumber | TUnion<TLiteral<any>[]>; | ||
export interface TRecord<K extends TRecordKey = TRecordKey, T extends TSchema = TSchema> extends TSchema { | ||
[Kind]: 'Record'; | ||
static: Record<Static<K>, Static<T, this['params']>>; | ||
type: 'object'; | ||
patternProperties: { | ||
[pattern: string]: T; | ||
}; | ||
additionalProperties: false; | ||
} | ||
export interface TEnum<T extends TEnumKey[]> extends TSchema, CustomOptions { | ||
$static: StaticEnum<T>; | ||
kind: typeof EnumKind; | ||
anyOf: T; | ||
export interface TSelf extends TSchema { | ||
[Kind]: 'Self'; | ||
static: this['params'][0]; | ||
$ref: string; | ||
} | ||
export interface TRef<T extends TSchema> extends TSchema, CustomOptions { | ||
$static: Static<T>; | ||
kind: typeof RefKind; | ||
export declare type TRecursiveReduce<T extends TSchema> = Static<T, [TRecursiveReduce<T>]>; | ||
export interface TRecursive<T extends TSchema> extends TSchema { | ||
static: TRecursiveReduce<T>; | ||
} | ||
export interface TRef<T extends TSchema = TSchema> extends TSchema { | ||
[Kind]: 'Ref'; | ||
static: Static<T, this['params']>; | ||
$ref: string; | ||
} | ||
export interface TRequired<T extends TObject | TRef<TObject>> extends TObject { | ||
static: Required<Static<T, this['params']>>; | ||
} | ||
export declare type StringFormatOption = 'date-time' | 'time' | 'date' | 'email' | 'idn-email' | 'hostname' | 'idn-hostname' | 'ipv4' | 'ipv6' | 'uri' | 'uri-reference' | 'iri' | 'uuid' | 'iri-reference' | 'uri-template' | 'json-pointer' | 'relative-json-pointer' | 'regex'; | ||
export interface StringOptions<TFormat extends string> extends SchemaOptions { | ||
minLength?: number; | ||
maxLength?: number; | ||
pattern?: string; | ||
format?: TFormat; | ||
contentEncoding?: '7bit' | '8bit' | 'binary' | 'quoted-printable' | 'base64'; | ||
contentMediaType?: string; | ||
} | ||
export interface TString extends TSchema, StringOptions<string> { | ||
$static: string; | ||
kind: typeof StringKind; | ||
[Kind]: 'String'; | ||
static: string; | ||
type: 'string'; | ||
} | ||
export interface TNumber extends TSchema, NumberOptions { | ||
$static: number; | ||
kind: typeof NumberKind; | ||
type: 'number'; | ||
export interface TTuple<T extends TSchema[] = TSchema[]> extends TSchema { | ||
[Kind]: 'Tuple'; | ||
static: { | ||
[K in keyof T]: T[K] extends TSchema ? Static<T[K], this['params']> : T[K]; | ||
}; | ||
type: 'array'; | ||
items?: T; | ||
additionalItems?: false; | ||
minItems: number; | ||
maxItems: number; | ||
} | ||
export interface TInteger extends TSchema, NumberOptions { | ||
$static: number; | ||
kind: typeof IntegerKind; | ||
type: 'integer'; | ||
export interface TUndefined extends TSchema { | ||
[Kind]: 'Undefined'; | ||
specialized: 'Undefined'; | ||
static: undefined; | ||
type: 'object'; | ||
} | ||
export interface TBoolean extends TSchema, CustomOptions { | ||
$static: boolean; | ||
kind: typeof BooleanKind; | ||
type: 'boolean'; | ||
export interface TUnion<T extends TSchema[] = TSchema[]> extends TSchema { | ||
[Kind]: 'Union'; | ||
static: { | ||
[K in keyof T]: T[K] extends TSchema ? Static<T[K], this['params']> : never; | ||
}[number]; | ||
anyOf: T; | ||
} | ||
export interface TNull extends TSchema, CustomOptions { | ||
$static: null; | ||
kind: typeof NullKind; | ||
type: 'null'; | ||
export interface Uint8ArrayOptions extends SchemaOptions { | ||
maxByteLength?: number; | ||
minByteLength?: number; | ||
} | ||
export interface TUnknown extends TSchema, CustomOptions { | ||
$static: unknown; | ||
kind: typeof UnknownKind; | ||
export interface TUint8Array extends TSchema, Uint8ArrayOptions { | ||
[Kind]: 'Uint8Array'; | ||
static: Uint8Array; | ||
specialized: 'Uint8Array'; | ||
type: 'object'; | ||
} | ||
export interface TAny extends TSchema, CustomOptions { | ||
$static: any; | ||
kind: typeof AnyKind; | ||
export interface TUnknown extends TSchema { | ||
[Kind]: 'Unknown'; | ||
static: unknown; | ||
} | ||
export declare const ConstructorKind: unique symbol; | ||
export declare const FunctionKind: unique symbol; | ||
export declare const PromiseKind: unique symbol; | ||
export declare const UndefinedKind: unique symbol; | ||
export declare const VoidKind: unique symbol; | ||
export interface TConstructor<T extends TSchema[], U extends TSchema> extends TSchema, CustomOptions { | ||
$static: StaticConstructor<T, U>; | ||
kind: typeof ConstructorKind; | ||
type: 'constructor'; | ||
arguments: TSchema[]; | ||
returns: TSchema; | ||
export interface TUnsafe<T> extends TSchema { | ||
[Kind]: 'Unknown'; | ||
static: T; | ||
} | ||
export interface TFunction<T extends TSchema[], U extends TSchema> extends TSchema, CustomOptions { | ||
$static: StaticFunction<T, U>; | ||
kind: typeof FunctionKind; | ||
type: 'function'; | ||
arguments: TSchema[]; | ||
returns: TSchema; | ||
export interface TVoid extends TSchema { | ||
[Kind]: 'Void'; | ||
static: void; | ||
type: 'null'; | ||
} | ||
export interface TPromise<T extends TSchema> extends TSchema, CustomOptions { | ||
$static: StaticPromise<T>; | ||
kind: typeof PromiseKind; | ||
type: 'promise'; | ||
item: TSchema; | ||
} | ||
export interface TUndefined extends TSchema, CustomOptions { | ||
$static: undefined; | ||
kind: typeof UndefinedKind; | ||
type: 'undefined'; | ||
} | ||
export interface TVoid extends TSchema, CustomOptions { | ||
$static: void; | ||
kind: typeof VoidKind; | ||
type: 'void'; | ||
} | ||
export declare type Selectable = TObject<TProperties> | TRef<TObject<TProperties>>; | ||
export declare type SelectablePropertyKeys<T extends Selectable> = T extends TObject<infer U> ? keyof U : T extends TRef<TObject<infer U>> ? keyof U : never; | ||
export declare type SelectableProperties<T extends Selectable> = T extends TObject<infer U> ? U : T extends TRef<TObject<infer U>> ? U : never; | ||
export declare type UnionToIntersect<U> = (U extends any ? (k: U) => void : never) extends ((k: infer I) => void) ? I : never; | ||
export declare type StaticReadonlyOptionalPropertyKeys<T extends TProperties> = { | ||
[K in keyof T]: T[K] extends TReadonlyOptional<TSchema> ? K : never; | ||
}[keyof T]; | ||
export declare type StaticReadonlyPropertyKeys<T extends TProperties> = { | ||
[K in keyof T]: T[K] extends TReadonly<TSchema> ? K : never; | ||
}[keyof T]; | ||
export declare type StaticOptionalPropertyKeys<T extends TProperties> = { | ||
[K in keyof T]: T[K] extends TOptional<TSchema> ? K : never; | ||
}[keyof T]; | ||
export declare type StaticRequiredPropertyKeys<T extends TProperties> = keyof Omit<T, StaticReadonlyOptionalPropertyKeys<T> | StaticReadonlyPropertyKeys<T> | StaticOptionalPropertyKeys<T>>; | ||
export declare type StaticIntersectEvaluate<T extends readonly TSchema[]> = { | ||
[K in keyof T]: T[K] extends TSchema ? Static<T[K]> : never; | ||
}; | ||
export declare type StaticIntersectReduce<I extends unknown, T extends readonly any[]> = T extends [infer A, ...infer B] ? StaticIntersectReduce<I & A, B> : I; | ||
export declare type StaticRequired<T extends TProperties> = { | ||
[K in keyof T]: T[K] extends TReadonlyOptional<infer U> ? TReadonly<U> : T[K] extends TReadonly<infer U> ? TReadonly<U> : T[K] extends TOptional<infer U> ? U : T[K]; | ||
}; | ||
export declare type StaticPartial<T extends TProperties> = { | ||
[K in keyof T]: T[K] extends TReadonlyOptional<infer U> ? TReadonlyOptional<U> : T[K] extends TReadonly<infer U> ? TReadonlyOptional<U> : T[K] extends TOptional<infer U> ? TOptional<U> : TOptional<T[K]>; | ||
}; | ||
export declare type StaticProperties<T extends TProperties> = { | ||
readonly [K in StaticReadonlyOptionalPropertyKeys<T>]?: Static<T[K]>; | ||
} & { | ||
readonly [K in StaticReadonlyPropertyKeys<T>]: Static<T[K]>; | ||
} & { | ||
[K in StaticOptionalPropertyKeys<T>]?: Static<T[K]>; | ||
} & { | ||
[K in StaticRequiredPropertyKeys<T>]: Static<T[K]>; | ||
}; | ||
export declare type StaticRecord<K extends TRecordKey, T extends TSchema> = K extends TString ? Record<string, Static<T>> : K extends TNumber ? Record<number, Static<T>> : K extends TKeyOf<TKey[]> ? Record<K['$static'], Static<T>> : K extends TUnion<TSchema[]> ? Record<K['$static'], Static<T>> : never; | ||
export declare type StaticEnum<T> = T extends TEnumKey<infer U>[] ? U : never; | ||
export declare type StaticKeyOf<T extends TKey[]> = T extends Array<infer K> ? K : never; | ||
export declare type StaticIntersect<T extends readonly TSchema[]> = StaticIntersectReduce<unknown, StaticIntersectEvaluate<T>>; | ||
export declare type StaticUnion<T extends readonly TSchema[]> = { | ||
[K in keyof T]: T[K] extends TSchema ? Static<T[K]> : never; | ||
}[number]; | ||
export declare type StaticTuple<T extends readonly TSchema[]> = { | ||
[K in keyof T]: T[K] extends TSchema ? Static<T[K]> : never; | ||
}; | ||
export declare type StaticObject<T extends TProperties> = StaticProperties<T> extends infer I ? { | ||
[K in keyof I]: I[K]; | ||
} : never; | ||
export declare type StaticArray<T extends TSchema> = Array<Static<T>>; | ||
export declare type StaticLiteral<T extends TValue> = T; | ||
export declare type StaticParameters<T extends readonly TSchema[]> = { | ||
[K in keyof T]: T[K] extends TSchema ? Static<T[K]> : never; | ||
}; | ||
export declare type StaticConstructor<T extends readonly TSchema[], U extends TSchema> = new (...args: [...StaticParameters<T>]) => Static<U>; | ||
export declare type StaticFunction<T extends readonly TSchema[], U extends TSchema> = (...args: [...StaticParameters<T>]) => Static<U>; | ||
export declare type StaticPromise<T extends TSchema> = Promise<Static<T>>; | ||
export declare type Static<T extends TSchema> = T['$static']; | ||
/** Creates a static type from a TypeBox type */ | ||
export declare type Static<T extends TSchema, P extends unknown[] = []> = (T & { | ||
params: P; | ||
})['static']; | ||
export declare class TypeBuilder { | ||
protected readonly schemas: Map<string, TSchema>; | ||
constructor(); | ||
/** `Standard` Modifies an object property to be both readonly and optional */ | ||
/** Creates a readonly optional property */ | ||
ReadonlyOptional<T extends TSchema>(item: T): TReadonlyOptional<T>; | ||
/** `Standard` Modifies an object property to be readonly */ | ||
/** Creates a readonly property */ | ||
Readonly<T extends TSchema>(item: T): TReadonly<T>; | ||
/** `Standard` Modifies an object property to be optional */ | ||
/** Creates a optional property */ | ||
Optional<T extends TSchema>(item: T): TOptional<T>; | ||
/** `Standard` Creates a type type */ | ||
Tuple<T extends TSchema[]>(items: [...T], options?: CustomOptions): TTuple<T>; | ||
/** `Standard` Creates an object type with the given properties */ | ||
/** Creates a any type */ | ||
Any(options?: SchemaOptions): TAny; | ||
/** Creates a array type */ | ||
Array<T extends TSchema>(items: T, options?: ArrayOptions): TArray<T>; | ||
/** Creates a boolean type */ | ||
Boolean(options?: SchemaOptions): TBoolean; | ||
/** Creates a constructor type */ | ||
Constructor<T extends TSchema[], U extends TSchema>(parameters: [...T], returns: U, options?: SchemaOptions): TConstructor<T, U>; | ||
/** Creates a enum type */ | ||
Enum<T extends Record<string, string | number>>(item: T, options?: SchemaOptions): TEnum<T>; | ||
/** Creates a function type */ | ||
Function<T extends readonly TSchema[], U extends TSchema>(parameters: [...T], returns: U, options?: SchemaOptions): TFunction<T, U>; | ||
/** Creates a integer type */ | ||
Integer(options?: NumericOptions): TInteger; | ||
/** Creates a intersect type. */ | ||
Intersect<T extends TObject[]>(objects: [...T], options?: ObjectOptions): TIntersect<T>; | ||
/** Creates a keyof type */ | ||
KeyOf<T extends TObject>(object: T, options?: SchemaOptions): TUnion<TKeyOf<T>>; | ||
/** Creates a literal type. */ | ||
Literal<T extends TLiteralValue>(value: T, options?: SchemaOptions): TLiteral<T>; | ||
/** Creates a null type */ | ||
Null(options?: SchemaOptions): TNull; | ||
/** Creates a number type */ | ||
Number(options?: NumericOptions): TNumber; | ||
/** Creates an object type with the given properties */ | ||
Object<T extends TProperties>(properties: T, options?: ObjectOptions): TObject<T>; | ||
/** `Standard` Creates an intersect type. */ | ||
Intersect<T extends TSchema[]>(items: [...T], options?: IntersectOptions): TIntersect<T>; | ||
/** `Standard` Creates a union type */ | ||
Union<T extends TSchema[]>(items: [...T], options?: CustomOptions): TUnion<T>; | ||
/** `Standard` Creates an array type */ | ||
Array<T extends TSchema>(items: T, options?: ArrayOptions): TArray<T>; | ||
/** `Standard` Creates an enum type from a TypeScript enum */ | ||
Enum<T extends TEnumType>(item: T, options?: CustomOptions): TEnum<TEnumKey<T[keyof T]>[]>; | ||
/** `Standard` Creates a literal type. Supports string, number and boolean values only */ | ||
Literal<T extends TValue>(value: T, options?: CustomOptions): TLiteral<T>; | ||
/** `Standard` Creates a string type */ | ||
/** Creates a new object whose properties are omitted from the given object */ | ||
Omit<T extends TObject, Properties extends Array<ObjectPropertyKeys<T>>>(schema: T, keys: [...Properties], options?: ObjectOptions): TOmit<T, Properties>; | ||
/** Creates an object type whose properties are all optional */ | ||
Partial<T extends TObject>(schema: T, options?: ObjectOptions): TPartial<T>; | ||
/** Creates a new object whose properties are picked from the given object */ | ||
Pick<T extends TObject, Properties extends Array<ObjectPropertyKeys<T>>>(schema: T, keys: [...Properties], options?: ObjectOptions): TPick<T, Properties>; | ||
/** Creates a promise type. This type cannot be represented in schema. */ | ||
Promise<T extends TSchema>(item: T, options?: SchemaOptions): TPromise<T>; | ||
/** Creates an object whose properties are derived from the given string literal union. */ | ||
Record<K extends TUnion<TLiteral[]>, T extends TSchema>(key: K, schema: T, options?: ObjectOptions): TObject<TRecordProperties<K, T>>; | ||
/** Creates a record type */ | ||
Record<K extends TString | TNumber, T extends TSchema>(key: K, schema: T, options?: ObjectOptions): TRecord<K, T>; | ||
/** Creates a recursive object type */ | ||
Recursive<T extends TSchema>(callback: (self: TSelf) => T, options?: SchemaOptions): TRecursive<T>; | ||
/** Creates a reference schema */ | ||
Ref<T extends TSchema>(schema: T, options?: SchemaOptions): TRef<T>; | ||
/** Creates a string type from a regular expression */ | ||
RegEx(regex: RegExp, options?: SchemaOptions): TString; | ||
/** Creates an object type whose properties are all required */ | ||
Required<T extends TObject>(schema: T, options?: SchemaOptions): TRequired<T>; | ||
/** Removes Kind and Modifier symbol property keys from this schema */ | ||
Strict<T extends TSchema>(schema: T): T; | ||
/** Creates a string type */ | ||
String<TCustomFormatOption extends string>(options?: StringOptions<StringFormatOption | TCustomFormatOption>): TString; | ||
/** `Standard` Creates a string type from a regular expression */ | ||
RegEx(regex: RegExp, options?: CustomOptions): TString; | ||
/** `Standard` Creates a number type */ | ||
Number(options?: NumberOptions): TNumber; | ||
/** `Standard` Creates an integer type */ | ||
Integer(options?: NumberOptions): TInteger; | ||
/** `Standard` Creates a boolean type */ | ||
Boolean(options?: CustomOptions): TBoolean; | ||
/** `Standard` Creates a null type */ | ||
Null(options?: CustomOptions): TNull; | ||
/** `Standard` Creates an unknown type */ | ||
Unknown(options?: CustomOptions): TUnknown; | ||
/** `Standard` Creates an any type */ | ||
Any(options?: CustomOptions): TAny; | ||
/** `Standard` Creates a record type */ | ||
Record<K extends TRecordKey, T extends TSchema>(key: K, value: T, options?: ObjectOptions): TRecord<K, T>; | ||
/** `Standard` Creates a keyof type from the given object */ | ||
KeyOf<T extends TObject<TProperties> | TRef<TObject<TProperties>>>(object: T, options?: CustomOptions): TKeyOf<SelectablePropertyKeys<T>[]>; | ||
/** `Standard` Makes all properties in the given object type required */ | ||
Required<T extends TObject<TProperties> | TRef<TObject<TProperties>>>(object: T, options?: ObjectOptions): TObject<StaticRequired<T['properties']>>; | ||
/** `Standard` Makes all properties in the given object type optional */ | ||
Partial<T extends TObject<TProperties> | TRef<TObject<TProperties>>>(object: T, options?: ObjectOptions): TObject<StaticPartial<T['properties']>>; | ||
/** `Standard` Picks property keys from the given object type */ | ||
Pick<T extends TObject<TProperties> | TRef<TObject<TProperties>>, K extends SelectablePropertyKeys<T>[]>(object: T, keys: [...K], options?: ObjectOptions): TObject<Pick<SelectableProperties<T>, K[number]>>; | ||
/** `Standard` Omits property keys from the given object type */ | ||
Omit<T extends TObject<TProperties> | TRef<TObject<TProperties>>, K extends SelectablePropertyKeys<T>[]>(object: T, keys: [...K], options?: ObjectOptions): TObject<Omit<SelectableProperties<T>, K[number]>>; | ||
/** `Standard` Omits the `kind` and `modifier` properties from the underlying schema */ | ||
Strict<T extends TSchema>(schema: T, options?: CustomOptions): T; | ||
/** `Extended` Creates a constructor type */ | ||
Constructor<T extends TSchema[], U extends TSchema>(args: [...T], returns: U, options?: CustomOptions): TConstructor<T, U>; | ||
/** `Extended` Creates a function type */ | ||
Function<T extends TSchema[], U extends TSchema>(args: [...T], returns: U, options?: CustomOptions): TFunction<T, U>; | ||
/** `Extended` Creates a promise type */ | ||
Promise<T extends TSchema>(item: T, options?: CustomOptions): TPromise<T>; | ||
/** `Extended` Creates a undefined type */ | ||
Undefined(options?: CustomOptions): TUndefined; | ||
/** `Extended` Creates a void type */ | ||
Void(options?: CustomOptions): TVoid; | ||
/** `Standard` Creates a namespace for a set of related types */ | ||
Namespace<T extends TDefinitions>($defs: T, options?: CustomOptions): TNamespace<T>; | ||
/** `Standard` References a type within a namespace. The referenced namespace must specify an `$id` */ | ||
Ref<T extends TNamespace<TDefinitions>, K extends keyof T['$defs']>(namespace: T, key: K): TRef<T['$defs'][K]>; | ||
/** `Standard` References type. The referenced type must specify an `$id` */ | ||
Ref<T extends TSchema>(schema: T): TRef<T>; | ||
/** `Experimental` Creates a recursive type */ | ||
Rec<T extends TSchema>(callback: (self: TAny) => T, options?: CustomOptions): T; | ||
/** Conditionally stores and schema if it contains an $id and returns */ | ||
protected Store<T extends TSchema | TNamespace<TDefinitions>, S = Omit<T, '$static'>>(schema: S): T; | ||
/** Conditionally dereferences a schema if RefKind. Otherwise return argument */ | ||
protected Deref<T extends TSchema>(schema: T): any; | ||
/** Creates a tuple type */ | ||
Tuple<T extends TSchema[]>(items: [...T], options?: SchemaOptions): TTuple<T>; | ||
/** Creates a undefined type */ | ||
Undefined(options?: SchemaOptions): TUndefined; | ||
/** Creates a union type */ | ||
Union<T extends TSchema[]>(items: [...T], options?: SchemaOptions): TUnion<T>; | ||
/** Creates a Uint8Array type */ | ||
Uint8Array(options?: Uint8ArrayOptions): TUint8Array; | ||
/** Creates an unknown type */ | ||
Unknown(options?: SchemaOptions): TUnknown; | ||
/** Creates a user defined schema that infers as type T */ | ||
Unsafe<T>(options?: SchemaOptions): TUnsafe<T>; | ||
/** Creates a void type */ | ||
Void(options?: SchemaOptions): TVoid; | ||
/** Use this function to return TSchema with static and params omitted */ | ||
protected Create<T>(schema: Omit<T, 'static' | 'params'>): T; | ||
/** Clones the given value */ | ||
protected Clone(value: any): any; | ||
} | ||
/** JSON Schema Type Builder with Static Type Resolution for TypeScript */ | ||
export declare const Type: TypeBuilder; | ||
export {}; |
496
typebox.js
"use strict"; | ||
/*-------------------------------------------------------------------------- | ||
TypeBox: JSON Schema Type Builder with Static Type Resolution for TypeScript | ||
@sinclair/typebox | ||
The MIT License (MIT) | ||
Copyright (c) 2021 Haydn Paterson (sinclair) <haydn.developer@gmail.com> | ||
Copyright (c) 2022 Haydn Paterson (sinclair) <haydn.developer@gmail.com> | ||
@@ -30,317 +30,301 @@ Permission is hereby granted, free of charge, to any person obtaining a copy | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.Type = exports.TypeBuilder = exports.VoidKind = exports.UndefinedKind = exports.PromiseKind = exports.FunctionKind = exports.ConstructorKind = exports.RefKind = exports.AnyKind = exports.UnknownKind = exports.NullKind = exports.BooleanKind = exports.IntegerKind = exports.NumberKind = exports.StringKind = exports.LiteralKind = exports.EnumKind = exports.ArrayKind = exports.RecordKind = exports.ObjectKind = exports.TupleKind = exports.UnionKind = exports.IntersectKind = exports.KeyOfKind = exports.NamespaceKind = exports.ReadonlyModifier = exports.OptionalModifier = exports.ReadonlyOptionalModifier = void 0; | ||
exports.Type = exports.TypeBuilder = exports.Modifier = exports.Kind = void 0; | ||
// -------------------------------------------------------------------------- | ||
// Modifiers | ||
// Symbols | ||
// -------------------------------------------------------------------------- | ||
exports.ReadonlyOptionalModifier = Symbol('ReadonlyOptionalModifier'); | ||
exports.OptionalModifier = Symbol('OptionalModifier'); | ||
exports.ReadonlyModifier = Symbol('ReadonlyModifier'); | ||
exports.Kind = Symbol.for('TypeBox.Kind'); | ||
exports.Modifier = Symbol.for('TypeBox.Modifier'); | ||
// -------------------------------------------------------------------------- | ||
// Schema Standard | ||
// -------------------------------------------------------------------------- | ||
exports.NamespaceKind = Symbol('NamespaceKind'); | ||
exports.KeyOfKind = Symbol('KeyOfKind'); | ||
exports.IntersectKind = Symbol('IntersectKind'); | ||
exports.UnionKind = Symbol('UnionKind'); | ||
exports.TupleKind = Symbol('TupleKind'); | ||
exports.ObjectKind = Symbol('ObjectKind'); | ||
exports.RecordKind = Symbol('RecordKind'); | ||
exports.ArrayKind = Symbol('ArrayKind'); | ||
exports.EnumKind = Symbol('EnumKind'); | ||
exports.LiteralKind = Symbol('LiteralKind'); | ||
exports.StringKind = Symbol('StringKind'); | ||
exports.NumberKind = Symbol('NumberKind'); | ||
exports.IntegerKind = Symbol('IntegerKind'); | ||
exports.BooleanKind = Symbol('BooleanKind'); | ||
exports.NullKind = Symbol('NullKind'); | ||
exports.UnknownKind = Symbol('UnknownKind'); | ||
exports.AnyKind = Symbol('AnyKind'); | ||
exports.RefKind = Symbol('RefKind'); | ||
// -------------------------------------------------------------------------- | ||
// Extended Schema Types | ||
// -------------------------------------------------------------------------- | ||
exports.ConstructorKind = Symbol('ConstructorKind'); | ||
exports.FunctionKind = Symbol('FunctionKind'); | ||
exports.PromiseKind = Symbol('PromiseKind'); | ||
exports.UndefinedKind = Symbol('UndefinedKind'); | ||
exports.VoidKind = Symbol('VoidKind'); | ||
// -------------------------------------------------------------------------- | ||
// Utility | ||
// -------------------------------------------------------------------------- | ||
function isObject(object) { | ||
return typeof object === 'object' && object !== null && !Array.isArray(object); | ||
} | ||
function isArray(object) { | ||
return typeof object === 'object' && object !== null && Array.isArray(object); | ||
} | ||
function clone(object) { | ||
if (isObject(object)) | ||
return Object.keys(object).reduce((acc, key) => ({ ...acc, [key]: clone(object[key]) }), {}); | ||
if (isArray(object)) | ||
return object.map((item) => clone(item)); | ||
return object; | ||
} | ||
// -------------------------------------------------------------------------- | ||
// TypeBuilder | ||
// -------------------------------------------------------------------------- | ||
let TypeOrdinal = 0; | ||
class TypeBuilder { | ||
schemas; | ||
constructor() { | ||
this.schemas = new Map(); | ||
} | ||
/** `Standard` Modifies an object property to be both readonly and optional */ | ||
// ---------------------------------------------------------------------- | ||
// Modifiers | ||
// ---------------------------------------------------------------------- | ||
/** Creates a readonly optional property */ | ||
ReadonlyOptional(item) { | ||
return { ...item, modifier: exports.ReadonlyOptionalModifier }; | ||
return { [exports.Modifier]: 'ReadonlyOptional', ...item }; | ||
} | ||
/** `Standard` Modifies an object property to be readonly */ | ||
/** Creates a readonly property */ | ||
Readonly(item) { | ||
return { ...item, modifier: exports.ReadonlyModifier }; | ||
return { [exports.Modifier]: 'Readonly', ...item }; | ||
} | ||
/** `Standard` Modifies an object property to be optional */ | ||
/** Creates a optional property */ | ||
Optional(item) { | ||
return { ...item, modifier: exports.OptionalModifier }; | ||
return { [exports.Modifier]: 'Optional', ...item }; | ||
} | ||
/** `Standard` Creates a type type */ | ||
Tuple(items, options = {}) { | ||
const additionalItems = false; | ||
const minItems = items.length; | ||
const maxItems = items.length; | ||
const schema = ((items.length > 0) | ||
? { ...options, kind: exports.TupleKind, type: 'array', items, additionalItems, minItems, maxItems } | ||
: { ...options, kind: exports.TupleKind, type: 'array', minItems, maxItems }); | ||
return this.Store(schema); | ||
// ---------------------------------------------------------------------- | ||
// Types | ||
// ---------------------------------------------------------------------- | ||
/** Creates a any type */ | ||
Any(options = {}) { | ||
return this.Create({ ...options, [exports.Kind]: 'Any' }); | ||
} | ||
/** `Standard` Creates an object type with the given properties */ | ||
Object(properties, options = {}) { | ||
const property_names = Object.keys(properties); | ||
const optional = property_names.filter(name => { | ||
const candidate = properties[name]; | ||
return (candidate.modifier && | ||
(candidate.modifier === exports.OptionalModifier || | ||
candidate.modifier === exports.ReadonlyOptionalModifier)); | ||
}); | ||
const required_names = property_names.filter(name => !optional.includes(name)); | ||
const required = (required_names.length > 0) ? required_names : undefined; | ||
return this.Store(((required) | ||
? { ...options, kind: exports.ObjectKind, type: 'object', properties, required } | ||
: { ...options, kind: exports.ObjectKind, type: 'object', properties })); | ||
/** Creates a array type */ | ||
Array(items, options = {}) { | ||
return this.Create({ ...options, [exports.Kind]: 'Array', type: 'array', items }); | ||
} | ||
/** `Standard` Creates an intersect type. */ | ||
Intersect(items, options = {}) { | ||
return this.Store({ ...options, kind: exports.IntersectKind, type: 'object', allOf: items }); | ||
/** Creates a boolean type */ | ||
Boolean(options = {}) { | ||
return this.Create({ ...options, [exports.Kind]: 'Boolean', type: 'boolean' }); | ||
} | ||
/** `Standard` Creates a union type */ | ||
Union(items, options = {}) { | ||
return this.Store({ ...options, kind: exports.UnionKind, anyOf: items }); | ||
/** Creates a constructor type */ | ||
Constructor(parameters, returns, options = {}) { | ||
return this.Create({ ...options, [exports.Kind]: 'Constructor', type: 'constructor', parameters, returns }); | ||
} | ||
/** `Standard` Creates an array type */ | ||
Array(items, options = {}) { | ||
return this.Store({ ...options, kind: exports.ArrayKind, type: 'array', items }); | ||
} | ||
/** `Standard` Creates an enum type from a TypeScript enum */ | ||
/** Creates a enum type */ | ||
Enum(item, options = {}) { | ||
const values = Object.keys(item).filter(key => isNaN(key)).map(key => item[key]); | ||
const anyOf = values.map(value => typeof value === 'string' ? { type: 'string', const: value } : { type: 'number', const: value }); | ||
return this.Store({ ...options, kind: exports.EnumKind, anyOf }); | ||
const values = Object.keys(item) | ||
.filter((key) => isNaN(key)) | ||
.map((key) => item[key]); | ||
const anyOf = values.map((value) => (typeof value === 'string' ? { [exports.Kind]: 'Literal', type: 'string', const: value } : { [exports.Kind]: 'Literal', type: 'number', const: value })); | ||
return this.Create({ ...options, [exports.Kind]: 'Union', anyOf }); | ||
} | ||
/** `Standard` Creates a literal type. Supports string, number and boolean values only */ | ||
Literal(value, options = {}) { | ||
return this.Store({ ...options, kind: exports.LiteralKind, const: value, type: typeof value }); | ||
/** Creates a function type */ | ||
Function(parameters, returns, options = {}) { | ||
return this.Create({ ...options, [exports.Kind]: 'Function', type: 'function', parameters, returns }); | ||
} | ||
/** `Standard` Creates a string type */ | ||
String(options = {}) { | ||
return this.Store({ ...options, kind: exports.StringKind, type: 'string' }); | ||
/** Creates a integer type */ | ||
Integer(options = {}) { | ||
return this.Create({ ...options, [exports.Kind]: 'Integer', type: 'integer' }); | ||
} | ||
/** `Standard` Creates a string type from a regular expression */ | ||
RegEx(regex, options = {}) { | ||
return this.String({ ...options, pattern: regex.source }); | ||
/** Creates a intersect type. */ | ||
Intersect(objects, options = {}) { | ||
const isOptional = (schema) => (schema[exports.Modifier] && schema[exports.Modifier] === 'Optional') || schema[exports.Modifier] === 'ReadonlyOptional'; | ||
const [required, optional] = [new Set(), new Set()]; | ||
for (const object of objects) { | ||
for (const [key, schema] of Object.entries(object.properties)) { | ||
if (isOptional(schema)) | ||
optional.add(key); | ||
} | ||
} | ||
for (const object of objects) { | ||
for (const key of Object.keys(object.properties)) { | ||
if (!optional.has(key)) | ||
required.add(key); | ||
} | ||
} | ||
const properties = {}; | ||
for (const object of objects) { | ||
for (const [key, schema] of Object.entries(object.properties)) { | ||
delete schema[exports.Modifier]; | ||
properties[key] = properties[key] === undefined ? schema : { [exports.Kind]: 'Union', anyOf: [properties[key], { ...schema }] }; | ||
} | ||
} | ||
if (required.size > 0) { | ||
return this.Create({ ...options, [exports.Kind]: 'Object', type: 'object', properties, required: [...required] }); | ||
} | ||
else { | ||
return this.Create({ ...options, [exports.Kind]: 'Object', type: 'object', properties }); | ||
} | ||
} | ||
/** `Standard` Creates a number type */ | ||
Number(options = {}) { | ||
return this.Store({ ...options, kind: exports.NumberKind, type: 'number' }); | ||
/** Creates a keyof type */ | ||
KeyOf(object, options = {}) { | ||
const items = Object.keys(object.properties).map((key) => this.Create({ ...options, [exports.Kind]: 'Literal', type: 'string', const: key })); | ||
return this.Create({ ...options, [exports.Kind]: 'Union', anyOf: items }); | ||
} | ||
/** `Standard` Creates an integer type */ | ||
Integer(options = {}) { | ||
return this.Store({ ...options, kind: exports.IntegerKind, type: 'integer' }); | ||
/** Creates a literal type. */ | ||
Literal(value, options = {}) { | ||
return this.Create({ ...options, [exports.Kind]: 'Literal', const: value, type: typeof value }); | ||
} | ||
/** `Standard` Creates a boolean type */ | ||
Boolean(options = {}) { | ||
return this.Store({ ...options, kind: exports.BooleanKind, type: 'boolean' }); | ||
} | ||
/** `Standard` Creates a null type */ | ||
/** Creates a null type */ | ||
Null(options = {}) { | ||
return this.Store({ ...options, kind: exports.NullKind, type: 'null' }); | ||
return this.Create({ ...options, [exports.Kind]: 'Null', type: 'null' }); | ||
} | ||
/** `Standard` Creates an unknown type */ | ||
Unknown(options = {}) { | ||
return this.Store({ ...options, kind: exports.UnknownKind }); | ||
/** Creates a number type */ | ||
Number(options = {}) { | ||
return this.Create({ ...options, [exports.Kind]: 'Number', type: 'number' }); | ||
} | ||
/** `Standard` Creates an any type */ | ||
Any(options = {}) { | ||
return this.Store({ ...options, kind: exports.AnyKind }); | ||
/** Creates an object type with the given properties */ | ||
Object(properties, options = {}) { | ||
const property_names = Object.keys(properties); | ||
const optional = property_names.filter((name) => { | ||
const property = properties[name]; | ||
const modifier = property[exports.Modifier]; | ||
return modifier && (modifier === 'Optional' || modifier === 'ReadonlyOptional'); | ||
}); | ||
const required = property_names.filter((name) => !optional.includes(name)); | ||
if (required.length > 0) { | ||
return this.Create({ ...options, [exports.Kind]: 'Object', type: 'object', properties, required }); | ||
} | ||
else { | ||
return this.Create({ ...options, [exports.Kind]: 'Object', type: 'object', properties }); | ||
} | ||
} | ||
/** `Standard` Creates a record type */ | ||
Record(key, value, options = {}) { | ||
const pattern = (() => { | ||
switch (key.kind) { | ||
case exports.UnionKind: return `^${key.anyOf.map((literal) => literal.const).join('|')}$`; | ||
case exports.KeyOfKind: return `^${key.enum.join('|')}$`; | ||
case exports.NumberKind: return '^(0|[1-9][0-9]*)$'; | ||
case exports.StringKind: return key.pattern ? key.pattern : '^.*$'; | ||
default: throw Error('Invalid Record Key'); | ||
} | ||
})(); | ||
return this.Store({ ...options, kind: exports.RecordKind, type: 'object', patternProperties: { [pattern]: value } }); | ||
/** Creates a new object whose properties are omitted from the given object */ | ||
Omit(schema, keys, options = {}) { | ||
const next = { ...this.Clone(schema), ...options }; | ||
next.required = next.required ? next.required.filter((key) => !keys.includes(key)) : undefined; | ||
for (const key of Object.keys(next.properties)) { | ||
if (keys.includes(key)) | ||
delete next.properties[key]; | ||
} | ||
return this.Create(next); | ||
} | ||
/** `Standard` Creates a keyof type from the given object */ | ||
KeyOf(object, options = {}) { | ||
const source = this.Deref(object); | ||
const keys = Object.keys(source.properties); | ||
return this.Store({ ...options, kind: exports.KeyOfKind, type: 'string', enum: keys }); | ||
} | ||
/** `Standard` Makes all properties in the given object type required */ | ||
Required(object, options = {}) { | ||
const source = this.Deref(object); | ||
const schema = { ...clone(source), ...options }; | ||
schema.required = Object.keys(schema.properties); | ||
for (const key of Object.keys(schema.properties)) { | ||
const property = schema.properties[key]; | ||
switch (property.modifier) { | ||
case exports.ReadonlyOptionalModifier: | ||
property.modifier = exports.ReadonlyModifier; | ||
/** Creates an object type whose properties are all optional */ | ||
Partial(schema, options = {}) { | ||
const next = { ...this.Clone(schema), ...options }; | ||
delete next.required; | ||
for (const key of Object.keys(next.properties)) { | ||
const property = next.properties[key]; | ||
const modifer = property[exports.Modifier]; | ||
switch (modifer) { | ||
case 'ReadonlyOptional': | ||
property[exports.Modifier] = 'ReadonlyOptional'; | ||
break; | ||
case exports.ReadonlyModifier: | ||
property.modifier = exports.ReadonlyModifier; | ||
case 'Readonly': | ||
property[exports.Modifier] = 'ReadonlyOptional'; | ||
break; | ||
case exports.OptionalModifier: | ||
delete property.modifier; | ||
case 'Optional': | ||
property[exports.Modifier] = 'Optional'; | ||
break; | ||
default: | ||
delete property.modifier; | ||
property[exports.Modifier] = 'Optional'; | ||
break; | ||
} | ||
} | ||
return this.Store(schema); | ||
return this.Create(next); | ||
} | ||
/** `Standard` Makes all properties in the given object type optional */ | ||
Partial(object, options = {}) { | ||
const source = this.Deref(object); | ||
const schema = { ...clone(source), ...options }; | ||
delete schema.required; | ||
for (const key of Object.keys(schema.properties)) { | ||
const property = schema.properties[key]; | ||
switch (property.modifier) { | ||
case exports.ReadonlyOptionalModifier: | ||
property.modifier = exports.ReadonlyOptionalModifier; | ||
/** Creates a new object whose properties are picked from the given object */ | ||
Pick(schema, keys, options = {}) { | ||
const next = { ...this.Clone(schema), ...options }; | ||
next.required = next.required ? next.required.filter((key) => keys.includes(key)) : undefined; | ||
for (const key of Object.keys(next.properties)) { | ||
if (!keys.includes(key)) | ||
delete next.properties[key]; | ||
} | ||
return this.Create(next); | ||
} | ||
/** Creates a promise type. This type cannot be represented in schema. */ | ||
Promise(item, options = {}) { | ||
return this.Create({ ...options, [exports.Kind]: 'Promise', type: 'promise', item }); | ||
} | ||
/** Creates a record type */ | ||
Record(key, value, options = {}) { | ||
// If string literal union return TObject with properties extracted from union. | ||
if (key[exports.Kind] === 'Union') { | ||
return this.Object(key.anyOf.reduce((acc, literal) => { | ||
return { ...acc, [literal.const]: value }; | ||
}, {}), { ...options }); | ||
} | ||
// otherwise return TRecord with patternProperties | ||
const pattern = key[exports.Kind] === 'Number' ? '^(0|[1-9][0-9]*)$' : key[exports.Kind] === 'String' && key.pattern ? key.pattern : '^.*$'; | ||
return this.Create({ | ||
...options, | ||
[exports.Kind]: 'Record', | ||
type: 'object', | ||
patternProperties: { [pattern]: value }, | ||
additionalProperties: false, | ||
}); | ||
} | ||
/** Creates a recursive object type */ | ||
Recursive(callback, options = {}) { | ||
if (options.$id === undefined) | ||
options.$id = `type-${TypeOrdinal++}`; | ||
const self = callback({ [exports.Kind]: 'Self', $ref: `${options.$id}` }); | ||
self.$id = options.$id; | ||
return this.Create({ ...options, ...self }); | ||
} | ||
/** Creates a reference schema */ | ||
Ref(schema, options = {}) { | ||
if (schema.$id === undefined) | ||
throw Error('Cannot create reference schema as target schema as has no $id'); | ||
return this.Create({ ...options, [exports.Kind]: 'Ref', $ref: schema.$id }); | ||
} | ||
/** Creates a string type from a regular expression */ | ||
RegEx(regex, options = {}) { | ||
return this.Create({ ...options, [exports.Kind]: 'String', type: 'string', pattern: regex.source }); | ||
} | ||
/** Creates an object type whose properties are all required */ | ||
Required(schema, options = {}) { | ||
const next = { ...this.Clone(schema), ...options }; | ||
next.required = Object.keys(next.properties); | ||
for (const key of Object.keys(next.properties)) { | ||
const property = next.properties[key]; | ||
const modifier = property[exports.Modifier]; | ||
switch (modifier) { | ||
case 'ReadonlyOptional': | ||
property[exports.Modifier] = 'Readonly'; | ||
break; | ||
case exports.ReadonlyModifier: | ||
property.modifier = exports.ReadonlyOptionalModifier; | ||
case 'Readonly': | ||
property[exports.Modifier] = 'Readonly'; | ||
break; | ||
case exports.OptionalModifier: | ||
property.modifier = exports.OptionalModifier; | ||
case 'Optional': | ||
delete property[exports.Modifier]; | ||
break; | ||
default: | ||
property.modifier = exports.OptionalModifier; | ||
delete property[exports.Modifier]; | ||
break; | ||
} | ||
} | ||
return this.Store(schema); | ||
return this.Create(next); | ||
} | ||
/** `Standard` Picks property keys from the given object type */ | ||
Pick(object, keys, options = {}) { | ||
const source = this.Deref(object); | ||
const schema = { ...clone(source), ...options }; | ||
schema.required = schema.required ? schema.required.filter((key) => keys.includes(key)) : undefined; | ||
for (const key of Object.keys(schema.properties)) { | ||
if (!keys.includes(key)) | ||
delete schema.properties[key]; | ||
} | ||
return this.Store(schema); | ||
/** Removes Kind and Modifier symbol property keys from this schema */ | ||
Strict(schema) { | ||
return JSON.parse(JSON.stringify(schema)); | ||
} | ||
/** `Standard` Omits property keys from the given object type */ | ||
Omit(object, keys, options = {}) { | ||
const source = this.Deref(object); | ||
const schema = { ...clone(source), ...options }; | ||
schema.required = schema.required ? schema.required.filter((key) => !keys.includes(key)) : undefined; | ||
for (const key of Object.keys(schema.properties)) { | ||
if (keys.includes(key)) | ||
delete schema.properties[key]; | ||
} | ||
return this.Store(schema); | ||
/** Creates a string type */ | ||
String(options = {}) { | ||
return this.Create({ ...options, [exports.Kind]: 'String', type: 'string' }); | ||
} | ||
/** `Standard` Omits the `kind` and `modifier` properties from the underlying schema */ | ||
Strict(schema, options = {}) { | ||
return JSON.parse(JSON.stringify({ ...options, ...schema })); | ||
/** Creates a tuple type */ | ||
Tuple(items, options = {}) { | ||
const additionalItems = false; | ||
const minItems = items.length; | ||
const maxItems = items.length; | ||
const schema = (items.length > 0 ? { ...options, [exports.Kind]: 'Tuple', type: 'array', items, additionalItems, minItems, maxItems } : { ...options, [exports.Kind]: 'Tuple', type: 'array', minItems, maxItems }); | ||
return this.Create(schema); | ||
} | ||
/** `Extended` Creates a constructor type */ | ||
Constructor(args, returns, options = {}) { | ||
return this.Store({ ...options, kind: exports.ConstructorKind, type: 'constructor', arguments: args, returns }); | ||
/** Creates a undefined type */ | ||
Undefined(options = {}) { | ||
return this.Create({ ...options, [exports.Kind]: 'Undefined', type: 'object', specialized: 'Undefined' }); | ||
} | ||
/** `Extended` Creates a function type */ | ||
Function(args, returns, options = {}) { | ||
return this.Store({ ...options, kind: exports.FunctionKind, type: 'function', arguments: args, returns }); | ||
/** Creates a union type */ | ||
Union(items, options = {}) { | ||
return this.Create({ ...options, [exports.Kind]: 'Union', anyOf: items }); | ||
} | ||
/** `Extended` Creates a promise type */ | ||
Promise(item, options = {}) { | ||
return this.Store({ ...options, type: 'promise', kind: exports.PromiseKind, item }); | ||
/** Creates a Uint8Array type */ | ||
Uint8Array(options = {}) { | ||
return this.Create({ ...options, [exports.Kind]: 'Uint8Array', type: 'object', specialized: 'Uint8Array' }); | ||
} | ||
/** `Extended` Creates a undefined type */ | ||
Undefined(options = {}) { | ||
return this.Store({ ...options, type: 'undefined', kind: exports.UndefinedKind }); | ||
/** Creates an unknown type */ | ||
Unknown(options = {}) { | ||
return this.Create({ ...options, [exports.Kind]: 'Unknown' }); | ||
} | ||
/** `Extended` Creates a void type */ | ||
/** Creates a user defined schema that infers as type T */ | ||
Unsafe(options = {}) { | ||
return this.Create({ ...options, [exports.Kind]: 'Unknown' }); | ||
} | ||
/** Creates a void type */ | ||
Void(options = {}) { | ||
return this.Store({ ...options, type: 'void', kind: exports.VoidKind }); | ||
return this.Create({ ...options, [exports.Kind]: 'Void', type: 'null' }); | ||
} | ||
/** `Standard` Creates a namespace for a set of related types */ | ||
Namespace($defs, options = {}) { | ||
return this.Store({ ...options, kind: exports.NamespaceKind, $defs }); | ||
/** Use this function to return TSchema with static and params omitted */ | ||
Create(schema) { | ||
return schema; | ||
} | ||
Ref(...args) { | ||
if (args.length === 2) { | ||
const namespace = args[0]; | ||
const targetKey = args[1]; | ||
if (namespace.$id === undefined) | ||
throw new Error(`Referenced namespace has no $id`); | ||
if (!this.schemas.has(namespace.$id)) | ||
throw new Error(`Unable to locate namespace with $id '${namespace.$id}'`); | ||
return this.Store({ kind: exports.RefKind, $ref: `${namespace.$id}#/$defs/${targetKey}` }); | ||
/** Clones the given value */ | ||
Clone(value) { | ||
const isObject = (object) => typeof object === 'object' && object !== null && !Array.isArray(object); | ||
const isArray = (object) => typeof object === 'object' && object !== null && Array.isArray(object); | ||
if (isObject(value)) { | ||
return Object.keys(value).reduce((acc, key) => ({ | ||
...acc, | ||
[key]: this.Clone(value[key]), | ||
}), Object.getOwnPropertySymbols(value).reduce((acc, key) => ({ | ||
...acc, | ||
[key]: this.Clone(value[key]), | ||
}), {})); | ||
} | ||
else if (args.length === 1) { | ||
const target = args[0]; | ||
if (target.$id === undefined) | ||
throw new Error(`Referenced schema has no $id`); | ||
if (!this.schemas.has(target.$id)) | ||
throw new Error(`Unable to locate schema with $id '${target.$id}'`); | ||
return this.Store({ kind: exports.RefKind, $ref: target.$id }); | ||
else if (isArray(value)) { | ||
return value.map((item) => this.Clone(item)); | ||
} | ||
else { | ||
throw new Error('Type.Ref: Invalid arguments'); | ||
return value; | ||
} | ||
} | ||
/** `Experimental` Creates a recursive type */ | ||
Rec(callback, options = {}) { | ||
const $id = options.$id || ''; | ||
const self = callback({ $ref: `${$id}#/$defs/self` }); | ||
return this.Store({ ...options, $ref: `${$id}#/$defs/self`, $defs: { self } }); | ||
} | ||
/** Conditionally stores and schema if it contains an $id and returns */ | ||
Store(schema) { | ||
const $schema = schema; | ||
if (!$schema['$id']) | ||
return $schema; | ||
this.schemas.set($schema['$id'], $schema); | ||
return $schema; | ||
} | ||
/** Conditionally dereferences a schema if RefKind. Otherwise return argument */ | ||
Deref(schema) { | ||
const $schema = schema; | ||
if ($schema['kind'] !== exports.RefKind) | ||
return schema; | ||
if (!this.schemas.has($schema['$ref'])) | ||
throw Error(`Unable to locate schema with $id '${$schema['$ref']}'`); | ||
return this.Deref(this.schemas.get($schema['$ref'])); | ||
} | ||
} | ||
exports.TypeBuilder = TypeBuilder; | ||
/** JSON Schema Type Builder with Static Type Resolution for TypeScript */ | ||
exports.Type = new TypeBuilder(); |
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
Uses eval
Supply chain riskPackage uses dynamic code execution (e.g., eval()), which is a dangerous practice. This can prevent the code from running in certain environments and increases the risk that the code may contain exploits or malicious behavior.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
164932
27
2462
755
11
7