Revision 0.32.0 (#689)

This commit is contained in:
sinclairzx81
2023-12-22 14:00:46 +09:00
committed by GitHub
parent 573cdb1694
commit ca4000cc9a
501 changed files with 25098 additions and 8148 deletions

View File

@@ -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:

View File

@@ -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:

View File

@@ -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`)
}

View File

@@ -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'
}

473
changelog/0.32.0.md Normal file
View File

@@ -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)
<a name="Type-Imports"></a>
### 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
```
<a name="Value-Function-Imports"></a>
### 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
<a name="CommonJS-and-ESM"></a>
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.
<a name="Types"></a>
## Types
Revision 0.32.0 adds three new types to the type system and makes enhancements to Readonly and Optional modifiers.
<a name="Types-Mapped-Type"></a>
### 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.
<a name="Types-Const-Type"></a>
### 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<TTuple<[
// TLiteral<1>,
// TLiteral<2>,
// TLiteral<3>
// ]>>
const C = Type.Const({ // const C: TObject<{
x: 1, // x: TReadonly<TLiteral<1>>,
y: 2, // y: TReadonly<TLiteral<2>>,
z: 3 // z: TReadonly<TLiteral<3>>,
} 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`.
<a name="Types-Deref-Type"></a>
### 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.
<a name="Types-RegExp-Type"></a>
### 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<typeof T> // type T = string
Value.Check(T, 'abc') // ok
Value.Check(T, 'ABC') // ok
// Extended Syntax
const E = Type.RegExp(/<a?:.+?:\d{18}>|\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
```
<a name="Types-Subtractive-Modifiers"></a>
### 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.
<a name="Values"></a>
## Values
Revision 0.32.0 adds two new functions to the Value module.
<a name="Values-Clean-Function"></a>
### 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.
<a name="Values-Default-Function"></a>
### 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.
<a name="Optimizations"></a>
## 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.
<a name="Optimizations-Bundle-Size"></a>
```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'
└──────────────────────┴────────────┴────────────┴─────────────┘
```
<a name="Errors"></a>
## Errors
Revision 0.32.0 makes some enhancements to errors.
<a name="Errors-Error-Parameter"></a>
### 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.
<a name="Breaking"></a>
## Breaking
The following list the breaking changes in Revision 0.32.0.
<a name="Breaking-Renamed-Symbols"></a>
### 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'
```
<a name="Breaking-TypeGuard-Interface-Change"></a>
### 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({ ... })
```
<a name="Breaking-Value-Submodule-Imports"></a>
### 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'
```
<a name="Breaking-Error-Function"></a>
### 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)
}
})
```
<a name="Breaking-RegEx"></a>
### 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
```

View File

@@ -0,0 +1,148 @@
/*--------------------------------------------------------------------------
@sinclair/typebox
The MIT License (MIT)
Copyright (c) 2017-2023 Haydn Paterson (sinclair) <haydn.developer@gmail.com>
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<boolean, ${Visit(schema.patternProperties[Types.PatternBooleanExact], references)}>` :
Types.PatternNumberExact in schema.patternProperties ? `Record<number, ${Visit(schema.patternProperties[Types.PatternNumberExact], references)}>` :
Types.PatternStringExact in schema.patternProperties ? `Record<string, ${Visit(schema.patternProperties[Types.PatternStringExact], references)}>` :
`{}`
)
}
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)
}
}

View File

@@ -0,0 +1 @@
export * from './annotation'

View File

@@ -44,7 +44,6 @@ import {
TTuple,
TProperties,
TIntersect,
IntersectType,
TUnion,
TNever
} from '@sinclair/typebox'
@@ -75,7 +74,7 @@ export type TEvaluateArray<T extends TSchema[]> = T extends [infer L, ...infer
[]
// prettier-ignore
export type TEvaluate<T extends TSchema> =
T extends TIntersect<infer S> ? IntersectType<TEvaluateIntersectRest<S>> :
T extends TIntersect<infer S> ? TIntersect<TEvaluateIntersectRest<S>> :
T extends TUnion<infer S> ? TUnion<TEvaluateArray<S>> :
T extends TConstructor<infer P, infer R> ? TConstructor<TEvaluateArray<P>, TEvaluate<R>> :
T extends TFunction<infer P, infer R> ? TFunction<TEvaluateArray<P>, TEvaluate<R>> :
@@ -119,16 +118,16 @@ export function EvaluateArray<T extends TSchema[] | undefined>(rest: T) {
// prettier-ignore
export function Evaluate<T extends TSchema>(schema: T): TEvaluate<T> {
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<T>
}

View File

@@ -26,7 +26,6 @@ THE SOFTWARE.
---------------------------------------------------------------------------*/
export * from './const'
export * from './evaluate'
export * from './partial-deep'
export * from './union-enum'

View File

@@ -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<T extends TProperties> = {
[K in keyof T]: TPartial<T[K]>
}
export type TPartialDeepRest<T extends TSchema[]> = T extends [infer L, ...infer R]
? [TPartial<AssertType<L>>, ...TPartialDeepRest<AssertRest<R>>]
: []
export type TPartialDeepRest<T extends TSchema[]> =
T extends [infer L extends TSchema, ...infer R extends TSchema[]]
? [TPartial<L>, ...TPartialDeepRest<R>]
: []
export type TPartialDeep<T extends TSchema> =
T extends TIntersect<infer S> ? TIntersect<TPartialDeepRest<S>> :
T extends TUnion<infer S> ? TUnion<TPartialDeepRest<S>> :
@@ -57,9 +58,9 @@ function PartialDeepRest<T extends TSchema[]>(rest: [...T]): TPartialDeepRest<T>
/** Maps the given schema as deep partial, making all properties and sub properties optional */
export function PartialDeep<T extends TSchema>(type: T): TPartialDeep<T> {
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
}

View File

@@ -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, U> = 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 string> = T extends `${infer L}${infer R}` ? `${Reverse<R>}${L}` : T
export type Tick<T extends string, B extends Base> = T extends keyof B ? B[T] : never
export type Next<T extends string, B extends Base> = T extends Assert<B, Base>['m'] ? Assert<B, Base>['t'] : T extends `${infer L}${infer R}` ? L extends Assert<B, Base>['m'] ? `${Assert<Tick<L, B>, string>}${Next<R, B>}` : `${Assert<Tick<L, B>, string>}${R}` : never
export type Increment<T extends string, B extends Base = Base10> = Reverse<Next<Reverse<T>, B>>
// --------------------------------------------------------------------------
// SchemaOptions
// Metadata
// --------------------------------------------------------------------------
export interface Metadata {
[name: string]: any
@@ -65,9 +54,10 @@ export interface TBoolean extends Types.TSchema {
// --------------------------------------------------------------------------
// TUnion
// --------------------------------------------------------------------------
type InferUnion<T extends TStruct[], D extends string, Index = string> = T extends [infer L, ...infer R]
? Types.Evaluate<{ [_ in D]: Index } & Types.Static<Types.AssertType<L>>> | InferUnion<Types.AssertRest<R>, D, Increment<Types.Assert<Index, string>>>
: never
export type InferUnion<T extends TStruct[], D extends string, Index = string> =
T extends [infer L extends TStruct, ...infer R extends TStruct[]]
? Types.Evaluate<{ [_ in D]: Index } & Types.Static<L>> | InferUnion<R, D, Types.Increment<Types.Assert<Index, string>>>
: never
export interface TUnion<T extends TStruct[] = TStruct[], D extends string = string> 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<T extends TFields> = { [K in keyof T]: T[K] extends (Types.TOptional<T[K]>) ? T[K] : never }
type RequiredKeys<T extends TFields> = { [K in keyof T]: T[K] extends (Types.TOptional<T[K]>) ? never : T[K] }
// static inference
type ReadonlyOptionalPropertyKeys<T extends TFields> = { [K in keyof T]: T[K] extends Types.TReadonly<Types.TSchema> ? (T[K] extends Types.TOptional<T[K]> ? K : never) : never }[keyof T]
type ReadonlyPropertyKeys<T extends TFields> = { [K in keyof T]: T[K] extends Types.TReadonly<Types.TSchema> ? (T[K] extends Types.TOptional<T[K]> ? never : K) : never }[keyof T]
type OptionalPropertyKeys<T extends TFields> = { [K in keyof T]: T[K] extends Types.TOptional<Types.TSchema> ? (T[K] extends Types.TReadonly<T[K]> ? never : K) : never }[keyof T]
type RequiredPropertyKeys<T extends TFields> = keyof Omit<T, ReadonlyOptionalPropertyKeys<T> | ReadonlyPropertyKeys<T> | OptionalPropertyKeys<T>>
// prettier-ignore
type StructStaticProperties<T extends TFields, R extends Record<keyof any, unknown>> = Types.Evaluate<(
Readonly<Partial<Pick<R, ReadonlyOptionalPropertyKeys<T>>>> &
Readonly<Pick<R, ReadonlyPropertyKeys<T>>> &
Partial<Pick<R, OptionalPropertyKeys<T>>> &
Required<Pick<R, RequiredPropertyKeys<T>>>
)>
// prettier-ignore
export type StructStatic<T extends TFields, P extends unknown[]> = StructStaticProperties<T, {
[K in keyof T]: Static<T[K], P>
}>
export interface StructMetadata extends Metadata {
additionalProperties?: boolean
}
export interface TStruct<T extends TFields = TFields> extends Types.TSchema, StructMetadata {
[Types.Kind]: 'TypeDef:Struct'
static: Types.PropertiesReduce<T, this['params']>
static: StructStatic<T, this['params']>
optionalProperties: { [K in Types.Assert<OptionalKeys<T>, keyof T>]: T[K] }
properties: { [K in Types.Assert<RequiredKeys<T>, keyof T>]: T[K] }
}
@@ -487,8 +494,8 @@ Types.TypeRegistry.Set<TTimestamp>('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<T extends TFields>(fields: T, metadata: StructMetadata = {}): TStruct<T> {
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)

View File

@@ -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.
<a name="Example"></a>
## 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<T extends TSchema>(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
})
```

View File

@@ -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`)
}

View File

@@ -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)

623
package-lock.json generated
View File

@@ -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",

View File

@@ -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",

835
readme.md

File diff suppressed because it is too large Load Diff

View File

