diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml
index e482eb7..7d9b211 100644
--- a/.github/workflows/build.yml
+++ b/.github/workflows/build.yml
@@ -8,7 +8,7 @@ jobs:
node: [16.x, 18.x, 20.x]
os: [ubuntu-latest, windows-latest, macOS-latest]
steps:
- - uses: actions/checkout@v2
+ - uses: actions/checkout@v3
- name: Install Node
uses: actions/setup-node@v3
with:
diff --git a/.github/workflows/nightly.yml b/.github/workflows/nightly.yml
index 7ad6b9d..d43b3bc 100644
--- a/.github/workflows/nightly.yml
+++ b/.github/workflows/nightly.yml
@@ -10,7 +10,7 @@ jobs:
node: [20.x]
os: [ubuntu-latest]
steps:
- - uses: actions/checkout@v2
+ - uses: actions/checkout@v3
- name: Install Node
uses: actions/setup-node@v3
with:
diff --git a/benchmark/measurement/index.ts b/benchmark/measurement/index.ts
deleted file mode 100644
index 6175663..0000000
--- a/benchmark/measurement/index.ts
+++ /dev/null
@@ -1,5 +0,0 @@
-import { shell } from '@sinclair/hammer'
-
-export async function measurement() {
- await shell(`hammer run benchmark/measurement/module/index.ts --dist target/benchmark/measurement`)
-}
diff --git a/changelog/0.24.6.md b/changelog/0.24.6.md
index 68477e0..b329dec 100644
--- a/changelog/0.24.6.md
+++ b/changelog/0.24.6.md
@@ -13,7 +13,7 @@ const T: any = {} // T is any
const { type } = T // unsafe: type is any
-if(TypeGuard.TString(T)) {
+if(TypeGuard.IsString(T)) {
const { type } = T // safe: type is 'string'
}
diff --git a/changelog/0.32.0.md b/changelog/0.32.0.md
new file mode 100644
index 0000000..83a1bdd
--- /dev/null
+++ b/changelog/0.32.0.md
@@ -0,0 +1,473 @@
+## [0.32.0](https://www.npmjs.com/package/@sinclair/typebox/v/0.32.0)
+
+## Overview
+
+Revision 0.32.0 adds support for ESM and carries out the work necessary to fully modularize the TypeBox type system to enable selective type imports. This revision also adds three new types (Mapped, Const, and Deref), along with two new Value functions (Clean and Default) as well as many enhancements to existing types (Index, KeyOf, RegExp, Optional and Readonly). This revision also carries out many internal optimizations to enhance type inference across all types.
+
+This revision is a milestone revision for the TypeBox project. It has several breaking changes and requires a minor revision.
+
+## Contents
+
+- [Type Imports](#Type-Imports)
+- [Value Function Import](#Value-Function-Imports)
+- [CommonJS and ESM](#CommonJS-and-ESM)
+- [Types](#Types)
+ - [Mapped Type](#Types-Mapped-Type)
+ - [Const Type](#Types-Const-Type)
+ - [Deref Type](#Types-Deref-Type)
+ - [RegExp Type](#Types-RegExp-Type)
+ - [Subtract Modifiers](#Types-Subtract-Modifiers)
+- [Values](#Values)
+ - [Clean Function](#Values-Clean-Function)
+ - [Default Function](#Values-Default-Function)
+- [Errors](#Errors)
+ - [Error Parameter](#Errors-Error-Parameter)
+- [Optimizations](#Optimizations)
+ - [Bundle Size](#Optimizations-Bundle-Size)
+- [Breaking](#Breaking)
+ - [Renamed Symbols](#Breaking-Renamed-Symbols)
+ - [TypeGuard Interface Change](#Breaking-TypeGuard-Interface-Change)
+ - [Value Submodule Imports](#Breaking-Value-Submodule-Imports)
+ - [Error Function](#Breaking-Error-Function)
+ - [RegEx](#Breaking-RegEx)
+
+
+
+### Type Imports
+
+Revision 0.32.0 adds the ability to import types individually.
+
+```typescript
+import { Type, type Static } from '@sinclair/typebox' // classic - 37.0 kb minified
+
+import { Object, String, Number, type Static } from '@sinclair/typebox' // selective - 6.5 kb minified
+```
+
+
+
+### Value Function Imports
+
+Revision 0.32.0 adds the ability to import value functions from the `/value` module path.
+
+```typescript
+import { Value } from '@sinclair/typebox/value' // classic - 61.5 kb minified
+
+import { Check } from '@sinclair/typebox/value' // selective - 18.2 kb minified
+```
+
+### CommonJS and ESM
+
+
+
+Revision 0.32.0 now publishes both CommonJS and ESM builds of TypeBox. Existing CommonJS users should not be impacted by the addition of ESM. For ESM users however, particularily those using bundlers, it's now possible to benefit from deep tree shake optimizations provided by modern bundler tooling.
+
+
+
+## Types
+
+Revision 0.32.0 adds three new types to the type system and makes enhancements to Readonly and Optional modifiers.
+
+
+
+### Mapped Type
+
+Revision 0.32.0 adds the Mapped type which replicates TS [Mapped Types](https://www.typescriptlang.org/docs/handbook/2/mapped-types.html) at runtime. The following shows the syntax comparison between TypeScript and TypeBox.
+
+#### TypeScript
+
+```typescript
+type T = {
+ x: number,
+ y: number,
+ z: number
+}
+
+type M = { [K in keyof T]: T[K] } // a mapped type
+```
+#### TypeBox
+```typescript
+const T = Type.Object({
+ x: Type.Number(),
+ y: Type.Number(),
+ z: Type.Number()
+})
+
+const M = Type.Mapped(Type.KeyOf(T), K => Type.Index(T, K)) // a mapped type
+```
+Mapped types use a functional design to replicate the TypeScript feature. For users interested in this type, it may be helpful to use the [TypeBox Workbench](https://sinclairzx81.github.io/typebox-workbench/) which can generate runtime Mapped types from TypeScript syntax.
+
+
+
+### Const Type
+
+Revision 0.32.0 adds a new Const type that creates `readonly` types from object, array and primitive literal values. This type analogs the TypeScript `as const` syntax. The following shows general usage.
+
+```typescript
+const A = Type.Const(1 as const) // const A: TLiteral<1>
+
+const B = Type.Const([1, 2, 3] as const) // const B: TReadonly,
+ // TLiteral<2>,
+ // TLiteral<3>
+ // ]>>
+
+const C = Type.Const({ // const C: TObject<{
+ x: 1, // x: TReadonly>,
+ y: 2, // y: TReadonly>,
+ z: 3 // z: TReadonly>,
+} as const) // }>
+```
+Revision 0.32.0 continues support for TypeScript 4.0, and because of this, the `as const` syntax must be appended to each literal value passed to the Const type. When TypeBox ends support for 4.0, updates will be made to this type to make use of [Const Type Parameters](https://devblogs.microsoft.com/typescript/announcing-typescript-5-0/#const-type-parameters). This update will enable TypeBox to correctly infer the readonly literal type without the need for `as const`.
+
+
+
+
+### Deref Type
+
+Revision 0.32.0 adds a new Type.Deref type which can be used to dereference type schematics.
+
+```typescript
+const Vector = Type.Object({ // const Vector = {
+ x: Type.Number(), // type: 'object',
+ y: Type.Number(), // required: ['x', 'y', 'z'],
+}, { $id: 'Vector' }) // properties: {
+ // x: { type: 'number' },
+ // y: { type: 'number' }
+ // },
+ // $id: 'Vector'
+ // }
+
+const VectorRef = Type.Ref(Vector) // const VectorRef = {
+ // $ref: 'Vector'
+ // }
+// ... Embedded Reference Type
+
+const Vertex = Type.Object({ // const Vertex = {
+ position: VectorRef, // type: 'object',
+ texcoord: VectorRef, // required: ['position', 'texcoord'],
+}) // properties: {
+ // position: { $ref: 'Vector' },
+ // texcoord: { $ref: 'Vector' }
+ // }
+ // }
+
+// ... Dereferenced Embedded Reference Type
+
+const VertexDeref = Type.Deref(Vertex, [Vector]) // const VertexDeref = {
+ // type: 'object',
+ // required: ['position', 'texcoord'],
+ // properties: {
+ // position: {
+ // type: 'object',
+ // required: ['x', 'y', 'z'],
+ // properties: {
+ // x: { type: 'number' },
+ // y: { type: 'number' }
+ // }
+ // },
+ // texcoord: {
+ // type: 'object',
+ // required: ['x', 'y', 'z'],
+ // properties: {
+ // x: { type: 'number' },
+ // y: { type: 'number' }
+ // }
+ // }
+ // }
+ // }
+```
+The addition of Deref was prompted by issues composing reference types with mapping types (such as Partial, Required, Pick and Omit) which is generally not supported. Prior to Revision 0.32.0, there was some expectation for users to maintain and dereference types manually. In 0.32.0, users will still need to maintain references, but Deref will offer a more convenient mechanism to normalize reference types prior to composition.
+
+
+
+
+### RegExp Type
+
+Revision 0.32.0 updates RegExp to support the full ECMA 262 regular expression syntax. In previous revisions, this type had been expressed as an alias for `TString` with a `pattern` to try ensure compliance with the [regular expression](https://json-schema.org/understanding-json-schema/reference/regular_expressions) subset supported by Json Schema. In Revision 0.32.0, RegExp is given a new type representation unto itself (named `TRegExp`) which houses both `source` and `flags` properties used to reconstruct a JavaScript regular expression object, making it properly distinct from `TString` and fully supportive of UTF-16.
+
+```typescript
+// Case Insensitive
+
+const T = Type.RegExp(/abc/i) // const T = {
+ // type: 'RegExp',
+ // source: 'abc',
+ // flags: 'i'
+ // }
+
+type T = Static // type T = string
+
+Value.Check(T, 'abc') // ok
+Value.Check(T, 'ABC') // ok
+
+// Extended Syntax
+
+const E = Type.RegExp(/|\p{Extended_Pictographic}/gu)
+
+Value.Check(E, '♥️♦️♠️♣️') // ok - emoji supported
+```
+
+The RegExp type can be thought of as a more capable TemplateLiteral that can only reasonably infer as `string`. Additionally, the RegExp inference type of `string` is unique to the other `[JavaScript]` types in that it does not infer as it's named type. The updates to RegExp were prompted by the limitations with Json Schema expressions, and to provide better options for users requiring general Unicode validation support. For Json Schema compliance, the recommendation moving forward will be to use either String with pattern or TemplateLiteral.
+
+```typescript
+const T = Type.String({ pattern: '^(a|b|c)$' }) // Json Schema compliant
+
+const T = Type.TemplateLiteral('${a|b|c}') // Json Schema compliant
+
+const T = Type.RegExp(/$(a|b|c)$/) // Non Json Schema compliant
+```
+
+
+
+### Subtract Modifier
+
+Revision 0.32.0 adds new overloads for Readonly and Optional modifiers that enable them to subtract (or remove) that modifier from a type. Both Readonly and Optional now accept an optional secondary boolean argument that if `false`, will remove the modifier.
+
+#### TypeScript
+```typescript
+type T = {
+ x?: number,
+ y?: number
+}
+type M = { [K in keyof T]-?: T[K] } // -? - subtract optional modifier
+```
+#### TypeBox
+```typescript
+const T = Type.Object({
+ x: Type.Optional(Type.Number()),
+ y: Type.Optional(Type.Number())
+})
+const M = Type.Mapped(Type.KeyOf(T), K => {
+ return Type.Optional(Type.Index(T, K), false) // false - subtract optional modifier
+})
+```
+Subtractive modifiers are provided in support of the new Mapped type feature.
+
+
+
+## Values
+
+Revision 0.32.0 adds two new functions to the Value module.
+
+
+
+### Clean Function
+
+Revision 0.32.0 adds a new Clean function that can be used to omit any values unknown to the type. This function will work irrespective of if `additionalProperties` is specified on the type. The Clean function is intended to replicate the functionality of Ajv's `removeAdditional` configuration.
+
+```typescript
+const T = Type.Object({
+ x: Type.Number(),
+ y: Type.Number()
+})
+
+const X = Value.Clean(T, null) // const 'X = null
+
+const Y = Value.Clean(T, { x: 1 }) // const 'Y = { x: 1 }
+
+const Z = Value.Clean(T, { x: 1, y: 2, z: 3 }) // const 'Z = { x: 1, y: 2 }
+```
+
+Note: the Clean function does not check the validity of the value being cleaned, and does not provide assurances that the result will be valid. Its return value is `unknown` and should be checked before use.
+
+
+
+### Default Function
+
+Revision 0.32.0 adds a new Default function that can be used to add missing values if the type specifies a `default` annotation. This function is intended to replicate Ajv's `useDefaults` functionality.
+
+```typescript
+const T = Type.Object({
+ x: Type.Number({ default: 0 }),
+ y: Type.Number({ default: 0 })
+})
+
+const X = Value.Default(T, null) // const 'X = null - non-enumerable
+
+const Y = Value.Default(T, { }) // const 'Y = { x: 0, y: 0 }
+
+const Z = Value.Default(T, { x: 1 }) // const 'Z = { x: 1, y: 0 }
+```
+
+The Default function does not check the validity of the value being defaulted, and does not provide assurances that the result will be valid. Its return value is `unknown` and should be checked before use.
+
+
+
+## Optimizations
+
+Following the work to modularize TypeBox's type system, additional optimizations were carried out across each submodule to only import dependent type infrastructure. This has led to some fairly significant reductions in output sizes across each submodule. The main TypeBox import has increased in size due in part to the new Mapped types feature and other associative types, however selective imports supported on this revision should offer options for users concerned about output bundle size. There will be contined work to optimize the new type system throughout 0.32.0 and subsequent revisions.
+
+The following shows the comparisons between 0.31.0 and 0.32.0.
+
+
+
+```typescript
+// Revision 0.31.0
+
+┌──────────────────────┬────────────┬────────────┬─────────────┐
+│ (index) │ Compiled │ Minified │ Compression │
+├──────────────────────┼────────────┼────────────┼─────────────┤
+│ typebox/compiler │ '163.6 kb' │ ' 71.6 kb' │ '2.28 x' │
+│ typebox/errors │ '113.3 kb' │ ' 50.1 kb' │ '2.26 x' │
+│ typebox/system │ ' 83.9 kb' │ ' 37.5 kb' │ '2.24 x' │
+│ typebox/value │ '191.1 kb' │ ' 82.3 kb' │ '2.32 x' │
+│ typebox │ ' 73.8 kb' │ ' 32.3 kb' │ '2.29 x' │
+└──────────────────────┴────────────┴────────────┴─────────────┘
+
+// Revision 0.32.0
+
+┌──────────────────────┬────────────┬────────────┬─────────────┐
+│ (index) │ Compiled │ Minified │ Compression │
+├──────────────────────┼────────────┼────────────┼─────────────┤
+│ typebox/compiler │ '120.6 kb' │ ' 52.9 kb' │ '2.28 x' │
+│ typebox/errors │ ' 55.7 kb' │ ' 25.5 kb' │ '2.19 x' │
+│ typebox/system │ ' 4.7 kb' │ ' 2.0 kb' │ '2.33 x' │
+│ typebox/value │ '146.2 kb' │ ' 62.0 kb' │ '2.36 x' │
+│ typebox │ ' 91.4 kb' │ ' 37.8 kb' │ '2.42 x' │
+└──────────────────────┴────────────┴────────────┴─────────────┘
+```
+
+
+## Errors
+
+Revision 0.32.0 makes some enhancements to errors.
+
+
+
+### Error Parameter
+
+Revision 0.32.0 updates TypeBox's ErrorFunction to accept an ErrorParameter that contains additional information regarding the cause of a validation error. In Revision 0.31.0, only `errorType` and `schema` were passed through to this function. In 0.32.0 the additional properties `value` and `path` are also passed through. This update was prompted by some users needing to be able to generate specific error messages derived from specific values or other associated information.
+
+The following shows the changes from 0.31.0 to 0.32.0.
+
+```typescript
+// Revision 0.31.0
+
+import { TypeSystemErrorFunction } from '@sinclair/typebox/system'
+
+TypeSystemErrorFunction.Set((schema, errorType) => {
+
+ return 'oh no, an error!'
+})
+
+// Revision 0.32.0
+
+import { SetErrorFunction } from '@sinclair/typebox/errors'
+
+SetErrorFunction(({ schema, errorType, path, value }) => { // as destructured object
+
+ return 'oh no, an error!'
+})
+```
+Note that Revision 0.32.0 does make a breaking interface change by moving the ErrorFunction from `/system` to `/errors`. See breaking changes for more information.
+
+
+
+## Breaking
+
+The following list the breaking changes in Revision 0.32.0.
+
+
+
+
+### Renamed Symbols
+
+Revision 0.32.0 renames the `Optional`, `Required` and `Transform` symbols to `OptionalKind`, `RequiredKind` and `TransformKind`. This change was necessary to avoid conflicts with exported type functions.
+
+```typescript
+// Revision 0.31.0
+import { Kind, Hint, Optional, Required, Transform } from '@sinclair/typebox' // these are symbols
+
+// Revision 0.32.0
+import {
+ Kind, Hint, OptionalKind, RequiredKind, TransformKind, // these are symbols
+ Optional, Required, Transform // these are type imports
+} from '@sinclair/typebox'
+```
+
+
+
+### TypeGuard Interface Change
+
+Revision 0.32.0 has a breaking interface change on the TypeGuard utility where the `T` prefixed guard functions have been updated to use the `Is` prefix. This naming change is perhaps somewhat more sensible than the previous naming, however the update was largely prompted by TypeScript compiler issues where interface types (i.e. `TString`) where conflicting with the `TString` functions leading to breakage in CommonJS.
+
+```typescript
+// Revision 0.31.0
+
+import { TypeGuard, Kind } from '@sinclair/typebox'
+
+const R = TypeGuard.TString({ ... })
+
+// Revision 0.32.0
+
+import { TypeGuard } from '@sinclair/typebox'
+
+const R = TypeGuard.IsString({ ... })
+```
+
+
+
+### Value Submodule Imports
+
+The value submodule function import paths are unfortunately no longer supported. Instead, these can be imported directly on the `/value` path. The need to break the submodule paths was mostly due to complexities configuring dual ESM and CommonJS publishing for the package, as well as retaining support for pre and post node16 module resolution (of which many complexities reside, both for Node as well as for TypeScript type module resolution)
+
+```typescript
+// Revision 0.31.0
+
+import { Check } from '@sinclair/typebox/value/check'
+
+// Revision 0.32.0
+
+import { Check } from '@sinclair/typebox/value'
+```
+
+
+
+### Error Function
+
+The TypeSystemErrorFunction has been replaced with SetErrorFunction which can be imported on the `/errors` submodule. This change is generally a tidy up, and to reserve the `/system` submodule for type system policy configuration, as well as future Json Schema generation options (draft 2020-12)
+
+```typescript
+// Revision 0.31.0
+
+import { TypeSystemErrorFunction, ValueErrorType, DefaultErrorFunction } from '@sinclair/typebox/system'
+
+TypeSystemErrorFunction.Set((schema, errorType) => { // i18n override
+ switch(errorType) {
+ /* en-US */ case ValueErrorType.String: return 'Expected string'
+ /* fr-FR */ case ValueErrorType.Number: return 'Nombre attendu'
+ /* ko-KR */ case ValueErrorType.Boolean: return '예상 부울'
+ /* en-US */ default: return DefaultErrorFunction(schema, errorType)
+ }
+})
+
+// Revision 0.32.0
+
+import { SetErrorFunction, ValueErrorType, DefaultErrorFunction } from '@sinclair/typebox/errors'
+
+SetErrorFunction((error) => { // i18n override
+ switch(error.errorType) {
+ /* en-US */ case ValueErrorType.String: return 'Expected string'
+ /* fr-FR */ case ValueErrorType.Number: return 'Nombre attendu'
+ /* ko-KR */ case ValueErrorType.Boolean: return '예상 부울'
+ /* en-US */ default: return DefaultErrorFunction(error)
+ }
+})
+```
+
+
+
+### RegEx
+
+This RegEx function was flagged for deprecation on 0.30.0. It has been removed on Revision 0.32.0. Use the Type.RegExp type, or Type.String with a pattern to remain compatible with the Json Schema specification.
+
+```typescript
+// Revision 0.31.0
+
+const T = Type.RegEx(/abc/) // deprecation warning
+
+// Revision 0.32.0
+
+const A = Type.RegExp(/abc/) // JavaScript Type
+
+const B = Type.String({ pattern: /abc/.source }) // Json Type
+```
\ No newline at end of file
diff --git a/example/annotation/annotation.ts b/example/annotation/annotation.ts
new file mode 100644
index 0000000..26bebaf
--- /dev/null
+++ b/example/annotation/annotation.ts
@@ -0,0 +1,148 @@
+/*--------------------------------------------------------------------------
+
+@sinclair/typebox
+
+The MIT License (MIT)
+
+Copyright (c) 2017-2023 Haydn Paterson (sinclair)
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+
+---------------------------------------------------------------------------*/
+
+import * as Types from '@sinclair/typebox'
+
+// -------------------------------------------------------------------
+// Annotation
+//
+// Generates TypeScript Type Annotations from TypeBox types
+// -------------------------------------------------------------------
+/** Generates TypeScript Type Annotations from TypeBox types */
+export namespace Annotation {
+ // -----------------------------------------------------------------
+ // Escape
+ // -----------------------------------------------------------------
+ function Escape(content: string) {
+ return content.replace(/'/g, "\\'")
+ }
+ // -----------------------------------------------------------------
+ // Types
+ // -----------------------------------------------------------------
+ function Intersect(schema: Types.TSchema[], references: Types.TSchema[]): string {
+ const [L, ...R] = schema
+ // prettier-ignore
+ return R.length === 0
+ ? `${Visit(L, references)}`
+ : `${Visit(L, references)} & ${Intersect(R, references)}`
+ }
+ function Union(schema: Types.TSchema[], references: Types.TSchema[]): string {
+ const [L, ...R] = schema
+ // prettier-ignore
+ return R.length === 0
+ ? `${Visit(L, references)}`
+ : `${Visit(L, references)} | ${Union(R, references)}`
+ }
+ function Tuple(schema: Types.TSchema[], references: Types.TSchema[]): string {
+ const [L, ...R] = schema
+ // prettier-ignore
+ return R.length > 0
+ ? `${Visit(L, references)}, ${Tuple(R, references)}`
+ : ``
+ }
+ function Property(schema: Types.TProperties, K: string, references: Types.TSchema[]): string {
+ const TK = schema[K]
+ // prettier-ignore
+ return (
+ Types.TypeGuard.IsOptional(TK) && Types.TypeGuard.IsReadonly(TK) ? `readonly ${K}?: ${Visit(TK, references)}` :
+ Types.TypeGuard.IsReadonly(TK) ? `readonly ${K}: ${Visit(TK, references)}` :
+ Types.TypeGuard.IsOptional(TK) ? `${K}?: ${Visit(TK, references)}` :
+ `${K}: ${Visit(TK, references)}`
+ )
+ }
+ function Properties(schema: Types.TProperties, K: string[], references: Types.TSchema[]): string {
+ const [L, ...R] = K
+ // prettier-ignore
+ return R.length === 0
+ ? `${Property(schema, L, references)}`
+ : `${Property(schema, L, references)}; ${Properties(schema, R, references)}`
+ }
+ function Parameters(schema: Types.TSchema[], I: number, references: Types.TSchema[]): string {
+ const [L, ...R] = schema
+ // prettier-ignore
+ return R.length === 0
+ ? `param_${I}: ${Visit(L, references)}`
+ : `param_${I}: ${Visit(L, references)}, ${Parameters(R, I + 1, references)}`
+ }
+ function Literal(schema: Types.TLiteral, references: Types.TSchema[]): string {
+ return typeof schema.const === 'string' ? `'${Escape(schema.const)}'` : schema.const.toString()
+ }
+ function Record(schema: Types.TRecord, references: Types.TSchema[]): string {
+ // prettier-ignore
+ return (
+ Types.PatternBooleanExact in schema.patternProperties ? `Record` :
+ Types.PatternNumberExact in schema.patternProperties ? `Record` :
+ Types.PatternStringExact in schema.patternProperties ? `Record` :
+ `{}`
+ )
+ }
+ function TemplateLiteral(schema: Types.TTemplateLiteral, references: Types.TSchema[]) {
+ const E = Types.TemplateLiteralParseExact(schema.pattern)
+ if (!Types.IsTemplateLiteralExpressionFinite(E)) return 'string'
+ return [...Types.TemplateLiteralExpressionGenerate(E)].map((literal) => `'${Escape(literal)}'`).join(' | ')
+ }
+ function Visit(schema: Types.TSchema, references: Types.TSchema[]): string {
+ // prettier-ignore
+ return (
+ Types.TypeGuard.IsAny(schema) ? 'any' :
+ Types.TypeGuard.IsArray(schema) ? `${Visit(schema.items, references)}[]` :
+ Types.TypeGuard.IsAsyncIterator(schema) ? `AsyncIterableIterator<${Visit(schema.items, references)}>` :
+ Types.TypeGuard.IsBigInt(schema) ? `bigint` :
+ Types.TypeGuard.IsBoolean(schema) ? `boolean` :
+ Types.TypeGuard.IsConstructor(schema) ? `new (${Parameters(schema.parameter, 0, references)}) => ${Visit(schema.returns, references)}` :
+ Types.TypeGuard.IsDate(schema) ? 'Date' :
+ Types.TypeGuard.IsFunction(schema) ? `(${Parameters(schema.parameters, 0, references)}) => ${Visit(schema.returns, references)}` :
+ Types.TypeGuard.IsInteger(schema) ? 'number' :
+ Types.TypeGuard.IsIntersect(schema) ? `(${Intersect(schema.allOf, references)})` :
+ Types.TypeGuard.IsIterator(schema) ? `IterableIterator<${Visit(schema.items, references)}>` :
+ Types.TypeGuard.IsLiteral(schema) ? `${Literal(schema, references)}` :
+ Types.TypeGuard.IsNever(schema) ? `never` :
+ Types.TypeGuard.IsNull(schema) ? `null` :
+ Types.TypeGuard.IsNot(schema) ? 'unknown' :
+ Types.TypeGuard.IsNumber(schema) ? 'number' :
+ Types.TypeGuard.IsObject(schema) ? `{ ${Properties(schema.properties, Object.getOwnPropertyNames(schema.properties), references)} }` :
+ Types.TypeGuard.IsPromise(schema) ? `Promise<${Visit(schema.item, references)}>` :
+ Types.TypeGuard.IsRecord(schema) ? `${Record(schema, references)}` :
+ Types.TypeGuard.IsRef(schema) ? `${Visit(Types.Type.Deref(schema, references), references)}` :
+ Types.TypeGuard.IsString(schema) ? 'string' :
+ Types.TypeGuard.IsSymbol(schema) ? 'symbol' :
+ Types.TypeGuard.IsTemplateLiteral(schema) ? `${TemplateLiteral(schema, references)}` :
+ Types.TypeGuard.IsThis(schema) ? 'unknown' : // requires named interface
+ Types.TypeGuard.IsTuple(schema) ? `[${Tuple(schema.items || [], references)}]` :
+ Types.TypeGuard.IsUint8Array(schema) ? `Uint8Array` :
+ Types.TypeGuard.IsUndefined(schema) ? 'undefined' :
+ Types.TypeGuard.IsUnion(schema) ? `${Union(schema.anyOf, references)}` :
+ Types.TypeGuard.IsVoid(schema) ? `void` :
+ 'unknown'
+ )
+ }
+ /** Generates a TypeScript annotation for the given schema */
+ export function Code(schema: Types.TSchema, references: Types.TSchema[] = []): string {
+ return Visit(schema, references)
+ }
+}
\ No newline at end of file
diff --git a/example/annotation/index.ts b/example/annotation/index.ts
new file mode 100644
index 0000000..34ccf26
--- /dev/null
+++ b/example/annotation/index.ts
@@ -0,0 +1 @@
+export * from './annotation'
\ No newline at end of file
diff --git a/examples/collections/array.ts b/example/collections/array.ts
similarity index 100%
rename from examples/collections/array.ts
rename to example/collections/array.ts
diff --git a/examples/collections/index.ts b/example/collections/index.ts
similarity index 100%
rename from examples/collections/index.ts
rename to example/collections/index.ts
diff --git a/examples/collections/map.ts b/example/collections/map.ts
similarity index 100%
rename from examples/collections/map.ts
rename to example/collections/map.ts
diff --git a/examples/collections/readme.md b/example/collections/readme.md
similarity index 100%
rename from examples/collections/readme.md
rename to example/collections/readme.md
diff --git a/examples/collections/set.ts b/example/collections/set.ts
similarity index 100%
rename from examples/collections/set.ts
rename to example/collections/set.ts
diff --git a/examples/formats/date-time.ts b/example/formats/date-time.ts
similarity index 100%
rename from examples/formats/date-time.ts
rename to example/formats/date-time.ts
diff --git a/examples/formats/date.ts b/example/formats/date.ts
similarity index 100%
rename from examples/formats/date.ts
rename to example/formats/date.ts
diff --git a/examples/formats/email.ts b/example/formats/email.ts
similarity index 100%
rename from examples/formats/email.ts
rename to example/formats/email.ts
diff --git a/examples/formats/index.ts b/example/formats/index.ts
similarity index 100%
rename from examples/formats/index.ts
rename to example/formats/index.ts
diff --git a/examples/formats/ipv4.ts b/example/formats/ipv4.ts
similarity index 100%
rename from examples/formats/ipv4.ts
rename to example/formats/ipv4.ts
diff --git a/examples/formats/ipv6.ts b/example/formats/ipv6.ts
similarity index 100%
rename from examples/formats/ipv6.ts
rename to example/formats/ipv6.ts
diff --git a/examples/formats/time.ts b/example/formats/time.ts
similarity index 100%
rename from examples/formats/time.ts
rename to example/formats/time.ts
diff --git a/examples/formats/url.ts b/example/formats/url.ts
similarity index 100%
rename from examples/formats/url.ts
rename to example/formats/url.ts
diff --git a/examples/formats/uuid.ts b/example/formats/uuid.ts
similarity index 100%
rename from examples/formats/uuid.ts
rename to example/formats/uuid.ts
diff --git a/examples/index.ts b/example/index.ts
similarity index 100%
rename from examples/index.ts
rename to example/index.ts
diff --git a/examples/prototypes/evaluate.ts b/example/prototypes/evaluate.ts
similarity index 82%
rename from examples/prototypes/evaluate.ts
rename to example/prototypes/evaluate.ts
index 5fa7b21..530972f 100644
--- a/examples/prototypes/evaluate.ts
+++ b/example/prototypes/evaluate.ts
@@ -44,7 +44,6 @@ import {
TTuple,
TProperties,
TIntersect,
- IntersectType,
TUnion,
TNever
} from '@sinclair/typebox'
@@ -75,7 +74,7 @@ export type TEvaluateArray = T extends [infer L, ...infer
[]
// prettier-ignore
export type TEvaluate =
- T extends TIntersect ? IntersectType> :
+ T extends TIntersect ? TIntersect> :
T extends TUnion ? TUnion> :
T extends TConstructor ? TConstructor, TEvaluate> :
T extends TFunction ? TFunction, TEvaluate> :
@@ -119,16 +118,16 @@ export function EvaluateArray(rest: T) {
// prettier-ignore
export function Evaluate(schema: T): TEvaluate {
return (
- TypeGuard.TIntersect(schema) ? Type.Intersect(EvaluateIntersectRest(schema.allOf)) :
- TypeGuard.TUnion(schema) ? Type.Union(EvaluateArray(schema.anyOf)) :
- TypeGuard.TAsyncIterator(schema) ? Type.AsyncIterator(Evaluate(schema.items)) :
- TypeGuard.TIterator(schema) ? Type.Iterator(Evaluate(schema.items)) :
- TypeGuard.TObject(schema) ? Type.Object(EvaluateProperties(schema.properties)) :
- TypeGuard.TConstructor(schema) ? Type.Constructor(EvaluateArray(schema.parameters), Evaluate(schema.returns)) :
- TypeGuard.TFunction(schema) ? Type.Function(EvaluateArray(schema.parameters), Evaluate(schema.returns)) :
- TypeGuard.TTuple(schema) ? Type.Tuple(EvaluateArray(schema.items)) :
- TypeGuard.TArray(schema) ? Type.Promise(Evaluate(schema.items)) :
- TypeGuard.TPromise(schema) ? Type.Promise(Evaluate(schema.item)) :
+ TypeGuard.IsIntersect(schema) ? Type.Intersect(EvaluateIntersectRest(schema.allOf)) :
+ TypeGuard.IsUnion(schema) ? Type.Union(EvaluateArray(schema.anyOf)) :
+ TypeGuard.IsAsyncIterator(schema) ? Type.AsyncIterator(Evaluate(schema.items)) :
+ TypeGuard.IsIterator(schema) ? Type.Iterator(Evaluate(schema.items)) :
+ TypeGuard.IsObject(schema) ? Type.Object(EvaluateProperties(schema.properties)) :
+ TypeGuard.IsConstructor(schema) ? Type.Constructor(EvaluateArray(schema.parameters), Evaluate(schema.returns)) :
+ TypeGuard.IsFunction(schema) ? Type.Function(EvaluateArray(schema.parameters), Evaluate(schema.returns)) :
+ TypeGuard.IsTuple(schema) ? Type.Tuple(EvaluateArray(schema.items)) :
+ TypeGuard.IsArray(schema) ? Type.Promise(Evaluate(schema.items)) :
+ TypeGuard.IsPromise(schema) ? Type.Promise(Evaluate(schema.item)) :
schema
) as TEvaluate
}
diff --git a/examples/prototypes/index.ts b/example/prototypes/index.ts
similarity index 98%
rename from examples/prototypes/index.ts
rename to example/prototypes/index.ts
index ef44e7d..4a70931 100644
--- a/examples/prototypes/index.ts
+++ b/example/prototypes/index.ts
@@ -26,7 +26,6 @@ THE SOFTWARE.
---------------------------------------------------------------------------*/
-export * from './const'
export * from './evaluate'
export * from './partial-deep'
export * from './union-enum'
diff --git a/examples/prototypes/partial-deep.ts b/example/prototypes/partial-deep.ts
similarity index 84%
rename from examples/prototypes/partial-deep.ts
rename to example/prototypes/partial-deep.ts
index 1315b65..c089618 100644
--- a/examples/prototypes/partial-deep.ts
+++ b/example/prototypes/partial-deep.ts
@@ -26,7 +26,7 @@ THE SOFTWARE.
---------------------------------------------------------------------------*/
-import { TypeGuard, Type, TSchema, TIntersect, TUnion, TObject, TPartial, TProperties, AssertRest, AssertType, Evaluate } from '@sinclair/typebox'
+import { TypeGuard, Type, TSchema, TIntersect, TUnion, TObject, TPartial, TProperties, Evaluate } from '@sinclair/typebox'
// -------------------------------------------------------------------------------------
// TDeepPartial
@@ -34,9 +34,10 @@ import { TypeGuard, Type, TSchema, TIntersect, TUnion, TObject, TPartial, TPrope
export type TPartialDeepProperties = {
[K in keyof T]: TPartial
}
-export type TPartialDeepRest = T extends [infer L, ...infer R]
- ? [TPartial>, ...TPartialDeepRest>]
- : []
+export type TPartialDeepRest =
+ T extends [infer L extends TSchema, ...infer R extends TSchema[]]
+ ? [TPartial, ...TPartialDeepRest]
+ : []
export type TPartialDeep =
T extends TIntersect ? TIntersect> :
T extends TUnion ? TUnion> :
@@ -57,9 +58,9 @@ function PartialDeepRest(rest: [...T]): TPartialDeepRest
/** Maps the given schema as deep partial, making all properties and sub properties optional */
export function PartialDeep(type: T): TPartialDeep {
return (
- TypeGuard.TIntersect(type) ? Type.Intersect(PartialDeepRest(type.allOf)) :
- TypeGuard.TUnion(type) ? Type.Union(PartialDeepRest(type.anyOf)) :
- TypeGuard.TObject(type) ? Type.Partial(Type.Object(PartialDeepProperties(type.properties))) :
+ TypeGuard.IsIntersect(type) ? Type.Intersect(PartialDeepRest(type.allOf)) :
+ TypeGuard.IsUnion(type) ? Type.Union(PartialDeepRest(type.anyOf)) :
+ TypeGuard.IsObject(type) ? Type.Partial(Type.Object(PartialDeepProperties(type.properties))) :
type
) as any
}
\ No newline at end of file
diff --git a/examples/prototypes/readme.md b/example/prototypes/readme.md
similarity index 100%
rename from examples/prototypes/readme.md
rename to example/prototypes/readme.md
diff --git a/examples/prototypes/union-enum.ts b/example/prototypes/union-enum.ts
similarity index 100%
rename from examples/prototypes/union-enum.ts
rename to example/prototypes/union-enum.ts
diff --git a/examples/prototypes/union-oneof.ts b/example/prototypes/union-oneof.ts
similarity index 100%
rename from examples/prototypes/union-oneof.ts
rename to example/prototypes/union-oneof.ts
diff --git a/examples/typedef/index.ts b/example/typedef/index.ts
similarity index 100%
rename from examples/typedef/index.ts
rename to example/typedef/index.ts
diff --git a/examples/typedef/readme.md b/example/typedef/readme.md
similarity index 100%
rename from examples/typedef/readme.md
rename to example/typedef/readme.md
diff --git a/examples/typedef/typedef.ts b/example/typedef/typedef.ts
similarity index 93%
rename from examples/typedef/typedef.ts
rename to example/typedef/typedef.ts
index 5eb12a3..233ac5c 100644
--- a/examples/typedef/typedef.ts
+++ b/example/typedef/typedef.ts
@@ -26,22 +26,11 @@ THE SOFTWARE.
---------------------------------------------------------------------------*/
-import { TypeSystemErrorFunction, DefaultErrorFunction } from '@sinclair/typebox/system'
-import * as Types from '@sinclair/typebox'
+import { SetErrorFunction, DefaultErrorFunction } from '@sinclair/typebox/errors'
+import * as Types from '@sinclair/typebox/type'
// --------------------------------------------------------------------------
-// Utility Types
-// --------------------------------------------------------------------------
-export type Assert = T extends U ? T : never
-export type Base = { m: string, t: string }
-export type Base16 = { m: 'F', t: '01', '0': '1', '1': '2', '2': '3', '3': '4', '4': '5', '5': '6', '6': '7', '7': '8', '8': '9', '9': 'A', 'A': 'B', 'B': 'C', 'C': 'D', 'D': 'E', 'E': 'F', 'F': '0' }
-export type Base10 = { m: '9', t: '01', '0': '1', '1': '2', '2': '3', '3': '4', '4': '5', '5': '6', '6': '7', '7': '8', '8': '9', '9': '0' }
-export type Reverse = T extends `${infer L}${infer R}` ? `${Reverse}${L}` : T
-export type Tick = T extends keyof B ? B[T] : never
-export type Next = T extends Assert['m'] ? Assert['t'] : T extends `${infer L}${infer R}` ? L extends Assert['m'] ? `${Assert, string>}${Next}` : `${Assert, string>}${R}` : never
-export type Increment = Reverse, B>>
-// --------------------------------------------------------------------------
-// SchemaOptions
+// Metadata
// --------------------------------------------------------------------------
export interface Metadata {
[name: string]: any
@@ -65,9 +54,10 @@ export interface TBoolean extends Types.TSchema {
// --------------------------------------------------------------------------
// TUnion
// --------------------------------------------------------------------------
-type InferUnion = T extends [infer L, ...infer R]
- ? Types.Evaluate<{ [_ in D]: Index } & Types.Static>> | InferUnion, D, Increment>>
- : never
+export type InferUnion =
+ T extends [infer L extends TStruct, ...infer R extends TStruct[]]
+ ? Types.Evaluate<{ [_ in D]: Index } & Types.Static> | InferUnion>>
+ : never
export interface TUnion extends Types.TSchema {
[Types.Kind]: 'TypeDef:Union'
@@ -170,14 +160,31 @@ export interface TString extends Types.TSchema {
// --------------------------------------------------------------------------
// TStruct
// --------------------------------------------------------------------------
+// used for structural type inference
type OptionalKeys = { [K in keyof T]: T[K] extends (Types.TOptional) ? T[K] : never }
type RequiredKeys = { [K in keyof T]: T[K] extends (Types.TOptional) ? never : T[K] }
+// static inference
+type ReadonlyOptionalPropertyKeys = { [K in keyof T]: T[K] extends Types.TReadonly ? (T[K] extends Types.TOptional ? K : never) : never }[keyof T]
+type ReadonlyPropertyKeys = { [K in keyof T]: T[K] extends Types.TReadonly ? (T[K] extends Types.TOptional ? never : K) : never }[keyof T]
+type OptionalPropertyKeys = { [K in keyof T]: T[K] extends Types.TOptional ? (T[K] extends Types.TReadonly ? never : K) : never }[keyof T]
+type RequiredPropertyKeys = keyof Omit | ReadonlyPropertyKeys | OptionalPropertyKeys>
+// prettier-ignore
+type StructStaticProperties> = Types.Evaluate<(
+ Readonly>>> &
+ Readonly>> &
+ Partial>> &
+ Required>>
+)>
+// prettier-ignore
+export type StructStatic = StructStaticProperties
+}>
export interface StructMetadata extends Metadata {
additionalProperties?: boolean
}
export interface TStruct extends Types.TSchema, StructMetadata {
[Types.Kind]: 'TypeDef:Struct'
- static: Types.PropertiesReduce
+ static: StructStatic
optionalProperties: { [K in Types.Assert, keyof T>]: T[K] }
properties: { [K in Types.Assert, keyof T>]: T[K] }
}
@@ -487,8 +494,8 @@ Types.TypeRegistry.Set('TypeDef:Timestamp', (schema, value) => Value
// --------------------------------------------------------------------------
// TypeSystemErrorFunction
// --------------------------------------------------------------------------
-TypeSystemErrorFunction.Set((schema, type) => {
- switch(schema[Types.Kind]) {
+SetErrorFunction((error) => {
+ switch(error.schema[Types.Kind]) {
case 'TypeDef:Array': return 'Expected Array'
case 'TypeDef:Boolean': return 'Expected Boolean'
case 'TypeDef:Union': return 'Expected Union'
@@ -503,7 +510,7 @@ TypeSystemErrorFunction.Set((schema, type) => {
case 'TypeDef:Struct': return 'Expected Struct'
case 'TypeDef:Timestamp': return 'Expected Timestamp'
}
- return DefaultErrorFunction(schema, type)
+ return DefaultErrorFunction(error)
})
// --------------------------------------------------------------------------
// TypeDefBuilder
@@ -588,8 +595,8 @@ export class TypeDefBuilder {
}
/** [Standard] Creates a Struct type */
public Struct(fields: T, metadata: StructMetadata = {}): TStruct {
- const optionalProperties = globalThis.Object.getOwnPropertyNames(fields).reduce((acc, key) => (Types.TypeGuard.TOptional(fields[key]) ? { ...acc, [key]: fields[key] } : { ...acc }), {} as TFields)
- const properties = globalThis.Object.getOwnPropertyNames(fields).reduce((acc, key) => (Types.TypeGuard.TOptional(fields[key]) ? { ...acc } : { ...acc, [key]: fields[key] }), {} as TFields)
+ const optionalProperties = globalThis.Object.getOwnPropertyNames(fields).reduce((acc, key) => (Types.TypeGuard.IsOptional(fields[key]) ? { ...acc, [key]: fields[key] } : { ...acc }), {} as TFields)
+ const properties = globalThis.Object.getOwnPropertyNames(fields).reduce((acc, key) => (Types.TypeGuard.IsOptional(fields[key]) ? { ...acc } : { ...acc, [key]: fields[key] }), {} as TFields)
const optionalObject = globalThis.Object.getOwnPropertyNames(optionalProperties).length > 0 ? { optionalProperties: optionalProperties } : {}
const requiredObject = globalThis.Object.getOwnPropertyNames(properties).length === 0 ? {} : { properties: properties }
return this.Create({ [Types.Kind]: 'TypeDef:Struct', ...requiredObject, ...optionalObject }, metadata)
diff --git a/examples/trpc/readme.md b/examples/trpc/readme.md
deleted file mode 100644
index c5c7051..0000000
--- a/examples/trpc/readme.md
+++ /dev/null
@@ -1,46 +0,0 @@
-# Using TypeBox with TRPC
-
-To use TypeBox with TRPC, you will need to wrap types in a TRPC compatible validation function. The following shows wrapping a type using the TypeCompiler.
-
-
-
-## Example
-
-[TypeScript Link Here](https://www.typescriptlang.org/play?#code/JYWwDg9gTgLgBAbzsAdsGAVASgBQMIA0c2+AolFNHAL5wBmlIcA5AAIxRgDGA9AM4BTKADchzALAAoUJFiJiATzAC8EcMAA2QmvUYtWfVFw0BDYFB4wlAgEYQAHjy5qwmsVJnR4SDNaIYAZS4ACwEQEx0GNX1DFGMzCytlO3sJSSkeHjgAWly8-ILCouKS0rLyvIys1XUtPjgI32UGlAATOCgBGABXKBR6iOMIPl6BeioSPCqcitm5+YWCqQF7WXg6briYYAgUOCxuJoEAHgw4FZgBNvrAkLCTAD4ACj478IAuYiJOuiErrgEfE+t1C4QA2gBdOAAXjgkIAlIgpHA4M5+vA7lwANYwxTKGquLRQAB0BLcLzeJm+Al+nTigPhyI6XV6eyewhMGm6Ak+myxKAgAHcUIjoQ8kZIUSjgHQ4E9MVjSaFsezOdz4YjOj0+nAOVyBEyUWi+N44GATDBgkQQIC+CYAOZjWiwhXE8iUKB8VX6+HEgBi5hNT3hAEJDXBLZRBXAUAJo5N3dAnkgbXw7Y7PgADAAkCFT6YEtDoVFz5st1EzRGcrR5LAAQgBBAAiAH0sKQAIoAVVIAQwzBojMlNCk1Gmiwnk6nlUkmTgXYL4+ny5XZSkxvg8FhqHQk2JXE6FoEwfXuxNDVa7VhMGJYEoANaoyZxNQYG6MCeBy4Rye4aOxIAeRsAArAQuA-BBwxRExgWsYkADluhAGwhGDAgoLgGxYOUBCkJQqA0PDaghxRDVnwgd83w-L8fz-ODEOQ1CSNI5jiQAR25KAFCeZNkBQKjBxhcVX3fYkIgAaj4qjiRsRE5ySARsjtX4pGWVYvFRM94BMMAwCwCjLigXEb0od9UKQJkTEvOBR3hIA)
-
-```typescript
-import { initTRPC, TRPCError } from '@trpc/server'
-import { TypeCompiler } from '@sinclair/typebox/compiler'
-import { Type, TSchema } from '@sinclair/typebox'
-
-// ---------------------------------------------------------------------------------
-// Compiles a Type and returns a closure for TRPC
-// ---------------------------------------------------------------------------------
-export function RpcType(schema: T, references: TSchema[] = []) {
- const check = TypeCompiler.Compile(schema, references)
- return (value: unknown) => {
- if (check.Check(value)) return value
- const { path, message } = check.Errors(value).First()!
- throw new TRPCError({ message: `${message} for ${path}`, code: 'BAD_REQUEST' })
- }
-}
-// ---------------------------------------------------------------------------------
-// Usage
-// ---------------------------------------------------------------------------------
-const t = initTRPC.create()
-const add = t.procedure
- .input(RpcType(
- Type.Object({
- a: Type.Number(),
- b: Type.Number(),
- })
- ))
- .output(RpcType(
- Type.Number()
- ))
- .query(({ input }) => input.a + input.b) // type-safe
-
-export const appRouter = t.router({
- add
-})
-```
\ No newline at end of file
diff --git a/hammer.mjs b/hammer.mjs
index 2e02a03..661d90a 100644
--- a/hammer.mjs
+++ b/hammer.mjs
@@ -1,36 +1,32 @@
-import { compression, measurement } from './benchmark'
-import { readFileSync } from 'fs'
+import * as Benchmark from './task/benchmark'
+import * as Build from './task/build'
+import * as Fs from 'fs'
// -------------------------------------------------------------------------------
// Clean
// -------------------------------------------------------------------------------
export async function clean() {
+ await folder('node_modules/typebox').delete()
await folder('target').delete()
}
// -------------------------------------------------------------------------------
// Format
// -------------------------------------------------------------------------------
export async function format() {
- await shell('prettier --no-semi --single-quote --print-width 240 --trailing-comma all --write src test examples/index.ts benchmark')
+ await shell('prettier --no-semi --single-quote --print-width 240 --trailing-comma all --write src test task example/index.ts')
}
// -------------------------------------------------------------------------------
// Start
// -------------------------------------------------------------------------------
export async function start() {
- await shell(`hammer run examples/index.ts --dist target/examples`)
+ await shell(`hammer run example/index.ts --dist target/example`)
}
// -------------------------------------------------------------------------------
// Benchmark
// -------------------------------------------------------------------------------
-export async function benchmark_compression() {
- await compression()
-}
-export async function benchmark_measurement() {
- await measurement()
-}
export async function benchmark() {
- await benchmark_compression()
- await benchmark_measurement()
+ await Benchmark.compression()
+ await Benchmark.measurement()
}
// -------------------------------------------------------------------------------
// Test
@@ -56,20 +52,36 @@ export async function test(filter = '') {
// -------------------------------------------------------------------------------
// Build
// -------------------------------------------------------------------------------
+export async function build_check(target = 'target/build') {
+ const { version } = JSON.parse(Fs.readFileSync('package.json', 'utf8'))
+ await shell(`cd ${target} && attw sinclair-typebox-${version}.tgz`)
+}
export async function build(target = 'target/build') {
await test()
- await folder(target).delete()
- await shell(`tsc -p ./src/tsconfig.json --outDir ${target}`)
- await folder(target).add('package.json')
+ await clean()
+ await Promise.all([
+ Build.Import.build(target),
+ Build.Require.build(target),
+ Build.Redirect.build(target)
+ ])
await folder(target).add('readme.md')
await folder(target).add('license')
await shell(`cd ${target} && npm pack`)
+ await build_check(target)
+}
+// -------------------------------------------------------------------------------
+// Install
+// -------------------------------------------------------------------------------
+export async function install_local() {
+ await clean()
+ await build('target/typebox')
+ await folder('node_modules').add('target/typebox')
}
// -------------------------------------------------------------
// Publish
// -------------------------------------------------------------
export async function publish(otp, target = 'target/build') {
- const { version } = JSON.parse(readFileSync('package.json', 'utf8'))
+ const { version } = JSON.parse(Fs.readFileSync('package.json', 'utf8'))
if(version.includes('-dev')) throw Error(`package version should not include -dev specifier`)
await shell(`cd ${target} && npm publish sinclair-typebox-${version}.tgz --access=public --otp ${otp}`)
await shell(`git tag ${version}`)
@@ -79,7 +91,7 @@ export async function publish(otp, target = 'target/build') {
// Publish-Dev
// -------------------------------------------------------------
export async function publish_dev(otp, target = 'target/build') {
- const { version } = JSON.parse(readFileSync(`${target}/package.json`, 'utf8'))
+ const { version } = JSON.parse(Fs.readFileSync(`${target}/package.json`, 'utf8'))
if(!version.includes('-dev')) throw Error(`development package version should include -dev specifier`)
await shell(`cd ${target} && npm publish sinclair-typebox-${version}.tgz --access=public --otp ${otp} --tag dev`)
}
\ No newline at end of file
diff --git a/license b/license
index 08641fd..971ec5d 100644
--- a/license
+++ b/license
@@ -1,4 +1,6 @@
-TypeBox: JSON Schema Type Builder with Static Type Resolution for TypeScript
+TypeBox
+
+Json Schema Type Builder with Static Type Resolution for TypeScript
The MIT License (MIT)
diff --git a/package-lock.json b/package-lock.json
index 88740ec..6ce4d3f 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1,17 +1,18 @@
{
"name": "@sinclair/typebox",
- "version": "0.31.28",
+ "version": "0.32.0",
"lockfileVersion": 2,
"requires": true,
"packages": {
"": {
"name": "@sinclair/typebox",
- "version": "0.31.28",
+ "version": "0.32.0",
"license": "MIT",
"devDependencies": {
+ "@arethetypeswrong/cli": "^0.13.2",
"@sinclair/hammer": "^0.18.0",
"@types/mocha": "^9.1.1",
- "@types/node": "^18.11.9",
+ "@types/node": "^20.10.1",
"ajv": "^8.12.0",
"ajv-formats": "^2.1.1",
"mocha": "^9.2.2",
@@ -19,6 +20,59 @@
"typescript": "^5.3.2"
}
},
+ "node_modules/@andrewbranch/untar.js": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/@andrewbranch/untar.js/-/untar.js-1.0.3.tgz",
+ "integrity": "sha512-Jh15/qVmrLGhkKJBdXlK1+9tY4lZruYjsgkDFj08ZmDiWVBLJcqkok7Z0/R0In+i1rScBpJlSvrTS2Lm41Pbnw==",
+ "dev": true
+ },
+ "node_modules/@arethetypeswrong/cli": {
+ "version": "0.13.2",
+ "resolved": "https://registry.npmjs.org/@arethetypeswrong/cli/-/cli-0.13.2.tgz",
+ "integrity": "sha512-eqRWeFFiI58xwsiUfZSdZsmNCaqqtxmSPP9554ajiCDrB/aNzq5VktVK7dNiT9PamunNeoej4KbDBnkNwVacvg==",
+ "dev": true,
+ "dependencies": {
+ "@arethetypeswrong/core": "0.13.2",
+ "chalk": "^4.1.2",
+ "cli-table3": "^0.6.3",
+ "commander": "^10.0.1",
+ "marked": "^9.1.2",
+ "marked-terminal": "^6.0.0",
+ "semver": "^7.5.4"
+ },
+ "bin": {
+ "attw": "dist/index.js"
+ },
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@arethetypeswrong/core": {
+ "version": "0.13.2",
+ "resolved": "https://registry.npmjs.org/@arethetypeswrong/core/-/core-0.13.2.tgz",
+ "integrity": "sha512-1l6ygar+6TH4o1JipWWGCEZlOhAwEShm1yKx+CgIByNjCzufbu6k9DNbDmBjdouusNRhBIOYQe1UHnJig+GtAw==",
+ "dev": true,
+ "dependencies": {
+ "@andrewbranch/untar.js": "^1.0.3",
+ "fflate": "^0.7.4",
+ "semver": "^7.5.4",
+ "typescript": "5.3.2",
+ "validate-npm-package-name": "^5.0.0"
+ },
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@colors/colors": {
+ "version": "1.5.0",
+ "resolved": "https://registry.npmjs.org/@colors/colors/-/colors-1.5.0.tgz",
+ "integrity": "sha512-ooWCrlZP11i8GImSjTHYHLkvFDP48nS4+204nGb1RiX/WXYHmJA2III9/e2DWVabCESdW7hBAEzHRqUn9OUVvQ==",
+ "dev": true,
+ "optional": true,
+ "engines": {
+ "node": ">=0.1.90"
+ }
+ },
"node_modules/@esbuild/linux-loong64": {
"version": "0.15.7",
"resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.15.7.tgz",
@@ -47,6 +101,18 @@
"hammer": "hammer"
}
},
+ "node_modules/@sindresorhus/is": {
+ "version": "4.6.0",
+ "resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-4.6.0.tgz",
+ "integrity": "sha512-t09vSN3MdfsyCHoFcTRCH/iUtG7OJ0CsjzB8cjAmKc/va/kIgeDI/TxsigdncE/4be734m0cvIYwNaV4i2XqAw==",
+ "dev": true,
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/sindresorhus/is?sponsor=1"
+ }
+ },
"node_modules/@types/mocha": {
"version": "9.1.1",
"resolved": "https://registry.npmjs.org/@types/mocha/-/mocha-9.1.1.tgz",
@@ -54,10 +120,13 @@
"dev": true
},
"node_modules/@types/node": {
- "version": "18.17.2",
- "resolved": "https://registry.npmjs.org/@types/node/-/node-18.17.2.tgz",
- "integrity": "sha512-wBo3KqP/PBqje5TI9UTiuL3yWfP6sdPtjtygSOqcYZWT232dfDeDOnkDps5wqZBP9NgGgYrNejinl0faAuE+HQ==",
- "dev": true
+ "version": "20.10.1",
+ "resolved": "https://registry.npmjs.org/@types/node/-/node-20.10.1.tgz",
+ "integrity": "sha512-T2qwhjWwGH81vUEx4EXmBKsTJRXFXNZTL4v0gi01+zyBmCwzE6TyHszqX01m+QHTEq+EZNo13NeJIdEqf+Myrg==",
+ "dev": true,
+ "dependencies": {
+ "undici-types": "~5.26.4"
+ }
},
"node_modules/@ungap/promise-all-settled": {
"version": "1.1.2",
@@ -107,6 +176,21 @@
"node": ">=6"
}
},
+ "node_modules/ansi-escapes": {
+ "version": "6.2.0",
+ "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-6.2.0.tgz",
+ "integrity": "sha512-kzRaCqXnpzWs+3z5ABPQiVke+iq0KXkHo8xiWV4RPTi5Yli0l97BEQuhXV1s7+aSU/fu1kUuxgS4MsQ0fRuygw==",
+ "dev": true,
+ "dependencies": {
+ "type-fest": "^3.0.0"
+ },
+ "engines": {
+ "node": ">=14.16"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
"node_modules/ansi-regex": {
"version": "5.0.1",
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz",
@@ -131,6 +215,12 @@
"url": "https://github.com/chalk/ansi-styles?sponsor=1"
}
},
+ "node_modules/ansicolors": {
+ "version": "0.3.2",
+ "resolved": "https://registry.npmjs.org/ansicolors/-/ansicolors-0.3.2.tgz",
+ "integrity": "sha512-QXu7BPrP29VllRxH8GwB7x5iX5qWKAAMLqKQGWTeLWVlNHNOpVMJ91dsxQAIWXpjuW5wqvxu3Jd/nRjrJ+0pqg==",
+ "dev": true
+ },
"node_modules/anymatch": {
"version": "3.1.3",
"resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz",
@@ -193,6 +283,15 @@
"integrity": "sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw==",
"dev": true
},
+ "node_modules/builtins": {
+ "version": "5.0.1",
+ "resolved": "https://registry.npmjs.org/builtins/-/builtins-5.0.1.tgz",
+ "integrity": "sha512-qwVpFEHNfhYJIzNRBvd2C1kyo6jz3ZSMPyyuR47OPdiKWlbYnZNyDWuyR175qDnAJLiCo5fBBqPb3RiXgWlkOQ==",
+ "dev": true,
+ "dependencies": {
+ "semver": "^7.0.0"
+ }
+ },
"node_modules/camelcase": {
"version": "6.3.0",
"resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz",
@@ -205,6 +304,19 @@
"url": "https://github.com/sponsors/sindresorhus"
}
},
+ "node_modules/cardinal": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/cardinal/-/cardinal-2.1.1.tgz",
+ "integrity": "sha512-JSr5eOgoEymtYHBjNWyjrMqet9Am2miJhlfKNdqLp6zoeAh0KN5dRAcxlecj5mAJrmQomgiOBj35xHLrFjqBpw==",
+ "dev": true,
+ "dependencies": {
+ "ansicolors": "~0.3.2",
+ "redeyed": "~2.1.0"
+ },
+ "bin": {
+ "cdl": "bin/cdl.js"
+ }
+ },
"node_modules/chalk": {
"version": "4.1.2",
"resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
@@ -233,6 +345,15 @@
"node": ">=8"
}
},
+ "node_modules/char-regex": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/char-regex/-/char-regex-1.0.2.tgz",
+ "integrity": "sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw==",
+ "dev": true,
+ "engines": {
+ "node": ">=10"
+ }
+ },
"node_modules/chokidar": {
"version": "3.5.3",
"resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz",
@@ -260,6 +381,21 @@
"fsevents": "~2.3.2"
}
},
+ "node_modules/cli-table3": {
+ "version": "0.6.3",
+ "resolved": "https://registry.npmjs.org/cli-table3/-/cli-table3-0.6.3.tgz",
+ "integrity": "sha512-w5Jac5SykAeZJKntOxJCrm63Eg5/4dhMWIcuTbo9rpE+brgaSZo0RuNJZeOyMgsUdhDeojvgyQLmjI+K50ZGyg==",
+ "dev": true,
+ "dependencies": {
+ "string-width": "^4.2.0"
+ },
+ "engines": {
+ "node": "10.* || >= 12.*"
+ },
+ "optionalDependencies": {
+ "@colors/colors": "1.5.0"
+ }
+ },
"node_modules/cliui": {
"version": "7.0.4",
"resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz",
@@ -289,6 +425,15 @@
"integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
"dev": true
},
+ "node_modules/commander": {
+ "version": "10.0.1",
+ "resolved": "https://registry.npmjs.org/commander/-/commander-10.0.1.tgz",
+ "integrity": "sha512-y4Mg2tXshplEbSGzx7amzPwKKOCGuoSRP/CjEdwwk0FOGlUbq6lKuoyDZTNZkmxHdJtp54hdfY/JUrdL7Xfdug==",
+ "dev": true,
+ "engines": {
+ "node": ">=14"
+ }
+ },
"node_modules/concat-map": {
"version": "0.0.1",
"resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
@@ -345,6 +490,12 @@
"integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==",
"dev": true
},
+ "node_modules/emojilib": {
+ "version": "2.4.0",
+ "resolved": "https://registry.npmjs.org/emojilib/-/emojilib-2.4.0.tgz",
+ "integrity": "sha512-5U0rVMU5Y2n2+ykNLQqMoqklN9ICBT/KsvC1Gz6vqHbz2AXXGkG+Pm5rMWk/8Vjrr/mY9985Hi8DYzn1F09Nyw==",
+ "dev": true
+ },
"node_modules/esbuild": {
"version": "0.15.7",
"resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.15.7.tgz",
@@ -722,12 +873,31 @@
"url": "https://github.com/sponsors/sindresorhus"
}
},
+ "node_modules/esprima": {
+ "version": "4.0.1",
+ "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz",
+ "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==",
+ "dev": true,
+ "bin": {
+ "esparse": "bin/esparse.js",
+ "esvalidate": "bin/esvalidate.js"
+ },
+ "engines": {
+ "node": ">=4"
+ }
+ },
"node_modules/fast-deep-equal": {
"version": "3.1.3",
"resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz",
"integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==",
"dev": true
},
+ "node_modules/fflate": {
+ "version": "0.7.4",
+ "resolved": "https://registry.npmjs.org/fflate/-/fflate-0.7.4.tgz",
+ "integrity": "sha512-5u2V/CDW15QM1XbbgS+0DfPxVB+jUKhWEKuuFuHncbk3tEEqzmoXL+2KyOFuKGqOnmdIy0/davWF1CkuwtibCw==",
+ "dev": true
+ },
"node_modules/fill-range": {
"version": "7.0.1",
"resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz",
@@ -1008,6 +1178,62 @@
"url": "https://github.com/sponsors/sindresorhus"
}
},
+ "node_modules/lru-cache": {
+ "version": "6.0.0",
+ "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz",
+ "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==",
+ "dev": true,
+ "dependencies": {
+ "yallist": "^4.0.0"
+ },
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/marked": {
+ "version": "9.1.6",
+ "resolved": "https://registry.npmjs.org/marked/-/marked-9.1.6.tgz",
+ "integrity": "sha512-jcByLnIFkd5gSXZmjNvS1TlmRhCXZjIzHYlaGkPlLIekG55JDR2Z4va9tZwCiP+/RDERiNhMOFu01xd6O5ct1Q==",
+ "dev": true,
+ "bin": {
+ "marked": "bin/marked.js"
+ },
+ "engines": {
+ "node": ">= 16"
+ }
+ },
+ "node_modules/marked-terminal": {
+ "version": "6.1.0",
+ "resolved": "https://registry.npmjs.org/marked-terminal/-/marked-terminal-6.1.0.tgz",
+ "integrity": "sha512-QaCSF6NV82oo6K0szEnmc65ooDeW0T/Adcyf0fcW+Hto2GT1VADFg8dn1zaeHqzj65fqDH1hMNChGNRaC/lbkA==",
+ "dev": true,
+ "dependencies": {
+ "ansi-escapes": "^6.2.0",
+ "cardinal": "^2.1.1",
+ "chalk": "^5.3.0",
+ "cli-table3": "^0.6.3",
+ "node-emoji": "^2.1.0",
+ "supports-hyperlinks": "^3.0.0"
+ },
+ "engines": {
+ "node": ">=16.0.0"
+ },
+ "peerDependencies": {
+ "marked": ">=1 <11"
+ }
+ },
+ "node_modules/marked-terminal/node_modules/chalk": {
+ "version": "5.3.0",
+ "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.3.0.tgz",
+ "integrity": "sha512-dLitG79d+GV1Nb/VYcCDFivJeK1hiukt9QjRNVOsUtTy1rR1YJsmpGGTZ3qJos+uw7WmWF4wUwBd9jxjocFC2w==",
+ "dev": true,
+ "engines": {
+ "node": "^12.17.0 || ^14.13 || >=16.0.0"
+ },
+ "funding": {
+ "url": "https://github.com/chalk/chalk?sponsor=1"
+ }
+ },
"node_modules/minimatch": {
"version": "4.2.1",
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-4.2.1.tgz",
@@ -1081,6 +1307,21 @@
"node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1"
}
},
+ "node_modules/node-emoji": {
+ "version": "2.1.3",
+ "resolved": "https://registry.npmjs.org/node-emoji/-/node-emoji-2.1.3.tgz",
+ "integrity": "sha512-E2WEOVsgs7O16zsURJ/eH8BqhF029wGpEOnv7Urwdo2wmQanOACwJQh0devF9D9RhoZru0+9JXIS0dBXIAz+lA==",
+ "dev": true,
+ "dependencies": {
+ "@sindresorhus/is": "^4.6.0",
+ "char-regex": "^1.0.2",
+ "emojilib": "^2.4.0",
+ "skin-tone": "^2.0.0"
+ },
+ "engines": {
+ "node": ">=18"
+ }
+ },
"node_modules/normalize-path": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz",
@@ -1204,6 +1445,15 @@
"node": ">=8.10.0"
}
},
+ "node_modules/redeyed": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/redeyed/-/redeyed-2.1.1.tgz",
+ "integrity": "sha512-FNpGGo1DycYAdnrKFxCMmKYgo/mILAqtRYbkdQD8Ep/Hk2PQ5+aEAEx+IU713RTDmuBaH0c8P5ZozurNu5ObRQ==",
+ "dev": true,
+ "dependencies": {
+ "esprima": "~4.0.0"
+ }
+ },
"node_modules/require-directory": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz",
@@ -1242,6 +1492,21 @@
}
]
},
+ "node_modules/semver": {
+ "version": "7.5.4",
+ "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz",
+ "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==",
+ "dev": true,
+ "dependencies": {
+ "lru-cache": "^6.0.0"
+ },
+ "bin": {
+ "semver": "bin/semver.js"
+ },
+ "engines": {
+ "node": ">=10"
+ }
+ },
"node_modules/serialize-javascript": {
"version": "6.0.0",
"resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.0.tgz",
@@ -1251,6 +1516,18 @@
"randombytes": "^2.1.0"
}
},
+ "node_modules/skin-tone": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/skin-tone/-/skin-tone-2.0.0.tgz",
+ "integrity": "sha512-kUMbT1oBJCpgrnKoSr0o6wPtvRWT9W9UKvGLwfJYO2WuahZRHOpEyL1ckyMGgMWh0UdpmaoFqKKD29WTomNEGA==",
+ "dev": true,
+ "dependencies": {
+ "unicode-emoji-modifier-base": "^1.0.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
"node_modules/string-width": {
"version": "4.2.3",
"resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz",
@@ -1304,6 +1581,31 @@
"url": "https://github.com/chalk/supports-color?sponsor=1"
}
},
+ "node_modules/supports-hyperlinks": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/supports-hyperlinks/-/supports-hyperlinks-3.0.0.tgz",
+ "integrity": "sha512-QBDPHyPQDRTy9ku4URNGY5Lah8PAaXs6tAAwp55sL5WCsSW7GIfdf6W5ixfziW+t7wh3GVvHyHHyQ1ESsoRvaA==",
+ "dev": true,
+ "dependencies": {
+ "has-flag": "^4.0.0",
+ "supports-color": "^7.0.0"
+ },
+ "engines": {
+ "node": ">=14.18"
+ }
+ },
+ "node_modules/supports-hyperlinks/node_modules/supports-color": {
+ "version": "7.2.0",
+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
+ "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
+ "dev": true,
+ "dependencies": {
+ "has-flag": "^4.0.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
"node_modules/to-regex-range": {
"version": "5.0.1",
"resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz",
@@ -1316,6 +1618,18 @@
"node": ">=8.0"
}
},
+ "node_modules/type-fest": {
+ "version": "3.13.1",
+ "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-3.13.1.tgz",
+ "integrity": "sha512-tLq3bSNx+xSpwvAJnzrK0Ep5CLNWjvFTOp71URMaAEWBfRb9nnJiBoUe0tF8bI4ZFO3omgBR6NvnbzVUT3Ly4g==",
+ "dev": true,
+ "engines": {
+ "node": ">=14.16"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
"node_modules/typescript": {
"version": "5.3.2",
"resolved": "https://registry.npmjs.org/typescript/-/typescript-5.3.2.tgz",
@@ -1329,6 +1643,21 @@
"node": ">=14.17"
}
},
+ "node_modules/undici-types": {
+ "version": "5.26.5",
+ "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz",
+ "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==",
+ "dev": true
+ },
+ "node_modules/unicode-emoji-modifier-base": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/unicode-emoji-modifier-base/-/unicode-emoji-modifier-base-1.0.0.tgz",
+ "integrity": "sha512-yLSH4py7oFH3oG/9K+XWrz1pSi3dfUrWEnInbxMfArOfc1+33BlGPQtLsOYwvdMy11AwUBetYuaRxSPqgkq+8g==",
+ "dev": true,
+ "engines": {
+ "node": ">=4"
+ }
+ },
"node_modules/uri-js": {
"version": "4.4.1",
"resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz",
@@ -1338,6 +1667,18 @@
"punycode": "^2.1.0"
}
},
+ "node_modules/validate-npm-package-name": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/validate-npm-package-name/-/validate-npm-package-name-5.0.0.tgz",
+ "integrity": "sha512-YuKoXDAhBYxY7SfOKxHBDoSyENFeW5VvIIQp2TGQuit8gpK6MnWaQelBKxso72DoxTZfZdcP3W90LqpSkgPzLQ==",
+ "dev": true,
+ "dependencies": {
+ "builtins": "^5.0.0"
+ },
+ "engines": {
+ "node": "^14.17.0 || ^16.13.0 || >=18.0.0"
+ }
+ },
"node_modules/which": {
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz",
@@ -1391,6 +1732,12 @@
"node": ">=10"
}
},
+ "node_modules/yallist": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz",
+ "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==",
+ "dev": true
+ },
"node_modules/yargs": {
"version": "16.2.0",
"resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz",
@@ -1447,6 +1794,47 @@
}
},
"dependencies": {
+ "@andrewbranch/untar.js": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/@andrewbranch/untar.js/-/untar.js-1.0.3.tgz",
+ "integrity": "sha512-Jh15/qVmrLGhkKJBdXlK1+9tY4lZruYjsgkDFj08ZmDiWVBLJcqkok7Z0/R0In+i1rScBpJlSvrTS2Lm41Pbnw==",
+ "dev": true
+ },
+ "@arethetypeswrong/cli": {
+ "version": "0.13.2",
+ "resolved": "https://registry.npmjs.org/@arethetypeswrong/cli/-/cli-0.13.2.tgz",
+ "integrity": "sha512-eqRWeFFiI58xwsiUfZSdZsmNCaqqtxmSPP9554ajiCDrB/aNzq5VktVK7dNiT9PamunNeoej4KbDBnkNwVacvg==",
+ "dev": true,
+ "requires": {
+ "@arethetypeswrong/core": "0.13.2",
+ "chalk": "^4.1.2",
+ "cli-table3": "^0.6.3",
+ "commander": "^10.0.1",
+ "marked": "^9.1.2",
+ "marked-terminal": "^6.0.0",
+ "semver": "^7.5.4"
+ }
+ },
+ "@arethetypeswrong/core": {
+ "version": "0.13.2",
+ "resolved": "https://registry.npmjs.org/@arethetypeswrong/core/-/core-0.13.2.tgz",
+ "integrity": "sha512-1l6ygar+6TH4o1JipWWGCEZlOhAwEShm1yKx+CgIByNjCzufbu6k9DNbDmBjdouusNRhBIOYQe1UHnJig+GtAw==",
+ "dev": true,
+ "requires": {
+ "@andrewbranch/untar.js": "^1.0.3",
+ "fflate": "^0.7.4",
+ "semver": "^7.5.4",
+ "typescript": "5.3.2",
+ "validate-npm-package-name": "^5.0.0"
+ }
+ },
+ "@colors/colors": {
+ "version": "1.5.0",
+ "resolved": "https://registry.npmjs.org/@colors/colors/-/colors-1.5.0.tgz",
+ "integrity": "sha512-ooWCrlZP11i8GImSjTHYHLkvFDP48nS4+204nGb1RiX/WXYHmJA2III9/e2DWVabCESdW7hBAEzHRqUn9OUVvQ==",
+ "dev": true,
+ "optional": true
+ },
"@esbuild/linux-loong64": {
"version": "0.15.7",
"resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.15.7.tgz",
@@ -1463,6 +1851,12 @@
"esbuild": "0.15.7"
}
},
+ "@sindresorhus/is": {
+ "version": "4.6.0",
+ "resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-4.6.0.tgz",
+ "integrity": "sha512-t09vSN3MdfsyCHoFcTRCH/iUtG7OJ0CsjzB8cjAmKc/va/kIgeDI/TxsigdncE/4be734m0cvIYwNaV4i2XqAw==",
+ "dev": true
+ },
"@types/mocha": {
"version": "9.1.1",
"resolved": "https://registry.npmjs.org/@types/mocha/-/mocha-9.1.1.tgz",
@@ -1470,10 +1864,13 @@
"dev": true
},
"@types/node": {
- "version": "18.17.2",
- "resolved": "https://registry.npmjs.org/@types/node/-/node-18.17.2.tgz",
- "integrity": "sha512-wBo3KqP/PBqje5TI9UTiuL3yWfP6sdPtjtygSOqcYZWT232dfDeDOnkDps5wqZBP9NgGgYrNejinl0faAuE+HQ==",
- "dev": true
+ "version": "20.10.1",
+ "resolved": "https://registry.npmjs.org/@types/node/-/node-20.10.1.tgz",
+ "integrity": "sha512-T2qwhjWwGH81vUEx4EXmBKsTJRXFXNZTL4v0gi01+zyBmCwzE6TyHszqX01m+QHTEq+EZNo13NeJIdEqf+Myrg==",
+ "dev": true,
+ "requires": {
+ "undici-types": "~5.26.4"
+ }
},
"@ungap/promise-all-settled": {
"version": "1.1.2",
@@ -1508,6 +1905,15 @@
"integrity": "sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA==",
"dev": true
},
+ "ansi-escapes": {
+ "version": "6.2.0",
+ "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-6.2.0.tgz",
+ "integrity": "sha512-kzRaCqXnpzWs+3z5ABPQiVke+iq0KXkHo8xiWV4RPTi5Yli0l97BEQuhXV1s7+aSU/fu1kUuxgS4MsQ0fRuygw==",
+ "dev": true,
+ "requires": {
+ "type-fest": "^3.0.0"
+ }
+ },
"ansi-regex": {
"version": "5.0.1",
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz",
@@ -1523,6 +1929,12 @@
"color-convert": "^2.0.1"
}
},
+ "ansicolors": {
+ "version": "0.3.2",
+ "resolved": "https://registry.npmjs.org/ansicolors/-/ansicolors-0.3.2.tgz",
+ "integrity": "sha512-QXu7BPrP29VllRxH8GwB7x5iX5qWKAAMLqKQGWTeLWVlNHNOpVMJ91dsxQAIWXpjuW5wqvxu3Jd/nRjrJ+0pqg==",
+ "dev": true
+ },
"anymatch": {
"version": "3.1.3",
"resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz",
@@ -1576,12 +1988,31 @@
"integrity": "sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw==",
"dev": true
},
+ "builtins": {
+ "version": "5.0.1",
+ "resolved": "https://registry.npmjs.org/builtins/-/builtins-5.0.1.tgz",
+ "integrity": "sha512-qwVpFEHNfhYJIzNRBvd2C1kyo6jz3ZSMPyyuR47OPdiKWlbYnZNyDWuyR175qDnAJLiCo5fBBqPb3RiXgWlkOQ==",
+ "dev": true,
+ "requires": {
+ "semver": "^7.0.0"
+ }
+ },
"camelcase": {
"version": "6.3.0",
"resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz",
"integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==",
"dev": true
},
+ "cardinal": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/cardinal/-/cardinal-2.1.1.tgz",
+ "integrity": "sha512-JSr5eOgoEymtYHBjNWyjrMqet9Am2miJhlfKNdqLp6zoeAh0KN5dRAcxlecj5mAJrmQomgiOBj35xHLrFjqBpw==",
+ "dev": true,
+ "requires": {
+ "ansicolors": "~0.3.2",
+ "redeyed": "~2.1.0"
+ }
+ },
"chalk": {
"version": "4.1.2",
"resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
@@ -1603,6 +2034,12 @@
}
}
},
+ "char-regex": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/char-regex/-/char-regex-1.0.2.tgz",
+ "integrity": "sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw==",
+ "dev": true
+ },
"chokidar": {
"version": "3.5.3",
"resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz",
@@ -1619,6 +2056,16 @@
"readdirp": "~3.6.0"
}
},
+ "cli-table3": {
+ "version": "0.6.3",
+ "resolved": "https://registry.npmjs.org/cli-table3/-/cli-table3-0.6.3.tgz",
+ "integrity": "sha512-w5Jac5SykAeZJKntOxJCrm63Eg5/4dhMWIcuTbo9rpE+brgaSZo0RuNJZeOyMgsUdhDeojvgyQLmjI+K50ZGyg==",
+ "dev": true,
+ "requires": {
+ "@colors/colors": "1.5.0",
+ "string-width": "^4.2.0"
+ }
+ },
"cliui": {
"version": "7.0.4",
"resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz",
@@ -1645,6 +2092,12 @@
"integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
"dev": true
},
+ "commander": {
+ "version": "10.0.1",
+ "resolved": "https://registry.npmjs.org/commander/-/commander-10.0.1.tgz",
+ "integrity": "sha512-y4Mg2tXshplEbSGzx7amzPwKKOCGuoSRP/CjEdwwk0FOGlUbq6lKuoyDZTNZkmxHdJtp54hdfY/JUrdL7Xfdug==",
+ "dev": true
+ },
"concat-map": {
"version": "0.0.1",
"resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
@@ -1686,6 +2139,12 @@
"integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==",
"dev": true
},
+ "emojilib": {
+ "version": "2.4.0",
+ "resolved": "https://registry.npmjs.org/emojilib/-/emojilib-2.4.0.tgz",
+ "integrity": "sha512-5U0rVMU5Y2n2+ykNLQqMoqklN9ICBT/KsvC1Gz6vqHbz2AXXGkG+Pm5rMWk/8Vjrr/mY9985Hi8DYzn1F09Nyw==",
+ "dev": true
+ },
"esbuild": {
"version": "0.15.7",
"resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.15.7.tgz",
@@ -1867,12 +2326,24 @@
"integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==",
"dev": true
},
+ "esprima": {
+ "version": "4.0.1",
+ "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz",
+ "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==",
+ "dev": true
+ },
"fast-deep-equal": {
"version": "3.1.3",
"resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz",
"integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==",
"dev": true
},
+ "fflate": {
+ "version": "0.7.4",
+ "resolved": "https://registry.npmjs.org/fflate/-/fflate-0.7.4.tgz",
+ "integrity": "sha512-5u2V/CDW15QM1XbbgS+0DfPxVB+jUKhWEKuuFuHncbk3tEEqzmoXL+2KyOFuKGqOnmdIy0/davWF1CkuwtibCw==",
+ "dev": true
+ },
"fill-range": {
"version": "7.0.1",
"resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz",
@@ -2073,6 +2544,43 @@
"is-unicode-supported": "^0.1.0"
}
},
+ "lru-cache": {
+ "version": "6.0.0",
+ "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz",
+ "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==",
+ "dev": true,
+ "requires": {
+ "yallist": "^4.0.0"
+ }
+ },
+ "marked": {
+ "version": "9.1.6",
+ "resolved": "https://registry.npmjs.org/marked/-/marked-9.1.6.tgz",
+ "integrity": "sha512-jcByLnIFkd5gSXZmjNvS1TlmRhCXZjIzHYlaGkPlLIekG55JDR2Z4va9tZwCiP+/RDERiNhMOFu01xd6O5ct1Q==",
+ "dev": true
+ },
+ "marked-terminal": {
+ "version": "6.1.0",
+ "resolved": "https://registry.npmjs.org/marked-terminal/-/marked-terminal-6.1.0.tgz",
+ "integrity": "sha512-QaCSF6NV82oo6K0szEnmc65ooDeW0T/Adcyf0fcW+Hto2GT1VADFg8dn1zaeHqzj65fqDH1hMNChGNRaC/lbkA==",
+ "dev": true,
+ "requires": {
+ "ansi-escapes": "^6.2.0",
+ "cardinal": "^2.1.1",
+ "chalk": "^5.3.0",
+ "cli-table3": "^0.6.3",
+ "node-emoji": "^2.1.0",
+ "supports-hyperlinks": "^3.0.0"
+ },
+ "dependencies": {
+ "chalk": {
+ "version": "5.3.0",
+ "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.3.0.tgz",
+ "integrity": "sha512-dLitG79d+GV1Nb/VYcCDFivJeK1hiukt9QjRNVOsUtTy1rR1YJsmpGGTZ3qJos+uw7WmWF4wUwBd9jxjocFC2w==",
+ "dev": true
+ }
+ }
+ },
"minimatch": {
"version": "4.2.1",
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-4.2.1.tgz",
@@ -2126,6 +2634,18 @@
"integrity": "sha512-n6Vs/3KGyxPQd6uO0eH4Bv0ojGSUvuLlIHtC3Y0kEO23YRge8H9x1GCzLn28YX0H66pMkxuaeESFq4tKISKwdw==",
"dev": true
},
+ "node-emoji": {
+ "version": "2.1.3",
+ "resolved": "https://registry.npmjs.org/node-emoji/-/node-emoji-2.1.3.tgz",
+ "integrity": "sha512-E2WEOVsgs7O16zsURJ/eH8BqhF029wGpEOnv7Urwdo2wmQanOACwJQh0devF9D9RhoZru0+9JXIS0dBXIAz+lA==",
+ "dev": true,
+ "requires": {
+ "@sindresorhus/is": "^4.6.0",
+ "char-regex": "^1.0.2",
+ "emojilib": "^2.4.0",
+ "skin-tone": "^2.0.0"
+ }
+ },
"normalize-path": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz",
@@ -2207,6 +2727,15 @@
"picomatch": "^2.2.1"
}
},
+ "redeyed": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/redeyed/-/redeyed-2.1.1.tgz",
+ "integrity": "sha512-FNpGGo1DycYAdnrKFxCMmKYgo/mILAqtRYbkdQD8Ep/Hk2PQ5+aEAEx+IU713RTDmuBaH0c8P5ZozurNu5ObRQ==",
+ "dev": true,
+ "requires": {
+ "esprima": "~4.0.0"
+ }
+ },
"require-directory": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz",
@@ -2225,6 +2754,15 @@
"integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==",
"dev": true
},
+ "semver": {
+ "version": "7.5.4",
+ "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz",
+ "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==",
+ "dev": true,
+ "requires": {
+ "lru-cache": "^6.0.0"
+ }
+ },
"serialize-javascript": {
"version": "6.0.0",
"resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.0.tgz",
@@ -2234,6 +2772,15 @@
"randombytes": "^2.1.0"
}
},
+ "skin-tone": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/skin-tone/-/skin-tone-2.0.0.tgz",
+ "integrity": "sha512-kUMbT1oBJCpgrnKoSr0o6wPtvRWT9W9UKvGLwfJYO2WuahZRHOpEyL1ckyMGgMWh0UdpmaoFqKKD29WTomNEGA==",
+ "dev": true,
+ "requires": {
+ "unicode-emoji-modifier-base": "^1.0.0"
+ }
+ },
"string-width": {
"version": "4.2.3",
"resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz",
@@ -2269,6 +2816,27 @@
"has-flag": "^4.0.0"
}
},
+ "supports-hyperlinks": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/supports-hyperlinks/-/supports-hyperlinks-3.0.0.tgz",
+ "integrity": "sha512-QBDPHyPQDRTy9ku4URNGY5Lah8PAaXs6tAAwp55sL5WCsSW7GIfdf6W5ixfziW+t7wh3GVvHyHHyQ1ESsoRvaA==",
+ "dev": true,
+ "requires": {
+ "has-flag": "^4.0.0",
+ "supports-color": "^7.0.0"
+ },
+ "dependencies": {
+ "supports-color": {
+ "version": "7.2.0",
+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
+ "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
+ "dev": true,
+ "requires": {
+ "has-flag": "^4.0.0"
+ }
+ }
+ }
+ },
"to-regex-range": {
"version": "5.0.1",
"resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz",
@@ -2278,12 +2846,30 @@
"is-number": "^7.0.0"
}
},
+ "type-fest": {
+ "version": "3.13.1",
+ "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-3.13.1.tgz",
+ "integrity": "sha512-tLq3bSNx+xSpwvAJnzrK0Ep5CLNWjvFTOp71URMaAEWBfRb9nnJiBoUe0tF8bI4ZFO3omgBR6NvnbzVUT3Ly4g==",
+ "dev": true
+ },
"typescript": {
"version": "5.3.2",
"resolved": "https://registry.npmjs.org/typescript/-/typescript-5.3.2.tgz",
"integrity": "sha512-6l+RyNy7oAHDfxC4FzSJcz9vnjTKxrLpDG5M2Vu4SHRVNg6xzqZp6LYSR9zjqQTu8DU/f5xwxUdADOkbrIX2gQ==",
"dev": true
},
+ "undici-types": {
+ "version": "5.26.5",
+ "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz",
+ "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==",
+ "dev": true
+ },
+ "unicode-emoji-modifier-base": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/unicode-emoji-modifier-base/-/unicode-emoji-modifier-base-1.0.0.tgz",
+ "integrity": "sha512-yLSH4py7oFH3oG/9K+XWrz1pSi3dfUrWEnInbxMfArOfc1+33BlGPQtLsOYwvdMy11AwUBetYuaRxSPqgkq+8g==",
+ "dev": true
+ },
"uri-js": {
"version": "4.4.1",
"resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz",
@@ -2293,6 +2879,15 @@
"punycode": "^2.1.0"
}
},
+ "validate-npm-package-name": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/validate-npm-package-name/-/validate-npm-package-name-5.0.0.tgz",
+ "integrity": "sha512-YuKoXDAhBYxY7SfOKxHBDoSyENFeW5VvIIQp2TGQuit8gpK6MnWaQelBKxso72DoxTZfZdcP3W90LqpSkgPzLQ==",
+ "dev": true,
+ "requires": {
+ "builtins": "^5.0.0"
+ }
+ },
"which": {
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz",
@@ -2331,6 +2926,12 @@
"integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==",
"dev": true
},
+ "yallist": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz",
+ "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==",
+ "dev": true
+ },
"yargs": {
"version": "16.2.0",
"resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz",
diff --git a/package.json b/package.json
index 064dc20..342d3bc 100644
--- a/package.json
+++ b/package.json
@@ -1,7 +1,7 @@
{
"name": "@sinclair/typebox",
- "version": "0.31.28",
- "description": "JSONSchema Type Builder with Static Type Resolution for TypeScript",
+ "version": "0.32.0",
+ "description": "Json Schema Type Builder with Static Type Resolution for TypeScript",
"keywords": [
"typescript",
"json-schema",
@@ -10,28 +10,6 @@
],
"author": "sinclairzx81",
"license": "MIT",
- "main": "./typebox.js",
- "types": "./typebox.d.ts",
- "exports": {
- "./compiler": "./compiler/index.js",
- "./errors": "./errors/index.js",
- "./system": "./system/index.js",
- "./value/cast": "./value/cast.js",
- "./value/check": "./value/check.js",
- "./value/clone": "./value/clone.js",
- "./value/convert": "./value/convert.js",
- "./value/create": "./value/create.js",
- "./value/delta": "./value/delta.js",
- "./value/deref": "./value/deref.js",
- "./value/equal": "./value/equal.js",
- "./value/guard": "./value/guard.js",
- "./value/hash": "./value/hash.js",
- "./value/mutate": "./value/mutate.js",
- "./value/pointer": "./value/pointer.js",
- "./value/transform": "./value/transform.js",
- "./value": "./value/index.js",
- ".": "./typebox.js"
- },
"repository": {
"type": "git",
"url": "https://github.com/sinclairzx81/typebox"
@@ -40,21 +18,21 @@
"test:typescript": "hammer task test_typescript",
"test:static": "hammer task test_static",
"test:runtime": "hammer task test_runtime",
+ "install:local": "hammer task install_local",
+ "benchmark": "hammer task benchmark",
+ "build": "hammer task build",
"test": "hammer task test",
"clean": "hammer task clean",
"format": "hammer task format",
"start": "hammer task start",
- "benchmark:compression": "hammer task benchmark_compression",
- "benchmark:measurement": "hammer task benchmark_measurement",
- "benchmark": "hammer task benchmark",
- "build": "hammer task build",
"publish": "hammer task publish",
"publish:dev": "hammer task publish_dev"
},
"devDependencies": {
+ "@arethetypeswrong/cli": "^0.13.2",
"@sinclair/hammer": "^0.18.0",
"@types/mocha": "^9.1.1",
- "@types/node": "^18.11.9",
+ "@types/node": "^20.10.1",
"ajv": "^8.12.0",
"ajv-formats": "^2.1.1",
"mocha": "^9.2.2",
diff --git a/readme.md b/readme.md
index 8ba3501..d667120 100644
--- a/readme.md
+++ b/readme.md
@@ -20,21 +20,14 @@
## Install
-#### Npm
```bash
$ npm install @sinclair/typebox --save
```
-#### Esm + Deno
-
-```typescript
-import { Type, Static } from 'https://esm.sh/@sinclair/typebox'
-```
-
## Example
```typescript
-import { Type, Static } from '@sinclair/typebox'
+import { Type, type Static } from '@sinclair/typebox'
const T = Type.Object({ // const T = {
x: Type.Number(), // type: 'object',
@@ -58,9 +51,9 @@ type T = Static // type T = {
## Overview
-TypeBox is a runtime type builder 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 assertion rules of the TypeScript compiler. TypeBox enables one to create a unified type that can be statically checked by TypeScript and runtime asserted using standard JSON Schema validation.
+TypeBox is a runtime type builder that creates in-memory Json Schema objects that infer as TypeScript types. The schematics produced by this library are designed to match the static type checking rules of the TypeScript compiler. TypeBox offers a unified type that can be statically checked by TypeScript and runtime asserted using standard Json Schema validation.
-This library is designed to enable JSON schema to compose with the same flexibility as TypeScript's type system. It can be used as a simple tool to build up complex schemas or integrated into REST or RPC services to help validate data received over the wire.
+This library is built to be a runtime type system offering similar capabilities to TypeScript's static type system. It can be used as a simple tool to build up complex schematics or integrated into REST and RPC services to help validate data received over the wire.
License MIT
@@ -71,17 +64,19 @@ License MIT
- [Types](#types)
- [Json](#types-json)
- [JavaScript](#types-javascript)
+ - [Import](#types-import)
- [Options](#types-options)
- [Properties](#types-properties)
- [Generics](#types-generics)
- [References](#types-references)
- [Recursive](#types-recursive)
- - [Conditional](#types-conditional)
- - [Template Literal](#types-templateliteral)
+ - [Template Literal](#types-template-literal)
- [Indexed](#types-indexed)
- - [Rest](#types-rest)
- - [Transform](#types-transform)
+ - [Mapped](#types-mapped)
+ - [Conditional](#types-conditional)
- [Intrinsic](#types-intrinsic)
+ - [Transform](#types-transform)
+ - [Rest](#types-rest)
- [Guard](#types-guard)
- [Unsafe](#types-unsafe)
- [Strict](#types-strict)
@@ -90,6 +85,8 @@ License MIT
- [Clone](#values-clone)
- [Check](#values-check)
- [Convert](#values-convert)
+ - [Default](#values-default)
+ - [Clean](#values-clean)
- [Cast](#values-cast)
- [Decode](#values-decode)
- [Encode](#values-decode)
@@ -107,10 +104,8 @@ License MIT
- [Ajv](#typecheck-ajv)
- [TypeCompiler](#typecheck-typecompiler)
- [TypeSystem](#typesystem)
- - [Types](#typesystem-types)
- - [Formats](#typesystem-formats)
- - [Errors](#typesystem-errors)
- [Policies](#typesystem-policies)
+- [Error Function](#error-function)
- [Workbench](#workbench)
- [Codegen](#codegen)
- [Ecosystem](#ecosystem)
@@ -127,7 +122,7 @@ License MIT
The following shows general usage.
```typescript
-import { Type, Static } from '@sinclair/typebox'
+import { Type, type Static } from '@sinclair/typebox'
//--------------------------------------------------------------------------------------------
//
@@ -297,6 +292,22 @@ The following table lists the supported Json types. These types are fully compat
│ │ │ } │
│ │ │ │
├────────────────────────────────┼─────────────────────────────┼────────────────────────────────┤
+│ const T = Type.Const({ │ type T = { │ const T = { │
+│ x: 1, │ readonly x: 1, │ type: 'object', │
+│ y: 2, │ readonly y: 2 │ required: ['x', 'y'], │
+│ } as const) │ } │ properties: { │
+│ │ │ x: { │
+│ │ │ type: 'number', │
+│ │ │ const: 1 │
+│ │ │ }, │
+│ │ │ y: { │
+│ │ │ type: 'number', │
+│ │ │ const: 2 │
+│ │ │ } │
+│ │ │ } │
+│ │ │ } │
+│ │ │ │
+├────────────────────────────────┼─────────────────────────────┼────────────────────────────────┤
│ const T = Type.KeyOf( │ type T = keyof { │ const T = { │
│ Type.Object({ │ x: number, │ anyOf: [{ │
│ x: Type.Number(), │ y: number │ type: 'string', │
@@ -365,8 +376,8 @@ The following table lists the supported Json types. These types are fully compat
├────────────────────────────────┼─────────────────────────────┼────────────────────────────────┤
│ const T = Type.Extends( │ type T = │ const T = { │
│ Type.String(), │ string extends number │ const: false, │
-│ Type.Number(), │ true : false │ type: 'boolean' │
-│ Type.Literal(true), │ │ } │
+│ Type.Number(), │ ? true │ type: 'boolean' │
+│ Type.Literal(true), │ : false │ } │
│ Type.Literal(false) │ │ │
│ ) │ │ │
│ │ │ │
@@ -389,6 +400,20 @@ The following table lists the supported Json types. These types are fully compat
│ ) │ │ │
│ │ │ │
├────────────────────────────────┼─────────────────────────────┼────────────────────────────────┤
+│ const T = Type.Mapped( │ type T = { │ const T = { │
+│ Type.Union([ │ [_ in 'x' | 'y'] : number │ type: 'object', │
+│ Type.Literal('x'), │ } │ required: ['x', 'y'], │
+│ Type.Literal('y') │ │ properties: { │
+│ ]), │ │ x: { │
+│ () => Type.Number() │ │ type: 'number' │
+│ ) │ │ }, │
+│ │ │ y: { │
+│ │ │ type: 'number' │
+│ │ │ } │
+│ │ │ } │
+│ │ │ } │
+│ │ │ │
+├────────────────────────────────┼─────────────────────────────┼────────────────────────────────┤
│ const U = Type.Union([ │ type U = 'open' | 'close' │ const T = { │
│ Type.Literal('open'), │ │ type: 'string', │
│ Type.Literal('close') │ type T = `on${U}` │ pattern: '^on(open|close)$' │
@@ -580,9 +605,10 @@ TypeBox provides an extended type set that can be used to create schematics for
│ │ │ } │
│ │ │ │
├────────────────────────────────┼─────────────────────────────┼────────────────────────────────┤
-│ const T = Type.RegExp(/abc/) │ type T = string │ const T = { │
-│ │ │ type: 'string' │
-│ │ │ pattern: 'abc' │
+│ const T = Type.RegExp(/abc/i) │ type T = string │ const T = { │
+│ │ │ type: 'RegExp' │
+│ │ │ source: 'abc' │
+│ │ │ flags: 'i' │
│ │ │ } │
│ │ │ │
├────────────────────────────────┼─────────────────────────────┼────────────────────────────────┤
@@ -618,11 +644,27 @@ TypeBox provides an extended type set that can be used to create schematics for
└────────────────────────────────┴─────────────────────────────┴────────────────────────────────┘
```
+
+
+### Import
+
+Import the Type namespace to bring in TypeBox's full type system. This is recommended for most users.
+
+```typescript
+import { Type, type Static } from '@sinclair/typebox'
+```
+
+You can also selectively import types. This enables modern bundlers to tree shake for unused types.
+
+```typescript
+import { Object, Number, String, Boolean, type Static } from '@sinclair/typebox'
+```
+
### Options
-You can pass Json Schema options on the last argument of any type. Option hints specific to each type are provided for convenience.
+You can pass Json Schema options on the last argument of any given type. Option hints specific to each type are provided for convenience.
```typescript
// String must be an email
@@ -690,35 +732,27 @@ Object properties can be modified with Readonly and Optional. The following tabl
│ │ │ │
└────────────────────────────────┴─────────────────────────────┴────────────────────────────────┘
```
+
### Generic Types
-Generic types can be created with generic functions. All types extend the base type TSchema. It is common to constrain generic function arguments to this type. The following creates a generic Vector type.
+Generic types can be created with functions. TypeBox types extend the TSchema interface so you should constrain parameters to this type. The following creates a generic Vector type.
```typescript
-import { Type, Static, TSchema } from '@sinclair/typebox'
+import { Type, type Static, type TSchema } from '@sinclair/typebox'
-const Vector = (t: T) => Type.Object({ x: t, y: t, z: t })
+const Vector = (T: T) =>
+ Type.Object({ // type Vector = {
+ x: T, // x: T,
+ y: T, // y: T,
+ z: T // z: T
+ }) // }
-const NumberVector = Vector(Type.Number()) // const NumberVector = {
- // type: 'object',
- // required: ['x', 'y', 'z'],
- // properties: {
- // x: { type: 'number' },
- // y: { type: 'number' },
- // z: { type: 'number' }
- // }
- // }
-
-type NumberVector = Static // type NumberVector = {
- // x: number,
- // y: number,
- // z: number
- // }
+const NumberVector = Vector(Type.Number()) // type NumberVector = Vector
```
-Generic types are often used to create aliases for more complex types. The following creates a Nullable generic type.
+Generic types are often used to create aliases for complex types. The following creates a Nullable generic type.
```typescript
const Nullable = (schema: T) => Type.Union([schema, Type.Null()])
@@ -737,26 +771,69 @@ type T = Static // type T = string | null
### Reference Types
-Reference types are supported with Ref.
+Reference types can be created with Ref. These types infer the same as the target type but only store a named `$ref` to the target type.
```typescript
-const T = Type.String({ $id: 'T' }) // const T = {
- // $id: 'T',
- // type: 'string'
- // }
-
-const R = Type.Ref('T') // const R = {
- // $ref: 'T'
+const Vector = Type.Object({ // const Vector = {
+ x: Type.Number(), // type: 'object',
+ y: Type.Number(), // required: ['x', 'y', 'z'],
+}, { $id: 'Vector' }) // properties: {
+ // x: { type: 'number' },
+ // y: { type: 'number' }
+ // },
+ // $id: 'Vector'
// }
-type R = Static // type R = string
+const VectorRef = Type.Ref(Vector) // const VectorRef = {
+ // $ref: 'Vector'
+ // }
+
+type VectorRef = Static // type VectorRef = {
+ // x: number,
+ // y: number
+ // }
```
+Use Deref to dereference a type. This function will replace any interior reference with the target type.
+```typescript
+const Vertex = Type.Object({ // const Vertex = {
+ position: VectorRef, // type: 'object',
+ texcoord: VectorRef, // required: ['position', 'texcoord'],
+}) // properties: {
+ // position: { $ref: 'Vector' },
+ // texcoord: { $ref: 'Vector' }
+ // }
+ // }
+
+const VertexDeref = Type.Deref(Vertex, [Vector]) // const VertexDeref = {
+ // type: 'object',
+ // required: ['position', 'texcoord'],
+ // properties: {
+ // position: {
+ // type: 'object',
+ // required: ['x', 'y', 'z'],
+ // properties: {
+ // x: { type: 'number' },
+ // y: { type: 'number' }
+ // }
+ // },
+ // texcoord: {
+ // type: 'object',
+ // required: ['x', 'y', 'z'],
+ // properties: {
+ // x: { type: 'number' },
+ // y: { type: 'number' }
+ // }
+ // }
+ // }
+ // }
+```
+Note that Ref types do not store structural information about the type they're referencing. Because of this, these types cannot be used with some mapping types (such as Partial or Pick). For applications that require mapping on Ref, use Deref to normalize the type first.
### Recursive Types
-TypeBox supports singular recursive data structures. Recursive type inference is also supported. The following creates a recursive Node data structure.
+TypeBox supports recursive data structures with Recursive. This type wraps an interior type and provides it a `this` context that allows the type to reference itself. The following creates a recursive type. Singular recursive inference is also supported.
```typescript
const Node = Type.Recursive(This => Type.Object({ // const Node = {
@@ -789,204 +866,155 @@ function test(node: Node) {
}
```
-
-
-### Conditional Types
-
-TypeBox supports runtime conditional types with Extends. This type will perform a structural assignability check for the first two arguments and returns one of the second two arguments based on the result. The Extends type is modelled after TypeScript conditional types. The Exclude and Extract conditional types are also supported.
-
-```typescript
-// TypeScript
-
-type T0 = string extends number ? true : false // type T0 = false
-
-type T1 = Extract<(1 | 2 | 3), 1> // type T1 = 1
-
-type T2 = Exclude<(1 | 2 | 3), 1> // type T2 = 2 | 3
-
-// TypeBox
-
-const T0 = Type.Extends( // const T0: TLiteral = {
- Type.String(), // type: 'boolean',
- Type.Number(), // const: false
- Type.Literal(true), // }
- Type.Literal(false)
-)
-
-const T1 = Type.Extract( // const T1: TLiteral<1> = {
- Type.Union([ // type: 'number',
- Type.Literal(1), // const: 1
- Type.Literal(2), // }
- Type.Literal(3)
- ]),
- Type.Literal(1)
-)
-
-const T2 = Type.Exclude( // const T2: TUnion<[
- Type.Union([ // TLiteral<2>,
- Type.Literal(1), // TLiteral<3>
- Type.Literal(2), // ]> = {
- Type.Literal(3) // anyOf: [{
- ]), // type: 'number',
- Type.Literal(1) // const: 2
-) // }, {
- // type: 'number',
- // const: 3
- // }]
- // }
-```
-
-
+
### Template Literal Types
-TypeBox supports template literal types with TemplateLiteral. This type can be created using a string syntax that is similar to the TypeScript template literal syntax. This type can also be constructed by passing an array of Union and Literal types in sequence. The following example shows the string syntax.
+TypeBox supports template literal types with TemplateLiteral. This type can be created using a syntax similar to the TypeScript template literal syntax or composed from exterior types. TypeBox encodes template literals as regular expressions which enables the template to be checked by Json Schema validators. This type also supports regular expression parsing that enables template patterns to be used for generative types. The following shows both TypeScript and TypeBox usage.
```typescript
// TypeScript
-type T = `option${'A'|'B'|'C'}` // type T = 'optionA' | 'optionB' | 'optionC'
+type K = `prop${'A'|'B'|'C'}` // type T = 'propA' | 'propB' | 'propC'
-type R = Record // type R = {
- // optionA: string
- // optionB: string
- // optionC: string
+type R = Record // type R = {
+ // propA: string
+ // propB: string
+ // propC: string
// }
// TypeBox
-const T = Type.TemplateLiteral('option${A|B|C}') // const T = {
- // pattern: '^option(A|B|C)$',
- // type: 'string'
- // }
+const K = Type.TemplateLiteral('prop${A|B|C}') // const K: TTemplateLiteral<[
+ // TLiteral<'prop'>,
+ // TUnion<[
+ // TLiteral<'A'>,
+ // TLiteral<'B'>,
+ // TLiteral<'C'>,
+ // ]>
+ // ]>
-const R = Type.Record(T, Type.String()) // const R = {
- // type: 'object',
- // required: ['optionA', 'optionB'],
- // properties: {
- // optionA: {
- // type: 'string'
- // },
- // optionB: {
- // type: 'string'
- // }
- // optionC: {
- // type: 'string'
- // }
- // }
- // }
+const R = Type.Record(K, Type.String()) // const R: TObject<{
+ // hello1: TString,
+ // hello2: TString,
+ // hello3: TString,
+ // }>
```
### Indexed Access Types
-TypeBox supports Indexed Access Types with Index. This type enables uniform access to interior property and array element types without having to extract them from the underlying schema representation. This type is supported for Object, Array, Tuple, Union and Intersect types.
+TypeBox supports indexed access types with Index. This type enables uniform access to interior property and element types without having to extract them from the underlying schema representation. This type is supported for Object, Array, Tuple, Union and Intersect types.
```typescript
-const T = Type.Object({ // const T = {
- x: Type.Number(), // type: 'object',
- y: Type.String(), // required: ['x', 'y', 'z'],
- z: Type.Boolean() // properties: {
-}) // x: { type: 'number' },
- // y: { type: 'string' },
- // z: { type: 'string' }
- // }
- // }
+const T = Type.Object({ // type T = {
+ x: Type.Number(), // x: number,
+ y: Type.String(), // y: string,
+ z: Type.Boolean() // z: boolean
+}) // }
-const A = Type.Index(T, ['x']) // const A = { type: 'number' }
+const A = Type.Index(T, ['x']) // type A = T['x']
+ //
+ // ... evaluated as
+ //
+ // const A: TNumber
-const B = Type.Index(T, ['x', 'y']) // const B = {
- // anyOf: [
- // { type: 'number' },
- // { type: 'string' }
- // ]
- // }
+const B = Type.Index(T, ['x', 'y']) // type B = T['x' | 'y']
+ //
+ // ... evaluated as
+ //
+ // const B: TUnion<[
+ // TNumber,
+ // TString,
+ // ]>
-const C = Type.Index(T, Type.KeyOf(T)) // const C = {
- // anyOf: [
- // { type: 'number' },
- // { type: 'string' },
- // { type: 'boolean' }
- // ]
- // }
+const C = Type.Index(T, Type.KeyOf(T)) // type C = T[keyof T]
+ //
+ // ... evaluated as
+ //
+ // const C: TUnion<[
+ // TNumber,
+ // TString,
+ // TBoolean
+ // ]>
```
-
+
-### Rest Types
+### Mapped Types
-TypeBox provides the Rest type to uniformly extract variadic tuples from Intersect, Union and Tuple types. This type can be useful to remap variadic types into different forms. The following uses Rest to remap a Tuple into a Union.
+TypeBox supports mapped object types with Mapped. This type accepts two arguments, the first is a union type typically derived from KeyOf, the second is a mapping function that receives a mapping key `K` that can be used to index properties of a type. The following implements Partial using mapped types.
```typescript
-const T = Type.Tuple([ // const T = {
- Type.String(), // type: 'array',
- Type.Number() // items: [
-]) // { type: 'string' },
- // { type: 'number' }
- // ],
- // additionalItems: false,
- // minItems: 2,
- // maxItems: 2,
- // }
+const T = Type.Object({ // type T = {
+ x: Type.Number(), // x: number,
+ y: Type.String(), // y: string,
+ z: Type.Boolean() // z: boolean
+}) // }
-const R = Type.Rest(T) // const R = [
- // { type: 'string' },
- // { type: 'number' }
- // ]
-
-const U = Type.Union(R) // const U = {
- // anyOf: [
- // { type: 'string' },
- // { type: 'number' }
- // ]
- // }
+const M = Type.Mapped(Type.KeyOf(T), K => { // type M = { [K in keyof T]?: T[K] }
+ return Type.Optional(Type.Index(T, K)) //
+}) // ... evaluated as
+ //
+ // const M: TObject<{
+ // x: TOptional,
+ // y: TOptional,
+ // z: TOptional
+ // }>
```
-
+
-### Transform Types
+### Conditional Types
-TypeBox supports value decoding and encoding with Transform types. These types work in tandem with the Encode and Decode functions available on the Value and TypeCompiler modules. Transform types can be used to convert Json encoded values into constructs more natural to JavaScript. The following creates a Transform type to decode numbers into Dates using the Value module.
+TypeBox supports runtime conditional types with Extends. This type performs a structural assignability check against the first (`left`) and second (`right`) arguments and will return either the third (`true`) or fourth (`false`) argument based on the result. The conditional types Exclude and Extract are also supported. The following shows both TypeScript and TypeBox examples of conditional types.
```typescript
-import { Value } from '@sinclair/typebox/value'
+// Extends
+const A = Type.Extends( // type A = string extends number ? 1 : 2
+ Type.String(), //
+ Type.Number(), // ... evaluated as
+ Type.Literal(1), //
+ Type.Literal(2) // const A: TLiteral<2>
+)
-const T = Type.Transform(Type.Number())
- .Decode(value => new Date(value)) // required: number to Date
- .Encode(value => value.getTime()) // required: Date to number
+// Extract
+const B = Type.Extract( // type B = Extract<1 | 2 | 3, 1>
+ Type.Union([ //
+ Type.Literal(1), // ... evaluated as
+ Type.Literal(2), //
+ Type.Literal(3) // const B: TLiteral<1>
+ ]),
+ Type.Literal(1)
+)
-const decoded = Value.Decode(T, 0) // const decoded = Date(1970-01-01T00:00:00.000Z)
-const encoded = Value.Encode(T, decoded) // const encoded = 0
-```
-Use the StaticEncode or StaticDecode types to infer a Transform type.
-```typescript
-import { Static, StaticDecode, StaticEncode } from '@sinclair/typebox'
-
-const T = Type.Transform(Type.Array(Type.Number(), { uniqueItems: true }))
- .Decode(value => new Set(value))
- .Encode(value => [...value])
-
-type D = StaticDecode // type D = Set
-type E = StaticEncode // type E = Array
-type T = Static // type T = Array
+// Exclude
+const C = Type.Exclude( // type C = Exclude<1 | 2 | 3, 1>
+ Type.Union([ //
+ Type.Literal(1), // ... evaluated as
+ Type.Literal(2), //
+ Type.Literal(3) // const C: TUnion<[
+ ]), // TLiteral<2>,
+ Type.Literal(1) // TLiteral<3>,
+) // ]>
```
### Intrinsic Types
-TypeBox supports the TypeScript Intrinsic String Manipulation types Uppercase, Lowercase, Capitalize and Uncapitalize. These types can be used to remap String Literal, TemplateLiteral and Union types.
+TypeBox supports the TypeScript intrinsic string manipulation types Uppercase, Lowercase, Capitalize and Uncapitalize. These types can be used to remap Literal, Template Literal and Union of Literal types.
```typescript
// TypeScript
-
type A = Capitalize<'hello'> // type A = 'Hello'
+
type B = Capitalize<'hello' | 'world'> // type C = 'Hello' | 'World'
+
type C = Capitalize<`hello${1|2|3}`> // type B = 'Hello1' | 'Hello2' | 'Hello3'
// TypeBox
-
const A = Type.Capitalize(Type.Literal('hello')) // const A: TLiteral<'Hello'>
const B = Type.Capitalize(Type.Union([ // const B: TUnion<[
@@ -1004,6 +1032,55 @@ const C = Type.Capitalize( // const C: TTemplateLitera
// ]>
```
+
+
+### Transform Types
+
+TypeBox supports value decoding and encoding with Transform types. These types work in tandem with the Encode and Decode functions available on the Value and TypeCompiler submodules. Transform types can be used to convert Json encoded values into constructs more natural to JavaScript. The following creates a Transform type to decode numbers into Dates using the Value submodule.
+
+```typescript
+import { Value } from '@sinclair/typebox/value'
+
+const T = Type.Transform(Type.Number())
+ .Decode(value => new Date(value)) // decode: number to Date
+ .Encode(value => value.getTime()) // encode: Date to number
+
+const D = Value.Decode(T, 0) // const D = Date(1970-01-01T00:00:00.000Z)
+const E = Value.Encode(T, D) // const E = 0
+```
+Use the StaticEncode or StaticDecode types to infer a Transform type.
+```typescript
+import { Static, StaticDecode, StaticEncode } from '@sinclair/typebox'
+
+const T = Type.Transform(Type.Array(Type.Number(), { uniqueItems: true }))
+ .Decode(value => new Set(value))
+ .Encode(value => [...value])
+
+type D = StaticDecode // type D = Set
+type E = StaticEncode // type E = Array
+type T = Static // type T = Array
+```
+
+
+
+### Rest Types
+
+TypeBox provides the Rest type to uniformly extract variadic tuples from Intersect, Union and Tuple types. This type can be useful to remap variadic types into different forms. The following uses Rest to remap a Tuple into a Union.
+
+```typescript
+const T = Type.Tuple([ // const T: TTuple<[
+ Type.String(), // TString,
+ Type.Number() // TNumber
+]) // ]>
+
+const R = Type.Rest(T) // const R: [TString, TNumber]
+
+const U = Type.Union(R) // const T: TUnion<[
+ // TString,
+ // TNumber
+ // ]>
+```
+
### Unsafe Types
@@ -1011,13 +1088,11 @@ const C = Type.Capitalize( // const C: TTemplateLitera
TypeBox supports user defined types with Unsafe. This type allows you to specify both schema representation and inference type. The following creates an Unsafe type with a number schema that infers as string.
```typescript
-const T = Type.Unsafe({ type: 'number' }) // const T = {
- // type: 'number'
- // }
+const T = Type.Unsafe({ type: 'number' }) // const T = { type: 'number' }
type T = Static // type T = string - ?
```
-The Unsafe type is often used to create schematics for extended specifications like OpenAPI
+The Unsafe type is often used to create schematics for extended specifications like OpenAPI.
```typescript
const Nullable = (schema: T) => Type.Unsafe | null>({
@@ -1042,18 +1117,18 @@ type S = Static // type S = 'A' | 'B' | 'C'
```
-### Type Guard
+### TypeGuard
-TypeBox can type check its own types with the TypeGuard module. This module is written for reflection and provides structural tests for every TypeBox type. Functions of this module return `is` guards which can be used with TypeScript control flow assertions to obtain schema inference. The following guards that the value A is TString.
+TypeBox can check its own types with the TypeGuard module. This module is written for type introspection and provides structural tests for every built-in TypeBox type. Functions of this module return `is` guards which can be used with control flow assertions to obtain schema inference for unknown values. The following guards that the value `T` is TString.
```typescript
-import { Type, Kind, TypeGuard } from '@sinclair/typebox'
+import { TypeGuard, Kind } from '@sinclair/typebox'
-const A: unknown = { ... }
+const T = { [Kind]: 'String', type: 'string' }
-if(TypeGuard.TString(A)) {
+if(TypeGuard.IsString(T)) {
- A.type // A.type = 'string'
+ // T is TString
}
```
@@ -1065,13 +1140,13 @@ TypeBox types contain various symbol properties that are used for reflection, co
```typescript
const T = Type.Object({ // const T = {
- name: Type.Optional(Type.String()) // [Kind]: 'Object',
+ name: Type.Optional(Type.String()) // [Symbol(TypeBox.Kind)]: 'Object',
}) // type: 'object',
// properties: {
// name: {
// type: 'string',
- // [Kind]: 'String',
- // [Optional]: 'Optional'
+ // [Symbol(TypeBox.Kind)]: 'String',
+ // [Symbol(TypeBox.Optional)]: 'Optional'
// }
// }
// }
@@ -1090,7 +1165,7 @@ const U = Type.Strict(T) // const U = {
## Values
-TypeBox provides an optional utility module that can be used to perform structural operations on JavaScript values. This module includes functionality to create, check and cast values from types as well as check equality, clone, diff and patch JavaScript values. This module is provided via optional import.
+TypeBox provides an optional Value submodule that can be used to perform structural operations on JavaScript values. This submodule includes functionality to create, check and cast values from types as well as check equality, clone, diff and patch JavaScript values. This submodule is provided via optional import.
```typescript
import { Value } from '@sinclair/typebox/value'
@@ -1144,11 +1219,49 @@ const R1 = Value.Convert(T, { x: '3.14' }) // const R1 = { x: 3.14 }
const R2 = Value.Convert(T, { x: 'not a number' }) // const R2 = { x: 'not a number' }
```
+
+
+### Clean
+
+Use Clean to remove excess properties from a value. This function does not check the value and returns an unknown type. You should Check the result before use. Clean is a mutable operation. To avoid mutation, Clone the value first.
+
+```typescript
+const T = Type.Object({
+ x: Type.Number(),
+ y: Type.Number()
+})
+
+const X = Value.Clean(T, null) // const 'X = null
+
+const Y = Value.Clean(T, { x: 1 }) // const 'Y = { x: 1 }
+
+const Z = Value.Clean(T, { x: 1, y: 2, z: 3 }) // const 'Z = { x: 1, y: 2 }
+```
+
+
+
+### Default
+
+Use Default to generate missing properties on a value using default schema annotations if available. This function does not check the value and returns an unknown type. You should Check the result before use. Default is a mutable operation. To avoid mutation, Clone the value first.
+
+```typescript
+const T = Type.Object({
+ x: Type.Number({ default: 0 }),
+ y: Type.Number({ default: 0 })
+})
+
+const X = Value.Default(T, null) // const 'X = null - non-enumerable
+
+const Y = Value.Default(T, { }) // const 'Y = { x: 0, y: 0 }
+
+const Z = Value.Default(T, { x: 1 }) // const 'Z = { x: 1, y: 0 }
+```
+
### Cast
-Use the Cast function to cast a value with a type. The cast function will retain as much information as possible from the original value.
+Use the Cast function to upcast a value into a target type. This function will retain as much infomation as possible from the original value. The Cast function is intended to be used in data migration scenarios where existing values need to be upgraded to match a modified type.
```typescript
const T = Type.Object({ x: Type.Number(), y: Type.Number() }, { additionalProperties: false })
@@ -1164,7 +1277,7 @@ const Z = Value.Cast(T, { x: 1, y: 2, z: 3 }) // const Z = { x: 1, y: 2 }
### Decode
-Use the Decode function to decode a value from a type, or throw if the value is invalid. The return value will infer as the decoded type. This function will run Transform codecs if available.
+Use the Decode function to decode a value from a type or throw if the value is invalid. The return value will infer as the decoded type. This function will run Transform codecs if available.
```typescript
const A = Value.Decode(Type.String(), 'hello') // const A = 'hello'
@@ -1175,7 +1288,7 @@ const B = Value.Decode(Type.String(), 42) // throw
### Encode
-Use the Encode function to encode a value to a type, or throw if the value is invalid. The return value will infer as the encoded type. This function will run Transform codecs if available.
+Use the Encode function to encode a value to a type or throw if the value is invalid. The return value will infer as the encoded type. This function will run Transform codecs if available.
```typescript
const A = Value.Encode(Type.String(), 'hello') // const A = 'hello'
@@ -1275,7 +1388,7 @@ const Y = { z: 1 } // const Y = { z: 1 }
const X = { y: Y } // const X = { y: { z: 1 } }
const A = { x: X } // const A = { x: { y: { z: 1 } } }
-Value.Mutate(A, { x: { y: { z: 2 } } }) // const A' = { x: { y: { z: 2 } } }
+Value.Mutate(A, { x: { y: { z: 2 } } }) // A' = { x: { y: { z: 2 } } }
const R0 = A.x.y.z === 2 // const R0 = true
const R1 = A.x.y === Y // const R1 = true
@@ -1293,9 +1406,9 @@ import { ValuePointer } from '@sinclair/typebox/value'
const A = { x: 0, y: 0, z: 0 }
-ValuePointer.Set(A, '/x', 1) // const A' = { x: 1, y: 0, z: 0 }
-ValuePointer.Set(A, '/y', 1) // const A' = { x: 1, y: 1, z: 0 }
-ValuePointer.Set(A, '/z', 1) // const A' = { x: 1, y: 1, z: 1 }
+ValuePointer.Set(A, '/x', 1) // A' = { x: 1, y: 0, z: 0 }
+ValuePointer.Set(A, '/y', 1) // A' = { x: 1, y: 1, z: 0 }
+ValuePointer.Set(A, '/z', 1) // A' = { x: 1, y: 1, z: 1 }
```
@@ -1308,15 +1421,18 @@ The TypeBox type system can be extended with additional types and formats using
### TypeRegistry
-Use the TypeRegistry to register a new type. The Kind must match the registered type name.
+Use the TypeRegistry to register a type. The Kind must match the registered type name.
```typescript
-import { TypeRegistry, Kind } from '@sinclair/typebox'
+import { TSchema, Kind, TypeRegistry } from '@sinclair/typebox'
TypeRegistry.Set('Foo', (schema, value) => value === 'foo')
-const A = Value.Check({ [Kind]: 'Foo' }, 'foo') // const A = true
-const B = Value.Check({ [Kind]: 'Foo' }, 'bar') // const B = false
+const Foo = { [Kind]: 'Foo' } as TSchema
+
+const A = Value.Check(Foo, 'foo') // const A = true
+
+const B = Value.Check(Foo, 'bar') // const B = false
```
@@ -1333,6 +1449,7 @@ FormatRegistry.Set('foo', (value) => value === 'foo')
const T = Type.String({ format: 'foo' })
const A = Value.Check(T, 'foo') // const A = true
+
const B = Value.Check(T, 'bar') // const B = false
```
@@ -1445,7 +1562,7 @@ const all = [...C.Errors(value)] // const all = [{
// }]
```
-Use the Code function to generate assertion functions as strings. This function can be used to create high performance assertions that can be written to disk as importable modules. The following generates code to check a string.
+Use the Code function to generate assertion functions as strings. This function can be used to generate code that can be written to disk as importable modules. This technique is sometimes referred to as Ahead of Time (AOT) compilation. The following generates code to check a string.
```typescript
const C = TypeCompiler.Code(Type.String()) // const C = `return function check(value) {
@@ -1459,94 +1576,13 @@ const C = TypeCompiler.Code(Type.String()) // const C = `return functi
## TypeSystem
-The TypeBox TypeSystem module provides functionality to define types above and beyond the built-in Json and JavaScript type sets. They also manage TypeBox's localization options (i18n) for error message generation and can control various assertion policies used when type checking. Configurations made to the TypeSystem module are observed by the TypeCompiler, Value and Error modules.
-
-
-
-### Types
-
-Use the TypeSystem Type function to register a user defined type.
-
-```typescript
-import { TypeSystem } from '@sinclair/typebox/system'
-
-const StringSet = TypeSystem.Type>('StringSet', (options, value) => {
- return value instanceof Set && [...value].every(value => typeof value === 'string')
-})
-
-const T = StringSet({}) // Pass options if any
-
-const A = Value.Check(T, new Set()) // const A = true
-const B = Value.Check(T, new Set(['hello'])) // const B = true
-const C = Value.Check(T, new Set([1])) // const C = false
-
-```
-
-
-
-### Formats
-
-Use the TypeSystem Format function to register a string format.
-
-```typescript
-import { TypeSystem } from '@sinclair/typebox/system'
-
-const F = TypeSystem.Format('foo', value => value === 'Foo')
-
-const T = Type.String({ format: F })
-
-const A = Value.Check(T, 'foo') // const A = true
-const B = Value.Check(T, 'bar') // const B = false
-```
-
-
-
-### Errors
-
-Use the TypeSystemErrorFunction to override validation error messages. This can be used to localize errors or create error messages for user defined types.
-
-```typescript
-import { TypeSystemErrorFunction, ValueErrorType, DefaultErrorFunction } from '@sinclair/typebox/system'
-
-TypeSystemErrorFunction.Set((schema, errorType) => { // i18n override
- switch(errorType) {
- /* en-US */ case ValueErrorType.String: return 'Expected string'
- /* fr-FR */ case ValueErrorType.Number: return 'Nombre attendu'
- /* ko-KR */ case ValueErrorType.Boolean: return '예상 부울'
- /* en-US */ default: return DefaultErrorFunction(schema, errorType)
- }
-})
-const T = Type.Object({ // const T = { ... }
- x: Type.String(),
- y: Type.Number(),
- z: Type.Boolean()
-})
-const E = [...Value.Errors(T, { // const E = [{
- x: null, // type: 48,
- y: null, // schema: { ... },
- z: null // path: '/x',
-})] // value: null,
- // message: 'Expected string'
- // }, {
- // type: 34,
- // schema: { ... },
- // path: '/y',
- // value: null,
- // message: 'Nombre attendu'
- // }, {
- // type: 14,
- // schema: { ... },
- // path: '/z',
- // value: null,
- // message: '예상 부울'
- // }]
-```
+The TypeBox TypeSystem module provides configurations to use either Json Schema or TypeScript type checking semantics. Configurations made to the TypeSystem module are observed by the TypeCompiler, Value and Error modules.
### Policies
-TypeBox validates using standard Json Schema assertion policies by default. The TypeSystemPolicy module can override some of these to have TypeBox check values inline with TypeScript static assertions. It also provides overrides for certain checking rules related to non-serializable values (such as void) which can be useful in Json based protocols such as JsonRpc-2.
+TypeBox validates using standard Json Schema assertion policies by default. The TypeSystemPolicy module can override some of these to have TypeBox assert values inline with TypeScript static checks. It also provides overrides for certain checking rules related to non-serializable values (such as void) which can be helpful in Json based protocols such as Json Rpc 2.0.
The following overrides are available.
@@ -1573,11 +1609,58 @@ TypeSystemPolicy.AllowNaN = true
// Allow void types to check with undefined and null (default is false)
//
-// Used to signal void return on Json-RPC 2.0 protocol
+// Used to signal void return on Json-Rpc 2.0 protocol
TypeSystemPolicy.AllowNullVoid = true
```
+
+
+## Error Function
+
+Error messages in TypeBox can be customized by defining an ErrorFunction. This function allows for the localization of error messages as well as enabling custom error messages for custom types. By default, TypeBox will generate messages using the `en-US` locale. To support additional locales, you can replicate the function found in `src/errors/function.ts` and create a locale specific translation. The function can then be set via SetErrorFunction.
+
+The following example shows an inline error function that intercepts errors for String, Number and Boolean only. The DefaultErrorFunction is used to return a default error message.
+
+
+```typescript
+import { SetErrorFunction, DefaultErrorFunction, ValueErrorType } from '@sinclair/typebox/errors'
+
+SetErrorFunction((error) => { // i18n override
+ switch(error.errorType) {
+ /* en-US */ case ValueErrorType.String: return 'Expected string'
+ /* fr-FR */ case ValueErrorType.Number: return 'Nombre attendu'
+ /* ko-KR */ case ValueErrorType.Boolean: return '예상 부울'
+ /* en-US */ default: return DefaultErrorFunction(error)
+ }
+})
+const T = Type.Object({ // const T: TObject<{
+ x: Type.String(), // TString,
+ y: Type.Number(), // TNumber,
+ z: Type.Boolean() // TBoolean
+}) // }>
+
+const E = [...Value.Errors(T, { // const E = [{
+ x: null, // type: 48,
+ y: null, // schema: { ... },
+ z: null // path: '/x',
+})] // value: null,
+ // message: 'Expected string'
+ // }, {
+ // type: 34,
+ // schema: { ... },
+ // path: '/y',
+ // value: null,
+ // message: 'Nombre attendu'
+ // }, {
+ // type: 14,
+ // schema: { ... },
+ // path: '/z',
+ // value: null,
+ // message: '예상 부울'
+ // }]
+```
+
## TypeBox Workbench
@@ -1590,7 +1673,7 @@ TypeBox offers a web based code generation tool that can convert TypeScript type
## TypeBox Codegen
-TypeBox provides a code generation library that can be used to automate type translation between TypeScript and TypeBox. This library also includes functionality to transform TypeScript types to other ecosystem libraries.
+TypeBox provides a code generation library that can be integrated into toolchains to automate type translation between TypeScript and TypeBox. This library also includes functionality to transform TypeScript types to other ecosystem libraries.
[TypeBox Codegen Link Here](https://github.com/sinclairzx81/typebox-codegen)
@@ -1619,7 +1702,7 @@ The following is a list of community packages that offer general tooling, extend
## Benchmark
-This project maintains a set of benchmarks that measure Ajv, Value and TypeCompiler compilation and validation performance. These benchmarks can be run locally by cloning this repository and running `npm run benchmark`. The results below show for Ajv version 8.12.0 running on Node 20.0.0.
+This project maintains a set of benchmarks that measure Ajv, Value and TypeCompiler compilation and validation performance. These benchmarks can be run locally by cloning this repository and running `npm run benchmark`. The results below show for Ajv version 8.12.0 running on Node 20.10.0.
For additional comparative benchmarks, please refer to [typescript-runtime-type-benchmarks](https://moltar.github.io/typescript-runtime-type-benchmarks/).
@@ -1627,41 +1710,41 @@ For additional comparative benchmarks, please refer to [typescript-runtime-type-
### Compile
-This benchmark measures compilation performance for varying types. You can review this benchmark [here](https://github.com/sinclairzx81/typebox/blob/master/benchmark/measurement/module/compile.ts).
+This benchmark measures compilation performance for varying types.
```typescript
┌────────────────────────────┬────────────┬──────────────┬──────────────┬──────────────┐
│ (index) │ Iterations │ Ajv │ TypeCompiler │ Performance │
├────────────────────────────┼────────────┼──────────────┼──────────────┼──────────────┤
-│ Literal_String │ 1000 │ ' 216 ms' │ ' 9 ms' │ ' 24.00 x' │
-│ Literal_Number │ 1000 │ ' 169 ms' │ ' 7 ms' │ ' 24.14 x' │
-│ Literal_Boolean │ 1000 │ ' 150 ms' │ ' 5 ms' │ ' 30.00 x' │
-│ Primitive_Number │ 1000 │ ' 161 ms' │ ' 7 ms' │ ' 23.00 x' │
-│ Primitive_String │ 1000 │ ' 148 ms' │ ' 6 ms' │ ' 24.67 x' │
-│ Primitive_String_Pattern │ 1000 │ ' 185 ms' │ ' 9 ms' │ ' 20.56 x' │
-│ Primitive_Boolean │ 1000 │ ' 132 ms' │ ' 4 ms' │ ' 33.00 x' │
-│ Primitive_Null │ 1000 │ ' 141 ms' │ ' 3 ms' │ ' 47.00 x' │
-│ Object_Unconstrained │ 1000 │ ' 1109 ms' │ ' 30 ms' │ ' 36.97 x' │
-│ Object_Constrained │ 1000 │ ' 1200 ms' │ ' 24 ms' │ ' 50.00 x' │
-│ Object_Vector3 │ 1000 │ ' 379 ms' │ ' 9 ms' │ ' 42.11 x' │
-│ Object_Box3D │ 1000 │ ' 1709 ms' │ ' 30 ms' │ ' 56.97 x' │
-│ Tuple_Primitive │ 1000 │ ' 456 ms' │ ' 14 ms' │ ' 32.57 x' │
-│ Tuple_Object │ 1000 │ ' 1229 ms' │ ' 17 ms' │ ' 72.29 x' │
-│ Composite_Intersect │ 1000 │ ' 570 ms' │ ' 17 ms' │ ' 33.53 x' │
-│ Composite_Union │ 1000 │ ' 513 ms' │ ' 19 ms' │ ' 27.00 x' │
-│ Math_Vector4 │ 1000 │ ' 782 ms' │ ' 13 ms' │ ' 60.15 x' │
-│ Math_Matrix4 │ 1000 │ ' 393 ms' │ ' 12 ms' │ ' 32.75 x' │
-│ Array_Primitive_Number │ 1000 │ ' 361 ms' │ ' 12 ms' │ ' 30.08 x' │
-│ Array_Primitive_String │ 1000 │ ' 296 ms' │ ' 5 ms' │ ' 59.20 x' │
-│ Array_Primitive_Boolean │ 1000 │ ' 315 ms' │ ' 4 ms' │ ' 78.75 x' │
-│ Array_Object_Unconstrained │ 1000 │ ' 1721 ms' │ ' 22 ms' │ ' 78.23 x' │
-│ Array_Object_Constrained │ 1000 │ ' 1450 ms' │ ' 21 ms' │ ' 69.05 x' │
-│ Array_Tuple_Primitive │ 1000 │ ' 813 ms' │ ' 13 ms' │ ' 62.54 x' │
-│ Array_Tuple_Object │ 1000 │ ' 1537 ms' │ ' 17 ms' │ ' 90.41 x' │
-│ Array_Composite_Intersect │ 1000 │ ' 753 ms' │ ' 17 ms' │ ' 44.29 x' │
-│ Array_Composite_Union │ 1000 │ ' 808 ms' │ ' 16 ms' │ ' 50.50 x' │
-│ Array_Math_Vector4 │ 1000 │ ' 1118 ms' │ ' 16 ms' │ ' 69.88 x' │
-│ Array_Math_Matrix4 │ 1000 │ ' 690 ms' │ ' 9 ms' │ ' 76.67 x' │
+│ Literal_String │ 1000 │ ' 242 ms' │ ' 10 ms' │ ' 24.20 x' │
+│ Literal_Number │ 1000 │ ' 200 ms' │ ' 8 ms' │ ' 25.00 x' │
+│ Literal_Boolean │ 1000 │ ' 168 ms' │ ' 6 ms' │ ' 28.00 x' │
+│ Primitive_Number │ 1000 │ ' 165 ms' │ ' 8 ms' │ ' 20.63 x' │
+│ Primitive_String │ 1000 │ ' 154 ms' │ ' 6 ms' │ ' 25.67 x' │
+│ Primitive_String_Pattern │ 1000 │ ' 208 ms' │ ' 14 ms' │ ' 14.86 x' │
+│ Primitive_Boolean │ 1000 │ ' 142 ms' │ ' 6 ms' │ ' 23.67 x' │
+│ Primitive_Null │ 1000 │ ' 143 ms' │ ' 6 ms' │ ' 23.83 x' │
+│ Object_Unconstrained │ 1000 │ ' 1217 ms' │ ' 31 ms' │ ' 39.26 x' │
+│ Object_Constrained │ 1000 │ ' 1275 ms' │ ' 26 ms' │ ' 49.04 x' │
+│ Object_Vector3 │ 1000 │ ' 405 ms' │ ' 12 ms' │ ' 33.75 x' │
+│ Object_Box3D │ 1000 │ ' 1833 ms' │ ' 27 ms' │ ' 67.89 x' │
+│ Tuple_Primitive │ 1000 │ ' 475 ms' │ ' 13 ms' │ ' 36.54 x' │
+│ Tuple_Object │ 1000 │ ' 1267 ms' │ ' 30 ms' │ ' 42.23 x' │
+│ Composite_Intersect │ 1000 │ ' 604 ms' │ ' 18 ms' │ ' 33.56 x' │
+│ Composite_Union │ 1000 │ ' 545 ms' │ ' 20 ms' │ ' 27.25 x' │
+│ Math_Vector4 │ 1000 │ ' 829 ms' │ ' 12 ms' │ ' 69.08 x' │
+│ Math_Matrix4 │ 1000 │ ' 405 ms' │ ' 10 ms' │ ' 40.50 x' │
+│ Array_Primitive_Number │ 1000 │ ' 372 ms' │ ' 12 ms' │ ' 31.00 x' │
+│ Array_Primitive_String │ 1000 │ ' 327 ms' │ ' 5 ms' │ ' 65.40 x' │
+│ Array_Primitive_Boolean │ 1000 │ ' 300 ms' │ ' 4 ms' │ ' 75.00 x' │
+│ Array_Object_Unconstrained │ 1000 │ ' 1755 ms' │ ' 21 ms' │ ' 83.57 x' │
+│ Array_Object_Constrained │ 1000 │ ' 1516 ms' │ ' 20 ms' │ ' 75.80 x' │
+│ Array_Tuple_Primitive │ 1000 │ ' 825 ms' │ ' 14 ms' │ ' 58.93 x' │
+│ Array_Tuple_Object │ 1000 │ ' 1616 ms' │ ' 16 ms' │ ' 101.00 x' │
+│ Array_Composite_Intersect │ 1000 │ ' 776 ms' │ ' 16 ms' │ ' 48.50 x' │
+│ Array_Composite_Union │ 1000 │ ' 820 ms' │ ' 14 ms' │ ' 58.57 x' │
+│ Array_Math_Vector4 │ 1000 │ ' 1166 ms' │ ' 15 ms' │ ' 77.73 x' │
+│ Array_Math_Matrix4 │ 1000 │ ' 695 ms' │ ' 8 ms' │ ' 86.88 x' │
└────────────────────────────┴────────────┴──────────────┴──────────────┴──────────────┘
```
@@ -1669,43 +1752,43 @@ This benchmark measures compilation performance for varying types. You can revie
### Validate
-This benchmark measures validation performance for varying types. You can review this benchmark [here](https://github.com/sinclairzx81/typebox/blob/master/benchmark/measurement/module/check.ts).
+This benchmark measures validation performance for varying types.
```typescript
┌────────────────────────────┬────────────┬──────────────┬──────────────┬──────────────┬──────────────┐
│ (index) │ Iterations │ ValueCheck │ Ajv │ TypeCompiler │ Performance │
├────────────────────────────┼────────────┼──────────────┼──────────────┼──────────────┼──────────────┤
-│ Literal_String │ 1000000 │ ' 24 ms' │ ' 5 ms' │ ' 4 ms' │ ' 1.25 x' │
-│ Literal_Number │ 1000000 │ ' 15 ms' │ ' 20 ms' │ ' 10 ms' │ ' 2.00 x' │
-│ Literal_Boolean │ 1000000 │ ' 14 ms' │ ' 19 ms' │ ' 9 ms' │ ' 2.11 x' │
-│ Primitive_Number │ 1000000 │ ' 25 ms' │ ' 18 ms' │ ' 10 ms' │ ' 1.80 x' │
-│ Primitive_String │ 1000000 │ ' 21 ms' │ ' 24 ms' │ ' 9 ms' │ ' 2.67 x' │
-│ Primitive_String_Pattern │ 1000000 │ ' 156 ms' │ ' 43 ms' │ ' 38 ms' │ ' 1.13 x' │
+│ Literal_String │ 1000000 │ ' 18 ms' │ ' 5 ms' │ ' 4 ms' │ ' 1.25 x' │
+│ Literal_Number │ 1000000 │ ' 16 ms' │ ' 18 ms' │ ' 10 ms' │ ' 1.80 x' │
+│ Literal_Boolean │ 1000000 │ ' 15 ms' │ ' 19 ms' │ ' 10 ms' │ ' 1.90 x' │
+│ Primitive_Number │ 1000000 │ ' 21 ms' │ ' 19 ms' │ ' 10 ms' │ ' 1.90 x' │
+│ Primitive_String │ 1000000 │ ' 22 ms' │ ' 18 ms' │ ' 9 ms' │ ' 2.00 x' │
+│ Primitive_String_Pattern │ 1000000 │ ' 155 ms' │ ' 41 ms' │ ' 34 ms' │ ' 1.21 x' │
│ Primitive_Boolean │ 1000000 │ ' 18 ms' │ ' 17 ms' │ ' 9 ms' │ ' 1.89 x' │
-│ Primitive_Null │ 1000000 │ ' 20 ms' │ ' 17 ms' │ ' 9 ms' │ ' 1.89 x' │
-│ Object_Unconstrained │ 1000000 │ ' 1055 ms' │ ' 32 ms' │ ' 24 ms' │ ' 1.33 x' │
-│ Object_Constrained │ 1000000 │ ' 1232 ms' │ ' 49 ms' │ ' 43 ms' │ ' 1.14 x' │
-│ Object_Vector3 │ 1000000 │ ' 432 ms' │ ' 23 ms' │ ' 13 ms' │ ' 1.77 x' │
-│ Object_Box3D │ 1000000 │ ' 1993 ms' │ ' 54 ms' │ ' 46 ms' │ ' 1.17 x' │
-│ Object_Recursive │ 1000000 │ ' 5115 ms' │ ' 342 ms' │ ' 159 ms' │ ' 2.15 x' │
-│ Tuple_Primitive │ 1000000 │ ' 156 ms' │ ' 21 ms' │ ' 13 ms' │ ' 1.62 x' │
-│ Tuple_Object │ 1000000 │ ' 740 ms' │ ' 29 ms' │ ' 18 ms' │ ' 1.61 x' │
-│ Composite_Intersect │ 1000000 │ ' 797 ms' │ ' 26 ms' │ ' 14 ms' │ ' 1.86 x' │
-│ Composite_Union │ 1000000 │ ' 530 ms' │ ' 23 ms' │ ' 13 ms' │ ' 1.77 x' │
-│ Math_Vector4 │ 1000000 │ ' 240 ms' │ ' 22 ms' │ ' 11 ms' │ ' 2.00 x' │
-│ Math_Matrix4 │ 1000000 │ ' 1036 ms' │ ' 39 ms' │ ' 27 ms' │ ' 1.44 x' │
-│ Array_Primitive_Number │ 1000000 │ ' 248 ms' │ ' 20 ms' │ ' 12 ms' │ ' 1.67 x' │
-│ Array_Primitive_String │ 1000000 │ ' 227 ms' │ ' 22 ms' │ ' 13 ms' │ ' 1.69 x' │
-│ Array_Primitive_Boolean │ 1000000 │ ' 138 ms' │ ' 21 ms' │ ' 13 ms' │ ' 1.62 x' │
-│ Array_Object_Unconstrained │ 1000000 │ ' 5540 ms' │ ' 66 ms' │ ' 59 ms' │ ' 1.12 x' │
-│ Array_Object_Constrained │ 1000000 │ ' 5750 ms' │ ' 123 ms' │ ' 108 ms' │ ' 1.14 x' │
-│ Array_Object_Recursive │ 1000000 │ ' 21842 ms' │ ' 1771 ms' │ ' 599 ms' │ ' 2.96 x' │
-│ Array_Tuple_Primitive │ 1000000 │ ' 715 ms' │ ' 36 ms' │ ' 29 ms' │ ' 1.24 x' │
-│ Array_Tuple_Object │ 1000000 │ ' 3131 ms' │ ' 63 ms' │ ' 50 ms' │ ' 1.26 x' │
-│ Array_Composite_Intersect │ 1000000 │ ' 3064 ms' │ ' 44 ms' │ ' 35 ms' │ ' 1.26 x' │
-│ Array_Composite_Union │ 1000000 │ ' 2172 ms' │ ' 65 ms' │ ' 31 ms' │ ' 2.10 x' │
-│ Array_Math_Vector4 │ 1000000 │ ' 1032 ms' │ ' 37 ms' │ ' 24 ms' │ ' 1.54 x' │
-│ Array_Math_Matrix4 │ 1000000 │ ' 4859 ms' │ ' 114 ms' │ ' 86 ms' │ ' 1.33 x' │
+│ Primitive_Null │ 1000000 │ ' 19 ms' │ ' 17 ms' │ ' 9 ms' │ ' 1.89 x' │
+│ Object_Unconstrained │ 1000000 │ ' 1003 ms' │ ' 32 ms' │ ' 24 ms' │ ' 1.33 x' │
+│ Object_Constrained │ 1000000 │ ' 1265 ms' │ ' 49 ms' │ ' 38 ms' │ ' 1.29 x' │
+│ Object_Vector3 │ 1000000 │ ' 418 ms' │ ' 22 ms' │ ' 13 ms' │ ' 1.69 x' │
+│ Object_Box3D │ 1000000 │ ' 2035 ms' │ ' 56 ms' │ ' 49 ms' │ ' 1.14 x' │
+│ Object_Recursive │ 1000000 │ ' 5243 ms' │ ' 326 ms' │ ' 157 ms' │ ' 2.08 x' │
+│ Tuple_Primitive │ 1000000 │ ' 153 ms' │ ' 20 ms' │ ' 12 ms' │ ' 1.67 x' │
+│ Tuple_Object │ 1000000 │ ' 781 ms' │ ' 28 ms' │ ' 18 ms' │ ' 1.56 x' │
+│ Composite_Intersect │ 1000000 │ ' 742 ms' │ ' 25 ms' │ ' 14 ms' │ ' 1.79 x' │
+│ Composite_Union │ 1000000 │ ' 558 ms' │ ' 24 ms' │ ' 13 ms' │ ' 1.85 x' │
+│ Math_Vector4 │ 1000000 │ ' 246 ms' │ ' 22 ms' │ ' 11 ms' │ ' 2.00 x' │
+│ Math_Matrix4 │ 1000000 │ ' 1052 ms' │ ' 43 ms' │ ' 28 ms' │ ' 1.54 x' │
+│ Array_Primitive_Number │ 1000000 │ ' 272 ms' │ ' 22 ms' │ ' 12 ms' │ ' 1.83 x' │
+│ Array_Primitive_String │ 1000000 │ ' 235 ms' │ ' 24 ms' │ ' 14 ms' │ ' 1.71 x' │
+│ Array_Primitive_Boolean │ 1000000 │ ' 134 ms' │ ' 23 ms' │ ' 14 ms' │ ' 1.64 x' │
+│ Array_Object_Unconstrained │ 1000000 │ ' 6280 ms' │ ' 65 ms' │ ' 59 ms' │ ' 1.10 x' │
+│ Array_Object_Constrained │ 1000000 │ ' 6076 ms' │ ' 130 ms' │ ' 119 ms' │ ' 1.09 x' │
+│ Array_Object_Recursive │ 1000000 │ ' 22738 ms' │ ' 1730 ms' │ ' 635 ms' │ ' 2.72 x' │
+│ Array_Tuple_Primitive │ 1000000 │ ' 689 ms' │ ' 35 ms' │ ' 30 ms' │ ' 1.17 x' │
+│ Array_Tuple_Object │ 1000000 │ ' 3266 ms' │ ' 63 ms' │ ' 52 ms' │ ' 1.21 x' │
+│ Array_Composite_Intersect │ 1000000 │ ' 3310 ms' │ ' 44 ms' │ ' 36 ms' │ ' 1.22 x' │
+│ Array_Composite_Union │ 1000000 │ ' 2432 ms' │ ' 69 ms' │ ' 33 ms' │ ' 2.09 x' │
+│ Array_Math_Vector4 │ 1000000 │ ' 1158 ms' │ ' 37 ms' │ ' 24 ms' │ ' 1.54 x' │
+│ Array_Math_Matrix4 │ 1000000 │ ' 5435 ms' │ ' 132 ms' │ ' 92 ms' │ ' 1.43 x' │
└────────────────────────────┴────────────┴──────────────┴──────────────┴──────────────┴──────────────┘
```
@@ -1719,11 +1802,11 @@ The following table lists esbuild compiled and minified sizes for each TypeBox m
┌──────────────────────┬────────────┬────────────┬─────────────┐
│ (index) │ Compiled │ Minified │ Compression │
├──────────────────────┼────────────┼────────────┼─────────────┤
-│ typebox/compiler │ '163.6 kb' │ ' 71.6 kb' │ '2.28 x' │
-│ typebox/errors │ '113.3 kb' │ ' 50.1 kb' │ '2.26 x' │
-│ typebox/system │ ' 83.9 kb' │ ' 37.5 kb' │ '2.24 x' │
-│ typebox/value │ '191.1 kb' │ ' 82.3 kb' │ '2.32 x' │
-│ typebox │ ' 73.8 kb' │ ' 32.3 kb' │ '2.29 x' │
+│ typebox/compiler │ '120.6 kb' │ ' 52.9 kb' │ '2.28 x' │
+│ typebox/errors │ ' 55.7 kb' │ ' 25.5 kb' │ '2.19 x' │
+│ typebox/system │ ' 4.7 kb' │ ' 2.0 kb' │ '2.33 x' │
+│ typebox/value │ '146.2 kb' │ ' 62.0 kb' │ '2.36 x' │
+│ typebox │ ' 91.4 kb' │ ' 37.8 kb' │ '2.42 x' │
└──────────────────────┴────────────┴────────────┴─────────────┘
```
diff --git a/src/compiler/compiler.ts b/src/compiler/compiler.ts
index fe03f6d..7f7368c 100644
--- a/src/compiler/compiler.ts
+++ b/src/compiler/compiler.ts
@@ -26,25 +26,70 @@ THE SOFTWARE.
---------------------------------------------------------------------------*/
-import { EncodeTransform, DecodeTransform, HasTransform, TransformDecodeCheckError, TransformEncodeCheckError } from '../value/transform'
-import { IsArray, IsString, IsNumber, IsBigInt } from '../value/guard'
-import { Errors, ValueErrorIterator } from '../errors/errors'
+import { TransformEncode, TransformDecode, HasTransform, TransformDecodeCheckError, TransformEncodeCheckError } from '../value/transform/index'
+import { Errors, ValueErrorIterator } from '../errors/index'
import { TypeSystemPolicy } from '../system/index'
-import { Deref } from '../value/deref'
-import { Hash } from '../value/hash'
-import * as Types from '../typebox'
+import { TypeBoxError } from '../type/error/index'
+import { Deref } from '../value/deref/index'
+import { Hash } from '../value/hash/index'
+import { Kind } from '../type/symbols/index'
-// -------------------------------------------------------------------
+import { TypeRegistry, FormatRegistry } from '../type/registry/index'
+import { KeyOfPattern } from '../type/keyof/index'
+import { ExtendsUndefinedCheck } from '../type/extends/extends-undefined'
+
+import type { TSchema } from '../type/schema/index'
+import type { TAsyncIterator } from '../type/async-iterator/index'
+import type { TAny } from '../type/any/index'
+import type { TArray } from '../type/array/index'
+import type { TBigInt } from '../type/bigint/index'
+import type { TBoolean } from '../type/boolean/index'
+import type { TDate } from '../type/date/index'
+import type { TConstructor } from '../type/constructor/index'
+import type { TFunction } from '../type/function/index'
+import type { TInteger } from '../type/integer/index'
+import type { TIntersect } from '../type/intersect/index'
+import type { TIterator } from '../type/iterator/index'
+import type { TLiteral } from '../type/literal/index'
+import { Never, type TNever } from '../type/never/index'
+import type { TNot } from '../type/not/index'
+import type { TNull } from '../type/null/index'
+import type { TNumber } from '../type/number/index'
+import type { TObject } from '../type/object/index'
+import type { TPromise } from '../type/promise/index'
+import type { TRecord } from '../type/record/index'
+import type { TRef } from '../type/ref/index'
+import type { TRegExp } from '../type/regexp/index'
+import type { TTemplateLiteral } from '../type/template-literal/index'
+import type { TThis } from '../type/recursive/index'
+import type { TTuple } from '../type/tuple/index'
+import type { TUnion } from '../type/union/index'
+import type { TUnknown } from '../type/unknown/index'
+import type { Static, StaticDecode, StaticEncode } from '../type/static/index'
+import type { TString } from '../type/string/index'
+import type { TSymbol } from '../type/symbol/index'
+import type { TUndefined } from '../type/undefined/index'
+import type { TUint8Array } from '../type/uint8array/index'
+import type { TVoid } from '../type/void/index'
+// ------------------------------------------------------------------
+// ValueGuard
+// ------------------------------------------------------------------
+import { IsArray, IsString, IsNumber, IsBigInt } from '../value/guard/index'
+// ------------------------------------------------------------------
+// TypeGuard
+// ------------------------------------------------------------------
+import { IsSchema } from '../type/guard/type'
+// ------------------------------------------------------------------
// CheckFunction
-// -------------------------------------------------------------------
+// ------------------------------------------------------------------
export type CheckFunction = (value: unknown) => boolean
-// -------------------------------------------------------------------
+// ------------------------------------------------------------------
// TypeCheck
-// -------------------------------------------------------------------
-export class TypeCheck {
+// ------------------------------------------------------------------
+export class TypeCheck {
private readonly hasTransform: boolean
- constructor(private readonly schema: T, private readonly references: Types.TSchema[], private readonly checkFunc: CheckFunction, private readonly code: string) {
- this.hasTransform = HasTransform.Has(schema, references)
+ constructor(private readonly schema: T, private readonly references: TSchema[], private readonly checkFunc: CheckFunction, private readonly code: string) {
+ this.hasTransform = HasTransform(schema, references)
}
/** Returns the generated assertion code used to validate this type. */
public Code(): string {
@@ -55,24 +100,24 @@ export class TypeCheck {
return Errors(this.schema, this.references, value)
}
/** Returns true if the value matches the compiled type. */
- public Check(value: unknown): value is Types.Static {
+ public Check(value: unknown): value is Static {
return this.checkFunc(value)
}
/** Decodes a value or throws if error */
- public Decode(value: unknown): Types.StaticDecode {
+ public Decode(value: unknown): StaticDecode {
if (!this.checkFunc(value)) throw new TransformDecodeCheckError(this.schema, value, this.Errors(value).First()!)
- return this.hasTransform ? DecodeTransform.Decode(this.schema, this.references, value) : value
+ return this.hasTransform ? TransformDecode(this.schema, this.references, value) : value
}
/** Encodes a value or throws if error */
- public Encode(value: unknown): Types.StaticEncode {
- const encoded = this.hasTransform ? EncodeTransform.Encode(this.schema, this.references, value) : value
+ public Encode(value: unknown): StaticEncode {
+ const encoded = this.hasTransform ? TransformEncode(this.schema, this.references, value) : value
if (!this.checkFunc(encoded)) throw new TransformEncodeCheckError(this.schema, value, this.Errors(value).First()!)
return encoded
}
}
-// -------------------------------------------------------------------
+// ------------------------------------------------------------------
// Character
-// -------------------------------------------------------------------
+// ------------------------------------------------------------------
namespace Character {
export function DollarSign(code: number) {
return code === 36
@@ -87,9 +132,9 @@ namespace Character {
return code >= 48 && code <= 57
}
}
-// -------------------------------------------------------------------
+// ------------------------------------------------------------------
// MemberExpression
-// -------------------------------------------------------------------
+// ------------------------------------------------------------------
namespace MemberExpression {
function IsFirstCharacterNumeric(value: string) {
if (value.length === 0) return false
@@ -111,9 +156,9 @@ namespace MemberExpression {
return IsAccessor(key) ? `${object}.${key}` : `${object}['${EscapeHyphen(key)}']`
}
}
-// -------------------------------------------------------------------
+// ------------------------------------------------------------------
// Identifier
-// -------------------------------------------------------------------
+// ------------------------------------------------------------------
namespace Identifier {
export function Encode($id: string) {
const buffer: string[] = []
@@ -128,30 +173,30 @@ namespace Identifier {
return buffer.join('').replace(/__/g, '_')
}
}
-// -------------------------------------------------------------------
+// ------------------------------------------------------------------
// LiteralString
-// -------------------------------------------------------------------
+// ------------------------------------------------------------------
namespace LiteralString {
export function Escape(content: string) {
return content.replace(/'/g, "\\'")
}
}
-// -------------------------------------------------------------------
+// ------------------------------------------------------------------
// Errors
-// -------------------------------------------------------------------
-export class TypeCompilerUnknownTypeError extends Types.TypeBoxError {
- constructor(public readonly schema: Types.TSchema) {
+// ------------------------------------------------------------------
+export class TypeCompilerUnknownTypeError extends TypeBoxError {
+ constructor(public readonly schema: TSchema) {
super('Unknown type')
}
}
-export class TypeCompilerTypeGuardError extends Types.TypeBoxError {
- constructor(public readonly schema: Types.TSchema) {
+export class TypeCompilerTypeGuardError extends TypeBoxError {
+ constructor(public readonly schema: TSchema) {
super('Preflight validation check failed to guard for the given schema')
}
}
-// -------------------------------------------------------------------
+// ------------------------------------------------------------------
// Policy
-// -------------------------------------------------------------------
+// ------------------------------------------------------------------
export namespace Policy {
export function IsExactOptionalProperty(value: string, key: string, expression: string) {
return TypeSystemPolicy.ExactOptionalPropertyTypes ? `('${key}' in ${value} ? ${expression} : true)` : `(${MemberExpression.Encode(value, key)} !== undefined ? ${expression} : true)`
@@ -171,36 +216,36 @@ export namespace Policy {
return TypeSystemPolicy.AllowNullVoid ? `(${value} === undefined || ${value} === null)` : `${value} === undefined`
}
}
-// -------------------------------------------------------------------
+// ------------------------------------------------------------------
// TypeCompiler
-// -------------------------------------------------------------------
+// ------------------------------------------------------------------
export type TypeCompilerLanguageOption = 'typescript' | 'javascript'
export interface TypeCompilerCodegenOptions {
language?: TypeCompilerLanguageOption
}
/** Compiles Types for Runtime Type Checking */
export namespace TypeCompiler {
- // ----------------------------------------------------------------------
+ // ----------------------------------------------------------------
// Guards
- // ----------------------------------------------------------------------
- function IsAnyOrUnknown(schema: Types.TSchema) {
- return schema[Types.Kind] === 'Any' || schema[Types.Kind] === 'Unknown'
+ // ----------------------------------------------------------------
+ function IsAnyOrUnknown(schema: TSchema) {
+ return schema[Kind] === 'Any' || schema[Kind] === 'Unknown'
}
- // -------------------------------------------------------------------
+ // ----------------------------------------------------------------
// Types
- // -------------------------------------------------------------------
- function* TAny(schema: Types.TAny, references: Types.TSchema[], value: string): IterableIterator {
+ // ----------------------------------------------------------------
+ function* FromAny(schema: TAny, references: TSchema[], value: string): IterableIterator {
yield 'true'
}
- function* TArray(schema: Types.TArray, references: Types.TSchema[], value: string): IterableIterator {
+ function* FromArray(schema: TArray, references: TSchema[], value: string): IterableIterator {
yield `Array.isArray(${value})`
const [parameter, accumulator] = [CreateParameter('value', 'any'), CreateParameter('acc', 'number')]
if (IsNumber(schema.maxItems)) yield `${value}.length <= ${schema.maxItems}`
if (IsNumber(schema.minItems)) yield `${value}.length >= ${schema.minItems}`
const elementExpression = CreateExpression(schema.items, references, 'value')
yield `${value}.every((${parameter}) => ${elementExpression})`
- if (Types.TypeGuard.TSchema(schema.contains) || IsNumber(schema.minContains) || IsNumber(schema.maxContains)) {
- const containsSchema = Types.TypeGuard.TSchema(schema.contains) ? schema.contains : Types.Type.Never()
+ if (IsSchema(schema.contains) || IsNumber(schema.minContains) || IsNumber(schema.maxContains)) {
+ const containsSchema = IsSchema(schema.contains) ? schema.contains : Never()
const checkExpression = CreateExpression(containsSchema, references, 'value')
const checkMinContains = IsNumber(schema.minContains) ? [`(count >= ${schema.minContains})`] : []
const checkMaxContains = IsNumber(schema.maxContains) ? [`(count <= ${schema.maxContains})`] : []
@@ -214,10 +259,10 @@ export namespace TypeCompiler {
yield `((${parameter}) => { ${block} )(${value})`
}
}
- function* TAsyncIterator(schema: Types.TAsyncIterator, references: Types.TSchema[], value: string): IterableIterator {
+ function* FromAsyncIterator(schema: TAsyncIterator, references: TSchema[], value: string): IterableIterator {
yield `(typeof value === 'object' && Symbol.asyncIterator in ${value})`
}
- function* TBigInt(schema: Types.TBigInt, references: Types.TSchema[], value: string): IterableIterator {
+ function* FromBigInt(schema: TBigInt, references: TSchema[], value: string): IterableIterator {
yield `(typeof ${value} === 'bigint')`
if (IsBigInt(schema.exclusiveMaximum)) yield `${value} < BigInt(${schema.exclusiveMaximum})`
if (IsBigInt(schema.exclusiveMinimum)) yield `${value} > BigInt(${schema.exclusiveMinimum})`
@@ -225,13 +270,13 @@ export namespace TypeCompiler {
if (IsBigInt(schema.minimum)) yield `${value} >= BigInt(${schema.minimum})`
if (IsBigInt(schema.multipleOf)) yield `(${value} % BigInt(${schema.multipleOf})) === 0`
}
- function* TBoolean(schema: Types.TBoolean, references: Types.TSchema[], value: string): IterableIterator {
+ function* FromBoolean(schema: TBoolean, references: TSchema[], value: string): IterableIterator {
yield `(typeof ${value} === 'boolean')`
}
- function* TConstructor(schema: Types.TConstructor, references: Types.TSchema[], value: string): IterableIterator {
+ function* FromConstructor(schema: TConstructor, references: TSchema[], value: string): IterableIterator {
yield* Visit(schema.returns, references, `${value}.prototype`)
}
- function* TDate(schema: Types.TDate, references: Types.TSchema[], value: string): IterableIterator {
+ function* FromDate(schema: TDate, references: TSchema[], value: string): IterableIterator {
yield `(${value} instanceof Date) && Number.isFinite(${value}.getTime())`
if (IsNumber(schema.exclusiveMaximumTimestamp)) yield `${value}.getTime() < ${schema.exclusiveMaximumTimestamp}`
if (IsNumber(schema.exclusiveMinimumTimestamp)) yield `${value}.getTime() > ${schema.exclusiveMinimumTimestamp}`
@@ -239,10 +284,10 @@ export namespace TypeCompiler {
if (IsNumber(schema.minimumTimestamp)) yield `${value}.getTime() >= ${schema.minimumTimestamp}`
if (IsNumber(schema.multipleOfTimestamp)) yield `(${value}.getTime() % ${schema.multipleOfTimestamp}) === 0`
}
- function* TFunction(schema: Types.TFunction, references: Types.TSchema[], value: string): IterableIterator {
+ function* FromFunction(schema: TFunction, references: TSchema[], value: string): IterableIterator {
yield `(typeof ${value} === 'function')`
}
- function* TInteger(schema: Types.TInteger, references: Types.TSchema[], value: string): IterableIterator {
+ function* FromInteger(schema: TInteger, references: TSchema[], value: string): IterableIterator {
yield `(typeof ${value} === 'number' && Number.isInteger(${value}))`
if (IsNumber(schema.exclusiveMaximum)) yield `${value} < ${schema.exclusiveMaximum}`
if (IsNumber(schema.exclusiveMinimum)) yield `${value} > ${schema.exclusiveMinimum}`
@@ -250,41 +295,41 @@ export namespace TypeCompiler {
if (IsNumber(schema.minimum)) yield `${value} >= ${schema.minimum}`
if (IsNumber(schema.multipleOf)) yield `(${value} % ${schema.multipleOf}) === 0`
}
- function* TIntersect(schema: Types.TIntersect, references: Types.TSchema[], value: string): IterableIterator {
- const check1 = schema.allOf.map((schema: Types.TSchema) => CreateExpression(schema, references, value)).join(' && ')
+ function* FromIntersect(schema: TIntersect, references: TSchema[], value: string): IterableIterator {
+ const check1 = schema.allOf.map((schema: TSchema) => CreateExpression(schema, references, value)).join(' && ')
if (schema.unevaluatedProperties === false) {
- const keyCheck = CreateVariable(`${new RegExp(Types.KeyResolver.ResolvePattern(schema))};`)
+ const keyCheck = CreateVariable(`${new RegExp(KeyOfPattern(schema))};`)
const check2 = `Object.getOwnPropertyNames(${value}).every(key => ${keyCheck}.test(key))`
yield `(${check1} && ${check2})`
- } else if (Types.TypeGuard.TSchema(schema.unevaluatedProperties)) {
- const keyCheck = CreateVariable(`${new RegExp(Types.KeyResolver.ResolvePattern(schema))};`)
+ } else if (IsSchema(schema.unevaluatedProperties)) {
+ const keyCheck = CreateVariable(`${new RegExp(KeyOfPattern(schema))};`)
const check2 = `Object.getOwnPropertyNames(${value}).every(key => ${keyCheck}.test(key) || ${CreateExpression(schema.unevaluatedProperties, references, `${value}[key]`)})`
yield `(${check1} && ${check2})`
} else {
yield `(${check1})`
}
}
- function* TIterator(schema: Types.TIterator, references: Types.TSchema[], value: string): IterableIterator {
+ function* FromIterator(schema: TIterator, references: TSchema[], value: string): IterableIterator {
yield `(typeof value === 'object' && Symbol.iterator in ${value})`
}
- function* TLiteral(schema: Types.TLiteral, references: Types.TSchema[], value: string): IterableIterator {
+ function* FromLiteral(schema: TLiteral, references: TSchema[], value: string): IterableIterator {
if (typeof schema.const === 'number' || typeof schema.const === 'boolean') {
yield `(${value} === ${schema.const})`
} else {
yield `(${value} === '${LiteralString.Escape(schema.const)}')`
}
}
- function* TNever(schema: Types.TNever, references: Types.TSchema[], value: string): IterableIterator {
+ function* FromNever(schema: TNever, references: TSchema[], value: string): IterableIterator {
yield `false`
}
- function* TNot(schema: Types.TNot, references: Types.TSchema[], value: string): IterableIterator {
+ function* FromNot(schema: TNot, references: TSchema[], value: string): IterableIterator {
const expression = CreateExpression(schema.not, references, value)
yield `(!${expression})`
}
- function* TNull(schema: Types.TNull, references: Types.TSchema[], value: string): IterableIterator {
+ function* FromNull(schema: TNull, references: TSchema[], value: string): IterableIterator {
yield `(${value} === null)`
}
- function* TNumber(schema: Types.TNumber, references: Types.TSchema[], value: string): IterableIterator {
+ function* FromNumber(schema: TNumber, references: TSchema[], value: string): IterableIterator {
yield Policy.IsNumberLike(value)
if (IsNumber(schema.exclusiveMaximum)) yield `${value} < ${schema.exclusiveMaximum}`
if (IsNumber(schema.exclusiveMinimum)) yield `${value} > ${schema.exclusiveMinimum}`
@@ -292,7 +337,7 @@ export namespace TypeCompiler {
if (IsNumber(schema.minimum)) yield `${value} >= ${schema.minimum}`
if (IsNumber(schema.multipleOf)) yield `(${value} % ${schema.multipleOf}) === 0`
}
- function* TObject(schema: Types.TObject, references: Types.TSchema[], value: string): IterableIterator {
+ function* FromObject(schema: TObject, references: TSchema[], value: string): IterableIterator {
yield Policy.IsObjectLike(value)
if (IsNumber(schema.minProperties)) yield `Object.getOwnPropertyNames(${value}).length >= ${schema.minProperties}`
if (IsNumber(schema.maxProperties)) yield `Object.getOwnPropertyNames(${value}).length <= ${schema.maxProperties}`
@@ -302,7 +347,7 @@ export namespace TypeCompiler {
const property = schema.properties[knownKey]
if (schema.required && schema.required.includes(knownKey)) {
yield* Visit(property, references, memberExpression)
- if (Types.ExtendsUndefined.Check(property) || IsAnyOrUnknown(property)) yield `('${knownKey}' in ${value})`
+ if (ExtendsUndefinedCheck(property) || IsAnyOrUnknown(property)) yield `('${knownKey}' in ${value})`
} else {
const expression = CreateExpression(property, references, memberExpression)
yield Policy.IsExactOptionalProperty(value, knownKey, expression)
@@ -322,28 +367,33 @@ export namespace TypeCompiler {
yield `(Object.getOwnPropertyNames(${value}).every(key => ${keys}.includes(key) || ${expression}))`
}
}
- function* TPromise(schema: Types.TPromise, references: Types.TSchema[], value: string): IterableIterator {
+ function* FromPromise(schema: TPromise, references: TSchema[], value: string): IterableIterator {
yield `(typeof value === 'object' && typeof ${value}.then === 'function')`
}
- function* TRecord(schema: Types.TRecord, references: Types.TSchema[], value: string): IterableIterator {
+ function* FromRecord(schema: TRecord, references: TSchema[], value: string): IterableIterator {
yield Policy.IsRecordLike(value)
if (IsNumber(schema.minProperties)) yield `Object.getOwnPropertyNames(${value}).length >= ${schema.minProperties}`
if (IsNumber(schema.maxProperties)) yield `Object.getOwnPropertyNames(${value}).length <= ${schema.maxProperties}`
const [patternKey, patternSchema] = Object.entries(schema.patternProperties)[0]
const variable = CreateVariable(`${new RegExp(patternKey)}`)
const check1 = CreateExpression(patternSchema, references, 'value')
- const check2 = Types.TypeGuard.TSchema(schema.additionalProperties) ? CreateExpression(schema.additionalProperties, references, value) : schema.additionalProperties === false ? 'false' : 'true'
+ const check2 = IsSchema(schema.additionalProperties) ? CreateExpression(schema.additionalProperties, references, value) : schema.additionalProperties === false ? 'false' : 'true'
const expression = `(${variable}.test(key) ? ${check1} : ${check2})`
yield `(Object.entries(${value}).every(([key, value]) => ${expression}))`
}
- function* TRef(schema: Types.TRef, references: Types.TSchema[], value: string): IterableIterator {
+ function* FromRef(schema: TRef, references: TSchema[], value: string): IterableIterator {
const target = Deref(schema, references)
// Reference: If we have seen this reference before we can just yield and return the function call.
// If this isn't the case we defer to visit to generate and set the function for subsequent passes.
if (state.functions.has(schema.$ref)) return yield `${CreateFunctionName(schema.$ref)}(${value})`
yield* Visit(target, references, value)
}
- function* TString(schema: Types.TString, references: Types.TSchema[], value: string): IterableIterator {
+ function* FromRegExp(schema: TRegExp, references: TSchema[], value: string): IterableIterator {
+ const variable = CreateVariable(`${new RegExp(schema.source, schema.flags)};`)
+ yield `(typeof ${value} === 'string')`
+ yield `${variable}.test(${value})`
+ }
+ function* FromString(schema: TString, references: TSchema[], value: string): IterableIterator {
yield `(typeof ${value} === 'string')`
if (IsNumber(schema.maxLength)) yield `${value}.length <= ${schema.maxLength}`
if (IsNumber(schema.minLength)) yield `${value}.length >= ${schema.minLength}`
@@ -355,19 +405,19 @@ export namespace TypeCompiler {
yield `format('${schema.format}', ${value})`
}
}
- function* TSymbol(schema: Types.TSymbol, references: Types.TSchema[], value: string): IterableIterator {
+ function* FromSymbol(schema: TSymbol, references: TSchema[], value: string): IterableIterator {
yield `(typeof ${value} === 'symbol')`
}
- function* TTemplateLiteral(schema: Types.TTemplateLiteral, references: Types.TSchema[], value: string): IterableIterator {
+ function* FromTemplateLiteral(schema: TTemplateLiteral, references: TSchema[], value: string): IterableIterator {
yield `(typeof ${value} === 'string')`
const variable = CreateVariable(`${new RegExp(schema.pattern)};`)
yield `${variable}.test(${value})`
}
- function* TThis(schema: Types.TThis, references: Types.TSchema[], value: string): IterableIterator {
+ function* FromThis(schema: TThis, references: TSchema[], value: string): IterableIterator {
// Note: This types are assured to be hoisted prior to this call. Just yield the function.
yield `${CreateFunctionName(schema.$ref)}(${value})`
}
- function* TTuple(schema: Types.TTuple, references: Types.TSchema[], value: string): IterableIterator {
+ function* FromTuple(schema: TTuple, references: TSchema[], value: string): IterableIterator {
yield `Array.isArray(${value})`
if (schema.items === undefined) return yield `${value}.length === 0`
yield `(${value}.length === ${schema.maxItems})`
@@ -376,35 +426,35 @@ export namespace TypeCompiler {
yield `${expression}`
}
}
- function* TUndefined(schema: Types.TUndefined, references: Types.TSchema[], value: string): IterableIterator {
+ function* FromUndefined(schema: TUndefined, references: TSchema[], value: string): IterableIterator {
yield `${value} === undefined`
}
- function* TUnion(schema: Types.TUnion, references: Types.TSchema[], value: string): IterableIterator {
- const expressions = schema.anyOf.map((schema: Types.TSchema) => CreateExpression(schema, references, value))
+ function* FromUnion(schema: TUnion, references: TSchema[], value: string): IterableIterator {
+ const expressions = schema.anyOf.map((schema: TSchema) => CreateExpression(schema, references, value))
yield `(${expressions.join(' || ')})`
}
- function* TUint8Array(schema: Types.TUint8Array, references: Types.TSchema[], value: string): IterableIterator {
+ function* FromUint8Array(schema: TUint8Array, references: TSchema[], value: string): IterableIterator {
yield `${value} instanceof Uint8Array`
if (IsNumber(schema.maxByteLength)) yield `(${value}.length <= ${schema.maxByteLength})`
if (IsNumber(schema.minByteLength)) yield `(${value}.length >= ${schema.minByteLength})`
}
- function* TUnknown(schema: Types.TUnknown, references: Types.TSchema[], value: string): IterableIterator {
+ function* FromUnknown(schema: TUnknown, references: TSchema[], value: string): IterableIterator {
yield 'true'
}
- function* TVoid(schema: Types.TVoid, references: Types.TSchema[], value: string): IterableIterator {
+ function* FromVoid(schema: TVoid, references: TSchema[], value: string): IterableIterator {
yield Policy.IsVoidLike(value)
}
- function* TKind(schema: Types.TSchema, references: Types.TSchema[], value: string): IterableIterator {
+ function* FromKind(schema: TSchema, references: TSchema[], value: string): IterableIterator {
const instance = state.instances.size
state.instances.set(instance, schema)
- yield `kind('${schema[Types.Kind]}', ${instance}, ${value})`
+ yield `kind('${schema[Kind]}', ${instance}, ${value})`
}
- function* Visit(schema: T, references: Types.TSchema[], value: string, useHoisting: boolean = true): IterableIterator {
+ function* Visit(schema: TSchema, references: TSchema[], value: string, useHoisting: boolean = true): IterableIterator {
const references_ = IsString(schema.$id) ? [...references, schema] : references
const schema_ = schema as any
- // ----------------------------------------------------------------------------------
+ // --------------------------------------------------------------
// Hoisting
- // ----------------------------------------------------------------------------------
+ // --------------------------------------------------------------
if (useHoisting && IsString(schema.$id)) {
const functionName = CreateFunctionName(schema.$id)
if (state.functions.has(functionName)) {
@@ -415,86 +465,88 @@ export namespace TypeCompiler {
return yield `${functionName}(${value})`
}
}
- switch (schema_[Types.Kind]) {
+ switch (schema_[Kind]) {
case 'Any':
- return yield* TAny(schema_, references_, value)
+ return yield* FromAny(schema_, references_, value)
case 'Array':
- return yield* TArray(schema_, references_, value)
+ return yield* FromArray(schema_, references_, value)
case 'AsyncIterator':
- return yield* TAsyncIterator(schema_, references_, value)
+ return yield* FromAsyncIterator(schema_, references_, value)
case 'BigInt':
- return yield* TBigInt(schema_, references_, value)
+ return yield* FromBigInt(schema_, references_, value)
case 'Boolean':
- return yield* TBoolean(schema_, references_, value)
+ return yield* FromBoolean(schema_, references_, value)
case 'Constructor':
- return yield* TConstructor(schema_, references_, value)
+ return yield* FromConstructor(schema_, references_, value)
case 'Date':
- return yield* TDate(schema_, references_, value)
+ return yield* FromDate(schema_, references_, value)
case 'Function':
- return yield* TFunction(schema_, references_, value)
+ return yield* FromFunction(schema_, references_, value)
case 'Integer':
- return yield* TInteger(schema_, references_, value)
+ return yield* FromInteger(schema_, references_, value)
case 'Intersect':
- return yield* TIntersect(schema_, references_, value)
+ return yield* FromIntersect(schema_, references_, value)
case 'Iterator':
- return yield* TIterator(schema_, references_, value)
+ return yield* FromIterator(schema_, references_, value)
case 'Literal':
- return yield* TLiteral(schema_, references_, value)
+ return yield* FromLiteral(schema_, references_, value)
case 'Never':
- return yield* TNever(schema_, references_, value)
+ return yield* FromNever(schema_, references_, value)
case 'Not':
- return yield* TNot(schema_, references_, value)
+ return yield* FromNot(schema_, references_, value)
case 'Null':
- return yield* TNull(schema_, references_, value)
+ return yield* FromNull(schema_, references_, value)
case 'Number':
- return yield* TNumber(schema_, references_, value)
+ return yield* FromNumber(schema_, references_, value)
case 'Object':
- return yield* TObject(schema_, references_, value)
+ return yield* FromObject(schema_, references_, value)
case 'Promise':
- return yield* TPromise(schema_, references_, value)
+ return yield* FromPromise(schema_, references_, value)
case 'Record':
- return yield* TRecord(schema_, references_, value)
+ return yield* FromRecord(schema_, references_, value)
case 'Ref':
- return yield* TRef(schema_, references_, value)
+ return yield* FromRef(schema_, references_, value)
+ case 'RegExp':
+ return yield* FromRegExp(schema_, references_, value)
case 'String':
- return yield* TString(schema_, references_, value)
+ return yield* FromString(schema_, references_, value)
case 'Symbol':
- return yield* TSymbol(schema_, references_, value)
+ return yield* FromSymbol(schema_, references_, value)
case 'TemplateLiteral':
- return yield* TTemplateLiteral(schema_, references_, value)
+ return yield* FromTemplateLiteral(schema_, references_, value)
case 'This':
- return yield* TThis(schema_, references_, value)
+ return yield* FromThis(schema_, references_, value)
case 'Tuple':
- return yield* TTuple(schema_, references_, value)
+ return yield* FromTuple(schema_, references_, value)
case 'Undefined':
- return yield* TUndefined(schema_, references_, value)
+ return yield* FromUndefined(schema_, references_, value)
case 'Union':
- return yield* TUnion(schema_, references_, value)
+ return yield* FromUnion(schema_, references_, value)
case 'Uint8Array':
- return yield* TUint8Array(schema_, references_, value)
+ return yield* FromUint8Array(schema_, references_, value)
case 'Unknown':
- return yield* TUnknown(schema_, references_, value)
+ return yield* FromUnknown(schema_, references_, value)
case 'Void':
- return yield* TVoid(schema_, references_, value)
+ return yield* FromVoid(schema_, references_, value)
default:
- if (!Types.TypeRegistry.Has(schema_[Types.Kind])) throw new TypeCompilerUnknownTypeError(schema)
- return yield* TKind(schema_, references_, value)
+ if (!TypeRegistry.Has(schema_[Kind])) throw new TypeCompilerUnknownTypeError(schema)
+ return yield* FromKind(schema_, references_, value)
}
}
- // -------------------------------------------------------------------
+ // ----------------------------------------------------------------
// Compiler State
- // -------------------------------------------------------------------
+ // ----------------------------------------------------------------
// prettier-ignore
const state = {
- language: 'javascript', // target language
- functions: new Map(), // local functions
- variables: new Map(), // local variables
- instances: new Map() // exterior kind instances
+ language: 'javascript', // target language
+ functions: new Map(), // local functions
+ variables: new Map(), // local variables
+ instances: new Map() // exterior kind instances
}
- // -------------------------------------------------------------------
+ // ----------------------------------------------------------------
// Compiler Factory
- // -------------------------------------------------------------------
- function CreateExpression(schema: Types.TSchema, references: Types.TSchema[], value: string, useHoisting: boolean = true): string {
+ // ----------------------------------------------------------------
+ function CreateExpression(schema: TSchema, references: TSchema[], value: string, useHoisting: boolean = true): string {
return `(${[...Visit(schema, references, value, useHoisting)].join(' && ')})`
}
function CreateFunctionName($id: string) {
@@ -505,7 +557,7 @@ export namespace TypeCompiler {
state.variables.set(variableName, `const ${variableName} = ${expression}`)
return variableName
}
- function CreateFunction(name: string, schema: Types.TSchema, references: Types.TSchema[], value: string, useHoisting: boolean = true): string {
+ function CreateFunction(name: string, schema: TSchema, references: TSchema[], value: string, useHoisting: boolean = true): string {
const [newline, pad] = ['\n', (length: number) => ''.padStart(length, ' ')]
const parameter = CreateParameter('value', 'any')
const returns = CreateReturns('boolean')
@@ -519,10 +571,10 @@ export namespace TypeCompiler {
function CreateReturns(type: string) {
return state.language === 'typescript' ? `: ${type}` : ''
}
- // -------------------------------------------------------------------
+ // ----------------------------------------------------------------
// Compile
- // -------------------------------------------------------------------
- function Build(schema: T, references: Types.TSchema[], options: TypeCompilerCodegenOptions): string {
+ // ----------------------------------------------------------------
+ function Build(schema: T, references: TSchema[], options: TypeCompilerCodegenOptions): string {
const functionCode = CreateFunction('check', schema, references, 'value') // will populate functions and variables
const parameter = CreateParameter('value', 'any')
const returns = CreateReturns('boolean')
@@ -535,9 +587,9 @@ export namespace TypeCompiler {
return [...variables, ...functions, checkFunction].join('\n')
}
/** Generates the code used to assert this type and returns it as a string */
- export function Code(schema: T, references: Types.TSchema[], options?: TypeCompilerCodegenOptions): string
+ export function Code(schema: T, references: TSchema[], options?: TypeCompilerCodegenOptions): string
/** Generates the code used to assert this type and returns it as a string */
- export function Code(schema: T, options?: TypeCompilerCodegenOptions): string
+ export function Code(schema: T, options?: TypeCompilerCodegenOptions): string
/** Generates the code used to assert this type and returns it as a string */
export function Code(...args: any[]) {
const defaults = { language: 'javascript' }
@@ -554,24 +606,24 @@ export namespace TypeCompiler {
state.variables.clear()
state.functions.clear()
state.instances.clear()
- if (!Types.TypeGuard.TSchema(schema)) throw new TypeCompilerTypeGuardError(schema)
- for (const schema of references) if (!Types.TypeGuard.TSchema(schema)) throw new TypeCompilerTypeGuardError(schema)
+ if (!IsSchema(schema)) throw new TypeCompilerTypeGuardError(schema)
+ for (const schema of references) if (!IsSchema(schema)) throw new TypeCompilerTypeGuardError(schema)
return Build(schema, references, options)
}
/** Compiles a TypeBox type for optimal runtime type checking. Types must be valid TypeBox types of TSchema */
- export function Compile(schema: T, references: Types.TSchema[] = []): TypeCheck {
+ export function Compile(schema: T, references: TSchema[] = []): TypeCheck {
const generatedCode = Code(schema, references, { language: 'javascript' })
const compiledFunction = globalThis.Function('kind', 'format', 'hash', generatedCode)
const instances = new Map(state.instances)
function typeRegistryFunction(kind: string, instance: number, value: unknown) {
- if (!Types.TypeRegistry.Has(kind) || !instances.has(instance)) return false
- const checkFunc = Types.TypeRegistry.Get(kind)!
+ if (!TypeRegistry.Has(kind) || !instances.has(instance)) return false
+ const checkFunc = TypeRegistry.Get(kind)!
const schema = instances.get(instance)!
return checkFunc(schema, value)
}
function formatRegistryFunction(format: string, value: string) {
- if (!Types.FormatRegistry.Has(format)) return false
- const checkFunc = Types.FormatRegistry.Get(format)!
+ if (!FormatRegistry.Has(format)) return false
+ const checkFunc = FormatRegistry.Get(format)!
return checkFunc(value)
}
function hashFunction(value: unknown) {
diff --git a/src/compiler/index.ts b/src/compiler/index.ts
index cc91cb4..48b4c10 100644
--- a/src/compiler/index.ts
+++ b/src/compiler/index.ts
@@ -27,4 +27,4 @@ THE SOFTWARE.
---------------------------------------------------------------------------*/
export { ValueError, ValueErrorType, ValueErrorIterator } from '../errors/index'
-export * from './compiler'
+export { TypeCompiler, TypeCheck, type TypeCompilerCodegenOptions, type TypeCompilerLanguageOption, TypeCompilerTypeGuardError, TypeCompilerUnknownTypeError } from './compiler'
diff --git a/src/errors/errors.ts b/src/errors/errors.ts
index 9f09e1f..c84ebab 100644
--- a/src/errors/errors.ts
+++ b/src/errors/errors.ts
@@ -26,15 +26,72 @@ THE SOFTWARE.
---------------------------------------------------------------------------*/
-import { IsArray, IsUint8Array, IsDate, IsPromise, IsFunction, IsAsyncIterator, IsIterator, IsBoolean, IsNumber, IsBigInt, IsString, IsSymbol, IsInteger, IsNull, IsUndefined } from '../value/guard'
-import { TypeSystemPolicy, TypeSystemErrorFunction } from '../system/system'
-import { Deref } from '../value/deref'
-import { Hash } from '../value/hash'
-import * as Types from '../typebox'
+import { TypeSystemPolicy } from '../system/index'
+import { KeyOfPattern } from '../type/keyof/index'
+import { TypeRegistry, FormatRegistry } from '../type/registry/index'
+import { ExtendsUndefinedCheck } from '../type/extends/extends-undefined'
+import { GetErrorFunction } from './function'
+import { TypeBoxError } from '../type/error/index'
+import { Deref } from '../value/deref/index'
+import { Hash } from '../value/hash/index'
+import { Kind } from '../type/symbols/index'
-// --------------------------------------------------------------------------
+import type { TSchema } from '../type/schema/index'
+import type { TAsyncIterator } from '../type/async-iterator/index'
+import type { TAny } from '../type/any/index'
+import type { TArray } from '../type/array/index'
+import type { TBigInt } from '../type/bigint/index'
+import type { TBoolean } from '../type/boolean/index'
+import type { TDate } from '../type/date/index'
+import type { TConstructor } from '../type/constructor/index'
+import type { TFunction } from '../type/function/index'
+import type { TInteger } from '../type/integer/index'
+import type { TIntersect } from '../type/intersect/index'
+import type { TIterator } from '../type/iterator/index'
+import type { TLiteral } from '../type/literal/index'
+import { Never, type TNever } from '../type/never/index'
+import type { TNot } from '../type/not/index'
+import type { TNull } from '../type/null/index'
+import type { TNumber } from '../type/number/index'
+import type { TObject } from '../type/object/index'
+import type { TPromise } from '../type/promise/index'
+import type { TRecord } from '../type/record/index'
+import type { TRef } from '../type/ref/index'
+import type { TRegExp } from '../type/regexp/index'
+import type { TTemplateLiteral } from '../type/template-literal/index'
+import type { TThis } from '../type/recursive/index'
+import type { TTuple } from '../type/tuple/index'
+import type { TUnion } from '../type/union/index'
+import type { TUnknown } from '../type/unknown/index'
+import type { TString } from '../type/string/index'
+import type { TSymbol } from '../type/symbol/index'
+import type { TUndefined } from '../type/undefined/index'
+import type { TUint8Array } from '../type/uint8array/index'
+import type { TVoid } from '../type/void/index'
+// ------------------------------------------------------------------
+// ValueGuard
+// ------------------------------------------------------------------
+// prettier-ignore
+import {
+ IsArray,
+ IsUint8Array,
+ IsDate,
+ IsPromise,
+ IsFunction,
+ IsAsyncIterator,
+ IsIterator,
+ IsBoolean,
+ IsNumber,
+ IsBigInt,
+ IsString,
+ IsSymbol,
+ IsInteger,
+ IsNull,
+ IsUndefined
+} from '../value/guard/index'
+// ------------------------------------------------------------------
// ValueErrorType
-// --------------------------------------------------------------------------
+// ------------------------------------------------------------------
export enum ValueErrorType {
ArrayContains,
ArrayMaxContains,
@@ -84,6 +141,7 @@ export enum ValueErrorType {
ObjectRequiredProperty,
Object,
Promise,
+ RegExp,
StringFormatUnknown,
StringFormat,
StringMaxLength,
@@ -100,39 +158,39 @@ export enum ValueErrorType {
Union,
Void,
}
-// --------------------------------------------------------------------------
+// ------------------------------------------------------------------
// ValueError
-// --------------------------------------------------------------------------
+// ------------------------------------------------------------------
export interface ValueError {
type: ValueErrorType
- schema: Types.TSchema
+ schema: TSchema
path: string
value: unknown
message: string
}
-// --------------------------------------------------------------------------
+// ------------------------------------------------------------------
// ValueErrors
-// --------------------------------------------------------------------------
-export class ValueErrorsUnknownTypeError extends Types.TypeBoxError {
- constructor(public readonly schema: Types.TSchema) {
+// ------------------------------------------------------------------
+export class ValueErrorsUnknownTypeError extends TypeBoxError {
+ constructor(public readonly schema: TSchema) {
super('Unknown type')
}
}
-// --------------------------------------------------------------------------
+// ------------------------------------------------------------------
// EscapeKey
-// --------------------------------------------------------------------------
-export function EscapeKey(key: string): string {
+// ------------------------------------------------------------------
+function EscapeKey(key: string): string {
return key.replace(/~/g, '~0').replace(/\//g, '~1') // RFC6901 Path
}
-// --------------------------------------------------------------------------
+// ------------------------------------------------------------------
// Guards
-// --------------------------------------------------------------------------
+// ------------------------------------------------------------------
function IsDefined(value: unknown): value is T {
return value !== undefined
}
-// --------------------------------------------------------------------------
+// ------------------------------------------------------------------
// ValueErrorIterator
-// --------------------------------------------------------------------------
+// ------------------------------------------------------------------
export class ValueErrorIterator {
constructor(private readonly iterator: IterableIterator) {}
public [Symbol.iterator]() {
@@ -147,14 +205,14 @@ export class ValueErrorIterator {
// --------------------------------------------------------------------------
// Create
// --------------------------------------------------------------------------
-function Create(type: ValueErrorType, schema: Types.TSchema, path: string, value: unknown): ValueError {
- return { type, schema, path, value, message: TypeSystemErrorFunction.Get()(schema, type) }
+function Create(errorType: ValueErrorType, schema: TSchema, path: string, value: unknown): ValueError {
+ return { type: errorType, schema, path, value, message: GetErrorFunction()({ errorType, path, schema, value }) }
}
// --------------------------------------------------------------------------
// Types
// --------------------------------------------------------------------------
-function* TAny(schema: Types.TAny, references: Types.TSchema[], path: string, value: any): IterableIterator {}
-function* TArray(schema: Types.TArray, references: Types.TSchema[], path: string, value: any): IterableIterator {
+function* FromAny(schema: TAny, references: TSchema[], path: string, value: any): IterableIterator {}
+function* FromArray(schema: TArray, references: TSchema[], path: string, value: any): IterableIterator {
if (!IsArray(value)) {
return yield Create(ValueErrorType.Array, schema, path, value)
}
@@ -175,7 +233,7 @@ function* TArray(schema: Types.TArray, references: Types.TSchema[], path: string
if (!(IsDefined(schema.contains) || IsDefined(schema.minContains) || IsDefined(schema.maxContains))) {
return
}
- const containsSchema = IsDefined(schema.contains) ? schema.contains : Types.Type.Never()
+ const containsSchema = IsDefined(schema.contains) ? schema.contains : Never()
const containsCount = value.reduce((acc: number, value, index) => (Visit(containsSchema, references, `${path}${index}`, value).next().done === true ? acc + 1 : acc), 0)
if (containsCount === 0) {
yield Create(ValueErrorType.ArrayContains, schema, path, value)
@@ -187,10 +245,10 @@ function* TArray(schema: Types.TArray, references: Types.TSchema[], path: string
yield Create(ValueErrorType.ArrayMaxContains, schema, path, value)
}
}
-function* TAsyncIterator(schema: Types.TAsyncIterator, references: Types.TSchema[], path: string, value: any): IterableIterator {
+function* FromAsyncIterator(schema: TAsyncIterator, references: TSchema[], path: string, value: any): IterableIterator {
if (!IsAsyncIterator(value)) yield Create(ValueErrorType.AsyncIterator, schema, path, value)
}
-function* TBigInt(schema: Types.TBigInt, references: Types.TSchema[], path: string, value: any): IterableIterator {
+function* FromBigInt(schema: TBigInt, references: TSchema[], path: string, value: any): IterableIterator {
if (!IsBigInt(value)) return yield Create(ValueErrorType.BigInt, schema, path, value)
if (IsDefined(schema.exclusiveMaximum) && !(value < schema.exclusiveMaximum)) {
yield Create(ValueErrorType.BigIntExclusiveMaximum, schema, path, value)
@@ -208,13 +266,13 @@ function* TBigInt(schema: Types.TBigInt, references: Types.TSchema[], path: stri
yield Create(ValueErrorType.BigIntMultipleOf, schema, path, value)
}
}
-function* TBoolean(schema: Types.TBoolean, references: Types.TSchema[], path: string, value: any): IterableIterator {
+function* FromBoolean(schema: TBoolean, references: TSchema[], path: string, value: any): IterableIterator {
if (!IsBoolean(value)) yield Create(ValueErrorType.Boolean, schema, path, value)
}
-function* TConstructor(schema: Types.TConstructor, references: Types.TSchema[], path: string, value: any): IterableIterator {
+function* FromConstructor(schema: TConstructor, references: TSchema[], path: string, value: any): IterableIterator {
yield* Visit(schema.returns, references, path, value.prototype)
}
-function* TDate(schema: Types.TDate, references: Types.TSchema[], path: string, value: any): IterableIterator {
+function* FromDate(schema: TDate, references: TSchema[], path: string, value: any): IterableIterator {
if (!IsDate(value)) return yield Create(ValueErrorType.Date, schema, path, value)
if (IsDefined(schema.exclusiveMaximumTimestamp) && !(value.getTime() < schema.exclusiveMaximumTimestamp)) {
yield Create(ValueErrorType.DateExclusiveMaximumTimestamp, schema, path, value)
@@ -232,10 +290,10 @@ function* TDate(schema: Types.TDate, references: Types.TSchema[], path: string,
yield Create(ValueErrorType.DateMultipleOfTimestamp, schema, path, value)
}
}
-function* TFunction(schema: Types.TFunction, references: Types.TSchema[], path: string, value: any): IterableIterator {
+function* FromFunction(schema: TFunction, references: TSchema[], path: string, value: any): IterableIterator {
if (!IsFunction(value)) yield Create(ValueErrorType.Function, schema, path, value)
}
-function* TInteger(schema: Types.TInteger, references: Types.TSchema[], path: string, value: any): IterableIterator {
+function* FromInteger(schema: TInteger, references: TSchema[], path: string, value: any): IterableIterator {
if (!IsInteger(value)) return yield Create(ValueErrorType.Integer, schema, path, value)
if (IsDefined