@@ -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<T extends Types.TSchema> {
// ------------------------------------------------------------------
export class TypeCheck<T extends TSchema> {
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<T extends Types.TSchema> {
return Errors(this.schema, this.references, value)
}
/** Returns true if the value matches the compiled type. */
public Check(value: unknown): value is Types.Static<T> {
public Check(value: unknown): value is Static<T> {
return this.checkFunc(value)
}
/** Decodes a value or throws if error */
public Decode(value: unknown): Types.StaticDecode<T> {
public Decode(value: unknown): StaticDecode<T> {
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<T> {
const encoded = this.hasTransform ? EncodeTransform.Encode(this.schema, this.references, value) : value
public Encode(value: unknown): StaticEncode<T> {
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<string> {
// ----------------------------------------------------------------
function* FromAny(schema: TAny, references: TSchema[], value: string): IterableIterator<string> {
yield 'true'
}
function* TArray(schema: Types.TArray, references: Types.TSchema[], value: string): IterableIterator<string> {
function* FromArray(schema: TArray, references: TSchema[], value: string): IterableIterator<string> {
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<string> {
function* FromAsyncIterator(schema: TAsyncIterator, references: TSchema[], value: string): IterableIterator<string> {
yield `(typeof value === 'object' && Symbol.asyncIterator in ${value})`
}
function* TBigInt(schema: Types.TBigInt, references: Types.TSchema[], value: string): IterableIterator<string> {
function* FromBigInt(schema: TBigInt, references: TSchema[], value: string): IterableIterator<string> {
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<string> {
function* FromBoolean(schema: TBoolean, references: TSchema[], value: string): IterableIterator<string> {
yield `(typeof ${value} === 'boolean')`
}
function* TConstructor(schema: Types.TConstructor, references: Types.TSchema[], value: string): IterableIterator<string> {
function* FromConstructor(schema: TConstructor, references: TSchema[], value: string): IterableIterator<string> {
yield* Visit(schema.returns, references, `${value}.prototype`)
}
function* TDate(schema: Types.TDate, references: Types.TSchema[], value: string): IterableIterator<string> {
function* FromDate(schema: TDate, references: TSchema[], value: string): IterableIterator<string> {
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<string> {
function* FromFunction(schema: TFunction, references: TSchema[], value: string): IterableIterator<string> {
yield `(typeof ${value} === 'function')`
}
function* TInteger(schema: Types.TInteger, references: Types.TSchema[], value: string): IterableIterator<string> {
function* FromInteger(schema: TInteger, references: TSchema[], value: string): IterableIterator<string> {
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<string> {
const check1 = schema.allOf.map((schema: Types.TSchema) => CreateExpression(schema, references, value)).join(' && ')
function* FromIntersect(schema: TIntersect, references: TSchema[], value: string): IterableIterator<string> {
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<string> {
function* FromIterator(schema: TIterator, references: TSchema[], value: string): IterableIterator<string> {
yield `(typeof value === 'object' && Symbol.iterator in ${value})`
}
function* TLiteral(schema: Types.TLiteral, references: Types.TSchema[], value: string): IterableIterator<string> {
function* FromLiteral(schema: TLiteral, references: TSchema[], value: string): IterableIterator<string> {
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<string> {
function* FromNever(schema: TNever, references: TSchema[], value: string): IterableIterator<string> {
yield `false`
}
function* TNot(schema: Types.TNot, references: Types.TSchema[], value: string): IterableIterator<string> {
function* FromNot(schema: TNot, references: TSchema[], value: string): IterableIterator<string> {
const expression = CreateExpression(schema.not, references, value)
yield `(!${expression})`
}
function* TNull(schema: Types.TNull, references: Types.TSchema[], value: string): IterableIterator<string> {
function* FromNull(schema: TNull, references: TSchema[], value: string): IterableIterator<string> {
yield `(${value} === null)`
}
function* TNumber(schema: Types.TNumber, references: Types.TSchema[], value: string): IterableIterator<string> {
function* FromNumber(schema: TNumber, references: TSchema[], value: string): IterableIterator<string> {
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<string> {
function* FromObject(schema: TObject, references: TSchema[], value: string): IterableIterator<string> {
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<any>, references: Types.TSchema[], value: string): IterableIterator<string> {
function* FromPromise(schema: TPromise, references: TSchema[], value: string): IterableIterator<string> {
yield `(typeof value === 'object' && typeof ${value}.then === 'function')`
}
function* TRecord(schema: Types.TRecord<any, any>, references: Types.TSchema[], value: string): IterableIterator<string> {
function* FromRecord(schema: TRecord, references: TSchema[], value: string): IterableIterator<string> {
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<any>, references: Types.TSchema[], value: string): IterableIterator<string> {
function* FromRef(schema: TRef, references: TSchema[], value: string): IterableIterator<string> {
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<string> {
function* FromRegExp(schema: TRegExp, references: TSchema[], value: string): IterableIterator<string> {
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<string> {
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<string> {
function* FromSymbol(schema: TSymbol, references: TSchema[], value: string): IterableIterator<string> {
yield `(typeof ${value} === 'symbol')`
}
function* TTemplateLiteral(schema: Types.TTemplateLiteral, references: Types.TSchema[], value: string): IterableIterator<string> {
function* FromTemplateLiteral(schema: TTemplateLiteral, references: TSchema[], value: string): IterableIterator<string> {
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<string> {
function* FromThis(schema: TThis, references: TSchema[], value: string): IterableIterator<string> {
// 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<any[]>, references: Types.TSchema[], value: string): IterableIterator<string> {
function* FromTuple(schema: TTuple, references: TSchema[], value: string): IterableIterator<string> {
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<string> {
function* FromUndefined(schema: TUndefined, references: TSchema[], value: string): IterableIterator<string> {
yield `${value} === undefined`
}
function* TUnion(schema: Types.TUnion<any[]>, references: Types.TSchema[], value: string): IterableIterator<string> {
const expressions = schema.anyOf.map((schema: Types.TSchema) => CreateExpression(schema, references, value))
function* FromUnion(schema: TUnion, references: TSchema[], value: string): IterableIterator<string> {
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<string> {
function* FromUint8Array(schema: TUint8Array, references: TSchema[], value: string): IterableIterator<string> {
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<string> {
function* FromUnknown(schema: TUnknown, references: TSchema[], value: string): IterableIterator<string> {
yield 'true'
}
function* TVoid(schema: Types.TVoid, references: Types.TSchema[], value: string): IterableIterator<string> {
function* FromVoid(schema: TVoid, references: TSchema[], value: string): IterableIterator<string> {
yield Policy.IsVoidLike(value)
}
function* TKind(schema: Types.TSchema, references: Types.TSchema[], value: string): IterableIterator<string> {
function* FromKind(schema: TSchema, references: TSchema[], value: string): IterableIterator<string> {
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<T extends Types.TSchema>(schema: T, references: Types.TSchema[], value: string, useHoisting: boolean = true): IterableIterator<string> {
function* Visit(schema: TSchema, references: TSchema[], value: string, useHoisting: boolean = true): IterableIterator<string> {
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<string, string>(), // local functions
variables: new Map<string, string>(), // local variables
instances: new Map<number, Types.TKind>() // exterior kind instances
language: 'javascript', // target language
functions: new Map<string, string>(), // local functions
variables: new Map<string, string>(), // local variables
instances: new Map<number, TSchema>() // 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<T extends Types.TSchema>(schema: T, references: Types.TSchema[], options: TypeCompilerCodegenOptions): string {
// ----------------------------------------------------------------
function Build<T extends TSchema>(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<T extends Types.TSchema>(schema: T, references: Types.TSchema[], options?: TypeCompilerCodegenOptions): string
export function Code<T extends TSchema>(schema: T, references: TSchema[], options?: TypeCompilerCodegenOptions): string
/** Generates the code used to assert this type and returns it as a string */
export function Code<T extends Types.TSchema>(schema: T, options?: TypeCompilerCodegenOptions): string
export function Code<T extends TSchema>(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<T extends Types.TSchema>(schema: T, references: Types.TSchema[] = []): TypeCheck<T> {
export function Compile<T extends TSchema>(schema: T, references: TSchema[] = []): TypeCheck<T> {
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) {

View File

@@ -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'

View File

@@ -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<T>(value: unknown): value is T {
return value !== undefined
}
// --------------------------------------------------------------------------
// ------------------------------------------------------------------
// ValueErrorIterator
// --------------------------------------------------------------------------
// ------------------------------------------------------------------
export class ValueErrorIterator {
constructor(private readonly iterator: IterableIterator<ValueError>) {}
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<ValueError> {}
function* TArray(schema: Types.TArray, references: Types.TSchema[], path: string, value: any): IterableIterator<ValueError> {
function* FromAny(schema: TAny, references: TSchema[], path: string, value: any): IterableIterator<ValueError> {}
function* FromArray(schema: TArray, references: TSchema[], path: string, value: any): IterableIterator<ValueError> {
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<Types.TSchema>(schema.contains) ? schema.contains : Types.Type.Never()
const containsSchema = IsDefined<TSchema>(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<ValueError> {
function* FromAsyncIterator(schema: TAsyncIterator, references: TSchema[], path: string, value: any): IterableIterator<ValueError> {
if (!IsAsyncIterator(value)) yield Create(ValueErrorType.AsyncIterator, schema, path, value)
}
function* TBigInt(schema: Types.TBigInt, references: Types.TSchema[], path: string, value: any): IterableIterator<ValueError> {
function* FromBigInt(schema: TBigInt, references: TSchema[], path: string, value: any): IterableIterator<ValueError> {
if (!IsBigInt(value)) return yield Create(ValueErrorType.BigInt, schema, path, value)
if (IsDefined<bigint>(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<ValueError> {
function* FromBoolean(schema: TBoolean, references: TSchema[], path: string, value: any): IterableIterator<ValueError> {
if (!IsBoolean(value)) yield Create(ValueErrorType.Boolean, schema, path, value)
}
function* TConstructor(schema: Types.TConstructor, references: Types.TSchema[], path: string, value: any): IterableIterator<ValueError> {
function* FromConstructor(schema: TConstructor, references: TSchema[], path: string, value: any): IterableIterator<ValueError> {
yield* Visit(schema.returns, references, path, value.prototype)
}
function* TDate(schema: Types.TDate, references: Types.TSchema[], path: string, value: any): IterableIterator<ValueError> {
function* FromDate(schema: TDate, references: TSchema[], path: string, value: any): IterableIterator<ValueError> {
if (!IsDate(value)) return yield Create(ValueErrorType.Date, schema, path, value)
if (IsDefined<number>(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<ValueError> {
function* FromFunction(schema: TFunction, references: TSchema[], path: string, value: any): IterableIterator<ValueError> {
if (!IsFunction(value)) yield Create(ValueErrorType.Function, schema, path, value)
}
function* TInteger(schema: Types.TInteger, references: Types.TSchema[], path: string, value: any): IterableIterator<ValueError> {
function* FromInteger(schema: TInteger, references: TSchema[], path: string, value: any): IterableIterator<ValueError> {
if (!IsInteger(value)) return yield Create(ValueErrorType.Integer, schema, path, value)
if (IsDefined<number>(schema.exclusiveMaximum) && !(value < schema.exclusiveMaximum)) {
yield Create(ValueErrorType.IntegerExclusiveMaximum, schema, path, value)
@@ -253,7 +311,7 @@ function* TInteger(schema: Types.TInteger, references: Types.TSchema[], path: st
yield Create(ValueErrorType.IntegerMultipleOf, schema, path, value)
}
}
function* TIntersect(schema: Types.TIntersect, references: Types.TSchema[], path: string, value: any): IterableIterator<ValueError> {
function* FromIntersect(schema: TIntersect, references: TSchema[], path: string, value: any): IterableIterator<ValueError> {
for (const inner of schema.allOf) {
const next = Visit(inner, references, path, value).next()
if (!next.done) {
@@ -262,7 +320,7 @@ function* TIntersect(schema: Types.TIntersect, references: Types.TSchema[], path
}
}
if (schema.unevaluatedProperties === false) {
const keyCheck = new RegExp(Types.KeyResolver.ResolvePattern(schema))
const keyCheck = new RegExp(KeyOfPattern(schema))
for (const valueKey of Object.getOwnPropertyNames(value)) {
if (!keyCheck.test(valueKey)) {
yield Create(ValueErrorType.IntersectUnevaluatedProperties, schema, `${path}/${valueKey}`, value)
@@ -270,7 +328,7 @@ function* TIntersect(schema: Types.TIntersect, references: Types.TSchema[], path
}
}
if (typeof schema.unevaluatedProperties === 'object') {
const keyCheck = new RegExp(Types.KeyResolver.ResolvePattern(schema))
const keyCheck = new RegExp(KeyOfPattern(schema))
for (const valueKey of Object.getOwnPropertyNames(value)) {
if (!keyCheck.test(valueKey)) {
const next = Visit(schema.unevaluatedProperties, references, `${path}/${valueKey}`, value[valueKey]).next()
@@ -279,22 +337,22 @@ function* TIntersect(schema: Types.TIntersect, references: Types.TSchema[], path
}
}
}
function* TIterator(schema: Types.TIterator, references: Types.TSchema[], path: string, value: any): IterableIterator<ValueError> {
function* FromIterator(schema: TIterator, references: TSchema[], path: string, value: any): IterableIterator<ValueError> {
if (!IsIterator(value)) yield Create(ValueErrorType.Iterator, schema, path, value)
}
function* TLiteral(schema: Types.TLiteral, references: Types.TSchema[], path: string, value: any): IterableIterator<ValueError> {
function* FromLiteral(schema: TLiteral, references: TSchema[], path: string, value: any): IterableIterator<ValueError> {
if (!(value === schema.const)) yield Create(ValueErrorType.Literal, schema, path, value)
}
function* TNever(schema: Types.TNever, references: Types.TSchema[], path: string, value: any): IterableIterator<ValueError> {
function* FromNever(schema: TNever, references: TSchema[], path: string, value: any): IterableIterator<ValueError> {
yield Create(ValueErrorType.Never, schema, path, value)
}
function* TNot(schema: Types.TNot, references: Types.TSchema[], path: string, value: any): IterableIterator<ValueError> {
function* FromNot(schema: TNot, references: TSchema[], path: string, value: any): IterableIterator<ValueError> {
if (Visit(schema.not, references, path, value).next().done === true) yield Create(ValueErrorType.Not, schema, path, value)
}
function* TNull(schema: Types.TNull, references: Types.TSchema[], path: string, value: any): IterableIterator<ValueError> {
function* FromNull(schema: TNull, references: TSchema[], path: string, value: any): IterableIterator<ValueError> {
if (!IsNull(value)) yield Create(ValueErrorType.Null, schema, path, value)
}
function* TNumber(schema: Types.TNumber, references: Types.TSchema[], path: string, value: any): IterableIterator<ValueError> {
function* FromNumber(schema: TNumber, references: TSchema[], path: string, value: any): IterableIterator<ValueError> {
if (!TypeSystemPolicy.IsNumberLike(value)) return yield Create(ValueErrorType.Number, schema, path, value)
if (IsDefined<number>(schema.exclusiveMaximum) && !(value < schema.exclusiveMaximum)) {
yield Create(ValueErrorType.NumberExclusiveMaximum, schema, path, value)
@@ -312,7 +370,7 @@ function* TNumber(schema: Types.TNumber, references: Types.TSchema[], path: stri
yield Create(ValueErrorType.NumberMultipleOf, schema, path, value)
}
}
function* TObject(schema: Types.TObject, references: Types.TSchema[], path: string, value: any): IterableIterator<ValueError> {
function* FromObject(schema: TObject, references: TSchema[], path: string, value: any): IterableIterator<ValueError> {
if (!TypeSystemPolicy.IsObjectLike(value)) return yield Create(ValueErrorType.Object, schema, path, value)
if (IsDefined<number>(schema.minProperties) && !(Object.getOwnPropertyNames(value).length >= schema.minProperties)) {
yield Create(ValueErrorType.ObjectMinProperties, schema, path, value)
@@ -337,14 +395,14 @@ function* TObject(schema: Types.TObject, references: Types.TSchema[], path: stri
if (typeof schema.additionalProperties === 'object') {
for (const valueKey of unknownKeys) {
if (knownKeys.includes(valueKey)) continue
yield* Visit(schema.additionalProperties as Types.TSchema, references, `${path}/${EscapeKey(valueKey)}`, value[valueKey])
yield* Visit(schema.additionalProperties as TSchema, references, `${path}/${EscapeKey(valueKey)}`, value[valueKey])
}
}
for (const knownKey of knownKeys) {
const property = schema.properties[knownKey]
if (schema.required && schema.required.includes(knownKey)) {
yield* Visit(property, references, `${path}/${EscapeKey(knownKey)}`, value[knownKey])
if (Types.ExtendsUndefined.Check(schema) && !(knownKey in value)) {
if (ExtendsUndefinedCheck(schema) && !(knownKey in value)) {
yield Create(ValueErrorType.ObjectRequiredProperty, property, `${path}/${EscapeKey(knownKey)}`, undefined)
}
} else {
@@ -354,10 +412,10 @@ function* TObject(schema: Types.TObject, references: Types.TSchema[], path: stri
}
}
}
function* TPromise(schema: Types.TPromise, references: Types.TSchema[], path: string, value: any): IterableIterator<ValueError> {
function* FromPromise(schema: TPromise, references: TSchema[], path: string, value: any): IterableIterator<ValueError> {
if (!IsPromise(value)) yield Create(ValueErrorType.Promise, schema, path, value)
}
function* TRecord(schema: Types.TRecord, references: Types.TSchema[], path: string, value: any): IterableIterator<ValueError> {
function* FromRecord(schema: TRecord, references: TSchema[], path: string, value: any): IterableIterator<ValueError> {
if (!TypeSystemPolicy.IsRecordLike(value)) return yield Create(ValueErrorType.Object, schema, path, value)
if (IsDefined<number>(schema.minProperties) && !(Object.getOwnPropertyNames(value).length >= schema.minProperties)) {
yield Create(ValueErrorType.ObjectMinProperties, schema, path, value)
@@ -372,7 +430,7 @@ function* TRecord(schema: Types.TRecord, references: Types.TSchema[], path: stri
}
if (typeof schema.additionalProperties === 'object') {
for (const [propertyKey, propertyValue] of Object.entries(value)) {
if (!regex.test(propertyKey)) yield* Visit(schema.additionalProperties as Types.TSchema, references, `${path}/${EscapeKey(propertyKey)}`, propertyValue)
if (!regex.test(propertyKey)) yield* Visit(schema.additionalProperties as TSchema, references, `${path}/${EscapeKey(propertyKey)}`, propertyValue)
}
}
if (schema.additionalProperties === false) {
@@ -382,10 +440,16 @@ function* TRecord(schema: Types.TRecord, references: Types.TSchema[], path: stri
}
}
}
function* TRef(schema: Types.TRef<any>, references: Types.TSchema[], path: string, value: any): IterableIterator<ValueError> {
function* FromRef(schema: TRef, references: TSchema[], path: string, value: any): IterableIterator<ValueError> {
yield* Visit(Deref(schema, references), references, path, value)
}
function* TString(schema: Types.TString, references: Types.TSchema[], path: string, value: any): IterableIterator<ValueError> {
function* FromRegExp(schema: TRegExp, references: TSchema[], path: string, value: any): IterableIterator<ValueError> {
const regex = new RegExp(schema.source, schema.flags)
if (!regex.test(value)) {
return yield Create(ValueErrorType.RegExp, schema, path, value)
}
}
function* FromString(schema: TString, references: TSchema[], path: string, value: any): IterableIterator<ValueError> {
if (!IsString(value)) return yield Create(ValueErrorType.String, schema, path, value)
if (IsDefined<number>(schema.minLength) && !(value.length >= schema.minLength)) {
yield Create(ValueErrorType.StringMinLength, schema, path, value)
@@ -400,30 +464,30 @@ function* TString(schema: Types.TString, references: Types.TSchema[], path: stri
}
}
if (IsString(schema.format)) {
if (!Types.FormatRegistry.Has(schema.format)) {
if (!FormatRegistry.Has(schema.format)) {
yield Create(ValueErrorType.StringFormatUnknown, schema, path, value)
} else {
const format = Types.FormatRegistry.Get(schema.format)!
const format = FormatRegistry.Get(schema.format)!
if (!format(value)) {
yield Create(ValueErrorType.StringFormat, schema, path, value)
}
}
}
}
function* TSymbol(schema: Types.TSymbol, references: Types.TSchema[], path: string, value: any): IterableIterator<ValueError> {
function* FromSymbol(schema: TSymbol, references: TSchema[], path: string, value: any): IterableIterator<ValueError> {
if (!IsSymbol(value)) yield Create(ValueErrorType.Symbol, schema, path, value)
}
function* TTemplateLiteral(schema: Types.TTemplateLiteral, references: Types.TSchema[], path: string, value: any): IterableIterator<ValueError> {
function* FromTemplateLiteral(schema: TTemplateLiteral, references: TSchema[], path: string, value: any): IterableIterator<ValueError> {
if (!IsString(value)) return yield Create(ValueErrorType.String, schema, path, value)
const regex = new RegExp(schema.pattern)
if (!regex.test(value)) {
yield Create(ValueErrorType.StringPattern, schema, path, value)
}
}
function* TThis(schema: Types.TThis, references: Types.TSchema[], path: string, value: any): IterableIterator<ValueError> {
function* FromThis(schema: TThis, references: TSchema[], path: string, value: any): IterableIterator<ValueError> {
yield* Visit(Deref(schema, references), references, path, value)
}
function* TTuple(schema: Types.TTuple<any[]>, references: Types.TSchema[], path: string, value: any): IterableIterator<ValueError> {
function* FromTuple(schema: TTuple<any[]>, references: TSchema[], path: string, value: any): IterableIterator<ValueError> {
if (!IsArray(value)) return yield Create(ValueErrorType.Tuple, schema, path, value)
if (schema.items === undefined && !(value.length === 0)) {
return yield Create(ValueErrorType.TupleLength, schema, path, value)
@@ -438,10 +502,10 @@ function* TTuple(schema: Types.TTuple<any[]>, references: Types.TSchema[], path:
yield* Visit(schema.items[i], references, `${path}/${i}`, value[i])
}
}
function* TUndefined(schema: Types.TUndefined, references: Types.TSchema[], path: string, value: any): IterableIterator<ValueError> {
function* FromUndefined(schema: TUndefined, references: TSchema[], path: string, value: any): IterableIterator<ValueError> {
if (!IsUndefined(value)) yield Create(ValueErrorType.Undefined, schema, path, value)
}
function* TUnion(schema: Types.TUnion, references: Types.TSchema[], path: string, value: any): IterableIterator<ValueError> {
function* FromUnion(schema: TUnion, references: TSchema[], path: string, value: any): IterableIterator<ValueError> {
let count = 0
for (const subschema of schema.anyOf) {
const errors = [...Visit(subschema, references, path, value)]
@@ -452,7 +516,7 @@ function* TUnion(schema: Types.TUnion, references: Types.TSchema[], path: string
yield Create(ValueErrorType.Union, schema, path, value)
}
}
function* TUint8Array(schema: Types.TUint8Array, references: Types.TSchema[], path: string, value: any): IterableIterator<ValueError> {
function* FromUint8Array(schema: TUint8Array, references: TSchema[], path: string, value: any): IterableIterator<ValueError> {
if (!IsUint8Array(value)) return yield Create(ValueErrorType.Uint8Array, schema, path, value)
if (IsDefined<number>(schema.maxByteLength) && !(value.length <= schema.maxByteLength)) {
yield Create(ValueErrorType.Uint8ArrayMaxByteLength, schema, path, value)
@@ -461,87 +525,89 @@ function* TUint8Array(schema: Types.TUint8Array, references: Types.TSchema[], pa
yield Create(ValueErrorType.Uint8ArrayMinByteLength, schema, path, value)
}
}
function* TUnknown(schema: Types.TUnknown, references: Types.TSchema[], path: string, value: any): IterableIterator<ValueError> {}
function* TVoid(schema: Types.TVoid, references: Types.TSchema[], path: string, value: any): IterableIterator<ValueError> {
function* FromUnknown(schema: TUnknown, references: TSchema[], path: string, value: any): IterableIterator<ValueError> {}
function* FromVoid(schema: TVoid, references: TSchema[], path: string, value: any): IterableIterator<ValueError> {
if (!TypeSystemPolicy.IsVoidLike(value)) yield Create(ValueErrorType.Void, schema, path, value)
}
function* TKind(schema: Types.TSchema, references: Types.TSchema[], path: string, value: any): IterableIterator<ValueError> {
const check = Types.TypeRegistry.Get(schema[Types.Kind])!
function* FromKind(schema: TSchema, references: TSchema[], path: string, value: any): IterableIterator<ValueError> {
const check = TypeRegistry.Get(schema[Kind])!
if (!check(schema, value)) yield Create(ValueErrorType.Kind, schema, path, value)
}
function* Visit<T extends Types.TSchema>(schema: T, references: Types.TSchema[], path: string, value: any): IterableIterator<ValueError> {
function* Visit<T extends TSchema>(schema: T, references: TSchema[], path: string, value: any): IterableIterator<ValueError> {
const references_ = IsDefined<string>(schema.$id) ? [...references, schema] : references
const schema_ = schema as any
switch (schema_[Types.Kind]) {
switch (schema_[Kind]) {
case 'Any':
return yield* TAny(schema_, references_, path, value)
return yield* FromAny(schema_, references_, path, value)
case 'Array':
return yield* TArray(schema_, references_, path, value)
return yield* FromArray(schema_, references_, path, value)
case 'AsyncIterator':
return yield* TAsyncIterator(schema_, references_, path, value)
return yield* FromAsyncIterator(schema_, references_, path, value)
case 'BigInt':
return yield* TBigInt(schema_, references_, path, value)
return yield* FromBigInt(schema_, references_, path, value)
case 'Boolean':
return yield* TBoolean(schema_, references_, path, value)
return yield* FromBoolean(schema_, references_, path, value)
case 'Constructor':
return yield* TConstructor(schema_, references_, path, value)
return yield* FromConstructor(schema_, references_, path, value)
case 'Date':
return yield* TDate(schema_, references_, path, value)
return yield* FromDate(schema_, references_, path, value)
case 'Function':
return yield* TFunction(schema_, references_, path, value)
return yield* FromFunction(schema_, references_, path, value)
case 'Integer':
return yield* TInteger(schema_, references_, path, value)
return yield* FromInteger(schema_, references_, path, value)
case 'Intersect':
return yield* TIntersect(schema_, references_, path, value)
return yield* FromIntersect(schema_, references_, path, value)
case 'Iterator':
return yield* TIterator(schema_, references_, path, value)
return yield* FromIterator(schema_, references_, path, value)
case 'Literal':
return yield* TLiteral(schema_, references_, path, value)
return yield* FromLiteral(schema_, references_, path, value)
case 'Never':
return yield* TNever(schema_, references_, path, value)
return yield* FromNever(schema_, references_, path, value)
case 'Not':
return yield* TNot(schema_, references_, path, value)
return yield* FromNot(schema_, references_, path, value)
case 'Null':
return yield* TNull(schema_, references_, path, value)
return yield* FromNull(schema_, references_, path, value)
case 'Number':
return yield* TNumber(schema_, references_, path, value)
return yield* FromNumber(schema_, references_, path, value)
case 'Object':
return yield* TObject(schema_, references_, path, value)
return yield* FromObject(schema_, references_, path, value)
case 'Promise':
return yield* TPromise(schema_, references_, path, value)
return yield* FromPromise(schema_, references_, path, value)
case 'Record':
return yield* TRecord(schema_, references_, path, value)
return yield* FromRecord(schema_, references_, path, value)
case 'Ref':
return yield* TRef(schema_, references_, path, value)
return yield* FromRef(schema_, references_, path, value)
case 'RegExp':
return yield* FromRegExp(schema_, references_, path, value)
case 'String':
return yield* TString(schema_, references_, path, value)
return yield* FromString(schema_, references_, path, value)
case 'Symbol':
return yield* TSymbol(schema_, references_, path, value)
return yield* FromSymbol(schema_, references_, path, value)
case 'TemplateLiteral':
return yield* TTemplateLiteral(schema_, references_, path, value)
return yield* FromTemplateLiteral(schema_, references_, path, value)
case 'This':
return yield* TThis(schema_, references_, path, value)
return yield* FromThis(schema_, references_, path, value)
case 'Tuple':
return yield* TTuple(schema_, references_, path, value)
return yield* FromTuple(schema_, references_, path, value)
case 'Undefined':
return yield* TUndefined(schema_, references_, path, value)
return yield* FromUndefined(schema_, references_, path, value)
case 'Union':
return yield* TUnion(schema_, references_, path, value)
return yield* FromUnion(schema_, references_, path, value)
case 'Uint8Array':
return yield* TUint8Array(schema_, references_, path, value)
return yield* FromUint8Array(schema_, references_, path, value)
case 'Unknown':
return yield* TUnknown(schema_, references_, path, value)
return yield* FromUnknown(schema_, references_, path, value)
case 'Void':
return yield* TVoid(schema_, references_, path, value)
return yield* FromVoid(schema_, references_, path, value)
default:
if (!Types.TypeRegistry.Has(schema_[Types.Kind])) throw new ValueErrorsUnknownTypeError(schema)
return yield* TKind(schema_, references_, path, value)
if (!TypeRegistry.Has(schema_[Kind])) throw new ValueErrorsUnknownTypeError(schema)
return yield* FromKind(schema_, references_, path, value)
}
}
/** Returns an iterator for each error in this value. */
export function Errors<T extends Types.TSchema>(schema: T, references: Types.TSchema[], value: unknown): ValueErrorIterator
export function Errors<T extends TSchema>(schema: T, references: TSchema[], value: unknown): ValueErrorIterator
/** Returns an iterator for each error in this value. */
export function Errors<T extends Types.TSchema>(schema: T, value: unknown): ValueErrorIterator
export function Errors<T extends TSchema>(schema: T, value: unknown): ValueErrorIterator
/** Returns an iterator for each error in this value. */
export function Errors(...args: any[]) {
const iterator = args.length === 3 ? Visit(args[0], args[1], '', args[2]) : Visit(args[0], [], '', args[1])

193
src/errors/function.ts Normal file
View File

@@ -0,0 +1,193 @@
/*--------------------------------------------------------------------------
@sinclair/typebox/system
The MIT License (MIT)
Copyright (c) 2017-2023 Haydn Paterson (sinclair) <haydn.developer@gmail.com>
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 { TSchema } from '../type/schema/index'
import { Kind } from '../type/symbols/index'
import { ValueErrorType } from './errors'
/** Creates an error message using en-US as the default locale */
export function DefaultErrorFunction(error: ErrorFunctionParameter) {
switch (error.errorType) {
case ValueErrorType.ArrayContains:
return 'Expected array to contain at least one matching value'
case ValueErrorType.ArrayMaxContains:
return `Expected array to contain no more than ${error.schema.maxContains} matching values`
case ValueErrorType.ArrayMinContains:
return `Expected array to contain at least ${error.schema.minContains} matching values`
case ValueErrorType.ArrayMaxItems:
return `Expected array length to be less or equal to ${error.schema.maxItems}`
case ValueErrorType.ArrayMinItems:
return `Expected array length to be greater or equal to ${error.schema.minItems}`
case ValueErrorType.ArrayUniqueItems:
return 'Expected array elements to be unique'
case ValueErrorType.Array:
return 'Expected array'
case ValueErrorType.AsyncIterator:
return 'Expected AsyncIterator'
case ValueErrorType.BigIntExclusiveMaximum:
return `Expected bigint to be less than ${error.schema.exclusiveMaximum}`
case ValueErrorType.BigIntExclusiveMinimum:
return `Expected bigint to be greater than ${error.schema.exclusiveMinimum}`
case ValueErrorType.BigIntMaximum:
return `Expected bigint to be less or equal to ${error.schema.maximum}`
case ValueErrorType.BigIntMinimum:
return `Expected bigint to be greater or equal to ${error.schema.minimum}`
case ValueErrorType.BigIntMultipleOf:
return `Expected bigint to be a multiple of ${error.schema.multipleOf}`
case ValueErrorType.BigInt:
return 'Expected bigint'
case ValueErrorType.Boolean:
return 'Expected boolean'
case ValueErrorType.DateExclusiveMinimumTimestamp:
return `Expected Date timestamp to be greater than ${error.schema.exclusiveMinimumTimestamp}`
case ValueErrorType.DateExclusiveMaximumTimestamp:
return `Expected Date timestamp to be less than ${error.schema.exclusiveMaximumTimestamp}`
case ValueErrorType.DateMinimumTimestamp:
return `Expected Date timestamp to be greater or equal to ${error.schema.minimumTimestamp}`
case ValueErrorType.DateMaximumTimestamp:
return `Expected Date timestamp to be less or equal to ${error.schema.maximumTimestamp}`
case ValueErrorType.DateMultipleOfTimestamp:
return `Expected Date timestamp to be a multiple of ${error.schema.multipleOfTimestamp}`
case ValueErrorType.Date:
return 'Expected Date'
case ValueErrorType.Function:
return 'Expected function'
case ValueErrorType.IntegerExclusiveMaximum:
return `Expected integer to be less than ${error.schema.exclusiveMaximum}`
case ValueErrorType.IntegerExclusiveMinimum:
return `Expected integer to be greater than ${error.schema.exclusiveMinimum}`
case ValueErrorType.IntegerMaximum:
return `Expected integer to be less or equal to ${error.schema.maximum}`
case ValueErrorType.IntegerMinimum:
return `Expected integer to be greater or equal to ${error.schema.minimum}`
case ValueErrorType.IntegerMultipleOf:
return `Expected integer to be a multiple of ${error.schema.multipleOf}`
case ValueErrorType.Integer:
return 'Expected integer'
case ValueErrorType.IntersectUnevaluatedProperties:
return 'Unexpected property'
case ValueErrorType.Intersect:
return 'Expected all values to match'
case ValueErrorType.Iterator:
return 'Expected Iterator'
case ValueErrorType.Literal:
return `Expected ${typeof error.schema.const === 'string' ? `'${error.schema.const}'` : error.schema.const}`
case ValueErrorType.Never:
return 'Never'
case ValueErrorType.Not:
return 'Value should not match'
case ValueErrorType.Null:
return 'Expected null'
case ValueErrorType.NumberExclusiveMaximum:
return `Expected number to be less than ${error.schema.exclusiveMaximum}`
case ValueErrorType.NumberExclusiveMinimum:
return `Expected number to be greater than ${error.schema.exclusiveMinimum}`
case ValueErrorType.NumberMaximum:
return `Expected number to be less or equal to ${error.schema.maximum}`
case ValueErrorType.NumberMinimum:
return `Expected number to be greater or equal to ${error.schema.minimum}`
case ValueErrorType.NumberMultipleOf:
return `Expected number to be a multiple of ${error.schema.multipleOf}`
case ValueErrorType.Number:
return 'Expected number'
case ValueErrorType.Object:
return 'Expected object'
case ValueErrorType.ObjectAdditionalProperties:
return 'Unexpected property'
case ValueErrorType.ObjectMaxProperties:
return `Expected object to have no more than ${error.schema.maxProperties} properties`
case ValueErrorType.ObjectMinProperties:
return `Expected object to have at least ${error.schema.minProperties} properties`
case ValueErrorType.ObjectRequiredProperty:
return 'Required property'
case ValueErrorType.Promise:
return 'Expected Promise'
case ValueErrorType.RegExp:
return 'Expected string to match regular expression'
case ValueErrorType.StringFormatUnknown:
return `Unknown format '${error.schema.format}'`
case ValueErrorType.StringFormat:
return `Expected string to match '${error.schema.format}' format`
case ValueErrorType.StringMaxLength:
return `Expected string length less or equal to ${error.schema.maxLength}`
case ValueErrorType.StringMinLength:
return `Expected string length greater or equal to ${error.schema.minLength}`
case ValueErrorType.StringPattern:
return `Expected string to match '${error.schema.pattern}'`
case ValueErrorType.String:
return 'Expected string'
case ValueErrorType.Symbol:
return 'Expected symbol'
case ValueErrorType.TupleLength:
return `Expected tuple to have ${error.schema.maxItems || 0} elements`
case ValueErrorType.Tuple:
return 'Expected tuple'
case ValueErrorType.Uint8ArrayMaxByteLength:
return `Expected byte length less or equal to ${error.schema.maxByteLength}`
case ValueErrorType.Uint8ArrayMinByteLength:
return `Expected byte length greater or equal to ${error.schema.minByteLength}`
case ValueErrorType.Uint8Array:
return 'Expected Uint8Array'
case ValueErrorType.Undefined:
return 'Expected undefined'
case ValueErrorType.Union:
return 'Expected union value'
case ValueErrorType.Void:
return 'Expected void'
case ValueErrorType.Kind:
return `Expected kind '${error.schema[Kind]}'`
default:
return 'Unknown error type'
}
}
// ------------------------------------------------------------------
// ErrorFunction
// ------------------------------------------------------------------
export type ErrorFunctionParameter = {
/** The type of validation error */
errorType: ValueErrorType
/** The path of the error */
path: string
/** The schema associated with the error */
schema: TSchema
/** The value associated with the error */
value: unknown
}
export type ErrorFunction = (parameter: ErrorFunctionParameter) => string
/** Manages error message providers */
let errorFunction: ErrorFunction = DefaultErrorFunction
/** Sets the error function used to generate error messages. */
export function SetErrorFunction(callback: ErrorFunction) {
errorFunction = callback
}
/** Gets the error function used to generate error messages */
export function GetErrorFunction(): ErrorFunction {
return errorFunction
}

View File

@@ -26,4 +26,5 @@ THE SOFTWARE.
---------------------------------------------------------------------------*/
export * from './errors'
export { Errors, ValueError, ValueErrorIterator, ValueErrorType, ValueErrorsUnknownTypeError } from './errors'
export { DefaultErrorFunction, GetErrorFunction, SetErrorFunction, type ErrorFunction } from './function'

117
src/index.ts Normal file
View File

@@ -0,0 +1,117 @@
/*--------------------------------------------------------------------------
@sinclair/typebox
The MIT License (MIT)
Copyright (c) 2017-2023 Haydn Paterson (sinclair) <haydn.developer@gmail.com>
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.
---------------------------------------------------------------------------*/
// ------------------------------------------------------------------
// Infrastructure
// ------------------------------------------------------------------
export { Kind, Hint, ReadonlyKind, OptionalKind, TransformKind } from './type/symbols/index'
export { PatternBoolean, PatternBooleanExact, PatternNumber, PatternNumberExact, PatternString, PatternStringExact } from './type/patterns/index'
export { TypeRegistry, FormatRegistry } from './type/registry/index'
export { TypeGuard, ValueGuard } from './type/guard/index'
export { CloneType, CloneRest } from './type/clone/type'
export { TypeBoxError } from './type/error/index'
// ------------------------------------------------------------------
// Type
// ------------------------------------------------------------------
export { Any, type TAny } from './type/any/index'
export { Array, type TArray, type ArrayOptions } from './type/array/index'
export { AsyncIterator, type TAsyncIterator } from './type/async-iterator/index'
export { Awaited, type TAwaited } from './type/awaited/index'
export { BigInt, type TBigInt, type BigIntOptions } from './type/bigint/index'
export { Boolean, type TBoolean } from './type/boolean/index'
export { Composite, type TComposite } from './type/composite/index'
export { Const, type TConst } from './type/const/index'
export { Constructor, type TConstructor } from './type/constructor/index'
export { ConstructorParameters, type TConstructorParameters } from './type/constructor-parameters/index'
export { Date, type TDate, type DateOptions } from './type/date/index'
export { Deref, type TDeref } from './type/deref/index'
export { Enum, type TEnum } from './type/enum/index'
export { Exclude, type TExclude, type TExcludeFromMappedResult } from './type/exclude/index'
export { Extends, type TExtends, type ExtendsFromMappedResult, type ExtendsFromMappedKey, ExtendsCheck, ExtendsResult, ExtendsUndefinedCheck } from './type/extends/index'
export { Extract, type TExtract, type TExtractFromMappedResult } from './type/extract/index'
export { Function, type TFunction } from './type/function/index'
export { Increment, type Assert, type AssertType, type AssertRest, type AssertProperties, type Ensure, type Evaluate, type TupleToIntersect, type TupleToUnion, type UnionToTuple } from './type/helpers/index'
export { Index, IndexPropertyKeys, IndexFromMappedKey, IndexFromMappedResult, type TIndex, type TIndexPropertyKeys, type TIndexFromMappedKey, type TIndexFromMappedResult } from './type/indexed/index'
export { InstanceType, type TInstanceType } from './type/instance-type/index'
export { Integer, type TInteger, type IntegerOptions } from './type/integer/index'
export { Intersect, IntersectEvaluated, type TIntersect, type TIntersectEvaluated, type IntersectOptions } from './type/intersect/index'
export { Iterator, type TIterator } from './type/iterator/index'
export { Intrinsic, IntrinsicFromMappedKey, type TIntrinsic, Capitalize, type TCapitalize, Lowercase, type TLowercase, Uncapitalize, type TUncapitalize, Uppercase, type TUppercase } from './type/intrinsic/index'
export { KeyOf, type TKeyOf, type KeyOfFromMappedResult, KeyOfPropertyKeys, KeyOfPattern } from './type/keyof/index'
export { Literal, type TLiteral } from './type/literal/index'
export { Mapped, MappedKey, MappedResult, type TMapped, type TMappedKey, type TMappedResult, type TMappedFunction } from './type/mapped/index'
export { Never, type TNever } from './type/never/index'
export { Not, type TNot } from './type/not/index'
export { Null, type TNull } from './type/null/index'
export { Number, type TNumber, type NumberOptions } from './type/number/index'
export { Object, type TObject, type TProperties, type ObjectOptions } from './type/object/index'
export { Omit, type TOmit, type TOmitFromMappedKey, type TOmitFromMappedResult } from './type/omit/index'
export { Optional, OptionalFromMappedResult, type TOptional, type TOptionalWithFlag, type TOptionalFromMappedResult } from './type/optional/index'
export { Parameters, type TParameters } from './type/parameters/index'
export { Partial, PartialFromMappedResult, type TPartial, type TPartialFromMappedResult } from './type/partial/index'
export { Pick, type TPick, type TPickFromMappedKey, type TPickFromMappedResult } from './type/pick/index'
export { Promise, type TPromise } from './type/promise/index'
export { Readonly, ReadonlyFromMappedResult, type TReadonly, type TReadonlyWithFlag, type TReadonlyFromMappedResult } from './type/readonly/index'
export { ReadonlyOptional, type TReadonlyOptional } from './type/readonly-optional/index'
export { Record, type TRecord } from './type/record/index'
export { Recursive, type TRecursive, type TThis } from './type/recursive/index'
export { Ref, type TRef } from './type/ref/index'
export { RegExp, type TRegExp } from './type/regexp/index'
export { Required, type TRequired, type TRequiredFromMappedResult } from './type/required/index'
export { Rest, type TRest } from './type/rest/index'
export { ReturnType, type TReturnType } from './type/return-type/index'
export { type TSchema, type TKind, type SchemaOptions, type TAnySchema } from './type/schema/index'
export { type Static, type StaticDecode, type StaticEncode } from './type/static/index'
export { Strict } from './type/strict/index'
export { String, type TString, type StringOptions, type StringFormatOption, type StringContentEncodingOption } from './type/string/index'
export { Symbol, type TSymbol, type TSymbolValue as SymbolValue } from './type/symbol/index'
export {
TemplateLiteral,
IsTemplateLiteralFinite,
IsTemplateLiteralExpressionFinite,
TemplateLiteralParse,
TemplateLiteralParseExact,
TemplateLiteralGenerate,
TemplateLiteralExpressionGenerate,
type TTemplateLiteral,
type TIsTemplateLiteralFinite,
type TTemplateLiteralGenerate,
type TTemplateLiteralKind,
} from './type/template-literal/index'
export { Transform, TransformDecodeBuilder, TransformEncodeBuilder, type TTransform, type TransformOptions, type TransformFunction } from './type/transform/index'
export { Tuple, type TTuple } from './type/tuple/index'
export { Uint8Array, type TUint8Array, type Uint8ArrayOptions } from './type/uint8array/index'
export { Undefined, type TUndefined } from './type/undefined/index'
export { Union, UnionEvaluated, type TUnion, type TUnionEvaluated } from './type/union/index'
export { Unknown, type TUnknown } from './type/unknown/index'
export { Unsafe, type TUnsafe } from './type/unsafe/index'
export { Void, type TVoid } from './type/void/index'
// ------------------------------------------------------------------
// Namespace
// ------------------------------------------------------------------
export { Type, JsonTypeBuilder, JavaScriptTypeBuilder } from './type/type/index'

View File

@@ -26,5 +26,5 @@ THE SOFTWARE.
---------------------------------------------------------------------------*/
export { ValueErrorType } from '../errors/errors'
export * from './system'
export { TypeSystemPolicy } from './policy'
export { TypeSystem, TypeSystemDuplicateFormat, TypeSystemDuplicateTypeKind } from './system'

67
src/system/policy.ts Normal file
View File

@@ -0,0 +1,67 @@
/*--------------------------------------------------------------------------
@sinclair/typebox/system
The MIT License (MIT)
Copyright (c) 2017-2023 Haydn Paterson (sinclair) <haydn.developer@gmail.com>
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 { IsObject, IsArray, IsNumber, IsUndefined } from '../value/guard/index'
export namespace TypeSystemPolicy {
// ------------------------------------------------------------------
// TypeSystemPolicy
// ------------------------------------------------------------------
/** Shared assertion routines used by the value and errors modules */
/** Sets whether TypeBox should assert optional properties using the TypeScript `exactOptionalPropertyTypes` assertion policy. The default is `false` */
export let ExactOptionalPropertyTypes: boolean = false
/** Sets whether arrays should be treated as a kind of objects. The default is `false` */
export let AllowArrayObject: boolean = false
/** Sets whether `NaN` or `Infinity` should be treated as valid numeric values. The default is `false` */
export let AllowNaN: boolean = false
/** Sets whether `null` should validate for void types. The default is `false` */
export let AllowNullVoid: boolean = false
/** Asserts this value using the ExactOptionalPropertyTypes policy */
export function IsExactOptionalProperty(value: Record<keyof any, unknown>, key: string) {
return ExactOptionalPropertyTypes ? key in value : value[key] !== undefined
}
/** Asserts this value using the AllowArrayObjects policy */
export function IsObjectLike(value: unknown): value is Record<keyof any, unknown> {
const isObject = IsObject(value)
return AllowArrayObject ? isObject : isObject && !IsArray(value)
}
/** Asserts this value as a record using the AllowArrayObjects policy */
export function IsRecordLike(value: unknown): value is Record<keyof any, unknown> {
return IsObjectLike(value) && !(value instanceof Date) && !(value instanceof Uint8Array)
}
/** Asserts this value using the AllowNaN policy */
export function IsNumberLike(value: unknown): value is number {
const isNumber = IsNumber(value)
return AllowNaN ? isNumber : isNumber && Number.isFinite(value)
}
/** Asserts this value using the AllowVoidNull policy */
export function IsVoidLike(value: unknown): value is void {
const isUndefined = IsUndefined(value)
return AllowNullVoid ? isUndefined || value === null : isUndefined
}
}

View File

@@ -26,234 +26,39 @@ THE SOFTWARE.
---------------------------------------------------------------------------*/
import { IsObject, IsArray, IsNumber, IsUndefined } from '../value/guard'
import { ValueErrorType } from '../errors/errors'
import * as Types from '../typebox'
import { TypeRegistry, FormatRegistry } from '../type/registry/index'
import { Unsafe } from '../type/unsafe/index'
import { Kind } from '../type/symbols/index'
import { TypeBoxError } from '../type/error/index'
// --------------------------------------------------------------------------
// ------------------------------------------------------------------
// Errors
// --------------------------------------------------------------------------
export class TypeSystemDuplicateTypeKind extends Types.TypeBoxError {
// ------------------------------------------------------------------
export class TypeSystemDuplicateTypeKind extends TypeBoxError {
constructor(kind: string) {
super(`Duplicate type kind '${kind}' detected`)
}
}
export class TypeSystemDuplicateFormat extends Types.TypeBoxError {
export class TypeSystemDuplicateFormat extends TypeBoxError {
constructor(kind: string) {
super(`Duplicate string format '${kind}' detected`)
}
}
// -------------------------------------------------------------------------------------------
// ------------------------------------------------------------------
// TypeSystem
// -------------------------------------------------------------------------------------------
// ------------------------------------------------------------------
/** Creates user defined types and formats and provides overrides for value checking behaviours */
export namespace TypeSystem {
/** Creates a new type */
export function Type<Type, Options = Record<PropertyKey, unknown>>(kind: string, check: (options: Options, value: unknown) => boolean) {
if (Types.TypeRegistry.Has(kind)) throw new TypeSystemDuplicateTypeKind(kind)
Types.TypeRegistry.Set(kind, check)
return (options: Partial<Options> = {}) => Types.Type.Unsafe<Type>({ ...options, [Types.Kind]: kind })
if (TypeRegistry.Has(kind)) throw new TypeSystemDuplicateTypeKind(kind)
TypeRegistry.Set(kind, check)
return (options: Partial<Options> = {}) => Unsafe<Type>({ ...options, [Kind]: kind })
}
/** Creates a new string format */
export function Format<F extends string>(format: F, check: (value: string) => boolean): F {
if (Types.FormatRegistry.Has(format)) throw new TypeSystemDuplicateFormat(format)
Types.FormatRegistry.Set(format, check)
if (FormatRegistry.Has(format)) throw new TypeSystemDuplicateFormat(format)
FormatRegistry.Set(format, check)
return format
}
}
// --------------------------------------------------------------------------
// TypeSystemErrorFunction
// --------------------------------------------------------------------------
/** Manages error message providers */
export namespace TypeSystemErrorFunction {
let errorMessageFunction: ErrorFunction = DefaultErrorFunction
/** Resets the error message function to en-us */
export function Reset() {
errorMessageFunction = DefaultErrorFunction
}
/** Sets the error message function used to generate error messages */
export function Set(callback: ErrorFunction) {
errorMessageFunction = callback
}
/** Gets the error message function */
export function Get(): ErrorFunction {
return errorMessageFunction
}
}
// --------------------------------------------------------------------------
// TypeSystemPolicy
// --------------------------------------------------------------------------
/** Shared assertion routines used by the value and errors modules */
export namespace TypeSystemPolicy {
/** Sets whether TypeBox should assert optional properties using the TypeScript `exactOptionalPropertyTypes` assertion policy. The default is `false` */
export let ExactOptionalPropertyTypes: boolean = false
/** Sets whether arrays should be treated as a kind of objects. The default is `false` */
export let AllowArrayObject: boolean = false
/** Sets whether `NaN` or `Infinity` should be treated as valid numeric values. The default is `false` */
export let AllowNaN: boolean = false
/** Sets whether `null` should validate for void types. The default is `false` */
export let AllowNullVoid: boolean = false
/** Asserts this value using the ExactOptionalPropertyTypes policy */
export function IsExactOptionalProperty(value: Record<keyof any, unknown>, key: string) {
return ExactOptionalPropertyTypes ? key in value : value[key] !== undefined
}
/** Asserts this value using the AllowArrayObjects policy */
export function IsObjectLike(value: unknown): value is Record<keyof any, unknown> {
const isObject = IsObject(value)
return AllowArrayObject ? isObject : isObject && !IsArray(value)
}
/** Asserts this value as a record using the AllowArrayObjects policy */
export function IsRecordLike(value: unknown): value is Record<keyof any, unknown> {
return IsObjectLike(value) && !(value instanceof Date) && !(value instanceof Uint8Array)
}
/** Asserts this value using the AllowNaN policy */
export function IsNumberLike(value: unknown): value is number {
const isNumber = IsNumber(value)
return AllowNaN ? isNumber : isNumber && Number.isFinite(value)
}
/** Asserts this value using the AllowVoidNull policy */
export function IsVoidLike(value: unknown): value is void {
const isUndefined = IsUndefined(value)
return AllowNullVoid ? isUndefined || value === null : isUndefined
}
}
// --------------------------------------------------------------------------
// ErrorFunction
// --------------------------------------------------------------------------
export type ErrorFunction = (schema: Types.TSchema, type: ValueErrorType) => string
// --------------------------------------------------------------------------
// DefaultErrorFunction
// --------------------------------------------------------------------------
/** Creates an error message using en-US as the default locale */
export function DefaultErrorFunction(schema: Types.TSchema, errorType: ValueErrorType) {
switch (errorType) {
case ValueErrorType.ArrayContains:
return 'Expected array to contain at least one matching value'
case ValueErrorType.ArrayMaxContains:
return `Expected array to contain no more than ${schema.maxContains} matching values`
case ValueErrorType.ArrayMinContains:
return `Expected array to contain at least ${schema.minContains} matching values`
case ValueErrorType.ArrayMaxItems:
return `Expected array length to be less or equal to ${schema.maxItems}`
case ValueErrorType.ArrayMinItems:
return `Expected array length to be greater or equal to ${schema.minItems}`
case ValueErrorType.ArrayUniqueItems:
return 'Expected array elements to be unique'
case ValueErrorType.Array:
return 'Expected array'
case ValueErrorType.AsyncIterator:
return 'Expected AsyncIterator'
case ValueErrorType.BigIntExclusiveMaximum:
return `Expected bigint to be less than ${schema.exclusiveMaximum}`
case ValueErrorType.BigIntExclusiveMinimum:
return `Expected bigint to be greater than ${schema.exclusiveMinimum}`
case ValueErrorType.BigIntMaximum:
return `Expected bigint to be less or equal to ${schema.maximum}`
case ValueErrorType.BigIntMinimum:
return `Expected bigint to be greater or equal to ${schema.minimum}`
case ValueErrorType.BigIntMultipleOf:
return `Expected bigint to be a multiple of ${schema.multipleOf}`
case ValueErrorType.BigInt:
return 'Expected bigint'
case ValueErrorType.Boolean:
return 'Expected boolean'
case ValueErrorType.DateExclusiveMinimumTimestamp:
return `Expected Date timestamp to be greater than ${schema.exclusiveMinimumTimestamp}`
case ValueErrorType.DateExclusiveMaximumTimestamp:
return `Expected Date timestamp to be less than ${schema.exclusiveMaximumTimestamp}`
case ValueErrorType.DateMinimumTimestamp:
return `Expected Date timestamp to be greater or equal to ${schema.minimumTimestamp}`
case ValueErrorType.DateMaximumTimestamp:
return `Expected Date timestamp to be less or equal to ${schema.maximumTimestamp}`
case ValueErrorType.DateMultipleOfTimestamp:
return `Expected Date timestamp to be a multiple of ${schema.multipleOfTimestamp}`
case ValueErrorType.Date:
return 'Expected Date'
case ValueErrorType.Function:
return 'Expected function'
case ValueErrorType.IntegerExclusiveMaximum:
return `Expected integer to be less than ${schema.exclusiveMaximum}`
case ValueErrorType.IntegerExclusiveMinimum:
return `Expected integer to be greater than ${schema.exclusiveMinimum}`
case ValueErrorType.IntegerMaximum:
return `Expected integer to be less or equal to ${schema.maximum}`
case ValueErrorType.IntegerMinimum:
return `Expected integer to be greater or equal to ${schema.minimum}`
case ValueErrorType.IntegerMultipleOf:
return `Expected integer to be a multiple of ${schema.multipleOf}`
case ValueErrorType.Integer:
return 'Expected integer'
case ValueErrorType.IntersectUnevaluatedProperties:
return 'Unexpected property'
case ValueErrorType.Intersect:
return 'Expected all values to match'
case ValueErrorType.Iterator:
return 'Expected Iterator'
case ValueErrorType.Literal:
return `Expected ${typeof schema.const === 'string' ? `'${schema.const}'` : schema.const}`
case ValueErrorType.Never:
return 'Never'
case ValueErrorType.Not:
return 'Value should not match'
case ValueErrorType.Null:
return 'Expected null'
case ValueErrorType.NumberExclusiveMaximum:
return `Expected number to be less than ${schema.exclusiveMaximum}`
case ValueErrorType.NumberExclusiveMinimum:
return `Expected number to be greater than ${schema.exclusiveMinimum}`
case ValueErrorType.NumberMaximum:
return `Expected number to be less or equal to ${schema.maximum}`
case ValueErrorType.NumberMinimum:
return `Expected number to be greater or equal to ${schema.minimum}`
case ValueErrorType.NumberMultipleOf:
return `Expected number to be a multiple of ${schema.multipleOf}`
case ValueErrorType.Number:
return 'Expected number'
case ValueErrorType.Object:
return 'Expected object'
case ValueErrorType.ObjectAdditionalProperties:
return 'Unexpected property'
case ValueErrorType.ObjectMaxProperties:
return `Expected object to have no more than ${schema.maxProperties} properties`
case ValueErrorType.ObjectMinProperties:
return `Expected object to have at least ${schema.minProperties} properties`
case ValueErrorType.ObjectRequiredProperty:
return 'Required property'
case ValueErrorType.Promise:
return 'Expected Promise'
case ValueErrorType.StringFormatUnknown:
return `Unknown format '${schema.format}'`
case ValueErrorType.StringFormat:
return `Expected string to match '${schema.format}' format`
case ValueErrorType.StringMaxLength:
return `Expected string length less or equal to ${schema.maxLength}`
case ValueErrorType.StringMinLength:
return `Expected string length greater or equal to ${schema.minLength}`
case ValueErrorType.StringPattern:
return `Expected string to match '${schema.pattern}'`
case ValueErrorType.String:
return 'Expected string'
case ValueErrorType.Symbol:
return 'Expected symbol'
case ValueErrorType.TupleLength:
return `Expected tuple to have ${schema.maxItems || 0} elements`
case ValueErrorType.Tuple:
return 'Expected tuple'
case ValueErrorType.Uint8ArrayMaxByteLength:
return `Expected byte length less or equal to ${schema.maxByteLength}`
case ValueErrorType.Uint8ArrayMinByteLength:
return `Expected byte length greater or equal to ${schema.minByteLength}`
case ValueErrorType.Uint8Array:
return 'Expected Uint8Array'
case ValueErrorType.Undefined:
return 'Expected undefined'
case ValueErrorType.Union:
return 'Expected union value'
case ValueErrorType.Void:
return 'Expected void'
case ValueErrorType.Kind:
return `Expected kind '${schema[Types.Kind]}'`
default:
return 'Unknown error type'
}
}

View File

@@ -1,4 +1,4 @@
{
"extends": "../tsconfig.json",
"files": ["compiler/index.ts", "errors/index.ts", "system/index.ts", "value/index.ts", "typebox.ts"]
"files": ["compiler/index.ts", "errors/index.ts", "system/index.ts", "type/index.ts", "value/index.ts", "index.ts"]
}

40
src/type/any/any.ts Normal file
View File

@@ -0,0 +1,40 @@
/*--------------------------------------------------------------------------
@sinclair/typebox/type
The MIT License (MIT)
Copyright (c) 2017-2023 Haydn Paterson (sinclair) <haydn.developer@gmail.com>
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 type { TSchema, SchemaOptions } from '../schema/index'
import { Kind } from '../symbols/index'
export interface TAny extends TSchema {
[Kind]: 'Any'
static: any
}
/** `[Json]` Creates an Any type */
export function Any(options: SchemaOptions = {}): TAny {
return { ...options, [Kind]: 'Any' } as unknown as TAny
}

29
src/type/any/index.ts Normal file
View File

@@ -0,0 +1,29 @@
/*--------------------------------------------------------------------------
@sinclair/typebox/type
The MIT License (MIT)
Copyright (c) 2017-2023 Haydn Paterson (sinclair) <haydn.developer@gmail.com>
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.
---------------------------------------------------------------------------*/
export * from './any'

62
src/type/array/array.ts Normal file
View File

@@ -0,0 +1,62 @@
/*--------------------------------------------------------------------------
@sinclair/typebox/type
The MIT License (MIT)
Copyright (c) 2017-2023 Haydn Paterson (sinclair) <haydn.developer@gmail.com>
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 type { TSchema, SchemaOptions } from '../schema/index'
import type { Static } from '../static/index'
import { Kind } from '../symbols/index'
import { CloneType } from '../clone/type'
export interface ArrayOptions extends SchemaOptions {
/** The minimum number of items in this array */
minItems?: number
/** The maximum number of items in this array */
maxItems?: number
/** Should this schema contain unique items */
uniqueItems?: boolean
/** A schema for which some elements should match */
contains?: TSchema
/** A minimum number of contains schema matches */
minContains?: number
/** A maximum number of contains schema matches */
maxContains?: number
}
export interface TArray<T extends TSchema = TSchema> extends TSchema, ArrayOptions {
[Kind]: 'Array'
static: Array<Static<T, this['params']>>
type: 'array'
items: T
}
/** `[Json]` Creates an Array type */
export function Array<T extends TSchema>(schema: T, options: ArrayOptions = {}): TArray<T> {
return {
...options,
[Kind]: 'Array',
type: 'array',
items: CloneType(schema),
} as unknown as TArray<T>
}

29
src/type/array/index.ts Normal file
View File

@@ -0,0 +1,29 @@
/*--------------------------------------------------------------------------
@sinclair/typebox/type
The MIT License (MIT)
Copyright (c) 2017-2023 Haydn Paterson (sinclair) <haydn.developer@gmail.com>
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.
---------------------------------------------------------------------------*/
export * from './array'

View File

@@ -0,0 +1,48 @@
/*--------------------------------------------------------------------------
@sinclair/typebox/type
The MIT License (MIT)
Copyright (c) 2017-2023 Haydn Paterson (sinclair) <haydn.developer@gmail.com>
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 type { TSchema, SchemaOptions } from '../schema/index'
import type { Static } from '../static/index'
import { Kind } from '../symbols/index'
import { CloneType } from '../clone/type'
export interface TAsyncIterator<T extends TSchema = TSchema> extends TSchema {
[Kind]: 'AsyncIterator'
static: AsyncIterableIterator<Static<T, this['params']>>
type: 'AsyncIterator'
items: T
}
/** `[JavaScript]` Creates a AsyncIterator type */
export function AsyncIterator<T extends TSchema>(items: T, options: SchemaOptions = {}): TAsyncIterator<T> {
return {
...options,
[Kind]: 'AsyncIterator',
type: 'AsyncIterator',
items: CloneType(items),
} as unknown as TAsyncIterator<T>
}

View File

@@ -0,0 +1,29 @@
/*--------------------------------------------------------------------------
@sinclair/typebox/type
The MIT License (MIT)
Copyright (c) 2017-2023 Haydn Paterson (sinclair) <haydn.developer@gmail.com>
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.
---------------------------------------------------------------------------*/
export * from './async-iterator'

105
src/type/awaited/awaited.ts Normal file
View File

@@ -0,0 +1,105 @@
/*--------------------------------------------------------------------------
@sinclair/typebox/type
The MIT License (MIT)
Copyright (c) 2017-2023 Haydn Paterson (sinclair) <haydn.developer@gmail.com>
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 type { TSchema, SchemaOptions } from '../schema/index'
import { Intersect, type TIntersect } from '../intersect/index'
import { Union, type TUnion } from '../union/index'
import { type TPromise } from '../promise/index'
import { CloneType } from '../clone/type'
// ------------------------------------------------------------------
// TypeGuard
// ------------------------------------------------------------------
import { IsIntersect, IsUnion, IsPromise } from '../guard/type'
// ------------------------------------------------------------------
// FromRest
// ------------------------------------------------------------------
// prettier-ignore
type TFromRest<T extends TSchema[], Acc extends TSchema[] = []> =
T extends [infer L extends TSchema, ...infer R extends TSchema[]]
? TFromRest<R, [...Acc, TFromSchema<L>]>
: Acc
// prettier-ignore
function FromRest<T extends TSchema[]>(T: [...T]) : TFromRest<T> {
return T.map(L => FromSchema(L)) as TFromRest<T>
}
// ----------------------------------------------------------------
// FromIntersect
// ----------------------------------------------------------------
// prettier-ignore
type TFromIntersect<T extends TSchema[]> = TIntersect<TFromRest<T>>
// prettier-ignore
function FromIntersect<T extends TSchema[]>(T: [...T]): TFromIntersect<T> {
return Intersect(FromRest(T) as TSchema[]) as unknown as TFromIntersect<T>
}
// ----------------------------------------------------------------
// FromUnion
// ----------------------------------------------------------------
// prettier-ignore
type TFromUnion<T extends TSchema[]> = TUnion<TFromRest<T>>
// prettier-ignore
function FromUnion<T extends TSchema[]>(T: [...T]): TFromUnion<T> {
return Union(FromRest(T) as TSchema[]) as unknown as TFromUnion<T>
}
// ----------------------------------------------------------------
// Promise
// ----------------------------------------------------------------
type TFromPromise<T extends TSchema> = TFromSchema<T>
// prettier-ignore
function FromPromise<T extends TSchema>(T: T): TFromPromise<T> {
return FromSchema(T) as TFromPromise<T>
}
// ----------------------------------------------------------------
// FromSchema
// ----------------------------------------------------------------
// prettier-ignore
type TFromSchema<T extends TSchema> =
T extends TIntersect<infer S> ? TIntersect<TFromRest<S>> :
T extends TUnion<infer S> ? TUnion<TFromRest<S>> :
T extends TPromise<infer S> ? TFromSchema<S> :
T
// prettier-ignore
function FromSchema<T extends TSchema>(T: T): TFromSchema<T> {
return (
IsIntersect(T) ? FromIntersect(T.allOf) :
IsUnion(T) ? FromUnion(T.anyOf) :
IsPromise(T) ? FromPromise(T.item) :
T
) as TFromSchema<T>
}
// ------------------------------------------------------------------
// TAwaited
// ------------------------------------------------------------------
// prettier-ignore
export type TAwaited<T extends TSchema> = (
TFromSchema<T>
)
/** `[JavaScript]` Constructs a type by recursively unwrapping Promise types */
export function Awaited<T extends TSchema>(T: T, options: SchemaOptions = {}): TFromSchema<T> {
return CloneType(FromSchema(T), options)
}

29
src/type/awaited/index.ts Normal file
View File

@@ -0,0 +1,29 @@
/*--------------------------------------------------------------------------
@sinclair/typebox/type
The MIT License (MIT)
Copyright (c) 2017-2023 Haydn Paterson (sinclair) <haydn.developer@gmail.com>
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.
---------------------------------------------------------------------------*/
export * from './awaited'

51
src/type/bigint/bigint.ts Normal file
View File

@@ -0,0 +1,51 @@
/*--------------------------------------------------------------------------
@sinclair/typebox/type
The MIT License (MIT)
Copyright (c) 2017-2023 Haydn Paterson (sinclair) <haydn.developer@gmail.com>
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 type { TSchema, SchemaOptions } from '../schema/index'
import { Kind } from '../symbols/index'
export interface BigIntOptions extends SchemaOptions {
exclusiveMaximum?: bigint
exclusiveMinimum?: bigint
maximum?: bigint
minimum?: bigint
multipleOf?: bigint
}
export interface TBigInt extends TSchema, BigIntOptions {
[Kind]: 'BigInt'
static: bigint
type: 'bigint'
}
/** `[JavaScript]` Creates a BigInt type */
export function BigInt(options: BigIntOptions = {}): TBigInt {
return {
...options,
[Kind]: 'BigInt',
type: 'bigint',
} as TBigInt
}

29
src/type/bigint/index.ts Normal file
View File

@@ -0,0 +1,29 @@
/*--------------------------------------------------------------------------
@sinclair/typebox/type
The MIT License (MIT)
Copyright (c) 2017-2023 Haydn Paterson (sinclair) <haydn.developer@gmail.com>
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.
---------------------------------------------------------------------------*/
export * from './bigint'

View File

@@ -0,0 +1,44 @@
/*--------------------------------------------------------------------------
@sinclair/typebox/type
The MIT License (MIT)
Copyright (c) 2017-2023 Haydn Paterson (sinclair) <haydn.developer@gmail.com>
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 type { TSchema, SchemaOptions } from '../schema/index'
import { Kind } from '../symbols/index'
export interface TBoolean extends TSchema {
[Kind]: 'Boolean'
static: boolean
type: 'boolean'
}
/** `[Json]` Creates a Boolean type */
export function Boolean(options: SchemaOptions = {}): TBoolean {
return {
...options,
[Kind]: 'Boolean',
type: 'boolean',
} as unknown as TBoolean
}

29
src/type/boolean/index.ts Normal file
View File

@@ -0,0 +1,29 @@
/*--------------------------------------------------------------------------
@sinclair/typebox/type
The MIT License (MIT)
Copyright (c) 2017-2023 Haydn Paterson (sinclair) <haydn.developer@gmail.com>
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.
---------------------------------------------------------------------------*/
export * from './boolean'

30
src/type/clone/index.ts Normal file
View File

@@ -0,0 +1,30 @@
/*--------------------------------------------------------------------------
@sinclair/typebox/type
The MIT License (MIT)
Copyright (c) 2017-2023 Haydn Paterson (sinclair) <haydn.developer@gmail.com>
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.
---------------------------------------------------------------------------*/
export * as TypeClone from './type'
export * as ValueClone from './value'

39
src/type/clone/type.ts Normal file
View File

@@ -0,0 +1,39 @@
/*--------------------------------------------------------------------------
@sinclair/typebox/type
The MIT License (MIT)
Copyright (c) 2017-2023 Haydn Paterson (sinclair) <haydn.developer@gmail.com>
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 type { TSchema, SchemaOptions } from '../schema/index'
import { Clone } from './value'
/** Clones a Rest */
export function CloneRest<T extends TSchema[]>(schemas: T): T {
return schemas.map((schema) => CloneType(schema)) as T
}
/** Clones a Type */
export function CloneType<T extends TSchema>(schema: T, options: SchemaOptions = {}): T {
return { ...Clone(schema), ...options }
}

62
src/type/clone/value.ts Normal file
View File

@@ -0,0 +1,62 @@
/*--------------------------------------------------------------------------
@sinclair/typebox/type
The MIT License (MIT)
Copyright (c) 2017-2023 Haydn Paterson (sinclair) <haydn.developer@gmail.com>
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 ValueGuard from '../guard/value'
function ArrayType(value: unknown[]) {
return (value as any).map((value: unknown) => Visit(value as any))
}
function DateType(value: Date) {
return new Date(value.getTime())
}
function Uint8ArrayType(value: Uint8Array) {
return new Uint8Array(value)
}
function RegExpType(value: RegExp) {
return new RegExp(value.source, value.flags)
}
function ObjectType(value: Record<keyof any, unknown>) {
const clonedProperties = Object.getOwnPropertyNames(value).reduce((acc, key) => ({ ...acc, [key]: Visit(value[key]) }), {})
const clonedSymbols = Object.getOwnPropertySymbols(value).reduce((acc, key) => ({ ...acc, [key]: Visit(value[key as any]) }), {})
return { ...clonedProperties, ...clonedSymbols }
}
// prettier-ignore
function Visit(value: unknown): any {
return (
ValueGuard.IsArray(value) ? ArrayType(value) :
ValueGuard.IsDate(value) ? DateType(value) :
ValueGuard.IsUint8Array(value) ? Uint8ArrayType(value) :
ValueGuard.IsRegExp(value) ? RegExpType(value) :
ValueGuard.IsObject(value) ? ObjectType(value) :
value
)
}
/** Clones a value */
export function Clone<T>(value: T): T {
return Visit(value)
}

View File

@@ -0,0 +1,75 @@
/*--------------------------------------------------------------------------
@sinclair/typebox/type
The MIT License (MIT)
Copyright (c) 2017-2023 Haydn Paterson (sinclair) <haydn.developer@gmail.com>
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 type { TSchema } from '../schema/index'
import type { UnionToTuple, Assert, Evaluate } from '../helpers/index'
import { Object, type TObject, type TProperties, type ObjectOptions } from '../object/index'
import { Intersect, type TIntersect } from '../intersect/index'
import { Index, type TIndex } from '../indexed/index'
import { KeyOfPropertyKeys } from '../keyof/index'
import { CloneType } from '../clone/type'
// ------------------------------------------------------------------
// TCompositeKeys
// ------------------------------------------------------------------
// prettier-ignore
type TCompositeKeys<T extends TObject[], Acc extends PropertyKey = never> =
T extends [infer L extends TObject, ...infer R extends TObject[]]
? TCompositeKeys<R, Acc | keyof L['properties']>
: Acc
// ------------------------------------------------------------------
// TCompositeIndex
// ------------------------------------------------------------------
// prettier-ignore
type TCompositeIndex<T extends TIntersect<TObject[]>, K extends string[], Acc extends TProperties = {}> =
K extends [infer L extends string, ...infer R extends string[]]
? TCompositeIndex<T, R, Acc & { [_ in L]: TIndex<T, [L]> }>
: Acc
// prettier-ignore
type TCompositeReduce<T extends TObject[]> = UnionToTuple<TCompositeKeys<T>> extends infer K
? Evaluate<TCompositeIndex<TIntersect<T>, Assert<K, string[]>>>
: {} // ^ indexed via intersection of T
// prettier-ignore
type TCompositeResolve<T extends TObject[]> = TIntersect<T> extends TIntersect
? TObject<TCompositeReduce<T>>
: TObject<{}>
function CompositeResolve<T extends TObject[]>(T: [...T]): TCompositeResolve<T> {
const intersect: TSchema = Intersect(T, {})
const keys = KeyOfPropertyKeys(intersect) as string[]
const properties = keys.reduce((acc, key) => ({ ...acc, [key]: Index(intersect, [key]) }), {} as TProperties)
return Object(properties) as TCompositeResolve<T>
}
// ------------------------------------------------------------------
// TComposite
// ------------------------------------------------------------------
export type TComposite<T extends TObject[]> = TCompositeResolve<T>
/** `[Json]` Creates a Composite object type */
export function Composite<T extends TObject[]>(T: [...T], options?: ObjectOptions): TComposite<T> {
return CloneType(CompositeResolve(T) as TObject, options) as TComposite<T>
}

View File

@@ -0,0 +1,29 @@
/*--------------------------------------------------------------------------
@sinclair/typebox/type
The MIT License (MIT)
Copyright (c) 2017-2023 Haydn Paterson (sinclair) <haydn.developer@gmail.com>
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.
---------------------------------------------------------------------------*/
export * from './composite'

135
src/type/const/const.ts Normal file
View File

@@ -0,0 +1,135 @@
/*--------------------------------------------------------------------------
@sinclair/typebox/type
The MIT License (MIT)
Copyright (c) 2017-2023 Haydn Paterson (sinclair) <haydn.developer@gmail.com>
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 type { AssertRest, Evaluate } from '../helpers/index'
import type { TSchema, SchemaOptions } from '../schema/index'
import type { TProperties } from '../object/index'
import { Any, type TAny } from '../any/index'
import { BigInt, type TBigInt } from '../bigint/index'
import { Date, type TDate } from '../date/index'
import { Function as FunctionType, type TFunction } from '../function/index'
import { Literal, type TLiteral } from '../literal/index'
import { type TNever } from '../never/index'
import { Null, type TNull } from '../null/index'
import { Object, type TObject } from '../object/index'
import { Symbol, type TSymbol } from '../symbol/index'
import { Tuple, type TTuple } from '../tuple/index'
import { Readonly, type TReadonly } from '../readonly/index'
import { Undefined, type TUndefined } from '../undefined/index'
import { Uint8Array, type TUint8Array } from '../uint8array/index'
import { Unknown, type TUnknown } from '../unknown/index'
import { TypeClone } from '../clone/index'
// ------------------------------------------------------------------
// ValueGuard
// ------------------------------------------------------------------
import { IsArray, IsNumber, IsBigInt, IsUint8Array, IsDate, IsIterator, IsObject, IsAsyncIterator, IsFunction, IsUndefined, IsNull, IsSymbol, IsBoolean, IsString } from '../guard/value'
// ------------------------------------------------------------------
// FromArray
// ------------------------------------------------------------------
// prettier-ignore
type TFromArray<T extends readonly unknown[]> =
T extends readonly [infer L extends unknown, ...infer R extends unknown[]]
? [FromValue<L, false>, ...TFromArray<R>]
: T
// prettier-ignore
function FromArray<T extends readonly unknown[]>(T: [...T]): TFromArray<T> {
return T.map(L => FromValue(L, false)) as TFromArray<T>
}
// ------------------------------------------------------------------
// FromProperties
// ------------------------------------------------------------------
// prettier-ignore
type TFromProperties<T extends Record<PropertyKey, unknown>> = {
-readonly [K in keyof T]: FromValue<T[K], false> extends infer R extends TSchema
? TReadonly<R>
: TReadonly<TNever>
}
// prettier-ignore
function FromProperties<T extends Record<PropertyKey, unknown>>(value: T): TFromProperties<T> {
return globalThis.Object.getOwnPropertyNames(value).reduce((acc, key) => {
return { ...acc, [key]: Readonly(FromValue(value[key], false)) }
}, {} as TProperties) as unknown as TFromProperties<T>
}
// ------------------------------------------------------------------
// ConditionalReadonly - Only applied if not root
// ------------------------------------------------------------------
type TConditionalReadonly<T extends TSchema, Root extends boolean> = Root extends true ? T : TReadonly<T>
function ConditionalReadonly<T extends TSchema, Root extends boolean>(T: T, root: Root): TConditionalReadonly<T, Root> {
return (root === true ? T : Readonly(T)) as unknown as TConditionalReadonly<T, Root>
}
// ------------------------------------------------------------------
// FromValue
// ------------------------------------------------------------------
// prettier-ignore
type FromValue<T, Root extends boolean> =
T extends AsyncIterableIterator<unknown> ? TConditionalReadonly<TAny, Root> :
T extends IterableIterator<unknown> ? TConditionalReadonly<TAny, Root> :
T extends readonly unknown[] ? TReadonly<TTuple<AssertRest<TFromArray<T>>>> :
T extends Uint8Array ? TUint8Array :
T extends Date ? TDate :
T extends Record<PropertyKey, unknown> ? TConditionalReadonly<TObject<Evaluate<TFromProperties<T>>>, Root> :
T extends Function ? TConditionalReadonly<TFunction<[], TUnknown>, Root> :
T extends undefined ? TUndefined :
T extends null ? TNull :
T extends symbol ? TSymbol :
T extends number ? TLiteral<T> :
T extends boolean ? TLiteral<T> :
T extends string ? TLiteral<T> :
T extends bigint ? TBigInt :
TObject<{}>
// prettier-ignore
function FromValue<T, Root extends boolean>(value: T, root: Root): FromValue<T, Root> {
return (
IsAsyncIterator(value) ? ConditionalReadonly(Any(), root) :
IsIterator(value) ? ConditionalReadonly(Any(), root) :
IsArray(value) ? Readonly(Tuple(FromArray(value) as TSchema[])) :
IsUint8Array(value) ? Uint8Array() :
IsDate(value) ? Date() :
IsObject(value) ? ConditionalReadonly(Object(FromProperties(value as Record<PropertyKey, unknown>) as TProperties), root) :
IsFunction(value) ? ConditionalReadonly(FunctionType([], Unknown()), root) :
IsUndefined(value) ? Undefined() :
IsNull(value) ? Null() :
IsSymbol(value) ? Symbol() :
IsBigInt(value) ? BigInt() :
IsNumber(value) ? Literal(value) :
IsBoolean(value) ? Literal(value) :
IsString(value) ? Literal(value) :
Object({})
) as FromValue<T, Root>
}
// ------------------------------------------------------------------
// TConst
// ------------------------------------------------------------------
export type TConst<T> = FromValue<T, true>
/** `[JavaScript]` Creates a readonly const type from the given value. */
export function Const</* const (not supported in 4.0) */ T>(T: T, options: SchemaOptions = {}): TConst<T> {
return TypeClone.CloneType(FromValue(T, true), options) as TConst<T>
}

29
src/type/const/index.ts Normal file
View File

@@ -0,0 +1,29 @@
/*--------------------------------------------------------------------------
@sinclair/typebox/type
The MIT License (MIT)
Copyright (c) 2017-2023 Haydn Paterson (sinclair) <haydn.developer@gmail.com>
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.
---------------------------------------------------------------------------*/
export * from './const'

View File

@@ -0,0 +1,46 @@
/*--------------------------------------------------------------------------
@sinclair/typebox/type
The MIT License (MIT)
Copyright (c) 2017-2023 Haydn Paterson (sinclair) <haydn.developer@gmail.com>
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 type { TSchema, SchemaOptions } from '../schema/index'
import type { Ensure } from '../helpers/index'
import type { TConstructor } from '../constructor/index'
import { Tuple, type TTuple } from '../tuple/index'
import { CloneRest } from '../clone/type'
// ------------------------------------------------------------------
// ConstructorParameters
// ------------------------------------------------------------------
// prettier-ignore
export type TConstructorParameters<T extends TConstructor<TSchema[], TSchema>> = (
Ensure<TTuple<T['parameters']>>
)
/** `[JavaScript]` Extracts the ConstructorParameters from the given Constructor type */
export function ConstructorParameters<T extends TConstructor<TSchema[], TSchema>>(schema: T, options: SchemaOptions = {}): TConstructorParameters<T> {
return Tuple(CloneRest(schema.parameters), { ...options })
}

View File

@@ -0,0 +1,29 @@
/*--------------------------------------------------------------------------
@sinclair/typebox/type
The MIT License (MIT)
Copyright (c) 2017-2023 Haydn Paterson (sinclair) <haydn.developer@gmail.com>
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.
---------------------------------------------------------------------------*/
export * from './constructor-parameters'

View File

@@ -0,0 +1,67 @@
/*--------------------------------------------------------------------------
@sinclair/typebox/type
The MIT License (MIT)
Copyright (c) 2017-2023 Haydn Paterson (sinclair) <haydn.developer@gmail.com>
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 type { TSchema, SchemaOptions } from '../schema/index'
import type { Static } from '../static/index'
import type { Ensure } from '../helpers/index'
import { CloneType, CloneRest } from '../clone/type'
import { Kind } from '../symbols/index'
// ------------------------------------------------------------------
// TConstructorStatic
// ------------------------------------------------------------------
type ConstructorStaticReturnType<T extends TSchema, P extends unknown[]> = Static<T, P>
// prettier-ignore
type ConstructorStaticParameters<T extends TSchema[], P extends unknown[], Acc extends unknown[] = []> =
T extends [infer L extends TSchema, ...infer R extends TSchema[]]
? ConstructorStaticParameters<R, P, [...Acc, Static<L, P>]>
: Acc
// prettier-ignore
type ConstructorStatic<T extends TSchema[], U extends TSchema, P extends unknown[]> = (
Ensure<new (...param: ConstructorStaticParameters<T, P>) => ConstructorStaticReturnType<U, P>>
)
// ------------------------------------------------------------------
// TConstructor
// ------------------------------------------------------------------
export interface TConstructor<T extends TSchema[] = TSchema[], U extends TSchema = TSchema> extends TSchema {
[Kind]: 'Constructor'
static: ConstructorStatic<T, U, this['params']>
type: 'Constructor'
parameters: T
returns: U
}
/** `[JavaScript]` Creates a Constructor type */
export function Constructor<T extends TSchema[], U extends TSchema>(parameters: [...T], returns: U, options?: SchemaOptions): TConstructor<T, U> {
return {
...options,
[Kind]: 'Constructor',
type: 'Constructor',
parameters: CloneRest(parameters),
returns: CloneType(returns),
} as unknown as TConstructor<T, U>
}

View File

@@ -0,0 +1,29 @@
/*--------------------------------------------------------------------------
@sinclair/typebox/type
The MIT License (MIT)
Copyright (c) 2017-2023 Haydn Paterson (sinclair) <haydn.developer@gmail.com>
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.
---------------------------------------------------------------------------*/
export * from './constructor'

56
src/type/date/date.ts Normal file
View File

@@ -0,0 +1,56 @@
/*--------------------------------------------------------------------------
@sinclair/typebox/type
The MIT License (MIT)
Copyright (c) 2017-2023 Haydn Paterson (sinclair) <haydn.developer@gmail.com>
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 type { TSchema, SchemaOptions } from '../schema/index'
import { Kind } from '../symbols/index'
export interface DateOptions extends SchemaOptions {
/** The exclusive maximum timestamp value */
exclusiveMaximumTimestamp?: number
/** The exclusive minimum timestamp value */
exclusiveMinimumTimestamp?: number
/** The maximum timestamp value */
maximumTimestamp?: number
/** The minimum timestamp value */
minimumTimestamp?: number
/** The multiple of timestamp value */
multipleOfTimestamp?: number
}
export interface TDate extends TSchema, DateOptions {
[Kind]: 'Date'
static: Date
type: 'date'
}
/** `[JavaScript]` Creates a Date type */
export function Date(options: DateOptions = {}): TDate {
return {
...options,
[Kind]: 'Date',
type: 'Date',
} as unknown as TDate
}

29
src/type/date/index.ts Normal file
View File

@@ -0,0 +1,29 @@
/*--------------------------------------------------------------------------
@sinclair/typebox/type
The MIT License (MIT)
Copyright (c) 2017-2023 Haydn Paterson (sinclair) <haydn.developer@gmail.com>
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.
---------------------------------------------------------------------------*/
export * from './date'

174
src/type/deref/deref.ts Normal file
View File

@@ -0,0 +1,174 @@
/*--------------------------------------------------------------------------
@sinclair/typebox/type
The MIT License (MIT)
Copyright (c) 2017-2023 Haydn Paterson (sinclair) <haydn.developer@gmail.com>
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 type { TSchema } from '../schema/index'
import type { Evaluate } from '../helpers/index'
import type { TTuple } from '../tuple/index'
import type { TIntersect } from '../intersect/index'
import type { TUnion } from '../union/index'
import type { TPromise } from '../promise/index'
import type { TAsyncIterator } from '../async-iterator/index'
import type { TIterator } from '../iterator/index'
import type { TArray } from '../array/index'
import type { TConstructor } from '../constructor/index'
import type { TFunction } from '../function/index'
import type { TRef } from '../ref/index'
import type { TObject, TProperties } from '../object/index'
import { CloneType, CloneRest } from '../clone/type'
import { Discard } from '../discard/index'
import { IsUndefined } from '../guard/value'
// ------------------------------------------------------------------
// TypeGuard
// ------------------------------------------------------------------
import { IsConstructor, IsFunction, IsIntersect, IsUnion, IsTuple, IsArray, IsObject, IsPromise, IsAsyncIterator, IsIterator, IsRef } from '../guard/type'
// ------------------------------------------------------------------
// FromRest
// ------------------------------------------------------------------
// prettier-ignore
export type TFromRest<T extends TSchema[], Acc extends TSchema[] = []> = (
T extends [infer L extends TSchema, ...infer R extends TSchema[]]
? TFromRest<R, [...Acc, DerefResolve<L>]>
: Acc
)
function FromRest(schema: TSchema[], references: TSchema[]) {
return schema.map((schema) => Deref(schema, references))
}
// ------------------------------------------------------------------
// FromProperties
// ------------------------------------------------------------------
// prettier-ignore
type FromProperties<T extends TProperties> = Evaluate<{
[K in keyof T]: DerefResolve<T[K]>
}>
// prettier-ignore
function FromProperties(properties: TProperties, references: TSchema[]) {
return globalThis.Object.getOwnPropertyNames(properties).reduce((acc, key) => {
return {...acc, [key]: Deref(properties[key], references) }
}, {} as TProperties)
}
// prettier-ignore
function FromConstructor(schema: TConstructor, references: TSchema[]) {
schema.parameters = FromRest(schema.parameters, references)
schema.returns = Deref(schema.returns, references)
return schema
}
// prettier-ignore
function FromFunction(schema: TFunction, references: TSchema[]) {
schema.parameters = FromRest(schema.parameters, references)
schema.returns = Deref(schema.returns, references)
return schema
}
// prettier-ignore
function FromIntersect(schema: TIntersect, references: TSchema[]) {
schema.allOf = FromRest(schema.allOf, references)
return schema
}
// prettier-ignore
function FromUnion(schema: TUnion, references: TSchema[]) {
schema.anyOf = FromRest(schema.anyOf, references)
return schema
}
// prettier-ignore
function FromTuple(schema: TTuple, references: TSchema[]) {
if(IsUndefined(schema.items)) return schema
schema.items = FromRest(schema.items, references)
return schema
}
// prettier-ignore
function FromArray(schema: TArray, references: TSchema[]) {
schema.items = Deref(schema.items, references)
return schema
}
// prettier-ignore
function FromObject(schema: TObject, references: TSchema[]) {
schema.properties = FromProperties(schema.properties, references)
return schema
}
// prettier-ignore
function FromPromise(schema: TPromise, references: TSchema[]) {
schema.item = Deref(schema.item, references)
return schema
}
// prettier-ignore
function FromAsyncIterator(schema: TAsyncIterator, references: TSchema[]) {
schema.items = Deref(schema.items, references)
return schema
}
// prettier-ignore
function FromIterator(schema: TIterator, references: TSchema[]) {
schema.items = Deref(schema.items, references)
return schema
}
// prettier-ignore
function FromRef(schema: TRef, references: TSchema[]) {
const target = references.find(remote => remote.$id === schema.$ref)
if(target === undefined) throw Error(`Unable to dereference schema with $id ${schema.$ref}`)
const discard = Discard(target, ['$id']) as TSchema
return Deref(discard, references)
}
// prettier-ignore
export type DerefResolve<T extends TSchema> =
T extends TConstructor<infer S extends TSchema[], infer R extends TSchema> ? TConstructor<TFromRest<S>, DerefResolve<R>> :
T extends TFunction<infer S extends TSchema[], infer R extends TSchema> ? TFunction<TFromRest<S>, DerefResolve<R>> :
T extends TIntersect<infer S extends TSchema[]> ? TIntersect<TFromRest<S>> :
T extends TUnion<infer S extends TSchema[]> ? TUnion<TFromRest<S>> :
T extends TTuple<infer S extends TSchema[]> ? TTuple<TFromRest<S>> :
T extends TObject<infer S extends TProperties> ? TObject<FromProperties<S>> :
T extends TArray<infer S extends TSchema> ? TArray<DerefResolve<S>> :
T extends TPromise<infer S extends TSchema> ? TPromise<DerefResolve<S>> :
T extends TAsyncIterator<infer S extends TSchema> ? TAsyncIterator<DerefResolve<S>> :
T extends TIterator<infer S extends TSchema> ? TIterator<DerefResolve<S>> :
T extends TRef<infer S extends TSchema> ? DerefResolve<S> :
T
// prettier-ignore
export function DerefResolve<T extends TSchema>(schema: T, references: TSchema[]): TDeref<T> {
return (
IsConstructor(schema) ? FromConstructor(schema, references) :
IsFunction(schema) ? FromFunction(schema, references) :
IsIntersect(schema) ? FromIntersect(schema, references) :
IsUnion(schema) ? FromUnion(schema, references) :
IsTuple(schema) ? FromTuple(schema, references) :
IsArray(schema) ? FromArray(schema, references) :
IsObject(schema) ? FromObject(schema, references) :
IsPromise(schema) ? FromPromise(schema, references) :
IsAsyncIterator(schema) ? FromAsyncIterator(schema, references) :
IsIterator(schema) ? FromIterator(schema, references) :
IsRef(schema) ? FromRef(schema, references) :
schema
) as TDeref<T>
}
// ------------------------------------------------------------------
// TDeref
// ------------------------------------------------------------------
export type TDeref<T extends TSchema> = DerefResolve<T>
/** `[Json]` Creates a dereferenced type */
export function Deref<T extends TSchema>(schema: T, references: TSchema[]): TDeref<T> {
return DerefResolve(CloneType(schema), CloneRest(references))
}

29
src/type/deref/index.ts Normal file
View File

@@ -0,0 +1,29 @@
/*--------------------------------------------------------------------------
@sinclair/typebox/type
The MIT License (MIT)
Copyright (c) 2017-2023 Haydn Paterson (sinclair) <haydn.developer@gmail.com>
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.
---------------------------------------------------------------------------*/
export * from './deref'

View File

@@ -0,0 +1,35 @@
/*--------------------------------------------------------------------------
@sinclair/typebox/type
The MIT License (MIT)
Copyright (c) 2017-2023 Haydn Paterson (sinclair) <haydn.developer@gmail.com>
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.
---------------------------------------------------------------------------*/
function DiscardKey(value: Record<PropertyKey, any>, key: PropertyKey) {
const { [key]: _, ...rest } = value
return rest
}
export function Discard(value: Record<PropertyKey, any>, keys: PropertyKey[]) {
return keys.reduce((acc, key) => DiscardKey(acc, key), value)
}

29
src/type/discard/index.ts Normal file
View File

@@ -0,0 +1,29 @@
/*--------------------------------------------------------------------------
@sinclair/typebox/type
The MIT License (MIT)
Copyright (c) 2017-2023 Haydn Paterson (sinclair) <haydn.developer@gmail.com>
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.
---------------------------------------------------------------------------*/
export * from './discard'

58
src/type/enum/enum.ts Normal file
View File

@@ -0,0 +1,58 @@
/*--------------------------------------------------------------------------
@sinclair/typebox/type
The MIT License (MIT)
Copyright (c) 2017-2023 Haydn Paterson (sinclair) <haydn.developer@gmail.com>
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 type { TSchema, SchemaOptions } from '../schema/index'
import { Literal, type TLiteral } from '../literal/index'
import { Kind, Hint } from '../symbols/index'
import { Union } from '../union/index'
// ------------------------------------------------------------------
// ValueGuard
// ------------------------------------------------------------------
import { IsUndefined } from '../guard/value'
// ------------------------------------------------------------------
// TEnum
// ------------------------------------------------------------------
export type TEnumRecord = Record<TEnumKey, TEnumValue>
export type TEnumValue = string | number
export type TEnumKey = string
export interface TEnum<T extends Record<string, string | number> = Record<string, string | number>> extends TSchema {
[Kind]: 'Union'
[Hint]: 'Enum'
static: T[keyof T]
anyOf: TLiteral<T[keyof T]>[]
}
/** `[Json]` Creates a Enum type */
export function Enum<V extends TEnumValue, T extends Record<TEnumKey, V>>(item: T, options: SchemaOptions = {}): TEnum<T> {
if (IsUndefined(item)) throw new Error('Enum undefined or empty')
const values1 = globalThis.Object.getOwnPropertyNames(item)
.filter((key) => isNaN(key as any))
.map((key) => item[key]) as T[keyof T][]
const values2 = [...new Set(values1)]
const anyOf = values2.map((value) => Literal(value))
return Union(anyOf, { ...options, [Hint]: 'Enum' }) as unknown as TEnum<T>
}

29
src/type/enum/index.ts Normal file
View File

@@ -0,0 +1,29 @@
/*--------------------------------------------------------------------------
@sinclair/typebox/type
The MIT License (MIT)
Copyright (c) 2017-2023 Haydn Paterson (sinclair) <haydn.developer@gmail.com>
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.
---------------------------------------------------------------------------*/
export * from './enum'

34
src/type/error/error.ts Normal file
View File

@@ -0,0 +1,34 @@
/*--------------------------------------------------------------------------
@sinclair/typebox/type
The MIT License (MIT)
Copyright (c) 2017-2023 Haydn Paterson (sinclair) <haydn.developer@gmail.com>
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.
---------------------------------------------------------------------------*/
/** The base Error type thrown for all TypeBox exceptions */
export class TypeBoxError extends Error {
constructor(message: string) {
super(message)
}
}

29
src/type/error/index.ts Normal file
View File

@@ -0,0 +1,29 @@
/*--------------------------------------------------------------------------
@sinclair/typebox/type
The MIT License (MIT)
Copyright (c) 2017-2023 Haydn Paterson (sinclair) <haydn.developer@gmail.com>
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.
---------------------------------------------------------------------------*/
export * from './error'

View File

@@ -0,0 +1,89 @@
/*--------------------------------------------------------------------------
@sinclair/typebox/type
The MIT License (MIT)
Copyright (c) 2017-2023 Haydn Paterson (sinclair) <haydn.developer@gmail.com>
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 type { TSchema, SchemaOptions } from '../schema/index'
import type { TProperties } from '../object/index'
import { MappedResult, type TMappedResult } from '../mapped/index'
import { Exclude, type TExclude } from './exclude'
// ------------------------------------------------------------------
// FromProperties
// ------------------------------------------------------------------
// prettier-ignore
type TFromProperties<
K extends TProperties,
T extends TSchema
> = (
{ [K2 in keyof K]: TExclude<K[K2], T> }
)
// prettier-ignore
function FromProperties<
P extends TProperties,
T extends TSchema
>(P: P, U: T, options: SchemaOptions): TFromProperties<P, T> {
return globalThis.Object.getOwnPropertyNames(P).reduce((Acc, K2) => {
return {...Acc, [K2]: Exclude(P[K2], U, options) }
}, {}) as TFromProperties<P, T>
}
// ------------------------------------------------------------------
// FromMappedResult
// ------------------------------------------------------------------
// prettier-ignore
type TFromMappedResult<
R extends TMappedResult,
T extends TSchema
> = (
TFromProperties<R['properties'], T>
)
// prettier-ignore
function FromMappedResult<
R extends TMappedResult,
T extends TSchema
>(R: R, T: T, options: SchemaOptions): TFromMappedResult<R, T> {
return FromProperties(R.properties, T, options) as TFromMappedResult<R, T>
}
// ------------------------------------------------------------------
// ExcludeFromMappedResult
// ------------------------------------------------------------------
// prettier-ignore
export type TExcludeFromMappedResult<
R extends TMappedResult,
T extends TSchema,
P extends TProperties = TFromMappedResult<R, T>
> = (
TMappedResult<P>
)
// prettier-ignore
export function ExcludeFromMappedResult<
R extends TMappedResult,
T extends TSchema,
P extends TProperties = TFromMappedResult<R, T>
>(R: R, T: T, options: SchemaOptions): TMappedResult<P> {
const P = FromMappedResult(R, T, options) as unknown as P
return MappedResult(P)
}

View File

@@ -0,0 +1,96 @@
/*--------------------------------------------------------------------------
@sinclair/typebox/type
The MIT License (MIT)
Copyright (c) 2017-2023 Haydn Paterson (sinclair) <haydn.developer@gmail.com>
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 type { TSchema, SchemaOptions } from '../schema/index'
import type { UnionToTuple, AssertRest, AssertType, Assert } from '../helpers/index'
import type { TMappedResult } from '../mapped/index'
import { TemplateLiteralToUnion, type TTemplateLiteral } from '../template-literal/index'
import { Union, type TUnion } from '../union/index'
import { Never, type TNever } from '../never/index'
import { type TLiteral } from '../literal/index'
import { type Static } from '../static/index'
import { type TUnionEvaluated } from '../union/index'
import { ExtendsCheck, ExtendsResult } from '../extends/index'
import { CloneType } from '../clone/type'
import { ExcludeFromMappedResult, type TExcludeFromMappedResult } from './exclude-from-mapped-result'
// ------------------------------------------------------------------
// TypeGuard
// ------------------------------------------------------------------
import { IsMappedResult, IsTemplateLiteral, IsUnion } from '../guard/type'
// ------------------------------------------------------------------
// ExcludeResolve
// ------------------------------------------------------------------
// prettier-ignore
type TExcludeTemplateLiteralResult<T extends string> = TUnionEvaluated<AssertRest<UnionToTuple<{ [K in T]: TLiteral<K> }[T]>>>
// prettier-ignore
type TExcludeTemplateLiteral<T extends TTemplateLiteral, U extends TSchema> = (
Exclude<Static<T>, Static<U>> extends infer S ? TExcludeTemplateLiteralResult<Assert<S, string>> : never
)
// prettier-ignore
type TExcludeArray<T extends TSchema[], U extends TSchema> = AssertRest<UnionToTuple<{
[K in keyof T]: Static<AssertType<T[K]>> extends Static<U> ? never : T[K]
}[number]>> extends infer R extends TSchema[] ? TUnionEvaluated<R> : never
// prettier-ignore
type TExcludeResolve<T extends TSchema, U extends TSchema> =
T extends TTemplateLiteral ? TExcludeTemplateLiteral<T, U> :
T extends TUnion<infer S> ? TExcludeArray<S, U> :
T extends U
? TNever
: T
// prettier-ignore
function ExcludeResolve<L extends TSchema, R extends TSchema>(L: L, R: R): TExcludeResolve<L, R> {
return (
IsTemplateLiteral(L) ? ExcludeResolve(TemplateLiteralToUnion(L), R) :
IsTemplateLiteral(R) ? ExcludeResolve(L, TemplateLiteralToUnion(R)) :
IsUnion(L) ? (() => {
const narrowed = L.anyOf.filter((inner) => ExtendsCheck(inner, R) === ExtendsResult.False)
return (narrowed.length === 1 ? narrowed[0] : Union(narrowed))
})() :
ExtendsCheck(L, R) !== ExtendsResult.False ? Never() :
L
) as TExcludeResolve<L, R>
}
// ------------------------------------------------------------------
// TExclude
// ------------------------------------------------------------------
export type TExclude<T extends TSchema, U extends TSchema> = TExcludeResolve<T, U>
/** `[Json]` Constructs a type by excluding from unionType all union members that are assignable to excludedMembers */
export function Exclude<L extends TMappedResult, R extends TSchema>(unionType: L, excludedMembers: R, options?: SchemaOptions): TExcludeFromMappedResult<L, R>
/** `[Json]` Constructs a type by excluding from unionType all union members that are assignable to excludedMembers */
export function Exclude<L extends TSchema, R extends TSchema>(unionType: L, excludedMembers: R, options?: SchemaOptions): TExclude<L, R>
/** `[Json]` Constructs a type by excluding from unionType all union members that are assignable to excludedMembers */
export function Exclude(unionType: TSchema, excludedMembers: TSchema, options: SchemaOptions = {}) {
if (IsMappedResult(unionType)) {
return ExcludeFromMappedResult(unionType, excludedMembers, options)
} else {
const E = ExcludeResolve(unionType, excludedMembers) as any
return CloneType(E, options)
}
}

30
src/type/exclude/index.ts Normal file
View File

@@ -0,0 +1,30 @@
/*--------------------------------------------------------------------------
@sinclair/typebox/type
The MIT License (MIT)
Copyright (c) 2017-2023 Haydn Paterson (sinclair) <haydn.developer@gmail.com>
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.
---------------------------------------------------------------------------*/
export * from './exclude-from-mapped-result'
export * from './exclude'

View File

@@ -0,0 +1,776 @@
/*--------------------------------------------------------------------------
@sinclair/typebox/type
The MIT License (MIT)
Copyright (c) 2017-2023 Haydn Paterson (sinclair) <haydn.developer@gmail.com>
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 { type TAny, Any } from '../any/index'
import { type TArray } from '../array/index'
import { type TAsyncIterator } from '../async-iterator/index'
import { type TBigInt } from '../bigint/index'
import { type TBoolean } from '../boolean/index'
import { type TConstructor } from '../constructor/index'
import { type TDate } from '../date/index'
import { type TFunction, Function as FunctionType } from '../function/index'
import { type TInteger } from '../integer/index'
import { type TIntersect } from '../intersect/index'
import { type TIterator } from '../iterator/index'
import { type TLiteral } from '../literal/index'
import { type TNever } from '../never/index'
import { type TNot } from '../not/index'
import { type TNull } from '../null/index'
import { type TNumber, Number } from '../number/index'
import { type TObject } from '../object/index'
import { type TPromise } from '../promise/index'
import { type TRecord } from '../record/index'
import { type TSchema } from '../schema/index'
import { type TString, String } from '../string/index'
import { type TSymbol } from '../symbol/index'
import { type TTuple } from '../tuple/index'
import { type TUint8Array } from '../uint8array/index'
import { type TUndefined } from '../undefined/index'
import { type TUnion } from '../union/index'
import { type TUnknown, Unknown } from '../unknown/index'
import { type TVoid } from '../void/index'
import { TemplateLiteralToUnion } from '../template-literal/index'
import { PatternNumberExact, PatternStringExact } from '../patterns/index'
import { Kind, Hint } from '../symbols/index'
import { TypeBoxError } from '../error/index'
import { TypeGuard, ValueGuard } from '../guard/index'
export class ExtendsResolverError extends TypeBoxError {}
export enum ExtendsResult {
Union,
True,
False,
}
// ------------------------------------------------------------------
// IntoBooleanResult
// ------------------------------------------------------------------
// prettier-ignore
function IntoBooleanResult(result: ExtendsResult) {
return result === ExtendsResult.False ? result : ExtendsResult.True
}
// ------------------------------------------------------------------
// Throw
// ------------------------------------------------------------------
// prettier-ignore
function Throw(message: string): never {
throw new ExtendsResolverError(message)
}
// ------------------------------------------------------------------
// StructuralRight
// ------------------------------------------------------------------
// prettier-ignore
function IsStructuralRight(right: TSchema): boolean {
return (
TypeGuard.IsNever(right) ||
TypeGuard.IsIntersect(right) ||
TypeGuard.IsUnion(right) ||
TypeGuard.IsUnknown(right) ||
TypeGuard.IsAny(right)
)
}
// prettier-ignore
function StructuralRight(left: TSchema, right: TSchema) {
return (
TypeGuard.IsNever(right) ? FromNeverRight(left, right) :
TypeGuard.IsIntersect(right) ? FromIntersectRight(left, right) :
TypeGuard.IsUnion(right) ? FromUnionRight(left, right) :
TypeGuard.IsUnknown(right) ? FromUnknownRight(left, right) :
TypeGuard.IsAny(right) ? FromAnyRight(left, right) :
Throw('StructuralRight')
)
}
// ------------------------------------------------------------------
// Any
// ------------------------------------------------------------------
// prettier-ignore
function FromAnyRight(left: TSchema, right: TAny) {
return ExtendsResult.True
}
// prettier-ignore
function FromAny(left: TAny, right: TSchema) {
return (
TypeGuard.IsIntersect(right) ? FromIntersectRight(left, right) :
(TypeGuard.IsUnion(right) && right.anyOf.some((schema) => TypeGuard.IsAny(schema) || TypeGuard.IsUnknown(schema))) ? ExtendsResult.True :
TypeGuard.IsUnion(right) ? ExtendsResult.Union :
TypeGuard.IsUnknown(right) ? ExtendsResult.True :
TypeGuard.IsAny(right) ? ExtendsResult.True :
ExtendsResult.Union
)
}
// ------------------------------------------------------------------
// Array
// ------------------------------------------------------------------
// prettier-ignore
function FromArrayRight(left: TSchema, right: TArray) {
return (
TypeGuard.IsUnknown(left) ? ExtendsResult.False :
TypeGuard.IsAny(left) ? ExtendsResult.Union :
TypeGuard.IsNever(left) ? ExtendsResult.True :
ExtendsResult.False
)
}
// prettier-ignore
function FromArray(left: TArray, right: TSchema) {
return (
TypeGuard.IsObject(right) && IsObjectArrayLike(right) ? ExtendsResult.True :
IsStructuralRight(right) ? StructuralRight(left, right) :
!TypeGuard.IsArray(right) ? ExtendsResult.False :
IntoBooleanResult(Visit(left.items, right.items))
)
}
// ------------------------------------------------------------------
// AsyncIterator
// ------------------------------------------------------------------
// prettier-ignore
function FromAsyncIterator(left: TAsyncIterator, right: TSchema) {
return (
IsStructuralRight(right) ? StructuralRight(left, right) :
!TypeGuard.IsAsyncIterator(right) ? ExtendsResult.False :
IntoBooleanResult(Visit(left.items, right.items))
)
}
// ------------------------------------------------------------------
// BigInt
// ------------------------------------------------------------------
// prettier-ignore
function FromBigInt(left: TBigInt, right: TSchema): ExtendsResult {
return (
IsStructuralRight(right) ? StructuralRight(left, right) :
TypeGuard.IsObject(right) ? FromObjectRight(left, right) :
TypeGuard.IsRecord(right) ? FromRecordRight(left, right) :
TypeGuard.IsBigInt(right) ? ExtendsResult.True :
ExtendsResult.False
)
}
// ------------------------------------------------------------------
// Boolean
// ------------------------------------------------------------------
// prettier-ignore
function FromBooleanRight(left: TSchema, right: TBoolean) {
return (
TypeGuard.IsLiteralBoolean(left) ? ExtendsResult.True :
TypeGuard.IsBoolean(left) ? ExtendsResult.True :
ExtendsResult.False
)
}
// prettier-ignore
function FromBoolean(left: TBoolean, right: TSchema): ExtendsResult {
return (
IsStructuralRight(right) ? StructuralRight(left, right) :
TypeGuard.IsObject(right) ? FromObjectRight(left, right) :
TypeGuard.IsRecord(right) ? FromRecordRight(left, right) :
TypeGuard.IsBoolean(right) ? ExtendsResult.True :
ExtendsResult.False
)
}
// ------------------------------------------------------------------
// Constructor
// ------------------------------------------------------------------
// prettier-ignore
function FromConstructor(left: TConstructor, right: TSchema) {
return (
IsStructuralRight(right) ? StructuralRight(left, right) :
TypeGuard.IsObject(right) ? FromObjectRight(left, right) :
!TypeGuard.IsConstructor(right) ? ExtendsResult.False :
left.parameters.length > right.parameters.length ? ExtendsResult.False :
(!left.parameters.every((schema, index) => IntoBooleanResult(Visit(right.parameters[index], schema)) === ExtendsResult.True)) ? ExtendsResult.False :
IntoBooleanResult(Visit(left.returns, right.returns))
)
}
// ------------------------------------------------------------------
// Date
// ------------------------------------------------------------------
// prettier-ignore
function FromDate(left: TDate, right: TSchema) {
return (
IsStructuralRight(right) ? StructuralRight(left, right) :
TypeGuard.IsObject(right) ? FromObjectRight(left, right) :
TypeGuard.IsRecord(right) ? FromRecordRight(left, right) :
TypeGuard.IsDate(right) ? ExtendsResult.True :
ExtendsResult.False
)
}
// ------------------------------------------------------------------
// Function
// ------------------------------------------------------------------
// prettier-ignore
function FromFunction(left: TFunction, right: TSchema) {
return (
IsStructuralRight(right) ? StructuralRight(left, right) :
TypeGuard.IsObject(right) ? FromObjectRight(left, right) :
!TypeGuard.IsFunction(right) ? ExtendsResult.False :
left.parameters.length > right.parameters.length ? ExtendsResult.False :
(!left.parameters.every((schema, index) => IntoBooleanResult(Visit(right.parameters[index], schema)) === ExtendsResult.True)) ? ExtendsResult.False :
IntoBooleanResult(Visit(left.returns, right.returns))
)
}
// ------------------------------------------------------------------
// Integer
// ------------------------------------------------------------------
// prettier-ignore
function FromIntegerRight(left: TSchema, right: TInteger) {
return (
TypeGuard.IsLiteral(left) && ValueGuard.IsNumber(left.const) ? ExtendsResult.True :
TypeGuard.IsNumber(left) || TypeGuard.IsInteger(left) ? ExtendsResult.True :
ExtendsResult.False
)
}
// prettier-ignore
function FromInteger(left: TInteger, right: TSchema): ExtendsResult {
return (
TypeGuard.IsInteger(right) || TypeGuard.IsNumber(right) ? ExtendsResult.True :
IsStructuralRight(right) ? StructuralRight(left, right) :
TypeGuard.IsObject(right) ? FromObjectRight(left, right) :
TypeGuard.IsRecord(right) ? FromRecordRight(left, right) :
ExtendsResult.False
)
}
// ------------------------------------------------------------------
// Intersect
// ------------------------------------------------------------------
// prettier-ignore
function FromIntersectRight(left: TSchema, right: TIntersect): ExtendsResult {
return right.allOf.every((schema) => Visit(left, schema) === ExtendsResult.True)
? ExtendsResult.True
: ExtendsResult.False
}
// prettier-ignore
function FromIntersect(left: TIntersect, right: TSchema) {
return left.allOf.some((schema) => Visit(schema, right) === ExtendsResult.True)
? ExtendsResult.True
: ExtendsResult.False
}
// ------------------------------------------------------------------
// Iterator
// ------------------------------------------------------------------
// prettier-ignore
function FromIterator(left: TIterator, right: TSchema) {
return (
IsStructuralRight(right) ? StructuralRight(left, right) :
!TypeGuard.IsIterator(right) ? ExtendsResult.False :
IntoBooleanResult(Visit(left.items, right.items))
)
}
// ------------------------------------------------------------------
// Literal
// ------------------------------------------------------------------
// prettier-ignore
function FromLiteral(left: TLiteral, right: TSchema): ExtendsResult {
return (
TypeGuard.IsLiteral(right) && right.const === left.const ? ExtendsResult.True :
IsStructuralRight(right) ? StructuralRight(left, right) :
TypeGuard.IsObject(right) ? FromObjectRight(left, right) :
TypeGuard.IsRecord(right) ? FromRecordRight(left, right) :
TypeGuard.IsString(right) ? FromStringRight(left, right) :
TypeGuard.IsNumber(right) ? FromNumberRight(left, right) :
TypeGuard.IsInteger(right) ? FromIntegerRight(left, right) :
TypeGuard.IsBoolean(right) ? FromBooleanRight(left, right) :
ExtendsResult.False
)
}
// ------------------------------------------------------------------
// Never
// ------------------------------------------------------------------
// prettier-ignore
function FromNeverRight(left: TSchema, right: TNever) {
return ExtendsResult.False
}
// prettier-ignore
function FromNever(left: TNever, right: TSchema) {
return ExtendsResult.True
}
// ------------------------------------------------------------------
// Not
// ------------------------------------------------------------------
// prettier-ignore
function UnwrapTNot<T extends TNot>(schema: T): TUnknown | TNot['not'] {
let [current, depth]: [TSchema, number] = [schema, 0]
while (true) {
if (!TypeGuard.IsNot(current)) break
current = current.not
depth += 1
}
return depth % 2 === 0 ? current : Unknown()
}
// prettier-ignore
function FromNot(left: TSchema, right: TSchema) {
// TypeScript has no concept of negated types, and attempts to correctly check the negated
// type at runtime would put TypeBox at odds with TypeScripts ability to statically infer
// the type. Instead we unwrap to either unknown or T and continue evaluating.
// prettier-ignore
return (
TypeGuard.IsNot(left) ? Visit(UnwrapTNot(left), right) :
TypeGuard.IsNot(right) ? Visit(left, UnwrapTNot(right)) :
Throw('Invalid fallthrough for Not')
)
}
// ------------------------------------------------------------------
// Null
// ------------------------------------------------------------------
// prettier-ignore
function FromNull(left: TNull, right: TSchema) {
return (
IsStructuralRight(right) ? StructuralRight(left, right) :
TypeGuard.IsObject(right) ? FromObjectRight(left, right) :
TypeGuard.IsRecord(right) ? FromRecordRight(left, right) :
TypeGuard.IsNull(right) ? ExtendsResult.True :
ExtendsResult.False
)
}
// ------------------------------------------------------------------
// Number
// ------------------------------------------------------------------
// prettier-ignore
function FromNumberRight(left: TSchema, right: TNumber) {
return (
TypeGuard.IsLiteralNumber(left) ? ExtendsResult.True :
TypeGuard.IsNumber(left) || TypeGuard.IsInteger(left) ? ExtendsResult.True :
ExtendsResult.False
)
}
// prettier-ignore
function FromNumber(left: TNumber, right: TSchema): ExtendsResult {
return (
IsStructuralRight(right) ? StructuralRight(left, right) :
TypeGuard.IsObject(right) ? FromObjectRight(left, right) :
TypeGuard.IsRecord(right) ? FromRecordRight(left, right) :
TypeGuard.IsInteger(right) || TypeGuard.IsNumber(right) ? ExtendsResult.True :
ExtendsResult.False
)
}
// ------------------------------------------------------------------
// Object
// ------------------------------------------------------------------
// prettier-ignore
function IsObjectPropertyCount(schema: TObject, count: number) {
return Object.getOwnPropertyNames(schema.properties).length === count
}
// prettier-ignore
function IsObjectStringLike(schema: TObject) {
return IsObjectArrayLike(schema)
}
// prettier-ignore
function IsObjectSymbolLike(schema: TObject) {
return IsObjectPropertyCount(schema, 0) || (
IsObjectPropertyCount(schema, 1) && 'description' in schema.properties && TypeGuard.IsUnion(schema.properties.description) && schema.properties.description.anyOf.length === 2 && ((
TypeGuard.IsString(schema.properties.description.anyOf[0]) &&
TypeGuard.IsUndefined(schema.properties.description.anyOf[1])
) || (
TypeGuard.IsString(schema.properties.description.anyOf[1]) &&
TypeGuard.IsUndefined(schema.properties.description.anyOf[0])
))
)
}
// prettier-ignore
function IsObjectNumberLike(schema: TObject) {
return IsObjectPropertyCount(schema, 0)
}
// prettier-ignore
function IsObjectBooleanLike(schema: TObject) {
return IsObjectPropertyCount(schema, 0)
}
// prettier-ignore
function IsObjectBigIntLike(schema: TObject) {
return IsObjectPropertyCount(schema, 0)
}
// prettier-ignore
function IsObjectDateLike(schema: TObject) {
return IsObjectPropertyCount(schema, 0)
}
// prettier-ignore
function IsObjectUint8ArrayLike(schema: TObject) {
return IsObjectArrayLike(schema)
}
// prettier-ignore
function IsObjectFunctionLike(schema: TObject) {
const length = Number()
return IsObjectPropertyCount(schema, 0) || (IsObjectPropertyCount(schema, 1) && 'length' in schema.properties && IntoBooleanResult(Visit(schema.properties['length'], length)) === ExtendsResult.True)
}
// prettier-ignore
function IsObjectConstructorLike(schema: TObject) {
return IsObjectPropertyCount(schema, 0)
}
// prettier-ignore
function IsObjectArrayLike(schema: TObject) {
const length = Number()
return IsObjectPropertyCount(schema, 0) || (IsObjectPropertyCount(schema, 1) && 'length' in schema.properties && IntoBooleanResult(Visit(schema.properties['length'], length)) === ExtendsResult.True)
}
// prettier-ignore
function IsObjectPromiseLike(schema: TObject) {
const then = FunctionType([Any()], Any())
return IsObjectPropertyCount(schema, 0) || (IsObjectPropertyCount(schema, 1) && 'then' in schema.properties && IntoBooleanResult(Visit(schema.properties['then'], then)) === ExtendsResult.True)
}
// ------------------------------------------------------------------
// Property
// ------------------------------------------------------------------
// prettier-ignore
function Property(left: TSchema, right: TSchema) {
return (
Visit(left, right) === ExtendsResult.False ? ExtendsResult.False :
TypeGuard.IsOptional(left) && !TypeGuard.IsOptional(right) ? ExtendsResult.False :
ExtendsResult.True
)
}
// prettier-ignore
function FromObjectRight(left: TSchema, right: TObject) {
return (
TypeGuard.IsUnknown(left) ? ExtendsResult.False :
TypeGuard.IsAny(left) ? ExtendsResult.Union : (
TypeGuard.IsNever(left) ||
(TypeGuard.IsLiteralString(left) && IsObjectStringLike(right)) ||
(TypeGuard.IsLiteralNumber(left) && IsObjectNumberLike(right)) ||
(TypeGuard.IsLiteralBoolean(left) && IsObjectBooleanLike(right)) ||
(TypeGuard.IsSymbol(left) && IsObjectSymbolLike(right)) ||
(TypeGuard.IsBigInt(left) && IsObjectBigIntLike(right)) ||
(TypeGuard.IsString(left) && IsObjectStringLike(right)) ||
(TypeGuard.IsSymbol(left) && IsObjectSymbolLike(right)) ||
(TypeGuard.IsNumber(left) && IsObjectNumberLike(right)) ||
(TypeGuard.IsInteger(left) && IsObjectNumberLike(right)) ||
(TypeGuard.IsBoolean(left) && IsObjectBooleanLike(right)) ||
(TypeGuard.IsUint8Array(left) && IsObjectUint8ArrayLike(right)) ||
(TypeGuard.IsDate(left) && IsObjectDateLike(right)) ||
(TypeGuard.IsConstructor(left) && IsObjectConstructorLike(right)) ||
(TypeGuard.IsFunction(left) && IsObjectFunctionLike(right))
) ? ExtendsResult.True :
(TypeGuard.IsRecord(left) && TypeGuard.IsString(RecordKey(left))) ? (() => {
// When expressing a Record with literal key values, the Record is converted into a Object with
// the Hint assigned as `Record`. This is used to invert the extends logic.
return right[Hint] === 'Record' ? ExtendsResult.True : ExtendsResult.False
})() :
(TypeGuard.IsRecord(left) && TypeGuard.IsNumber(RecordKey(left))) ? (() => {
return IsObjectPropertyCount(right, 0) ? ExtendsResult.True : ExtendsResult.False
})() :
ExtendsResult.False
)
}
// prettier-ignore
function FromObject(left: TObject, right: TSchema) {
return (
IsStructuralRight(right) ? StructuralRight(left, right) :
TypeGuard.IsRecord(right) ? FromRecordRight(left, right) :
!TypeGuard.IsObject(right) ? ExtendsResult.False :
(() => {
for (const key of Object.getOwnPropertyNames(right.properties)) {
if (!(key in left.properties) && !TypeGuard.IsOptional(right.properties[key])) {
return ExtendsResult.False
}
if (TypeGuard.IsOptional(right.properties[key])) {
return ExtendsResult.True
}
if (Property(left.properties[key], right.properties[key]) === ExtendsResult.False) {
return ExtendsResult.False
}
}
return ExtendsResult.True
})()
)
}
// ------------------------------------------------------------------
// Promise
// ------------------------------------------------------------------
// prettier-ignore
function FromPromise(left: TPromise, right: TSchema) {
return (
IsStructuralRight(right) ? StructuralRight(left, right) :
TypeGuard.IsObject(right) && IsObjectPromiseLike(right) ? ExtendsResult.True :
!TypeGuard.IsPromise(right) ? ExtendsResult.False :
IntoBooleanResult(Visit(left.item, right.item))
)
}
// ------------------------------------------------------------------
// Record
// ------------------------------------------------------------------
// prettier-ignore
function RecordKey(schema: TRecord) {
return (
PatternNumberExact in schema.patternProperties ? Number() :
PatternStringExact in schema.patternProperties ? String() :
Throw('Unknown record key pattern')
)
}
// prettier-ignore
function RecordValue(schema: TRecord) {
return (
PatternNumberExact in schema.patternProperties ? schema.patternProperties[PatternNumberExact] :
PatternStringExact in schema.patternProperties ? schema.patternProperties[PatternStringExact] :
Throw('Unable to get record value schema')
)
}
// prettier-ignore
function FromRecordRight(left: TSchema, right: TRecord) {
const [Key, Value] = [RecordKey(right), RecordValue(right)]
return (
(
TypeGuard.IsLiteralString(left) && TypeGuard.IsNumber(Key) && IntoBooleanResult(Visit(left, Value)) === ExtendsResult.True) ? ExtendsResult.True :
TypeGuard.IsUint8Array(left) && TypeGuard.IsNumber(Key) ? Visit(left, Value) :
TypeGuard.IsString(left) && TypeGuard.IsNumber(Key) ? Visit(left, Value) :
TypeGuard.IsArray(left) && TypeGuard.IsNumber(Key) ? Visit(left, Value) :
TypeGuard.IsObject(left) ? (() => {
for (const key of Object.getOwnPropertyNames(left.properties)) {
if (Property(Value, left.properties[key]) === ExtendsResult.False) {
return ExtendsResult.False
}
}
return ExtendsResult.True
})() :
ExtendsResult.False
)
}
// prettier-ignore
function FromRecord(left: TRecord, right: TSchema) {
return (
IsStructuralRight(right) ? StructuralRight(left, right) :
TypeGuard.IsObject(right) ? FromObjectRight(left, right) :
!TypeGuard.IsRecord(right) ? ExtendsResult.False :
Visit(RecordValue(left), RecordValue(right))
)
}
// ------------------------------------------------------------------
// RegExp
// ------------------------------------------------------------------
// prettier-ignore
function FromRegExp(left: TSchema, right: TSchema) {
// Note: RegExp types evaluate as strings, not RegExp objects.
// Here we remap either into string and continue evaluating.
const L = TypeGuard.IsRegExp(left) ? String() : left
const R = TypeGuard.IsRegExp(right) ? String() : right
return Visit(L, R)
}
// ------------------------------------------------------------------
// String
// ------------------------------------------------------------------
// prettier-ignore
function FromStringRight(left: TSchema, right: TString) {
return (
TypeGuard.IsLiteral(left) && ValueGuard.IsString(left.const) ? ExtendsResult.True :
TypeGuard.IsString(left) ? ExtendsResult.True :
ExtendsResult.False
)
}
// prettier-ignore
function FromString(left: TString, right: TSchema): ExtendsResult {
return (
IsStructuralRight(right) ? StructuralRight(left, right) :
TypeGuard.IsObject(right) ? FromObjectRight(left, right) :
TypeGuard.IsRecord(right) ? FromRecordRight(left, right) :
TypeGuard.IsString(right) ? ExtendsResult.True :
ExtendsResult.False
)
}
// ------------------------------------------------------------------
// Symbol
// ------------------------------------------------------------------
// prettier-ignore
function FromSymbol(left: TSymbol, right: TSchema): ExtendsResult {
return (
IsStructuralRight(right) ? StructuralRight(left, right) :
TypeGuard.IsObject(right) ? FromObjectRight(left, right) :
TypeGuard.IsRecord(right) ? FromRecordRight(left, right) :
TypeGuard.IsSymbol(right) ? ExtendsResult.True :
ExtendsResult.False
)
}
// ------------------------------------------------------------------
// TemplateLiteral
// ------------------------------------------------------------------
// prettier-ignore
function FromTemplateLiteral(left: TSchema, right: TSchema) {
// TemplateLiteral types are resolved to either unions for finite expressions or string
// for infinite expressions. Here we call to TemplateLiteralResolver to resolve for
// either type and continue evaluating.
return (
TypeGuard.IsTemplateLiteral(left) ? Visit(TemplateLiteralToUnion(left), right) :
TypeGuard.IsTemplateLiteral(right) ? Visit(left, TemplateLiteralToUnion(right)) :
Throw('Invalid fallthrough for TemplateLiteral')
)
}
// ------------------------------------------------------------------
// Tuple
// ------------------------------------------------------------------
// prettier-ignore
function IsArrayOfTuple(left: TTuple, right: TSchema) {
return (
TypeGuard.IsArray(right) &&
left.items !== undefined &&
left.items.every((schema) => Visit(schema, right.items) === ExtendsResult.True)
)
}
// prettier-ignore
function FromTupleRight(left: TSchema, right: TTuple) {
return (
TypeGuard.IsNever(left) ? ExtendsResult.True :
TypeGuard.IsUnknown(left) ? ExtendsResult.False :
TypeGuard.IsAny(left) ? ExtendsResult.Union :
ExtendsResult.False
)
}
// prettier-ignore
function FromTuple(left: TTuple, right: TSchema): ExtendsResult {
return (
IsStructuralRight(right) ? StructuralRight(left, right) :
TypeGuard.IsObject(right) && IsObjectArrayLike(right) ? ExtendsResult.True :
TypeGuard.IsArray(right) && IsArrayOfTuple(left, right) ? ExtendsResult.True :
!TypeGuard.IsTuple(right) ? ExtendsResult.False :
(ValueGuard.IsUndefined(left.items) && !ValueGuard.IsUndefined(right.items)) || (!ValueGuard.IsUndefined(left.items) && ValueGuard.IsUndefined(right.items)) ? ExtendsResult.False :
(ValueGuard.IsUndefined(left.items) && !ValueGuard.IsUndefined(right.items)) ? ExtendsResult.True :
left.items!.every((schema, index) => Visit(schema, right.items![index]) === ExtendsResult.True) ? ExtendsResult.True :
ExtendsResult.False
)
}
// ------------------------------------------------------------------
// Uint8Array
// ------------------------------------------------------------------
// prettier-ignore
function FromUint8Array(left: TUint8Array, right: TSchema) {
return (
IsStructuralRight(right) ? StructuralRight(left, right) :
TypeGuard.IsObject(right) ? FromObjectRight(left, right) :
TypeGuard.IsRecord(right) ? FromRecordRight(left, right) :
TypeGuard.IsUint8Array(right) ? ExtendsResult.True :
ExtendsResult.False
)
}
// ------------------------------------------------------------------
// Undefined
// ------------------------------------------------------------------
// prettier-ignore
function FromUndefined(left: TUndefined, right: TSchema) {
return (
IsStructuralRight(right) ? StructuralRight(left, right) :
TypeGuard.IsObject(right) ? FromObjectRight(left, right) :
TypeGuard.IsRecord(right) ? FromRecordRight(left, right) :
TypeGuard.IsVoid(right) ? FromVoidRight(left, right) :
TypeGuard.IsUndefined(right) ? ExtendsResult.True :
ExtendsResult.False
)
}
// ------------------------------------------------------------------
// Union
// ------------------------------------------------------------------
// prettier-ignore
function FromUnionRight(left: TSchema, right: TUnion): ExtendsResult {
return right.anyOf.some((schema) => Visit(left, schema) === ExtendsResult.True)
? ExtendsResult.True
: ExtendsResult.False
}
// prettier-ignore
function FromUnion(left: TUnion, right: TSchema): ExtendsResult {
return left.anyOf.every((schema) => Visit(schema, right) === ExtendsResult.True)
? ExtendsResult.True
: ExtendsResult.False
}
// ------------------------------------------------------------------
// Unknown
// ------------------------------------------------------------------
// prettier-ignore
function FromUnknownRight(left: TSchema, right: TUnknown) {
return ExtendsResult.True
}
// prettier-ignore
function FromUnknown(left: TUnknown, right: TSchema) {
return (
TypeGuard.IsNever(right) ? FromNeverRight(left, right) :
TypeGuard.IsIntersect(right) ? FromIntersectRight(left, right) :
TypeGuard.IsUnion(right) ? FromUnionRight(left, right) :
TypeGuard.IsAny(right) ? FromAnyRight(left, right) :
TypeGuard.IsString(right) ? FromStringRight(left, right) :
TypeGuard.IsNumber(right) ? FromNumberRight(left, right) :
TypeGuard.IsInteger(right) ? FromIntegerRight(left, right) :
TypeGuard.IsBoolean(right) ? FromBooleanRight(left, right) :
TypeGuard.IsArray(right) ? FromArrayRight(left, right) :
TypeGuard.IsTuple(right) ? FromTupleRight(left, right) :
TypeGuard.IsObject(right) ? FromObjectRight(left, right) :
TypeGuard.IsUnknown(right) ? ExtendsResult.True :
ExtendsResult.False
)
}
// ------------------------------------------------------------------
// Void
// ------------------------------------------------------------------
// prettier-ignore
function FromVoidRight(left: TSchema, right: TVoid) {
return (
TypeGuard.IsUndefined(left) ? ExtendsResult.True :
TypeGuard.IsUndefined(left) ? ExtendsResult.True :
ExtendsResult.False
)
}
// prettier-ignore
function FromVoid(left: TVoid, right: TSchema) {
return (
TypeGuard.IsIntersect(right) ? FromIntersectRight(left, right) :
TypeGuard.IsUnion(right) ? FromUnionRight(left, right) :
TypeGuard.IsUnknown(right) ? FromUnknownRight(left, right) :
TypeGuard.IsAny(right) ? FromAnyRight(left, right) :
TypeGuard.IsObject(right) ? FromObjectRight(left, right) :
TypeGuard.IsVoid(right) ? ExtendsResult.True :
ExtendsResult.False
)
}
// prettier-ignore
function Visit(left: TSchema, right: TSchema): ExtendsResult {
return (
// resolvable
(TypeGuard.IsTemplateLiteral(left) || TypeGuard.IsTemplateLiteral(right)) ? FromTemplateLiteral(left, right) :
(TypeGuard.IsRegExp(left) || TypeGuard.IsRegExp(right)) ? FromRegExp(left, right) :
(TypeGuard.IsNot(left) || TypeGuard.IsNot(right)) ? FromNot(left, right) :
// standard
TypeGuard.IsAny(left) ? FromAny(left, right) :
TypeGuard.IsArray(left) ? FromArray(left, right) :
TypeGuard.IsBigInt(left) ? FromBigInt(left, right) :
TypeGuard.IsBoolean(left) ? FromBoolean(left, right) :
TypeGuard.IsAsyncIterator(left) ? FromAsyncIterator(left, right) :
TypeGuard.IsConstructor(left) ? FromConstructor(left, right) :
TypeGuard.IsDate(left) ? FromDate(left, right) :
TypeGuard.IsFunction(left) ? FromFunction(left, right) :
TypeGuard.IsInteger(left) ? FromInteger(left, right) :
TypeGuard.IsIntersect(left) ? FromIntersect(left, right) :
TypeGuard.IsIterator(left) ? FromIterator(left, right) :
TypeGuard.IsLiteral(left) ? FromLiteral(left, right) :
TypeGuard.IsNever(left) ? FromNever(left, right) :
TypeGuard.IsNull(left) ? FromNull(left, right) :
TypeGuard.IsNumber(left) ? FromNumber(left, right) :
TypeGuard.IsObject(left) ? FromObject(left, right) :
TypeGuard.IsRecord(left) ? FromRecord(left, right) :
TypeGuard.IsString(left) ? FromString(left, right) :
TypeGuard.IsSymbol(left) ? FromSymbol(left, right) :
TypeGuard.IsTuple(left) ? FromTuple(left, right) :
TypeGuard.IsPromise(left) ? FromPromise(left, right) :
TypeGuard.IsUint8Array(left) ? FromUint8Array(left, right) :
TypeGuard.IsUndefined(left) ? FromUndefined(left, right) :
TypeGuard.IsUnion(left) ? FromUnion(left, right) :
TypeGuard.IsUnknown(left) ? FromUnknown(left, right) :
TypeGuard.IsVoid(left) ? FromVoid(left, right) :
Throw(`Unknown left type operand '${left[Kind]}'`)
)
}
export function ExtendsCheck(left: TSchema, right: TSchema): ExtendsResult {
return Visit(left, right)
}

View File

@@ -0,0 +1,129 @@
/*--------------------------------------------------------------------------
@sinclair/typebox/type
The MIT License (MIT)
Copyright (c) 2017-2023 Haydn Paterson (sinclair) <haydn.developer@gmail.com>
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 type { TSchema, SchemaOptions } from '../schema/index'
import type { TProperties } from '../object/index'
import type { Assert } from '../helpers/index'
import { MappedResult, type TMappedResult, type TMappedKey } from '../mapped/index'
import { Literal, type TLiteral, type TLiteralValue } from '../literal/index'
import { Extends, type TExtends } from './extends'
// ------------------------------------------------------------------
// FromPropertyKey
// ------------------------------------------------------------------
// prettier-ignore
type TFromPropertyKey<
K extends PropertyKey,
U extends TSchema,
L extends TSchema,
R extends TSchema
> = {
[_ in K]: TExtends<TLiteral<Assert<K, TLiteralValue>>, U, L, R>
}
// prettier-ignore
function FromPropertyKey<
K extends PropertyKey,
U extends TSchema,
L extends TSchema,
R extends TSchema
>(K: K, U: U, L: L, R: R, options: SchemaOptions): TFromPropertyKey<K, U, L, R> {
return {
[K]: Extends(Literal(K as TLiteralValue), U, L, R, options) as any
} as TFromPropertyKey<K, U, L, R>
}
// ------------------------------------------------------------------
// FromPropertyKeys
// ------------------------------------------------------------------
// prettier-ignore
type TFromPropertyKeys<
K extends PropertyKey[],
U extends TSchema,
L extends TSchema,
R extends TSchema,
Acc extends TProperties = {}
> = (
K extends [infer LK extends PropertyKey, ...infer RK extends PropertyKey[]]
? TFromPropertyKeys<RK, U, L, R, Acc & TFromPropertyKey<LK, U, L, R>>
: Acc
)
// prettier-ignore
function FromPropertyKeys<
K extends PropertyKey[],
U extends TSchema,
L extends TSchema,
R extends TSchema
>(K: [...K], U: U, L: L, R: R, options: SchemaOptions): TFromPropertyKeys<K, U, L, R> {
return K.reduce((Acc, LK) => {
return { ...Acc, ...FromPropertyKey(LK, U, L, R, options) }
}, {} as TProperties) as TFromPropertyKeys<K, U, L, R>
}
// ------------------------------------------------------------------
// FromMappedKey
// ------------------------------------------------------------------
// prettier-ignore
type TFromMappedKey<
K extends TMappedKey,
U extends TSchema,
L extends TSchema,
R extends TSchema
> = (
TFromPropertyKeys<K['keys'], U, L, R>
)
// prettier-ignore
function FromMappedKey<
K extends TMappedKey,
U extends TSchema,
L extends TSchema,
R extends TSchema
>(K: K, U: U, L: L, R: R, options: SchemaOptions): TFromMappedKey<K, U, L, R> {
return FromPropertyKeys(K.keys, U, L, R, options) as TFromMappedKey<K, U, L, R>
}
// ------------------------------------------------------------------
// ExtendsFromMappedKey
// ------------------------------------------------------------------
// prettier-ignore
export type TExtendsFromMappedKey<
T extends TMappedKey,
U extends TSchema,
L extends TSchema,
R extends TSchema,
P extends TProperties = TFromMappedKey<T, U, L, R>
> = (
TMappedResult<P>
)
// prettier-ignore
export function ExtendsFromMappedKey<
T extends TMappedKey,
U extends TSchema,
L extends TSchema,
R extends TSchema,
P extends TProperties = TFromMappedKey<T, U, L, R>
>(T: T, U: U, L: L, R: R, options: SchemaOptions): TMappedResult<P> {
const P = FromMappedKey(T, U, L, R, options) as unknown as P
return MappedResult(P)
}

View File

@@ -0,0 +1,101 @@
/*--------------------------------------------------------------------------
@sinclair/typebox/type
The MIT License (MIT)
Copyright (c) 2017-2023 Haydn Paterson (sinclair) <haydn.developer@gmail.com>
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 type { TSchema, SchemaOptions } from '../schema/index'
import type { TProperties } from '../object/index'
import { MappedResult, type TMappedResult } from '../mapped/index'
import { Extends, type TExtends } from './extends'
// ------------------------------------------------------------------
// FromProperties
// ------------------------------------------------------------------
// prettier-ignore
type TFromProperties<
P extends TProperties,
Right extends TSchema,
False extends TSchema,
True extends TSchema
> = (
{ [K2 in keyof P]: TExtends<P[K2], Right, False, True> }
)
// prettier-ignore
function FromProperties<
P extends TProperties,
Right extends TSchema,
True extends TSchema,
False extends TSchema
>(P: P, Right: Right, True: True, False: False, options: SchemaOptions): TFromProperties<P, Right, True, False> {
return globalThis.Object.getOwnPropertyNames(P).reduce((Acc, K2) => {
return {...Acc, [K2]: Extends(P[K2], Right, True, False, options) }
}, {}) as TFromProperties<P, Right, True, False>
}
// ------------------------------------------------------------------
// FromMappedResult
// ------------------------------------------------------------------
// prettier-ignore
type TFromMappedResult<
Left extends TMappedResult,
Right extends TSchema,
True extends TSchema,
False extends TSchema
> = (
TFromProperties<Left['properties'], Right, True, False>
)
// prettier-ignore
function FromMappedResult<
Left extends TMappedResult,
Right extends TSchema,
True extends TSchema,
False extends TSchema
>(Left: Left, Right: Right, True: True, False: False, options: SchemaOptions): TFromMappedResult<Left, Right, True, False> {
return FromProperties(Left.properties, Right, True, False, options) as TFromMappedResult<Left, Right, True, False>
}
// ------------------------------------------------------------------
// ExtendsFromMappedResult
// ------------------------------------------------------------------
// prettier-ignore
export type TExtendsFromMappedResult<
Left extends TMappedResult,
Right extends TSchema,
True extends TSchema,
False extends TSchema,
P extends TProperties = TFromMappedResult<Left, Right, True, False>
> = (
TMappedResult<P>
)
// prettier-ignore
export function ExtendsFromMappedResult<
Left extends TMappedResult,
Right extends TSchema,
True extends TSchema,
False extends TSchema,
P extends TProperties = TFromMappedResult<Left, Right, True, False>
>(Left: Left, Right: Right, True: True, False: False, options: SchemaOptions): TMappedResult<P> {
const P = FromMappedResult(Left, Right, True, False, options) as unknown as P
return MappedResult(P)
}

View File

@@ -0,0 +1,55 @@
/*--------------------------------------------------------------------------
@sinclair/typebox/type
The MIT License (MIT)
Copyright (c) 2017-2023 Haydn Paterson (sinclair) <haydn.developer@gmail.com>
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 type { TSchema } from '../schema/index'
import type { TIntersect } from '../intersect/index'
import type { TUnion } from '../union/index'
import type { TNot } from '../not/index'
import { Kind } from '../symbols/index'
/** Fast undefined check used for properties of type undefined */
function Intersect(schema: TIntersect) {
return schema.allOf.every((schema) => ExtendsUndefinedCheck(schema))
}
function Union(schema: TUnion) {
return schema.anyOf.some((schema) => ExtendsUndefinedCheck(schema))
}
function Not(schema: TNot) {
return !ExtendsUndefinedCheck(schema.not)
}
/** Fast undefined check used for properties of type undefined */
// prettier-ignore
export function ExtendsUndefinedCheck(schema: TSchema): boolean {
return (
schema[Kind] === 'Intersect' ? Intersect(schema as TIntersect) :
schema[Kind] === 'Union' ? Union(schema as TUnion) :
schema[Kind] === 'Not' ? Not(schema as TNot) :
schema[Kind] === 'Undefined' ? true :
false
)
}

View File

@@ -0,0 +1,80 @@
/*--------------------------------------------------------------------------
@sinclair/typebox/type
The MIT License (MIT)
Copyright (c) 2017-2023 Haydn Paterson (sinclair) <haydn.developer@gmail.com>
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 type { TSchema, SchemaOptions } from '../schema/index'
import type { Static } from '../static/index'
import { type TUnion, Union } from '../union/index'
import { TMappedKey, TMappedResult } from '../mapped/index'
import { ExtendsCheck, ExtendsResult } from './extends-check'
import { UnionToTuple } from '../helpers/index'
import { CloneType } from '../clone/type'
import { ExtendsFromMappedKey, type TExtendsFromMappedKey } from './extends-from-mapped-key'
import { ExtendsFromMappedResult, type TExtendsFromMappedResult } from './extends-from-mapped-result'
// ------------------------------------------------------------------
// TypeGuard
// ------------------------------------------------------------------
import { IsMappedKey, IsMappedResult } from '../guard/type'
// prettier-ignore
type TExtendsResolve<L extends TSchema, R extends TSchema, T extends TSchema, U extends TSchema> = (
(Static<L> extends Static<R> ? T : U) extends infer O extends TSchema ?
UnionToTuple<O> extends [infer X extends TSchema, infer Y extends TSchema]
? TUnion<[X, Y]>
: O
: never
)
// prettier-ignore
function ExtendsResolve<L extends TSchema, R extends TSchema, T extends TSchema, U extends TSchema>(left: L, right: R, trueType: T, falseType: U): TExtendsResolve<L, R, T, U> {
const R = ExtendsCheck(left, right)
return (
R === ExtendsResult.Union ? Union([trueType, falseType]) :
R === ExtendsResult.True ? trueType :
falseType
) as unknown as TExtendsResolve<L, R, T, U>
}
// ------------------------------------------------------------------
// TExtends
// ------------------------------------------------------------------
export type TExtends<L extends TSchema, R extends TSchema, T extends TSchema, F extends TSchema> = TExtendsResolve<L, R, T, F>
/** `[Json]` Creates a Conditional type */
export function Extends<L extends TMappedResult, R extends TSchema, T extends TSchema, F extends TSchema>(L: L, R: R, T: T, F: F, options?: SchemaOptions): TExtendsFromMappedResult<L, R, T, F>
/** `[Json]` Creates a Conditional type */
export function Extends<L extends TMappedKey, R extends TSchema, T extends TSchema, F extends TSchema>(L: L, R: R, T: T, F: F, options?: SchemaOptions): TExtendsFromMappedKey<L, R, T, F>
/** `[Json]` Creates a Conditional type */
export function Extends<L extends TSchema, R extends TSchema, T extends TSchema, F extends TSchema>(L: L, R: R, T: T, F: F, options?: SchemaOptions): TExtends<L, R, T, F>
/** `[Json]` Creates a Conditional type */
export function Extends<L extends TSchema, R extends TSchema, T extends TSchema, F extends TSchema>(L: L, R: R, T: T, F: F, options: SchemaOptions = {}) {
// prettier-ignore
return (
IsMappedResult(L) ? ExtendsFromMappedResult(L, R, T, F, options) :
IsMappedKey(L) ? CloneType(ExtendsFromMappedKey(L, R, T, F, options)) :
CloneType(ExtendsResolve(L, R, T, F), options)
) as TExtends<L, R, T, F>
}

33
src/type/extends/index.ts Normal file
View File

@@ -0,0 +1,33 @@
/*--------------------------------------------------------------------------
@sinclair/typebox/type
The MIT License (MIT)
Copyright (c) 2017-2023 Haydn Paterson (sinclair) <haydn.developer@gmail.com>
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.
---------------------------------------------------------------------------*/
export * from './extends-check'
export * from './extends-from-mapped-key'
export * from './extends-from-mapped-result'
export * from './extends-undefined'
export * from './extends'

View File

@@ -0,0 +1,89 @@
/*--------------------------------------------------------------------------
@sinclair/typebox/type
The MIT License (MIT)
Copyright (c) 2017-2023 Haydn Paterson (sinclair) <haydn.developer@gmail.com>
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 type { TSchema, SchemaOptions } from '../schema/index'
import type { TProperties } from '../object/index'
import { MappedResult, type TMappedResult } from '../mapped/index'
import { Extract, type TExtract } from './extract'
// ------------------------------------------------------------------
// FromProperties
// ------------------------------------------------------------------
// prettier-ignore
type TFromProperties<
P extends TProperties,
T extends TSchema
> = (
{ [K2 in keyof P]: TExtract<P[K2], T> }
)
// prettier-ignore
function FromProperties<
P extends TProperties,
T extends TSchema
>(P: P, T: T, options: SchemaOptions): TFromProperties<P, T> {
return globalThis.Object.getOwnPropertyNames(P).reduce((Acc, K2) => {
return {...Acc, [K2]: Extract(P[K2], T, options) }
}, {}) as TFromProperties<P, T>
}
// ------------------------------------------------------------------
// FromMappedResult
// ------------------------------------------------------------------
// prettier-ignore
type TFromMappedResult<
R extends TMappedResult,
T extends TSchema
> = (
TFromProperties<R['properties'], T>
)
// prettier-ignore
function FromMappedResult<
R extends TMappedResult,
T extends TSchema
>(R: R, T: T, options: SchemaOptions): TFromMappedResult<R, T> {
return FromProperties(R.properties, T, options) as TFromMappedResult<R, T>
}
// ------------------------------------------------------------------
// ExtractFromMappedResult
// ------------------------------------------------------------------
// prettier-ignore
export type TExtractFromMappedResult<
R extends TMappedResult,
T extends TSchema,
P extends TProperties = TFromMappedResult<R, T>
> = (
TMappedResult<P>
)
// prettier-ignore
export function ExtractFromMappedResult<
R extends TMappedResult,
T extends TSchema,
P extends TProperties = TFromMappedResult<R, T>
>(R: R, T: T, options: SchemaOptions): TMappedResult<P> {
const P = FromMappedResult(R, T, options) as unknown as P
return MappedResult(P)
}

View File

@@ -0,0 +1,94 @@
/*--------------------------------------------------------------------------
@sinclair/typebox/type
The MIT License (MIT)
Copyright (c) 2017-2023 Haydn Paterson (sinclair) <haydn.developer@gmail.com>
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 type { TSchema, SchemaOptions } from '../schema/index'
import type { Assert, AssertRest, AssertType, UnionToTuple } from '../helpers/index'
import type { TMappedResult } from '../mapped/index'
import { TemplateLiteralToUnion, type TTemplateLiteral } from '../template-literal/index'
import { type TLiteral } from '../literal/index'
import { Union, type TUnion } from '../union/index'
import { type Static } from '../static/index'
import { Never } from '../never/index'
import { type TUnionEvaluated } from '../union/index'
import { ExtendsCheck, ExtendsResult } from '../extends/index'
import { CloneType } from '../clone/type'
import { ExtractFromMappedResult, type TExtractFromMappedResult } from './extract-from-mapped-result'
// ------------------------------------------------------------------
// TypeGuard
// ------------------------------------------------------------------
import { IsMappedResult, IsTemplateLiteral, IsUnion } from '../guard/type'
// ------------------------------------------------------------------
// ExtractResolve
// ------------------------------------------------------------------
// prettier-ignore
type TFromTemplateLiteralResult<T extends string> = TUnionEvaluated<AssertRest<UnionToTuple<{ [K in T]: TLiteral<K> }[T]>>>
// prettier-ignore
type TFromTemplateLiteral<T extends TTemplateLiteral, U extends TSchema> = Extract<Static<T>, Static<U>> extends infer S ? TFromTemplateLiteralResult<Assert<S, string>> : never
// prettier-ignore
type TFromArray<T extends TSchema[], U extends TSchema> = AssertRest<UnionToTuple<
{ [K in keyof T]: Static<AssertType<T[K]>> extends Static<U> ? T[K] : never
}[number]>> extends infer R extends TSchema[] ? TUnionEvaluated<R> : never
// prettier-ignore
type TExtractResolve<T extends TSchema, U extends TSchema> = (
T extends TTemplateLiteral ? TFromTemplateLiteral<T, U> :
T extends TUnion<infer S> ? TFromArray<S, U> :
T
)
// prettier-ignore
function ExtractResolve<L extends TSchema, R extends TSchema>(L: L, R: R): TExtractResolve<L, R> {
return (
IsTemplateLiteral(L) ? ExtractResolve(TemplateLiteralToUnion(L), R) :
IsTemplateLiteral(R) ? ExtractResolve(L, TemplateLiteralToUnion(R) as any) :
IsUnion(L) ? (() => {
const narrowed = L.anyOf.filter((inner) => ExtendsCheck(inner, R) !== ExtendsResult.False)
return (narrowed.length === 1 ? narrowed[0] : Union(narrowed))
})() :
ExtendsCheck(L, R) !== ExtendsResult.False ? L :
Never()
) as TExtractResolve<L, R>
}
// ------------------------------------------------------------------
// TExtract
// ------------------------------------------------------------------
// prettier-ignore
export type TExtract<T extends TSchema, U extends TSchema> = TExtractResolve<T, U>
/** `[Json]` Constructs a type by extracting from type all union members that are assignable to union */
export function Extract<L extends TMappedResult, R extends TSchema>(type: L, union: R, options?: SchemaOptions): TExtractFromMappedResult<L, R>
/** `[Json]` Constructs a type by extracting from type all union members that are assignable to union */
export function Extract<L extends TSchema, R extends TSchema>(type: L, union: R, options?: SchemaOptions): TExtract<L, R>
/** `[Json]` Constructs a type by extracting from type all union members that are assignable to union */
export function Extract(type: TSchema, union: TSchema, options: SchemaOptions = {}) {
if (IsMappedResult(type)) {
return ExtractFromMappedResult(type, union, options)
} else {
const E = ExtractResolve(type, union)
return CloneType(E, options)
}
}

30
src/type/extract/index.ts Normal file
View File

@@ -0,0 +1,30 @@
/*--------------------------------------------------------------------------
@sinclair/typebox/type
The MIT License (MIT)
Copyright (c) 2017-2023 Haydn Paterson (sinclair) <haydn.developer@gmail.com>
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.
---------------------------------------------------------------------------*/
export * from './extract-from-mapped-result'
export * from './extract'

View File

@@ -0,0 +1,67 @@
/*--------------------------------------------------------------------------
@sinclair/typebox/type
The MIT License (MIT)
Copyright (c) 2017-2023 Haydn Paterson (sinclair) <haydn.developer@gmail.com>
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 type { TSchema, SchemaOptions } from '../schema/index'
import type { Static } from '../static/index'
import type { Ensure } from '../helpers/index'
import { CloneType, CloneRest } from '../clone/type'
import { Kind } from '../symbols/index'
// ------------------------------------------------------------------
// FunctionStatic
// ------------------------------------------------------------------
type FunctionStaticReturnType<T extends TSchema, P extends unknown[]> = Static<T, P>
// prettier-ignore
type FunctionStaticParameters<T extends TSchema[], P extends unknown[], Acc extends unknown[] = []> =
T extends [infer L extends TSchema, ...infer R extends TSchema[]]
? FunctionStaticParameters<R, P, [...Acc, Static<L, P>]>
: Acc
// prettier-ignore
type FunctionStatic<T extends TSchema[], U extends TSchema, P extends unknown[]> = (
Ensure<(...param: FunctionStaticParameters<T, P>) => FunctionStaticReturnType<U, P>>
)
// ------------------------------------------------------------------
// TFunction
// ------------------------------------------------------------------
export interface TFunction<T extends TSchema[] = TSchema[], U extends TSchema = TSchema> extends TSchema {
[Kind]: 'Function'
static: FunctionStatic<T, U, this['params']>
type: 'Function'
parameters: T
returns: U
}
/** `[JavaScript]` Creates a Function type */
export function Function<T extends TSchema[], U extends TSchema>(parameters: [...T], returns: U, options?: SchemaOptions): TFunction<T, U> {
return {
...options,
[Kind]: 'Function',
type: 'Function',
parameters: CloneRest(parameters),
returns: CloneType(returns),
} as unknown as TFunction<T, U>
}

View File

@@ -0,0 +1,29 @@
/*--------------------------------------------------------------------------
@sinclair/typebox/type
The MIT License (MIT)
Copyright (c) 2017-2023 Haydn Paterson (sinclair) <haydn.developer@gmail.com>
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.
---------------------------------------------------------------------------*/
export * from './function'

30
src/type/guard/index.ts Normal file
View File

@@ -0,0 +1,30 @@
/*--------------------------------------------------------------------------
@sinclair/typebox/type
The MIT License (MIT)
Copyright (c) 2017-2023 Haydn Paterson (sinclair) <haydn.developer@gmail.com>
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.
---------------------------------------------------------------------------*/
export * as TypeGuard from './type'
export * as ValueGuard from './value'

618
src/type/guard/type.ts Normal file
View File

@@ -0,0 +1,618 @@
/*--------------------------------------------------------------------------
@sinclair/typebox/type
The MIT License (MIT)
Copyright (c) 2017-2023 Haydn Paterson (sinclair) <haydn.developer@gmail.com>
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 ValueGuard from './value'
import { Kind, Hint, TransformKind, ReadonlyKind, OptionalKind } from '../symbols/index'
import { TypeBoxError } from '../error/index'
import { TransformOptions } from '../transform/index'
import { TTemplateLiteral, TTemplateLiteralKind } from '../template-literal/index'
import { TArray } from '../array/index'
import { TBoolean } from '../boolean/index'
import type { TRecord } from '../record/index'
import type { TString } from '../string/index'
import type { TUnion } from '../union/index'
import type { TAny } from '../any/index'
import type { TAsyncIterator } from '../async-iterator/index'
import type { TBigInt } from '../bigint/index'
import type { TConstructor } from '../constructor/index'
import type { TFunction } from '../function/index'
import type { TInteger } from '../integer/index'
import type { TIntersect } from '../intersect/index'
import type { TIterator } from '../iterator/index'
import type { TLiteral, TLiteralValue } from '../literal/index'
import type { TMappedKey, TMappedResult } from '../mapped/index'
import type { TNever } from '../never/index'
import type { TNot } from '../not/index'
import type { TNull } from '../null/index'
import type { TNumber } from '../number/index'
import type { TObject, TAdditionalProperties, TProperties } from '../object/index'
import type { TOptional } from '../optional/index'
import type { TPromise } from '../promise/index'
import type { TReadonly } from '../readonly/index'
import type { TRef } from '../ref/index'
import type { TRegExp } from '../regexp/index'
import type { TSchema } from '../schema/index'
import type { TSymbol } from '../symbol/index'
import type { TTuple } from '../tuple/index'
import type { TUint8Array } from '../uint8array/index'
import type { TUndefined } from '../undefined/index'
import type { TUnknown } from '../unknown/index'
import type { TUnsafe } from '../unsafe/index'
import type { TVoid } from '../void/index'
import type { TDate } from '../date/index'
import type { TThis } from '../recursive/index'
export class TypeGuardUnknownTypeError extends TypeBoxError {}
const KnownTypes = [
'Any',
'Array',
'AsyncIterator',
'BigInt',
'Boolean',
'Constructor',
'Date',
'Enum',
'Function',
'Integer',
'Intersect',
'Iterator',
'Literal',
'MappedKey',
'MappedResult',
'Not',
'Null',
'Number',
'Object',
'Promise',
'Record',
'Ref',
'RegExp',
'String',
'Symbol',
'TemplateLiteral',
'This',
'Tuple',
'Undefined',
'Union',
'Uint8Array',
'Unknown',
'Void',
]
function IsPattern(value: unknown): value is string {
try {
new RegExp(value as string)
return true
} catch {
return false
}
}
function IsControlCharacterFree(value: unknown): value is string {
if (!ValueGuard.IsString(value)) return false
for (let i = 0; i < value.length; i++) {
const code = value.charCodeAt(i)
if ((code >= 7 && code <= 13) || code === 27 || code === 127) {
return false
}
}
return true
}
function IsAdditionalProperties(value: unknown): value is TAdditionalProperties {
return IsOptionalBoolean(value) || IsSchema(value)
}
function IsOptionalBigInt(value: unknown): value is bigint | undefined {
return ValueGuard.IsUndefined(value) || ValueGuard.IsBigInt(value)
}
function IsOptionalNumber(value: unknown): value is number | undefined {
return ValueGuard.IsUndefined(value) || ValueGuard.IsNumber(value)
}
function IsOptionalBoolean(value: unknown): value is boolean | undefined {
return ValueGuard.IsUndefined(value) || ValueGuard.IsBoolean(value)
}
function IsOptionalString(value: unknown): value is string | undefined {
return ValueGuard.IsUndefined(value) || ValueGuard.IsString(value)
}
function IsOptionalPattern(value: unknown): value is string | undefined {
return ValueGuard.IsUndefined(value) || (ValueGuard.IsString(value) && IsControlCharacterFree(value) && IsPattern(value))
}
function IsOptionalFormat(value: unknown): value is string | undefined {
return ValueGuard.IsUndefined(value) || (ValueGuard.IsString(value) && IsControlCharacterFree(value))
}
function IsOptionalSchema(value: unknown): value is boolean | undefined {
return ValueGuard.IsUndefined(value) || IsSchema(value)
}
// ------------------------------------------------------------------
// Modifiers
// ------------------------------------------------------------------
/** Returns true if this value has a Readonly symbol */
export function IsReadonly<T extends TSchema>(value: T): value is TReadonly<T> {
return ValueGuard.IsObject(value) && value[ReadonlyKind] === 'Readonly'
}
/** Returns true if this value has a Optional symbol */
export function IsOptional<T extends TSchema>(value: T): value is TOptional<T> {
return ValueGuard.IsObject(value) && value[OptionalKind] === 'Optional'
}
// ------------------------------------------------------------------
// Types
// ------------------------------------------------------------------
/** Returns true if the given value is TAny */
export function IsAny(value: unknown): value is TAny {
// prettier-ignore
return (
IsKindOf(value, 'Any') &&
IsOptionalString(value.$id)
)
}
/** Returns true if the given value is TArray */
export function IsArray(value: unknown): value is TArray {
return (
IsKindOf(value, 'Array') &&
value.type === 'array' &&
IsOptionalString(value.$id) &&
IsSchema(value.items) &&
IsOptionalNumber(value.minItems) &&
IsOptionalNumber(value.maxItems) &&
IsOptionalBoolean(value.uniqueItems) &&
IsOptionalSchema(value.contains) &&
IsOptionalNumber(value.minContains) &&
IsOptionalNumber(value.maxContains)
)
}
/** Returns true if the given value is TAsyncIterator */
export function IsAsyncIterator(value: unknown): value is TAsyncIterator {
// prettier-ignore
return (
IsKindOf(value, 'AsyncIterator') &&
value.type === 'AsyncIterator' &&
IsOptionalString(value.$id) &&
IsSchema(value.items)
)
}
/** Returns true if the given value is TBigInt */
export function IsBigInt(value: unknown): value is TBigInt {
// prettier-ignore
return (
IsKindOf(value, 'BigInt') &&
value.type === 'bigint' &&
IsOptionalString(value.$id) &&
IsOptionalBigInt(value.exclusiveMaximum) &&
IsOptionalBigInt(value.exclusiveMinimum) &&
IsOptionalBigInt(value.maximum) &&
IsOptionalBigInt(value.minimum) &&
IsOptionalBigInt(value.multipleOf)
)
}
/** Returns true if the given value is TBoolean */
export function IsBoolean(value: unknown): value is TBoolean {
// prettier-ignore
return (
IsKindOf(value, 'Boolean') &&
value.type === 'boolean' &&
IsOptionalString(value.$id)
)
}
/** Returns true if the given value is TConstructor */
export function IsConstructor(value: unknown): value is TConstructor {
// prettier-ignore
return (
IsKindOf(value, 'Constructor') &&
value.type === 'Constructor' &&
IsOptionalString(value.$id) &&
ValueGuard.IsArray(value.parameters) &&
value.parameters.every(schema => IsSchema(schema)) &&
IsSchema(value.returns)
)
}
/** Returns true if the given value is TDate */
export function IsDate(value: unknown): value is TDate {
return (
IsKindOf(value, 'Date') &&
value.type === 'Date' &&
IsOptionalString(value.$id) &&
IsOptionalNumber(value.exclusiveMaximumTimestamp) &&
IsOptionalNumber(value.exclusiveMinimumTimestamp) &&
IsOptionalNumber(value.maximumTimestamp) &&
IsOptionalNumber(value.minimumTimestamp) &&
IsOptionalNumber(value.multipleOfTimestamp)
)
}
/** Returns true if the given value is TFunction */
export function IsFunction(value: unknown): value is TFunction {
// prettier-ignore
return (
IsKindOf(value, 'Function') &&
value.type === 'Function' &&
IsOptionalString(value.$id) &&
ValueGuard.IsArray(value.parameters) &&
value.parameters.every(schema => IsSchema(schema)) &&
IsSchema(value.returns)
)
}
/** Returns true if the given value is TInteger */
export function IsInteger(value: unknown): value is TInteger {
return (
IsKindOf(value, 'Integer') &&
value.type === 'integer' &&
IsOptionalString(value.$id) &&
IsOptionalNumber(value.exclusiveMaximum) &&
IsOptionalNumber(value.exclusiveMinimum) &&
IsOptionalNumber(value.maximum) &&
IsOptionalNumber(value.minimum) &&
IsOptionalNumber(value.multipleOf)
)
}
/** Returns true if the given schema is TProperties */
export function IsProperties(value: unknown): value is TProperties {
// prettier-ignore
return (
ValueGuard.IsObject(value) &&
Object.entries(value).every(([key, schema]) => IsControlCharacterFree(key) && IsSchema(schema))
)
}
/** Returns true if the given value is TIntersect */
export function IsIntersect(value: unknown): value is TIntersect {
// prettier-ignore
return (
IsKindOf(value, 'Intersect') &&
(ValueGuard.IsString(value.type) && value.type !== 'object' ? false : true) &&
ValueGuard.IsArray(value.allOf) &&
value.allOf.every(schema => IsSchema(schema) && !IsTransform(schema)) &&
IsOptionalString(value.type) &&
(IsOptionalBoolean(value.unevaluatedProperties) || IsOptionalSchema(value.unevaluatedProperties)) &&
IsOptionalString(value.$id)
)
}
/** Returns true if the given value is TIterator */
export function IsIterator(value: unknown): value is TIterator {
// prettier-ignore
return (
IsKindOf(value, 'Iterator') &&
value.type === 'Iterator' &&
IsOptionalString(value.$id) &&
IsSchema(value.items)
)
}
/** Returns true if the given value is a TKind with the given name. */
export function IsKindOf<T extends string>(value: unknown, kind: T): value is Record<PropertyKey, unknown> & { [Kind]: T } {
return ValueGuard.IsObject(value) && Kind in value && value[Kind] === kind
}
/** Returns true if the given value is TLiteral<string> */
export function IsLiteralString(value: unknown): value is TLiteral<string> {
return IsLiteral(value) && ValueGuard.IsString(value.const)
}
/** Returns true if the given value is TLiteral<number> */
export function IsLiteralNumber(value: unknown): value is TLiteral<number> {
return IsLiteral(value) && ValueGuard.IsNumber(value.const)
}
/** Returns true if the given value is TLiteral<boolean> */
export function IsLiteralBoolean(value: unknown): value is TLiteral<boolean> {
return IsLiteral(value) && ValueGuard.IsBoolean(value.const)
}
/** Returns true if the given value is TLiteral */
export function IsLiteral(value: unknown): value is TLiteral {
// prettier-ignore
return (
IsKindOf(value, 'Literal') &&
IsOptionalString(value.$id) && IsLiteralValue(value.const)
)
}
/** Returns true if the given value is a TLiteralValue */
export function IsLiteralValue(value: unknown): value is TLiteralValue {
return ValueGuard.IsBoolean(value) || ValueGuard.IsNumber(value) || ValueGuard.IsString(value)
}
/** Returns true if the given value is a TMappedKey */
export function IsMappedKey(value: unknown): value is TMappedKey {
// prettier-ignore
return (
IsKindOf(value, 'MappedKey') &&
ValueGuard.IsArray(value.keys) &&
value.keys.every(key => ValueGuard.IsNumber(key) || ValueGuard.IsString(key))
)
}
/** Returns true if the given value is TMappedResult */
export function IsMappedResult(value: unknown): value is TMappedResult {
// prettier-ignore
return (
IsKindOf(value, 'MappedResult') &&
IsProperties(value.properties)
)
}
/** Returns true if the given value is TNever */
export function IsNever(value: unknown): value is TNever {
// prettier-ignore
return (
IsKindOf(value, 'Never') &&
ValueGuard.IsObject(value.not) &&
Object.getOwnPropertyNames(value.not).length === 0
)
}
/** Returns true if the given value is TNot */
export function IsNot(value: unknown): value is TNot {
// prettier-ignore
return (
IsKindOf(value, 'Not') &&
IsSchema(value.not)
)
}
/** Returns true if the given value is TNull */
export function IsNull(value: unknown): value is TNull {
// prettier-ignore
return (
IsKindOf(value, 'Null') &&
value.type === 'null' &&
IsOptionalString(value.$id)
)
}
/** Returns true if the given value is TNumber */
export function IsNumber(value: unknown): value is TNumber {
return (
IsKindOf(value, 'Number') &&
value.type === 'number' &&
IsOptionalString(value.$id) &&
IsOptionalNumber(value.exclusiveMaximum) &&
IsOptionalNumber(value.exclusiveMinimum) &&
IsOptionalNumber(value.maximum) &&
IsOptionalNumber(value.minimum) &&
IsOptionalNumber(value.multipleOf)
)
}
/** Returns true if the given value is TObject */
export function IsObject(value: unknown): value is TObject {
// prettier-ignore
return (
IsKindOf(value, 'Object') &&
value.type === 'object' &&
IsOptionalString(value.$id) &&
IsProperties(value.properties) &&
IsAdditionalProperties(value.additionalProperties) &&
IsOptionalNumber(value.minProperties) &&
IsOptionalNumber(value.maxProperties)
)
}
/** Returns true if the given value is TPromise */
export function IsPromise(value: unknown): value is TPromise {
// prettier-ignore
return (
IsKindOf(value, 'Promise') &&
value.type === 'Promise' &&
IsOptionalString(value.$id) &&
IsSchema(value.item)
)
}
/** Returns true if the given value is TRecord */
export function IsRecord(value: unknown): value is TRecord {
// prettier-ignore
return (
IsKindOf(value, 'Record') &&
value.type === 'object' &&
IsOptionalString(value.$id) &&
IsAdditionalProperties(value.additionalProperties) &&
ValueGuard.IsObject(value.patternProperties) &&
((schema: Record<PropertyKey, unknown>) => {
const keys = Object.getOwnPropertyNames(schema.patternProperties)
return (
keys.length === 1 &&
IsPattern(keys[0]) &&
ValueGuard.IsObject(schema.patternProperties) &&
IsSchema(schema.patternProperties[keys[0]])
)
})(value)
)
}
/** Returns true if this value is TRecursive */
export function IsRecursive(value: unknown): value is { [Hint]: 'Recursive' } {
return ValueGuard.IsObject(value) && Hint in value && value[Hint] === 'Recursive'
}
/** Returns true if the given value is TRef */
export function IsRef(value: unknown): value is TRef {
// prettier-ignore
return (
IsKindOf(value, 'Ref') &&
IsOptionalString(value.$id) &&
ValueGuard.IsString(value.$ref)
)
}
/** Returns true if the given value is TRegExp */
export function IsRegExp(value: unknown): value is TRegExp {
// prettier-ignore
return (
IsKindOf(value, 'RegExp') &&
IsOptionalString(value.$id) &&
ValueGuard.IsString(value.source) &&
ValueGuard.IsString(value.flags)
)
}
/** Returns true if the given value is TString */
export function IsString(value: unknown): value is TString {
// prettier-ignore
return (
IsKindOf(value, 'String') &&
value.type === 'string' &&
IsOptionalString(value.$id) &&
IsOptionalNumber(value.minLength) &&
IsOptionalNumber(value.maxLength) &&
IsOptionalPattern(value.pattern) &&
IsOptionalFormat(value.format)
)
}
/** Returns true if the given value is TSymbol */
export function IsSymbol(value: unknown): value is TSymbol {
// prettier-ignore
return (
IsKindOf(value, 'Symbol') &&
value.type === 'symbol' &&
IsOptionalString(value.$id)
)
}
/** Returns true if the given value is TTemplateLiteral */
export function IsTemplateLiteral(value: unknown): value is TTemplateLiteral<TTemplateLiteralKind[]> {
// prettier-ignore
return (
IsKindOf(value, 'TemplateLiteral') &&
value.type === 'string' &&
ValueGuard.IsString(value.pattern) &&
value.pattern[0] === '^' &&
value.pattern[value.pattern.length - 1] === '$'
)
}
/** Returns true if the given value is TThis */
export function IsThis(value: unknown): value is TThis {
// prettier-ignore
return (
IsKindOf(value, 'This') &&
IsOptionalString(value.$id) &&
ValueGuard.IsString(value.$ref)
)
}
/** Returns true of this value is TTransform */
export function IsTransform(value: unknown): value is { [TransformKind]: TransformOptions } {
return ValueGuard.IsObject(value) && TransformKind in value
}
/** Returns true if the given value is TTuple */
export function IsTuple(value: unknown): value is TTuple {
// prettier-ignore
return (
IsKindOf(value, 'Tuple') &&
value.type === 'array' &&
IsOptionalString(value.$id) &&
ValueGuard.IsNumber(value.minItems) &&
ValueGuard.IsNumber(value.maxItems) &&
value.minItems === value.maxItems &&
(( // empty
ValueGuard.IsUndefined(value.items) &&
ValueGuard.IsUndefined(value.additionalItems) &&
value.minItems === 0
) || (
ValueGuard.IsArray(value.items) &&
value.items.every(schema => IsSchema(schema))
))
)
}
/** Returns true if the given value is TUndefined */
export function IsUndefined(value: unknown): value is TUndefined {
// prettier-ignore
return (
IsKindOf(value, 'Undefined') &&
value.type === 'undefined' &&
IsOptionalString(value.$id)
)
}
/** Returns true if the given value is TUnion<Literal<string | number>[]> */
export function IsUnionLiteral(value: unknown): value is TUnion<TLiteral[]> {
return IsUnion(value) && value.anyOf.every((schema) => IsLiteralString(schema) || IsLiteralNumber(schema))
}
/** Returns true if the given value is TUnion */
export function IsUnion(value: unknown): value is TUnion {
// prettier-ignore
return (
IsKindOf(value, 'Union') &&
IsOptionalString(value.$id) &&
ValueGuard.IsObject(value) &&
ValueGuard.IsArray(value.anyOf) &&
value.anyOf.every(schema => IsSchema(schema))
)
}
/** Returns true if the given value is TUint8Array */
export function IsUint8Array(value: unknown): value is TUint8Array {
// prettier-ignore
return (
IsKindOf(value, 'Uint8Array') &&
value.type === 'Uint8Array' &&
IsOptionalString(value.$id) &&
IsOptionalNumber(value.minByteLength) &&
IsOptionalNumber(value.maxByteLength)
)
}
/** Returns true if the given value is TUnknown */
export function IsUnknown(value: unknown): value is TUnknown {
// prettier-ignore
return (
IsKindOf(value, 'Unknown') &&
IsOptionalString(value.$id)
)
}
/** Returns true if the given value is a raw TUnsafe */
export function IsUnsafe(value: unknown): value is TUnsafe<unknown> {
return IsKindOf(value, 'Unsafe')
}
/** Returns true if the given value is TVoid */
export function IsVoid(value: unknown): value is TVoid {
// prettier-ignore
return (
IsKindOf(value, 'Void') &&
value.type === 'void' &&
IsOptionalString(value.$id)
)
}
/** Returns true if the given value is TKind */
export function IsKind(value: unknown): value is Record<PropertyKey, unknown> & { [Kind]: string } {
return ValueGuard.IsObject(value) && Kind in value && ValueGuard.IsString(value[Kind]) && !KnownTypes.includes(value[Kind] as string)
}
/** Returns true if the given value is TSchema */
export function IsSchema(value: unknown): value is TSchema {
// prettier-ignore
return (
ValueGuard.IsObject(value)
) && (
IsAny(value) ||
IsArray(value) ||
IsBoolean(value) ||
IsBigInt(value) ||
IsAsyncIterator(value) ||
IsConstructor(value) ||
IsDate(value) ||
IsFunction(value) ||
IsInteger(value) ||
IsIntersect(value) ||
IsIterator(value) ||
IsLiteral(value) ||
IsMappedKey(value) ||
IsMappedResult(value) ||
IsNever(value) ||
IsNot(value) ||
IsNull(value) ||
IsNumber(value) ||
IsObject(value) ||
IsPromise(value) ||
IsRecord(value) ||
IsRef(value) ||
IsRegExp(value) ||
IsString(value) ||
IsSymbol(value) ||
IsTemplateLiteral(value) ||
IsThis(value) ||
IsTuple(value) ||
IsUndefined(value) ||
IsUnion(value) ||
IsUint8Array(value) ||
IsUnknown(value) ||
IsUnsafe(value) ||
IsVoid(value) ||
IsKind(value)
)
}

88
src/type/guard/value.ts Normal file
View File

@@ -0,0 +1,88 @@
/*--------------------------------------------------------------------------
@sinclair/typebox/type
The MIT License (MIT)
Copyright (c) 2017-2023 Haydn Paterson (sinclair) <haydn.developer@gmail.com>
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.
---------------------------------------------------------------------------*/
/** Returns true if this value is an async iterator */
export function IsAsyncIterator(value: unknown): value is AsyncIterableIterator<unknown> {
return IsObject(value) && !IsArray(value) && !IsUint8Array(value) && Symbol.asyncIterator in value
}
/** Returns true if this value is an array */
export function IsArray(value: unknown): value is unknown[] {
return Array.isArray(value)
}
/** Returns true if this value is bigint */
export function IsBigInt(value: unknown): value is bigint {
return typeof value === 'bigint'
}
/** Returns true if this value is a boolean */
export function IsBoolean(value: unknown): value is boolean {
return typeof value === 'boolean'
}
/** Returns true if this value is a Date object */
export function IsDate(value: unknown): value is Date {
return value instanceof globalThis.Date
}
/** Returns true if this value is a function */
export function IsFunction(value: unknown): value is Function {
return typeof value === 'function'
}
/** Returns true if this value is an iterator */
export function IsIterator(value: unknown): value is IterableIterator<unknown> {
return IsObject(value) && !IsArray(value) && !IsUint8Array(value) && Symbol.iterator in value
}
/** Returns true if this value is null */
export function IsNull(value: unknown): value is null {
return value === null
}
/** Returns true if this value is number */
export function IsNumber(value: unknown): value is number {
return typeof value === 'number'
}
/** Returns true if this value is an object */
export function IsObject(value: unknown): value is Record<PropertyKey, unknown> {
return typeof value === 'object' && value !== null
}
/** Returns true if this value is RegExp */
export function IsRegExp(value: unknown): value is RegExp {
return value instanceof globalThis.RegExp
}
/** Returns true if this value is string */
export function IsString(value: unknown): value is string {
return typeof value === 'string'
}
/** Returns true if this value is symbol */
export function IsSymbol(value: unknown): value is symbol {
return typeof value === 'symbol'
}
/** Returns true if this value is a Uint8Array */
export function IsUint8Array(value: unknown): value is Uint8Array {
return value instanceof globalThis.Uint8Array
}
/** Returns true if this value is undefined */
export function IsUndefined(value: unknown): value is undefined {
return value === undefined
}

View File

@@ -0,0 +1,69 @@
/*--------------------------------------------------------------------------
@sinclair/typebox/type
The MIT License (MIT)
Copyright (c) 2017-2023 Haydn Paterson (sinclair) <haydn.developer@gmail.com>
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 type { TSchema } from '../schema/index'
import type { TProperties } from '../object/index'
import type { TNever } from '../never/index'
// ------------------------------------------------------------------
// Helper: Common
// ------------------------------------------------------------------
export type TupleToIntersect<T extends any[]> = T extends [infer I] ? I : T extends [infer I, ...infer R] ? I & TupleToIntersect<R> : never
export type TupleToUnion<T extends any[]> = { [K in keyof T]: T[K] }[number]
export type UnionToIntersect<U> = (U extends unknown ? (arg: U) => 0 : never) extends (arg: infer I) => 0 ? I : never
export type UnionLast<U> = UnionToIntersect<U extends unknown ? (x: U) => 0 : never> extends (x: infer L) => 0 ? L : never
export type UnionToTuple<U, Acc extends unknown[] = [], R = UnionLast<U>> = [U] extends [never] ? Acc : UnionToTuple<Exclude<U, R>, [Extract<U, R>, ...Acc]>
export type Trim<T> = T extends `${' '}${infer U}` ? Trim<U> : T extends `${infer U}${' '}` ? Trim<U> : T
export type Assert<T, E> = T extends E ? T : never
export type Evaluate<T> = T extends infer O ? { [K in keyof O]: O[K] } : never
export type Ensure<T> = T extends infer U ? U : never
export type EmptyString = ''
export type ZeroString = '0'
// ------------------------------------------------------------------
// Helper: Increment
// ------------------------------------------------------------------
type IncrementBase = { m: '9'; t: '01'; '0': '1'; '1': '2'; '2': '3'; '3': '4'; '4': '5'; '5': '6'; '6': '7'; '7': '8'; '8': '9'; '9': '0' }
type IncrementTake<T extends keyof IncrementBase> = IncrementBase[T]
type IncrementStep<T extends string> = T extends IncrementBase['m']
? IncrementBase['t']
: T extends `${infer L extends keyof IncrementBase}${infer R}`
? L extends IncrementBase['m']
? `${IncrementTake<L>}${IncrementStep<R>}`
: `${IncrementTake<L>}${R}`
: never
type IncrementReverse<T extends string> = T extends `${infer L}${infer R}` ? `${IncrementReverse<R>}${L}` : T
export type Increment<T extends string> = IncrementReverse<IncrementStep<IncrementReverse<T>>>
/** Increments the given string value + 1 */
export function Increment<T extends string>(T: T): Increment<T> {
return (parseInt(T) + 1).toString() as Increment<T>
}
// ------------------------------------------------------------------
// Helper: Type Asserts
// ------------------------------------------------------------------
export type AssertProperties<T> = T extends TProperties ? T : TProperties
export type AssertRest<T, E extends TSchema[] = TSchema[]> = T extends E ? T : []
export type AssertType<T, E extends TSchema = TSchema> = T extends E ? T : TNever

29
src/type/helpers/index.ts Normal file
View File

@@ -0,0 +1,29 @@
/*--------------------------------------------------------------------------
@sinclair/typebox/type
The MIT License (MIT)
Copyright (c) 2017-2023 Haydn Paterson (sinclair) <haydn.developer@gmail.com>
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.
---------------------------------------------------------------------------*/
export * from './helpers'

98
src/type/index.ts Normal file
View File

@@ -0,0 +1,98 @@
/*--------------------------------------------------------------------------
@sinclair/typebox/type
The MIT License (MIT)
Copyright (c) 2017-2023 Haydn Paterson (sinclair) <haydn.developer@gmail.com>
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.
---------------------------------------------------------------------------*/
export * from './any/index'
export * from './array/index'
export * from './async-iterator/index'
export * from './awaited/index'
export * from './bigint/index'
export * from './boolean/index'
export * from './clone/index'
export * from './composite/index'
export * from './const/index'
export * from './constructor/index'
export * from './constructor-parameters/index'
export * from './date/index'
export * from './deref/index'
export * from './discard/index'
export * from './enum/index'
export * from './error/index'
export * from './exclude/index'
export * from './extends/index'
export * from './extract/index'
export * from './function/index'
export * from './guard/index'
export * from './helpers/index'
export * from './indexed/index'
export * from './instance-type/index'
export * from './integer/index'
export * from './intersect/index'
export * from './intrinsic/index'
export * from './iterator/index'
export * from './keyof/index'
export * from './literal/index'
export * from './mapped/index'
export * from './never/index'
export * from './not/index'
export * from './null/index'
export * from './number/index'
export * from './object/index'
export * from './omit/index'
export * from './optional/index'
export * from './parameters/index'
export * from './partial/index'
export * from './patterns/index'
export * from './pick/index'
export * from './promise/index'
export * from './readonly/index'
export * from './readonly-optional/index'
export * from './record/index'
export * from './recursive/index'
export * from './ref/index'
export * from './regexp/index'
export * from './registry/index'
export * from './required/index'
export * from './rest/index'
export * from './return-type/index'
export * from './schema/index'
export * from './sets/index'
export * from './static/index'
export * from './strict/index'
export * from './string/index'
export * from './symbol/index'
export * from './symbols/index'
export * from './template-literal/index'
export * from './transform/index'
export * from './tuple/index'
export * from './type/index'
export * from './uint8array/index'
export * from './undefined/index'
export * from './union/index'
export * from './unknown/index'
export * from './unsafe/index'
export * from './void/index'

Some files were not shown because too many files have changed in this diff Show More