diff --git a/.vscode/settings.json b/.vscode/settings.json index df318270b..abae0f574 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,6 +1,6 @@ { "files.exclude": { - "node_modules": true, + "node_modules": false, "package-lock.json": true }, "editor.suggest.showStatusBar": false, diff --git a/benchmark/compression/module/typebox.ts b/benchmark/compression/module/typebox.ts index 0b01566e5..abd5374e1 100644 --- a/benchmark/compression/module/typebox.ts +++ b/benchmark/compression/module/typebox.ts @@ -1,3 +1,3 @@ -import { Type } from '@sinclair/typebox' +import Type from '@sinclair/typebox' const T = Type.String() diff --git a/examples/collections/array.ts b/examples/collections/array.ts index 90f5d73b4..1a7a7550b 100644 --- a/examples/collections/array.ts +++ b/examples/collections/array.ts @@ -27,18 +27,18 @@ THE SOFTWARE. ---------------------------------------------------------------------------*/ import { TypeCheck, TypeCompiler, ValueError } from '@sinclair/typebox/compiler' -import { TSchema, Static, TypeBoxError } from '@sinclair/typebox' +import { TSchema, Static } from '@sinclair/typebox' import { Value } from '@sinclair/typebox/value' // ---------------------------------------------------------------- // TypeArrayError // ---------------------------------------------------------------- -export class TypeArrayError extends TypeBoxError { +export class TypeArrayError extends Error { constructor(message: string) { super(`${message}`) } } -export class TypeArrayLengthError extends TypeBoxError { +export class TypeArrayLengthError extends Error { constructor() { super('arrayLength not a number') } diff --git a/examples/collections/map.ts b/examples/collections/map.ts index 796140fe6..2fa3dffed 100644 --- a/examples/collections/map.ts +++ b/examples/collections/map.ts @@ -27,18 +27,18 @@ THE SOFTWARE. ---------------------------------------------------------------------------*/ import { TypeCheck, TypeCompiler, ValueError } from '@sinclair/typebox/compiler' -import { TSchema, Static, TypeBoxError } from '@sinclair/typebox' +import { TSchema, Static } from '@sinclair/typebox' import { Value } from '@sinclair/typebox/value' // ---------------------------------------------------------------- // TypeMapKeyError // ---------------------------------------------------------------- -export class TypeMapKeyError extends TypeBoxError { +export class TypeMapKeyError extends Error { constructor(message: string) { super(`${message} for key`) } } -export class TypeMapValueError extends TypeBoxError { +export class TypeMapValueError extends Error { constructor(key: unknown, message: string) { super(`${message} for key ${JSON.stringify(key)}`) } diff --git a/examples/collections/set.ts b/examples/collections/set.ts index 8cf312a3e..4e8d31213 100644 --- a/examples/collections/set.ts +++ b/examples/collections/set.ts @@ -27,13 +27,13 @@ THE SOFTWARE. ---------------------------------------------------------------------------*/ import { TypeCheck, TypeCompiler, ValueError } from '@sinclair/typebox/compiler' -import { TSchema, Static, TypeBoxError } from '@sinclair/typebox' +import { TSchema, Static } from '@sinclair/typebox' import { Value } from '@sinclair/typebox/value' // ---------------------------------------------------------------- // Errors // ---------------------------------------------------------------- -export class TypeSetError extends TypeBoxError { +export class TypeSetError extends Error { constructor(message: string) { super(`${message}`) } diff --git a/examples/index.ts b/examples/index.ts index ed52156bd..15226e4ec 100644 --- a/examples/index.ts +++ b/examples/index.ts @@ -1,7 +1,7 @@ import { TypeSystem } from '@sinclair/typebox/system' import { TypeCompiler } from '@sinclair/typebox/compiler' import { Value, ValuePointer } from '@sinclair/typebox/value' -import { Type, TypeGuard, Kind, Static, TSchema } from '@sinclair/typebox' +import { Type, TypeGuard, Symbols, Static, TSchema } from '@sinclair/typebox' // ----------------------------------------------------------- // Create: Type diff --git a/examples/prototypes/evaluate.ts b/examples/prototypes/evaluate.ts index 5fa7b2128..5260def0f 100644 --- a/examples/prototypes/evaluate.ts +++ b/examples/prototypes/evaluate.ts @@ -44,7 +44,6 @@ import { TTuple, TProperties, TIntersect, - IntersectType, TUnion, TNever } from '@sinclair/typebox' @@ -75,7 +74,7 @@ export type TEvaluateArray = T extends [infer L, ...infer [] // prettier-ignore export type TEvaluate = - T extends TIntersect ? IntersectType> : + T extends TIntersect ? TIntersect> : T extends TUnion ? TUnion> : T extends TConstructor ? TConstructor, TEvaluate> : T extends TFunction ? TFunction, TEvaluate> : diff --git a/examples/prototypes/index.ts b/examples/prototypes/index.ts index ef44e7d95..4a70931c8 100644 --- a/examples/prototypes/index.ts +++ b/examples/prototypes/index.ts @@ -26,7 +26,6 @@ THE SOFTWARE. ---------------------------------------------------------------------------*/ -export * from './const' export * from './evaluate' export * from './partial-deep' export * from './union-enum' diff --git a/examples/prototypes/partial-deep.ts b/examples/prototypes/partial-deep.ts index 1315b65b0..aa27a07aa 100644 --- a/examples/prototypes/partial-deep.ts +++ b/examples/prototypes/partial-deep.ts @@ -26,7 +26,7 @@ THE SOFTWARE. ---------------------------------------------------------------------------*/ -import { TypeGuard, Type, TSchema, TIntersect, TUnion, TObject, TPartial, TProperties, AssertRest, AssertType, Evaluate } from '@sinclair/typebox' +import { TypeGuard, Type, TSchema, TIntersect, TUnion, TObject, TPartial, TProperties, Evaluate } from '@sinclair/typebox' // ------------------------------------------------------------------------------------- // TDeepPartial @@ -34,9 +34,10 @@ import { TypeGuard, Type, TSchema, TIntersect, TUnion, TObject, TPartial, TPrope export type TPartialDeepProperties = { [K in keyof T]: TPartial } -export type TPartialDeepRest = T extends [infer L, ...infer R] - ? [TPartial>, ...TPartialDeepRest>] - : [] +export type TPartialDeepRest = + T extends [infer L extends TSchema, ...infer R extends TSchema[]] + ? [TPartial, ...TPartialDeepRest] + : [] export type TPartialDeep = T extends TIntersect ? TIntersect> : T extends TUnion ? TUnion> : diff --git a/examples/prototypes/union-enum.ts b/examples/prototypes/union-enum.ts index ee55d202c..c4b1d7a05 100644 --- a/examples/prototypes/union-enum.ts +++ b/examples/prototypes/union-enum.ts @@ -26,13 +26,13 @@ THE SOFTWARE. ---------------------------------------------------------------------------*/ -import { TypeRegistry, Kind, TSchema, SchemaOptions } from '@sinclair/typebox' +import { TypeRegistry, Symbols, TSchema, SchemaOptions } from '@sinclair/typebox' // ------------------------------------------------------------------------------------- // TUnionEnum // ------------------------------------------------------------------------------------- export interface TUnionEnum extends TSchema { - [Kind]: 'UnionEnum' + [Symbols.Kind]: 'UnionEnum' static: T[number] enum: T } @@ -45,5 +45,5 @@ export function UnionEnum(values: [...T], options return (typeof value === 'string' || typeof value === 'number') && schema.enum.includes(value) } if (!TypeRegistry.Has('UnionEnum')) TypeRegistry.Set('UnionEnum', UnionEnumCheck) - return { ...options, [Kind]: 'UnionEnum', enum: values } as TUnionEnum + return { ...options, [Symbols.Kind]: 'UnionEnum', enum: values } as TUnionEnum } \ No newline at end of file diff --git a/examples/prototypes/union-oneof.ts b/examples/prototypes/union-oneof.ts index 5129d457a..22559d028 100644 --- a/examples/prototypes/union-oneof.ts +++ b/examples/prototypes/union-oneof.ts @@ -26,14 +26,14 @@ THE SOFTWARE. ---------------------------------------------------------------------------*/ -import { TypeRegistry, Kind, Static, TSchema, SchemaOptions } from '@sinclair/typebox' +import { TypeRegistry, Symbols, Static, TSchema, SchemaOptions } from '@sinclair/typebox' import { Value } from '@sinclair/typebox/value' // ------------------------------------------------------------------------------------- // TUnionOneOf // ------------------------------------------------------------------------------------- export interface TUnionOneOf extends TSchema { - [Kind]: 'UnionOneOf' + [Symbols.Kind]: 'UnionOneOf' static: { [K in keyof T]: Static }[number] oneOf: T } @@ -46,5 +46,5 @@ export function UnionOneOf(oneOf: [...T], options: SchemaOp return 1 === schema.oneOf.reduce((acc: number, schema: any) => (Value.Check(schema, value) ? acc + 1 : acc), 0) } if (!TypeRegistry.Has('UnionOneOf')) TypeRegistry.Set('UnionOneOf', UnionOneOfCheck) - return { ...options, [Kind]: 'UnionOneOf', oneOf } as TUnionOneOf + return { ...options, [Symbols.Kind]: 'UnionOneOf', oneOf } as TUnionOneOf } \ No newline at end of file diff --git a/examples/typedef/typedef.ts b/examples/typedef/typedef.ts index 5eb12a372..2bf44754d 100644 --- a/examples/typedef/typedef.ts +++ b/examples/typedef/typedef.ts @@ -27,21 +27,10 @@ THE SOFTWARE. ---------------------------------------------------------------------------*/ import { TypeSystemErrorFunction, DefaultErrorFunction } from '@sinclair/typebox/system' -import * as Types from '@sinclair/typebox' +import * as Types from '@sinclair/typebox/type' // -------------------------------------------------------------------------- -// Utility Types -// -------------------------------------------------------------------------- -export type Assert = T extends U ? T : never -export type Base = { m: string, t: string } -export type Base16 = { m: 'F', t: '01', '0': '1', '1': '2', '2': '3', '3': '4', '4': '5', '5': '6', '6': '7', '7': '8', '8': '9', '9': 'A', 'A': 'B', 'B': 'C', 'C': 'D', 'D': 'E', 'E': 'F', 'F': '0' } -export type Base10 = { m: '9', t: '01', '0': '1', '1': '2', '2': '3', '3': '4', '4': '5', '5': '6', '6': '7', '7': '8', '8': '9', '9': '0' } -export type Reverse = T extends `${infer L}${infer R}` ? `${Reverse}${L}` : T -export type Tick = T extends keyof B ? B[T] : never -export type Next = T extends Assert['m'] ? Assert['t'] : T extends `${infer L}${infer R}` ? L extends Assert['m'] ? `${Assert, string>}${Next}` : `${Assert, string>}${R}` : never -export type Increment = Reverse, B>> -// -------------------------------------------------------------------------- -// SchemaOptions +// Metadata // -------------------------------------------------------------------------- export interface Metadata { [name: string]: any @@ -50,7 +39,7 @@ export interface Metadata { // TArray // -------------------------------------------------------------------------- export interface TArray extends Types.TSchema { - [Types.Kind]: 'TypeDef:Array' + [Types.Symbols.Kind]: 'TypeDef:Array' static: Types.Static[] elements: T } @@ -58,19 +47,19 @@ export interface TArray extends Types.T // TBoolean // -------------------------------------------------------------------------- export interface TBoolean extends Types.TSchema { - [Types.Kind]: 'TypeDef:Boolean' + [Types.Symbols.Kind]: 'TypeDef:Boolean' static: 'boolean' type: 'boolean' } // -------------------------------------------------------------------------- // TUnion // -------------------------------------------------------------------------- -type InferUnion = T extends [infer L, ...infer R] - ? Types.Evaluate<{ [_ in D]: Index } & Types.Static>> | InferUnion, D, Increment>> +export type InferUnion = T extends [infer L, ...infer R] + ? Types.Evaluate<{ [_ in D]: Index } & Types.Static>> | InferUnion, D, Types.Increment>> : never export interface TUnion extends Types.TSchema { - [Types.Kind]: 'TypeDef:Union' + [Types.Symbols.Kind]: 'TypeDef:Union' static: InferUnion discriminator: D, mapping: T @@ -79,7 +68,7 @@ export interface TUnion extends Types.TSchema { - [Types.Kind]: 'TypeDef:Enum' + [Types.Symbols.Kind]: 'TypeDef:Enum' static: T[number] enum: [...T] } @@ -87,7 +76,7 @@ export interface TEnum extends Types.TSchema { // TFloat32 // -------------------------------------------------------------------------- export interface TFloat32 extends Types.TSchema { - [Types.Kind]: 'TypeDef:Float32' + [Types.Symbols.Kind]: 'TypeDef:Float32' type: 'float32' static: number } @@ -95,7 +84,7 @@ export interface TFloat32 extends Types.TSchema { // TFloat64 // -------------------------------------------------------------------------- export interface TFloat64 extends Types.TSchema { - [Types.Kind]: 'TypeDef:Float64' + [Types.Symbols.Kind]: 'TypeDef:Float64' type: 'float64' static: number } @@ -103,7 +92,7 @@ export interface TFloat64 extends Types.TSchema { // TInt8 // -------------------------------------------------------------------------- export interface TInt8 extends Types.TSchema { - [Types.Kind]: 'TypeDef:Int8' + [Types.Symbols.Kind]: 'TypeDef:Int8' type: 'int8' static: number } @@ -111,7 +100,7 @@ export interface TInt8 extends Types.TSchema { // TInt16 // -------------------------------------------------------------------------- export interface TInt16 extends Types.TSchema { - [Types.Kind]: 'TypeDef:Int16' + [Types.Symbols.Kind]: 'TypeDef:Int16' type: 'int16' static: number } @@ -119,7 +108,7 @@ export interface TInt16 extends Types.TSchema { // TInt32 // -------------------------------------------------------------------------- export interface TInt32 extends Types.TSchema { - [Types.Kind]: 'TypeDef:Int32' + [Types.Symbols.Kind]: 'TypeDef:Int32' type: 'int32' static: number } @@ -127,7 +116,7 @@ export interface TInt32 extends Types.TSchema { // TUint8 // -------------------------------------------------------------------------- export interface TUint8 extends Types.TSchema { - [Types.Kind]: 'TypeDef:Uint8' + [Types.Symbols.Kind]: 'TypeDef:Uint8' type: 'uint8' static: number } @@ -135,7 +124,7 @@ export interface TUint8 extends Types.TSchema { // TUint16 // -------------------------------------------------------------------------- export interface TUint16 extends Types.TSchema { - [Types.Kind]: 'TypeDef:Uint16' + [Types.Symbols.Kind]: 'TypeDef:Uint16' type: 'uint16' static: number } @@ -143,7 +132,7 @@ export interface TUint16 extends Types.TSchema { // TUint32 // -------------------------------------------------------------------------- export interface TUint32 extends Types.TSchema { - [Types.Kind]: 'TypeDef:Uint32' + [Types.Symbols.Kind]: 'TypeDef:Uint32' type: 'uint32' static: number } @@ -155,7 +144,7 @@ export type TFields = Record // TRecord // -------------------------------------------------------------------------- export interface TRecord extends Types.TSchema { - [Types.Kind]: 'TypeDef:Record' + [Types.Symbols.Kind]: 'TypeDef:Record' static: Record> values: T } @@ -163,7 +152,7 @@ export interface TRecord extends Types. // TString // -------------------------------------------------------------------------- export interface TString extends Types.TSchema { - [Types.Kind]: 'TypeDef:String' + [Types.Symbols.Kind]: 'TypeDef:String' type: 'string' static: string } @@ -176,8 +165,8 @@ export interface StructMetadata extends Metadata { additionalProperties?: boolean } export interface TStruct extends Types.TSchema, StructMetadata { - [Types.Kind]: 'TypeDef:Struct' - static: Types.PropertiesReduce + [Types.Symbols.Kind]: 'TypeDef:Struct' + static: Types.ObjectResolve optionalProperties: { [K in Types.Assert, keyof T>]: T[K] } properties: { [K in Types.Assert, keyof T>]: T[K] } } @@ -185,7 +174,7 @@ export interface TStruct extends Types.TSchema, Str // TTimestamp // -------------------------------------------------------------------------- export interface TTimestamp extends Types.TSchema { - [Types.Kind]: 'TypeDef:Timestamp' + [Types.Symbols.Kind]: 'TypeDef:Timestamp' type: 'timestamp' static: string } @@ -240,7 +229,7 @@ export namespace TimestampFormat { // -------------------------------------------------------------------------- // ValueCheck // -------------------------------------------------------------------------- -export class ValueCheckError extends Types.TypeBoxError { +export class ValueCheckError extends Error { constructor(public readonly schema: Types.TSchema) { super('Unknown type') } @@ -339,7 +328,7 @@ export namespace ValueCheck { } function Visit(schema: Types.TSchema, value: unknown): boolean { const anySchema = schema as any - switch (anySchema[Types.Kind]) { + switch (anySchema[Types.Symbols.Kind]) { case 'TypeDef:Array': return Array(anySchema, value) case 'TypeDef:Boolean': return Boolean(anySchema, value) case 'TypeDef:Union': return Union(anySchema, value) @@ -389,50 +378,50 @@ export namespace TypeGuard { // Types // ------------------------------------------------------------------------ export function TArray(schema: unknown): schema is TArray { - return IsObject(schema) && schema[Types.Kind] === 'TypeDef:Array' && TSchema(schema['elements']) + return IsObject(schema) && schema[Types.Symbols.Kind] === 'TypeDef:Array' && TSchema(schema['elements']) } export function TBoolean(schema: unknown): schema is TBoolean { - return IsObject(schema) && schema[Types.Kind] === 'TypeDef:Boolean' && schema['type'] === 'boolean' + return IsObject(schema) && schema[Types.Symbols.Kind] === 'TypeDef:Boolean' && schema['type'] === 'boolean' } export function TUnion(schema: unknown): schema is TUnion { - if(!(IsObject(schema) && schema[Types.Kind] === 'TypeDef:Union' && IsString(schema['discriminator']) && IsObject(schema['mapping']))) return false + if(!(IsObject(schema) && schema[Types.Symbols.Kind] === 'TypeDef:Union' && IsString(schema['discriminator']) && IsObject(schema['mapping']))) return false return globalThis.Object.getOwnPropertyNames(schema['mapping']).every(key => TSchema((schema['mapping'] as any)[key])) } export function TEnum(schema: unknown): schema is TEnum { - return IsObject(schema) && schema[Types.Kind] === 'TypeDef:Enum' && IsArray(schema['enum']) && schema['enum'].every(item => IsString(item)) + return IsObject(schema) && schema[Types.Symbols.Kind] === 'TypeDef:Enum' && IsArray(schema['enum']) && schema['enum'].every(item => IsString(item)) } export function TFloat32(schema: unknown): schema is TFloat32 { - return IsObject(schema) && schema[Types.Kind] === 'TypeDef:Float32' && schema['type'] === 'float32' + return IsObject(schema) && schema[Types.Symbols.Kind] === 'TypeDef:Float32' && schema['type'] === 'float32' } export function TFloat64(schema: unknown): schema is TFloat64 { - return IsObject(schema) && schema[Types.Kind] === 'TypeDef:Float64' && schema['type'] === 'float64' + return IsObject(schema) && schema[Types.Symbols.Kind] === 'TypeDef:Float64' && schema['type'] === 'float64' } export function TInt8(schema: unknown): schema is TInt8 { - return IsObject(schema) && schema[Types.Kind] === 'TypeDef:Int8' && schema['type'] === 'int8' + return IsObject(schema) && schema[Types.Symbols.Kind] === 'TypeDef:Int8' && schema['type'] === 'int8' } export function TInt16(schema: unknown): schema is TInt16 { - return IsObject(schema) && schema[Types.Kind] === 'TypeDef:Int16' && schema['type'] === 'int16' + return IsObject(schema) && schema[Types.Symbols.Kind] === 'TypeDef:Int16' && schema['type'] === 'int16' } export function TInt32(schema: unknown): schema is TInt32 { - return IsObject(schema) && schema[Types.Kind] === 'TypeDef:Int32' && schema['type'] === 'int32' + return IsObject(schema) && schema[Types.Symbols.Kind] === 'TypeDef:Int32' && schema['type'] === 'int32' } export function TUint8(schema: unknown): schema is TUint8 { - return IsObject(schema) && schema[Types.Kind] === 'TypeDef:Uint8' && schema['type'] === 'uint8' + return IsObject(schema) && schema[Types.Symbols.Kind] === 'TypeDef:Uint8' && schema['type'] === 'uint8' } export function TUint16(schema: unknown): schema is TUint16 { - return IsObject(schema) && schema[Types.Kind] === 'TypeDef:Uint16' && schema['type'] === 'uint16' + return IsObject(schema) && schema[Types.Symbols.Kind] === 'TypeDef:Uint16' && schema['type'] === 'uint16' } export function TUint32(schema: unknown): schema is TUint32 { - return IsObject(schema) && schema[Types.Kind] === 'TypeDef:Uint32' && schema['type'] === 'uint32' + return IsObject(schema) && schema[Types.Symbols.Kind] === 'TypeDef:Uint32' && schema['type'] === 'uint32' } export function TRecord(schema: unknown): schema is TRecord { - return IsObject(schema) && schema[Types.Kind] === 'TypeDef:Record' && TSchema(schema['values']) + return IsObject(schema) && schema[Types.Symbols.Kind] === 'TypeDef:Record' && TSchema(schema['values']) } export function TString(schema: unknown): schema is TString { - return IsObject(schema) && schema[Types.Kind] === 'TypeDef:String' && schema['type'] === 'string' + return IsObject(schema) && schema[Types.Symbols.Kind] === 'TypeDef:String' && schema['type'] === 'string' } export function TStruct(schema: unknown): schema is TStruct { - if(!(IsObject(schema) && schema[Types.Kind] === 'TypeDef:Struct' && IsOptionalBoolean(schema['additionalProperties']))) return false + if(!(IsObject(schema) && schema[Types.Symbols.Kind] === 'TypeDef:Struct' && IsOptionalBoolean(schema['additionalProperties']))) return false const optionalProperties = schema['optionalProperties'] const requiredProperties = schema['properties'] const optionalCheck = optionalProperties === undefined || IsObject(optionalProperties) && globalThis.Object.getOwnPropertyNames(optionalProperties).every(key => TSchema(optionalProperties[key])) @@ -440,10 +429,10 @@ export namespace TypeGuard { return optionalCheck && requiredCheck } export function TTimestamp(schema: unknown): schema is TTimestamp { - return IsObject(schema) && schema[Types.Kind] === 'TypeDef:Timestamp' && schema['type'] === 'timestamp' + return IsObject(schema) && schema[Types.Symbols.Kind] === 'TypeDef:Timestamp' && schema['type'] === 'timestamp' } export function TKind(schema: unknown): schema is Types.TKind { - return IsObject(schema) && Types.Kind in schema && typeof (schema as any)[Types.Kind] === 'string' // TS 4.1.5: any required for symbol indexer + return IsObject(schema) && Types.Symbols.Kind in schema && typeof (schema as any)[Types.Symbols.Kind] === 'string' // TS 4.1.5: any required for symbol indexer } export function TSchema(schema: unknown): schema is Types.TSchema { // prettier-ignore @@ -464,7 +453,7 @@ export namespace TypeGuard { TString(schema) || TStruct(schema) || TTimestamp(schema) || - (TKind(schema) && Types.TypeRegistry.Has(schema[Types.Kind])) + (TKind(schema) && Types.TypeRegistry.Has(schema[Types.Symbols.Kind])) ) } } @@ -488,7 +477,7 @@ Types.TypeRegistry.Set('TypeDef:Timestamp', (schema, value) => Value // TypeSystemErrorFunction // -------------------------------------------------------------------------- TypeSystemErrorFunction.Set((schema, type) => { - switch(schema[Types.Kind]) { + switch(schema[Types.Symbols.Kind]) { case 'TypeDef:Array': return 'Expected Array' case 'TypeDef:Boolean': return 'Expected Boolean' case 'TypeDef:Union': return 'Expected Union' @@ -536,55 +525,55 @@ export class TypeDefBuilder { // ------------------------------------------------------------------------ /** [Standard] Creates a Array type */ public Array(elements: T, metadata: Metadata = {}): TArray { - return this.Create({ [Types.Kind]: 'TypeDef:Array', elements }, metadata) + return this.Create({ [Types.Symbols.Kind]: 'TypeDef:Array', elements }, metadata) } /** [Standard] Creates a Boolean type */ public Boolean(metadata: Metadata = {}): TBoolean { - return this.Create({ [Types.Kind]: 'TypeDef:Boolean', type: 'boolean' }, metadata) + return this.Create({ [Types.Symbols.Kind]: 'TypeDef:Boolean', type: 'boolean' }, metadata) } /** [Standard] Creates a Enum type */ public Enum(values: [...T], metadata: Metadata = {}): TEnum { - return this.Create({[Types.Kind]: 'TypeDef:Enum', enum: values }, metadata ) + return this.Create({[Types.Symbols.Kind]: 'TypeDef:Enum', enum: values }, metadata ) } /** [Standard] Creates a Float32 type */ public Float32(metadata: Metadata = {}): TFloat32 { - return this.Create({ [Types.Kind]: 'TypeDef:Float32', type: 'float32' }, metadata) + return this.Create({ [Types.Symbols.Kind]: 'TypeDef:Float32', type: 'float32' }, metadata) } /** [Standard] Creates a Float64 type */ public Float64(metadata: Metadata = {}): TFloat64 { - return this.Create({ [Types.Kind]: 'TypeDef:Float64', type: 'float64' }, metadata) + return this.Create({ [Types.Symbols.Kind]: 'TypeDef:Float64', type: 'float64' }, metadata) } /** [Standard] Creates a Int8 type */ public Int8(metadata: Metadata = {}): TInt8 { - return this.Create({ [Types.Kind]: 'TypeDef:Int8', type: 'int8' }, metadata) + return this.Create({ [Types.Symbols.Kind]: 'TypeDef:Int8', type: 'int8' }, metadata) } /** [Standard] Creates a Int16 type */ public Int16(metadata: Metadata = {}): TInt16 { - return this.Create({ [Types.Kind]: 'TypeDef:Int16', type: 'int16' }, metadata) + return this.Create({ [Types.Symbols.Kind]: 'TypeDef:Int16', type: 'int16' }, metadata) } /** [Standard] Creates a Int32 type */ public Int32(metadata: Metadata = {}): TInt32 { - return this.Create({ [Types.Kind]: 'TypeDef:Int32', type: 'int32' }, metadata) + return this.Create({ [Types.Symbols.Kind]: 'TypeDef:Int32', type: 'int32' }, metadata) } /** [Standard] Creates a Uint8 type */ public Uint8(metadata: Metadata = {}): TUint8 { - return this.Create({ [Types.Kind]: 'TypeDef:Uint8', type: 'uint8' }, metadata) + return this.Create({ [Types.Symbols.Kind]: 'TypeDef:Uint8', type: 'uint8' }, metadata) } /** [Standard] Creates a Uint16 type */ public Uint16(metadata: Metadata = {}): TUint16 { - return this.Create({ [Types.Kind]: 'TypeDef:Uint16', type: 'uint16' }, metadata) + return this.Create({ [Types.Symbols.Kind]: 'TypeDef:Uint16', type: 'uint16' }, metadata) } /** [Standard] Creates a Uint32 type */ public Uint32(metadata: Metadata = {}): TUint32 { - return this.Create({ [Types.Kind]: 'TypeDef:Uint32', type: 'uint32' }, metadata) + return this.Create({ [Types.Symbols.Kind]: 'TypeDef:Uint32', type: 'uint32' }, metadata) } /** [Standard] Creates a Record type */ public Record(values: T, metadata: Metadata = {}): TRecord { - return this.Create({ [Types.Kind]: 'TypeDef:Record', values },metadata) + return this.Create({ [Types.Symbols.Kind]: 'TypeDef:Record', values },metadata) } /** [Standard] Creates a String type */ public String(metadata: Metadata = {}): TString { - return this.Create({ [Types.Kind]: 'TypeDef:String', type: 'string' }, metadata) + return this.Create({ [Types.Symbols.Kind]: 'TypeDef:String', type: 'string' }, metadata) } /** [Standard] Creates a Struct type */ public Struct(fields: T, metadata: StructMetadata = {}): TStruct { @@ -592,18 +581,18 @@ export class TypeDefBuilder { const properties = globalThis.Object.getOwnPropertyNames(fields).reduce((acc, key) => (Types.TypeGuard.TOptional(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) + return this.Create({ [Types.Symbols.Kind]: 'TypeDef:Struct', ...requiredObject, ...optionalObject }, metadata) } /** [Standard] Creates a Union type */ public Union[], D extends string = 'type'>(structs: [...T], discriminator?: D): TUnion { discriminator = (discriminator || 'type') as D if (structs.length === 0) throw new Error('TypeDefBuilder: Union types must contain at least one struct') const mapping = structs.reduce((acc, current, index) => ({ ...acc, [index.toString()]: current }), {}) - return this.Create({ [Types.Kind]: 'TypeDef:Union', discriminator, mapping }, {}) + return this.Create({ [Types.Symbols.Kind]: 'TypeDef:Union', discriminator, mapping }, {}) } /** [Standard] Creates a Timestamp type */ public Timestamp(metadata: Metadata = {}): TTimestamp { - return this.Create({ [Types.Kind]: 'TypeDef:Timestamp', type: 'timestamp' }, metadata) + return this.Create({ [Types.Symbols.Kind]: 'TypeDef:Timestamp', type: 'timestamp' }, metadata) } } diff --git a/hammer.mjs b/hammer.mjs index 2e02a034e..8e8a985ee 100644 --- a/hammer.mjs +++ b/hammer.mjs @@ -65,6 +65,13 @@ export async function build(target = 'target/build') { await folder(target).add('license') await shell(`cd ${target} && npm pack`) } +// ------------------------------------------------------------------------------- +// Install +// ------------------------------------------------------------------------------- +export async function install_local(target = 'target/typebox') { + await build(target) + await folder('node_modules').add(target) +} // ------------------------------------------------------------- // Publish // ------------------------------------------------------------- diff --git a/package.json b/package.json index 064dc20a4..91fd92a94 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@sinclair/typebox", - "version": "0.31.28", + "version": "0.32.0-dev-1", "description": "JSONSchema Type Builder with Static Type Resolution for TypeScript", "keywords": [ "typescript", @@ -15,6 +15,7 @@ "exports": { "./compiler": "./compiler/index.js", "./errors": "./errors/index.js", + "./type": "./type/index.js", "./system": "./system/index.js", "./value/cast": "./value/cast.js", "./value/check": "./value/check.js", @@ -30,13 +31,17 @@ "./value/pointer": "./value/pointer.js", "./value/transform": "./value/transform.js", "./value": "./value/index.js", - ".": "./typebox.js" + ".": "./index.js" }, "repository": { "type": "git", "url": "https://github.com/sinclairzx81/typebox" }, "scripts": { + "benchmark:compression": "hammer task benchmark_compression", + "benchmark:measurement": "hammer task benchmark_measurement", + "benchmark": "hammer task benchmark", + "install:local": "hammer task install_local", "test:typescript": "hammer task test_typescript", "test:static": "hammer task test_static", "test:runtime": "hammer task test_runtime", @@ -44,9 +49,6 @@ "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" diff --git a/readme.md b/readme.md index 8ba350169..153aabf95 100644 --- a/readme.md +++ b/readme.md @@ -25,16 +25,10 @@ $ npm install @sinclair/typebox --save ``` -#### Esm + Deno - -```typescript -import { Type, Static } from 'https://esm.sh/@sinclair/typebox' -``` - ## Example ```typescript -import { Type, Static } from '@sinclair/typebox' +import Type { type Static } from '@sinclair/typebox' const T = Type.Object({ // const T = { x: Type.Number(), // type: 'object', @@ -127,7 +121,7 @@ License MIT The following shows general usage. ```typescript -import { Type, Static } from '@sinclair/typebox' +import Type { type Static } from '@sinclair/typebox' //-------------------------------------------------------------------------------------------- // @@ -697,7 +691,7 @@ Object properties can be modified with Readonly and Optional. The following tabl Generic types can be created with generic functions. All types extend the base type TSchema. It is common to constrain generic function arguments to this type. The following creates a generic Vector type. ```typescript -import { Type, Static, TSchema } from '@sinclair/typebox' +import Type, { type Static, type TSchema } from '@sinclair/typebox' const Vector = (t: T) => Type.Object({ x: t, y: t, z: t }) @@ -1047,7 +1041,7 @@ type S = Static // type S = 'A' | 'B' | 'C' TypeBox can type check its own types with the TypeGuard module. This module is written for reflection and provides structural tests for every TypeBox type. Functions of this module return `is` guards which can be used with TypeScript control flow assertions to obtain schema inference. The following guards that the value A is TString. ```typescript -import { Type, Kind, TypeGuard } from '@sinclair/typebox' +import Type, { TypeGuard } from '@sinclair/typebox' const A: unknown = { ... } @@ -1311,12 +1305,12 @@ The TypeBox type system can be extended with additional types and formats using Use the TypeRegistry to register a new type. The Kind must match the registered type name. ```typescript -import { TypeRegistry, Kind } from '@sinclair/typebox' +import { TypeRegistry, Symbols } from '@sinclair/typebox' TypeRegistry.Set('Foo', (schema, value) => value === 'foo') -const A = Value.Check({ [Kind]: 'Foo' }, 'foo') // const A = true -const B = Value.Check({ [Kind]: 'Foo' }, 'bar') // const B = false +const A = Value.Check({ [Symbols.Kind]: 'Foo' }, 'foo') // const A = true +const B = Value.Check({ [Symbols.Kind]: 'Foo' }, 'bar') // const B = false ``` @@ -1355,7 +1349,7 @@ $ npm install ajv ajv-formats --save ``` ```typescript -import { Type } from '@sinclair/typebox' +import Type from '@sinclair/typebox' import addFormats from 'ajv-formats' import Ajv from 'ajv' diff --git a/src/compiler/compiler.ts b/src/compiler/compiler.ts index fe03f6d2e..93d57899d 100644 --- a/src/compiler/compiler.ts +++ b/src/compiler/compiler.ts @@ -32,7 +32,7 @@ import { Errors, ValueErrorIterator } from '../errors/errors' import { TypeSystemPolicy } from '../system/index' import { Deref } from '../value/deref' import { Hash } from '../value/hash' -import * as Types from '../typebox' +import * as Types from '../type/index' // ------------------------------------------------------------------- // CheckFunction @@ -139,12 +139,12 @@ namespace LiteralString { // ------------------------------------------------------------------- // Errors // ------------------------------------------------------------------- -export class TypeCompilerUnknownTypeError extends Types.TypeBoxError { +export class TypeCompilerUnknownTypeError extends Error { constructor(public readonly schema: Types.TSchema) { super('Unknown type') } } -export class TypeCompilerTypeGuardError extends Types.TypeBoxError { +export class TypeCompilerTypeGuardError extends Error { constructor(public readonly schema: Types.TSchema) { super('Preflight validation check failed to guard for the given schema') } @@ -184,7 +184,7 @@ export namespace TypeCompiler { // Guards // ---------------------------------------------------------------------- function IsAnyOrUnknown(schema: Types.TSchema) { - return schema[Types.Kind] === 'Any' || schema[Types.Kind] === 'Unknown' + return schema[Types.Symbols.Kind] === 'Any' || schema[Types.Symbols.Kind] === 'Unknown' } // ------------------------------------------------------------------- // Types @@ -253,11 +253,11 @@ export namespace TypeCompiler { function* TIntersect(schema: Types.TIntersect, references: Types.TSchema[], value: string): IterableIterator { const check1 = schema.allOf.map((schema: Types.TSchema) => CreateExpression(schema, references, value)).join(' && ') if (schema.unevaluatedProperties === false) { - const keyCheck = CreateVariable(`${new RegExp(Types.KeyResolver.ResolvePattern(schema))};`) + const keyCheck = CreateVariable(`${new RegExp(Types.KeyOfStringResolvePattern(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))};`) + const keyCheck = CreateVariable(`${new RegExp(Types.KeyOfStringResolvePattern(schema))};`) const check2 = `Object.getOwnPropertyNames(${value}).every(key => ${keyCheck}.test(key) || ${CreateExpression(schema.unevaluatedProperties, references, `${value}[key]`)})` yield `(${check1} && ${check2})` } else { @@ -302,7 +302,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 (Types.ExtendsUndefinedCheck(property) || IsAnyOrUnknown(property)) yield `('${knownKey}' in ${value})` } else { const expression = CreateExpression(property, references, memberExpression) yield Policy.IsExactOptionalProperty(value, knownKey, expression) @@ -397,7 +397,7 @@ export namespace TypeCompiler { function* TKind(schema: Types.TSchema, references: Types.TSchema[], value: string): IterableIterator { const instance = state.instances.size state.instances.set(instance, schema) - yield `kind('${schema[Types.Kind]}', ${instance}, ${value})` + yield `kind('${schema[Types.Symbols.Kind]}', ${instance}, ${value})` } function* Visit(schema: T, references: Types.TSchema[], value: string, useHoisting: boolean = true): IterableIterator { const references_ = IsString(schema.$id) ? [...references, schema] : references @@ -415,7 +415,7 @@ export namespace TypeCompiler { return yield `${functionName}(${value})` } } - switch (schema_[Types.Kind]) { + switch (schema_[Types.Symbols.Kind]) { case 'Any': return yield* TAny(schema_, references_, value) case 'Array': @@ -477,7 +477,7 @@ export namespace TypeCompiler { case 'Void': return yield* TVoid(schema_, references_, value) default: - if (!Types.TypeRegistry.Has(schema_[Types.Kind])) throw new TypeCompilerUnknownTypeError(schema) + if (!Types.TypeRegistry.Has(schema_[Types.Symbols.Kind])) throw new TypeCompilerUnknownTypeError(schema) return yield* TKind(schema_, references_, value) } } diff --git a/src/errors/errors.ts b/src/errors/errors.ts index 9f09e1f55..7e680b1ed 100644 --- a/src/errors/errors.ts +++ b/src/errors/errors.ts @@ -30,7 +30,7 @@ import { IsArray, IsUint8Array, IsDate, IsPromise, IsFunction, IsAsyncIterator, import { TypeSystemPolicy, TypeSystemErrorFunction } from '../system/system' import { Deref } from '../value/deref' import { Hash } from '../value/hash' -import * as Types from '../typebox' +import * as Types from '../type/index' // -------------------------------------------------------------------------- // ValueErrorType @@ -113,7 +113,7 @@ export interface ValueError { // -------------------------------------------------------------------------- // ValueErrors // -------------------------------------------------------------------------- -export class ValueErrorsUnknownTypeError extends Types.TypeBoxError { +export class ValueErrorsUnknownTypeError extends Error { constructor(public readonly schema: Types.TSchema) { super('Unknown type') } @@ -262,7 +262,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(Types.KeyOfStringResolvePattern(schema)) for (const valueKey of Object.getOwnPropertyNames(value)) { if (!keyCheck.test(valueKey)) { yield Create(ValueErrorType.IntersectUnevaluatedProperties, schema, `${path}/${valueKey}`, value) @@ -270,7 +270,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(Types.KeyOfStringResolvePattern(schema)) for (const valueKey of Object.getOwnPropertyNames(value)) { if (!keyCheck.test(valueKey)) { const next = Visit(schema.unevaluatedProperties, references, `${path}/${valueKey}`, value[valueKey]).next() @@ -344,7 +344,7 @@ function* TObject(schema: Types.TObject, references: Types.TSchema[], path: stri 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 (Types.ExtendsUndefinedCheck(schema) && !(knownKey in value)) { yield Create(ValueErrorType.ObjectRequiredProperty, property, `${path}/${EscapeKey(knownKey)}`, undefined) } } else { @@ -466,13 +466,13 @@ function* TVoid(schema: Types.TVoid, references: Types.TSchema[], path: string, if (!TypeSystemPolicy.IsVoidLike(value)) yield Create(ValueErrorType.Void, schema, path, value) } function* TKind(schema: Types.TSchema, references: Types.TSchema[], path: string, value: any): IterableIterator { - const check = Types.TypeRegistry.Get(schema[Types.Kind])! + const check = Types.TypeRegistry.Get(schema[Types.Symbols.Kind])! if (!check(schema, value)) yield Create(ValueErrorType.Kind, schema, path, value) } function* Visit(schema: T, references: Types.TSchema[], path: string, value: any): IterableIterator { const references_ = IsDefined(schema.$id) ? [...references, schema] : references const schema_ = schema as any - switch (schema_[Types.Kind]) { + switch (schema_[Types.Symbols.Kind]) { case 'Any': return yield* TAny(schema_, references_, path, value) case 'Array': @@ -534,7 +534,7 @@ function* Visit(schema: T, references: Types.TSchema[], case 'Void': return yield* TVoid(schema_, references_, path, value) default: - if (!Types.TypeRegistry.Has(schema_[Types.Kind])) throw new ValueErrorsUnknownTypeError(schema) + if (!Types.TypeRegistry.Has(schema_[Types.Symbols.Kind])) throw new ValueErrorsUnknownTypeError(schema) return yield* TKind(schema_, references_, path, value) } } diff --git a/src/index.ts b/src/index.ts new file mode 100644 index 000000000..693ebaacd --- /dev/null +++ b/src/index.ts @@ -0,0 +1,106 @@ +/*-------------------------------------------------------------------------- + +@sinclair/typebox + +The MIT License (MIT) + +Copyright (c) 2017-2023 Haydn Paterson (sinclair) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +---------------------------------------------------------------------------*/ + +// ------------------------------------------------------------------ +// Types +// ------------------------------------------------------------------ +export { type TAny, Any } from './type/any/index' +export { type TArray, type ArrayOptions, Array } from './type/array/index' +export { type TAsyncIterator, AsyncIterator } from './type/async-iterator/index' +export { type TAwaited, Awaited } from './type/awaited/index' +export { type TBigInt, BigIntOptions, BigInt } from './type/bigint/index' +export { type TBoolean, Boolean } from './type/boolean/index' +export { type TCapitalize, Capitalize } from './type/intrinsic/index' +export { type TComposite, Composite } from './type/composite/index' +export { type TConstructor, Constructor } from './type/constructor/index' +export { type TConstructorParameters, ConstructorParameters } from './type/constructor-parameters/index' +export { type TDate, type DateOptions, Date } from './type/date/index' +export { type TEnum, Enum } from './type/enum/index' +export { type TExclude, Exclude } from './type/exclude/index' +export { type TExtends, Extends } from './type/extends/index' +export { type TExtract, Extract } from './type/extract/index' +export { type TFunction, Function } from './type/function/index' +export { type Assert, type AssertType, type AssertRest, type AssertProperties, type Ensure, type Evaluate } from './type/helpers/index' +export { type TIndex, Index } from './type/indexed/index' +export { type TInstanceType, InstanceType } from './type/instance-type/index' +export { type TInteger, type IntegerOptions, Integer } from './type/integer/index' +export { type TIntersect, type IntersectOptions, Intersect } from './type/intersect/index' +export { type TIterator, Iterator } from './type/iterator/index' +export { type TKeyOf, KeyOf } from './type/keyof/index' +export { type TLiteral, Literal } from './type/literal/index' +export { type TLowercase, Lowercase } from './type/intrinsic/index' +export { type TNever, Never } from './type/never/index' +export { type TNot, Not } from './type/not/index' +export { type TNull, Null } from './type/null/index' +export { type TNumber, type NumberOptions, Number } from './type/number/index' +export { type TObject, type TProperties, type ObjectOptions, Object } from './type/object/index' +export { type TOmit, Omit } from './type/omit/index' +export { type TOptional, Optional } from './type/optional/index' +export { type TParameters, Parameters } from './type/parameters/index' +export { type TPartial, Partial } from './type/partial/index' +export { type TPick, Pick } from './type/pick/index' +export { type TPromise, Promise } from './type/promise/index' +export { type TReadonly, Readonly } from './type/readonly/index' +export { type TReadonlyOptional, ReadonlyOptional } from './type/readonly-optional/index' +export { type TRecord, Record } from './type/record/index' +export { type TRecursive, type TThis, Recursive } from './type/recursive/index' +export { type TRef, Ref } from './type/ref/index' +export { type TRegExp, RegExp } from './type/regexp/index' +export { type TRequired, Required } from './type/required/index' +export { type TRest, Rest } from './type/rest/index' +export { type TReturnType, ReturnType } from './type/return-type/index' +export { type TSchema, type SchemaOptions } from './type/schema/index' +export { type Static, type StaticDecode, type StaticEncode } from './type/static/index' +export { type TString, type StringOptions, type StringFormatOption, type StringContentEncodingOption, String } from './type/string/index' +export { type TSymbol, type SymbolValue, Symbol } from './type/symbol/index' +export { type TTemplateLiteral, type TTemplateLiteralKind, TemplateLiteral } from './type/template-literal/index' +export { type TTransform, type TransformOptions, type TransformFunction, TransformDecodeBuilder, TransformEncodeBuilder, Transform } from './type/transform/index' +export { type TTuple, Tuple } from './type/tuple/index' +export { type TUint8Array, type Uint8ArrayOptions, Uint8Array } from './type/uint8array/index' +export { type TUncapitalize, Uncapitalize } from './type/intrinsic/index' +export { type TUndefined, Undefined } from './type/undefined/index' +export { type TUnion, Union } from './type/union/index' +export { type TUnknown, Unknown } from './type/unknown/index' +export { type TUnsafe, Unsafe } from './type/unsafe/index' +export { type TUppercase, Uppercase } from './type/intrinsic/index' +export { type TVoid, Void } from './type/void/index' +// ------------------------------------------------------------------ +// Infrastructure +// ------------------------------------------------------------------ +export { TypeRegistry, FormatRegistry } from './type/registry/index' +export { TypeGuard, ValueGuard } from './type/guard/index' +export { CloneType, CloneRest } from './type/clone/type' +export { Clone } from './type/clone/value' +export { Strict } from './type/strict/index' +export { Symbols } from './type/symbols/index' +// ------------------------------------------------------------------ +// Builder +// ------------------------------------------------------------------ +export { Type } from './type/builder/index' +import { Type } from './type/builder/index' +export default Type diff --git a/src/system/system.ts b/src/system/system.ts index 528286259..e2f80738e 100644 --- a/src/system/system.ts +++ b/src/system/system.ts @@ -28,17 +28,17 @@ THE SOFTWARE. import { IsObject, IsArray, IsNumber, IsUndefined } from '../value/guard' import { ValueErrorType } from '../errors/errors' -import * as Types from '../typebox' +import * as Types from '../type/index' // -------------------------------------------------------------------------- // Errors // -------------------------------------------------------------------------- -export class TypeSystemDuplicateTypeKind extends Types.TypeBoxError { +export class TypeSystemDuplicateTypeKind extends Error { constructor(kind: string) { super(`Duplicate type kind '${kind}' detected`) } } -export class TypeSystemDuplicateFormat extends Types.TypeBoxError { +export class TypeSystemDuplicateFormat extends Error { constructor(kind: string) { super(`Duplicate string format '${kind}' detected`) } @@ -52,7 +52,7 @@ export namespace TypeSystem { export function Type>(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 = {}) => Types.Type.Unsafe({ ...options, [Types.Kind]: kind }) + return (options: Partial = {}) => Types.Type.Unsafe({ ...options, [Types.Symbols.Kind]: kind }) } /** Creates a new string format */ export function Format(format: F, check: (value: string) => boolean): F { @@ -252,7 +252,7 @@ export function DefaultErrorFunction(schema: Types.TSchema, errorType: ValueErro case ValueErrorType.Void: return 'Expected void' case ValueErrorType.Kind: - return `Expected kind '${schema[Types.Kind]}'` + return `Expected kind '${schema[Types.Symbols.Kind]}'` default: return 'Unknown error type' } diff --git a/src/tsconfig.json b/src/tsconfig.json index c78307cfa..e53e3ebf1 100644 --- a/src/tsconfig.json +++ b/src/tsconfig.json @@ -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"] } diff --git a/src/type/any/any.ts b/src/type/any/any.ts new file mode 100644 index 000000000..4344925ed --- /dev/null +++ b/src/type/any/any.ts @@ -0,0 +1,43 @@ +/*-------------------------------------------------------------------------- + +@sinclair/typebox + +The MIT License (MIT) + +Copyright (c) 2017-2023 Haydn Paterson (sinclair) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +---------------------------------------------------------------------------*/ + +import type { TSchema, SchemaOptions } from '../schema/index' +import { Symbols } from '../symbols/index' + +// ------------------------------------------------------------------ +// TAny +// ------------------------------------------------------------------ +export interface TAny extends TSchema { + [Symbols.Kind]: 'Any' + static: any +} + +/** `[Json]` Creates an Any type */ +export function Any(options: SchemaOptions = {}): TAny { + return { ...options, [Symbols.Kind]: 'Any' } as unknown as TAny +} diff --git a/src/type/any/index.ts b/src/type/any/index.ts new file mode 100644 index 000000000..7f038dec6 --- /dev/null +++ b/src/type/any/index.ts @@ -0,0 +1,29 @@ +/*-------------------------------------------------------------------------- + +@sinclair/typebox + +The MIT License (MIT) + +Copyright (c) 2017-2023 Haydn Paterson (sinclair) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +---------------------------------------------------------------------------*/ + +export * from './any' diff --git a/src/type/array/array.ts b/src/type/array/array.ts new file mode 100644 index 000000000..b11b832fe --- /dev/null +++ b/src/type/array/array.ts @@ -0,0 +1,65 @@ +/*-------------------------------------------------------------------------- + +@sinclair/typebox + +The MIT License (MIT) + +Copyright (c) 2017-2023 Haydn Paterson (sinclair) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +---------------------------------------------------------------------------*/ + +import type { TSchema, SchemaOptions } from '../schema/index' +import type { Static } from '../static/index' +import { Symbols } from '../symbols/index' +import { CloneType } from '../clone/type' + +// ------------------------------------------------------------------ +// TArray +// ------------------------------------------------------------------ +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 extends TSchema, ArrayOptions { + [Symbols.Kind]: 'Array' + static: Static[] + type: 'array' + items: T +} +/** `[Json]` Creates an Array type */ +export function Array(schema: T, options: ArrayOptions = {}): TArray { + return { + ...options, + [Symbols.Kind]: 'Array', + type: 'array', + items: CloneType(schema), + } as unknown as TArray +} diff --git a/src/type/array/index.ts b/src/type/array/index.ts new file mode 100644 index 000000000..a221390e9 --- /dev/null +++ b/src/type/array/index.ts @@ -0,0 +1,29 @@ +/*-------------------------------------------------------------------------- + +@sinclair/typebox + +The MIT License (MIT) + +Copyright (c) 2017-2023 Haydn Paterson (sinclair) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +---------------------------------------------------------------------------*/ + +export * from './array' diff --git a/src/type/async-iterator/async-iterator.ts b/src/type/async-iterator/async-iterator.ts new file mode 100644 index 000000000..889167ad3 --- /dev/null +++ b/src/type/async-iterator/async-iterator.ts @@ -0,0 +1,51 @@ +/*-------------------------------------------------------------------------- + +@sinclair/typebox + +The MIT License (MIT) + +Copyright (c) 2017-2023 Haydn Paterson (sinclair) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +---------------------------------------------------------------------------*/ + +import type { TSchema, SchemaOptions } from '../schema/index' +import type { Static } from '../static/index' +import { Symbols } from '../symbols/index' +import { CloneType } from '../clone/type' + +// ------------------------------------------------------------------ +// TAsyncIterator +// ------------------------------------------------------------------ +export interface TAsyncIterator extends TSchema { + [Symbols.Kind]: 'AsyncIterator' + static: AsyncIterableIterator> + type: 'AsyncIterator' + items: T +} +/** `[JavaScript]` Creates a AsyncIterator type */ +export function AsyncIterator(items: T, options: SchemaOptions = {}): TAsyncIterator { + return { + ...options, + [Symbols.Kind]: 'AsyncIterator', + type: 'AsyncIterator', + items: CloneType(items), + } as unknown as TAsyncIterator +} diff --git a/src/type/async-iterator/index.ts b/src/type/async-iterator/index.ts new file mode 100644 index 000000000..8ee80e658 --- /dev/null +++ b/src/type/async-iterator/index.ts @@ -0,0 +1,29 @@ +/*-------------------------------------------------------------------------- + +@sinclair/typebox + +The MIT License (MIT) + +Copyright (c) 2017-2023 Haydn Paterson (sinclair) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +---------------------------------------------------------------------------*/ + +export * from './async-iterator' diff --git a/src/type/awaited/awaited.ts b/src/type/awaited/awaited.ts new file mode 100644 index 000000000..649cc947f --- /dev/null +++ b/src/type/awaited/awaited.ts @@ -0,0 +1,105 @@ +/*-------------------------------------------------------------------------- + +@sinclair/typebox + +The MIT License (MIT) + +Copyright (c) 2017-2023 Haydn Paterson (sinclair) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +---------------------------------------------------------------------------*/ + +import type { TSchema, SchemaOptions } from '../schema/index' +import { type TIntersect, Intersect } from '../intersect/index' +import { type TUnion, Union } from '../union/index' +import { type TPromise } from '../promise/index' +import { CloneType } from '../clone/type' +import { TIntersect as IsIntersectType, TUnion as IsUnionType, TPromise as IsPromiseType } from '../guard/type' + +// ------------------------------------------------------------------ +// AwaitedResolve +// ------------------------------------------------------------------ +// prettier-ignore +export type AwaitedUnwrap = + T extends [infer L extends TSchema, ...infer R extends TSchema[]] + ? [AwaitedResolve, ...AwaitedUnwrap] + : [] +// prettier-ignore +function AwaitedUnwrap(T: [...T]) : AwaitedUnwrap { + const [L, ...R] = T + return ( + T.length > 0 + ? [Resolve(L), ...AwaitedUnwrap(R)] + : [] + ) as AwaitedUnwrap +} +// ---------------------------------------------------------------- +// IntersectRest +// ---------------------------------------------------------------- +// prettier-ignore +export type AwaitedIntersectRest = TIntersect> +// prettier-ignore +export function AwaitedIntersectRest(T: [...T]): AwaitedIntersectRest { + return Intersect(AwaitedUnwrap(T) as TSchema[]) as unknown as AwaitedIntersectRest +} +// ---------------------------------------------------------------- +// UnionRest +// ---------------------------------------------------------------- +// prettier-ignore +export type AwaitedUnionRest = TUnion> +// prettier-ignore +export function AwaitedUnionRest(T: [...T]): AwaitedUnionRest { + return Union(AwaitedUnwrap(T) as TSchema[]) as unknown as AwaitedUnionRest +} +// ---------------------------------------------------------------- +// Promise +// ---------------------------------------------------------------- +export type AwaitedPromise = AwaitedResolve +// prettier-ignore +export function AwaitedPromise(T: T): AwaitedPromise { + return Resolve(T) as AwaitedPromise +} +// ---------------------------------------------------------------- +// Resolve +// ---------------------------------------------------------------- +// prettier-ignore +export type AwaitedResolve = + T extends TIntersect ? TIntersect> : + T extends TUnion ? TUnion> : + T extends TPromise ? AwaitedResolve : + T +// prettier-ignore +export function Resolve(T: T): AwaitedResolve { + return ( + IsIntersectType(T) ? AwaitedIntersectRest(T.allOf) : + IsUnionType(T) ? AwaitedUnionRest(T.anyOf) : + IsPromiseType(T) ? AwaitedPromise(T.item) : + T + ) as AwaitedResolve +} +// ------------------------------------------------------------------ +// TAwaited +// ------------------------------------------------------------------ +export type TAwaited = AwaitedResolve + +/** `[JavaScript]` Constructs a type by recursively unwrapping Promise types */ +export function Awaited(T: T, options: SchemaOptions = {}): AwaitedResolve { + return CloneType(Resolve(T), options) +} diff --git a/src/type/awaited/index.ts b/src/type/awaited/index.ts new file mode 100644 index 000000000..a46d4bca0 --- /dev/null +++ b/src/type/awaited/index.ts @@ -0,0 +1,29 @@ +/*-------------------------------------------------------------------------- + +@sinclair/typebox + +The MIT License (MIT) + +Copyright (c) 2017-2023 Haydn Paterson (sinclair) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +---------------------------------------------------------------------------*/ + +export * from './awaited' diff --git a/src/type/bigint/bigint.ts b/src/type/bigint/bigint.ts new file mode 100644 index 000000000..b22715f51 --- /dev/null +++ b/src/type/bigint/bigint.ts @@ -0,0 +1,54 @@ +/*-------------------------------------------------------------------------- + +@sinclair/typebox + +The MIT License (MIT) + +Copyright (c) 2017-2023 Haydn Paterson (sinclair) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +---------------------------------------------------------------------------*/ + +import type { TSchema, SchemaOptions } from '../schema/index' +import { Symbols } from '../symbols/index' + +// ------------------------------------------------------------------ +// TBigInt +// ------------------------------------------------------------------ +export interface BigIntOptions extends SchemaOptions { + exclusiveMaximum?: bigint + exclusiveMinimum?: bigint + maximum?: bigint + minimum?: bigint + multipleOf?: bigint +} +export interface TBigInt extends TSchema, BigIntOptions { + [Symbols.Kind]: 'BigInt' + static: bigint + type: 'bigint' +} +/** `[JavaScript]` Creates a BigInt type */ +export function BigInt(options: BigIntOptions = {}): TBigInt { + return { + ...options, + [Symbols.Kind]: 'BigInt', + type: 'bigint', + } as TBigInt +} diff --git a/src/type/bigint/index.ts b/src/type/bigint/index.ts new file mode 100644 index 000000000..3b5095f8f --- /dev/null +++ b/src/type/bigint/index.ts @@ -0,0 +1,29 @@ +/*-------------------------------------------------------------------------- + +@sinclair/typebox + +The MIT License (MIT) + +Copyright (c) 2017-2023 Haydn Paterson (sinclair) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +---------------------------------------------------------------------------*/ + +export * from './bigint' diff --git a/src/type/boolean/boolean.ts b/src/type/boolean/boolean.ts new file mode 100644 index 000000000..833a165ab --- /dev/null +++ b/src/type/boolean/boolean.ts @@ -0,0 +1,47 @@ +/*-------------------------------------------------------------------------- + +@sinclair/typebox + +The MIT License (MIT) + +Copyright (c) 2017-2023 Haydn Paterson (sinclair) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +---------------------------------------------------------------------------*/ + +import type { TSchema, SchemaOptions } from '../schema/index' +import { Symbols } from '../symbols/index' + +// ------------------------------------------------------------------ +// TBoolean +// ------------------------------------------------------------------ +export interface TBoolean extends TSchema { + [Symbols.Kind]: 'Boolean' + static: boolean + type: 'boolean' +} +/** `[Json]` Creates a Boolean type */ +export function Boolean(options: SchemaOptions = {}): TBoolean { + return { + ...options, + [Symbols.Kind]: 'Boolean', + type: 'boolean', + } as unknown as TBoolean +} diff --git a/src/type/boolean/index.ts b/src/type/boolean/index.ts new file mode 100644 index 000000000..11285b97c --- /dev/null +++ b/src/type/boolean/index.ts @@ -0,0 +1,29 @@ +/*-------------------------------------------------------------------------- + +@sinclair/typebox + +The MIT License (MIT) + +Copyright (c) 2017-2023 Haydn Paterson (sinclair) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +---------------------------------------------------------------------------*/ + +export * from './boolean' diff --git a/src/type/builder/builder.ts b/src/type/builder/builder.ts new file mode 100644 index 000000000..c10152207 --- /dev/null +++ b/src/type/builder/builder.ts @@ -0,0 +1,87 @@ +/*-------------------------------------------------------------------------- + +@sinclair/typebox + +The MIT License (MIT) + +Copyright (c) 2017-2023 Haydn Paterson (sinclair) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +---------------------------------------------------------------------------*/ + +// ------------------------------------------------------------------ +// TypeBuilder +// ------------------------------------------------------------------ + +export { Any } from '../any/index' +export { Array } from '../array/index' +export { AsyncIterator } from '../async-iterator/index' +export { Awaited } from '../awaited/index' +export { BigInt } from '../bigint/index' +export { Boolean } from '../boolean/index' +export { Composite } from '../composite/index' +export { Constructor } from '../constructor/index' +export { ConstructorParameters } from '../constructor-parameters/index' +export { Date } from '../date/index' +export { Enum } from '../enum/index' +export { Exclude } from '../exclude/index' +export { Extends } from '../extends/index' +export { Extract } from '../extract/index' +export { Function } from '../function/index' +export { Index } from '../indexed/index' +export { InstanceType } from '../instance-type/index' +export { Integer } from '../integer/index' +export { Intersect } from '../intersect/index' +export { Capitalize, Uncapitalize, Lowercase, Uppercase } from '../intrinsic/index' +export { Iterator } from '../iterator/index' +export { KeyOf } from '../keyof/index' +export { Literal } from '../literal/index' +export { Never } from '../never/index' +export { Not } from '../not/index' +export { Null } from '../null/index' +export { Number } from '../number/index' +export { Object } from '../object/index' +export { Omit } from '../omit/index' +export { Optional } from '../optional/index' +export { Parameters } from '../parameters/index' +export { Partial } from '../partial/index' +export { Pick } from '../pick/index' +export { Promise } from '../promise/index' +export { Readonly } from '../readonly/index' +export { ReadonlyOptional } from '../readonly-optional/index' +export { Record } from '../record/index' +export { Recursive } from '../recursive/index' +export { Ref } from '../ref/index' +export { RegExp } from '../regexp/index' +export { Required } from '../required/index' +export { Rest } from '../rest/index' +export { ReturnType } from '../return-type/index' +export { Strict } from '../strict/index' +export { String } from '../string/index' +export { Symbol } from '../symbol/index' +export { TemplateLiteral } from '../template-literal/index' +export { Transform } from '../transform/index' +export { Tuple } from '../tuple/index' +export { Uint8Array } from '../uint8array/index' +export { Undefined } from '../undefined/index' +export { Union } from '../union/index' +export { Unknown } from '../unknown/index' +export { Unsafe } from '../unsafe/index' +export { Void } from '../void/index' diff --git a/src/type/builder/index.ts b/src/type/builder/index.ts new file mode 100644 index 000000000..5e10470bc --- /dev/null +++ b/src/type/builder/index.ts @@ -0,0 +1,29 @@ +/*-------------------------------------------------------------------------- + +@sinclair/typebox + +The MIT License (MIT) + +Copyright (c) 2017-2023 Haydn Paterson (sinclair) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +---------------------------------------------------------------------------*/ + +export * as Type from './builder' diff --git a/src/type/clone/index.ts b/src/type/clone/index.ts new file mode 100644 index 000000000..64b9339bd --- /dev/null +++ b/src/type/clone/index.ts @@ -0,0 +1,30 @@ +/*-------------------------------------------------------------------------- + +@sinclair/typebox + +The MIT License (MIT) + +Copyright (c) 2017-2023 Haydn Paterson (sinclair) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +---------------------------------------------------------------------------*/ + +export * as TypeClone from './type' +export * as ValueClone from './value' diff --git a/src/type/clone/type.ts b/src/type/clone/type.ts new file mode 100644 index 000000000..5a44a99e0 --- /dev/null +++ b/src/type/clone/type.ts @@ -0,0 +1,39 @@ +/*-------------------------------------------------------------------------- + +@sinclair/typebox + +The MIT License (MIT) + +Copyright (c) 2017-2023 Haydn Paterson (sinclair) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +---------------------------------------------------------------------------*/ + +import type { TSchema, SchemaOptions } from '../schema/index' +import { Clone } from './value' + +/** Clones a Rest */ +export function CloneRest(schemas: T): T { + return schemas.map((schema) => CloneType(schema)) as T +} +/** Clones a Type */ +export function CloneType(schema: T, options: SchemaOptions = {}): T { + return { ...Clone(schema), ...options } +} diff --git a/src/type/clone/value.ts b/src/type/clone/value.ts new file mode 100644 index 000000000..a60cb8612 --- /dev/null +++ b/src/type/clone/value.ts @@ -0,0 +1,58 @@ +/*-------------------------------------------------------------------------- + +@sinclair/typebox + +The MIT License (MIT) + +Copyright (c) 2017-2023 Haydn Paterson (sinclair) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +---------------------------------------------------------------------------*/ + +import * as 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 ObjectType(value: Record) { + 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.IsObject(value) ? ObjectType(value) : + value + ) +} +/** Clones a value */ +export function Clone(value: T): T { + return Visit(value) +} diff --git a/src/type/composite/composite.ts b/src/type/composite/composite.ts new file mode 100644 index 000000000..0c6abe8a0 --- /dev/null +++ b/src/type/composite/composite.ts @@ -0,0 +1,72 @@ +/*-------------------------------------------------------------------------- + +@sinclair/typebox + +The MIT License (MIT) + +Copyright (c) 2017-2023 Haydn Paterson (sinclair) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +---------------------------------------------------------------------------*/ + +import type { TSchema } from '../schema/index' +import type { UnionToTuple, Assert, Evaluate } from '../helpers/index' +import { type TObject, type TProperties, type ObjectOptions, Object } from '../object/index' +import { type TIntersect, Intersect } from '../intersect/index' +import { KeyOfStringResolve } from '../keyof/index' +import { IndexedTypeResolve, Index } from '../indexed/index' +import { CloneType } from '../clone/type' + +// ------------------------------------------------------------------ +// CompositeResolve +// ------------------------------------------------------------------ +// prettier-ignore +type CompositeKeys = + T extends [infer L extends TObject, ...infer R extends TObject[]] + ? keyof L['properties'] | CompositeKeys + : never +// prettier-ignore +type CompositeIndex, K extends string[]> = + K extends [infer L extends string, ...infer R extends string[]] + ? { [_ in L]: IndexedTypeResolve } & CompositeIndex + : {} +// prettier-ignore +type CompositeReduce = UnionToTuple> extends infer K + ? Evaluate, Assert>> + : {} // ^ indexed via intersection of T +// prettier-ignore +export type CompositeResolve = TIntersect extends TIntersect + ? TObject> + : TObject<{}> +export function CompositeResolve(T: [...T]): CompositeResolve { + const intersect: TSchema = Intersect(T, {}) + const keys = KeyOfStringResolve(intersect) as string[] + const properties = keys.reduce((acc, key) => ({ ...acc, [key]: Index(intersect, [key]) }), {} as TProperties) + return Object(properties) as CompositeResolve +} +// ------------------------------------------------------------------ +// TComposite +// ------------------------------------------------------------------ +export type TComposite = CompositeResolve + +/** `[Json]` Creates a Composite object type */ +export function Composite(T: [...T], options?: ObjectOptions): CompositeResolve { + return CloneType(CompositeResolve(T) as TObject, options) as CompositeResolve +} diff --git a/src/type/composite/index.ts b/src/type/composite/index.ts new file mode 100644 index 000000000..f23607487 --- /dev/null +++ b/src/type/composite/index.ts @@ -0,0 +1,29 @@ +/*-------------------------------------------------------------------------- + +@sinclair/typebox + +The MIT License (MIT) + +Copyright (c) 2017-2023 Haydn Paterson (sinclair) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +---------------------------------------------------------------------------*/ + +export * from './composite' diff --git a/src/type/constructor-parameters/constructor-parameters.ts b/src/type/constructor-parameters/constructor-parameters.ts new file mode 100644 index 000000000..5aa791c5c --- /dev/null +++ b/src/type/constructor-parameters/constructor-parameters.ts @@ -0,0 +1,46 @@ +/*-------------------------------------------------------------------------- + +@sinclair/typebox + +The MIT License (MIT) + +Copyright (c) 2017-2023 Haydn Paterson (sinclair) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +---------------------------------------------------------------------------*/ + +import type { TSchema, SchemaOptions } from '../schema/index' +import type { Ensure } from '../helpers/index' +import type { TConstructor } from '../constructor/index' +import { type TTuple, Tuple } from '../tuple/index' +import { CloneRest } from '../clone/type' + +// ------------------------------------------------------------------ +// ConstructorParameters +// ------------------------------------------------------------------ +// prettier-ignore +export type TConstructorParameters> = ( + Ensure> +) + +/** `[JavaScript]` Extracts the ConstructorParameters from the given Constructor type */ +export function ConstructorParameters>(schema: T, options: SchemaOptions = {}): TConstructorParameters { + return Tuple(CloneRest(schema.parameters), { ...options }) +} diff --git a/src/type/constructor-parameters/index.ts b/src/type/constructor-parameters/index.ts new file mode 100644 index 000000000..f78668167 --- /dev/null +++ b/src/type/constructor-parameters/index.ts @@ -0,0 +1,29 @@ +/*-------------------------------------------------------------------------- + +@sinclair/typebox + +The MIT License (MIT) + +Copyright (c) 2017-2023 Haydn Paterson (sinclair) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +---------------------------------------------------------------------------*/ + +export * from './constructor-parameters' diff --git a/src/type/constructor/constructor.ts b/src/type/constructor/constructor.ts new file mode 100644 index 000000000..24ba4f8e0 --- /dev/null +++ b/src/type/constructor/constructor.ts @@ -0,0 +1,67 @@ +/*-------------------------------------------------------------------------- + +@sinclair/typebox + +The MIT License (MIT) + +Copyright (c) 2017-2023 Haydn Paterson (sinclair) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +---------------------------------------------------------------------------*/ + +import type { TSchema, SchemaOptions } from '../schema/index' +import type { Static } from '../static/index' +import type { Ensure } from '../helpers/index' +import { Symbols } from '../symbols/index' +import { CloneType, CloneRest } from '../clone/type' + +// ------------------------------------------------------------------ +// TConstructorResolve +// ------------------------------------------------------------------ +export type TConstructorReturnTypeResolve = Static +// prettier-ignore +export type TConstructorParametersResolve = + T extends [infer L extends TSchema, ...infer R extends TSchema[]] + ? [Static, ...TConstructorParametersResolve] + : [] +// prettier-ignore +export type TConstructorResolve = ( + Ensure) => TConstructorReturnTypeResolve> +) +// ------------------------------------------------------------------ +// TConstructor +// ------------------------------------------------------------------ +export interface TConstructor extends TSchema { + [Symbols.Kind]: 'Constructor' + static: TConstructorResolve + type: 'Constructor' + parameters: T + returns: U +} +/** `[JavaScript]` Creates a Constructor type */ +export function Constructor(parameters: [...T], returns: U, options?: SchemaOptions): TConstructor { + return { + ...options, + [Symbols.Kind]: 'Constructor', + type: 'Constructor', + parameters: CloneRest(parameters), + returns: CloneType(returns), + } as unknown as TConstructor +} diff --git a/src/type/constructor/index.ts b/src/type/constructor/index.ts new file mode 100644 index 000000000..f98b707e4 --- /dev/null +++ b/src/type/constructor/index.ts @@ -0,0 +1,29 @@ +/*-------------------------------------------------------------------------- + +@sinclair/typebox + +The MIT License (MIT) + +Copyright (c) 2017-2023 Haydn Paterson (sinclair) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +---------------------------------------------------------------------------*/ + +export * from './constructor' diff --git a/src/type/date/date.ts b/src/type/date/date.ts new file mode 100644 index 000000000..513d76038 --- /dev/null +++ b/src/type/date/date.ts @@ -0,0 +1,59 @@ +/*-------------------------------------------------------------------------- + +@sinclair/typebox + +The MIT License (MIT) + +Copyright (c) 2017-2023 Haydn Paterson (sinclair) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +---------------------------------------------------------------------------*/ + +import type { TSchema, SchemaOptions } from '../schema/index' +import { Symbols } from '../symbols/index' + +// ------------------------------------------------------------------ +// TDate +// ------------------------------------------------------------------ +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 { + [Symbols.Kind]: 'Date' + static: Date + type: 'date' +} +/** `[JavaScript]` Creates a Date type */ +export function Date(options: DateOptions = {}): TDate { + return { + ...options, + [Symbols.Kind]: 'Date', + type: 'Date', + } as unknown as TDate +} diff --git a/src/type/date/index.ts b/src/type/date/index.ts new file mode 100644 index 000000000..58d0e375c --- /dev/null +++ b/src/type/date/index.ts @@ -0,0 +1,29 @@ +/*-------------------------------------------------------------------------- + +@sinclair/typebox + +The MIT License (MIT) + +Copyright (c) 2017-2023 Haydn Paterson (sinclair) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +---------------------------------------------------------------------------*/ + +export * from './date' diff --git a/src/type/discard/discard.ts b/src/type/discard/discard.ts new file mode 100644 index 000000000..a2a1a3b8c --- /dev/null +++ b/src/type/discard/discard.ts @@ -0,0 +1,35 @@ +/*-------------------------------------------------------------------------- + +@sinclair/typebox + +The MIT License (MIT) + +Copyright (c) 2017-2023 Haydn Paterson (sinclair) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +---------------------------------------------------------------------------*/ + +function Key(value: Record, key: PropertyKey) { + const { [key]: _, ...rest } = value + return rest +} +export function Discard(value: Record, keys: PropertyKey[]) { + return keys.reduce((acc, key) => Key(acc, key), value) +} diff --git a/src/type/discard/index.ts b/src/type/discard/index.ts new file mode 100644 index 000000000..73ff2051b --- /dev/null +++ b/src/type/discard/index.ts @@ -0,0 +1,29 @@ +/*-------------------------------------------------------------------------- + +@sinclair/typebox + +The MIT License (MIT) + +Copyright (c) 2017-2023 Haydn Paterson (sinclair) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +---------------------------------------------------------------------------*/ + +export * from './discard' diff --git a/examples/prototypes/const.ts b/src/type/distinct/distinct.ts similarity index 50% rename from examples/prototypes/const.ts rename to src/type/distinct/distinct.ts index 75399a0aa..87dcc7393 100644 --- a/examples/prototypes/const.ts +++ b/src/type/distinct/distinct.ts @@ -1,6 +1,6 @@ /*-------------------------------------------------------------------------- -@sinclair/typebox/prototypes +@sinclair/typebox The MIT License (MIT) @@ -26,36 +26,44 @@ THE SOFTWARE. ---------------------------------------------------------------------------*/ -import { Type, ObjectMap, TypeGuard, TSchema, TIntersect, TUnion, TObject, TProperties, TReadonly, AssertProperties, AssertType, AssertRest, Evaluate, ReadonlyUnwrapType } from '@sinclair/typebox' +import { ExtendsCheck, ExtendsResult } from '../extends/index' +import { TSchema } from '../schema/index' -// ------------------------------------------------------------------------------------- -// TConst -// ------------------------------------------------------------------------------------- +// ------------------------------------------------------------------ +// Includes +// ------------------------------------------------------------------ // prettier-ignore -export type TConstArray = T extends [infer L, ...infer R] - ? [TConst, E>, ...TConstArray, E>] - : [] +type Includes = + T extends [infer L extends TSchema, ...infer R extends TSchema[]] + ? C extends L + ? true + : Includes + : false // prettier-ignore -export type TConstProperties = Evaluate, E> -}>> +function Includes(T: TSchema[], C: TSchema): boolean { + const [L, ...R] = T + return T.length > 0 + ? ExtendsCheck(C, L) === ExtendsResult.True + ? true + : Includes(R, C) + : false +} +// ------------------------------------------------------------------ +// DistinctType +// ------------------------------------------------------------------ // prettier-ignore -export type TConst = - T extends TIntersect ? TIntersect> : - T extends TUnion ? TUnion> : - T extends TObject ? TObject> : - E extends true ? T : TReadonly -// ------------------------------------------------------------------------------------- -// Const -// ------------------------------------------------------------------------------------- -/** `[Experimental]` Assigns readonly to all interior properties */ -export function Const(schema: T): TConst { - const mappable = (TypeGuard.TIntersect(schema) || TypeGuard.TUnion(schema) || TypeGuard.TObject(schema)) - // prettier-ignore - return mappable ? ObjectMap.Map(schema, (object) => { - const properties = Object.getOwnPropertyNames(object.properties).reduce((acc, key) => { - return { ...acc, [key]: Type.Readonly(object.properties[key] )} - }, {} as TProperties) - return Type.Object(properties, {...object}) - }, {}) : schema as any -} \ No newline at end of file +export type DistinctType = + T extends [infer L extends TSchema, ...infer R extends TSchema[]] + ? Includes extends false + ? DistinctType + : DistinctType + : Acc +// prettier-ignore +export function DistinctType(T: TSchema[], Acc: TSchema[] = []): TSchema[] { + const [L, ...R] = T + return T.length > 0 + ? Includes(Acc, L) === false + ? DistinctType(R, [...Acc, L]) + : DistinctType(R, [...Acc]) + : Acc +} diff --git a/src/type/distinct/index.ts b/src/type/distinct/index.ts new file mode 100644 index 000000000..c3e7b0bde --- /dev/null +++ b/src/type/distinct/index.ts @@ -0,0 +1,29 @@ +/*-------------------------------------------------------------------------- + +@sinclair/typebox + +The MIT License (MIT) + +Copyright (c) 2017-2023 Haydn Paterson (sinclair) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +---------------------------------------------------------------------------*/ + +export * from './distinct' diff --git a/src/type/enum/enum.ts b/src/type/enum/enum.ts new file mode 100644 index 000000000..a0e2302ad --- /dev/null +++ b/src/type/enum/enum.ts @@ -0,0 +1,56 @@ +/*-------------------------------------------------------------------------- + +@sinclair/typebox + +The MIT License (MIT) + +Copyright (c) 2017-2023 Haydn Paterson (sinclair) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +---------------------------------------------------------------------------*/ + +import type { TSchema, SchemaOptions } from '../schema/index' +import { type TLiteral, Literal } from '../literal/index' +import { Symbols } from '../symbols/index' +import { Union } from '../union/index' +import { IsUndefined } from '../guard/value' + +// ------------------------------------------------------------------ +// TEnum +// ------------------------------------------------------------------ +export type TEnumRecord = Record +export type TEnumValue = string | number +export type TEnumKey = string +export interface TEnum = Record> extends TSchema { + [Symbols.Kind]: 'Union' + [Symbols.Hint]: 'Enum' + static: T[keyof T] + anyOf: TLiteral[] +} +/** `[Json]` Creates a Enum type */ +export function Enum>(item: T, options: SchemaOptions = {}): TEnum { + 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, [Symbols.Hint]: 'Enum' }) as unknown as TEnum +} diff --git a/src/type/enum/index.ts b/src/type/enum/index.ts new file mode 100644 index 000000000..4cf2b91c2 --- /dev/null +++ b/src/type/enum/index.ts @@ -0,0 +1,29 @@ +/*-------------------------------------------------------------------------- + +@sinclair/typebox + +The MIT License (MIT) + +Copyright (c) 2017-2023 Haydn Paterson (sinclair) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +---------------------------------------------------------------------------*/ + +export * from './enum' diff --git a/src/type/exclude/exclude.ts b/src/type/exclude/exclude.ts new file mode 100644 index 000000000..7b39f1ab7 --- /dev/null +++ b/src/type/exclude/exclude.ts @@ -0,0 +1,83 @@ +/*-------------------------------------------------------------------------- + +@sinclair/typebox + +The MIT License (MIT) + +Copyright (c) 2017-2023 Haydn Paterson (sinclair) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +---------------------------------------------------------------------------*/ + +import type { TSchema, SchemaOptions } from '../schema/index' +import type { UnionToTuple, AssertRest, AssertType, Assert } from '../helpers/index' +import { type TTemplateLiteral, TemplateLiteralToUnion } from '../template-literal/index' +import { type TUnion, Union } from '../union/index' +import { type TNever, Never } from '../never/index' +import { type TLiteral } from '../literal/index' +import { type Static } from '../static/index' +import { ExtendsCheck, ExtendsResult } from '../extends/index' +import { UnionResolve } from '../union/index' +import { CloneType } from '../clone/type' +import { TTemplateLiteral as IsTemplateLiteralType, TUnion as IsUnionType } from '../guard/type' + +// ------------------------------------------------------------------ +// ExcludeResolve +// ------------------------------------------------------------------ +// prettier-ignore +export type ExcludeTemplateLiteralResult = UnionResolve }[T]>>> +// prettier-ignore +export type ExcludeTemplateLiteral = ( + Exclude, Static> extends infer S ? ExcludeTemplateLiteralResult> : never +) +// prettier-ignore +export type ExcludeArray = AssertRest> extends Static ? never : T[K] +}[number]>> extends infer R extends TSchema[] ? UnionResolve : never +// prettier-ignore +export type ExcludeResolve = + T extends TTemplateLiteral ? ExcludeTemplateLiteral : + T extends TUnion ? ExcludeArray : + T extends U + ? TNever + : T +// prettier-ignore +export function ExcludeResolve(L: L, R: R): ExcludeResolve { + return ( + IsTemplateLiteralType(L) ? ExcludeResolve(TemplateLiteralToUnion(L), R) : + IsTemplateLiteralType(R) ? ExcludeResolve(L, TemplateLiteralToUnion(R)) : + IsUnionType(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 ExcludeResolve +} +// ------------------------------------------------------------------ +// TExclude +// ------------------------------------------------------------------ +export type TExclude = ExcludeResolve + +/** `[Json]` Constructs a type by excluding from unionType all union members that are assignable to excludedMembers */ +export function Exclude(unionType: L, excludedMembers: R, options: SchemaOptions = {}): TExclude { + const E = ExcludeResolve(unionType, excludedMembers) as any + return CloneType(E, options) as TExclude +} diff --git a/src/type/exclude/index.ts b/src/type/exclude/index.ts new file mode 100644 index 000000000..e44c31822 --- /dev/null +++ b/src/type/exclude/index.ts @@ -0,0 +1,29 @@ +/*-------------------------------------------------------------------------- + +@sinclair/typebox + +The MIT License (MIT) + +Copyright (c) 2017-2023 Haydn Paterson (sinclair) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +---------------------------------------------------------------------------*/ + +export * from './exclude' diff --git a/src/type/extends/extends-check.ts b/src/type/extends/extends-check.ts new file mode 100644 index 000000000..5990af9f6 --- /dev/null +++ b/src/type/extends/extends-check.ts @@ -0,0 +1,764 @@ +/*-------------------------------------------------------------------------- + +@sinclair/typebox + +The MIT License (MIT) + +Copyright (c) 2017-2023 Haydn Paterson (sinclair) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +---------------------------------------------------------------------------*/ + +import { 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 } 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 { Symbols } from '../symbols/index' +import { TypeGuard, ValueGuard } from '../guard/index' + +export class ExtendsResolverError extends Error {} + +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.TNever(right) || + TypeGuard.TIntersect(right) || + TypeGuard.TUnion(right) || + TypeGuard.TUnknown(right) || + TypeGuard.TAny(right) + ) +} +// prettier-ignore +function StructuralRight(left: TSchema, right: TSchema) { + return ( + TypeGuard.TNever(right) ? TNeverRight(left, right) : + TypeGuard.TIntersect(right) ? TIntersectRight(left, right) : + TypeGuard.TUnion(right) ? TUnionRight(left, right) : + TypeGuard.TUnknown(right) ? TUnknownRight(left, right) : + TypeGuard.TAny(right) ? TAnyRight(left, right) : + Throw('StructuralRight') + ) +} +// ------------------------------------------------------------------ +// Any +// ------------------------------------------------------------------ +// prettier-ignore +function TAnyRight(left: TSchema, right: TAny) { + return ExtendsResult.True +} +// prettier-ignore +function TAny(left: TAny, right: TSchema) { + return ( + TypeGuard.TIntersect(right) ? TIntersectRight(left, right) : + (TypeGuard.TUnion(right) && right.anyOf.some((schema) => TypeGuard.TAny(schema) || TypeGuard.TUnknown(schema))) ? ExtendsResult.True : + TypeGuard.TUnion(right) ? ExtendsResult.Union : + TypeGuard.TUnknown(right) ? ExtendsResult.True : + TypeGuard.TAny(right) ? ExtendsResult.True : + ExtendsResult.Union + ) +} +// ------------------------------------------------------------------ +// Array +// ------------------------------------------------------------------ +// prettier-ignore +function TArrayRight(left: TSchema, right: TArray) { + return ( + TypeGuard.TUnknown(left) ? ExtendsResult.False : + TypeGuard.TAny(left) ? ExtendsResult.Union : + TypeGuard.TNever(left) ? ExtendsResult.True : + ExtendsResult.False + ) +} +// prettier-ignore +function TArray(left: TArray, right: TSchema) { + return ( + TypeGuard.TObject(right) && IsObjectArrayLike(right) ? ExtendsResult.True : + IsStructuralRight(right) ? StructuralRight(left, right) : + !TypeGuard.TArray(right) ? ExtendsResult.False : + IntoBooleanResult(Visit(left.items, right.items)) + ) +} +// ------------------------------------------------------------------ +// AsyncIterator +// ------------------------------------------------------------------ +// prettier-ignore +function TAsyncIterator(left: TAsyncIterator, right: TSchema) { + return ( + IsStructuralRight(right) ? StructuralRight(left, right) : + !TypeGuard.TAsyncIterator(right) ? ExtendsResult.False : + IntoBooleanResult(Visit(left.items, right.items)) + ) +} +// ------------------------------------------------------------------ +// BigInt +// ------------------------------------------------------------------ +// prettier-ignore +function TBigInt(left: TBigInt, right: TSchema): ExtendsResult { + return ( + IsStructuralRight(right) ? StructuralRight(left, right) : + TypeGuard.TObject(right) ? TObjectRight(left, right) : + TypeGuard.TRecord(right) ? TRecordRight(left, right) : + TypeGuard.TBigInt(right) ? ExtendsResult.True : + ExtendsResult.False + ) +} +// ------------------------------------------------------------------ +// Boolean +// ------------------------------------------------------------------ +// prettier-ignore +function TBooleanRight(left: TSchema, right: TBoolean) { + return ( + TypeGuard.TLiteralBoolean(left) ? ExtendsResult.True : + TypeGuard.TBoolean(left) ? ExtendsResult.True : + ExtendsResult.False + ) +} +// prettier-ignore +function TBoolean(left: TBoolean, right: TSchema): ExtendsResult { + return ( + IsStructuralRight(right) ? StructuralRight(left, right) : + TypeGuard.TObject(right) ? TObjectRight(left, right) : + TypeGuard.TRecord(right) ? TRecordRight(left, right) : + TypeGuard.TBoolean(right) ? ExtendsResult.True : + ExtendsResult.False + ) +} +// ------------------------------------------------------------------ +// Constructor +// ------------------------------------------------------------------ +// prettier-ignore +function TConstructor(left: TConstructor, right: TSchema) { + return ( + IsStructuralRight(right) ? StructuralRight(left, right) : + TypeGuard.TObject(right) ? TObjectRight(left, right) : + !TypeGuard.TConstructor(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 TDate(left: TDate, right: TSchema) { + return ( + IsStructuralRight(right) ? StructuralRight(left, right) : + TypeGuard.TObject(right) ? TObjectRight(left, right) : + TypeGuard.TRecord(right) ? TRecordRight(left, right) : + TypeGuard.TDate(right) ? ExtendsResult.True : + ExtendsResult.False + ) +} +// ------------------------------------------------------------------ +// Function +// ------------------------------------------------------------------ +// prettier-ignore +function TFunction(left: TFunction, right: TSchema) { + return ( + IsStructuralRight(right) ? StructuralRight(left, right) : + TypeGuard.TObject(right) ? TObjectRight(left, right) : + !TypeGuard.TFunction(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 TIntegerRight(left: TSchema, right: TInteger) { + return ( + TypeGuard.TLiteral(left) && ValueGuard.IsNumber(left.const) ? ExtendsResult.True : + TypeGuard.TNumber(left) || TypeGuard.TInteger(left) ? ExtendsResult.True : + ExtendsResult.False + ) +} +// prettier-ignore +function TInteger(left: TInteger, right: TSchema): ExtendsResult { + return ( + TypeGuard.TInteger(right) || TypeGuard.TNumber(right) ? ExtendsResult.True : + IsStructuralRight(right) ? StructuralRight(left, right) : + TypeGuard.TObject(right) ? TObjectRight(left, right) : + TypeGuard.TRecord(right) ? TRecordRight(left, right) : + ExtendsResult.False + ) +} +// ------------------------------------------------------------------ +// Intersect +// ------------------------------------------------------------------ +// prettier-ignore +function TIntersectRight(left: TSchema, right: TIntersect): ExtendsResult { + return right.allOf.every((schema) => Visit(left, schema) === ExtendsResult.True) + ? ExtendsResult.True + : ExtendsResult.False +} +// prettier-ignore +function TIntersect(left: TIntersect, right: TSchema) { + return left.allOf.some((schema) => Visit(schema, right) === ExtendsResult.True) + ? ExtendsResult.True + : ExtendsResult.False +} +// ------------------------------------------------------------------ +// Iterator +// ------------------------------------------------------------------ +// prettier-ignore +function TIterator(left: TIterator, right: TSchema) { + return ( + IsStructuralRight(right) ? StructuralRight(left, right) : + !TypeGuard.TIterator(right) ? ExtendsResult.False : + IntoBooleanResult(Visit(left.items, right.items)) + ) +} +// ------------------------------------------------------------------ +// Literal +// ------------------------------------------------------------------ +// prettier-ignore +function TLiteral(left: TLiteral, right: TSchema): ExtendsResult { + return ( + TypeGuard.TLiteral(right) && right.const === left.const ? ExtendsResult.True : + IsStructuralRight(right) ? StructuralRight(left, right) : + TypeGuard.TObject(right) ? TObjectRight(left, right) : + TypeGuard.TRecord(right) ? TRecordRight(left, right) : + TypeGuard.TString(right) ? TStringRight(left, right) : + TypeGuard.TNumber(right) ? TNumberRight(left, right) : + TypeGuard.TInteger(right) ? TIntegerRight(left, right) : + TypeGuard.TBoolean(right) ? TBooleanRight(left, right) : + ExtendsResult.False + ) +} +// ------------------------------------------------------------------ +// Never +// ------------------------------------------------------------------ +// prettier-ignore +function TNeverRight(left: TSchema, right: TNever) { + return ExtendsResult.False +} +// prettier-ignore +function TNever(left: TNever, right: TSchema) { + return ExtendsResult.True +} +// ------------------------------------------------------------------ +// Not +// ------------------------------------------------------------------ +// prettier-ignore +function UnwrapTNot(schema: T): TUnknown | TNot['not'] { + let [current, depth]: [TSchema, number] = [schema, 0] + while (true) { + if (!TypeGuard.TNot(current)) break + current = current.not + depth += 1 + } + return depth % 2 === 0 ? current : Unknown() +} +// prettier-ignore +function TNot(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.TNot(left) ? Visit(UnwrapTNot(left), right) : + TypeGuard.TNot(right) ? Visit(left, UnwrapTNot(right)) : + Throw('Invalid fallthrough for Not') + ) +} +// ------------------------------------------------------------------ +// Null +// ------------------------------------------------------------------ +// prettier-ignore +function TNull(left: TNull, right: TSchema) { + return ( + IsStructuralRight(right) ? StructuralRight(left, right) : + TypeGuard.TObject(right) ? TObjectRight(left, right) : + TypeGuard.TRecord(right) ? TRecordRight(left, right) : + TypeGuard.TNull(right) ? ExtendsResult.True : + ExtendsResult.False + ) +} +// ------------------------------------------------------------------ +// Number +// ------------------------------------------------------------------ +// prettier-ignore +function TNumberRight(left: TSchema, right: TNumber) { + return ( + TypeGuard.TLiteralNumber(left) ? ExtendsResult.True : + TypeGuard.TNumber(left) || TypeGuard.TInteger(left) ? ExtendsResult.True : + ExtendsResult.False + ) +} +// prettier-ignore +function TNumber(left: TNumber, right: TSchema): ExtendsResult { + return ( + IsStructuralRight(right) ? StructuralRight(left, right) : + TypeGuard.TObject(right) ? TObjectRight(left, right) : + TypeGuard.TRecord(right) ? TRecordRight(left, right) : + TypeGuard.TInteger(right) || TypeGuard.TNumber(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.TUnion(schema.properties.description) && schema.properties.description.anyOf.length === 2 && (( + TypeGuard.TString(schema.properties.description.anyOf[0]) && + TypeGuard.TUndefined(schema.properties.description.anyOf[1]) + ) || ( + TypeGuard.TString(schema.properties.description.anyOf[1]) && + TypeGuard.TUndefined(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 = Function([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.TOptional(left) && !TypeGuard.TOptional(right) ? ExtendsResult.False : + ExtendsResult.True + ) +} +// prettier-ignore +function TObjectRight(left: TSchema, right: TObject) { + return ( + TypeGuard.TUnknown(left) ? ExtendsResult.False : + TypeGuard.TAny(left) ? ExtendsResult.Union : ( + TypeGuard.TNever(left) || + (TypeGuard.TLiteralString(left) && IsObjectStringLike(right)) || + (TypeGuard.TLiteralNumber(left) && IsObjectNumberLike(right)) || + (TypeGuard.TLiteralBoolean(left) && IsObjectBooleanLike(right)) || + (TypeGuard.TSymbol(left) && IsObjectSymbolLike(right)) || + (TypeGuard.TBigInt(left) && IsObjectBigIntLike(right)) || + (TypeGuard.TString(left) && IsObjectStringLike(right)) || + (TypeGuard.TSymbol(left) && IsObjectSymbolLike(right)) || + (TypeGuard.TNumber(left) && IsObjectNumberLike(right)) || + (TypeGuard.TInteger(left) && IsObjectNumberLike(right)) || + (TypeGuard.TBoolean(left) && IsObjectBooleanLike(right)) || + (TypeGuard.TUint8Array(left) && IsObjectUint8ArrayLike(right)) || + (TypeGuard.TDate(left) && IsObjectDateLike(right)) || + (TypeGuard.TConstructor(left) && IsObjectConstructorLike(right)) || + (TypeGuard.TFunction(left) && IsObjectFunctionLike(right)) + ) ? ExtendsResult.True : + (TypeGuard.TRecord(left) && TypeGuard.TString(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[Symbols.Hint] === 'Record' ? ExtendsResult.True : ExtendsResult.False + })() : + (TypeGuard.TRecord(left) && TypeGuard.TNumber(RecordKey(left))) ? (() => { + return IsObjectPropertyCount(right, 0) ? ExtendsResult.True : ExtendsResult.False + })() : + ExtendsResult.False + ) +} +// prettier-ignore +function TObject(left: TObject, right: TSchema) { + return ( + IsStructuralRight(right) ? StructuralRight(left, right) : + TypeGuard.TRecord(right) ? TRecordRight(left, right) : + !TypeGuard.TObject(right) ? ExtendsResult.False : + (() => { + for (const key of Object.getOwnPropertyNames(right.properties)) { + if (!(key in left.properties) && !TypeGuard.TOptional(right.properties[key])) { + return ExtendsResult.False + } + if (TypeGuard.TOptional(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 TPromise(left: TPromise, right: TSchema) { + return ( + IsStructuralRight(right) ? StructuralRight(left, right) : + TypeGuard.TObject(right) && IsObjectPromiseLike(right) ? ExtendsResult.True : + !TypeGuard.TPromise(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 TRecordRight(left: TSchema, right: TRecord) { + const [Key, Value] = [RecordKey(right), RecordValue(right)] + return ( + ( + TypeGuard.TLiteralString(left) && TypeGuard.TNumber(Key) && IntoBooleanResult(Visit(left, Value)) === ExtendsResult.True) ? ExtendsResult.True : + TypeGuard.TUint8Array(left) && TypeGuard.TNumber(Key) ? Visit(left, Value) : + TypeGuard.TString(left) && TypeGuard.TNumber(Key) ? Visit(left, Value) : + TypeGuard.TArray(left) && TypeGuard.TNumber(Key) ? Visit(left, Value) : + TypeGuard.TObject(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 TRecord(left: TRecord, right: TSchema) { + return ( + IsStructuralRight(right) ? StructuralRight(left, right) : + TypeGuard.TObject(right) ? TObjectRight(left, right) : + !TypeGuard.TRecord(right) ? ExtendsResult.False : + Visit(RecordValue(left), RecordValue(right)) + ) +} +// ------------------------------------------------------------------ +// String +// ------------------------------------------------------------------ +// prettier-ignore +function TStringRight(left: TSchema, right: TString) { + return ( + TypeGuard.TLiteral(left) && ValueGuard.IsString(left.const) ? ExtendsResult.True : + TypeGuard.TString(left) ? ExtendsResult.True : + ExtendsResult.False + ) +} +// prettier-ignore +function TString(left: TString, right: TSchema): ExtendsResult { + return ( + IsStructuralRight(right) ? StructuralRight(left, right) : + TypeGuard.TObject(right) ? TObjectRight(left, right) : + TypeGuard.TRecord(right) ? TRecordRight(left, right) : + TypeGuard.TString(right) ? ExtendsResult.True : + ExtendsResult.False + ) +} +// ------------------------------------------------------------------ +// Symbol +// ------------------------------------------------------------------ +// prettier-ignore +function TSymbol(left: TSymbol, right: TSchema): ExtendsResult { + return ( + IsStructuralRight(right) ? StructuralRight(left, right) : + TypeGuard.TObject(right) ? TObjectRight(left, right) : + TypeGuard.TRecord(right) ? TRecordRight(left, right) : + TypeGuard.TSymbol(right) ? ExtendsResult.True : + ExtendsResult.False + ) +} +// ------------------------------------------------------------------ +// TemplateLiteral +// ------------------------------------------------------------------ +// prettier-ignore +function TTemplateLiteral(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.TTemplateLiteral(left) ? Visit(TemplateLiteralToUnion(left), right) : + TypeGuard.TTemplateLiteral(right) ? Visit(left, TemplateLiteralToUnion(right)) : + Throw('Invalid fallthrough for TemplateLiteral') + ) +} +// ------------------------------------------------------------------ +// Tuple +// ------------------------------------------------------------------ +// prettier-ignore +function IsArrayOfTuple(left: TTuple, right: TSchema) { + return ( + TypeGuard.TArray(right) && + left.items !== undefined && + left.items.every((schema) => Visit(schema, right.items) === ExtendsResult.True) + ) +} +// prettier-ignore +function TTupleRight(left: TSchema, right: TTuple) { + return ( + TypeGuard.TNever(left) ? ExtendsResult.True : + TypeGuard.TUnknown(left) ? ExtendsResult.False : + TypeGuard.TAny(left) ? ExtendsResult.Union : + ExtendsResult.False + ) +} +// prettier-ignore +function TTuple(left: TTuple, right: TSchema): ExtendsResult { + return ( + IsStructuralRight(right) ? StructuralRight(left, right) : + TypeGuard.TObject(right) && IsObjectArrayLike(right) ? ExtendsResult.True : + TypeGuard.TArray(right) && IsArrayOfTuple(left, right) ? ExtendsResult.True : + !TypeGuard.TTuple(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 TUint8Array(left: TUint8Array, right: TSchema) { + return ( + IsStructuralRight(right) ? StructuralRight(left, right) : + TypeGuard.TObject(right) ? TObjectRight(left, right) : + TypeGuard.TRecord(right) ? TRecordRight(left, right) : + TypeGuard.TUint8Array(right) ? ExtendsResult.True : + ExtendsResult.False + ) +} +// ------------------------------------------------------------------ +// Undefined +// ------------------------------------------------------------------ +// prettier-ignore +function TUndefined(left: TUndefined, right: TSchema) { + return ( + IsStructuralRight(right) ? StructuralRight(left, right) : + TypeGuard.TObject(right) ? TObjectRight(left, right) : + TypeGuard.TRecord(right) ? TRecordRight(left, right) : + TypeGuard.TVoid(right) ? VoidRight(left, right) : + TypeGuard.TUndefined(right) ? ExtendsResult.True : + ExtendsResult.False + ) +} +// ------------------------------------------------------------------ +// Union +// ------------------------------------------------------------------ +// prettier-ignore +function TUnionRight(left: TSchema, right: TUnion): ExtendsResult { + return right.anyOf.some((schema) => Visit(left, schema) === ExtendsResult.True) + ? ExtendsResult.True + : ExtendsResult.False +} +// prettier-ignore +function TUnion(left: TUnion, right: TSchema): ExtendsResult { + return left.anyOf.every((schema) => Visit(schema, right) === ExtendsResult.True) + ? ExtendsResult.True + : ExtendsResult.False +} +// ------------------------------------------------------------------ +// Unknown +// ------------------------------------------------------------------ +// prettier-ignore +function TUnknownRight(left: TSchema, right: TUnknown) { + return ExtendsResult.True +} +// prettier-ignore +function TUnknown(left: TUnknown, right: TSchema) { + return ( + TypeGuard.TNever(right) ? TNeverRight(left, right) : + TypeGuard.TIntersect(right) ? TIntersectRight(left, right) : + TypeGuard.TUnion(right) ? TUnionRight(left, right) : + TypeGuard.TAny(right) ? TAnyRight(left, right) : + TypeGuard.TString(right) ? TStringRight(left, right) : + TypeGuard.TNumber(right) ? TNumberRight(left, right) : + TypeGuard.TInteger(right) ? TIntegerRight(left, right) : + TypeGuard.TBoolean(right) ? TBooleanRight(left, right) : + TypeGuard.TArray(right) ? TArrayRight(left, right) : + TypeGuard.TTuple(right) ? TTupleRight(left, right) : + TypeGuard.TObject(right) ? TObjectRight(left, right) : + TypeGuard.TUnknown(right) ? ExtendsResult.True : + ExtendsResult.False + ) +} +// ------------------------------------------------------------------ +// Void +// ------------------------------------------------------------------ +// prettier-ignore +function VoidRight(left: TSchema, right: TVoid) { + return ( + TypeGuard.TUndefined(left) ? ExtendsResult.True : + TypeGuard.TUndefined(left) ? ExtendsResult.True : + ExtendsResult.False + ) +} +// prettier-ignore +function TVoid(left: TVoid, right: TSchema) { + return ( + TypeGuard.TIntersect(right) ? TIntersectRight(left, right) : + TypeGuard.TUnion(right) ? TUnionRight(left, right) : + TypeGuard.TUnknown(right) ? TUnknownRight(left, right) : + TypeGuard.TAny(right) ? TAnyRight(left, right) : + TypeGuard.TObject(right) ? TObjectRight(left, right) : + TypeGuard.TVoid(right) ? ExtendsResult.True : + ExtendsResult.False + ) +} +// prettier-ignore +function Visit(left: TSchema, right: TSchema): ExtendsResult { + return ( + // resolvable + (TypeGuard.TTemplateLiteral(left) || TypeGuard.TTemplateLiteral(right)) ? TTemplateLiteral(left, right) : + (TypeGuard.TNot(left) || TypeGuard.TNot(right)) ? TNot(left, right) : + // standard + TypeGuard.TAny(left) ? TAny(left, right) : + TypeGuard.TArray(left) ? TArray(left, right) : + TypeGuard.TBigInt(left) ? TBigInt(left, right) : + TypeGuard.TBoolean(left) ? TBoolean(left, right) : + TypeGuard.TAsyncIterator(left) ? TAsyncIterator(left, right) : + TypeGuard.TConstructor(left) ? TConstructor(left, right) : + TypeGuard.TDate(left) ? TDate(left, right) : + TypeGuard.TFunction(left) ? TFunction(left, right) : + TypeGuard.TInteger(left) ? TInteger(left, right) : + TypeGuard.TIntersect(left) ? TIntersect(left, right) : + TypeGuard.TIterator(left) ? TIterator(left, right) : + TypeGuard.TLiteral(left) ? TLiteral(left, right) : + TypeGuard.TNever(left) ? TNever(left, right) : + TypeGuard.TNull(left) ? TNull(left, right) : + TypeGuard.TNumber(left) ? TNumber(left, right) : + TypeGuard.TObject(left) ? TObject(left, right) : + TypeGuard.TRecord(left) ? TRecord(left, right) : + TypeGuard.TString(left) ? TString(left, right) : + TypeGuard.TSymbol(left) ? TSymbol(left, right) : + TypeGuard.TTuple(left) ? TTuple(left, right) : + TypeGuard.TPromise(left) ? TPromise(left, right) : + TypeGuard.TUint8Array(left) ? TUint8Array(left, right) : + TypeGuard.TUndefined(left) ? TUndefined(left, right) : + TypeGuard.TUnion(left) ? TUnion(left, right) : + TypeGuard.TUnknown(left) ? TUnknown(left, right) : + TypeGuard.TVoid(left) ? TVoid(left, right) : + Throw(`Unknown left type operand '${left[Symbols.Kind]}'`) + ) +} +export function ExtendsCheck(left: TSchema, right: TSchema): ExtendsResult { + return Visit(left, right) +} diff --git a/src/type/extends/extends-undefined.ts b/src/type/extends/extends-undefined.ts new file mode 100644 index 000000000..44d75f00a --- /dev/null +++ b/src/type/extends/extends-undefined.ts @@ -0,0 +1,55 @@ +/*-------------------------------------------------------------------------- + +@sinclair/typebox + +The MIT License (MIT) + +Copyright (c) 2017-2023 Haydn Paterson (sinclair) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +---------------------------------------------------------------------------*/ + +import type { TSchema } from '../schema/index' +import type { TIntersect } from '../intersect/index' +import type { TUnion } from '../union/index' +import type { TNot } from '../not/index' +import { Symbols } 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[Symbols.Kind] === 'Intersect' ? Intersect(schema as TIntersect) : + schema[Symbols.Kind] === 'Union' ? Union(schema as TUnion) : + schema[Symbols.Kind] === 'Not' ? Not(schema as TNot) : + schema[Symbols.Kind] === 'Undefined' ? true : + false + ) +} diff --git a/src/type/extends/extends.ts b/src/type/extends/extends.ts new file mode 100644 index 000000000..cdc1898c9 --- /dev/null +++ b/src/type/extends/extends.ts @@ -0,0 +1,63 @@ +/*-------------------------------------------------------------------------- + +@sinclair/typebox + +The MIT License (MIT) + +Copyright (c) 2017-2023 Haydn Paterson (sinclair) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +---------------------------------------------------------------------------*/ + +import type { TSchema, SchemaOptions } from '../schema/index' +import type { Static } from '../static/index' +import { type TUnion, Union } from '../union/index' +import { ExtendsCheck, ExtendsResult } from './extends-check' +import { UnionToTuple } from '../helpers/index' +import { CloneType } from '../clone/type' + +// prettier-ignore +export type ExtendsResolve = ( + (Static extends Static ? T : U) extends infer O extends TSchema ? + UnionToTuple extends [infer X extends TSchema, infer Y extends TSchema] + ? TUnion<[X, Y]> + : O + : never +) +// prettier-ignore +export function ExtendsResolve(left: L, right: R, trueType: T, falseType: U): ExtendsResolve { + const R = ExtendsCheck(left, right) + return ( + R === ExtendsResult.Union ? Union([trueType, falseType]) : + R === ExtendsResult.True ? trueType : + falseType + ) as unknown as ExtendsResolve +} + +// ------------------------------------------------------------------ +// TExtends +// ------------------------------------------------------------------ +export type TExtends = ExtendsResolve + +/** `[Json]` Creates a Conditional type */ +export function Extends(L: L, R: R, T: T, F: F, options: SchemaOptions = {}): TExtends { + const E = ExtendsResolve(L, R, T, F) + return CloneType(E, options) as TExtends +} diff --git a/src/type/extends/index.ts b/src/type/extends/index.ts new file mode 100644 index 000000000..2ad012224 --- /dev/null +++ b/src/type/extends/index.ts @@ -0,0 +1,31 @@ +/*-------------------------------------------------------------------------- + +@sinclair/typebox + +The MIT License (MIT) + +Copyright (c) 2017-2023 Haydn Paterson (sinclair) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +---------------------------------------------------------------------------*/ + +export * from './extends-check' +export * from './extends-undefined' +export * from './extends' diff --git a/src/type/extract/extract.ts b/src/type/extract/extract.ts new file mode 100644 index 000000000..f065a21d6 --- /dev/null +++ b/src/type/extract/extract.ts @@ -0,0 +1,84 @@ +/*-------------------------------------------------------------------------- + +@sinclair/typebox + +The MIT License (MIT) + +Copyright (c) 2017-2023 Haydn Paterson (sinclair) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +---------------------------------------------------------------------------*/ + +import type { TSchema, SchemaOptions } from '../schema/index' +import type { Assert, AssertRest, AssertType, UnionToTuple } from '../helpers/index' +import { type TTemplateLiteral, TemplateLiteralToUnion } from '../template-literal/index' +import { type TLiteral } from '../literal/index' +import { type TUnion, Union } from '../union/index' +import { type Static } from '../static/index' +import { Never } from '../never/index' +import { UnionResolve } from '../union/index' +import { ExtendsCheck, ExtendsResult } from '../extends/index' +import { CloneType } from '../clone/type' +import { TTemplateLiteral as IsTemplateLiteralType, TUnion as IsUnionType } from '../guard/type' + +// ------------------------------------------------------------------ +// ExtractResolve +// ------------------------------------------------------------------ +// prettier-ignore +type FromTemplateLiteralResult = UnionResolve }[T]>>> +// prettier-ignore +type FromTemplateLiteral = Extract, Static> extends infer S ? FromTemplateLiteralResult> : never +// prettier-ignore +type FromArray = AssertRest> extends Static ? T[K] : never +}[number]>> extends infer R extends TSchema[] ? UnionResolve : never +// prettier-ignore +export type ExtractResolve = ( + T extends TTemplateLiteral ? FromTemplateLiteral : + T extends TUnion ? FromArray : + T extends U + ? T + : T // ? +) +// prettier-ignore +export function ExtractResolve(L: L, R: R): ExtractResolve { + return ( + IsTemplateLiteralType(L) ? ExtractResolve(TemplateLiteralToUnion(L), R) : + IsTemplateLiteralType(R) ? ExtractResolve(L, TemplateLiteralToUnion(R) as any) : + IsUnionType(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 ExtractResolve +} + +// ------------------------------------------------------------------ +// TExtract +// ------------------------------------------------------------------ +// prettier-ignore +export type TExtract = ExtractResolve + +/** `[Json]` Constructs a type by extracting from type all union members that are assignable to union */ +export function Extract(type: L, union: R, options: SchemaOptions = {}): TExtract { + const E = ExtractResolve(type, union) + return CloneType(E, options) as TExtract +} diff --git a/src/type/extract/index.ts b/src/type/extract/index.ts new file mode 100644 index 000000000..641cc9e74 --- /dev/null +++ b/src/type/extract/index.ts @@ -0,0 +1,29 @@ +/*-------------------------------------------------------------------------- + +@sinclair/typebox + +The MIT License (MIT) + +Copyright (c) 2017-2023 Haydn Paterson (sinclair) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +---------------------------------------------------------------------------*/ + +export * from './extract' diff --git a/src/type/function/function.ts b/src/type/function/function.ts new file mode 100644 index 000000000..4f1bc4f67 --- /dev/null +++ b/src/type/function/function.ts @@ -0,0 +1,68 @@ +/*-------------------------------------------------------------------------- + +@sinclair/typebox + +The MIT License (MIT) + +Copyright (c) 2017-2023 Haydn Paterson (sinclair) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +---------------------------------------------------------------------------*/ + +import 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 { Symbols } from '../symbols/index' + +// ------------------------------------------------------------------ +// FunctionResolve +// ------------------------------------------------------------------ +export type FunctionReturnTypeResolve = Static + +// prettier-ignore +export type FunctionParametersResolve = + T extends [infer L extends TSchema, ...infer R extends TSchema[]] + ? [Static, ...FunctionParametersResolve] + : [] +// prettier-ignore +export type FunctionResolve = ( + Ensure<(...param: FunctionParametersResolve) => FunctionReturnTypeResolve> +) +// ------------------------------------------------------------------ +// TFunction +// ------------------------------------------------------------------ +export interface TFunction extends TSchema { + [Symbols.Kind]: 'Function' + static: FunctionResolve + type: 'Function' + parameters: T + returns: U +} +/** `[JavaScript]` Creates a Function type */ +export function Function(parameters: [...T], returns: U, options?: SchemaOptions): TFunction { + return { + ...options, + [Symbols.Kind]: 'Function', + type: 'Function', + parameters: CloneRest(parameters), + returns: CloneType(returns), + } as unknown as TFunction +} diff --git a/src/type/function/index.ts b/src/type/function/index.ts new file mode 100644 index 000000000..4a8e31b9a --- /dev/null +++ b/src/type/function/index.ts @@ -0,0 +1,29 @@ +/*-------------------------------------------------------------------------- + +@sinclair/typebox + +The MIT License (MIT) + +Copyright (c) 2017-2023 Haydn Paterson (sinclair) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +---------------------------------------------------------------------------*/ + +export * from './function' diff --git a/src/type/guard/index.ts b/src/type/guard/index.ts new file mode 100644 index 000000000..572e24f48 --- /dev/null +++ b/src/type/guard/index.ts @@ -0,0 +1,30 @@ +/*-------------------------------------------------------------------------- + +@sinclair/typebox + +The MIT License (MIT) + +Copyright (c) 2017-2023 Haydn Paterson (sinclair) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +---------------------------------------------------------------------------*/ + +export * as TypeGuard from './type' +export * as ValueGuard from './value' diff --git a/src/type/guard/type.ts b/src/type/guard/type.ts new file mode 100644 index 000000000..89615d489 --- /dev/null +++ b/src/type/guard/type.ts @@ -0,0 +1,576 @@ +/*-------------------------------------------------------------------------- + +@sinclair/typebox + +The MIT License (MIT) + +Copyright (c) 2017-2023 Haydn Paterson (sinclair) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +---------------------------------------------------------------------------*/ + +import * as ValueGuard from './value' +import { Symbols } from '../symbols/index' + +import type { TransformOptions } from '../transform/index' +import type { TTemplateLiteral, TTemplateLiteralKind } from '../template-literal/index' +import type { TArray } from '../array/index' +import type { 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 } from '../literal/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 } 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 { 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 Error {} + +const KnownTypes = [ + 'Any', + 'Array', + 'AsyncIterator', + 'BigInt', + 'Boolean', + 'Constructor', + 'Date', + 'Enum', + 'Function', + 'Integer', + 'Intersect', + 'Iterator', + 'Literal', + 'Not', + 'Null', + 'Number', + 'Object', + 'Promise', + 'Record', + 'Ref', + '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) || TSchema(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) || TSchema(value) +} +// ------------------------------------------------------------------ +// Modifiers +// ------------------------------------------------------------------ +/** Returns true if this value has a Readonly symbol */ +export function TReadonly(schema: T): schema is TReadonly { + return ValueGuard.IsObject(schema) && schema[Symbols.Readonly] === 'Readonly' +} +/** Returns true if this value has a Optional symbol */ +export function TOptional(schema: T): schema is TOptional { + return ValueGuard.IsObject(schema) && schema[Symbols.Optional] === 'Optional' +} +// ------------------------------------------------------------------ +// Types +// ------------------------------------------------------------------ +/** Returns true if the given value is TAny */ +export function TAny(schema: unknown): schema is TAny { + // prettier-ignore + return ( + TKindOf(schema, 'Any') && + IsOptionalString(schema.$id) + ) +} +/** Returns true if the given value is TArray */ +export function TArray(schema: unknown): schema is TArray { + return ( + TKindOf(schema, 'Array') && + schema.type === 'array' && + IsOptionalString(schema.$id) && + TSchema(schema.items) && + IsOptionalNumber(schema.minItems) && + IsOptionalNumber(schema.maxItems) && + IsOptionalBoolean(schema.uniqueItems) && + IsOptionalSchema(schema.contains) && + IsOptionalNumber(schema.minContains) && + IsOptionalNumber(schema.maxContains) + ) +} +/** Returns true if the given value is TAsyncIterator */ +export function TAsyncIterator(schema: unknown): schema is TAsyncIterator { + // prettier-ignore + return ( + TKindOf(schema, 'AsyncIterator') && + schema.type === 'AsyncIterator' && + IsOptionalString(schema.$id) && + TSchema(schema.items) + ) +} +/** Returns true if the given value is TBigInt */ +export function TBigInt(schema: unknown): schema is TBigInt { + // prettier-ignore + return ( + TKindOf(schema, 'BigInt') && + schema.type === 'bigint' && + IsOptionalString(schema.$id) && + IsOptionalBigInt(schema.exclusiveMaximum) && + IsOptionalBigInt(schema.exclusiveMinimum) && + IsOptionalBigInt(schema.maximum) && + IsOptionalBigInt(schema.minimum) && + IsOptionalBigInt(schema.multipleOf) + ) +} +/** Returns true if the given value is TBoolean */ +export function TBoolean(schema: unknown): schema is TBoolean { + // prettier-ignore + return ( + TKindOf(schema, 'Boolean') && + schema.type === 'boolean' && + IsOptionalString(schema.$id) + ) +} +/** Returns true if the given value is TConstructor */ +export function TConstructor(schema: unknown): schema is TConstructor { + // prettier-ignore + return ( + TKindOf(schema, 'Constructor') && + schema.type === 'Constructor' && + IsOptionalString(schema.$id) && + ValueGuard.IsArray(schema.parameters) && + schema.parameters.every(schema => TSchema(schema)) && + TSchema(schema.returns) + ) +} +/** Returns true if the given value is TDate */ +export function TDate(schema: unknown): schema is TDate { + return ( + TKindOf(schema, 'Date') && + schema.type === 'Date' && + IsOptionalString(schema.$id) && + IsOptionalNumber(schema.exclusiveMaximumTimestamp) && + IsOptionalNumber(schema.exclusiveMinimumTimestamp) && + IsOptionalNumber(schema.maximumTimestamp) && + IsOptionalNumber(schema.minimumTimestamp) && + IsOptionalNumber(schema.multipleOfTimestamp) + ) +} +/** Returns true if the given value is TFunction */ +export function TFunction(schema: unknown): schema is TFunction { + // prettier-ignore + return ( + TKindOf(schema, 'Function') && + schema.type === 'Function' && + IsOptionalString(schema.$id) && + ValueGuard.IsArray(schema.parameters) && + schema.parameters.every(schema => TSchema(schema)) && + TSchema(schema.returns) + ) +} +/** Returns true if the given value is TInteger */ +export function TInteger(schema: unknown): schema is TInteger { + return ( + TKindOf(schema, 'Integer') && + schema.type === 'integer' && + IsOptionalString(schema.$id) && + IsOptionalNumber(schema.exclusiveMaximum) && + IsOptionalNumber(schema.exclusiveMinimum) && + IsOptionalNumber(schema.maximum) && + IsOptionalNumber(schema.minimum) && + IsOptionalNumber(schema.multipleOf) + ) +} +/** Returns true if the given value is TIntersect */ +export function TIntersect(schema: unknown): schema is TIntersect { + // prettier-ignore + return ( + TKindOf(schema, 'Intersect') && + (ValueGuard.IsString(schema.type) && schema.type !== 'object' ? false : true) && + ValueGuard.IsArray(schema.allOf) && + schema.allOf.every(schema => TSchema(schema) && !TTransform(schema)) && + IsOptionalString(schema.type) && + (IsOptionalBoolean(schema.unevaluatedProperties) || IsOptionalSchema(schema.unevaluatedProperties)) && + IsOptionalString(schema.$id) + ) +} +/** Returns true if the given value is TIterator */ +export function TIterator(schema: unknown): schema is TIterator { + // prettier-ignore + return ( + TKindOf(schema, 'Iterator') && + schema.type === 'Iterator' && + IsOptionalString(schema.$id) && + TSchema(schema.items) + ) +} +/** Returns true if the given value is a TKind with the given name. */ +export function TKindOf(schema: unknown, kind: T): schema is Record & { [Symbols.Kind]: T } { + return ValueGuard.IsObject(schema) && Symbols.Kind in schema && schema[Symbols.Kind] === kind +} +/** Returns true if the given value is TLiteral */ +export function TLiteralString(schema: unknown): schema is TLiteral { + return TLiteral(schema) && ValueGuard.IsString(schema.const) +} +/** Returns true if the given value is TLiteral */ +export function TLiteralNumber(schema: unknown): schema is TLiteral { + return TLiteral(schema) && ValueGuard.IsNumber(schema.const) +} +/** Returns true if the given value is TLiteral */ +export function TLiteralBoolean(schema: unknown): schema is TLiteral { + return TLiteral(schema) && ValueGuard.IsBoolean(schema.const) +} +/** Returns true if the given value is TLiteral */ +export function TLiteral(schema: unknown): schema is TLiteral { + // prettier-ignore + return ( + TKindOf(schema, 'Literal') && + IsOptionalString(schema.$id) && ( + ValueGuard.IsBoolean(schema.const) || + ValueGuard.IsNumber(schema.const) || + ValueGuard.IsString(schema.const) + ) + ) +} +/** Returns true if the given value is TNever */ +export function TNever(schema: unknown): schema is TNever { + // prettier-ignore + return ( + TKindOf(schema, 'Never') && + ValueGuard.IsObject(schema.not) && + Object.getOwnPropertyNames(schema.not).length === 0 + ) +} +/** Returns true if the given value is TNot */ +export function TNot(schema: unknown): schema is TNot { + // prettier-ignore + return ( + TKindOf(schema, 'Not') && + TSchema(schema.not) + ) +} +/** Returns true if the given value is TNull */ +export function TNull(schema: unknown): schema is TNull { + // prettier-ignore + return ( + TKindOf(schema, 'Null') && + schema.type === 'null' && + IsOptionalString(schema.$id) + ) +} +/** Returns true if the given value is TNumber */ +export function TNumber(schema: unknown): schema is TNumber { + return ( + TKindOf(schema, 'Number') && + schema.type === 'number' && + IsOptionalString(schema.$id) && + IsOptionalNumber(schema.exclusiveMaximum) && + IsOptionalNumber(schema.exclusiveMinimum) && + IsOptionalNumber(schema.maximum) && + IsOptionalNumber(schema.minimum) && + IsOptionalNumber(schema.multipleOf) + ) +} +/** Returns true if the given value is TObject */ +export function TObject(schema: unknown): schema is TObject { + // prettier-ignore + return ( + TKindOf(schema, 'Object') && + schema.type === 'object' && + IsOptionalString(schema.$id) && + ValueGuard.IsObject(schema.properties) && + Object.entries(schema.properties).every(([key, schema]) => IsControlCharacterFree(key) && TSchema(schema)) && + IsAdditionalProperties(schema.additionalProperties) && + IsOptionalNumber(schema.minProperties) && + IsOptionalNumber(schema.maxProperties) + ) +} +/** Returns true if the given value is TPromise */ +export function TPromise(schema: unknown): schema is TPromise { + // prettier-ignore + return ( + TKindOf(schema, 'Promise') && + schema.type === 'Promise' && + IsOptionalString(schema.$id) && + TSchema(schema.item) + ) +} +/** Returns true if the given value is TRecord */ +export function TRecord(schema: unknown): schema is TRecord { + // prettier-ignore + return ( + TKindOf(schema, 'Record') && + schema.type === 'object' && + IsOptionalString(schema.$id) && + IsAdditionalProperties(schema.additionalProperties) && + ValueGuard.IsObject(schema.patternProperties) && + ((schema: Record) => { + const keys = Object.getOwnPropertyNames(schema.patternProperties) + return ( + keys.length === 1 && + IsPattern(keys[0]) && + ValueGuard.IsObject(schema.patternProperties) && + TSchema(schema.patternProperties[keys[0]]) + ) + })(schema) + ) +} +/** Returns true if this value is TRecursive */ +export function TRecursive(schema: unknown): schema is { [Symbols.Hint]: 'Recursive' } { + return ValueGuard.IsObject(schema) && Symbols.Hint in schema && schema[Symbols.Hint] === 'Recursive' +} +/** Returns true if the given value is TRef */ +export function TRef(schema: unknown): schema is TRef { + // prettier-ignore + return ( + TKindOf(schema, 'Ref') && + IsOptionalString(schema.$id) && + ValueGuard.IsString(schema.$ref) + ) +} +/** Returns true if the given value is TString */ +export function TString(schema: unknown): schema is TString { + // prettier-ignore + return ( + TKindOf(schema, 'String') && + schema.type === 'string' && + IsOptionalString(schema.$id) && + IsOptionalNumber(schema.minLength) && + IsOptionalNumber(schema.maxLength) && + IsOptionalPattern(schema.pattern) && + IsOptionalFormat(schema.format) + ) +} +/** Returns true if the given value is TSymbol */ +export function TSymbol(schema: unknown): schema is TSymbol { + // prettier-ignore + return ( + TKindOf(schema, 'Symbol') && + schema.type === 'symbol' && + IsOptionalString(schema.$id) + ) +} +/** Returns true if the given value is TTemplateLiteral */ +export function TTemplateLiteral(schema: unknown): schema is TTemplateLiteral { + // prettier-ignore + return ( + TKindOf(schema, 'TemplateLiteral') && + schema.type === 'string' && + ValueGuard.IsString(schema.pattern) && + schema.pattern[0] === '^' && + schema.pattern[schema.pattern.length - 1] === '$' + ) +} +/** Returns true if the given value is TThis */ +export function TThis(schema: unknown): schema is TThis { + // prettier-ignore + return ( + TKindOf(schema, 'This') && + IsOptionalString(schema.$id) && + ValueGuard.IsString(schema.$ref) + ) +} +/** Returns true of this value is TTransform */ +export function TTransform(schema: unknown): schema is { [Symbols.Transform]: TransformOptions } { + return ValueGuard.IsObject(schema) && Symbols.Transform in schema +} +/** Returns true if the given value is TTuple */ +export function TTuple(schema: unknown): schema is TTuple { + // prettier-ignore + return ( + TKindOf(schema, 'Tuple') && + schema.type === 'array' && + IsOptionalString(schema.$id) && + ValueGuard.IsNumber(schema.minItems) && + ValueGuard.IsNumber(schema.maxItems) && + schema.minItems === schema.maxItems && + (( // empty + ValueGuard.IsUndefined(schema.items) && + ValueGuard.IsUndefined(schema.additionalItems) && + schema.minItems === 0 + ) || ( + ValueGuard.IsArray(schema.items) && + schema.items.every(schema => TSchema(schema)) + )) + ) +} +/** Returns true if the given value is TUndefined */ +export function TUndefined(schema: unknown): schema is TUndefined { + // prettier-ignore + return ( + TKindOf(schema, 'Undefined') && + schema.type === 'undefined' && + IsOptionalString(schema.$id) + ) +} +/** Returns true if the given value is TUnion[]> */ +export function TUnionLiteral(schema: unknown): schema is TUnion { + return TUnion(schema) && schema.anyOf.every((schema) => TLiteralString(schema) || TLiteralNumber(schema)) +} +/** Returns true if the given value is TUnion */ +export function TUnion(schema: unknown): schema is TUnion { + // prettier-ignore + return ( + TKindOf(schema, 'Union') && + IsOptionalString(schema.$id) && + ValueGuard.IsObject(schema) && + ValueGuard.IsArray(schema.anyOf) && + schema.anyOf.every(schema => TSchema(schema)) + ) +} +/** Returns true if the given value is TUint8Array */ +export function TUint8Array(schema: unknown): schema is TUint8Array { + // prettier-ignore + return ( + TKindOf(schema, 'Uint8Array') && + schema.type === 'Uint8Array' && + IsOptionalString(schema.$id) && + IsOptionalNumber(schema.minByteLength) && + IsOptionalNumber(schema.maxByteLength) + ) +} +/** Returns true if the given value is TUnknown */ +export function TUnknown(schema: unknown): schema is TUnknown { + // prettier-ignore + return ( + TKindOf(schema, 'Unknown') && + IsOptionalString(schema.$id) + ) +} +/** Returns true if the given value is a raw TUnsafe */ +export function TUnsafe(schema: unknown): schema is TUnsafe { + return TKindOf(schema, 'Unsafe') +} +/** Returns true if the given value is TVoid */ +export function TVoid(schema: unknown): schema is TVoid { + // prettier-ignore + return ( + TKindOf(schema, 'Void') && + schema.type === 'void' && + IsOptionalString(schema.$id) + ) +} +/** Returns true if the given value is TKind */ +export function TKind(schema: unknown): schema is Record & { [Symbols.Kind]: string } { + return ValueGuard.IsObject(schema) && Symbols.Kind in schema && ValueGuard.IsString(schema[Symbols.Kind]) && !KnownTypes.includes(schema[Symbols.Kind] as string) +} +/** Returns true if the given value is TSchema */ +export function TSchema(schema: unknown): schema is TSchema { + // prettier-ignore + return ( + ValueGuard.IsObject(schema) + ) && ( + TAny(schema) || + TArray(schema) || + TBoolean(schema) || + TBigInt(schema) || + TAsyncIterator(schema) || + TConstructor(schema) || + TDate(schema) || + TFunction(schema) || + TInteger(schema) || + TIntersect(schema) || + TIterator(schema) || + TLiteral(schema) || + TNever(schema) || + TNot(schema) || + TNull(schema) || + TNumber(schema) || + TObject(schema) || + TPromise(schema) || + TRecord(schema) || + TRef(schema) || + TString(schema) || + TSymbol(schema) || + TTemplateLiteral(schema) || + TThis(schema) || + TTuple(schema) || + TUndefined(schema) || + TUnion(schema) || + TUint8Array(schema) || + TUnknown(schema) || + TUnsafe(schema) || + TVoid(schema) || + TKind(schema) + ) +} diff --git a/src/type/guard/value.ts b/src/type/guard/value.ts new file mode 100644 index 000000000..9ea64b1fe --- /dev/null +++ b/src/type/guard/value.ts @@ -0,0 +1,68 @@ +/*-------------------------------------------------------------------------- + +@sinclair/typebox + +The MIT License (MIT) + +Copyright (c) 2017-2023 Haydn Paterson (sinclair) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +---------------------------------------------------------------------------*/ + +/** 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 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 { + return typeof value === 'object' && value !== null +} +/** 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 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 +} diff --git a/src/type/helpers/helpers.ts b/src/type/helpers/helpers.ts new file mode 100644 index 000000000..9d97a3e9c --- /dev/null +++ b/src/type/helpers/helpers.ts @@ -0,0 +1,69 @@ +/*-------------------------------------------------------------------------- + +@sinclair/typebox + +The MIT License (MIT) + +Copyright (c) 2017-2023 Haydn Paterson (sinclair) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +---------------------------------------------------------------------------*/ + +import type { TSchema } from '../schema/index' +import type { TProperties } from '../object/index' +import type { TNever } from '../never/index' +// ------------------------------------------------------------------ +// Helper: Common +// ------------------------------------------------------------------ +export type TupleToIntersect = T extends [infer I] ? I : T extends [infer I, ...infer R] ? I & TupleToIntersect : never +export type TupleToUnion = { [K in keyof T]: T[K] }[number] +export type UnionToIntersect = (U extends unknown ? (arg: U) => 0 : never) extends (arg: infer I) => 0 ? I : never +export type UnionLast = UnionToIntersect 0 : never> extends (x: infer L) => 0 ? L : never +export type UnionToTuple> = [U] extends [never] ? [] : [...UnionToTuple>, L] +export type Trim = T extends `${' '}${infer U}` ? Trim : T extends `${infer U}${' '}` ? Trim : T +export type Assert = T extends E ? T : never +export type Evaluate = T extends infer O ? { [K in keyof O]: O[K] } : never +export type Ensure = T extends infer U ? U : never +export type EmptyString = '' +export type ZeroString = '0' +// ------------------------------------------------------------------ +// Helper: Increment +// ------------------------------------------------------------------ +export 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' } +export type IncrementTake = IncrementBase[T] +export type IncrementStep = T extends IncrementBase['m'] + ? IncrementBase['t'] + : T extends `${infer L extends keyof IncrementBase}${infer R}` + ? L extends IncrementBase['m'] + ? `${IncrementTake}${IncrementStep}` + : `${IncrementTake}${R}` + : never +export type IncrementReverse = T extends `${infer L}${infer R}` ? `${IncrementReverse}${L}` : T +export type Increment = IncrementReverse>> +/** Increments the given string value + 1 */ +export function Increment(T: T): Increment { + return (parseInt(T) + 1).toString() as Increment +} +// ------------------------------------------------------------------ +// Helper: Type Asserts +// ------------------------------------------------------------------ +export type AssertProperties = T extends TProperties ? T : TProperties +export type AssertRest = T extends E ? T : [] +export type AssertType = T extends E ? T : TNever diff --git a/src/type/helpers/index.ts b/src/type/helpers/index.ts new file mode 100644 index 000000000..0c6fb3f16 --- /dev/null +++ b/src/type/helpers/index.ts @@ -0,0 +1,29 @@ +/*-------------------------------------------------------------------------- + +@sinclair/typebox + +The MIT License (MIT) + +Copyright (c) 2017-2023 Haydn Paterson (sinclair) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +---------------------------------------------------------------------------*/ + +export * from './helpers' diff --git a/src/type/index.ts b/src/type/index.ts new file mode 100644 index 000000000..7cf39c7a7 --- /dev/null +++ b/src/type/index.ts @@ -0,0 +1,95 @@ +/*-------------------------------------------------------------------------- + +@sinclair/typebox + +The MIT License (MIT) + +Copyright (c) 2017-2023 Haydn Paterson (sinclair) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +---------------------------------------------------------------------------*/ + +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 './builder/index' +export * from './clone/index' +export * from './composite/index' +export * from './constructor/index' +export * from './constructor-parameters/index' +export * from './date/index' +export * from './discard/index' +export * from './enum/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 './modifiers/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 './operators/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 './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 './uint8array/index' +export * from './undefined/index' +export * from './union/index' +export * from './unknown/index' +export * from './unsafe/index' +export * from './void/index' diff --git a/src/type/indexed/index.ts b/src/type/indexed/index.ts new file mode 100644 index 000000000..7ab7ded97 --- /dev/null +++ b/src/type/indexed/index.ts @@ -0,0 +1,31 @@ +/*-------------------------------------------------------------------------- + +@sinclair/typebox + +The MIT License (MIT) + +Copyright (c) 2017-2023 Haydn Paterson (sinclair) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +---------------------------------------------------------------------------*/ + +export * from './indexed-type' +export * from './indexed-key' +export * from './indexed' diff --git a/src/type/indexed/indexed-key.ts b/src/type/indexed/indexed-key.ts new file mode 100644 index 000000000..d38663c34 --- /dev/null +++ b/src/type/indexed/indexed-key.ts @@ -0,0 +1,115 @@ +/*-------------------------------------------------------------------------- + +@sinclair/typebox + +The MIT License (MIT) + +Copyright (c) 2017-2023 Haydn Paterson (sinclair) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +---------------------------------------------------------------------------*/ + +import { type TTemplateLiteral, TemplateLiteralGenerate, TemplateLiteralParseExact, IsTemplateLiteralFinite, TemplateLiteralToUnion } from '../template-literal/index' +import { type TLiteral, type TLiteralValue } from '../literal/index' +import { type TInteger } from '../integer/index' +import { type TNumber } from '../number/index' +import { type TSchema } from '../schema/index' +import { type TUnion } from '../union/index' +import { TTemplateLiteral as IsTemplateLiteralType, TUnionLiteral as IsUnionLiteralType, TUnion as IsUnionType, TLiteral as IsLiteralType, TNumber as IsNumberType, TInteger as IsIntegerType } from '../guard/type' + +// ------------------------------------------------------------------ +// FromTemplateLiteral +// ------------------------------------------------------------------ +// prettier-ignore +type FromTemplateLiteral> = ( + F extends true + ? TemplateLiteralGenerate extends infer R extends string[] ? R : [] + : [] +) +// prettier-ignore +function FromTemplateLiteral(T: T): FromTemplateLiteral { + const E = TemplateLiteralParseExact(T.pattern) + const F = IsTemplateLiteralFinite(E) + const S = TemplateLiteralToUnion(T) + return ( + F === true + ? IsUnionLiteralType(S) + ? S.anyOf.map(S => S.const.toString()) + : [] + : [] + ) as unknown as FromTemplateLiteral +} +// ------------------------------------------------------------------ +// FromUnion +// ------------------------------------------------------------------ +// prettier-ignore +type FromUnion = ( + T extends [infer L extends TSchema, ...infer R extends TSchema[]] + ? [...IndexedKeyResolve, ...FromUnion] + : [] +) +// prettier-ignore +function FromUnion(T: T): FromUnion{ + const [L, ...R] = T + return ( + T.length > 0 + ? [...IndexedKeyResolve(L), ...FromUnion(R)] + : [] + ) as FromUnion +} +// ------------------------------------------------------------------ +// FromLiteral +// ------------------------------------------------------------------ +// prettier-ignore +type FromLiteral = ( + T extends PropertyKey + ? [`${T}`] + : [] +) +// prettier-ignore +function FromLiteral(T: T): FromLiteral { + return ( + [T.toString()] + ) as FromLiteral +} +// ------------------------------------------------------------------ +// IndexedKeyResolve +// ------------------------------------------------------------------ +// prettier-ignore +export type IndexedKeyResolve = ( + T extends TTemplateLiteral ? FromTemplateLiteral : + T extends TUnion ? FromUnion : + T extends TLiteral ? FromLiteral : + T extends TNumber ? ['[number]'] : + T extends TInteger ? ['[number]'] : + [] +) +/** Resolves Indexer String Keys form the given Schema. Th */ +// prettier-ignore +export function IndexedKeyResolve(T: T): IndexedKeyResolve { + return [...new Set(( + IsTemplateLiteralType(T) ? FromTemplateLiteral(T) : + IsUnionType(T) ? FromUnion(T.anyOf) : + IsLiteralType(T) ? FromLiteral(T.const) : + IsNumberType(T) ? ['[number]'] : + IsIntegerType(T) ? ['[number]'] : + [] + ))] as unknown as IndexedKeyResolve +} diff --git a/src/type/indexed/indexed-type.ts b/src/type/indexed/indexed-type.ts new file mode 100644 index 000000000..a9e058579 --- /dev/null +++ b/src/type/indexed/indexed-type.ts @@ -0,0 +1,228 @@ +/*-------------------------------------------------------------------------- + +@sinclair/typebox + +The MIT License (MIT) + +Copyright (c) 2017-2023 Haydn Paterson (sinclair) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +---------------------------------------------------------------------------*/ + +import { type TSchema } from '../schema/index' +import { type TObject, type TProperties } from '../object' +import { type TNever, Never } from '../never/index' +import { type TRecursive } from '../recursive/index' +import { type TIntersect } from '../intersect/index' +import { type TUnion } from '../union/index' +import { type TTuple } from '../tuple/index' +import { type TArray } from '../array/index' +import { IntersectResolve } from '../intersect/index' +import { UnionResolve } from '../union/index' + +import { TIntersect as IsIntersectType, TUnion as IsUnionType, TTuple as IsTupleType, TArray as IsArrayType, TObject as IsObjectType, TNever as IsNeverType } from '../guard/type' +// ------------------------------------------------------------------ +// FromRest +// ------------------------------------------------------------------ +// prettier-ignore +type FromRest = ( + T extends [infer L extends TSchema, ...infer R extends TSchema[]] + ? [FromKey, ...FromRest] + : [] +) +// prettier-ignore +function FromRest(T: [...T], K: K): FromRest { + const [L, ...R] = T + return ( + T.length > 0 + ? [FromKey(L, K), ...FromRest(R, K)] + : [] + ) as FromRest +} +// ------------------------------------------------------------------ +// FromIntersectRest +// ------------------------------------------------------------------ +// prettier-ignore +type FromIntersectRest = ( + T extends [infer L extends TSchema, ...infer R extends TSchema[]] + ? L extends TNever + ? [...FromIntersectRest] + : [L, ...FromIntersectRest] + : [] +) +// prettier-ignore +function FromIntersectRest(T: [...T]): FromIntersectRest { + const [L, ...R] = T + return ( + T.length > 0 + ? IsNeverType(L) + ? [...FromIntersectRest(R)] + : [L, ...FromIntersectRest(R)] + : [] + ) as FromIntersectRest +} +// prettier-ignore +type FromIntersect = ( + IntersectResolve>> +) +// prettier-ignore +function FromIntersect(T: [...T], K: K): FromIntersect { + return ( + IntersectResolve(FromIntersectRest(FromRest(T as TSchema[], K))) + ) as FromIntersect +} +// ------------------------------------------------------------------ +// FromUnionRest +// ------------------------------------------------------------------ +// prettier-ignore +type FromUnionRest = ( + T extends [infer L extends TSchema, ...infer R extends TSchema[]] + ? L extends TNever + ? [] + : FromUnionRest + : S +) +// prettier-ignore +function FromUnionRest(T: [...T], S = T): FromUnionRest { + const [L, ...R] = T + return ( + T.length > 0 + ? IsNeverType(L) + ? [] + : FromUnionRest(R, S) + : S + ) as FromUnionRest +} +// prettier-ignore +type FromUnion = ( + UnionResolve>> +) +// prettier-ignore +function FromUnion(T: [...T], K: K): FromUnion { + return ( + UnionResolve(FromUnionRest(FromRest(T as TSchema[], K))) + ) as FromUnion +} +// ------------------------------------------------------------------ +// FromTuple +// ------------------------------------------------------------------ +// prettier-ignore +type FromTuple = ( + K extends keyof T ? T[K] : + K extends '[number]' ? UnionResolve : + TNever +) +// prettier-ignore +function FromTuple(T: [...T], K: K): FromTuple { + return ( + K in T ? T[K as number] : + K === '[number]' ? UnionResolve(T) : + Never() + ) as FromTuple +} +// ------------------------------------------------------------------ +// FromArray +// ------------------------------------------------------------------ +// prettier-ignore +type FromArray = ( + K extends '[number]' + ? T + : TNever +) +// prettier-ignore +function FromArray(T: T, K: K): FromArray { + return ( + K === '[number]' + ? T + : Never() + ) as FromArray +} +// ------------------------------------------------------------------ +// FromProperty +// ------------------------------------------------------------------ +// prettier-ignore +type FromProperty = ( + K extends keyof T + ? T[K] + : TNever +) +// prettier-ignore +function FromProperty(T: T, K: K): FromProperty { + return ( + K in T + ? T[K as string] + : Never() + ) as FromProperty +} +// ------------------------------------------------------------------ +// FromKey +// ------------------------------------------------------------------ +// prettier-ignore +type FromKey = ( + T extends TRecursive ? FromKey : + T extends TIntersect ? FromIntersect : + T extends TUnion ? FromUnion : + T extends TTuple ? FromTuple : + T extends TArray ? FromArray : + T extends TObject ? FromProperty : + TNever +) +// prettier-ignore +function FromKey(T: T, K: K): FromKey { + return ( + IsIntersectType(T) ? FromIntersect(T.allOf, K) : + IsUnionType(T) ? FromUnion(T.anyOf, K) : + IsTupleType(T) ? FromTuple(T.items ?? [], K) : + IsArrayType(T) ? FromArray(T.items, K) : + IsObjectType(T) ? FromProperty(T.properties, K) : + Never() + ) as FromKey +} +// ------------------------------------------------------------------ +// FromKeys +// ------------------------------------------------------------------ +// prettier-ignore +type FromKeys = ( + K extends [infer L extends PropertyKey, ...infer R extends PropertyKey[]] + ? [FromKey, ...FromKeys] + : [] +) +// prettier-ignore +function FromKeys(T: T, K: [...K]): FromKeys { + const [L, ...R] = K + return ( + K.length > 0 + ? [FromKey(T, L), ...FromKeys(T, R)] + : [] + ) as FromKeys +} +// ------------------------------------------------------------------ +// IndexedTypeResolve +// ------------------------------------------------------------------ +// prettier-ignore +export type IndexedTypeResolve = ( + UnionResolve> +) +// prettier-ignore +export function IndexedTypeResolve(T: T, K: [...K]): IndexedTypeResolve { + return ( + UnionResolve(FromKeys(T, K as PropertyKey[])) + ) as IndexedTypeResolve +} diff --git a/src/type/indexed/indexed.ts b/src/type/indexed/indexed.ts new file mode 100644 index 000000000..702bd59d8 --- /dev/null +++ b/src/type/indexed/indexed.ts @@ -0,0 +1,49 @@ +/*-------------------------------------------------------------------------- + +@sinclair/typebox + +The MIT License (MIT) + +Copyright (c) 2017-2023 Haydn Paterson (sinclair) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +---------------------------------------------------------------------------*/ + +import type { TSchema, SchemaOptions } from '../schema/index' +import { IndexedTypeResolve } from './indexed-type' +import { IndexedKeyResolve } from './indexed-key' +import { CloneType } from '../clone/type' +import { TSchema as IsSchemaType } from '../guard/type' + +// ------------------------------------------------------------------ +// TIndex +// ------------------------------------------------------------------ +export type TIndex = IndexedTypeResolve + +/** `[Json]` Returns an Indexed property type for the given keys */ +export function Index>(T: T, K: K, options?: SchemaOptions): TIndex +/** `[Json]` Returns an Indexed property type for the given keys */ +export function Index(T: T, K: readonly [...K], options?: SchemaOptions): TIndex +/** `[Json]` Returns an Indexed property type for the given keys */ +export function Index(T: TSchema, K: any, options: SchemaOptions = {}): any { + const keys = IsSchemaType(K) ? IndexedKeyResolve(K) : (K as string[]) + const type = IndexedTypeResolve(T, keys) + return CloneType(type, options) +} diff --git a/src/type/instance-type/index.ts b/src/type/instance-type/index.ts new file mode 100644 index 000000000..b25c037d4 --- /dev/null +++ b/src/type/instance-type/index.ts @@ -0,0 +1,29 @@ +/*-------------------------------------------------------------------------- + +@sinclair/typebox + +The MIT License (MIT) + +Copyright (c) 2017-2023 Haydn Paterson (sinclair) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +---------------------------------------------------------------------------*/ + +export * from './instance-type' diff --git a/src/type/instance-type/instance-type.ts b/src/type/instance-type/instance-type.ts new file mode 100644 index 000000000..50fff353a --- /dev/null +++ b/src/type/instance-type/instance-type.ts @@ -0,0 +1,41 @@ +/*-------------------------------------------------------------------------- + +@sinclair/typebox + +The MIT License (MIT) + +Copyright (c) 2017-2023 Haydn Paterson (sinclair) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +---------------------------------------------------------------------------*/ + +import type { TSchema, SchemaOptions } from '../schema/index' +import type { TConstructor } from '../constructor/index' +import { CloneType } from '../clone/type' + +// ------------------------------------------------------------------ +// TInstanceType +// ------------------------------------------------------------------ +export type TInstanceType> = T['returns'] + +/** `[JavaScript]` Extracts the InstanceType from the given Constructor type */ +export function InstanceType>(schema: T, options: SchemaOptions = {}): TInstanceType { + return CloneType(schema.returns, options) +} diff --git a/src/type/integer/index.ts b/src/type/integer/index.ts new file mode 100644 index 000000000..c48d28cc3 --- /dev/null +++ b/src/type/integer/index.ts @@ -0,0 +1,29 @@ +/*-------------------------------------------------------------------------- + +@sinclair/typebox + +The MIT License (MIT) + +Copyright (c) 2017-2023 Haydn Paterson (sinclair) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +---------------------------------------------------------------------------*/ + +export * from './integer' diff --git a/src/type/integer/integer.ts b/src/type/integer/integer.ts new file mode 100644 index 000000000..ab0f05cf9 --- /dev/null +++ b/src/type/integer/integer.ts @@ -0,0 +1,54 @@ +/*-------------------------------------------------------------------------- + +@sinclair/typebox + +The MIT License (MIT) + +Copyright (c) 2017-2023 Haydn Paterson (sinclair) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +---------------------------------------------------------------------------*/ + +import type { TSchema, SchemaOptions } from '../schema/index' +import { Symbols } from '../symbols/index' + +// ------------------------------------------------------------------ +// TInteger +// ------------------------------------------------------------------ +export interface IntegerOptions extends SchemaOptions { + exclusiveMaximum?: number + exclusiveMinimum?: number + maximum?: number + minimum?: number + multipleOf?: number +} +export interface TInteger extends TSchema, IntegerOptions { + [Symbols.Kind]: 'Integer' + static: number + type: 'integer' +} +/** `[Json]` Creates an Integer type */ +export function Integer(options: IntegerOptions = {}): TInteger { + return { + ...options, + [Symbols.Kind]: 'Integer', + type: 'integer', + } as unknown as TInteger +} diff --git a/src/type/intersect/index.ts b/src/type/intersect/index.ts new file mode 100644 index 000000000..841edd7a7 --- /dev/null +++ b/src/type/intersect/index.ts @@ -0,0 +1,29 @@ +/*-------------------------------------------------------------------------- + +@sinclair/typebox + +The MIT License (MIT) + +Copyright (c) 2017-2023 Haydn Paterson (sinclair) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +---------------------------------------------------------------------------*/ + +export * from './intersect' diff --git a/src/type/intersect/intersect.ts b/src/type/intersect/intersect.ts new file mode 100644 index 000000000..9d72b4747 --- /dev/null +++ b/src/type/intersect/intersect.ts @@ -0,0 +1,79 @@ +/*-------------------------------------------------------------------------- + +@sinclair/typebox + +The MIT License (MIT) + +Copyright (c) 2017-2023 Haydn Paterson (sinclair) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +---------------------------------------------------------------------------*/ + +import type { TupleToIntersect, AssertType } from '../helpers/index' +import type { TSchema, SchemaOptions } from '../schema/index' +import type { Static } from '../static/index' +import { type TNever, Never } from '../never/index' +import { OptionalFromIntersect } from '../modifiers/index' +import { Symbols } from '../symbols/index' +import { CloneType, CloneRest } from '../clone/type' +import { TTransform as IsTransformType, TObject as IsObjectType, TSchema as IsSchemaType } from '../guard/type' + +// ------------------------------------------------------------------ +// IntersectResolve +// ------------------------------------------------------------------ +// prettier-ignore +export type IntersectResolve = ( + T extends [] ? TNever : + T extends [TSchema] ? T[0] : + OptionalFromIntersect +) +// prettier-ignore +export function IntersectResolve(T: T): IntersectResolve { + return ( + T.length === 0 + ? Never() + : T.length === 1 + ? T[0] + : OptionalFromIntersect(T)) as IntersectResolve +} +// ------------------------------------------------------------------ +// TIntersect +// ------------------------------------------------------------------ +export type TUnevaluatedProperties = undefined | TSchema | boolean +export interface IntersectOptions extends SchemaOptions { + unevaluatedProperties?: TUnevaluatedProperties +} +export interface TIntersect extends TSchema, IntersectOptions { + [Symbols.Kind]: 'Intersect' + static: TupleToIntersect<{ [K in keyof T]: Static, this['params']> }> + type?: 'object' + allOf: [...T] +} +/** `[Json]` Creates an Intersect type */ +export function Intersect(T: [...T], options: IntersectOptions = {}): IntersectResolve { + if (T.length === 0) return Never() as IntersectResolve + if (T.length === 1) return CloneType(T[0], options) as IntersectResolve + if (T.some((schema) => IsTransformType(schema))) throw new Error('Cannot intersect transform types') + const allObjects = T.every((schema) => IsObjectType(schema)) + const clonedUnevaluatedProperties = IsSchemaType(options.unevaluatedProperties) ? { unevaluatedProperties: CloneType(options.unevaluatedProperties) } : {} + return (options.unevaluatedProperties === false || IsSchemaType(options.unevaluatedProperties) || allObjects + ? { ...options, ...clonedUnevaluatedProperties, [Symbols.Kind]: 'Intersect', type: 'object', allOf: CloneRest(T) } + : { ...options, ...clonedUnevaluatedProperties, [Symbols.Kind]: 'Intersect', allOf: CloneRest(T) }) as unknown as IntersectResolve +} diff --git a/src/type/intrinsic/index.ts b/src/type/intrinsic/index.ts new file mode 100644 index 000000000..d4522d5e0 --- /dev/null +++ b/src/type/intrinsic/index.ts @@ -0,0 +1,29 @@ +/*-------------------------------------------------------------------------- + +@sinclair/typebox + +The MIT License (MIT) + +Copyright (c) 2017-2023 Haydn Paterson (sinclair) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +---------------------------------------------------------------------------*/ + +export * from './intrinsic' diff --git a/src/type/intrinsic/intrinsic.ts b/src/type/intrinsic/intrinsic.ts new file mode 100644 index 000000000..90dccc0e5 --- /dev/null +++ b/src/type/intrinsic/intrinsic.ts @@ -0,0 +1,171 @@ +/*-------------------------------------------------------------------------- + +@sinclair/typebox + +The MIT License (MIT) + +Copyright (c) 2017-2023 Haydn Paterson (sinclair) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +---------------------------------------------------------------------------*/ + +import type { TSchema, SchemaOptions } from '../schema/index' +import { type TTemplateLiteral, type TTemplateLiteralKind, TemplateLiteral, TemplateLiteralParseExact, IsTemplateLiteralFinite, TemplateLiteralGenerate } from '../template-literal/index' +import { type TLiteral, type TLiteralValue, Literal } from '../literal/index' +import { type TUnion, Union } from '../union/index' +import { TTemplateLiteral as IsTemplateLiteralType, TUnion as IsUnionType, TLiteral as IsLiteralType } from '../guard/type' +import { CloneType } from '../clone/type' + +// ------------------------------------------------------------------ +// Apply +// ------------------------------------------------------------------ +function ApplyUncapitalize(value: string): string { + const [first, rest] = [value.slice(0, 1), value.slice(1)] + return [first.toLowerCase(), rest].join('') +} +function ApplyCapitalize(value: string): string { + const [first, rest] = [value.slice(0, 1), value.slice(1)] + return [first.toUpperCase(), rest].join('') +} +function ApplyUppercase(value: string): string { + return value.toUpperCase() +} +function ApplyLowercase(value: string): string { + return value.toLowerCase() +} +// ------------------------------------------------------------------ +// IntrinsicMode +// ------------------------------------------------------------------ +type IntrinsicMode = 'Uppercase' | 'Lowercase' | 'Capitalize' | 'Uncapitalize' +// ------------------------------------------------------------------ +// FromTemplateLiteral +// ------------------------------------------------------------------ +// prettier-ignore +type FromTemplateLiteral = + M extends IntrinsicMode ? + T extends [infer L extends TTemplateLiteralKind, ...infer R extends TTemplateLiteralKind[]] + ? [IntrinsicResolve, ...FromTemplateLiteral] + : T + : T +function FromTemplateLiteral(schema: TTemplateLiteral, mode: IntrinsicMode): FromTemplateLiteral { + // note: template literals require special runtime handling as they are encoded in string patterns. + // This diverges from the mapped type which would otherwise map on the template literal kind. + const expression = TemplateLiteralParseExact(schema.pattern) + const finite = IsTemplateLiteralFinite(expression) + if (!finite) return { ...schema, pattern: FromLiteralValue(schema.pattern, mode) } as any + const strings = [...TemplateLiteralGenerate(expression)] + const literals = strings.map((value) => Literal(value)) + const mapped = FromRest(literals as any, mode) + const union = Union(mapped) + return TemplateLiteral([union]) as unknown as FromTemplateLiteral +} +// ------------------------------------------------------------------ +// FromLiteralValue +// ------------------------------------------------------------------ +// prettier-ignore +type FromLiteralValue = ( + T extends string ? + M extends 'Uncapitalize' ? Uncapitalize : + M extends 'Capitalize' ? Capitalize : + M extends 'Uppercase' ? Uppercase : + M extends 'Lowercase' ? Lowercase : + string + : T +) +// prettier-ignore +function FromLiteralValue(value: TLiteralValue, mode: IntrinsicMode) { + return ( + typeof value === 'string' ? ( + mode === 'Uncapitalize' ? ApplyUncapitalize(value) : + mode === 'Capitalize' ? ApplyCapitalize(value) : + mode === 'Uppercase' ? ApplyUppercase(value) : + mode === 'Lowercase' ? ApplyLowercase(value) : + value + ) : value.toString() + ) +} +// ------------------------------------------------------------------ +// FromRest +// ------------------------------------------------------------------ +// prettier-ignore +type FromRest = + T extends [infer L extends TSchema, ...infer R extends TSchema[]] + ? [IntrinsicResolve, ...FromRest] + : [] +function FromRest(T: [...T], mode: M): FromRest { + const [L, ...R] = T + return (T.length > 0 ? [IntrinsicResolve(L, mode), ...FromRest(R, mode)] : []) as FromRest +} +// ------------------------------------------------------------------ +// IntrinsicResolve +// ------------------------------------------------------------------ +// prettier-ignore +export type IntrinsicResolve = + T extends TTemplateLiteral ? TTemplateLiteral> : + T extends TUnion ? TUnion> : + T extends TLiteral ? TLiteral> : + T +/** Applies an intrinsic string manipulation to the given type. */ +// prettier-ignore +export function IntrinsicResolve(schema: T, mode: M): IntrinsicResolve { + return ( + IsTemplateLiteralType(schema) ? FromTemplateLiteral(schema, mode) : + IsUnionType(schema) ? Union(FromRest(schema.anyOf, mode)) : + IsLiteralType(schema) ? Literal(FromLiteralValue(schema.const, mode)) : + schema + ) as IntrinsicResolve +} + +// ------------------------------------------------------------------ +// TUncapitalize +// ------------------------------------------------------------------ +// prettier-ignore +export type TUncapitalize = IntrinsicResolve +/** `[Json]` Intrinsic function to Uncapitalize LiteralString types */ +export function Uncapitalize(T: T, options: SchemaOptions = {}): TUncapitalize { + return CloneType(IntrinsicResolve(T, 'Uncapitalize'), options) +} +// ------------------------------------------------------------------ +// TUppercase +// ------------------------------------------------------------------ +// prettier-ignore +export type TUppercase = IntrinsicResolve +/** `[Json]` Intrinsic function to Uppercase LiteralString types */ +export function Uppercase(T: T, options: SchemaOptions = {}): TUppercase { + return CloneType(IntrinsicResolve(T, 'Uppercase'), options) +} +// ------------------------------------------------------------------ +// TLowercase +// ------------------------------------------------------------------ +// prettier-ignore +export type TLowercase = IntrinsicResolve +/** `[Json]` Intrinsic function to Lowercase LiteralString types */ +export function Lowercase(T: T, options: SchemaOptions = {}): TLowercase { + return CloneType(IntrinsicResolve(T, 'Lowercase'), options) +} +// ------------------------------------------------------------------ +// TCapitalize +// ------------------------------------------------------------------ +// prettier-ignore +export type TCapitalize = IntrinsicResolve +/** `[Json]` Intrinsic function to Capitalize LiteralString types */ +export function Capitalize(T: T, options: SchemaOptions = {}): TCapitalize { + return CloneType(IntrinsicResolve(T, 'Capitalize'), options) +} diff --git a/src/type/iterator/index.ts b/src/type/iterator/index.ts new file mode 100644 index 000000000..f924c5475 --- /dev/null +++ b/src/type/iterator/index.ts @@ -0,0 +1,29 @@ +/*-------------------------------------------------------------------------- + +@sinclair/typebox + +The MIT License (MIT) + +Copyright (c) 2017-2023 Haydn Paterson (sinclair) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +---------------------------------------------------------------------------*/ + +export * from './iterator' diff --git a/src/type/iterator/iterator.ts b/src/type/iterator/iterator.ts new file mode 100644 index 000000000..081541049 --- /dev/null +++ b/src/type/iterator/iterator.ts @@ -0,0 +1,51 @@ +/*-------------------------------------------------------------------------- + +@sinclair/typebox + +The MIT License (MIT) + +Copyright (c) 2017-2023 Haydn Paterson (sinclair) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +---------------------------------------------------------------------------*/ + +import type { TSchema, SchemaOptions } from '../schema/index' +import type { Static } from '../static/index' +import { Symbols } from '../symbols/index' +import { CloneType } from '../clone/type' + +// ------------------------------------------------------------------ +// TIterator +// ------------------------------------------------------------------ +export interface TIterator extends TSchema { + [Symbols.Kind]: 'Iterator' + static: IterableIterator> + type: 'Iterator' + items: T +} +/** `[JavaScript]` Creates an Iterator type */ +export function Iterator(items: T, options: SchemaOptions = {}): TIterator { + return { + ...options, + [Symbols.Kind]: 'Iterator', + type: 'Iterator', + items: CloneType(items), + } as unknown as TIterator +} diff --git a/src/type/keyof/index.ts b/src/type/keyof/index.ts new file mode 100644 index 000000000..910240612 --- /dev/null +++ b/src/type/keyof/index.ts @@ -0,0 +1,31 @@ +/*-------------------------------------------------------------------------- + +@sinclair/typebox + +The MIT License (MIT) + +Copyright (c) 2017-2023 Haydn Paterson (sinclair) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +---------------------------------------------------------------------------*/ + +export * from './keyof-string' +export * from './keyof-type' +export * from './keyof' diff --git a/src/type/keyof/keyof-string.ts b/src/type/keyof/keyof-string.ts new file mode 100644 index 000000000..db15cf636 --- /dev/null +++ b/src/type/keyof/keyof-string.ts @@ -0,0 +1,178 @@ +/*-------------------------------------------------------------------------- + +@sinclair/typebox + +The MIT License (MIT) + +Copyright (c) 2017-2023 Haydn Paterson (sinclair) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +---------------------------------------------------------------------------*/ + +import type { TSchema } from '../schema/index' +import { type ZeroString, type UnionToTuple, Increment } from '../helpers/index' +import type { TRecursive } from '../recursive/index' +import type { TIntersect } from '../intersect/index' +import type { TUnion } from '../union/index' +import type { TTuple } from '../tuple/index' +import type { TArray } from '../array/index' +import type { TObject, TProperties } from '../object/index' +import { OperatorUnionMany, OperatorIntersectMany } from '../operators/index' +import { TIntersect as IsIntersectType, TUnion as IsUnionType, TTuple as IsTupleType, TArray as IsArrayType, TObject as IsObjectType, TRecord as IsRecordType } from '../guard/type' + +// ------------------------------------------------------------------ +// FromRest +// ------------------------------------------------------------------ +// prettier-ignore +type FromRest = ( + T extends [infer L extends TSchema, ...infer R extends TSchema[]] + ? [KeyOfStringResolve, ...FromRest] + : [] +) +// prettier-ignore +function FromRest(T: [...T]): FromRest { + const [L, ...R] = T + return ( + T.length > 0 + ? [KeyOfStringResolve(L), ...FromRest(R)] + : [] + ) as FromRest +} +// ------------------------------------------------------------------ +// FromIntersect +// ------------------------------------------------------------------ +// prettier-ignore +type FromIntersect> = ( + OperatorUnionMany +) +// prettier-ignore +function FromIntersect(T: [...T], C = FromRest(T)): FromIntersect { + return ( + OperatorUnionMany(C as PropertyKey[][]) as FromIntersect + ) +} +// ------------------------------------------------------------------ +// FromUnion +// ------------------------------------------------------------------ +// prettier-ignore +type FromUnion> = ( + OperatorIntersectMany +) +// prettier-ignore +function FromUnion(T: [...T]): FromUnion { + const C = FromRest(T) as PropertyKey[][] + return ( + OperatorIntersectMany(C) as FromUnion + ) +} +// ------------------------------------------------------------------ +// FromTuple +// ------------------------------------------------------------------ +// prettier-ignore +type FromTuple = + T extends [infer _ extends TSchema, ...infer R extends TSchema[]] + ? [I, ...FromTuple>] + : [] +// prettier-ignore +function FromTuple(T: [...T], I = '0'): FromTuple { + const [_, ...R] = T + return ( + T.length > 0 + ? [I, ...FromTuple(R, Increment(I))] + : [] + ) as FromTuple +} +// ------------------------------------------------------------------ +// FromArray +// ------------------------------------------------------------------ +// prettier-ignore +type FromArray<_ extends TSchema> = ( + ['[number]'] +) +// prettier-ignore +function FromArray<_ extends TSchema>(_: _): FromArray<_> { + return ( + ['[number]'] + ) +} +// ------------------------------------------------------------------ +// FromProperties +// ------------------------------------------------------------------ +// prettier-ignore +type FromProperties = ( + UnionToTuple +) +// prettier-ignore +function FromProperties(T: T): FromProperties { + return ( + globalThis.Object.getOwnPropertyNames(T) + ) as FromProperties +} +// ------------------------------------------------------------------ +// FromPatternProperties +// ------------------------------------------------------------------ +// prettier-ignore +function FromPatternProperties(patternProperties: Record): string[] { + if(!includePatternProperties) return [] + const patternPropertyKeys = globalThis.Object.getOwnPropertyNames(patternProperties) + return patternPropertyKeys.map(key => { + return (key[0] === '^' && key[key.length - 1] === '$') + ? key.slice(1, key.length - 1) + : key + }) +} +// ------------------------------------------------------------------ +// KeyOfStringResolve +// ------------------------------------------------------------------ +// prettier-ignore +export type KeyOfStringResolve = ( + T extends TRecursive ? KeyOfStringResolve : + T extends TIntersect ? FromIntersect : + T extends TUnion ? FromUnion : + T extends TTuple ? FromTuple : + T extends TArray ? FromArray : + T extends TObject ? FromProperties : + [] +) +/** Resolves finite keys from this type */ +// prettier-ignore +export function KeyOfStringResolve(T: T): KeyOfStringResolve { + return ( + IsIntersectType(T) ? FromIntersect(T.allOf) : + IsUnionType(T) ? FromUnion(T.anyOf) : + IsTupleType(T) ? FromTuple(T.items ?? []) : + IsArrayType(T) ? FromArray(T.items) : + IsObjectType(T) ? FromProperties(T.properties) : + IsRecordType(T) ? FromPatternProperties(T.patternProperties) : + [] + ) as KeyOfStringResolve +} +// ---------------------------------------------------------------- +// KeyOfStringResolvePattern +// ---------------------------------------------------------------- +let includePatternProperties = false +/** Resolves keys as a regular expression, including pattern property keys */ +export function KeyOfStringResolvePattern(schema: TSchema): string { + includePatternProperties = true + const keys = KeyOfStringResolve(schema) + includePatternProperties = false + const pattern = keys.map((key) => `(${key})`) + return `^(${pattern.join('|')})$` +} diff --git a/src/type/keyof/keyof-type.ts b/src/type/keyof/keyof-type.ts new file mode 100644 index 000000000..1900ac4e1 --- /dev/null +++ b/src/type/keyof/keyof-type.ts @@ -0,0 +1,70 @@ +/*-------------------------------------------------------------------------- + +@sinclair/typebox + +The MIT License (MIT) + +Copyright (c) 2017-2023 Haydn Paterson (sinclair) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +---------------------------------------------------------------------------*/ + +import type { TSchema } from '../schema/index' +import type { Ensure } from '../helpers/index' +import { type TLiteral, TLiteralValue, Literal } from '../literal/index' +import { type TNumber, Number } from '../number/index' +import { KeyOfStringResolve } from './keyof-string' +import { UnionResolve } from '../union/index' + +// ------------------------------------------------------------------ +// FromLiterals +// ------------------------------------------------------------------ +// prettier-ignore +type FromLiterals = ( + T extends [infer L extends TLiteralValue, ...infer R extends TLiteralValue[]] + ? L extends '[number]' + ? [TNumber, ...FromLiterals] + : [TLiteral, ...FromLiterals] + : [] +) +// prettier-ignore +function FromLiterals(T: [...T]): FromLiterals { + const [L, ...R] = T + return ( + T.length > 0 + ? L === '[number]' + ? [Number(), ...FromLiterals(R)] + : [Literal(L as TLiteralValue), ...FromLiterals(R)] + : [] + ) as FromLiterals +} +// ------------------------------------------------------------------ +// KeyOfTypeResolve +// ------------------------------------------------------------------ +// prettier-ignore +export type KeyOfTypeResolve = ( + Ensure>>> +) +// prettier-ignore +export function KeyOfTypeResolve(T: T): KeyOfTypeResolve { + return ( + UnionResolve(FromLiterals(KeyOfStringResolve(T) as TLiteralValue[])) + ) as unknown as KeyOfTypeResolve +} diff --git a/src/type/keyof/keyof.ts b/src/type/keyof/keyof.ts new file mode 100644 index 000000000..f626bcb5d --- /dev/null +++ b/src/type/keyof/keyof.ts @@ -0,0 +1,42 @@ +/*-------------------------------------------------------------------------- + +@sinclair/typebox + +The MIT License (MIT) + +Copyright (c) 2017-2023 Haydn Paterson (sinclair) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +---------------------------------------------------------------------------*/ + +import type { TSchema, SchemaOptions } from '../schema/index' +import { KeyOfTypeResolve } from './keyof-type' +import { CloneType } from '../clone/type' + +// ------------------------------------------------------------------ +// TKeyOf +// ------------------------------------------------------------------ +export type TKeyOf = KeyOfTypeResolve + +/** `[Json]` Creates a KeyOf type */ +export function KeyOf(schema: T, options: SchemaOptions = {}): KeyOfTypeResolve { + const K = KeyOfTypeResolve(schema) + return CloneType(K, options) as KeyOfTypeResolve +} diff --git a/src/type/literal/index.ts b/src/type/literal/index.ts new file mode 100644 index 000000000..afc98d28f --- /dev/null +++ b/src/type/literal/index.ts @@ -0,0 +1,29 @@ +/*-------------------------------------------------------------------------- + +@sinclair/typebox + +The MIT License (MIT) + +Copyright (c) 2017-2023 Haydn Paterson (sinclair) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +---------------------------------------------------------------------------*/ + +export * from './literal' diff --git a/src/type/literal/literal.ts b/src/type/literal/literal.ts new file mode 100644 index 000000000..5e5249519 --- /dev/null +++ b/src/type/literal/literal.ts @@ -0,0 +1,53 @@ +/*-------------------------------------------------------------------------- + +@sinclair/typebox + +The MIT License (MIT) + +Copyright (c) 2017-2023 Haydn Paterson (sinclair) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +---------------------------------------------------------------------------*/ + +import type { TSchema, SchemaOptions } from '../schema/index' +import { Symbols } from '../symbols/index' + +// ------------------------------------------------------------------ +// TLiteralValue +// ------------------------------------------------------------------ +export type TLiteralValue = boolean | number | string // | bigint - supported but variant disable due to potential numeric type conflicts + +// ------------------------------------------------------------------ +// TLiteral +// ------------------------------------------------------------------ +export interface TLiteral extends TSchema { + [Symbols.Kind]: 'Literal' + static: T + const: T +} +/** `[Json]` Creates a Literal type */ +export function Literal(value: T, options: SchemaOptions = {}): TLiteral { + return { + ...options, + [Symbols.Kind]: 'Literal', + const: value, + type: typeof value as 'string' | 'number' | 'boolean', + } as unknown as TLiteral +} diff --git a/src/type/modifiers/index.ts b/src/type/modifiers/index.ts new file mode 100644 index 000000000..483f9f7ef --- /dev/null +++ b/src/type/modifiers/index.ts @@ -0,0 +1,29 @@ +/*-------------------------------------------------------------------------- + +@sinclair/typebox + +The MIT License (MIT) + +Copyright (c) 2017-2023 Haydn Paterson (sinclair) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +---------------------------------------------------------------------------*/ + +export * from './modifiers' diff --git a/src/type/modifiers/modifiers.ts b/src/type/modifiers/modifiers.ts new file mode 100644 index 000000000..429556f31 --- /dev/null +++ b/src/type/modifiers/modifiers.ts @@ -0,0 +1,149 @@ +/*-------------------------------------------------------------------------- + +@sinclair/typebox + +The MIT License (MIT) + +Copyright (c) 2017-2023 Haydn Paterson (sinclair) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +---------------------------------------------------------------------------*/ + +import type { TSchema } from '../schema/index' +import type { TReadonly } from '../readonly/index' +import { type TIntersect, Intersect } from '../intersect/index' +import { type TUnion, Union } from '../union/index' +import { type TOptional, Optional } from '../optional/index' +import { Discard } from '../discard/index' +import { Symbols } from '../symbols/index' +import { TOptional as IsOptionalType } from '../guard/type' + +// ------------------------------------------------------------------ +// IsOptionalFromIntersect +// ------------------------------------------------------------------ +// prettier-ignore +type IsOptionalFromIntersect = ( + T extends [infer L extends TSchema, ...infer R extends TSchema[]] + ? L extends TOptional + ? IsOptionalFromIntersect + : false + : true +) +// prettier-ignore +function IsOptionalFromIntersect(T: T): IsOptionalFromIntersect { + const [L, ...R] = T + return ( + T.length > 0 + ? IsOptionalType(L) + ? IsOptionalFromIntersect(R) + : false + : true + ) as IsOptionalFromIntersect +} +// ------------------------------------------------------------------ +// IsOptionalFromUnion +// ------------------------------------------------------------------ +// prettier-ignore +type IsOptionalFromUnion = ( + T extends [infer L extends TSchema, ...infer R extends TSchema[]] ? + L extends TOptional + ? true + : IsOptionalFromUnion + : false +) +// prettier-ignore +function IsOptionalFromUnion(T: T): IsOptionalFromUnion { + const [L, ...R] = T + return ( + T.length > 0 + ? IsOptionalType(L) + ? true + : IsOptionalFromUnion(R) + : false + ) as IsOptionalFromUnion +} +// ------------------------------------------------------------------ +// RemoveOptionalFromRest +// ------------------------------------------------------------------ +// prettier-ignore +type RemoveOptionalFromRest = ( + T extends [infer L extends TSchema, ...infer R extends TSchema[]] + ? L extends TOptional + ? [RemoveOptionalFromSchema, ...RemoveOptionalFromRest] + : [L, ...RemoveOptionalFromRest] + : [] +) +// prettier-ignore +function RemoveOptionalFromRest(T: T): RemoveOptionalFromRest { + return ( + T.map(T => RemoveOptionalFromSchema(T)) + ) as RemoveOptionalFromRest +} +// ------------------------------------------------------------------ +// RemoveOptionalFromSchema +// ------------------------------------------------------------------ +// prettier-ignore +type RemoveOptionalFromSchema = ( + T extends TReadonly ? TReadonly> : + T extends TOptional ? RemoveOptionalFromSchema : + T +) +// prettier-ignore +function RemoveOptionalFromSchema(T: T): RemoveOptionalFromSchema { + return ( + Discard(T, [Symbols.Optional]) + ) as RemoveOptionalFromSchema +} +// ------------------------------------------------------------------ +// OptionalFromIntersect +// ------------------------------------------------------------------ +// prettier-ignore +export type OptionalFromIntersect> = ( + IsOptionalFromIntersect extends true + ? TOptional> + : TIntersect +) +// prettier-ignore +export function OptionalFromIntersect(T: T): OptionalFromIntersect { + const D = RemoveOptionalFromRest(T) as TSchema[] + return ( + IsOptionalFromIntersect(T) + ? Optional(Intersect(D)) + : Intersect(T) + ) as unknown as OptionalFromIntersect +} +// ------------------------------------------------------------------ +// OptionalFromUnion +// ------------------------------------------------------------------ +// prettier-ignore +export type OptionalFromUnion> = ( + IsOptionalFromUnion extends true + ? TOptional> + : TUnion +) +// prettier-ignore +export function OptionalFromUnion(T: T): OptionalFromUnion { + const D = RemoveOptionalFromRest(T) as TSchema[] + return ( + IsOptionalFromUnion(T) + ? Optional(Union(D)) + : Union(T) + ) as OptionalFromUnion +} diff --git a/src/type/never/index.ts b/src/type/never/index.ts new file mode 100644 index 000000000..bb41eb5bb --- /dev/null +++ b/src/type/never/index.ts @@ -0,0 +1,29 @@ +/*-------------------------------------------------------------------------- + +@sinclair/typebox + +The MIT License (MIT) + +Copyright (c) 2017-2023 Haydn Paterson (sinclair) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +---------------------------------------------------------------------------*/ + +export * from './never' diff --git a/src/type/never/never.ts b/src/type/never/never.ts new file mode 100644 index 000000000..d50c6b61a --- /dev/null +++ b/src/type/never/never.ts @@ -0,0 +1,47 @@ +/*-------------------------------------------------------------------------- + +@sinclair/typebox + +The MIT License (MIT) + +Copyright (c) 2017-2023 Haydn Paterson (sinclair) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +---------------------------------------------------------------------------*/ + +import type { TSchema, SchemaOptions } from '../schema/index' +import { Symbols } from '../symbols/index' + +// ------------------------------------------------------------------ +// TNever +// ------------------------------------------------------------------ +export interface TNever extends TSchema { + [Symbols.Kind]: 'Never' + static: never + not: {} +} +/** `[Json]` Creates a Never type */ +export function Never(options: SchemaOptions = {}): TNever { + return { + ...options, + [Symbols.Kind]: 'Never', + not: {}, + } as unknown as TNever +} diff --git a/src/type/not/index.ts b/src/type/not/index.ts new file mode 100644 index 000000000..1a5db6061 --- /dev/null +++ b/src/type/not/index.ts @@ -0,0 +1,29 @@ +/*-------------------------------------------------------------------------- + +@sinclair/typebox + +The MIT License (MIT) + +Copyright (c) 2017-2023 Haydn Paterson (sinclair) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +---------------------------------------------------------------------------*/ + +export * from './not' diff --git a/src/type/not/not.ts b/src/type/not/not.ts new file mode 100644 index 000000000..a03e4d159 --- /dev/null +++ b/src/type/not/not.ts @@ -0,0 +1,49 @@ +/*-------------------------------------------------------------------------- + +@sinclair/typebox + +The MIT License (MIT) + +Copyright (c) 2017-2023 Haydn Paterson (sinclair) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +---------------------------------------------------------------------------*/ + +import type { TSchema, SchemaOptions } from '../schema/index' +import type { Static } from '../static/index' +import { Symbols } from '../symbols/index' +import { CloneType } from '../clone/type' + +// ------------------------------------------------------------------ +// TNot +// ------------------------------------------------------------------ +export interface TNot extends TSchema { + [Symbols.Kind]: 'Not' + static: T extends TNot ? Static : unknown + not: T +} +/** `[Json]` Creates a Not type */ +export function Not(schema: T, options?: SchemaOptions): TNot { + return { + ...options, + [Symbols.Kind]: 'Not', + not: CloneType(schema), + } as unknown as TNot +} diff --git a/src/type/null/index.ts b/src/type/null/index.ts new file mode 100644 index 000000000..058789896 --- /dev/null +++ b/src/type/null/index.ts @@ -0,0 +1,29 @@ +/*-------------------------------------------------------------------------- + +@sinclair/typebox + +The MIT License (MIT) + +Copyright (c) 2017-2023 Haydn Paterson (sinclair) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +---------------------------------------------------------------------------*/ + +export * from './null' diff --git a/src/type/null/null.ts b/src/type/null/null.ts new file mode 100644 index 000000000..a09100b90 --- /dev/null +++ b/src/type/null/null.ts @@ -0,0 +1,47 @@ +/*-------------------------------------------------------------------------- + +@sinclair/typebox + +The MIT License (MIT) + +Copyright (c) 2017-2023 Haydn Paterson (sinclair) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +---------------------------------------------------------------------------*/ + +import type { TSchema, SchemaOptions } from '../schema/index' +import { Symbols } from '../symbols/index' + +// ------------------------------------------------------------------ +// TNull +// ------------------------------------------------------------------ +export interface TNull extends TSchema { + [Symbols.Kind]: 'Null' + static: null + type: 'null' +} +/** `[Json]` Creates a Null type */ +export function Null(options: SchemaOptions = {}): TNull { + return { + ...options, + [Symbols.Kind]: 'Null', + type: 'null', + } as unknown as TNull +} diff --git a/src/type/number/index.ts b/src/type/number/index.ts new file mode 100644 index 000000000..26b467504 --- /dev/null +++ b/src/type/number/index.ts @@ -0,0 +1,29 @@ +/*-------------------------------------------------------------------------- + +@sinclair/typebox + +The MIT License (MIT) + +Copyright (c) 2017-2023 Haydn Paterson (sinclair) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +---------------------------------------------------------------------------*/ + +export * from './number' diff --git a/src/type/number/number.ts b/src/type/number/number.ts new file mode 100644 index 000000000..f594e0e6a --- /dev/null +++ b/src/type/number/number.ts @@ -0,0 +1,54 @@ +/*-------------------------------------------------------------------------- + +@sinclair/typebox + +The MIT License (MIT) + +Copyright (c) 2017-2023 Haydn Paterson (sinclair) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +---------------------------------------------------------------------------*/ + +import type { TSchema, SchemaOptions } from '../schema/index' +import { Symbols } from '../symbols/index' + +// ------------------------------------------------------------------ +// TNumber +// ------------------------------------------------------------------ +export interface NumberOptions extends SchemaOptions { + exclusiveMaximum?: number + exclusiveMinimum?: number + maximum?: number + minimum?: number + multipleOf?: number +} +export interface TNumber extends TSchema, NumberOptions { + [Symbols.Kind]: 'Number' + static: number + type: 'number' +} +/** `[Json]` Creates a Number type */ +export function Number(options: NumberOptions = {}): TNumber { + return { + ...options, + [Symbols.Kind]: 'Number', + type: 'number', + } as unknown as TNumber +} diff --git a/src/type/object/index.ts b/src/type/object/index.ts new file mode 100644 index 000000000..8e0ccedf6 --- /dev/null +++ b/src/type/object/index.ts @@ -0,0 +1,29 @@ +/*-------------------------------------------------------------------------- + +@sinclair/typebox + +The MIT License (MIT) + +Copyright (c) 2017-2023 Haydn Paterson (sinclair) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +---------------------------------------------------------------------------*/ + +export * from './object' diff --git a/src/type/object/object.ts b/src/type/object/object.ts new file mode 100644 index 000000000..108ced740 --- /dev/null +++ b/src/type/object/object.ts @@ -0,0 +1,94 @@ +/*-------------------------------------------------------------------------- + +@sinclair/typebox + +The MIT License (MIT) + +Copyright (c) 2017-2023 Haydn Paterson (sinclair) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +---------------------------------------------------------------------------*/ + +import type { TSchema, SchemaOptions } from '../schema/index' +import type { Static } from '../static/index' +import type { Evaluate } from '../helpers/index' +import type { TReadonly } from '../readonly/index' +import type { TOptional } from '../optional/index' +import { CloneType } from '../clone/type' +import { Symbols } from '../symbols/index' +import { TOptional as IsOptionalType, TSchema as IsSchemaType } from '../guard/type' + +// ------------------------------------------------------------------ +// TProperties +// ------------------------------------------------------------------ +export type TPropertyKey = string | number +export type TProperties = Record +export type ReadonlyOptionalPropertyKeys = { [K in keyof T]: T[K] extends TReadonly ? (T[K] extends TOptional ? K : never) : never }[keyof T] +export type ReadonlyPropertyKeys = { [K in keyof T]: T[K] extends TReadonly ? (T[K] extends TOptional ? never : K) : never }[keyof T] +export type OptionalPropertyKeys = { [K in keyof T]: T[K] extends TOptional ? (T[K] extends TReadonly ? never : K) : never }[keyof T] +export type RequiredPropertyKeys = keyof Omit | ReadonlyPropertyKeys | OptionalPropertyKeys> +// prettier-ignore +export type PropertiesResolve> = Evaluate<( + Readonly>>> & + Readonly>> & + Partial>> & + Required>> +)> +// ------------------------------------------------------------------ +// ObjectResolve +// ------------------------------------------------------------------ +// prettier-ignore +export type ObjectResolve = PropertiesResolve +}> +// ------------------------------------------------------------------ +// TObject +// ------------------------------------------------------------------ +export type TAdditionalProperties = undefined | TSchema | boolean +export interface ObjectOptions extends SchemaOptions { + /** Additional property constraints for this object */ + additionalProperties?: TAdditionalProperties + /** The minimum number of properties allowed on this object */ + minProperties?: number + /** The maximum number of properties allowed on this object */ + maxProperties?: number +} +export interface TObject extends TSchema, ObjectOptions { + [Symbols.Kind]: 'Object' + static: ObjectResolve + additionalProperties?: TAdditionalProperties + type: 'object' + properties: T + required?: string[] +} +/** `[Json]` Creates an Object type */ +export function _Object(properties: T, options: ObjectOptions = {}): TObject { + const propertyKeys = globalThis.Object.getOwnPropertyNames(properties) + const optionalKeys = propertyKeys.filter((key) => IsOptionalType(properties[key])) + const requiredKeys = propertyKeys.filter((name) => !optionalKeys.includes(name)) + const clonedAdditionalProperties = IsSchemaType(options.additionalProperties) ? { additionalProperties: CloneType(options.additionalProperties) } : {} + const clonedProperties = propertyKeys.reduce((acc, key) => ({ ...acc, [key]: CloneType(properties[key]) }), {} as TProperties) + return (requiredKeys.length > 0 + ? { ...options, ...clonedAdditionalProperties, [Symbols.Kind]: 'Object', type: 'object', properties: clonedProperties, required: requiredKeys } + : { ...options, ...clonedAdditionalProperties, [Symbols.Kind]: 'Object', type: 'object', properties: clonedProperties }) as unknown as TObject +} + +/** `[Json]` Creates an Object type */ +export const Object = _Object diff --git a/src/type/omit/index.ts b/src/type/omit/index.ts new file mode 100644 index 000000000..83e5edd10 --- /dev/null +++ b/src/type/omit/index.ts @@ -0,0 +1,29 @@ +/*-------------------------------------------------------------------------- + +@sinclair/typebox + +The MIT License (MIT) + +Copyright (c) 2017-2023 Haydn Paterson (sinclair) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +---------------------------------------------------------------------------*/ + +export * from './omit' diff --git a/src/type/omit/omit.ts b/src/type/omit/omit.ts new file mode 100644 index 000000000..41bf098ed --- /dev/null +++ b/src/type/omit/omit.ts @@ -0,0 +1,116 @@ +/*-------------------------------------------------------------------------- + +@sinclair/typebox + +The MIT License (MIT) + +Copyright (c) 2017-2023 Haydn Paterson (sinclair) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +---------------------------------------------------------------------------*/ + +import type { TSchema, SchemaOptions } from '../schema/index' +import type { TupleToUnion, Evaluate } from '../helpers/index' +import { type TRecursive } from '../recursive/index' +import { type TIntersect, Intersect } from '../intersect/index' +import { type TUnion, Union } from '../union/index' +import { type TObject, type TProperties, Object } from '../object/index' + +import { IndexedKeyResolve } from '../indexed/index' +import { Discard } from '../discard/index' +import { Symbols } from '../symbols/index' +import { CloneType } from '../clone/type' +import { TIntersect as IsIntersectType, TUnion as IsUnionType, TObject as IsObjectType, TSchema as IsSchemaType } from '../guard/type' + +// ------------------------------------------------------------------ +// FromIntersect +// ------------------------------------------------------------------ +// prettier-ignore +type FromIntersect = + T extends [infer L extends TSchema, ...infer R extends TSchema[]] + ? [OmitResolve, ...FromIntersect] + : [] +// prettier-ignore +function FromIntersect(T: T, K: K) { + return T.map((T) => OmitResolve(T, K)) as FromIntersect +} +// ------------------------------------------------------------------ +// FromUnion +// ------------------------------------------------------------------ +// prettier-ignore +type FromUnion = + T extends [infer L extends TSchema, ...infer R extends TSchema[]] + ? [OmitResolve, ...FromUnion] + : [] +// prettier-ignore +function FromUnion(T: T, K: K) { + return T.map((T) => OmitResolve(T, K)) as FromUnion +} +// ------------------------------------------------------------------ +// FromProperty +// ------------------------------------------------------------------ +// prettier-ignore +function FromProperty, K extends PropertyKey>(T: T, K: K) { + const { [K]: _, ...R } = T + return R as TProperties +} +// prettier-ignore +type FromProperties> = Evaluate> +// prettier-ignore +function FromProperties(T: T, K: K) { + return K.reduce((T, K2) => { + return FromProperty(T, K2) + }, T as TProperties) +} +// ------------------------------------------------------------------ +// OmitResolve +// ------------------------------------------------------------------ +// prettier-ignore +export type OmitResolve = + T extends TRecursive ? TRecursive> : + T extends TIntersect ? TIntersect> : + T extends TUnion ? TUnion> : + T extends TObject ? TObject> : + TObject<{}> +// prettier-ignore +export function OmitResolve(T: T, K: [...K]): OmitResolve { + return ( + IsIntersectType(T) ? Intersect(FromIntersect(T.allOf, K)) : + IsUnionType(T) ? Union(FromUnion(T.anyOf, K)) : + IsObjectType(T) ? Object(FromProperties(T.properties, K)) : + Object({}) + ) as OmitResolve +} +// ------------------------------------------------------------------ +// TOmit +// ------------------------------------------------------------------ +// prettier-ignore +export type TOmit = OmitResolve + +/** `[Json]` Constructs a type whose keys are omitted from the given type */ +export function Omit>(T: T, K: K, options?: SchemaOptions): TOmit +/** `[Json]` Constructs a type whose keys are omitted from the given type */ +export function Omit(T: T, K: readonly [...K], options?: SchemaOptions): TOmit +export function Omit(T: TSchema, K: TSchema | readonly PropertyKey[], options: SchemaOptions = {}): any { + const I = IsSchemaType(K) ? IndexedKeyResolve(K) : (K as string[]) + const D = Discard(T, [Symbols.Transform, '$id', 'required']) as TSchema + const R = CloneType(OmitResolve(T, I), options) + return { ...D, ...R } +} diff --git a/src/type/operators/index.ts b/src/type/operators/index.ts new file mode 100644 index 000000000..aa6325eaa --- /dev/null +++ b/src/type/operators/index.ts @@ -0,0 +1,29 @@ +/*-------------------------------------------------------------------------- + +@sinclair/typebox + +The MIT License (MIT) + +Copyright (c) 2017-2023 Haydn Paterson (sinclair) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +---------------------------------------------------------------------------*/ + +export * from './operators' diff --git a/src/type/operators/operators.ts b/src/type/operators/operators.ts new file mode 100644 index 000000000..29ad08996 --- /dev/null +++ b/src/type/operators/operators.ts @@ -0,0 +1,224 @@ +/*-------------------------------------------------------------------------- + +@sinclair/typebox + +The MIT License (MIT) + +Copyright (c) 2017-2023 Haydn Paterson (sinclair) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +---------------------------------------------------------------------------*/ + +// ------------------------------------------------------------------ +// +// Operators (Set-Theory) +// +// The following functions perform common set-theory operations +// across arrays of PropertyKey. These operators are used in +// Intersect and Union composition. +// +// ------------------------------------------------------------------ + +// ------------------------------------------------------------------ +// OperatorIncludes +// ------------------------------------------------------------------ +// prettier-ignore +export type OperatorIncludes = ( + T extends [infer L extends PropertyKey, ...infer R extends PropertyKey[]] + ? S extends L + ? true + : OperatorIncludes + : false +) +/** Returns true if element S is in the set of T */ +// prettier-ignore +export function OperatorIncludes(T: [...T], S: S): OperatorIncludes { + const [L, ...R] = T + return ( + T.length > 0 + ? S === L + ? true + : OperatorIncludes(R, S) + : false + ) as OperatorIncludes +} +// ------------------------------------------------------------------ +// OperatorSubset +// ------------------------------------------------------------------ +// prettier-ignore +export type OperatorSubset = + T extends [infer L extends PropertyKey, ...infer R extends PropertyKey[]] + ? OperatorIncludes extends true + ? OperatorSubset + : false + : true + +/** Returns true if T is a subset of S */ +// prettier-ignore +export function OperatorSubset(T: [...T], S: [...S]): OperatorSubset { + const [L, ...R] = T + return ( + T.length > 0 + ? OperatorIncludes(S, L) === true + ? OperatorSubset(R, S) + : false + : true + ) as OperatorSubset +} +// ------------------------------------------------------------------ +// OperatorDistinct +// ------------------------------------------------------------------ +// prettier-ignore +export type OperatorDistinct = + T extends [infer L extends PropertyKey, ...infer R extends PropertyKey[]] + ? OperatorIncludes extends false + ? OperatorDistinct + : OperatorDistinct + : Acc +/** Returns a distinct set of elements */ +// prettier-ignore +export function OperatorDistinct(T: [...T], Acc: PropertyKey[] = []): OperatorDistinct { + const [L, ...R] = T + return ( + T.length > 0 + ? OperatorIncludes(Acc, L) === false + ? OperatorDistinct(R, [...Acc, L]) + : OperatorDistinct(R, [...Acc]) + : Acc + ) as OperatorDistinct +} +// ------------------------------------------------------------------ +// OperatorIntersect +// ------------------------------------------------------------------ +// prettier-ignore +export type OperatorIntersect = ( + T extends [infer L extends PropertyKey, ...infer R extends PropertyKey[]] + ? OperatorIncludes extends true + ? [L, ...OperatorIntersect] + : [...OperatorIntersect] + : [] +) +/** Returns the Intersect of the given sets */ +// prettier-ignore +export function OperatorIntersect(T: [...T], S: [...S]): OperatorIntersect { + const [L, ...R] = T + return ( + T.length > 0 + ? OperatorIncludes(S, L) === true + ? [L, ...OperatorIntersect(R, S)] + : [...OperatorIntersect(R, S)] + : [] + ) as OperatorIntersect +} +// ------------------------------------------------------------------ +// OperatorUnion +// ------------------------------------------------------------------ +// prettier-ignore +export type OperatorUnion = ( + T extends [infer L extends PropertyKey, ...infer R extends PropertyKey[]] + ? OperatorIncludes extends true + ? [...OperatorUnion] + : [L, ...OperatorUnion] + : S +) +/** Returns the Union of the given sets */ +// prettier-ignore +export function OperatorUnion(T: [...T], S: [...S]): OperatorUnion { + const [L, ...R] = T + return ( + T.length > 0 + ? OperatorIncludes(S, L) === true + ? [...OperatorUnion(R, S)] + : [L, ...OperatorUnion(R, S)] + : S + ) as OperatorUnion +} +// ------------------------------------------------------------------ +// OperatorComplement +// ------------------------------------------------------------------ +// prettier-ignore +export type OperatorComplement = ( + T extends [infer L extends PropertyKey, ...infer R extends PropertyKey[]] + ? OperatorIncludes extends true + ? [...OperatorComplement] + : [L, ...OperatorComplement] + : [] +) +/** Returns the Complement by omitting elements in T that are in S */ +// prettier-ignore +export function OperatorComplement(T: [...T], S: [...S]): OperatorComplement { + const [L, ...R] = T + return ( + T.length > 0 + ? OperatorIncludes(S, L) === true + ? [...OperatorComplement(R, S)] + : [L, ...OperatorComplement(R, S)] + : [] + ) as OperatorComplement +} +// ------------------------------------------------------------------ +// OperatorIntersectMany +// ------------------------------------------------------------------ +// prettier-ignore +export type OperatorIntersectMany = ( + T extends [infer L extends PropertyKey[]] + ? L + : T extends [infer L extends PropertyKey[], ...infer R extends PropertyKey[][]] + ? OperatorIntersect> + : [] +) +/** Returns the Intersect of multiple sets */ +// prettier-ignore +export function OperatorIntersectMany(T: [...T]): OperatorIntersectMany { + return ( + T.length === 1 + ? T[0] + : (() => { + const [L, ...R] = T + return ( + L.length > 0 + ? OperatorIntersect(L, OperatorIntersectMany(R)) + : [] + ) + })() + ) as OperatorIntersectMany +} +// ------------------------------------------------------------------ +// OperatorUnionMany +// ------------------------------------------------------------------ +// prettier-ignore +export type OperatorUnionMany = ( + T extends [infer L extends PropertyKey[]] + ? L + : T extends [infer L extends PropertyKey[], ...infer R extends PropertyKey[][]] + ? OperatorUnion> + : [] +) +/** Returns the Union of multiple sets */ +export function OperatorUnionMany(T: [...T]): OperatorUnionMany { + return ( + T.length === 1 + ? T[0] + : (() => { + const [L, ...R] = T + return T.length > 0 ? OperatorUnion(L, OperatorUnionMany(R)) : [] + })() + ) as OperatorUnionMany +} diff --git a/src/type/optional/index.ts b/src/type/optional/index.ts new file mode 100644 index 000000000..4cd5011be --- /dev/null +++ b/src/type/optional/index.ts @@ -0,0 +1,29 @@ +/*-------------------------------------------------------------------------- + +@sinclair/typebox + +The MIT License (MIT) + +Copyright (c) 2017-2023 Haydn Paterson (sinclair) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +---------------------------------------------------------------------------*/ + +export * from './optional' diff --git a/src/type/optional/optional.ts b/src/type/optional/optional.ts new file mode 100644 index 000000000..23951d119 --- /dev/null +++ b/src/type/optional/optional.ts @@ -0,0 +1,41 @@ +/*-------------------------------------------------------------------------- + +@sinclair/typebox + +The MIT License (MIT) + +Copyright (c) 2017-2023 Haydn Paterson (sinclair) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +---------------------------------------------------------------------------*/ + +import type { TSchema } from '../schema/index' +import { Symbols } from '../symbols/index' +import { CloneType } from '../clone/type' + +// ------------------------------------------------------------------ +// TOptional +// ------------------------------------------------------------------ +export type TOptional = T & { [Symbols.Optional]: 'Optional' } + +/** `[Json]` Creates an Optional property */ +export function Optional(schema: T): TOptional { + return { ...CloneType(schema), [Symbols.Optional]: 'Optional' } +} diff --git a/src/type/parameters/index.ts b/src/type/parameters/index.ts new file mode 100644 index 000000000..8ceae5140 --- /dev/null +++ b/src/type/parameters/index.ts @@ -0,0 +1,29 @@ +/*-------------------------------------------------------------------------- + +@sinclair/typebox + +The MIT License (MIT) + +Copyright (c) 2017-2023 Haydn Paterson (sinclair) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +---------------------------------------------------------------------------*/ + +export * from './parameters' diff --git a/src/type/parameters/parameters.ts b/src/type/parameters/parameters.ts new file mode 100644 index 000000000..f3895efd3 --- /dev/null +++ b/src/type/parameters/parameters.ts @@ -0,0 +1,43 @@ +/*-------------------------------------------------------------------------- + +@sinclair/typebox + +The MIT License (MIT) + +Copyright (c) 2017-2023 Haydn Paterson (sinclair) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +---------------------------------------------------------------------------*/ + +import type { TSchema, SchemaOptions } from '../schema/index' +import type { TFunction } from '../function/index' +import type { Ensure } from '../helpers/index' +import { type TTuple, Tuple } from '../tuple/index' +import { CloneRest } from '../clone/type' + +// ------------------------------------------------------------------ +// TParameters +// ------------------------------------------------------------------ +export type TParameters = Ensure> + +/** `[JavaScript]` Extracts the Parameters from the given Function type */ +export function Parameters>(schema: T, options: SchemaOptions = {}): TParameters { + return Tuple(CloneRest(schema.parameters), { ...options }) +} diff --git a/src/type/partial/index.ts b/src/type/partial/index.ts new file mode 100644 index 000000000..72d4a26bd --- /dev/null +++ b/src/type/partial/index.ts @@ -0,0 +1,29 @@ +/*-------------------------------------------------------------------------- + +@sinclair/typebox + +The MIT License (MIT) + +Copyright (c) 2017-2023 Haydn Paterson (sinclair) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +---------------------------------------------------------------------------*/ + +export * from './partial' diff --git a/src/type/partial/partial.ts b/src/type/partial/partial.ts new file mode 100644 index 000000000..01e822bb2 --- /dev/null +++ b/src/type/partial/partial.ts @@ -0,0 +1,127 @@ +/*-------------------------------------------------------------------------- + +@sinclair/typebox + +The MIT License (MIT) + +Copyright (c) 2017-2023 Haydn Paterson (sinclair) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +---------------------------------------------------------------------------*/ + +import type { TSchema, SchemaOptions } from '../schema/index' +import type { Evaluate } from '../helpers/index' +import { type TReadonlyOptional } from '../readonly-optional' +import { type TOptional, Optional } from '../optional/index' +import { type TReadonly } from '../readonly/index' +import { type TRecursive } from '../recursive/index' +import { type TObject, type TProperties, Object } from '../object/index' +import { type TIntersect, Intersect } from '../intersect/index' +import { type TUnion, Union } from '../union/index' +import { Discard } from '../discard/index' +import { Symbols } from '../symbols/index' +import { CloneType } from '../clone/type' +import { TIntersect as IsIntersectType, TUnion as IsUnionType, TObject as IsObjectType } from '../guard/type' + +// ------------------------------------------------------------------ +// FromIntersect +// ------------------------------------------------------------------ +// prettier-ignore +type FromIntersect = ( + T extends [infer L extends TSchema, ...infer R extends TSchema[]] + ? [PartialResolve, ...FromIntersect] + : [] +) +// prettier-ignore +function FromIntersect(T: [...T]) : FromIntersect { + const [L, ...R] = T + return ( + T.length > 0 + ? [PartialResolve(L), ...FromIntersect(R)] + : [] + ) as FromIntersect +} +// ------------------------------------------------------------------ +// FromUnion +// ------------------------------------------------------------------ +// prettier-ignore +type FromUnion = ( + T extends [infer L extends TSchema, ...infer R extends TSchema[]] + ? [PartialResolve, ...FromUnion] + : [] +) +// prettier-ignore +function FromUnion(T: [...T]): FromUnion { + const [L, ...R] = T + return ( + T.length > 0 + ? [PartialResolve(L), ...FromUnion(R)] + : [] + ) as FromUnion +} +// ------------------------------------------------------------------ +// FromProperties +// ------------------------------------------------------------------ +// prettier-ignore +type FromProperties = Evaluate<{ + [K in keyof T]: + T[K] extends (TReadonlyOptional) ? TReadonlyOptional : + T[K] extends (TReadonly) ? TReadonlyOptional : + T[K] extends (TOptional) ? TOptional : + TOptional +}> +// prettier-ignore +function FromProperties(T: T) { + return globalThis.Object.getOwnPropertyNames(T).reduce((Acc, K) => { + return { ...Acc, [K]: Optional(T[K]) } + }, {} as TProperties) +} +// ------------------------------------------------------------------ +// PartialResolve +// ------------------------------------------------------------------ +// prettier-ignore +export type PartialResolve = ( + T extends TRecursive ? TRecursive> : + T extends TIntersect ? TIntersect> : + T extends TUnion ? TUnion> : + T extends TObject ? TObject> : + TObject<{}> +) +// prettier-ignore +export function PartialResolve(T: T): PartialResolve { + return ( + IsIntersectType(T) ? Intersect(FromIntersect(T.allOf)) : + IsUnionType(T) ? Union(FromUnion(T.anyOf)) : + IsObjectType(T) ? Object(FromProperties(T.properties)) : + Object({}) + ) as PartialResolve +} + +// ------------------------------------------------------------------ +// TPartial +// ------------------------------------------------------------------ +export type TPartial = PartialResolve + +/** `[Json]` Constructs a type where all properties are optional */ +export function Partial(T: T, options: SchemaOptions = {}): TPartial { + const D = Discard(T, [Symbols.Transform, '$id', 'required']) as TSchema + const R = CloneType(PartialResolve(T), options) + return { ...D, ...R } +} diff --git a/src/type/patterns/index.ts b/src/type/patterns/index.ts new file mode 100644 index 000000000..f6b72e45c --- /dev/null +++ b/src/type/patterns/index.ts @@ -0,0 +1,29 @@ +/*-------------------------------------------------------------------------- + +@sinclair/typebox + +The MIT License (MIT) + +Copyright (c) 2017-2023 Haydn Paterson (sinclair) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +---------------------------------------------------------------------------*/ + +export * from './patterns' diff --git a/src/type/patterns/patterns.ts b/src/type/patterns/patterns.ts new file mode 100644 index 000000000..08810ad6a --- /dev/null +++ b/src/type/patterns/patterns.ts @@ -0,0 +1,34 @@ +/*-------------------------------------------------------------------------- + +@sinclair/typebox + +The MIT License (MIT) + +Copyright (c) 2017-2023 Haydn Paterson (sinclair) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +---------------------------------------------------------------------------*/ + +export const PatternBoolean = '(true|false)' +export const PatternNumber = '(0|[1-9][0-9]*)' +export const PatternString = '(.*)' +export const PatternBooleanExact = `^${PatternBoolean}$` +export const PatternNumberExact = `^${PatternNumber}$` +export const PatternStringExact = `^${PatternString}$` diff --git a/src/type/pick/index.ts b/src/type/pick/index.ts new file mode 100644 index 000000000..3c47cf36d --- /dev/null +++ b/src/type/pick/index.ts @@ -0,0 +1,29 @@ +/*-------------------------------------------------------------------------- + +@sinclair/typebox + +The MIT License (MIT) + +Copyright (c) 2017-2023 Haydn Paterson (sinclair) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +---------------------------------------------------------------------------*/ + +export * from './pick' diff --git a/src/type/pick/pick.ts b/src/type/pick/pick.ts new file mode 100644 index 000000000..c03e2f143 --- /dev/null +++ b/src/type/pick/pick.ts @@ -0,0 +1,108 @@ +/*-------------------------------------------------------------------------- + +@sinclair/typebox + +The MIT License (MIT) + +Copyright (c) 2017-2023 Haydn Paterson (sinclair) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +---------------------------------------------------------------------------*/ + +import type { TSchema, SchemaOptions } from '../schema/index' +import type { TupleToUnion, Evaluate } from '../helpers/index' +import { type TRecursive } from '../recursive/index' +import { type TIntersect, Intersect } from '../intersect/index' +import { type TUnion, Union } from '../union/index' +import { type TObject, type TProperties, Object } from '../object/index' +import { IndexedKeyResolve } from '../indexed/index' +import { Discard } from '../discard/index' +import { Symbols } from '../symbols/index' +import { CloneType } from '../clone/type' +import { TIntersect as IsIntersectType, TUnion as IsUnionType, TObject as IsObjectType, TSchema as IsSchemaType } from '../guard/type' + +// ------------------------------------------------------------------ +// FromIntersect +// ------------------------------------------------------------------ +// prettier-ignore +type FromIntersect = + T extends [infer L extends TSchema, ...infer R extends TSchema[]] + ? [PickResolve, ...FromIntersect] + : [] +function FromIntersect(T: T, K: K) { + return T.map((T) => PickResolve(T, K)) as FromIntersect +} +// ------------------------------------------------------------------ +// FromUnion +// ------------------------------------------------------------------ +// prettier-ignore +type FromUnion = + T extends [infer L extends TSchema, ...infer R extends TSchema[]] + ? [PickResolve, ...FromUnion] + : [] +// prettier-ignore +function FromUnion(T: T, K: K) { + return T.map((T) => PickResolve(T, K)) as FromUnion +} +// ------------------------------------------------------------------ +// FromProperties +// ------------------------------------------------------------------ +// prettier-ignore +type FromProperties> = Evaluate> +// prettier-ignore +function FromProperties(T: T, K: K) { + return K.reduce((Acc, K) => { + return K in T ? { ...Acc, [K]: T[K as keyof T] } : Acc + }, {}) +} +// ------------------------------------------------------------------ +// PickResolve +// ------------------------------------------------------------------ +// prettier-ignore +export type PickResolve = + T extends TRecursive ? TRecursive> : + T extends TIntersect ? TIntersect> : + T extends TUnion ? TUnion> : + T extends TObject ? TObject> : + TObject<{}> +// prettier-ignore +export function PickResolve(T: T, K: [...K]): PickResolve { + return ( + IsIntersectType(T) ? Intersect(FromIntersect(T.allOf, K)) : + IsUnionType(T) ? Union(FromUnion(T.anyOf, K)) : + IsObjectType(T) ? Object(FromProperties(T.properties, K)) : + Object({}) + ) as PickResolve +} +// ------------------------------------------------------------------ +// TPick +// ------------------------------------------------------------------ +export type TPick = PickResolve + +/** `[Json]` Constructs a type whose keys are picked from the given type */ +export function Pick>(T: T, K: K, options?: SchemaOptions): TPick +/** `[Json]` Constructs a type whose keys are picked from the given type */ +export function Pick(T: T, K: readonly [...K], options?: SchemaOptions): TPick +export function Pick(T: TSchema, K: TSchema | readonly PropertyKey[], options: SchemaOptions = {}): any { + const I = IsSchemaType(K) ? IndexedKeyResolve(K) : (K as string[]) + const D = Discard(T, [Symbols.Transform, '$id', 'required']) as TSchema + const R = CloneType(PickResolve(T, I), options) + return { ...D, ...R } +} diff --git a/src/type/promise/index.ts b/src/type/promise/index.ts new file mode 100644 index 000000000..eb024e0fa --- /dev/null +++ b/src/type/promise/index.ts @@ -0,0 +1,29 @@ +/*-------------------------------------------------------------------------- + +@sinclair/typebox + +The MIT License (MIT) + +Copyright (c) 2017-2023 Haydn Paterson (sinclair) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +---------------------------------------------------------------------------*/ + +export * from './promise' diff --git a/src/type/promise/promise.ts b/src/type/promise/promise.ts new file mode 100644 index 000000000..9baa70fcb --- /dev/null +++ b/src/type/promise/promise.ts @@ -0,0 +1,51 @@ +/*-------------------------------------------------------------------------- + +@sinclair/typebox + +The MIT License (MIT) + +Copyright (c) 2017-2023 Haydn Paterson (sinclair) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +---------------------------------------------------------------------------*/ + +import type { TSchema, SchemaOptions } from '../schema/index' +import type { Static } from '../static/index' +import { Symbols } from '../symbols/index' +import { CloneType } from '../clone/type' + +// ------------------------------------------------------------------ +// TPromise +// ------------------------------------------------------------------ +export interface TPromise extends TSchema { + [Symbols.Kind]: 'Promise' + static: Promise> + type: 'Promise' + item: TSchema +} +/** `[JavaScript]` Creates a Promise type */ +export function Promise(item: T, options: SchemaOptions = {}): TPromise { + return { + ...options, + [Symbols.Kind]: 'Promise', + type: 'Promise', + item: CloneType(item), + } as unknown as TPromise +} diff --git a/src/type/readonly-optional/index.ts b/src/type/readonly-optional/index.ts new file mode 100644 index 000000000..652e4f43a --- /dev/null +++ b/src/type/readonly-optional/index.ts @@ -0,0 +1,29 @@ +/*-------------------------------------------------------------------------- + +@sinclair/typebox + +The MIT License (MIT) + +Copyright (c) 2017-2023 Haydn Paterson (sinclair) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +---------------------------------------------------------------------------*/ + +export * from './readonly-optional' diff --git a/src/type/readonly-optional/readonly-optional.ts b/src/type/readonly-optional/readonly-optional.ts new file mode 100644 index 000000000..2e37095e9 --- /dev/null +++ b/src/type/readonly-optional/readonly-optional.ts @@ -0,0 +1,41 @@ +/*-------------------------------------------------------------------------- + +@sinclair/typebox + +The MIT License (MIT) + +Copyright (c) 2017-2023 Haydn Paterson (sinclair) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +---------------------------------------------------------------------------*/ + +import type { TSchema } from '../schema/index' +import { type TReadonly, Readonly } from '../readonly/index' +import { type TOptional, Optional } from '../optional/index' + +// ------------------------------------------------------------------ +// TReadonlyOptional +// ------------------------------------------------------------------ +export type TReadonlyOptional = TOptional & TReadonly + +/** `[Json]` Creates a Readonly and Optional property */ +export function ReadonlyOptional(schema: T): TReadonly> { + return Readonly(Optional(schema)) +} diff --git a/src/type/readonly/index.ts b/src/type/readonly/index.ts new file mode 100644 index 000000000..0a6b24667 --- /dev/null +++ b/src/type/readonly/index.ts @@ -0,0 +1,29 @@ +/*-------------------------------------------------------------------------- + +@sinclair/typebox + +The MIT License (MIT) + +Copyright (c) 2017-2023 Haydn Paterson (sinclair) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +---------------------------------------------------------------------------*/ + +export * from './readonly' diff --git a/src/type/readonly/readonly.ts b/src/type/readonly/readonly.ts new file mode 100644 index 000000000..8671287c5 --- /dev/null +++ b/src/type/readonly/readonly.ts @@ -0,0 +1,41 @@ +/*-------------------------------------------------------------------------- + +@sinclair/typebox + +The MIT License (MIT) + +Copyright (c) 2017-2023 Haydn Paterson (sinclair) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +---------------------------------------------------------------------------*/ + +import type { TSchema } from '../schema/index' +import { Symbols } from '../symbols/index' +import { CloneType } from '../clone/type' + +// ------------------------------------------------------------------ +// TReadonly +// ------------------------------------------------------------------ +export type TReadonly = T & { [Symbols.Readonly]: 'Readonly' } + +/** `[Json]` Creates a Readonly property */ +export function Readonly(schema: T): TReadonly { + return { ...CloneType(schema), [Symbols.Readonly]: 'Readonly' } +} diff --git a/src/type/record/index.ts b/src/type/record/index.ts new file mode 100644 index 000000000..f36ec97c8 --- /dev/null +++ b/src/type/record/index.ts @@ -0,0 +1,29 @@ +/*-------------------------------------------------------------------------- + +@sinclair/typebox + +The MIT License (MIT) + +Copyright (c) 2017-2023 Haydn Paterson (sinclair) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +---------------------------------------------------------------------------*/ + +export * from './record' diff --git a/src/type/record/record.ts b/src/type/record/record.ts new file mode 100644 index 000000000..f8c5267bd --- /dev/null +++ b/src/type/record/record.ts @@ -0,0 +1,196 @@ +/*-------------------------------------------------------------------------- + +@sinclair/typebox + +The MIT License (MIT) + +Copyright (c) 2017-2023 Haydn Paterson (sinclair) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +---------------------------------------------------------------------------*/ + +import type { TSchema } from '../schema/index' +import type { Static } from '../static/index' +import type { Evaluate, Ensure, Assert } from '../helpers/index' +import { type TObject, type TProperties, type TAdditionalProperties, type ObjectOptions, Object } from '../object/index' +import { type TLiteral, TLiteralValue } from '../literal/index' +import { type TNever, Never } from '../never/index' +import { type TUnion, Union } from '../union/index' +import { type TString } from '../string/index' +import { type TInteger } from '../integer/index' +import { type TNumber } from '../number/index' +import { type TEnum } from '../enum/index' + +import { TTemplateLiteral, IsTemplateLiteralFinite, TemplateLiteralParseExact } from '../template-literal/index' +import { PatternStringExact, PatternNumberExact } from '../patterns/index' +import { IndexedKeyResolve } from '../indexed/index' +import { Symbols } from '../symbols/index' +import { CloneType } from '../clone/type' +import { IsUndefined } from '../guard/value' +import { TUnion as IsUnionType, TTemplateLiteral as IsTemplateLiteralType, TLiteral as IsLiteralType, TString as IsStringType, TInteger as IsIntegerType, TNumber as IsNumberType } from '../guard/type' + +// ------------------------------------------------------------------ +// FromPattern | FromKeys +// ------------------------------------------------------------------ +// prettier-ignore +function FromPattern(pattern: string, T: TSchema) { + return { [Symbols.Kind]: 'Record', type: 'object', patternProperties: { [pattern]: CloneType(T) } } +} +// prettier-ignore +function FromKeys(keys: string[], T: TSchema) { + const properties = keys.reduce((acc, key) => ({ ...acc, [key]: CloneType(T) }), {} as TProperties) + return Object(properties, { [Symbols.Hint]: 'Record' }) +} +// ------------------------------------------------------------------ +// FromTemplateLiteralKey (Fast Inference) +// ------------------------------------------------------------------ +// prettier-ignore +export type FromTemplateLiteralKeyInfinite<_ extends TTemplateLiteral, T extends TSchema> = Ensure> +// prettier-ignore +export type FromTemplateLiteralKeyFinite> = ( + Ensure>> +) +// prettier-ignore +export type FromTemplateLiteralKey = IsTemplateLiteralFinite extends false + ? FromTemplateLiteralKeyInfinite + : FromTemplateLiteralKeyFinite +// prettier-ignore +export function FromTemplateLiteralKey(K: K, T: T): FromTemplateLiteralKey { + const expression = TemplateLiteralParseExact(K.pattern) + return ( + IsTemplateLiteralFinite(expression) + ? FromKeys(IndexedKeyResolve(K), T) + : FromPattern(K.pattern, T) + ) as FromTemplateLiteralKey +} +// ------------------------------------------------------------------ +// FromEnumKey (Special Case) +// ------------------------------------------------------------------ +// prettier-ignore +export type FromEnumKey, T extends TSchema> = Ensure> +// ------------------------------------------------------------------ +// FromUnionKey +// ------------------------------------------------------------------ +// prettier-ignore +export type FromUnionKeyLiteralString, T extends TSchema> = { [_ in K['const']]: T } +// prettier-ignore +export type FromUnionKeyLiteralNumber, T extends TSchema> = { [_ in K['const']]: T } +// prettier-ignore +export type FromUnionKeyRest = + K extends [infer L extends TSchema, ...infer R extends TSchema[]] ? ( + L extends TUnion ? FromUnionKeyRest & FromUnionKeyRest : + L extends TLiteral ? FromUnionKeyLiteralString & FromUnionKeyRest : + L extends TLiteral ? FromUnionKeyLiteralNumber & FromUnionKeyRest : + {}) : {} +// prettier-ignore +export type FromUnionKey> = ( + Ensure> +) +// prettier-ignore +export function FromUnionKey(K: K, T: T): FromUnionKey { + return FromKeys(IndexedKeyResolve(Union(K)), T) as FromUnionKey +} +// ------------------------------------------------------------------ +// FromLiteralKey +// ------------------------------------------------------------------ +// prettier-ignore +export type FromLiteralKey = ( + Ensure]: T }>> +) +// prettier-ignore +export function FromLiteralKey(K: K, T: T): FromLiteralKey { + return FromKeys([K.toString()], T) as FromLiteralKey +} +// ------------------------------------------------------------------ +// FromStringKey +// ------------------------------------------------------------------ +// prettier-ignore +export type FromStringKey<_ extends TString, T extends TSchema> = ( + Ensure> +) +// prettier-ignore +export function FromStringKey(K: K, T: T): FromStringKey { + const pattern = IsUndefined(K.pattern) ? PatternStringExact : K.pattern + return FromPattern(pattern, T) as FromStringKey +} +// ------------------------------------------------------------------ +// FromIntegerKey +// ------------------------------------------------------------------ +// prettier-ignore +export type FromIntegerKey<_ extends TSchema, T extends TSchema> = ( + Ensure> +) +// prettier-ignore +export function FromIntegerKey(_: K, T: T): FromIntegerKey { + return FromPattern(PatternNumberExact, T) as FromIntegerKey +} +// ------------------------------------------------------------------ +// FromNumberKey +// ------------------------------------------------------------------ +// prettier-ignore +export type FromNumberKey<_ extends TSchema, T extends TSchema> = ( + Ensure> +) +// prettier-ignore +export function FromNumberKey(_: K, T: T): FromIntegerKey { + return FromPattern(PatternNumberExact, T) as FromIntegerKey +} +// ------------------------------------------------------------------ +// RecordResolve +// ------------------------------------------------------------------ +// prettier-ignore +export type RecordResolve = + K extends TEnum ? FromEnumKey : // (Special: Ensure resolve Enum before Union) + K extends TUnion ? FromUnionKey : + K extends TTemplateLiteral ? FromTemplateLiteralKey : + K extends TLiteral ? FromLiteralKey : + K extends TInteger ? FromIntegerKey : + K extends TNumber ? FromNumberKey : + K extends TString ? FromStringKey : + TNever +// prettier-ignore +export function RecordResolve(K: K, T: T): RecordResolve { + return ( + IsUnionType(K) ? FromUnionKey(K.anyOf, T) : + IsTemplateLiteralType(K) ? FromTemplateLiteralKey(K, T) : + IsLiteralType(K) ? FromLiteralKey(K.const, T) : + IsStringType(K) ? FromStringKey(K, T) : + IsIntegerType(K) ? FromIntegerKey(K, T) : + IsNumberType(K) ? FromNumberKey(K, T) : + Never() + ) as unknown as RecordResolve +} + +// ------------------------------------------------------------------ +// TRecord +// ------------------------------------------------------------------ +// prettier-ignore +export interface TRecord extends TSchema { + [Symbols.Kind]: 'Record' + static: Record, string | number>, Static> + type: 'object' + patternProperties: { [pattern: string]: T } + additionalProperties: TAdditionalProperties +} +// prettier-ignore +/** `[Json]` Creates a Record type */ +export function Record(K: K, T: T, options: ObjectOptions = {}): RecordResolve { + return CloneType(RecordResolve(K, T), options) +} diff --git a/src/type/recursive/index.ts b/src/type/recursive/index.ts new file mode 100644 index 000000000..3b4e17dd9 --- /dev/null +++ b/src/type/recursive/index.ts @@ -0,0 +1,29 @@ +/*-------------------------------------------------------------------------- + +@sinclair/typebox + +The MIT License (MIT) + +Copyright (c) 2017-2023 Haydn Paterson (sinclair) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +---------------------------------------------------------------------------*/ + +export * from './recursive' diff --git a/src/type/recursive/recursive.ts b/src/type/recursive/recursive.ts new file mode 100644 index 000000000..2658f0b8e --- /dev/null +++ b/src/type/recursive/recursive.ts @@ -0,0 +1,66 @@ +/*-------------------------------------------------------------------------- + +@sinclair/typebox + +The MIT License (MIT) + +Copyright (c) 2017-2023 Haydn Paterson (sinclair) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +---------------------------------------------------------------------------*/ + +import type { TSchema, SchemaOptions } from '../schema/index' +import { CloneType } from '../clone/type' +import { IsUndefined } from '../guard/value' +import { Symbols } from '../symbols/index' +import { Static } from '../static/index' + +// ------------------------------------------------------------------ +// TThis +// ------------------------------------------------------------------ +export interface TThis extends TSchema { + [Symbols.Kind]: 'This' + static: this['params'][0] + $ref: string +} +// ------------------------------------------------------------------ +// RecursiveResolve +// ------------------------------------------------------------------ +export type RecursiveResolve = Static]> +// ------------------------------------------------------------------ +// TRecursive +// ------------------------------------------------------------------ +export interface TRecursive extends TSchema { + [Symbols.Hint]: 'Recursive' + static: RecursiveResolve +} +// Auto Tracked For Recursive Types without ID's +let Ordinal = 0 +/** `[Json]` Creates a Recursive type */ +export function Recursive(callback: (thisType: TThis) => T, options: SchemaOptions = {}): TRecursive { + if (IsUndefined(options.$id)) (options as any).$id = `T${Ordinal++}` + const thisType = callback({ [Symbols.Kind]: 'This', $ref: `${options.$id}` } as any) + thisType.$id = options.$id + return CloneType({ + ...options, + [Symbols.Hint]: 'Recursive', + ...thisType, + }) as unknown as TRecursive +} diff --git a/src/type/ref/index.ts b/src/type/ref/index.ts new file mode 100644 index 000000000..847d754b6 --- /dev/null +++ b/src/type/ref/index.ts @@ -0,0 +1,29 @@ +/*-------------------------------------------------------------------------- + +@sinclair/typebox + +The MIT License (MIT) + +Copyright (c) 2017-2023 Haydn Paterson (sinclair) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +---------------------------------------------------------------------------*/ + +export * from './ref' diff --git a/src/type/ref/ref.ts b/src/type/ref/ref.ts new file mode 100644 index 000000000..009a67700 --- /dev/null +++ b/src/type/ref/ref.ts @@ -0,0 +1,55 @@ +/*-------------------------------------------------------------------------- + +@sinclair/typebox + +The MIT License (MIT) + +Copyright (c) 2017-2023 Haydn Paterson (sinclair) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +---------------------------------------------------------------------------*/ + +import type { TSchema, SchemaOptions } from '../schema/index' +import type { Static } from '../static/index' +import { Symbols } from '../symbols/index' +import { IsString, IsUndefined } from '../guard/value' + +// ------------------------------------------------------------------ +// TRef +// ------------------------------------------------------------------ +export interface TRef extends TSchema { + [Symbols.Kind]: 'Ref' + static: Static + $ref: string +} +/** `[Json]` Creates a Ref type. The referenced type must contain a $id */ +export function Ref(schema: T, options?: SchemaOptions): TRef +/** `[Json]` Creates a Ref type. */ +export function Ref($ref: string, options?: SchemaOptions): TRef +/** `[Json]` Creates a Ref type. */ +export function Ref(unresolved: TSchema | string, options: SchemaOptions = {}) { + if (IsString(unresolved)) return { ...options, [Symbols.Kind]: 'Ref', $ref: unresolved } + if (IsUndefined(unresolved.$id)) throw new Error('Reference target type must specify an $id') + return { + ...options, + [Symbols.Kind]: 'Ref', + $ref: unresolved.$id!, + } +} diff --git a/src/type/regexp/index.ts b/src/type/regexp/index.ts new file mode 100644 index 000000000..4dc7260ee --- /dev/null +++ b/src/type/regexp/index.ts @@ -0,0 +1,29 @@ +/*-------------------------------------------------------------------------- + +@sinclair/typebox + +The MIT License (MIT) + +Copyright (c) 2017-2023 Haydn Paterson (sinclair) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +---------------------------------------------------------------------------*/ + +export * from './regexp' diff --git a/src/type/regexp/regexp.ts b/src/type/regexp/regexp.ts new file mode 100644 index 000000000..b4822d297 --- /dev/null +++ b/src/type/regexp/regexp.ts @@ -0,0 +1,47 @@ +/*-------------------------------------------------------------------------- + +@sinclair/typebox + +The MIT License (MIT) + +Copyright (c) 2017-2023 Haydn Paterson (sinclair) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +---------------------------------------------------------------------------*/ + +import type { SchemaOptions } from '../schema/index' +import type { TString } from '../string/index' +import { IsString } from '../guard/value' +import { Symbols } from '../symbols/index' + +// ------------------------------------------------------------------ +// TRegExp +// ------------------------------------------------------------------ +export type TRegExp = TString + +/** `[JavaScript]` Creates a String type from a Regular Expression pattern */ +export function RegExp(pattern: string, options?: SchemaOptions): TRegExp +/** `[JavaScript]` Creates a String type from a Regular Expression */ +export function RegExp(regex: RegExp, options?: SchemaOptions): TRegExp +/** `[JavaScript]` Creates a String type */ +export function RegExp(unresolved: string | RegExp, options: SchemaOptions = {}) { + const pattern = IsString(unresolved) ? unresolved : unresolved.source + return { ...options, [Symbols.Kind]: 'String', type: 'string', pattern } as TRegExp +} diff --git a/src/type/registry/format.ts b/src/type/registry/format.ts new file mode 100644 index 000000000..96aeca4f5 --- /dev/null +++ b/src/type/registry/format.ts @@ -0,0 +1,55 @@ +/*-------------------------------------------------------------------------- + +@sinclair/typebox + +The MIT License (MIT) + +Copyright (c) 2017-2023 Haydn Paterson (sinclair) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +---------------------------------------------------------------------------*/ + +export type FormatRegistryValidationFunction = (value: string) => boolean +/** A registry for user defined string formats */ +const map = new Map() +/** Returns the entries in this registry */ +export function Entries() { + return new Map(map) +} +/** Clears all user defined string formats */ +export function Clear() { + return map.clear() +} +/** Deletes a registered format */ +export function Delete(format: string) { + return map.delete(format) +} +/** Returns true if the user defined string format exists */ +export function Has(format: string) { + return map.has(format) +} +/** Sets a validation function for a user defined string format */ +export function Set(format: string, func: FormatRegistryValidationFunction) { + map.set(format, func) +} +/** Gets a validation function for a user defined string format */ +export function Get(format: string) { + return map.get(format) +} diff --git a/src/type/registry/index.ts b/src/type/registry/index.ts new file mode 100644 index 000000000..dbe30d7c0 --- /dev/null +++ b/src/type/registry/index.ts @@ -0,0 +1,30 @@ +/*-------------------------------------------------------------------------- + +@sinclair/typebox + +The MIT License (MIT) + +Copyright (c) 2017-2023 Haydn Paterson (sinclair) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +---------------------------------------------------------------------------*/ + +export * as FormatRegistry from './format' +export * as TypeRegistry from './type' diff --git a/src/type/registry/type.ts b/src/type/registry/type.ts new file mode 100644 index 000000000..123fac9e3 --- /dev/null +++ b/src/type/registry/type.ts @@ -0,0 +1,56 @@ +/*-------------------------------------------------------------------------- + +@sinclair/typebox + +The MIT License (MIT) + +Copyright (c) 2017-2023 Haydn Paterson (sinclair) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +---------------------------------------------------------------------------*/ + +export type TypeRegistryValidationFunction = (schema: TSchema, value: unknown) => boolean +/** A registry for user defined types */ + +const map = new Map>() +/** Returns the entries in this registry */ +export function Entries() { + return new Map(map) +} +/** Clears all user defined types */ +export function Clear() { + return map.clear() +} +/** Deletes a registered type */ +export function Delete(kind: string) { + return map.delete(kind) +} +/** Returns true if this registry contains this kind */ +export function Has(kind: string) { + return map.has(kind) +} +/** Sets a validation function for a user defined type */ +export function Set(kind: string, func: TypeRegistryValidationFunction) { + map.set(kind, func) +} +/** Gets a custom validation function for a user defined type */ +export function Get(kind: string) { + return map.get(kind) +} diff --git a/src/type/required/index.ts b/src/type/required/index.ts new file mode 100644 index 000000000..7958a5f81 --- /dev/null +++ b/src/type/required/index.ts @@ -0,0 +1,29 @@ +/*-------------------------------------------------------------------------- + +@sinclair/typebox + +The MIT License (MIT) + +Copyright (c) 2017-2023 Haydn Paterson (sinclair) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +---------------------------------------------------------------------------*/ + +export * from './required' diff --git a/src/type/required/required.ts b/src/type/required/required.ts new file mode 100644 index 000000000..92b999e99 --- /dev/null +++ b/src/type/required/required.ts @@ -0,0 +1,127 @@ +/*-------------------------------------------------------------------------- + +@sinclair/typebox + +The MIT License (MIT) + +Copyright (c) 2017-2023 Haydn Paterson (sinclair) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +---------------------------------------------------------------------------*/ + +import type { TSchema, SchemaOptions } from '../schema/index' +import type { Evaluate } from '../helpers/index' +import { type TReadonlyOptional } from '../readonly-optional/index' +import { type TOptional } from '../optional/index' +import { type TReadonly } from '../readonly/index' +import { type TRecursive } from '../recursive/index' +import { type TIntersect, Intersect } from '../intersect/index' +import { type TUnion, Union } from '../union/index' +import { type TObject, type TProperties, Object } from '../object/index' + +import { Symbols } from '../symbols/index' +import { CloneType } from '../clone/type' +import { Discard } from '../discard/index' +import { TIntersect as IsIntersectType, TUnion as IsUnionType, TObject as IsObjectType } from '../guard/type' + +// ------------------------------------------------------------------ +// FromIntersect +// ------------------------------------------------------------------ +// prettier-ignore +type FromIntersect = ( + T extends [infer L extends TSchema, ...infer R extends TSchema[]] + ? [RequiredResolve, ...FromIntersect] + : [] +) +// prettier-ignore +function FromIntersect(T: [...T]) : FromIntersect { + const [L, ...R] = T + return ( + T.length > 0 + ? [RequiredResolve(L), ...FromIntersect(R)] + : [] + ) as FromIntersect +} +// ------------------------------------------------------------------ +// FromUnion +// ------------------------------------------------------------------ +// prettier-ignore +type FromUnion = ( + T extends [infer L extends TSchema, ...infer R extends TSchema[]] + ? [RequiredResolve, ...FromUnion] + : [] +) +// prettier-ignore +function FromUnion(T: [...T]): FromUnion { + const [L, ...R] = T + return ( + T.length > 0 + ? [RequiredResolve(L), ...FromUnion(R)] + : [] + ) as FromUnion +} +// ------------------------------------------------------------------ +// FromProperties +// ------------------------------------------------------------------ +// prettier-ignore +type FromProperties = Evaluate<{ + [K in keyof T]: + T[K] extends (TReadonlyOptional) ? TReadonly : + T[K] extends (TReadonly) ? TReadonly : + T[K] extends (TOptional) ? S : + T[K] +}> +// prettier-ignore +function FromProperties(T: T) { + return globalThis.Object.getOwnPropertyNames(T).reduce((Acc, K) => { + return { ...Acc, [K]: Discard(T[K], [Symbols.Optional]) as TSchema } + }, {} as TProperties) +} +// ------------------------------------------------------------------ +// RequiredResolve +// ------------------------------------------------------------------ +// prettier-ignore +export type RequiredResolve = ( + T extends TRecursive ? TRecursive> : + T extends TIntersect ? TIntersect> : + T extends TUnion ? TUnion> : + T extends TObject ? TObject> : + TObject<{}> +) +// prettier-ignore +export function RequiredResolve(T: T): RequiredResolve { + return ( + IsIntersectType(T) ? Intersect(FromIntersect(T.allOf)) : + IsUnionType(T) ? Union(FromUnion(T.anyOf)) : + IsObjectType(T) ? Object(FromProperties(T.properties)) : + Object({}) + ) as RequiredResolve +} +// ------------------------------------------------------------------ +// TRequired +// ------------------------------------------------------------------ +export type TRequired = RequiredResolve + +/** `[Json]` Constructs a type where all properties are required */ +export function Required(T: T, options: SchemaOptions = {}): TRequired { + const D = Discard(T, [Symbols.Transform, '$id', 'required']) as TSchema + const R = CloneType(RequiredResolve(T) as any, options) + return { ...D, ...R } +} diff --git a/src/type/rest/index.ts b/src/type/rest/index.ts new file mode 100644 index 000000000..fcc6f7580 --- /dev/null +++ b/src/type/rest/index.ts @@ -0,0 +1,29 @@ +/*-------------------------------------------------------------------------- + +@sinclair/typebox + +The MIT License (MIT) + +Copyright (c) 2017-2023 Haydn Paterson (sinclair) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +---------------------------------------------------------------------------*/ + +export * from './rest' diff --git a/src/type/rest/rest.ts b/src/type/rest/rest.ts new file mode 100644 index 000000000..43df52a8f --- /dev/null +++ b/src/type/rest/rest.ts @@ -0,0 +1,56 @@ +/*-------------------------------------------------------------------------- + +@sinclair/typebox + +The MIT License (MIT) + +Copyright (c) 2017-2023 Haydn Paterson (sinclair) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +---------------------------------------------------------------------------*/ + +import type { TSchema } from '../schema/index' +import type { TIntersect } from '../intersect/index' +import type { TUnion } from '../union/index' +import type { TTuple } from '../tuple/index' +import { CloneRest } from '../clone/type' +import { TIntersect as IsIntersectType, TUnion as IsUnionType, TTuple as IsTupleType } from '../guard/type' + +// ------------------------------------------------------------------ +// RestResolve +// ------------------------------------------------------------------ +// prettier-ignore +export type RestResolve = + T extends TIntersect ? [...S] : + T extends TUnion ? [...S] : + T extends TTuple ? [...S] : + [] +export function RestResolve(T: T) { + return (IsIntersectType(T) ? [...T.allOf] : IsUnionType(T) ? [...T.anyOf] : IsTupleType(T) ? [...(T.items ?? [])] : []) as RestResolve +} +// ------------------------------------------------------------------ +// TRest +// ------------------------------------------------------------------ +export type TRest = RestResolve + +/** `[Json]` Extracts interior Rest elements from Tuple, Intersect and Union types */ +export function Rest(T: T): TRest { + return CloneRest(RestResolve(T)) +} diff --git a/src/type/return-type/index.ts b/src/type/return-type/index.ts new file mode 100644 index 000000000..06602abd2 --- /dev/null +++ b/src/type/return-type/index.ts @@ -0,0 +1,29 @@ +/*-------------------------------------------------------------------------- + +@sinclair/typebox + +The MIT License (MIT) + +Copyright (c) 2017-2023 Haydn Paterson (sinclair) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +---------------------------------------------------------------------------*/ + +export * from './return-type' diff --git a/src/type/return-type/return-type.ts b/src/type/return-type/return-type.ts new file mode 100644 index 000000000..993888908 --- /dev/null +++ b/src/type/return-type/return-type.ts @@ -0,0 +1,41 @@ +/*-------------------------------------------------------------------------- + +@sinclair/typebox + +The MIT License (MIT) + +Copyright (c) 2017-2023 Haydn Paterson (sinclair) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +---------------------------------------------------------------------------*/ + +import type { SchemaOptions } from '../schema/index' +import type { TFunction } from '../function/index' +import { CloneType } from '../clone/type' + +// ------------------------------------------------------------------ +// TReturnType +// ------------------------------------------------------------------ +export type TReturnType = T['returns'] + +/** `[JavaScript]` Extracts the ReturnType from the given Function type */ +export function ReturnType>(schema: T, options: SchemaOptions = {}): TReturnType { + return CloneType(schema.returns, options) +} diff --git a/src/type/schema/index.ts b/src/type/schema/index.ts new file mode 100644 index 000000000..0b1618cd1 --- /dev/null +++ b/src/type/schema/index.ts @@ -0,0 +1,29 @@ +/*-------------------------------------------------------------------------- + +@sinclair/typebox + +The MIT License (MIT) + +Copyright (c) 2017-2023 Haydn Paterson (sinclair) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +---------------------------------------------------------------------------*/ + +export * from './schema' diff --git a/src/type/schema/schema.ts b/src/type/schema/schema.ts new file mode 100644 index 000000000..b4e802bca --- /dev/null +++ b/src/type/schema/schema.ts @@ -0,0 +1,96 @@ +/*-------------------------------------------------------------------------- + +@sinclair/typebox + +The MIT License (MIT) + +Copyright (c) 2017-2023 Haydn Paterson (sinclair) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +---------------------------------------------------------------------------*/ + +import { Symbols } from '../symbols/index' + +// ------------------------------------------------------------------ +// TSchema +// ------------------------------------------------------------------ +export interface SchemaOptions { + $schema?: string + /** Id for this schema */ + $id?: string + /** Title of this schema */ + title?: string + /** Description of this schema */ + description?: string + /** Default value for this schema */ + default?: any + /** Example values matching this schema */ + examples?: any + /** Optional annotation for readOnly */ + readOnly?: boolean + /** Optional annotation for writeOnly */ + writeOnly?: boolean + [prop: string]: any +} +export interface TKind { + [Symbols.Kind]: string +} +export interface TSchema extends SchemaOptions, TKind { + [Symbols.Readonly]?: string + [Symbols.Optional]?: string + [Symbols.Hint]?: string + params: unknown[] + static: unknown +} +// ------------------------------------------------------------------ +// TAnySchema +// ------------------------------------------------------------------ +// export type TAnySchema = +// | TSchema +// | TAny +// | TArray +// | TAsyncIterator +// | TBigInt +// | TBoolean +// | TConstructor +// | TDate +// | TEnum +// | TFunction +// | TInteger +// | TIntersect +// | TIterator +// | TLiteral +// | TNot +// | TNull +// | TNumber +// | TObject +// | TPromise +// | TRecord +// | TRef +// | TString +// | TSymbol +// | TTemplateLiteral +// | TThis +// | TTuple +// | TUndefined +// | TUnion +// | TUint8Array +// | TUnknown +// | TVoid diff --git a/src/type/static/index.ts b/src/type/static/index.ts new file mode 100644 index 000000000..04be51471 --- /dev/null +++ b/src/type/static/index.ts @@ -0,0 +1,29 @@ +/*-------------------------------------------------------------------------- + +@sinclair/typebox + +The MIT License (MIT) + +Copyright (c) 2017-2023 Haydn Paterson (sinclair) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +---------------------------------------------------------------------------*/ + +export * from './static' diff --git a/src/type/static/static.ts b/src/type/static/static.ts new file mode 100644 index 000000000..ecf950710 --- /dev/null +++ b/src/type/static/static.ts @@ -0,0 +1,92 @@ +/*-------------------------------------------------------------------------- + +@sinclair/typebox + +The MIT License (MIT) + +Copyright (c) 2017-2023 Haydn Paterson (sinclair) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +---------------------------------------------------------------------------*/ + +import type { Evaluate } from '../helpers/index' +import type { TOptional } from '../optional/index' +import type { TReadonly } from '../readonly/index' +import type { TArray } from '../array/index' +import type { TAsyncIterator } from '../async-iterator/index' +import type { TConstructor } from '../constructor/index' +import type { TEnum } from '../enum/index' +import type { TFunction } from '../function/index' +import type { TIntersect } from '../intersect/index' +import type { TIterator } from '../iterator/index' +import type { TNot } from '../not/index' +import type { TObject, TProperties } from '../object/index' +import type { TPromise } from '../promise/index' +import type { TRecursive } from '../recursive/index' +import type { TRecord } from '../record/index' +import type { TRef } from '../ref/index' +import type { TTuple } from '../tuple/index' +import type { TUnion } from '../union/index' +import type { TUnsafe } from '../unsafe/index' +import type { TSchema } from '../schema/index' +import type { TTransform } from '../transform/index' + +// ------------------------------------------------------------------ +// DecodeType +// ------------------------------------------------------------------ +// prettier-ignore +export type DecodeProperties = { + [K in keyof T]: DecodeType +} +// prettier-ignore +export type DecodeRest = T extends [infer L extends TSchema, ...infer R extends TSchema[]] + ? [DecodeType, ...DecodeRest] + : [] +// prettier-ignore +export type DecodeType = ( + T extends TOptional ? TOptional> : + T extends TReadonly ? TReadonly> : + T extends TTransform ? TUnsafe : + T extends TArray ? TArray> : + T extends TAsyncIterator ? TAsyncIterator> : + T extends TConstructor ? TConstructor, DecodeType> : + T extends TEnum ? TEnum : // intercept for union. interior non decodable + T extends TFunction ? TFunction, DecodeType> : + T extends TIntersect ? TIntersect> : + T extends TIterator ? TIterator> : + T extends TNot ? TNot> : + T extends TObject ? TObject>> : + T extends TPromise ? TPromise> : + T extends TRecord ? TRecord> : + T extends TRecursive ? TRecursive> : + T extends TRef ? TRef> : + T extends TTuple ? TTuple> : + T extends TUnion ? TUnion> : + T +) +// ------------------------------------------------------------------ +// Static +// ------------------------------------------------------------------ +/** Creates an decoded static type from a TypeBox type */ +export type StaticDecode = Static, P> +/** Creates an encoded static type from a TypeBox type */ +export type StaticEncode = Static +/** Creates a static type from a TypeBox type */ +export type Static = (T & { params: P })['static'] diff --git a/src/type/strict/index.ts b/src/type/strict/index.ts new file mode 100644 index 000000000..07a8fe6f1 --- /dev/null +++ b/src/type/strict/index.ts @@ -0,0 +1,29 @@ +/*-------------------------------------------------------------------------- + +@sinclair/typebox + +The MIT License (MIT) + +Copyright (c) 2017-2023 Haydn Paterson (sinclair) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +---------------------------------------------------------------------------*/ + +export * from './strict' diff --git a/src/type/strict/strict.ts b/src/type/strict/strict.ts new file mode 100644 index 000000000..a41a0675d --- /dev/null +++ b/src/type/strict/strict.ts @@ -0,0 +1,34 @@ +/*-------------------------------------------------------------------------- + +@sinclair/typebox + +The MIT License (MIT) + +Copyright (c) 2017-2023 Haydn Paterson (sinclair) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +---------------------------------------------------------------------------*/ + +import type { TSchema } from '../schema/index' + +/** `[Json]` Omits compositing symbols from this schema */ +export function Strict(schema: T): T { + return JSON.parse(JSON.stringify(schema)) +} diff --git a/src/type/string/index.ts b/src/type/string/index.ts new file mode 100644 index 000000000..e6f45947f --- /dev/null +++ b/src/type/string/index.ts @@ -0,0 +1,29 @@ +/*-------------------------------------------------------------------------- + +@sinclair/typebox + +The MIT License (MIT) + +Copyright (c) 2017-2023 Haydn Paterson (sinclair) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +---------------------------------------------------------------------------*/ + +export * from './string' diff --git a/src/type/string/string.ts b/src/type/string/string.ts new file mode 100644 index 000000000..583cb8f3d --- /dev/null +++ b/src/type/string/string.ts @@ -0,0 +1,86 @@ +/*-------------------------------------------------------------------------- + +@sinclair/typebox + +The MIT License (MIT) + +Copyright (c) 2017-2023 Haydn Paterson (sinclair) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +---------------------------------------------------------------------------*/ + +import { TSchema, SchemaOptions } from '../schema/index' +import { Symbols } from '../symbols/index' + +// ------------------------------------------------------------------ +// TString +// ------------------------------------------------------------------ +export type StringFormatOption = + | 'date-time' + | 'time' + | 'date' + | 'email' + | 'idn-email' + | 'hostname' + | 'idn-hostname' + | 'ipv4' + | 'ipv6' + | 'uri' + | 'uri-reference' + | 'iri' + | 'uuid' + | 'iri-reference' + | 'uri-template' + | 'json-pointer' + | 'relative-json-pointer' + | 'regex' + | ({} & string) +// prettier-ignore +export type StringContentEncodingOption = + | '7bit' + | '8bit' + | 'binary' + | 'quoted-printable' + | 'base64' + | ({} & string) +export interface StringOptions extends SchemaOptions { + /** The maximum string length */ + maxLength?: number + /** The minimum string length */ + minLength?: number + /** A regular expression pattern this string should match */ + pattern?: string + /** A format this string should match */ + format?: StringFormatOption + /** The content encoding for this string */ + contentEncoding?: StringContentEncodingOption + /** The content media type for this string */ + contentMediaType?: string +} +export interface TString extends TSchema, StringOptions { + [Symbols.Kind]: 'String' + static: string + type: 'string' +} + +/** `[Json]` Creates a String type */ +export function String(options: StringOptions = {}): TString { + return { ...options, [Symbols.Kind]: 'String', type: 'string' } as unknown as TString +} diff --git a/src/type/symbol/index.ts b/src/type/symbol/index.ts new file mode 100644 index 000000000..f70c3772e --- /dev/null +++ b/src/type/symbol/index.ts @@ -0,0 +1,29 @@ +/*-------------------------------------------------------------------------- + +@sinclair/typebox + +The MIT License (MIT) + +Copyright (c) 2017-2023 Haydn Paterson (sinclair) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +---------------------------------------------------------------------------*/ + +export * from './symbol' diff --git a/src/type/symbol/symbol.ts b/src/type/symbol/symbol.ts new file mode 100644 index 000000000..9ab0c87f6 --- /dev/null +++ b/src/type/symbol/symbol.ts @@ -0,0 +1,44 @@ +/*-------------------------------------------------------------------------- + +@sinclair/typebox + +The MIT License (MIT) + +Copyright (c) 2017-2023 Haydn Paterson (sinclair) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +---------------------------------------------------------------------------*/ + +import { TSchema, SchemaOptions } from '../schema/index' +import { Symbols } from '../symbols/index' + +// ------------------------------------------------------------------ +// TSymbol +// ------------------------------------------------------------------ +export type SymbolValue = string | number | undefined +export interface TSymbol extends TSchema, SchemaOptions { + [Symbols.Kind]: 'Symbol' + static: symbol + type: 'symbol' +} +/** `[JavaScript]` Creates a Symbol type */ +export function Symbol(options?: SchemaOptions): TSymbol { + return { ...options, [Symbols.Kind]: 'Symbol', type: 'symbol' } as unknown as TSymbol +} diff --git a/src/type/symbols/index.ts b/src/type/symbols/index.ts new file mode 100644 index 000000000..1ec60c708 --- /dev/null +++ b/src/type/symbols/index.ts @@ -0,0 +1,29 @@ +/*-------------------------------------------------------------------------- + +@sinclair/typebox + +The MIT License (MIT) + +Copyright (c) 2017-2023 Haydn Paterson (sinclair) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +---------------------------------------------------------------------------*/ + +export * from './symbols' diff --git a/src/type/symbols/symbols.ts b/src/type/symbols/symbols.ts new file mode 100644 index 000000000..4ef2de5fb --- /dev/null +++ b/src/type/symbols/symbols.ts @@ -0,0 +1,55 @@ +/*-------------------------------------------------------------------------- + +@sinclair/typebox + +The MIT License (MIT) + +Copyright (c) 2017-2023 Haydn Paterson (sinclair) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +---------------------------------------------------------------------------*/ + +// ------------------------------------------------------------------ +// Symbols +// ------------------------------------------------------------------ +export interface Symbols { + /** Symbol key applied to transform types */ + readonly Transform: unique symbol + /** Symbol key applied to readonly types */ + readonly Readonly: unique symbol + /** Symbol key applied to optional types */ + readonly Optional: unique symbol + /** Symbol key applied to types */ + readonly Hint: unique symbol + /** Symbol key applied to types */ + readonly Kind: unique symbol +} +export const Symbols = { + /** Symbol key applied to transform types */ + Transform: Symbol.for('TypeBox.Transform'), + /** Symbol key applied to readonly types */ + Readonly: Symbol.for('TypeBox.Readonly'), + /** Symbol key applied to optional types */ + Optional: Symbol.for('TypeBox.Optional'), + /** Symbol key applied to types */ + Hint: Symbol.for('TypeBox.Hint'), + /** Symbol key applied to types */ + Kind: Symbol.for('TypeBox.Kind'), +} as Symbols diff --git a/src/type/template-literal/finite.ts b/src/type/template-literal/finite.ts new file mode 100644 index 000000000..fc4f95d9c --- /dev/null +++ b/src/type/template-literal/finite.ts @@ -0,0 +1,109 @@ +/*-------------------------------------------------------------------------- + +@sinclair/typebox + +The MIT License (MIT) + +Copyright (c) 2017-2023 Haydn Paterson (sinclair) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +---------------------------------------------------------------------------*/ + +import type { TTemplateLiteral, TTemplateLiteralKind } from '../template-literal/index' +import type { TUnion } from '../union/index' +import type { TString } from '../string/index' +import type { TBoolean } from '../boolean/index' +import type { TNumber } from '../number/index' +import type { TInteger } from '../integer/index' +import type { TBigInt } from '../bigint/index' +import type { TLiteral } from '../literal/index' +import type { Expression } from './parser' + +// ------------------------------------------------------------------ +// TemplateLiteralFiniteError +// ------------------------------------------------------------------ +export class TemplateLiteralFiniteError extends Error {} + +// ------------------------------------------------------------------ +// IsTemplateLiteralFiniteCheck +// ------------------------------------------------------------------ +// prettier-ignore +function IsNumberExpression(expression: Expression): boolean { + return ( + expression.type === 'or' && + expression.expr.length === 2 && + expression.expr[0].type === 'const' && + expression.expr[0].const === '0' && + expression.expr[1].type === 'const' && + expression.expr[1].const === '[1-9][0-9]*' + ) +} +// prettier-ignore +function IsBooleanExpression(expression: Expression): boolean { + return ( + expression.type === 'or' && + expression.expr.length === 2 && + expression.expr[0].type === 'const' && + expression.expr[0].const === 'true' && + expression.expr[1].type === 'const' && + expression.expr[1].const === 'false' + ) +} +// prettier-ignore +function IsStringExpression(expression: Expression) { + return expression.type === 'const' && expression.const === '.*' +} +// prettier-ignore +type IsTemplateLiteralFiniteCheck = + T extends TTemplateLiteral ? IsTemplateLiteralFiniteArray : + T extends TUnion ? IsTemplateLiteralFiniteArray : + T extends TString ? false : + T extends TBoolean ? false : + T extends TNumber ? false : + T extends TInteger ? false : + T extends TBigInt ? false : + T extends TLiteral ? true : + false +// prettier-ignore +type IsTemplateLiteralFiniteArray = + T extends [infer L extends TTemplateLiteralKind, ...infer R extends TTemplateLiteralKind[]] + ? IsTemplateLiteralFiniteCheck extends false + ? false + : IsTemplateLiteralFiniteArray : + true +// ------------------------------------------------------------------ +// IsTemplateLiteralFinite +// ------------------------------------------------------------------ +// prettier-ignore +export type IsTemplateLiteralFinite = + T extends TTemplateLiteral + ? IsTemplateLiteralFiniteArray + : false +// prettier-ignore +export function IsTemplateLiteralFinite(expression: Expression): boolean { + return ( + IsBooleanExpression(expression) ? true : + IsNumberExpression(expression) || IsStringExpression(expression) ? false : + (expression.type === 'and') ? expression.expr.every((expr) => IsTemplateLiteralFinite(expr)) : + (expression.type === 'or') ? expression.expr.every((expr) => IsTemplateLiteralFinite(expr)) : + (expression.type === 'const') ? true : + (() => { throw new TemplateLiteralFiniteError(`Unknown expression type`) })() + ) +} diff --git a/src/type/template-literal/generate.ts b/src/type/template-literal/generate.ts new file mode 100644 index 000000000..b913f6cdc --- /dev/null +++ b/src/type/template-literal/generate.ts @@ -0,0 +1,126 @@ +/*-------------------------------------------------------------------------- + +@sinclair/typebox + +The MIT License (MIT) + +Copyright (c) 2017-2023 Haydn Paterson (sinclair) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +---------------------------------------------------------------------------*/ + +import type { TTemplateLiteral, TTemplateLiteralKind } from './index' +import type { TLiteral, TLiteralValue } from '../literal/index' +import type { Expression, And, Or, Const } from './parser' +import type { TUnion } from '../union/index' + +// ------------------------------------------------------------------ +// StringReducers +// ------------------------------------------------------------------ +// StringReduceUnary<"A", ["B", "C"]> -> ["AB", "AC"] +// prettier-ignore +type StringReduceUnary = + R extends [infer A extends string, ...infer B extends string[]] + ? [`${L}${A}`, ...StringReduceUnary] + : [] + +// StringReduceBinary<['A', 'B'], ['C', 'D']> -> ["AC", "AD", "BC", "BD"] +// prettier-ignore +type StringReduceBinary = + L extends [infer A extends string, ...infer B extends string[]] + ? [...StringReduceUnary, ...StringReduceBinary] + : [] + +// StringReduceMany<[['A', 'B'], ['C', 'D'], ['E']]> -> [["ACE", "ADE", "BCE", "BDE"]] +// prettier-ignore +type StringReduceMany = + T extends [infer L extends string[], infer R extends string[], ...infer Rest extends string[][]] + ? StringReduceMany<[StringReduceBinary, ...Rest]> + : T + +// Reduce<[['A', 'B'], ['C', 'D'], ['E']]> -> ["ACE", "ADE", "BCE", "BDE"] +// prettier-ignore +type StringReduce> = + 0 extends keyof O + ? O[0] + : [] +// prettier-ignore +type TemplateLiteralReduceUnion = + T extends [infer L extends TLiteral, ...infer R extends TLiteral[]] + ? [L['const'], ...TemplateLiteralReduceUnion] + : [] +// prettier-ignore +type TemplateLiteralReduce = + T extends [infer L extends TTemplateLiteralKind, ...infer R extends TTemplateLiteralKind[]] + ? L extends TLiteral ? [[S], ...TemplateLiteralReduce] : + L extends TUnion + ? [TemplateLiteralReduceUnion, ...TemplateLiteralReduce] + : [] + : [] + +// ------------------------------------------------------------------ +// GenerateFromExpression +// ------------------------------------------------------------------ +// prettier-ignore +function* GenerateReduce(buffer: string[][]): IterableIterator { + if (buffer.length === 1) return yield* buffer[0] + for (const left of buffer[0]) { + for (const right of GenerateReduce(buffer.slice(1))) { + yield `${left}${right}` + } + } +} +// prettier-ignore +function* GenerateAnd(expression: And): IterableIterator { + return yield* GenerateReduce(expression.expr.map((expr) => [...TemplateLiteralGenerate(expr)])) +} +// prettier-ignore +function* GenerateOr(expression: Or): IterableIterator { + for (const expr of expression.expr) yield* TemplateLiteralGenerate(expr) +} +// prettier-ignore +function* GenerateConst(expression: Const): IterableIterator { + return yield expression.const +} +// ------------------------------------------------------------------ +// TemplateLiteralGenerateError +// ------------------------------------------------------------------ +export class TemplateLiteralGenerateError extends Error {} +// ------------------------------------------------------------------ +// TemplateLiteralGenerate +// ------------------------------------------------------------------ +// prettier-ignore +export type TemplateLiteralGenerate = + T extends TTemplateLiteral + ? TemplateLiteralReduce extends infer R extends string[][] + ? StringReduce + : [] + : [] +export function* TemplateLiteralGenerate(expression: Expression): IterableIterator { + return expression.type === 'and' + ? yield* GenerateAnd(expression) + : expression.type === 'or' + ? yield* GenerateOr(expression) + : expression.type === 'const' + ? yield* GenerateConst(expression) + : (() => { + throw new TemplateLiteralGenerateError('Unknown expression') + })() +} diff --git a/src/type/template-literal/index.ts b/src/type/template-literal/index.ts new file mode 100644 index 000000000..79501f952 --- /dev/null +++ b/src/type/template-literal/index.ts @@ -0,0 +1,35 @@ +/*-------------------------------------------------------------------------- + +@sinclair/typebox + +The MIT License (MIT) + +Copyright (c) 2017-2023 Haydn Paterson (sinclair) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +---------------------------------------------------------------------------*/ + +export * from './finite' +export * from './generate' +export * from './syntax' +export * from './parser' +export * from './pattern' +export * from './union' +export * from './template-literal' diff --git a/src/type/template-literal/parser.ts b/src/type/template-literal/parser.ts new file mode 100644 index 000000000..401abec6b --- /dev/null +++ b/src/type/template-literal/parser.ts @@ -0,0 +1,161 @@ +/*-------------------------------------------------------------------------- + +@sinclair/typebox + +The MIT License (MIT) + +Copyright (c) 2017-2023 Haydn Paterson (sinclair) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +---------------------------------------------------------------------------*/ + +// ------------------------------------------------------------------ +// TemplateLiteralParserError +// ------------------------------------------------------------------ +export class TemplateLiteralParserError extends Error {} +// ------------------------------------------------------------------ +// TemplateLiteralParse +// ------------------------------------------------------------------ +// prettier-ignore +export type Expression = And | Or | Const +export type Const = { type: 'const'; const: string } +export type And = { type: 'and'; expr: Expression[] } +export type Or = { type: 'or'; expr: Expression[] } +// prettier-ignore +function IsNonEscaped(pattern: string, index: number, char: string) { + return pattern[index] === char && pattern.charCodeAt(index - 1) !== 92 +} +// prettier-ignore +function IsOpenParen(pattern: string, index: number) { + return IsNonEscaped(pattern, index, '(') +} +// prettier-ignore +function IsCloseParen(pattern: string, index: number) { + return IsNonEscaped(pattern, index, ')') +} +// prettier-ignore +function IsSeparator(pattern: string, index: number) { + return IsNonEscaped(pattern, index, '|') +} +// prettier-ignore +function IsGroup(pattern: string) { + if (!(IsOpenParen(pattern, 0) && IsCloseParen(pattern, pattern.length - 1))) return false + let count = 0 + for (let index = 0; index < pattern.length; index++) { + if (IsOpenParen(pattern, index)) count += 1 + if (IsCloseParen(pattern, index)) count -= 1 + if (count === 0 && index !== pattern.length - 1) return false + } + return true +} +// prettier-ignore +function InGroup(pattern: string) { + return pattern.slice(1, pattern.length - 1) +} +// prettier-ignore +function IsPrecedenceOr(pattern: string) { + let count = 0 + for (let index = 0; index < pattern.length; index++) { + if (IsOpenParen(pattern, index)) count += 1 + if (IsCloseParen(pattern, index)) count -= 1 + if (IsSeparator(pattern, index) && count === 0) return true + } + return false +} +// prettier-ignore +function IsPrecedenceAnd(pattern: string) { + for (let index = 0; index < pattern.length; index++) { + if (IsOpenParen(pattern, index)) return true + } + return false +} +// prettier-ignore +function Or(pattern: string): Expression { + let [count, start] = [0, 0] + const expressions: Expression[] = [] + for (let index = 0; index < pattern.length; index++) { + if (IsOpenParen(pattern, index)) count += 1 + if (IsCloseParen(pattern, index)) count -= 1 + if (IsSeparator(pattern, index) && count === 0) { + const range = pattern.slice(start, index) + if (range.length > 0) expressions.push(TemplateLiteralParse(range)) + start = index + 1 + } + } + const range = pattern.slice(start) + if (range.length > 0) expressions.push(TemplateLiteralParse(range)) + if (expressions.length === 0) return { type: 'const', const: '' } + if (expressions.length === 1) return expressions[0] + return { type: 'or', expr: expressions } +} +// prettier-ignore +function And(pattern: string): Expression { + function Group(value: string, index: number): [number, number] { + if (!IsOpenParen(value, index)) throw new TemplateLiteralParserError(`TemplateLiteralParser: Index must point to open parens`) + let count = 0 + for (let scan = index; scan < value.length; scan++) { + if (IsOpenParen(value, scan)) count += 1 + if (IsCloseParen(value, scan)) count -= 1 + if (count === 0) return [index, scan] + } + throw new TemplateLiteralParserError(`TemplateLiteralParser: Unclosed group parens in expression`) + } + function Range(pattern: string, index: number): [number, number] { + for (let scan = index; scan < pattern.length; scan++) { + if (IsOpenParen(pattern, scan)) return [index, scan] + } + return [index, pattern.length] + } + const expressions: Expression[] = [] + for (let index = 0; index < pattern.length; index++) { + if (IsOpenParen(pattern, index)) { + const [start, end] = Group(pattern, index) + const range = pattern.slice(start, end + 1) + expressions.push(TemplateLiteralParse(range)) + index = end + } else { + const [start, end] = Range(pattern, index) + const range = pattern.slice(start, end) + if (range.length > 0) expressions.push(TemplateLiteralParse(range)) + index = end - 1 + } + } + return ( + (expressions.length === 0) ? { type: 'const', const: '' } : + (expressions.length === 1) ? expressions[0] : + { type: 'and', expr: expressions } + ) +} +/** Parses a pattern and returns an expression tree */ +// prettier-ignore +export function TemplateLiteralParse(pattern: string): Expression { + return ( + IsGroup(pattern) ? TemplateLiteralParse(InGroup(pattern)) : + IsPrecedenceOr(pattern) ? Or(pattern) : + IsPrecedenceAnd(pattern) ? And(pattern) : + { type: 'const', const: pattern } + ) +} + +/** Parses a pattern and strips forward and trailing ^ and $ */ +// prettier-ignore +export function TemplateLiteralParseExact(pattern: string): Expression { + return TemplateLiteralParse(pattern.slice(1, pattern.length - 1)) +} diff --git a/src/type/template-literal/pattern.ts b/src/type/template-literal/pattern.ts new file mode 100644 index 000000000..efb59d799 --- /dev/null +++ b/src/type/template-literal/pattern.ts @@ -0,0 +1,71 @@ +/*-------------------------------------------------------------------------- + +@sinclair/typebox + +The MIT License (MIT) + +Copyright (c) 2017-2023 Haydn Paterson (sinclair) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +---------------------------------------------------------------------------*/ + +import type { TSchema } from '../schema/index' +import type { TTemplateLiteralKind } from '../template-literal/index' +import { PatternNumber, PatternString, PatternBoolean } from '../patterns/index' +import { Symbols } from '../symbols/index' +import { + TTemplateLiteral as IsTemplateLiteralType, + TUnion as IsUnionType, + TNumber as IsNumberType, + TInteger as IsIntegerType, + TBigInt as IsBigIntType, + TString as IsStringType, + TLiteral as IsLiteralType, + TBoolean as IsBooleanType, +} from '../guard/type' + +// ------------------------------------------------------------------ +// TemplateLiteralPatternError +// ------------------------------------------------------------------ +export class TemplateLiteralPatternError extends Error {} + +// ------------------------------------------------------------------ +// TemplateLiteralPattern +// ------------------------------------------------------------------ +function Escape(value: string) { + return value.replace(/[.*+?^${}()|[\]\\]/g, '\\$&') +} +// prettier-ignore +function Visit(schema: TSchema, acc: string): string { + return ( + IsTemplateLiteralType(schema) ? schema.pattern.slice(1, schema.pattern.length - 1) : + IsUnionType(schema) ? `(${schema.anyOf.map((schema) => Visit(schema, acc)).join('|')})` : + IsNumberType(schema) ? `${acc}${PatternNumber}` : + IsIntegerType(schema) ? `${acc}${PatternNumber}` : + IsBigIntType(schema) ? `${acc}${PatternNumber}` : + IsStringType(schema) ? `${acc}${PatternString}` : + IsLiteralType(schema) ? `${acc}${Escape(schema.const.toString())}` : + IsBooleanType(schema) ? `${acc}${PatternBoolean}` : + (() => { throw new TemplateLiteralPatternError(`Unexpected Kind '${schema[Symbols.Kind]}'`) })() + ) +} +export function TemplateLiteralPattern(kinds: TTemplateLiteralKind[]): string { + return `^${kinds.map((schema) => Visit(schema, '')).join('')}\$` +} diff --git a/src/type/template-literal/syntax.ts b/src/type/template-literal/syntax.ts new file mode 100644 index 000000000..030249135 --- /dev/null +++ b/src/type/template-literal/syntax.ts @@ -0,0 +1,117 @@ +/*-------------------------------------------------------------------------- + +@sinclair/typebox + +The MIT License (MIT) + +Copyright (c) 2017-2023 Haydn Paterson (sinclair) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +---------------------------------------------------------------------------*/ + +import type { Ensure, Assert, Trim } from '../helpers/index' +import type { TTemplateLiteralKind, TTemplateLiteral } from '../template-literal/index' +import { type TLiteral, Literal } from '../literal/index' +import { type TBoolean, Boolean } from '../boolean/index' +import { type TBigInt, BigInt } from '../bigint/index' +import { type TNumber, Number } from '../number/index' +import { type TString, String } from '../string/index' +import { Union, UnionResolve } from '../union/index' +import { Never } from '../never/index' + +// ------------------------------------------------------------------ +// SyntaxParsers +// ------------------------------------------------------------------ +// prettier-ignore +function* FromUnion(syntax: string): IterableIterator { + const trim = syntax.trim().replace(/"|'/g, '') + return ( + trim === 'boolean' ? yield Boolean() : + trim === 'number' ? yield Number() : + trim === 'bigint' ? yield BigInt() : + trim === 'string' ? yield String() : + yield (() => { + const literals = trim.split('|').map((literal) => Literal(literal.trim())) + return ( + literals.length === 0 ? Never() : + literals.length === 1 ? literals[0] : + Union(literals) + ) + })() + ) +} +// prettier-ignore +function* FromTerminal(syntax: string): IterableIterator { + if (syntax[1] !== '{') { + const L = Literal('$') + const R = FromSyntax(syntax.slice(1)) + return yield* [L, ...R] + } + for (let i = 2; i < syntax.length; i++) { + if (syntax[i] === '}') { + const L = FromUnion(syntax.slice(2, i)) + const R = FromSyntax(syntax.slice(i + 1)) + return yield* [...L, ...R] + } + } + yield Literal(syntax) +} +// prettier-ignore +function* FromSyntax(syntax: string): IterableIterator { + for (let i = 0; i < syntax.length; i++) { + if (syntax[i] === '$') { + const L = Literal(syntax.slice(0, i)) + const R = FromTerminal(syntax.slice(i)) + return yield* [L, ...R] + } + } + yield Literal(syntax) +} +// prettier-ignore +export type FromUnionLiteral = + T extends `${infer L}|${infer R}` ? [TLiteral>, ...FromUnionLiteral] : + T extends `${infer L}` ? [TLiteral>] : + [] +export type FromUnion = UnionResolve> +// prettier-ignore +export type FromTerminal = + T extends 'boolean' ? TBoolean : + T extends 'bigint' ? TBigInt : + T extends 'number' ? TNumber : + T extends 'string' ? TString : + FromUnion +// prettier-ignore +export type FromString = + T extends `{${infer L}}${infer R}` ? [FromTerminal, ...FromString] : + T extends `${infer L}$${infer R}` ? [TLiteral, ...FromString] : + T extends `${infer L}` ? [TLiteral] : + [] + +// ------------------------------------------------------------------ +// TemplateLiteralSyntax +// ------------------------------------------------------------------ +// prettier-ignore +export type TemplateLiteralSyntax = Ensure, TTemplateLiteralKind[]>>> + +// prettier-ignore +/** Parses TemplateLiteralSyntax and returns a tuple of TemplateLiteralKinds */ +export function TemplateLiteralSyntax(syntax: string): TTemplateLiteralKind[] { + return [...FromSyntax(syntax)] +} diff --git a/src/type/template-literal/template-literal.ts b/src/type/template-literal/template-literal.ts new file mode 100644 index 000000000..4d4a10322 --- /dev/null +++ b/src/type/template-literal/template-literal.ts @@ -0,0 +1,99 @@ +/*-------------------------------------------------------------------------- + +@sinclair/typebox + +The MIT License (MIT) + +Copyright (c) 2017-2023 Haydn Paterson (sinclair) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +---------------------------------------------------------------------------*/ + +import type { TSchema, SchemaOptions } from '../schema/index' +import type { Assert } from '../helpers/index' +import type { TUnion } from '../union/index' +import type { TLiteral } from '../literal/index' +import type { TInteger } from '../integer/index' +import type { TNumber } from '../number/index' +import type { TBigInt } from '../bigint/index' +import type { TString } from '../string/index' +import type { TBoolean } from '../boolean/index' +import type { TNever } from '../never/index' +import type { Static } from '../static/index' + +import { TemplateLiteralPattern } from './pattern' +import { TemplateLiteralSyntax } from './syntax' +import { EmptyString } from '../helpers/index' +import { IsString } from '../guard/value' +import { Symbols } from '../symbols/index' + +// ------------------------------------------------------------------ +// TemplateLiteralResolve +// ------------------------------------------------------------------ +// prettier-ignore +type TemplateLiteralResolveConst = + T extends TUnion ? { [K in keyof U]: TemplateLiteralResolve, Acc> }[number] : + T extends TTemplateLiteral ? `${Static}` : + T extends TLiteral ? `${U}` : + T extends TString ? `${string}` : + T extends TNumber ? `${number}` : + T extends TBigInt ? `${bigint}` : + T extends TBoolean ? `${boolean}` : + never +// prettier-ignore +export type TemplateLiteralResolve = + T extends [infer L, ...infer R] ? `${TemplateLiteralResolveConst}${TemplateLiteralResolve, Acc>}` : + Acc +// ------------------------------------------------------------------ +// TTemplateLiteralKind +// ------------------------------------------------------------------ +// prettier-ignore +export type TTemplateLiteralKind = + | TTemplateLiteral + | TUnion + | TLiteral + | TInteger + | TNumber + | TBigInt + | TString + | TBoolean + | TNever +// ------------------------------------------------------------------ +// TTemplateLiteral +// ------------------------------------------------------------------ +// prettier-ignore +export interface TTemplateLiteral extends TSchema { + [Symbols.Kind]: 'TemplateLiteral' + static: TemplateLiteralResolve + type: 'string' + pattern: string // todo: it may be possible to infer this pattern +} +/** `[Json]` Creates a TemplateLiteral type from template dsl string */ +export function TemplateLiteral(syntax: T, options?: SchemaOptions): TemplateLiteralSyntax +/** `[Json]` Creates a TemplateLiteral type */ +export function TemplateLiteral(kinds: [...T], options?: SchemaOptions): TTemplateLiteral +/** `[Json]` Creates a TemplateLiteral type */ +// prettier-ignore +export function TemplateLiteral(unresolved: TTemplateLiteralKind[] | string, options: SchemaOptions = {}) { + const pattern = IsString(unresolved) + ? TemplateLiteralPattern(TemplateLiteralSyntax(unresolved)) + : TemplateLiteralPattern(unresolved as TTemplateLiteralKind[]) + return { ...options, [Symbols.Kind]: 'TemplateLiteral', type: 'string', pattern } +} diff --git a/src/type/template-literal/union.ts b/src/type/template-literal/union.ts new file mode 100644 index 000000000..c39e6f7e0 --- /dev/null +++ b/src/type/template-literal/union.ts @@ -0,0 +1,47 @@ +/*-------------------------------------------------------------------------- + +@sinclair/typebox + +The MIT License (MIT) + +Copyright (c) 2017-2023 Haydn Paterson (sinclair) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +---------------------------------------------------------------------------*/ + +import type { TTemplateLiteral } from './template-literal' +import { type TUnion, Union } from '../union/index' +import { type TLiteral, Literal } from '../literal/index' +import { type TString, String } from '../string/index' +import { type TNever } from '../never/index' +import { TemplateLiteralGenerate } from './generate' +import { TemplateLiteralParseExact } from './parser' +import { IsTemplateLiteralFinite } from './finite' + +// ------------------------------------------------------------------ +// TemplateLiteralToUnion +// ------------------------------------------------------------------ +/** Resolves a template literal as a TUnion */ +export function TemplateLiteralToUnion(template: TTemplateLiteral): TNever | TString | TUnion { + const expression = TemplateLiteralParseExact(template.pattern) + if (!IsTemplateLiteralFinite(expression)) return String() + const literals = [...TemplateLiteralGenerate(expression)].map((value) => Literal(value)) + return Union(literals) +} diff --git a/src/type/transform/index.ts b/src/type/transform/index.ts new file mode 100644 index 000000000..e0e666af4 --- /dev/null +++ b/src/type/transform/index.ts @@ -0,0 +1,29 @@ +/*-------------------------------------------------------------------------- + +@sinclair/typebox + +The MIT License (MIT) + +Copyright (c) 2017-2023 Haydn Paterson (sinclair) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +---------------------------------------------------------------------------*/ + +export * from './transform' diff --git a/src/type/transform/transform.ts b/src/type/transform/transform.ts new file mode 100644 index 000000000..e23a89ac1 --- /dev/null +++ b/src/type/transform/transform.ts @@ -0,0 +1,82 @@ +/*-------------------------------------------------------------------------- + +@sinclair/typebox + +The MIT License (MIT) + +Copyright (c) 2017-2023 Haydn Paterson (sinclair) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +---------------------------------------------------------------------------*/ + +import type { TSchema } from '../schema/index' +import type { Static, StaticDecode } from '../static' + +import { TTransform as IsTransform } from '../guard/type' +import { CloneType } from '../clone/type' +import { Symbols } from '../symbols/index' + +// ------------------------------------------------------------------ +// TransformBuilders +// ------------------------------------------------------------------ +export class TransformDecodeBuilder { + constructor(private readonly schema: T) {} + public Decode, U>>(decode: D): TransformEncodeBuilder { + return new TransformEncodeBuilder(this.schema, decode) + } +} +// prettier-ignore +export class TransformEncodeBuilder { + constructor(private readonly schema: T, private readonly decode: D) { } + private EncodeTransform, StaticDecode>>(encode: E, schema: TTransform) { + const Encode = (value: unknown) => schema[Symbols.Transform as any].Encode(encode(value as any)) + const Decode = (value: unknown) => this.decode(schema[Symbols.Transform as any].Decode(value)) + const Codec = { Encode: Encode, Decode: Decode } + return { ...schema, [Symbols.Transform]: Codec } + } + private EncodeSchema, StaticDecode>>(encode: E, schema: TSchema) { + const Codec = { Decode: this.decode, Encode: encode } + return { ...schema as TSchema, [Symbols.Transform]: Codec } + } + public Encode, StaticDecode>>(encode: E): TTransform> { + const schema = CloneType(this.schema) + return ( + IsTransform(schema) ? this.EncodeTransform(encode, schema): this.EncodeSchema(encode, schema) + ) as unknown as TTransform> + } +} +// ------------------------------------------------------------------ +// TTransform +// ------------------------------------------------------------------ +export type TransformFunction = (value: T) => U +export interface TransformOptions { + Decode: TransformFunction, O> + Encode: TransformFunction> +} +export type TTransformResolve = T extends TTransform ? S : Static +export interface TTransform extends TSchema { + static: TTransformResolve + [Symbols.Transform]: TransformOptions + [key: string]: any +} +/** `[Json]` Creates a Transform type */ +export function Transform(schema: I): TransformDecodeBuilder { + return new TransformDecodeBuilder(schema) +} diff --git a/src/type/tuple/index.ts b/src/type/tuple/index.ts new file mode 100644 index 000000000..4a79c6155 --- /dev/null +++ b/src/type/tuple/index.ts @@ -0,0 +1,29 @@ +/*-------------------------------------------------------------------------- + +@sinclair/typebox + +The MIT License (MIT) + +Copyright (c) 2017-2023 Haydn Paterson (sinclair) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +---------------------------------------------------------------------------*/ + +export * from './tuple' diff --git a/src/type/tuple/tuple.ts b/src/type/tuple/tuple.ts new file mode 100644 index 000000000..cf01ef8f4 --- /dev/null +++ b/src/type/tuple/tuple.ts @@ -0,0 +1,64 @@ +/*-------------------------------------------------------------------------- + +@sinclair/typebox + +The MIT License (MIT) + +Copyright (c) 2017-2023 Haydn Paterson (sinclair) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +---------------------------------------------------------------------------*/ + +import type { TSchema, SchemaOptions } from '../schema/index' +import type { Static } from '../static/index' +import { CloneRest } from '../clone/type' +import { Symbols } from '../symbols/index' + +// ------------------------------------------------------------------ +// TupleResolve +// ------------------------------------------------------------------ +// prettier-ignore +export type TupleResolve = + T extends [infer L extends TSchema, ...infer R extends TSchema[]] + ? [Static, ...TupleResolve] + : [] +// ------------------------------------------------------------------ +// TTuple +// ------------------------------------------------------------------ +export interface TTuple extends TSchema { + [Symbols.Kind]: 'Tuple' + static: TupleResolve + type: 'array' + items?: T + additionalItems?: false + minItems: number + maxItems: number +} +/** `[Json]` Creates a Tuple type */ +export function Tuple(items: [...T], options: SchemaOptions = {}): TTuple { + // return TupleResolver.Resolve(T) + const [additionalItems, minItems, maxItems] = [false, items.length, items.length] + // prettier-ignore + return ( + items.length > 0 ? + { ...options, [Symbols.Kind]: 'Tuple', type: 'array', items: CloneRest(items), additionalItems, minItems, maxItems } : + { ...options, [Symbols.Kind]: 'Tuple', type: 'array', minItems, maxItems } + ) as unknown as TTuple +} diff --git a/src/type/uint8array/index.ts b/src/type/uint8array/index.ts new file mode 100644 index 000000000..56012dcfe --- /dev/null +++ b/src/type/uint8array/index.ts @@ -0,0 +1,29 @@ +/*-------------------------------------------------------------------------- + +@sinclair/typebox + +The MIT License (MIT) + +Copyright (c) 2017-2023 Haydn Paterson (sinclair) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +---------------------------------------------------------------------------*/ + +export * from './uint8array' diff --git a/src/type/uint8array/uint8array.ts b/src/type/uint8array/uint8array.ts new file mode 100644 index 000000000..0d80525f9 --- /dev/null +++ b/src/type/uint8array/uint8array.ts @@ -0,0 +1,47 @@ +/*-------------------------------------------------------------------------- + +@sinclair/typebox + +The MIT License (MIT) + +Copyright (c) 2017-2023 Haydn Paterson (sinclair) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +---------------------------------------------------------------------------*/ + +import type { TSchema, SchemaOptions } from '../schema/index' +import { Symbols } from '../symbols/index' + +// ------------------------------------------------------------------ +// TUint8Array +// ------------------------------------------------------------------ +export interface Uint8ArrayOptions extends SchemaOptions { + maxByteLength?: number + minByteLength?: number +} +export interface TUint8Array extends TSchema, Uint8ArrayOptions { + [Symbols.Kind]: 'Uint8Array' + static: Uint8Array + type: 'uint8array' +} +/** `[JavaScript]` Creates a Uint8Array type */ +export function Uint8Array(options: Uint8ArrayOptions = {}): TUint8Array { + return { ...options, [Symbols.Kind]: 'Uint8Array', type: 'Uint8Array' } as unknown as TUint8Array +} diff --git a/src/type/undefined/index.ts b/src/type/undefined/index.ts new file mode 100644 index 000000000..0b169feb1 --- /dev/null +++ b/src/type/undefined/index.ts @@ -0,0 +1,29 @@ +/*-------------------------------------------------------------------------- + +@sinclair/typebox + +The MIT License (MIT) + +Copyright (c) 2017-2023 Haydn Paterson (sinclair) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +---------------------------------------------------------------------------*/ + +export * from './undefined' diff --git a/src/type/undefined/undefined.ts b/src/type/undefined/undefined.ts new file mode 100644 index 000000000..de2f128fd --- /dev/null +++ b/src/type/undefined/undefined.ts @@ -0,0 +1,43 @@ +/*-------------------------------------------------------------------------- + +@sinclair/typebox + +The MIT License (MIT) + +Copyright (c) 2017-2023 Haydn Paterson (sinclair) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +---------------------------------------------------------------------------*/ + +import type { TSchema, SchemaOptions } from '../schema/index' +import { Symbols } from '../symbols/index' + +// ------------------------------------------------------------------ +// TUndefined +// ------------------------------------------------------------------ +export interface TUndefined extends TSchema { + [Symbols.Kind]: 'Undefined' + static: undefined + type: 'undefined' +} +/** `[JavaScript]` Creates a Undefined type */ +export function Undefined(options: SchemaOptions = {}): TUndefined { + return { ...options, [Symbols.Kind]: 'Undefined', type: 'undefined' } as unknown as TUndefined +} diff --git a/src/type/union/index.ts b/src/type/union/index.ts new file mode 100644 index 000000000..4d49fad47 --- /dev/null +++ b/src/type/union/index.ts @@ -0,0 +1,29 @@ +/*-------------------------------------------------------------------------- + +@sinclair/typebox + +The MIT License (MIT) + +Copyright (c) 2017-2023 Haydn Paterson (sinclair) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +---------------------------------------------------------------------------*/ + +export * from './union' diff --git a/src/type/union/union.ts b/src/type/union/union.ts new file mode 100644 index 000000000..d072189ba --- /dev/null +++ b/src/type/union/union.ts @@ -0,0 +1,70 @@ +/*-------------------------------------------------------------------------- + +@sinclair/typebox + +The MIT License (MIT) + +Copyright (c) 2017-2023 Haydn Paterson (sinclair) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +---------------------------------------------------------------------------*/ + +import type { TSchema, SchemaOptions } from '../schema/index' +import type { Static } from '../static/index' +import { type TNever, Never } from '../never/index' +import { OptionalFromUnion } from '../modifiers/index' +import { CloneType, CloneRest } from '../clone/type' +import { Symbols } from '../symbols/index' + +// ------------------------------------------------------------------ +// UnionResolve +// ------------------------------------------------------------------ +// prettier-ignore +export type UnionResolve = ( + T extends [] ? TNever : + T extends [TSchema] ? T[0] : + OptionalFromUnion +) +// prettier-ignore +export function UnionResolve(T: [...T]): UnionResolve { + return ( + T.length === 0 ? Never() : + T.length === 1 ? T[0] : + OptionalFromUnion(T) + ) as UnionResolve +} +// ------------------------------------------------------------------ +// TUnion +// ------------------------------------------------------------------ +// prettier-ignore +export interface TUnion extends TSchema { + [Symbols.Kind]: 'Union' + static: { [K in keyof T]: T[K] extends TSchema ? Static : never }[number] + anyOf: T +} +/** `[Json]` Creates a Union type */ +// prettier-ignore +export function Union(T: [...T], options: SchemaOptions = {}): UnionResolve { + return ( + T.length === 0 ? Never(options) : + T.length === 1 ? CloneType(T[0], options) : + { ...options, [Symbols.Kind]: 'Union', anyOf: CloneRest(T) + }) as UnionResolve +} diff --git a/src/type/unknown/index.ts b/src/type/unknown/index.ts new file mode 100644 index 000000000..06f9abe5f --- /dev/null +++ b/src/type/unknown/index.ts @@ -0,0 +1,29 @@ +/*-------------------------------------------------------------------------- + +@sinclair/typebox + +The MIT License (MIT) + +Copyright (c) 2017-2023 Haydn Paterson (sinclair) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +---------------------------------------------------------------------------*/ + +export * from './unknown' diff --git a/src/type/unknown/unknown.ts b/src/type/unknown/unknown.ts new file mode 100644 index 000000000..a7fa1bb2c --- /dev/null +++ b/src/type/unknown/unknown.ts @@ -0,0 +1,45 @@ +/*-------------------------------------------------------------------------- + +@sinclair/typebox + +The MIT License (MIT) + +Copyright (c) 2017-2023 Haydn Paterson (sinclair) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +---------------------------------------------------------------------------*/ + +import type { TSchema, SchemaOptions } from '../schema/index' +import { Symbols } from '../symbols/index' + +// ------------------------------------------------------------------ +// TUnknown +// ------------------------------------------------------------------ +export interface TUnknown extends TSchema { + [Symbols.Kind]: 'Unknown' + static: unknown +} +/** `[Json]` Creates an Unknown type */ +export function Unknown(options: SchemaOptions = {}): TUnknown { + return { + ...options, + [Symbols.Kind]: 'Unknown', + } as unknown as TUnknown +} diff --git a/src/type/unsafe/index.ts b/src/type/unsafe/index.ts new file mode 100644 index 000000000..399385ed8 --- /dev/null +++ b/src/type/unsafe/index.ts @@ -0,0 +1,29 @@ +/*-------------------------------------------------------------------------- + +@sinclair/typebox + +The MIT License (MIT) + +Copyright (c) 2017-2023 Haydn Paterson (sinclair) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +---------------------------------------------------------------------------*/ + +export * from './unsafe' diff --git a/src/type/unsafe/unsafe.ts b/src/type/unsafe/unsafe.ts new file mode 100644 index 000000000..2efc20239 --- /dev/null +++ b/src/type/unsafe/unsafe.ts @@ -0,0 +1,48 @@ +/*-------------------------------------------------------------------------- + +@sinclair/typebox + +The MIT License (MIT) + +Copyright (c) 2017-2023 Haydn Paterson (sinclair) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +---------------------------------------------------------------------------*/ + +import type { TSchema, SchemaOptions } from '../schema/index' +import { Symbols } from '../symbols/index' + +// ------------------------------------------------------------------ +// TUnknown +// ------------------------------------------------------------------ +export interface UnsafeOptions extends SchemaOptions { + [Symbols.Kind]?: string +} +export interface TUnsafe extends TSchema { + [Symbols.Kind]: string + static: T +} +/** `[Json]` Creates a Unsafe type that will infers as the generic argument T */ +export function Unsafe(options: UnsafeOptions = {}): TUnsafe { + return { + ...options, + [Symbols.Kind]: options[Symbols.Kind] ?? 'Unsafe', + } as unknown as TUnsafe +} diff --git a/src/type/void/index.ts b/src/type/void/index.ts new file mode 100644 index 000000000..7787addaa --- /dev/null +++ b/src/type/void/index.ts @@ -0,0 +1,29 @@ +/*-------------------------------------------------------------------------- + +@sinclair/typebox + +The MIT License (MIT) + +Copyright (c) 2017-2023 Haydn Paterson (sinclair) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +---------------------------------------------------------------------------*/ + +export * from './void' diff --git a/src/type/void/void.ts b/src/type/void/void.ts new file mode 100644 index 000000000..ab3e9aa46 --- /dev/null +++ b/src/type/void/void.ts @@ -0,0 +1,47 @@ +/*-------------------------------------------------------------------------- + +@sinclair/typebox + +The MIT License (MIT) + +Copyright (c) 2017-2023 Haydn Paterson (sinclair) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +---------------------------------------------------------------------------*/ + +import type { TSchema, SchemaOptions } from '../schema/index' +import { Symbols } from '../symbols/index' + +// ------------------------------------------------------------------ +// TVoid +// ------------------------------------------------------------------ +export interface TVoid extends TSchema { + [Symbols.Kind]: 'Void' + static: void + type: 'void' +} +/** `[JavaScript]` Creates a Void type */ +export function Void(options: SchemaOptions = {}): TVoid { + return { + ...options, + [Symbols.Kind]: 'Void', + type: 'void', + } as unknown as TVoid +} diff --git a/src/typebox.ts b/src/typebox.ts deleted file mode 100644 index 57e8cb27b..000000000 --- a/src/typebox.ts +++ /dev/null @@ -1,3410 +0,0 @@ -/*-------------------------------------------------------------------------- - -@sinclair/typebox - -The MIT License (MIT) - -Copyright (c) 2017-2023 Haydn Paterson (sinclair) - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. - ----------------------------------------------------------------------------*/ - -// -------------------------------------------------------------------------- -// Symbols -// -------------------------------------------------------------------------- -export const Transform = Symbol.for('TypeBox.Transform') -export const Readonly = Symbol.for('TypeBox.Readonly') -export const Optional = Symbol.for('TypeBox.Optional') -export const Hint = Symbol.for('TypeBox.Hint') -export const Kind = Symbol.for('TypeBox.Kind') -// -------------------------------------------------------------------------- -// Patterns -// -------------------------------------------------------------------------- -export const PatternBoolean = '(true|false)' -export const PatternNumber = '(0|[1-9][0-9]*)' -export const PatternString = '(.*)' -export const PatternBooleanExact = `^${PatternBoolean}$` -export const PatternNumberExact = `^${PatternNumber}$` -export const PatternStringExact = `^${PatternString}$` -// -------------------------------------------------------------------------- -// Helpers -// -------------------------------------------------------------------------- -export type TupleToIntersect = T extends [infer I] ? I : T extends [infer I, ...infer R] ? I & TupleToIntersect : never -export type TupleToUnion = { [K in keyof T]: T[K] }[number] -export type UnionToIntersect = (U extends unknown ? (arg: U) => 0 : never) extends (arg: infer I) => 0 ? I : never -export type UnionLast = UnionToIntersect 0 : never> extends (x: infer L) => 0 ? L : never -export type UnionToTuple> = [U] extends [never] ? [] : [...UnionToTuple>, L] -export type Discard = T extends [infer L, ...infer R] ? (L extends D ? Discard : [L, ...Discard]) : [] -export type Flat = T extends [] ? [] : T extends [infer L] ? [...Flat] : T extends [infer L, ...infer R] ? [...Flat, ...Flat] : [T] -export type Trim = T extends `${' '}${infer U}` ? Trim : T extends `${infer U}${' '}` ? Trim : T -export type Assert = T extends E ? T : never -export type Evaluate = T extends infer O ? { [K in keyof O]: O[K] } : never -export type Ensure = T extends infer U ? U : never -// -------------------------------------------------------------------------- -// Type Assertions -// -------------------------------------------------------------------------- -export type AssertProperties = T extends TProperties ? T : TProperties -export type AssertRest = T extends E ? T : [] -export type AssertType = T extends E ? T : TNever -// -------------------------------------------------------------------------- -// Modifiers -// -------------------------------------------------------------------------- -export type TReadonlyOptional = TOptional & TReadonly -export type TReadonly = T & { [Readonly]: 'Readonly' } -export type TOptional = T & { [Optional]: 'Optional' } -// -------------------------------------------------------------------------- -// Readonly Unwrap -// -------------------------------------------------------------------------- -// prettier-ignore -export type ReadonlyUnwrapType = - T extends TReadonly ? ReadonlyUnwrapType : - T extends TOptional ? TOptional> : - T -// prettier-ignore -export type ReadonlyUnwrapRest = T extends [infer L, ...infer R] - ? L extends TReadonly - ? [ReadonlyUnwrapType>, ...ReadonlyUnwrapRest>] - : [L, ...ReadonlyUnwrapRest>] - : [] -// -------------------------------------------------------------------------- -// Optional Unwrap -// -------------------------------------------------------------------------- -// prettier-ignore -export type OptionalUnwrapType = - T extends TReadonly ? TReadonly> : - T extends TOptional ? OptionalUnwrapType : - T -// prettier-ignore -export type OptionalUnwrapRest = T extends [infer L, ...infer R] - ? L extends TOptional - ? [OptionalUnwrapType>, ...OptionalUnwrapRest>] - : [L, ...OptionalUnwrapRest>] - : [] -// -------------------------------------------------------------------------- -// IntersectType -// -------------------------------------------------------------------------- -// prettier-ignore -export type IntersectOptional = T extends [infer L, ...infer R] - ? L extends TOptional> - ? IntersectOptional> - : false - : true -// prettier-ignore -export type IntersectResolve>> = IntersectOptional> extends true - ? TOptional>> - : TIntersect> -// prettier-ignore -export type IntersectType = - T extends [] ? TNever : - T extends [TSchema] ? AssertType : - IntersectResolve -// -------------------------------------------------------------------------- -// UnionType -// -------------------------------------------------------------------------- -// prettier-ignore -export type UnionOptional = T extends [infer L, ...infer R] - ? L extends (TOptional>) - ? true - : UnionOptional> - : false -// prettier-ignore -export type UnionResolve>> = UnionOptional> extends true - ? TOptional>> - : TUnion> -// prettier-ignore -export type UnionType = - T extends [] ? TNever : - T extends [TSchema] ? AssertType : - UnionResolve -// -------------------------------------------------------------------------- -// TSchema -// -------------------------------------------------------------------------- -export interface SchemaOptions { - $schema?: string - /** Id for this schema */ - $id?: string - /** Title of this schema */ - title?: string - /** Description of this schema */ - description?: string - /** Default value for this schema */ - default?: any - /** Example values matching this schema */ - examples?: any - /** Optional annotation for readOnly */ - readOnly?: boolean - /** Optional annotation for writeOnly */ - writeOnly?: boolean - [prop: string]: any -} -export interface TKind { - [Kind]: string -} -export interface TSchema extends SchemaOptions, TKind { - [Readonly]?: string - [Optional]?: string - [Hint]?: string - params: unknown[] - static: unknown -} -// -------------------------------------------------------------------------- -// TAnySchema -// -------------------------------------------------------------------------- -export type TAnySchema = - | TSchema - | TAny - | TArray - | TAsyncIterator - | TBigInt - | TBoolean - | TConstructor - | TDate - | TEnum - | TFunction - | TInteger - | TIntersect - | TIterator - | TLiteral - | TNot - | TNull - | TNumber - | TObject - | TPromise - | TRecord - | TRef - | TString - | TSymbol - | TTemplateLiteral - | TThis - | TTuple - | TUndefined - | TUnion - | TUint8Array - | TUnknown - | TVoid -// -------------------------------------------------------------------------- -// TNumeric -// -------------------------------------------------------------------------- -export interface NumericOptions extends SchemaOptions { - exclusiveMaximum?: N - exclusiveMinimum?: N - maximum?: N - minimum?: N - multipleOf?: N -} -// -------------------------------------------------------------------------- -// TAny -// -------------------------------------------------------------------------- -export interface TAny extends TSchema { - [Kind]: 'Any' - static: any -} -// -------------------------------------------------------------------------- -// TArray -// -------------------------------------------------------------------------- -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 extends TSchema, ArrayOptions { - [Kind]: 'Array' - static: Static[] - type: 'array' - items: T -} -// -------------------------------------------------------------------------- -// TAsyncIterator -// -------------------------------------------------------------------------- -export interface TAsyncIterator extends TSchema { - [Kind]: 'AsyncIterator' - static: AsyncIterableIterator> - type: 'AsyncIterator' - items: T -} -// ------------------------------------------------------------------------------- -// TAwaited -// ------------------------------------------------------------------------------- -// prettier-ignore -export type TAwaitedRest = T extends [infer L, ...infer R] - ? [TAwaited>, ...TAwaitedRest>] - : [] -// prettier-ignore -export type TAwaited = - T extends TIntersect ? TIntersect> : - T extends TUnion ? TUnion> : - T extends TPromise ? TAwaited : - T -// -------------------------------------------------------------------------- -// TBigInt -// -------------------------------------------------------------------------- -export interface TBigInt extends TSchema, NumericOptions { - [Kind]: 'BigInt' - static: bigint - type: 'bigint' -} -// -------------------------------------------------------------------------- -// TBoolean -// -------------------------------------------------------------------------- -export interface TBoolean extends TSchema { - [Kind]: 'Boolean' - static: boolean - type: 'boolean' -} -// -------------------------------------------------------------------------- -// TConstructorParameters -// -------------------------------------------------------------------------- -export type TConstructorParameters> = Ensure> -// -------------------------------------------------------------------------- -// TInstanceType -// -------------------------------------------------------------------------- -export type TInstanceType> = T['returns'] -// -------------------------------------------------------------------------- -// TComposite -// -------------------------------------------------------------------------- -// prettier-ignore -export type TCompositeKeys = T extends [infer L, ...infer R] - ? keyof Assert['properties'] | TCompositeKeys> - : never -// prettier-ignore -export type TCompositeIndex, K extends string[]> = K extends [infer L, ...infer R] - ? { [_ in Assert]: TIndexType> } & TCompositeIndex> - : {} -// prettier-ignore -export type TCompositeReduce = UnionToTuple> extends infer K - ? Evaluate, Assert>> - : {} // ^ indexed via intersection of T -// prettier-ignore -export type TComposite = TIntersect extends TIntersect - ? TObject> - : TObject<{}> -// -------------------------------------------------------------------------- -// TConstructor -// -------------------------------------------------------------------------- -export type TConstructorReturnTypeResolve = Static -export type TConstructorParametersResolve = T extends [infer L extends TSchema, ...infer R extends TSchema[]] ? [Static, ...TFunctionParametersResolve] : [] -export type TConstructorResolve = Ensure) => TConstructorReturnTypeResolve> -export interface TConstructor extends TSchema { - [Kind]: 'Constructor' - static: TConstructorResolve - type: 'Constructor' - parameters: T - returns: U -} -// -------------------------------------------------------------------------- -// TDate -// -------------------------------------------------------------------------- -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' -} -// -------------------------------------------------------------------------- -// TEnum -// -------------------------------------------------------------------------- -export type TEnumRecord = Record -export type TEnumValue = string | number -export type TEnumKey = string -export interface TEnum = Record> extends TSchema { - [Kind]: 'Union' - [Hint]: 'Enum' - static: T[keyof T] - anyOf: TLiteral[] -} -// -------------------------------------------------------------------------- -// TExtends -// -------------------------------------------------------------------------- -// prettier-ignore -export type TExtends = - (Static extends Static ? T : U) extends infer O ? - UnionToTuple extends [infer X, infer Y] ? TUnion<[AssertType, AssertType]> : AssertType - : never -// -------------------------------------------------------------------------- -// TExclude -// -------------------------------------------------------------------------- -export type TExcludeTemplateLiteralResult = UnionType }[T]>>> -export type TExcludeTemplateLiteral = Exclude, Static> extends infer S ? TExcludeTemplateLiteralResult> : never -// prettier-ignore -export type TExcludeArray = AssertRest> extends Static ? never : T[K] -}[number]>> extends infer R ? UnionType> : never -// prettier-ignore -export type TExclude = - T extends TTemplateLiteral ? TExcludeTemplateLiteral : - T extends TUnion ? TExcludeArray : - T extends U ? TNever : T -// -------------------------------------------------------------------------- -// TExtract -// -------------------------------------------------------------------------- -export type TExtractTemplateLiteralResult = UnionType }[T]>>> -export type TExtractTemplateLiteral = Extract, Static> extends infer S ? TExtractTemplateLiteralResult> : never -// prettier-ignore -export type TExtractArray = AssertRest> extends Static ? T[K] : never -}[number]>> extends infer R ? UnionType> : never -// prettier-ignore -export type TExtract = - T extends TTemplateLiteral ? TExtractTemplateLiteral : - T extends TUnion ? TExtractArray : - T extends U ? T : T -// -------------------------------------------------------------------------- -// TFunction -// -------------------------------------------------------------------------- -export type TFunctionReturnTypeResolve = Static -export type TFunctionParametersResolve = T extends [infer L extends TSchema, ...infer R extends TSchema[]] ? [Static, ...TFunctionParametersResolve] : [] -export type TFunctionResolve = Ensure<(...param: TFunctionParametersResolve) => TFunctionReturnTypeResolve> -export interface TFunction extends TSchema { - [Kind]: 'Function' - static: TFunctionResolve - type: 'Function' - parameters: T - returns: U -} -// -------------------------------------------------------------------------- -// TIndex -// -------------------------------------------------------------------------- -export type TIndexRest = T extends [infer L, ...infer R] ? [TIndexType, K>, ...TIndexRest, K>] : [] -export type TIndexProperty = K extends keyof T ? [T[K]] : [] -export type TIndexTuple = K extends keyof T ? [T[K]] : [] -// prettier-ignore -export type TIndexType = - T extends TRecursive ? TIndexType : - T extends TIntersect ? IntersectType>, TNever>>> : - T extends TUnion ? UnionType>>> : - T extends TObject ? UnionType>>> : - T extends TTuple ? UnionType>>> : - [] -// prettier-ignore -export type TIndexRestMany = - K extends [infer L, ...infer R] ? [TIndexType>, ...TIndexRestMany>] : - [] -// prettier-ignore -export type TIndex = - T extends TRecursive ? TIndex : - T extends TIntersect ? UnionType>> : - T extends TUnion ? UnionType>> : - T extends TObject ? UnionType>> : - T extends TTuple ? UnionType>> : - TNever -// -------------------------------------------------------------------------- -// TIntrinsic -// -------------------------------------------------------------------------- -export type TIntrinsicMode = 'Uppercase' | 'Lowercase' | 'Capitalize' | 'Uncapitalize' -// prettier-ignore -export type TIntrinsicTemplateLiteral = - M extends ('Lowercase' | 'Uppercase') ? T extends [infer L, ...infer R] ? [TIntrinsic, M>, ...TIntrinsicTemplateLiteral, M>] : T : - M extends ('Capitalize' | 'Uncapitalize') ? T extends [infer L, ...infer R] ? [TIntrinsic, M>, ...R] : T : - T -// prettier-ignore -export type TIntrinsicLiteral = - T extends string ? - M extends 'Uncapitalize' ? Uncapitalize : - M extends 'Capitalize' ? Capitalize : - M extends 'Uppercase' ? Uppercase : - M extends 'Lowercase' ? Lowercase : - string - : T -// prettier-ignore -export type TIntrinsicRest = T extends [infer L, ...infer R] - ? [TIntrinsic, M>, ...TIntrinsicRest, M>] - : [] -// prettier-ignore -export type TIntrinsic = - T extends TTemplateLiteral ? TTemplateLiteral> : - T extends TUnion ? TUnion> : - T extends TLiteral ? TLiteral> : - T -// -------------------------------------------------------------------------- -// TInteger -// -------------------------------------------------------------------------- -export interface TInteger extends TSchema, NumericOptions { - [Kind]: 'Integer' - static: number - type: 'integer' -} -// -------------------------------------------------------------------------- -// TIntersect -// -------------------------------------------------------------------------- -export type TUnevaluatedProperties = undefined | TSchema | boolean -export interface IntersectOptions extends SchemaOptions { - unevaluatedProperties?: TUnevaluatedProperties -} -export interface TIntersect extends TSchema, IntersectOptions { - [Kind]: 'Intersect' - static: TupleToIntersect<{ [K in keyof T]: Static, this['params']> }> - type?: 'object' - allOf: [...T] -} -// -------------------------------------------------------------------------- -// TIterator -// -------------------------------------------------------------------------- -export interface TIterator extends TSchema { - [Kind]: 'Iterator' - static: IterableIterator> - type: 'Iterator' - items: T -} -// -------------------------------------------------------------------------- -// TKeyOf -// -------------------------------------------------------------------------- -// prettier-ignore -export type TKeyOfProperties = Discard extends infer S - ? UnionToTuple<{[K in keyof S]: TLiteral>}[keyof S]> - : [], undefined> // note: optional properties produce undefined types in tuple result. discard. -// prettier-ignore -export type TKeyOfIndicesArray = UnionToTuple -// prettier-ignore -export type TKeyOfIndices = AssertRest extends infer R ? { - [K in keyof R] : TLiteral> -}: []> -// prettier-ignore -export type TKeyOf = ( - T extends TRecursive ? TKeyOfProperties : - T extends TIntersect ? TKeyOfProperties : - T extends TUnion ? TKeyOfProperties : - T extends TObject ? TKeyOfProperties : - T extends TTuple ? TKeyOfIndices : - T extends TArray ? [TNumber] : - T extends TRecord ? [K] : - [] -) extends infer R ? UnionType> : never -// -------------------------------------------------------------------------- -// TLiteral -// -------------------------------------------------------------------------- -export type TLiteralValue = boolean | number | string // | bigint - supported but variant disable due to potential numeric type conflicts -export type TLiteralBoolean = TLiteral -export type TLiteralNumber = TLiteral -export type TLiteralString = TLiteral -export interface TLiteral extends TSchema { - [Kind]: 'Literal' - static: T - const: T -} -// -------------------------------------------------------------------------- -// TNever -// -------------------------------------------------------------------------- -export interface TNever extends TSchema { - [Kind]: 'Never' - static: never - not: {} -} -// -------------------------------------------------------------------------- -// TNot -// -------------------------------------------------------------------------- -export interface TNot extends TSchema { - [Kind]: 'Not' - static: T extends TNot ? Static : unknown - not: T -} -// -------------------------------------------------------------------------- -// TNull -// -------------------------------------------------------------------------- -export interface TNull extends TSchema { - [Kind]: 'Null' - static: null - type: 'null' -} -// -------------------------------------------------------------------------- -// TNumber -// -------------------------------------------------------------------------- -export interface TNumber extends TSchema, NumericOptions { - [Kind]: 'Number' - static: number - type: 'number' -} -// -------------------------------------------------------------------------- -// TObject -// -------------------------------------------------------------------------- -export type ReadonlyOptionalPropertyKeys = { [K in keyof T]: T[K] extends TReadonly ? (T[K] extends TOptional ? K : never) : never }[keyof T] -export type ReadonlyPropertyKeys = { [K in keyof T]: T[K] extends TReadonly ? (T[K] extends TOptional ? never : K) : never }[keyof T] -export type OptionalPropertyKeys = { [K in keyof T]: T[K] extends TOptional ? (T[K] extends TReadonly ? never : K) : never }[keyof T] -export type RequiredPropertyKeys = keyof Omit | ReadonlyPropertyKeys | OptionalPropertyKeys> -// prettier-ignore -export type PropertiesReducer> = Evaluate<( - Readonly>>> & - Readonly>> & - Partial>> & - Required>> -)> -// prettier-ignore -export type PropertiesReduce = PropertiesReducer -}> -export type TPropertyKey = string | number -export type TProperties = Record -export type ObjectProperties = T extends TObject ? U : never -export type ObjectPropertyKeys = T extends TObject ? keyof U : never -export type TAdditionalProperties = undefined | TSchema | boolean -export interface ObjectOptions extends SchemaOptions { - /** Additional property constraints for this object */ - additionalProperties?: TAdditionalProperties - /** The minimum number of properties allowed on this object */ - minProperties?: number - /** The maximum number of properties allowed on this object */ - maxProperties?: number -} -export interface TObject extends TSchema, ObjectOptions { - [Kind]: 'Object' - static: PropertiesReduce - additionalProperties?: TAdditionalProperties - type: 'object' - properties: T - required?: string[] -} -// -------------------------------------------------------------------------- -// TOmit -// -------------------------------------------------------------------------- -export type TOmitProperties = Evaluate>> -export type TOmitRest = AssertRest<{ [K2 in keyof T]: TOmit, K> }> -// prettier-ignore -export type TOmit = - T extends TRecursive ? TRecursive> : - T extends TIntersect ? TIntersect> : - T extends TUnion ? TUnion> : - T extends TObject ? TObject> : - T -// -------------------------------------------------------------------------- -// TParameters -// -------------------------------------------------------------------------- -export type TParameters = Ensure> -// -------------------------------------------------------------------------- -// TPartial -// -------------------------------------------------------------------------- -export type TPartialObjectArray = AssertRest<{ [K in keyof T]: TPartial> }, TObject[]> -export type TPartialRest = AssertRest<{ [K in keyof T]: TPartial> }> -// prettier-ignore -export type TPartialProperties = Evaluate) ? TReadonlyOptional : - T[K] extends (TReadonly) ? TReadonlyOptional : - T[K] extends (TOptional) ? TOptional : - TOptional -}>> -// prettier-ignore -export type TPartial = - T extends TRecursive ? TRecursive> : - T extends TIntersect ? TIntersect> : - T extends TUnion ? TUnion> : - T extends TObject ? TObject> : - T -// -------------------------------------------------------------------------- -// TPick -// -------------------------------------------------------------------------- -// Note the key K will overlap for varying TProperties gathered via recursive union and intersect traversal. Because of this, -// we need to extract only keys assignable to T on K2. This behavior is only required for Pick only. -// prettier-ignore -export type TPickProperties = - Pick, keyof T>> extends infer R ? ({ - [K in keyof R]: AssertType extends TSchema ? R[K] : never - }): never -export type TPickRest = { [K2 in keyof T]: TPick, K> } -// prettier-ignore -export type TPick = - T extends TRecursive ? TRecursive> : - T extends TIntersect ? TIntersect> : - T extends TUnion ? TUnion> : - T extends TObject ? TObject> : - T -// -------------------------------------------------------------------------- -// TPromise -// -------------------------------------------------------------------------- -export interface TPromise extends TSchema { - [Kind]: 'Promise' - static: Promise> - type: 'Promise' - item: TSchema -} -// -------------------------------------------------------------------------- -// TRecord -// -------------------------------------------------------------------------- -export type TRecordFromUnionLiteralString = { [_ in K['const']]: T } -export type TRecordFromUnionLiteralNumber = { [_ in K['const']]: T } -// prettier-ignore -export type TRecordFromEnumKey, T extends TSchema> = Ensure> -// prettier-ignore -export type TRecordFromUnionRest = K extends [infer L, ...infer R] ? ( - L extends TUnion ? TRecordFromUnionRest & TRecordFromUnionRest, T> : - L extends TLiteralString ? TRecordFromUnionLiteralString & TRecordFromUnionRest, T> : - L extends TLiteralNumber ? TRecordFromUnionLiteralNumber & TRecordFromUnionRest, T> : -{}) : {} -export type TRecordFromUnion = Ensure>>>> -export type TRecordFromTemplateLiteralKeyInfinite = Ensure> -export type TRecordFromTemplateLiteralKeyFinite> = Ensure]: T }>>> -// prettier-ignore -export type TRecordFromTemplateLiteralKey = IsTemplateLiteralFinite extends false - ? TRecordFromTemplateLiteralKeyInfinite - : TRecordFromTemplateLiteralKeyFinite -export type TRecordFromLiteralStringKey = Ensure> -export type TRecordFromLiteralNumberKey = Ensure> -export type TRecordFromStringKey = Ensure> -export type TRecordFromNumberKey = Ensure> -export type TRecordFromIntegerKey = Ensure> -// prettier-ignore -export type TRecordResolve = - K extends TEnum ? TRecordFromEnumKey : // Enum before Union (intercept Hint) - K extends TUnion ? TRecordFromUnion : - K extends TTemplateLiteral ? TRecordFromTemplateLiteralKey : - K extends TLiteralString ? TRecordFromLiteralStringKey : - K extends TLiteralNumber ? TRecordFromLiteralNumberKey : - K extends TString ? TRecordFromStringKey : - K extends TNumber ? TRecordFromNumberKey : - K extends TInteger ? TRecordFromIntegerKey : - TNever -export interface TRecord extends TSchema { - [Kind]: 'Record' - static: Record, string | number>, Static> - type: 'object' - patternProperties: { [pattern: string]: T } - additionalProperties: TAdditionalProperties -} -// -------------------------------------------------------------------------- -// TRecursive -// -------------------------------------------------------------------------- -export interface TThis extends TSchema { - [Kind]: 'This' - static: this['params'][0] - $ref: string -} -export type TRecursiveReduce = Static]> -export interface TRecursive extends TSchema { - [Hint]: 'Recursive' - static: TRecursiveReduce -} -// -------------------------------------------------------------------------- -// TRef -// -------------------------------------------------------------------------- -export interface TRef extends TSchema { - [Kind]: 'Ref' - static: Static - $ref: string -} -// -------------------------------------------------------------------------- -// TRest -// -------------------------------------------------------------------------- -export type TRest = T extends TIntersect ? R : T extends TUnion ? R : T extends TTuple ? R : [] -// -------------------------------------------------------------------------- -// TReturnType -// -------------------------------------------------------------------------- -export type TReturnType = T['returns'] -// -------------------------------------------------------------------------- -// TRequired -// -------------------------------------------------------------------------- -export type TRequiredRest = AssertRest<{ [K in keyof T]: TRequired> }> -// prettier-ignore -export type TRequiredProperties = Evaluate) ? TReadonly : - T[K] extends (TReadonly) ? TReadonly : - T[K] extends (TOptional) ? S : - T[K] -}>> -// prettier-ignore -export type TRequired = - T extends TRecursive ? TRecursive> : - T extends TIntersect ? TIntersect> : - T extends TUnion ? TUnion> : - T extends TObject ? TObject> : - T -// -------------------------------------------------------------------------- -// TString -// -------------------------------------------------------------------------- -export type StringFormatOption = - | 'date-time' - | 'time' - | 'date' - | 'email' - | 'idn-email' - | 'hostname' - | 'idn-hostname' - | 'ipv4' - | 'ipv6' - | 'uri' - | 'uri-reference' - | 'iri' - | 'uuid' - | 'iri-reference' - | 'uri-template' - | 'json-pointer' - | 'relative-json-pointer' - | 'regex' - | ({} & string) -// prettier-ignore -export type StringContentEncodingOption = - | '7bit' - | '8bit' - | 'binary' - | 'quoted-printable' - | 'base64' - | ({} & string) -export interface StringOptions extends SchemaOptions { - /** The maximum string length */ - maxLength?: number - /** The minimum string length */ - minLength?: number - /** A regular expression pattern this string should match */ - pattern?: string - /** A format this string should match */ - format?: StringFormatOption - /** The content encoding for this string */ - contentEncoding?: StringContentEncodingOption - /** The content media type for this string */ - contentMediaType?: string -} -export interface TString extends TSchema, StringOptions { - [Kind]: 'String' - static: string - type: 'string' -} -// -------------------------------------------------------------------------- -// TSymbol -// -------------------------------------------------------------------------- -export type SymbolValue = string | number | undefined -export interface TSymbol extends TSchema, SchemaOptions { - [Kind]: 'Symbol' - static: symbol - type: 'symbol' -} -// ------------------------------------------------------------------------- -// TTemplateLiteralParserDsl -// ------------------------------------------------------------------------- -// prettier-ignore -export type TTemplateLiteralDslParserUnionLiteral = - T extends `${infer L}|${infer R}` ? [TLiteral>, ...TTemplateLiteralDslParserUnionLiteral] : - T extends `${infer L}` ? [TLiteral>] : - [] -export type TTemplateLiteralDslParserUnion = UnionType> -// prettier-ignore -export type TTemplateLiteralDslParserTerminal = - T extends 'boolean' ? TBoolean : - T extends 'bigint' ? TBigInt : - T extends 'number' ? TNumber : - T extends 'string' ? TString : - TTemplateLiteralDslParserUnion -// prettier-ignore -export type TTemplateLiteralDslParserTemplate = - T extends `{${infer L}}${infer R}` ? [TTemplateLiteralDslParserTerminal, ...TTemplateLiteralDslParserTemplate] : - T extends `${infer L}$${infer R}` ? [TLiteral, ...TTemplateLiteralDslParserTemplate] : - T extends `${infer L}` ? [TLiteral] : - [] -export type TTemplateLiteralDslParser = Ensure, TTemplateLiteralKind[]>>> -// -------------------------------------------------------------------------- -// TTemplateLiteral -// -------------------------------------------------------------------------- -// prettier-ignore -export type IsTemplateLiteralFiniteCheck = - T extends TTemplateLiteral ? IsTemplateLiteralFiniteArray> : - T extends TUnion ? IsTemplateLiteralFiniteArray> : - T extends TString ? false : - T extends TBoolean ? false : - T extends TNumber ? false : - T extends TInteger ? false : - T extends TBigInt ? false : - T extends TLiteral ? true : - false -// prettier-ignore -export type IsTemplateLiteralFiniteArray = - T extends [infer L, ...infer R] ? IsTemplateLiteralFiniteCheck extends false ? false : IsTemplateLiteralFiniteArray> : - true -export type IsTemplateLiteralFinite = T extends TTemplateLiteral ? IsTemplateLiteralFiniteArray : false -export type TTemplateLiteralKind = TUnion | TLiteral | TInteger | TTemplateLiteral | TNumber | TBigInt | TString | TBoolean | TNever -// prettier-ignore -export type TTemplateLiteralConst = - T extends TUnion ? { [K in keyof U]: TTemplateLiteralUnion, Acc> }[number] : - T extends TTemplateLiteral ? `${Static}` : - T extends TLiteral ? `${U}` : - T extends TString ? `${string}` : - T extends TNumber ? `${number}` : - T extends TBigInt ? `${bigint}` : - T extends TBoolean ? `${boolean}` : - never -// prettier-ignore -export type TTemplateLiteralUnion = - T extends [infer L, ...infer R] ? `${TTemplateLiteralConst}${TTemplateLiteralUnion, Acc>}` : - Acc -export type TTemplateLiteralKeyRest = Assert>, TPropertyKey[]> -export interface TTemplateLiteral extends TSchema { - [Kind]: 'TemplateLiteral' - static: TTemplateLiteralUnion - type: 'string' - pattern: string // todo: it may be possible to infer this pattern -} -// -------------------------------------------------------------------------- -// TTransform -// -------------------------------------------------------------------------- -// prettier-ignore -export type DecodeProperties = { - [K in keyof T]: DecodeType -} -// prettier-ignore -export type DecodeRest = T extends [infer L extends TSchema, ...infer R extends TSchema[]] - ? [DecodeType, ...DecodeRest] - : [] -// prettier-ignore -export type DecodeType = ( - T extends TOptional ? TOptional> : - T extends TReadonly ? TReadonly> : - T extends TTransform ? TUnsafe : - T extends TArray ? TArray> : - T extends TAsyncIterator ? TAsyncIterator> : - T extends TConstructor ? TConstructor, DecodeType> : - T extends TEnum ? TEnum : // intercept for union. interior non decodable - T extends TFunction ? TFunction, DecodeType> : - T extends TIntersect ? TIntersect> : - T extends TIterator ? TIterator> : - T extends TNot ? TNot> : - T extends TObject ? TObject>> : - T extends TPromise ? TPromise> : - T extends TRecord ? TRecord> : - T extends TRecursive ? TRecursive> : - T extends TRef ? TRef> : - T extends TTuple ? TTuple> : - T extends TUnion ? TUnion> : - T -) -export type TransformFunction = (value: T) => U -export interface TransformOptions { - Decode: TransformFunction, O> - Encode: TransformFunction> -} -export type TTransformResolve = T extends TTransform ? S : Static -export interface TTransform extends TSchema { - static: TTransformResolve - [Transform]: TransformOptions - [key: string]: any -} -// -------------------------------------------------------------------------- -// TTuple -// -------------------------------------------------------------------------- -export type TTupleRest = T extends [infer L, ...infer R] ? [Static, P>, ...TTupleRest, P>] : [] -export interface TTuple extends TSchema { - [Kind]: 'Tuple' - static: TTupleRest - type: 'array' - items?: T - additionalItems?: false - minItems: number - maxItems: number -} -// -------------------------------------------------------------------------- -// TUndefined -// -------------------------------------------------------------------------- -export interface TUndefined extends TSchema { - [Kind]: 'Undefined' - static: undefined - type: 'undefined' -} -// -------------------------------------------------------------------------- -// TUnionLiteral -// -------------------------------------------------------------------------- -// prettier-ignore -export type TLiteralUnionReduce[]> = - T extends [infer L, ...infer R] ? [Assert>['const'], ...TLiteralUnionReduce[]>>] : - [] -// prettier-ignore -export type TUnionLiteralKeyRest[]>> = - T extends TUnion ? TLiteralUnionReduce[]>> : - [] -// -------------------------------------------------------------------------- -// TUnion -// -------------------------------------------------------------------------- -// prettier-ignore -export type TUnionTemplateLiteral> = Ensure}[S]>,TLiteral[]>>> -export interface TUnion extends TSchema { - [Kind]: 'Union' - static: { [K in keyof T]: T[K] extends TSchema ? Static : never }[number] - anyOf: T -} -// -------------------------------------------------------------------------- -// TUint8Array -// -------------------------------------------------------------------------- -export interface Uint8ArrayOptions extends SchemaOptions { - maxByteLength?: number - minByteLength?: number -} -export interface TUint8Array extends TSchema, Uint8ArrayOptions { - [Kind]: 'Uint8Array' - static: Uint8Array - type: 'uint8array' -} -// -------------------------------------------------------------------------- -// TUnknown -// -------------------------------------------------------------------------- -export interface TUnknown extends TSchema { - [Kind]: 'Unknown' - static: unknown -} -// -------------------------------------------------------------------------- -// TUnsafe -// -------------------------------------------------------------------------- -export interface UnsafeOptions extends SchemaOptions { - [Kind]?: string -} -export interface TUnsafe extends TSchema { - [Kind]: string - static: T -} -// -------------------------------------------------------------------------- -// TVoid -// -------------------------------------------------------------------------- -export interface TVoid extends TSchema { - [Kind]: 'Void' - static: void - type: 'void' -} -// -------------------------------------------------------------------------- -// Static -// -------------------------------------------------------------------------- -/** Creates an decoded static type from a TypeBox type */ -export type StaticDecode = Static, P> -/** Creates an encoded static type from a TypeBox type */ -export type StaticEncode = Static -/** Creates a static type from a TypeBox type */ -export type Static = (T & { params: P })['static'] -// -------------------------------------------------------------------------- -// TypeRegistry -// -------------------------------------------------------------------------- -export type TypeRegistryValidationFunction = (schema: TSchema, value: unknown) => boolean -/** A registry for user defined types */ -export namespace TypeRegistry { - const map = new Map>() - /** Returns the entries in this registry */ - export function Entries() { - return new Map(map) - } - /** Clears all user defined types */ - export function Clear() { - return map.clear() - } - /** Deletes a registered type */ - export function Delete(kind: string) { - return map.delete(kind) - } - /** Returns true if this registry contains this kind */ - export function Has(kind: string) { - return map.has(kind) - } - /** Sets a validation function for a user defined type */ - export function Set(kind: string, func: TypeRegistryValidationFunction) { - map.set(kind, func) - } - /** Gets a custom validation function for a user defined type */ - export function Get(kind: string) { - return map.get(kind) - } -} -// -------------------------------------------------------------------------- -// TypeBoxError -// -------------------------------------------------------------------------- -export class TypeBoxError extends Error { - constructor(message: string) { - super(message) - } -} -// -------------------------------------------------------------------------- -// TypeRegistry -// -------------------------------------------------------------------------- -export type FormatRegistryValidationFunction = (value: string) => boolean -/** A registry for user defined string formats */ -export namespace FormatRegistry { - const map = new Map() - /** Returns the entries in this registry */ - export function Entries() { - return new Map(map) - } - /** Clears all user defined string formats */ - export function Clear() { - return map.clear() - } - /** Deletes a registered format */ - export function Delete(format: string) { - return map.delete(format) - } - /** Returns true if the user defined string format exists */ - export function Has(format: string) { - return map.has(format) - } - /** Sets a validation function for a user defined string format */ - export function Set(format: string, func: FormatRegistryValidationFunction) { - map.set(format, func) - } - /** Gets a validation function for a user defined string format */ - export function Get(format: string) { - return map.get(format) - } -} -// -------------------------------------------------------------------------- -// ValueGuard -// -------------------------------------------------------------------------- -/** Provides functions to type guard raw JavaScript values */ -export namespace ValueGuard { - /** 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 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 { - return typeof value === 'object' && value !== null - } - /** 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 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 - } -} -// -------------------------------------------------------------------------- -// TypeGuard -// -------------------------------------------------------------------------- -export class TypeGuardUnknownTypeError extends TypeBoxError {} -/** Provides functions to test if JavaScript values are TypeBox types */ -export namespace TypeGuard { - 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) || TSchema(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) || TSchema(value) - } - // ---------------------------------------------------------------- - // Types - // ---------------------------------------------------------------- - /** Returns true if the given value is TAny */ - export function TAny(schema: unknown): schema is TAny { - // prettier-ignore - return ( - TKindOf(schema, 'Any') && - IsOptionalString(schema.$id) - ) - } - /** Returns true if the given value is TArray */ - export function TArray(schema: unknown): schema is TArray { - return ( - TKindOf(schema, 'Array') && - schema.type === 'array' && - IsOptionalString(schema.$id) && - TSchema(schema.items) && - IsOptionalNumber(schema.minItems) && - IsOptionalNumber(schema.maxItems) && - IsOptionalBoolean(schema.uniqueItems) && - IsOptionalSchema(schema.contains) && - IsOptionalNumber(schema.minContains) && - IsOptionalNumber(schema.maxContains) - ) - } - /** Returns true if the given value is TAsyncIterator */ - export function TAsyncIterator(schema: unknown): schema is TAsyncIterator { - // prettier-ignore - return ( - TKindOf(schema, 'AsyncIterator') && - schema.type === 'AsyncIterator' && - IsOptionalString(schema.$id) && - TSchema(schema.items) - ) - } - /** Returns true if the given value is TBigInt */ - export function TBigInt(schema: unknown): schema is TBigInt { - // prettier-ignore - return ( - TKindOf(schema, 'BigInt') && - schema.type === 'bigint' && - IsOptionalString(schema.$id) && - IsOptionalBigInt(schema.exclusiveMaximum) && - IsOptionalBigInt(schema.exclusiveMinimum) && - IsOptionalBigInt(schema.maximum) && - IsOptionalBigInt(schema.minimum) && - IsOptionalBigInt(schema.multipleOf) - ) - } - /** Returns true if the given value is TBoolean */ - export function TBoolean(schema: unknown): schema is TBoolean { - // prettier-ignore - return ( - TKindOf(schema, 'Boolean') && - schema.type === 'boolean' && - IsOptionalString(schema.$id) - ) - } - /** Returns true if the given value is TConstructor */ - export function TConstructor(schema: unknown): schema is TConstructor { - // prettier-ignore - return ( - TKindOf(schema, 'Constructor') && - schema.type === 'Constructor' && - IsOptionalString(schema.$id) && - ValueGuard.IsArray(schema.parameters) && - schema.parameters.every(schema => TSchema(schema)) && - TSchema(schema.returns) - ) - } - /** Returns true if the given value is TDate */ - export function TDate(schema: unknown): schema is TDate { - return ( - TKindOf(schema, 'Date') && - schema.type === 'Date' && - IsOptionalString(schema.$id) && - IsOptionalNumber(schema.exclusiveMaximumTimestamp) && - IsOptionalNumber(schema.exclusiveMinimumTimestamp) && - IsOptionalNumber(schema.maximumTimestamp) && - IsOptionalNumber(schema.minimumTimestamp) && - IsOptionalNumber(schema.multipleOfTimestamp) - ) - } - /** Returns true if the given value is TFunction */ - export function TFunction(schema: unknown): schema is TFunction { - // prettier-ignore - return ( - TKindOf(schema, 'Function') && - schema.type === 'Function' && - IsOptionalString(schema.$id) && - ValueGuard.IsArray(schema.parameters) && - schema.parameters.every(schema => TSchema(schema)) && - TSchema(schema.returns) - ) - } - /** Returns true if the given value is TInteger */ - export function TInteger(schema: unknown): schema is TInteger { - return ( - TKindOf(schema, 'Integer') && - schema.type === 'integer' && - IsOptionalString(schema.$id) && - IsOptionalNumber(schema.exclusiveMaximum) && - IsOptionalNumber(schema.exclusiveMinimum) && - IsOptionalNumber(schema.maximum) && - IsOptionalNumber(schema.minimum) && - IsOptionalNumber(schema.multipleOf) - ) - } - /** Returns true if the given value is TIntersect */ - export function TIntersect(schema: unknown): schema is TIntersect { - // prettier-ignore - return ( - TKindOf(schema, 'Intersect') && - (ValueGuard.IsString(schema.type) && schema.type !== 'object' ? false : true) && - ValueGuard.IsArray(schema.allOf) && - schema.allOf.every(schema => TSchema(schema) && !TTransform(schema)) && - IsOptionalString(schema.type) && - (IsOptionalBoolean(schema.unevaluatedProperties) || IsOptionalSchema(schema.unevaluatedProperties)) && - IsOptionalString(schema.$id) - ) - } - /** Returns true if the given value is TIterator */ - export function TIterator(schema: unknown): schema is TIterator { - // prettier-ignore - return ( - TKindOf(schema, 'Iterator') && - schema.type === 'Iterator' && - IsOptionalString(schema.$id) && - TSchema(schema.items) - ) - } - /** Returns true if the given value is a TKind with the given name. */ - export function TKindOf(schema: unknown, kind: T): schema is Record & { [Kind]: T } { - return TKind(schema) && schema[Kind] === kind - } - /** Returns true if the given value is TKind */ - export function TKind(schema: unknown): schema is Record & { [Kind]: string } { - return ValueGuard.IsObject(schema) && Kind in schema && ValueGuard.IsString(schema[Kind]) - } - /** Returns true if the given value is TLiteral */ - export function TLiteralString(schema: unknown): schema is TLiteral { - return TLiteral(schema) && ValueGuard.IsString(schema.const) - } - /** Returns true if the given value is TLiteral */ - export function TLiteralNumber(schema: unknown): schema is TLiteral { - return TLiteral(schema) && ValueGuard.IsNumber(schema.const) - } - /** Returns true if the given value is TLiteral */ - export function TLiteralBoolean(schema: unknown): schema is TLiteral { - return TLiteral(schema) && ValueGuard.IsBoolean(schema.const) - } - /** Returns true if the given value is TLiteral */ - export function TLiteral(schema: unknown): schema is TLiteral { - // prettier-ignore - return ( - TKindOf(schema, 'Literal') && - IsOptionalString(schema.$id) && ( - ValueGuard.IsBoolean(schema.const) || - ValueGuard.IsNumber(schema.const) || - ValueGuard.IsString(schema.const) - ) - ) - } - /** Returns true if the given value is TNever */ - export function TNever(schema: unknown): schema is TNever { - // prettier-ignore - return ( - TKindOf(schema, 'Never') && - ValueGuard.IsObject(schema.not) && - Object.getOwnPropertyNames(schema.not).length === 0 - ) - } - /** Returns true if the given value is TNot */ - export function TNot(schema: unknown): schema is TNot { - // prettier-ignore - return ( - TKindOf(schema, 'Not') && - TSchema(schema.not) - ) - } - /** Returns true if the given value is TNull */ - export function TNull(schema: unknown): schema is TNull { - // prettier-ignore - return ( - TKindOf(schema, 'Null') && - schema.type === 'null' && - IsOptionalString(schema.$id) - ) - } - /** Returns true if the given value is TNumber */ - export function TNumber(schema: unknown): schema is TNumber { - return ( - TKindOf(schema, 'Number') && - schema.type === 'number' && - IsOptionalString(schema.$id) && - IsOptionalNumber(schema.exclusiveMaximum) && - IsOptionalNumber(schema.exclusiveMinimum) && - IsOptionalNumber(schema.maximum) && - IsOptionalNumber(schema.minimum) && - IsOptionalNumber(schema.multipleOf) - ) - } - /** Returns true if the given value is TObject */ - export function TObject(schema: unknown): schema is TObject { - // prettier-ignore - return ( - TKindOf(schema, 'Object') && - schema.type === 'object' && - IsOptionalString(schema.$id) && - ValueGuard.IsObject(schema.properties) && - IsAdditionalProperties(schema.additionalProperties) && - IsOptionalNumber(schema.minProperties) && - IsOptionalNumber(schema.maxProperties) && - Object.entries(schema.properties).every(([key, schema]) => IsControlCharacterFree(key) && TSchema(schema)) - ) - } - /** Returns true if the given value is TPromise */ - export function TPromise(schema: unknown): schema is TPromise { - // prettier-ignore - return ( - TKindOf(schema, 'Promise') && - schema.type === 'Promise' && - IsOptionalString(schema.$id) && - TSchema(schema.item) - ) - } - /** Returns true if the given value is TRecord */ - export function TRecord(schema: unknown): schema is TRecord { - // prettier-ignore - return ( - TKindOf(schema, 'Record') && - schema.type === 'object' && - IsOptionalString(schema.$id) && - IsAdditionalProperties(schema.additionalProperties) && - ValueGuard.IsObject(schema.patternProperties) && - ((schema: Record) => { - const keys = Object.getOwnPropertyNames(schema.patternProperties) - return ( - keys.length === 1 && - IsPattern(keys[0]) && - ValueGuard.IsObject(schema.patternProperties) && - TSchema(schema.patternProperties[keys[0]]) - ) - })(schema) - ) - } - /** Returns true if this value is TRecursive */ - export function TRecursive(schema: unknown): schema is { [Hint]: 'Recursive' } { - return ValueGuard.IsObject(schema) && Hint in schema && schema[Hint] === 'Recursive' - } - /** Returns true if the given value is TRef */ - export function TRef(schema: unknown): schema is TRef { - // prettier-ignore - return ( - TKindOf(schema, 'Ref') && - IsOptionalString(schema.$id) && - ValueGuard.IsString(schema.$ref) - ) - } - /** Returns true if the given value is TString */ - export function TString(schema: unknown): schema is TString { - // prettier-ignore - return ( - TKindOf(schema, 'String') && - schema.type === 'string' && - IsOptionalString(schema.$id) && - IsOptionalNumber(schema.minLength) && - IsOptionalNumber(schema.maxLength) && - IsOptionalPattern(schema.pattern) && - IsOptionalFormat(schema.format) - ) - } - /** Returns true if the given value is TSymbol */ - export function TSymbol(schema: unknown): schema is TSymbol { - // prettier-ignore - return ( - TKindOf(schema, 'Symbol') && - schema.type === 'symbol' && - IsOptionalString(schema.$id) - ) - } - /** Returns true if the given value is TTemplateLiteral */ - export function TTemplateLiteral(schema: unknown): schema is TTemplateLiteral { - // prettier-ignore - return ( - TKindOf(schema, 'TemplateLiteral') && - schema.type === 'string' && - ValueGuard.IsString(schema.pattern) && - schema.pattern[0] === '^' && - schema.pattern[schema.pattern.length - 1] === '$' - ) - } - /** Returns true if the given value is TThis */ - export function TThis(schema: unknown): schema is TThis { - // prettier-ignore - return ( - TKindOf(schema, 'This') && - IsOptionalString(schema.$id) && - ValueGuard.IsString(schema.$ref) - ) - } - /** Returns true of this value is TTransform */ - export function TTransform(schema: unknown): schema is { [Transform]: TransformOptions } { - return ValueGuard.IsObject(schema) && Transform in schema - } - /** Returns true if the given value is TTuple */ - export function TTuple(schema: unknown): schema is TTuple { - // prettier-ignore - return ( - TKindOf(schema, 'Tuple') && - schema.type === 'array' && - IsOptionalString(schema.$id) && - ValueGuard.IsNumber(schema.minItems) && - ValueGuard.IsNumber(schema.maxItems) && - schema.minItems === schema.maxItems && - (( // empty - ValueGuard.IsUndefined(schema.items) && - ValueGuard.IsUndefined(schema.additionalItems) && - schema.minItems === 0 - ) || ( - ValueGuard.IsArray(schema.items) && - schema.items.every(schema => TSchema(schema)) - )) - ) - } - /** Returns true if the given value is TUndefined */ - export function TUndefined(schema: unknown): schema is TUndefined { - // prettier-ignore - return ( - TKindOf(schema, 'Undefined') && - schema.type === 'undefined' && - IsOptionalString(schema.$id) - ) - } - /** Returns true if the given value is TUnion[]> */ - export function TUnionLiteral(schema: unknown): schema is TUnion { - return TUnion(schema) && schema.anyOf.every((schema) => TLiteralString(schema) || TLiteralNumber(schema)) - } - /** Returns true if the given value is TUnion */ - export function TUnion(schema: unknown): schema is TUnion { - // prettier-ignore - return ( - TKindOf(schema, 'Union') && - IsOptionalString(schema.$id) && - ValueGuard.IsObject(schema) && - ValueGuard.IsArray(schema.anyOf) && - schema.anyOf.every(schema => TSchema(schema)) - ) - } - /** Returns true if the given value is TUint8Array */ - export function TUint8Array(schema: unknown): schema is TUint8Array { - // prettier-ignore - return ( - TKindOf(schema, 'Uint8Array') && - schema.type === 'Uint8Array' && - IsOptionalString(schema.$id) && - IsOptionalNumber(schema.minByteLength) && - IsOptionalNumber(schema.maxByteLength) - ) - } - /** Returns true if the given value is TUnknown */ - export function TUnknown(schema: unknown): schema is TUnknown { - // prettier-ignore - return ( - TKindOf(schema, 'Unknown') && - IsOptionalString(schema.$id) - ) - } - /** Returns true if the given value is a raw TUnsafe */ - export function TUnsafe(schema: unknown): schema is TUnsafe { - return TKindOf(schema, 'Unsafe') - } - /** Returns true if the given value is TVoid */ - export function TVoid(schema: unknown): schema is TVoid { - // prettier-ignore - return ( - TKindOf(schema, 'Void') && - schema.type === 'void' && - IsOptionalString(schema.$id) - ) - } - /** Returns true if this value has a Readonly symbol */ - export function TReadonly(schema: T): schema is TReadonly { - return ValueGuard.IsObject(schema) && schema[Readonly] === 'Readonly' - } - /** Returns true if this value has a Optional symbol */ - export function TOptional(schema: T): schema is TOptional { - return ValueGuard.IsObject(schema) && schema[Optional] === 'Optional' - } - /** Returns true if the given value is TSchema */ - export function TSchema(schema: unknown): schema is TSchema { - // prettier-ignore - return ( - ValueGuard.IsObject(schema) - ) && ( - TAny(schema) || - TArray(schema) || - TBoolean(schema) || - TBigInt(schema) || - TAsyncIterator(schema) || - TConstructor(schema) || - TDate(schema) || - TFunction(schema) || - TInteger(schema) || - TIntersect(schema) || - TIterator(schema) || - TLiteral(schema) || - TNever(schema) || - TNot(schema) || - TNull(schema) || - TNumber(schema) || - TObject(schema) || - TPromise(schema) || - TRecord(schema) || - TRef(schema) || - TString(schema) || - TSymbol(schema) || - TTemplateLiteral(schema) || - TThis(schema) || - TTuple(schema) || - TUndefined(schema) || - TUnion(schema) || - TUint8Array(schema) || - TUnknown(schema) || - TUnsafe(schema) || - TVoid(schema) || - (TKind(schema) && TypeRegistry.Has(schema[Kind] as any)) - ) - } -} -// -------------------------------------------------------------------------- -// ExtendsUndefined -// -------------------------------------------------------------------------- -/** Fast undefined check used for properties of type undefined */ -export namespace ExtendsUndefined { - export function Check(schema: TSchema): boolean { - return schema[Kind] === 'Intersect' - ? (schema as TIntersect).allOf.every((schema) => Check(schema)) - : schema[Kind] === 'Union' - ? (schema as TUnion).anyOf.some((schema) => Check(schema)) - : schema[Kind] === 'Undefined' - ? true - : schema[Kind] === 'Not' - ? !Check(schema.not) - : false - } -} -// -------------------------------------------------------------------------- -// TypeExtends -// -------------------------------------------------------------------------- -export class TypeExtendsError extends TypeBoxError {} -export enum TypeExtendsResult { - Union, - True, - False, -} -export namespace TypeExtends { - // -------------------------------------------------------------------------- - // IntoBooleanResult - // -------------------------------------------------------------------------- - function IntoBooleanResult(result: TypeExtendsResult) { - return result === TypeExtendsResult.False ? result : TypeExtendsResult.True - } - // -------------------------------------------------------------------------- - // Throw - // -------------------------------------------------------------------------- - function Throw(message: string): never { - throw new TypeExtendsError(message) - } - // -------------------------------------------------------------------------- - // StructuralRight - // -------------------------------------------------------------------------- - function IsStructuralRight(right: TSchema): boolean { - // prettier-ignore - return ( - TypeGuard.TNever(right) || - TypeGuard.TIntersect(right) || - TypeGuard.TUnion(right) || - TypeGuard.TUnknown(right) || - TypeGuard.TAny(right) - ) - } - function StructuralRight(left: TSchema, right: TSchema) { - // prettier-ignore - return ( - TypeGuard.TNever(right) ? TNeverRight(left, right) : - TypeGuard.TIntersect(right) ? TIntersectRight(left, right) : - TypeGuard.TUnion(right) ? TUnionRight(left, right) : - TypeGuard.TUnknown(right) ? TUnknownRight(left, right) : - TypeGuard.TAny(right) ? TAnyRight(left, right) : - Throw('StructuralRight') - ) - } - // -------------------------------------------------------------------------- - // Any - // -------------------------------------------------------------------------- - function TAnyRight(left: TSchema, right: TAny) { - return TypeExtendsResult.True - } - function TAny(left: TAny, right: TSchema) { - // prettier-ignore - return ( - TypeGuard.TIntersect(right) ? TIntersectRight(left, right) : - (TypeGuard.TUnion(right) && right.anyOf.some((schema) => TypeGuard.TAny(schema) || TypeGuard.TUnknown(schema))) ? TypeExtendsResult.True : - TypeGuard.TUnion(right) ? TypeExtendsResult.Union : - TypeGuard.TUnknown(right) ? TypeExtendsResult.True : - TypeGuard.TAny(right) ? TypeExtendsResult.True : - TypeExtendsResult.Union - ) - } - // -------------------------------------------------------------------------- - // Array - // -------------------------------------------------------------------------- - function TArrayRight(left: TSchema, right: TArray) { - // prettier-ignore - return ( - TypeGuard.TUnknown(left) ? TypeExtendsResult.False : - TypeGuard.TAny(left) ?TypeExtendsResult.Union : - TypeGuard.TNever(left) ? TypeExtendsResult.True : - TypeExtendsResult.False - ) - } - function TArray(left: TArray, right: TSchema) { - // prettier-ignore - return ( - TypeGuard.TObject(right) && IsObjectArrayLike(right) ? TypeExtendsResult.True : - IsStructuralRight(right) ? StructuralRight(left, right) : - !TypeGuard.TArray(right) ? TypeExtendsResult.False : - IntoBooleanResult(Visit(left.items, right.items)) - ) - } - // -------------------------------------------------------------------------- - // AsyncIterator - // -------------------------------------------------------------------------- - function TAsyncIterator(left: TAsyncIterator, right: TSchema) { - // prettier-ignore - return ( - IsStructuralRight(right) ? StructuralRight(left, right) : - !TypeGuard.TAsyncIterator(right) ? TypeExtendsResult.False : - IntoBooleanResult(Visit(left.items, right.items)) - ) - } - // -------------------------------------------------------------------------- - // BigInt - // -------------------------------------------------------------------------- - function TBigInt(left: TBigInt, right: TSchema): TypeExtendsResult { - // prettier-ignore - return ( - IsStructuralRight(right) ? StructuralRight(left, right) : - TypeGuard.TObject(right) ? TObjectRight(left, right) : - TypeGuard.TRecord(right) ? TRecordRight(left, right) : - TypeGuard.TBigInt(right) ? TypeExtendsResult.True : - TypeExtendsResult.False - ) - } - // -------------------------------------------------------------------------- - // Boolean - // -------------------------------------------------------------------------- - function TBooleanRight(left: TSchema, right: TBoolean) { - return TypeGuard.TLiteral(left) && ValueGuard.IsBoolean(left.const) ? TypeExtendsResult.True : TypeGuard.TBoolean(left) ? TypeExtendsResult.True : TypeExtendsResult.False - } - function TBoolean(left: TBoolean, right: TSchema): TypeExtendsResult { - // prettier-ignore - return ( - IsStructuralRight(right) ? StructuralRight(left, right) : - TypeGuard.TObject(right) ? TObjectRight(left, right) : - TypeGuard.TRecord(right) ? TRecordRight(left, right) : - TypeGuard.TBoolean(right) ? TypeExtendsResult.True : - TypeExtendsResult.False - ) - } - // -------------------------------------------------------------------------- - // Constructor - // -------------------------------------------------------------------------- - function TConstructor(left: TConstructor, right: TSchema) { - // prettier-ignore - return ( - IsStructuralRight(right) ? StructuralRight(left, right) : - TypeGuard.TObject(right) ? TObjectRight(left, right) : - !TypeGuard.TConstructor(right) ? TypeExtendsResult.False : - left.parameters.length > right.parameters.length ? TypeExtendsResult.False : - (!left.parameters.every((schema, index) => IntoBooleanResult(Visit(right.parameters[index], schema)) === TypeExtendsResult.True)) ? TypeExtendsResult.False : - IntoBooleanResult(Visit(left.returns, right.returns)) - ) - } - // -------------------------------------------------------------------------- - // Date - // -------------------------------------------------------------------------- - function TDate(left: TDate, right: TSchema) { - // prettier-ignore - return ( - IsStructuralRight(right) ? StructuralRight(left, right) : - TypeGuard.TObject(right) ? TObjectRight(left, right) : - TypeGuard.TRecord(right) ? TRecordRight(left, right) : - TypeGuard.TDate(right) ? TypeExtendsResult.True : - TypeExtendsResult.False - ) - } - // -------------------------------------------------------------------------- - // Function - // -------------------------------------------------------------------------- - function TFunction(left: TFunction, right: TSchema) { - // prettier-ignore - return ( - IsStructuralRight(right) ? StructuralRight(left, right) : - TypeGuard.TObject(right) ? TObjectRight(left, right) : - !TypeGuard.TFunction(right) ? TypeExtendsResult.False : - left.parameters.length > right.parameters.length ? TypeExtendsResult.False : - (!left.parameters.every((schema, index) => IntoBooleanResult(Visit(right.parameters[index], schema)) === TypeExtendsResult.True)) ? TypeExtendsResult.False : - IntoBooleanResult(Visit(left.returns, right.returns)) - ) - } - // -------------------------------------------------------------------------- - // Integer - // -------------------------------------------------------------------------- - function TIntegerRight(left: TSchema, right: TInteger) { - // prettier-ignore - return ( - TypeGuard.TLiteral(left) && ValueGuard.IsNumber(left.const) ? TypeExtendsResult.True : - TypeGuard.TNumber(left) || TypeGuard.TInteger(left) ? TypeExtendsResult.True : - TypeExtendsResult.False - ) - } - function TInteger(left: TInteger, right: TSchema): TypeExtendsResult { - // prettier-ignore - return ( - TypeGuard.TInteger(right) || TypeGuard.TNumber(right) ? TypeExtendsResult.True : - IsStructuralRight(right) ? StructuralRight(left, right) : - TypeGuard.TObject(right) ? TObjectRight(left, right) : - TypeGuard.TRecord(right) ? TRecordRight(left, right) : - TypeExtendsResult.False - ) - } - // -------------------------------------------------------------------------- - // Intersect - // -------------------------------------------------------------------------- - function TIntersectRight(left: TSchema, right: TIntersect): TypeExtendsResult { - // prettier-ignore - return right.allOf.every((schema) => Visit(left, schema) === TypeExtendsResult.True) - ? TypeExtendsResult.True - : TypeExtendsResult.False - } - function TIntersect(left: TIntersect, right: TSchema) { - // prettier-ignore - return left.allOf.some((schema) => Visit(schema, right) === TypeExtendsResult.True) - ? TypeExtendsResult.True - : TypeExtendsResult.False - } - // -------------------------------------------------------------------------- - // Iterator - // -------------------------------------------------------------------------- - function TIterator(left: TIterator, right: TSchema) { - // prettier-ignore - return ( - IsStructuralRight(right) ? StructuralRight(left, right) : - !TypeGuard.TIterator(right) ? TypeExtendsResult.False : - IntoBooleanResult(Visit(left.items, right.items)) - ) - } - // -------------------------------------------------------------------------- - // Literal - // -------------------------------------------------------------------------- - function TLiteral(left: TLiteral, right: TSchema): TypeExtendsResult { - // prettier-ignore - return ( - TypeGuard.TLiteral(right) && right.const === left.const ? TypeExtendsResult.True : - IsStructuralRight(right) ? StructuralRight(left, right) : - TypeGuard.TObject(right) ? TObjectRight(left, right) : - TypeGuard.TRecord(right) ? TRecordRight(left, right) : - TypeGuard.TString(right) ? TStringRight(left, right) : - TypeGuard.TNumber(right) ? TNumberRight(left, right) : - TypeGuard.TInteger(right) ? TIntegerRight(left, right) : - TypeGuard.TBoolean(right) ? TBooleanRight(left, right) : - TypeExtendsResult.False - ) - } - // -------------------------------------------------------------------------- - // Never - // -------------------------------------------------------------------------- - function TNeverRight(left: TSchema, right: TNever) { - return TypeExtendsResult.False - } - function TNever(left: TNever, right: TSchema) { - return TypeExtendsResult.True - } - // -------------------------------------------------------------------------- - // Not - // -------------------------------------------------------------------------- - function UnwrapTNot(schema: T): TUnknown | TNot['not'] { - let [current, depth]: [TSchema, number] = [schema, 0] - while (true) { - if (!TypeGuard.TNot(current)) break - current = current.not - depth += 1 - } - return depth % 2 === 0 ? current : Type.Unknown() - } - function TNot(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.TNot(left) ? Visit(UnwrapTNot(left), right) : - TypeGuard.TNot(right) ? Visit(left, UnwrapTNot(right)) : - Throw('Invalid fallthrough for Not') - ) - } - // -------------------------------------------------------------------------- - // Null - // -------------------------------------------------------------------------- - function TNull(left: TNull, right: TSchema) { - // prettier-ignore - return ( - IsStructuralRight(right) ? StructuralRight(left, right) : - TypeGuard.TObject(right) ? TObjectRight(left, right) : - TypeGuard.TRecord(right) ? TRecordRight(left, right) : - TypeGuard.TNull(right) ? TypeExtendsResult.True : - TypeExtendsResult.False - ) - } - // -------------------------------------------------------------------------- - // Number - // -------------------------------------------------------------------------- - function TNumberRight(left: TSchema, right: TNumber) { - // prettier-ignore - return ( - TypeGuard.TLiteralNumber(left) ? TypeExtendsResult.True : - TypeGuard.TNumber(left) || TypeGuard.TInteger(left) ? TypeExtendsResult.True : - TypeExtendsResult.False - ) - } - function TNumber(left: TNumber, right: TSchema): TypeExtendsResult { - // prettier-ignore - return ( - IsStructuralRight(right) ? StructuralRight(left, right) : - TypeGuard.TObject(right) ? TObjectRight(left, right) : - TypeGuard.TRecord(right) ? TRecordRight(left, right) : - TypeGuard.TInteger(right) || TypeGuard.TNumber(right) ? TypeExtendsResult.True : - TypeExtendsResult.False - ) - } - // -------------------------------------------------------------------------- - // Object - // -------------------------------------------------------------------------- - function IsObjectPropertyCount(schema: TObject, count: number) { - return Object.getOwnPropertyNames(schema.properties).length === count - } - function IsObjectStringLike(schema: TObject) { - return IsObjectArrayLike(schema) - } - function IsObjectSymbolLike(schema: TObject) { - // prettier-ignore - return IsObjectPropertyCount(schema, 0) || ( - IsObjectPropertyCount(schema, 1) && 'description' in schema.properties && TypeGuard.TUnion(schema.properties.description) && schema.properties.description.anyOf.length === 2 && (( - TypeGuard.TString(schema.properties.description.anyOf[0]) && - TypeGuard.TUndefined(schema.properties.description.anyOf[1]) - ) || ( - TypeGuard.TString(schema.properties.description.anyOf[1]) && - TypeGuard.TUndefined(schema.properties.description.anyOf[0]) - )) - ) - } - function IsObjectNumberLike(schema: TObject) { - return IsObjectPropertyCount(schema, 0) - } - function IsObjectBooleanLike(schema: TObject) { - return IsObjectPropertyCount(schema, 0) - } - function IsObjectBigIntLike(schema: TObject) { - return IsObjectPropertyCount(schema, 0) - } - function IsObjectDateLike(schema: TObject) { - return IsObjectPropertyCount(schema, 0) - } - function IsObjectUint8ArrayLike(schema: TObject) { - return IsObjectArrayLike(schema) - } - function IsObjectFunctionLike(schema: TObject) { - const length = Type.Number() - return IsObjectPropertyCount(schema, 0) || (IsObjectPropertyCount(schema, 1) && 'length' in schema.properties && IntoBooleanResult(Visit(schema.properties['length'], length)) === TypeExtendsResult.True) - } - function IsObjectConstructorLike(schema: TObject) { - return IsObjectPropertyCount(schema, 0) - } - function IsObjectArrayLike(schema: TObject) { - const length = Type.Number() - return IsObjectPropertyCount(schema, 0) || (IsObjectPropertyCount(schema, 1) && 'length' in schema.properties && IntoBooleanResult(Visit(schema.properties['length'], length)) === TypeExtendsResult.True) - } - function IsObjectPromiseLike(schema: TObject) { - const then = Type.Function([Type.Any()], Type.Any()) - return IsObjectPropertyCount(schema, 0) || (IsObjectPropertyCount(schema, 1) && 'then' in schema.properties && IntoBooleanResult(Visit(schema.properties['then'], then)) === TypeExtendsResult.True) - } - // -------------------------------------------------------------------------- - // Property - // -------------------------------------------------------------------------- - function Property(left: TSchema, right: TSchema) { - // prettier-ignore - return ( - Visit(left, right) === TypeExtendsResult.False ? TypeExtendsResult.False : - TypeGuard.TOptional(left) && !TypeGuard.TOptional(right) ? TypeExtendsResult.False : - TypeExtendsResult.True - ) - } - function TObjectRight(left: TSchema, right: TObject) { - // prettier-ignore - return ( - TypeGuard.TUnknown(left) ? TypeExtendsResult.False : - TypeGuard.TAny(left) ? TypeExtendsResult.Union : ( - TypeGuard.TNever(left) || - (TypeGuard.TLiteralString(left) && IsObjectStringLike(right)) || - (TypeGuard.TLiteralNumber(left) && IsObjectNumberLike(right)) || - (TypeGuard.TLiteralBoolean(left) && IsObjectBooleanLike(right)) || - (TypeGuard.TSymbol(left) && IsObjectSymbolLike(right)) || - (TypeGuard.TBigInt(left) && IsObjectBigIntLike(right)) || - (TypeGuard.TString(left) && IsObjectStringLike(right)) || - (TypeGuard.TSymbol(left) && IsObjectSymbolLike(right)) || - (TypeGuard.TNumber(left) && IsObjectNumberLike(right)) || - (TypeGuard.TInteger(left) && IsObjectNumberLike(right)) || - (TypeGuard.TBoolean(left) && IsObjectBooleanLike(right)) || - (TypeGuard.TUint8Array(left) && IsObjectUint8ArrayLike(right)) || - (TypeGuard.TDate(left) && IsObjectDateLike(right)) || - (TypeGuard.TConstructor(left) && IsObjectConstructorLike(right)) || - (TypeGuard.TFunction(left) && IsObjectFunctionLike(right)) - ) ? TypeExtendsResult.True : - (TypeGuard.TRecord(left) && TypeGuard.TString(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' ? TypeExtendsResult.True : TypeExtendsResult.False - })() : - (TypeGuard.TRecord(left) && TypeGuard.TNumber(RecordKey(left))) ? (() => { - return IsObjectPropertyCount(right, 0) - ? TypeExtendsResult.True - : TypeExtendsResult.False - })() : - TypeExtendsResult.False - ) - } - function TObject(left: TObject, right: TSchema) { - // prettier-ignore - return ( - IsStructuralRight(right) ? StructuralRight(left, right) : - TypeGuard.TRecord(right) ? TRecordRight(left, right) : - !TypeGuard.TObject(right) ? TypeExtendsResult.False : - (() => { - for (const key of Object.getOwnPropertyNames(right.properties)) { - if (!(key in left.properties) && !TypeGuard.TOptional(right.properties[key])) { - return TypeExtendsResult.False - } - if(TypeGuard.TOptional(right.properties[key])) { - return TypeExtendsResult.True - } - if (Property(left.properties[key], right.properties[key]) === TypeExtendsResult.False) { - return TypeExtendsResult.False - } - } - return TypeExtendsResult.True - })() - ) - } - // -------------------------------------------------------------------------- - // Promise - // -------------------------------------------------------------------------- - function TPromise(left: TPromise, right: TSchema) { - // prettier-ignore - return ( - IsStructuralRight(right) ? StructuralRight(left, right) : - TypeGuard.TObject(right) && IsObjectPromiseLike(right) ? TypeExtendsResult.True : - !TypeGuard.TPromise(right) ? TypeExtendsResult.False : - IntoBooleanResult(Visit(left.item, right.item)) - ) - } - // -------------------------------------------------------------------------- - // Record - // -------------------------------------------------------------------------- - function RecordKey(schema: TRecord) { - // prettier-ignore - return ( - PatternNumberExact in schema.patternProperties ? Type.Number() : - PatternStringExact in schema.patternProperties ? Type.String() : - Throw('Unknown record key pattern') - ) - } - function RecordValue(schema: TRecord) { - // prettier-ignore - return ( - PatternNumberExact in schema.patternProperties ? schema.patternProperties[PatternNumberExact] : - PatternStringExact in schema.patternProperties ? schema.patternProperties[PatternStringExact] : - Throw('Unable to get record value schema') - ) - } - function TRecordRight(left: TSchema, right: TRecord) { - const [Key, Value] = [RecordKey(right), RecordValue(right)] - // prettier-ignore - return ( - (TypeGuard.TLiteralString(left) && TypeGuard.TNumber(Key) && IntoBooleanResult(Visit(left, Value)) === TypeExtendsResult.True) ? TypeExtendsResult.True : - TypeGuard.TUint8Array(left) && TypeGuard.TNumber(Key) ? Visit(left, Value) : - TypeGuard.TString(left) && TypeGuard.TNumber(Key) ? Visit(left, Value) : - TypeGuard.TArray(left) && TypeGuard.TNumber(Key) ? Visit(left, Value) : - TypeGuard.TObject(left) ? (() => { - for (const key of Object.getOwnPropertyNames(left.properties)) { - if (Property(Value, left.properties[key]) === TypeExtendsResult.False) { - return TypeExtendsResult.False - } - } - return TypeExtendsResult.True - })() : - TypeExtendsResult.False - ) - } - function TRecord(left: TRecord, right: TSchema) { - // prettier-ignore - return ( - IsStructuralRight(right) ? StructuralRight(left, right) : - TypeGuard.TObject(right) ? TObjectRight(left, right) : - !TypeGuard.TRecord(right) ? TypeExtendsResult.False : - Visit(RecordValue(left), RecordValue(right)) - ) - } - // -------------------------------------------------------------------------- - // String - // -------------------------------------------------------------------------- - function TStringRight(left: TSchema, right: TString) { - // prettier-ignore - return ( - TypeGuard.TLiteral(left) && ValueGuard.IsString(left.const) ? TypeExtendsResult.True : - TypeGuard.TString(left) ? TypeExtendsResult.True : - TypeExtendsResult.False - ) - } - function TString(left: TString, right: TSchema): TypeExtendsResult { - // prettier-ignore - return ( - IsStructuralRight(right) ? StructuralRight(left, right) : - TypeGuard.TObject(right) ? TObjectRight(left, right) : - TypeGuard.TRecord(right) ? TRecordRight(left, right) : - TypeGuard.TString(right) ? TypeExtendsResult.True : - TypeExtendsResult.False - ) - } - // -------------------------------------------------------------------------- - // Symbol - // -------------------------------------------------------------------------- - function TSymbol(left: TSymbol, right: TSchema): TypeExtendsResult { - // prettier-ignore - return ( - IsStructuralRight(right) ? StructuralRight(left, right) : - TypeGuard.TObject(right) ? TObjectRight(left, right) : - TypeGuard.TRecord(right) ? TRecordRight(left, right) : - TypeGuard.TSymbol(right) ? TypeExtendsResult.True : - TypeExtendsResult.False - ) - } - // -------------------------------------------------------------------------- - // TemplateLiteral - // -------------------------------------------------------------------------- - function TTemplateLiteral(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. - // prettier-ignore - return ( - TypeGuard.TTemplateLiteral(left) ? Visit(TemplateLiteralResolver.Resolve(left), right) : - TypeGuard.TTemplateLiteral(right) ? Visit(left, TemplateLiteralResolver.Resolve(right)) : - Throw('Invalid fallthrough for TemplateLiteral') - ) - } - // -------------------------------------------------------------------------- - // Tuple - // -------------------------------------------------------------------------- - function IsArrayOfTuple(left: TTuple, right: TSchema) { - // prettier-ignore - return ( - TypeGuard.TArray(right) && - left.items !== undefined && - left.items.every((schema) => Visit(schema, right.items) === TypeExtendsResult.True) - ) - } - function TTupleRight(left: TSchema, right: TTuple) { - // prettier-ignore - return ( - TypeGuard.TNever(left) ? TypeExtendsResult.True : - TypeGuard.TUnknown(left) ? TypeExtendsResult.False : - TypeGuard.TAny(left) ? TypeExtendsResult.Union : - TypeExtendsResult.False - ) - } - function TTuple(left: TTuple, right: TSchema): TypeExtendsResult { - // prettier-ignore - return ( - IsStructuralRight(right) ? StructuralRight(left, right) : - TypeGuard.TObject(right) && IsObjectArrayLike(right) ? TypeExtendsResult.True : - TypeGuard.TArray(right) && IsArrayOfTuple(left, right) ? TypeExtendsResult.True : - !TypeGuard.TTuple(right) ? TypeExtendsResult.False : - (ValueGuard.IsUndefined(left.items) && !ValueGuard.IsUndefined(right.items)) || (!ValueGuard.IsUndefined(left.items) && ValueGuard.IsUndefined(right.items)) ? TypeExtendsResult.False : - (ValueGuard.IsUndefined(left.items) && !ValueGuard.IsUndefined(right.items)) ? TypeExtendsResult.True : - left.items!.every((schema, index) => Visit(schema, right.items![index]) === TypeExtendsResult.True) ? TypeExtendsResult.True : - TypeExtendsResult.False - ) - } - // -------------------------------------------------------------------------- - // Uint8Array - // -------------------------------------------------------------------------- - function TUint8Array(left: TUint8Array, right: TSchema) { - // prettier-ignore - return ( - IsStructuralRight(right) ? StructuralRight(left, right) : - TypeGuard.TObject(right) ? TObjectRight(left, right) : - TypeGuard.TRecord(right) ? TRecordRight(left, right) : - TypeGuard.TUint8Array(right) ? TypeExtendsResult.True : - TypeExtendsResult.False - ) - } - // -------------------------------------------------------------------------- - // Undefined - // -------------------------------------------------------------------------- - function TUndefined(left: TUndefined, right: TSchema) { - // prettier-ignore - return ( - IsStructuralRight(right) ? StructuralRight(left, right) : - TypeGuard.TObject(right) ? TObjectRight(left, right) : - TypeGuard.TRecord(right) ? TRecordRight(left, right) : - TypeGuard.TVoid(right) ? VoidRight(left, right) : - TypeGuard.TUndefined(right) ? TypeExtendsResult.True : - TypeExtendsResult.False - ) - } - // -------------------------------------------------------------------------- - // Union - // -------------------------------------------------------------------------- - function TUnionRight(left: TSchema, right: TUnion): TypeExtendsResult { - // prettier-ignore - return right.anyOf.some((schema) => Visit(left, schema) === TypeExtendsResult.True) - ? TypeExtendsResult.True - : TypeExtendsResult.False - } - function TUnion(left: TUnion, right: TSchema): TypeExtendsResult { - // prettier-ignore - return left.anyOf.every((schema) => Visit(schema, right) === TypeExtendsResult.True) - ? TypeExtendsResult.True - : TypeExtendsResult.False - } - // -------------------------------------------------------------------------- - // Unknown - // -------------------------------------------------------------------------- - function TUnknownRight(left: TSchema, right: TUnknown) { - return TypeExtendsResult.True - } - function TUnknown(left: TUnknown, right: TSchema) { - // prettier-ignore - return ( - TypeGuard.TNever(right) ? TNeverRight(left, right) : - TypeGuard.TIntersect(right) ? TIntersectRight(left, right) : - TypeGuard.TUnion(right) ? TUnionRight(left, right) : - TypeGuard.TAny(right) ? TAnyRight(left, right) : - TypeGuard.TString(right) ? TStringRight(left, right) : - TypeGuard.TNumber(right) ? TNumberRight(left, right) : - TypeGuard.TInteger(right) ? TIntegerRight(left, right) : - TypeGuard.TBoolean(right) ? TBooleanRight(left, right) : - TypeGuard.TArray(right) ? TArrayRight(left, right) : - TypeGuard.TTuple(right) ? TTupleRight(left, right) : - TypeGuard.TObject(right) ? TObjectRight(left, right) : - TypeGuard.TUnknown(right) ? TypeExtendsResult.True : - TypeExtendsResult.False - ) - } - // -------------------------------------------------------------------------- - // Void - // -------------------------------------------------------------------------- - function VoidRight(left: TSchema, right: TVoid) { - // prettier-ignore - return TypeGuard.TUndefined(left) ? TypeExtendsResult.True : - TypeGuard.TUndefined(left) ? TypeExtendsResult.True : - TypeExtendsResult.False - } - function TVoid(left: TVoid, right: TSchema) { - // prettier-ignore - return TypeGuard.TIntersect(right) ? TIntersectRight(left, right) : - TypeGuard.TUnion(right) ? TUnionRight(left, right) : - TypeGuard.TUnknown(right) ? TUnknownRight(left, right) : - TypeGuard.TAny(right) ? TAnyRight(left, right) : - TypeGuard.TObject(right) ? TObjectRight(left, right) : - TypeGuard.TVoid(right) ? TypeExtendsResult.True : - TypeExtendsResult.False - } - function Visit(left: TSchema, right: TSchema): TypeExtendsResult { - // prettier-ignore - return ( - // resolvable - (TypeGuard.TTemplateLiteral(left) || TypeGuard.TTemplateLiteral(right)) ? TTemplateLiteral(left, right) : - (TypeGuard.TNot(left) || TypeGuard.TNot(right)) ? TNot(left, right) : - // standard - TypeGuard.TAny(left) ? TAny(left, right) : - TypeGuard.TArray(left) ? TArray(left, right) : - TypeGuard.TBigInt(left) ? TBigInt(left, right) : - TypeGuard.TBoolean(left) ? TBoolean(left, right) : - TypeGuard.TAsyncIterator(left) ? TAsyncIterator(left, right) : - TypeGuard.TConstructor(left) ? TConstructor(left, right) : - TypeGuard.TDate(left) ? TDate(left, right) : - TypeGuard.TFunction(left) ? TFunction(left, right) : - TypeGuard.TInteger(left) ? TInteger(left, right) : - TypeGuard.TIntersect(left) ? TIntersect(left, right) : - TypeGuard.TIterator(left) ? TIterator(left, right) : - TypeGuard.TLiteral(left) ? TLiteral(left, right) : - TypeGuard.TNever(left) ? TNever(left, right) : - TypeGuard.TNull(left) ? TNull(left, right) : - TypeGuard.TNumber(left) ? TNumber(left, right) : - TypeGuard.TObject(left) ? TObject(left, right) : - TypeGuard.TRecord(left) ? TRecord(left, right) : - TypeGuard.TString(left) ? TString(left, right) : - TypeGuard.TSymbol(left) ? TSymbol(left, right) : - TypeGuard.TTuple(left) ? TTuple(left, right) : - TypeGuard.TPromise(left) ? TPromise(left, right) : - TypeGuard.TUint8Array(left) ? TUint8Array(left, right) : - TypeGuard.TUndefined(left) ? TUndefined(left, right) : - TypeGuard.TUnion(left) ? TUnion(left, right) : - TypeGuard.TUnknown(left) ? TUnknown(left, right) : - TypeGuard.TVoid(left) ? TVoid(left, right) : - Throw(`Unknown left type operand '${left[Kind]}'`) - ) - } - export function Extends(left: TSchema, right: TSchema): TypeExtendsResult { - return Visit(left, right) - } -} -// -------------------------------------------------------------------------- -// TypeClone -// -------------------------------------------------------------------------- -/** Specialized Clone for Types */ -export namespace TypeClone { - 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 ObjectType(value: Record) { - 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 } - } - function Visit(value: unknown): any { - // prettier-ignore - return ( - ValueGuard.IsArray(value) ? ArrayType(value) : - ValueGuard.IsDate(value) ? DateType(value) : - ValueGuard.IsUint8Array(value) ? Uint8ArrayType(value) : - ValueGuard.IsObject(value) ? ObjectType(value) : - value - ) - } - /** Clones a Rest */ - export function Rest(schemas: [...T]): T { - return schemas.map((schema) => Type(schema)) as T - } - /** Clones a Type */ - export function Type(schema: T, options: SchemaOptions = {}): T { - return { ...Visit(schema), ...options } - } -} -// -------------------------------------------------------------------------- -// IndexedAccessor -// -------------------------------------------------------------------------- -export namespace IndexedAccessor { - function OptionalUnwrap(schema: TSchema[]): TSchema[] { - return schema.map((schema) => { - const { [Optional]: _, ...clone } = TypeClone.Type(schema) - return clone - }) - } - function IsIntersectOptional(schema: TSchema[]): boolean { - return schema.every((schema) => TypeGuard.TOptional(schema)) - } - function IsUnionOptional(schema: TSchema[]): boolean { - return schema.some((schema) => TypeGuard.TOptional(schema)) - } - function ResolveIntersect(schema: TIntersect): TSchema { - return IsIntersectOptional(schema.allOf) ? Type.Optional(Type.Intersect(OptionalUnwrap(schema.allOf))) : schema - } - function ResolveUnion(schema: TUnion): TSchema { - return IsUnionOptional(schema.anyOf) ? Type.Optional(Type.Union(OptionalUnwrap(schema.anyOf))) : schema - } - function ResolveOptional(schema: TSchema) { - // prettier-ignore - return schema[Kind] === 'Intersect' ? ResolveIntersect(schema as TIntersect) : - schema[Kind] === 'Union' ? ResolveUnion(schema as TUnion) : - schema - } - function TIntersect(schema: TIntersect, key: string): TSchema { - const resolved = schema.allOf.reduce((acc, schema) => { - const indexed = Visit(schema, key) - return indexed[Kind] === 'Never' ? acc : [...acc, indexed] - }, [] as TSchema[]) - return ResolveOptional(Type.Intersect(resolved)) - } - function TUnion(schema: TUnion, key: string): TSchema { - const resolved = schema.anyOf.map((schema) => Visit(schema, key)) - return ResolveOptional(Type.Union(resolved)) - } - function TObject(schema: TObject, key: string): TSchema { - const property = schema.properties[key] - return ValueGuard.IsUndefined(property) ? Type.Never() : Type.Union([property]) - } - function TTuple(schema: TTuple, key: string): TSchema { - const items = schema.items - if (ValueGuard.IsUndefined(items)) return Type.Never() - const element = items[key as any as number] // - if (ValueGuard.IsUndefined(element)) return Type.Never() - return element - } - function Visit(schema: TSchema, key: string): TSchema { - // prettier-ignore - return schema[Kind] === 'Intersect' ? TIntersect(schema as TIntersect, key) : - schema[Kind] === 'Union' ? TUnion(schema as TUnion, key) : - schema[Kind] === 'Object' ? TObject(schema as TObject, key) : - schema[Kind] === 'Tuple' ? TTuple(schema as TTuple, key) : - Type.Never() - } - export function Resolve(schema: TSchema, keys: TPropertyKey[], options: SchemaOptions = {}): TSchema { - const resolved = keys.map((key) => Visit(schema, key.toString())) - return ResolveOptional(Type.Union(resolved, options)) - } -} -// -------------------------------------------------------------------------- -// Intrinsic -// -------------------------------------------------------------------------- -export namespace Intrinsic { - function Uncapitalize(value: string): string { - const [first, rest] = [value.slice(0, 1), value.slice(1)] - return `${first.toLowerCase()}${rest}` - } - function Capitalize(value: string): string { - const [first, rest] = [value.slice(0, 1), value.slice(1)] - return `${first.toUpperCase()}${rest}` - } - function Uppercase(value: string): string { - return value.toUpperCase() - } - function Lowercase(value: string): string { - return value.toLowerCase() - } - function IntrinsicTemplateLiteral(schema: TTemplateLiteral, mode: TIntrinsicMode) { - // note: template literals require special runtime handling as they are encoded in string patterns. - // This diverges from the mapped type which would otherwise map on the template literal kind. - const expression = TemplateLiteralParser.ParseExact(schema.pattern) - const finite = TemplateLiteralFinite.Check(expression) - if (!finite) return { ...schema, pattern: IntrinsicLiteral(schema.pattern, mode) } as any - const strings = [...TemplateLiteralGenerator.Generate(expression)] - const literals = strings.map((value) => Type.Literal(value)) - const mapped = IntrinsicRest(literals as any, mode) - const union = Type.Union(mapped) - return Type.TemplateLiteral([union]) - } - function IntrinsicLiteral(value: TLiteralValue, mode: TIntrinsicMode) { - // prettier-ignore - return typeof value === 'string' ? ( - mode === 'Uncapitalize' ? Uncapitalize(value) : - mode === 'Capitalize' ? Capitalize(value) : - mode === 'Uppercase' ? Uppercase(value) : - mode === 'Lowercase' ? Lowercase(value) : - value) : value.toString() - } - function IntrinsicRest(schema: TSchema[], mode: TIntrinsicMode): TSchema[] { - if (schema.length === 0) return [] - const [L, ...R] = schema - return [Map(L, mode), ...IntrinsicRest(R, mode)] - } - function Visit(schema: TSchema, mode: TIntrinsicMode) { - // prettier-ignore - return TypeGuard.TTemplateLiteral(schema) ? IntrinsicTemplateLiteral(schema, mode) : - TypeGuard.TUnion(schema) ? Type.Union(IntrinsicRest(schema.anyOf, mode)) : - TypeGuard.TLiteral(schema) ? Type.Literal(IntrinsicLiteral(schema.const, mode)) : - schema - } - /** Applies an intrinsic string manipulation to the given type. */ - export function Map(schema: T, mode: M): TIntrinsic { - return Visit(schema, mode) - } -} -// -------------------------------------------------------------------------- -// ObjectMap -// -------------------------------------------------------------------------- -export namespace ObjectMap { - function TIntersect(schema: TIntersect, callback: (object: TObject) => TObject) { - // prettier-ignore - return Type.Intersect(schema.allOf.map((inner) => Visit(inner, callback)), { ...schema }) - } - function TUnion(schema: TUnion, callback: (object: TObject) => TObject) { - // prettier-ignore - return Type.Union(schema.anyOf.map((inner) => Visit(inner, callback)), { ...schema }) - } - function TObject(schema: TObject, callback: (object: TObject) => TObject) { - return callback(schema) - } - function Visit(schema: TSchema, callback: (object: TObject) => TObject): TSchema { - // There are cases where users need to map objects with unregistered kinds. Using a TypeGuard here would - // prevent sub schema mapping as unregistered kinds will not pass TSchema checks. This is notable in the - // case of TObject where unregistered property kinds cause the TObject check to fail. As mapping is only - // used for composition, we use explicit checks instead. - // prettier-ignore - return ( - schema[Kind] === 'Intersect' ? TIntersect(schema as TIntersect, callback) : - schema[Kind] === 'Union' ? TUnion(schema as TUnion, callback) : - schema[Kind] === 'Object' ? TObject(schema as TObject, callback) : - schema - ) - } - export function Map(schema: TSchema, callback: (object: TObject) => TObject, options: SchemaOptions): T { - return { ...Visit(TypeClone.Type(schema), callback), ...options } as unknown as T - } -} -// -------------------------------------------------------------------------- -// KeyResolver -// -------------------------------------------------------------------------- -export interface KeyResolverOptions { - includePatterns: boolean -} -export namespace KeyResolver { - function UnwrapPattern(key: string) { - return key[0] === '^' && key[key.length - 1] === '$' ? key.slice(1, key.length - 1) : key - } - function TIntersect(schema: TIntersect, options: KeyResolverOptions): string[] { - return schema.allOf.reduce((acc, schema) => [...acc, ...Visit(schema, options)], [] as string[]) - } - function TUnion(schema: TUnion, options: KeyResolverOptions): string[] { - const sets = schema.anyOf.map((inner) => Visit(inner, options)) - return [...sets.reduce((set, outer) => outer.map((key) => (sets.every((inner) => inner.includes(key)) ? set.add(key) : set))[0], new Set())] - } - function TObject(schema: TObject, options: KeyResolverOptions): string[] { - return Object.getOwnPropertyNames(schema.properties) - } - function TRecord(schema: TRecord, options: KeyResolverOptions): string[] { - return options.includePatterns ? Object.getOwnPropertyNames(schema.patternProperties) : [] - } - function Visit(schema: TSchema, options: KeyResolverOptions): string[] { - // prettier-ignore - return ( - TypeGuard.TIntersect(schema) ? TIntersect(schema, options) : - TypeGuard.TUnion(schema) ? TUnion(schema, options) : - TypeGuard.TObject(schema) ? TObject(schema, options) : - TypeGuard.TRecord(schema) ? TRecord(schema, options) : - [] - ) - } - /** Resolves an array of keys in this schema */ - export function ResolveKeys(schema: TSchema, options: KeyResolverOptions): string[] { - return [...new Set(Visit(schema, options))] - } - /** Resolves a regular expression pattern matching all keys in this schema */ - export function ResolvePattern(schema: TSchema): string { - const keys = ResolveKeys(schema, { includePatterns: true }) - const pattern = keys.map((key) => `(${UnwrapPattern(key)})`) - return `^(${pattern.join('|')})$` - } -} -// -------------------------------------------------------------------------- -// KeyArrayResolver -// -------------------------------------------------------------------------- -export class KeyArrayResolverError extends TypeBoxError {} -export namespace KeyArrayResolver { - /** Resolves an array of string[] keys from the given schema or array type. */ - export function Resolve(schema: TSchema | string[]): string[] { - // prettier-ignore - return Array.isArray(schema) ? schema : - TypeGuard.TUnionLiteral(schema) ? schema.anyOf.map((schema) => schema.const.toString()) : - TypeGuard.TLiteral(schema) ? [schema.const as string] : - TypeGuard.TTemplateLiteral(schema) ? (() => { - const expression = TemplateLiteralParser.ParseExact(schema.pattern) - if (!TemplateLiteralFinite.Check(expression)) throw new KeyArrayResolverError('Cannot resolve keys from infinite template expression') - return [...TemplateLiteralGenerator.Generate(expression)] - })() : [] - } -} -// -------------------------------------------------------------------------- -// UnionResolver -// -------------------------------------------------------------------------- -export namespace UnionResolver { - function* TUnion(union: TUnion): IterableIterator { - for (const schema of union.anyOf) { - if (schema[Kind] === 'Union') { - yield* TUnion(schema as TUnion) - } else { - yield schema - } - } - } - /** Returns a resolved union with interior unions flattened */ - export function Resolve(union: TUnion): TUnion { - return Type.Union([...TUnion(union)], { ...union }) - } -} -// -------------------------------------------------------------------------- -// TemplateLiteralPattern -// -------------------------------------------------------------------------- -export class TemplateLiteralPatternError extends TypeBoxError {} -export namespace TemplateLiteralPattern { - function Throw(message: string): never { - throw new TemplateLiteralPatternError(message) - } - function Escape(value: string) { - return value.replace(/[.*+?^${}()|[\]\\]/g, '\\$&') - } - function Visit(schema: TSchema, acc: string): string { - // prettier-ignore - return ( - TypeGuard.TTemplateLiteral(schema) ? schema.pattern.slice(1, schema.pattern.length - 1) : - TypeGuard.TUnion(schema) ? `(${schema.anyOf.map((schema) => Visit(schema, acc)).join('|')})` : - TypeGuard.TNumber(schema) ? `${acc}${PatternNumber}` : - TypeGuard.TInteger(schema) ? `${acc}${PatternNumber}` : - TypeGuard.TBigInt(schema) ? `${acc}${PatternNumber}` : - TypeGuard.TString(schema) ? `${acc}${PatternString}` : - TypeGuard.TLiteral(schema) ? `${acc}${Escape(schema.const.toString())}` : - TypeGuard.TBoolean(schema) ? `${acc}${PatternBoolean}` : - Throw(`Unexpected Kind '${schema[Kind]}'`) - ) - } - export function Create(kinds: TTemplateLiteralKind[]): string { - return `^${kinds.map((schema) => Visit(schema, '')).join('')}\$` - } -} -// -------------------------------------------------------------------------------------- -// TemplateLiteralResolver -// -------------------------------------------------------------------------------------- -export namespace TemplateLiteralResolver { - /** Resolves a template literal as a TUnion */ - export function Resolve(template: TTemplateLiteral): TString | TUnion | TLiteral { - const expression = TemplateLiteralParser.ParseExact(template.pattern) - if (!TemplateLiteralFinite.Check(expression)) return Type.String() - const literals = [...TemplateLiteralGenerator.Generate(expression)].map((value) => Type.Literal(value)) - return Type.Union(literals) - } -} -// -------------------------------------------------------------------------------------- -// TemplateLiteralParser -// -------------------------------------------------------------------------------------- -export class TemplateLiteralParserError extends TypeBoxError {} -export namespace TemplateLiteralParser { - export type Expression = And | Or | Const - export type Const = { type: 'const'; const: string } - export type And = { type: 'and'; expr: Expression[] } - export type Or = { type: 'or'; expr: Expression[] } - function IsNonEscaped(pattern: string, index: number, char: string) { - return pattern[index] === char && pattern.charCodeAt(index - 1) !== 92 - } - function IsOpenParen(pattern: string, index: number) { - return IsNonEscaped(pattern, index, '(') - } - function IsCloseParen(pattern: string, index: number) { - return IsNonEscaped(pattern, index, ')') - } - function IsSeparator(pattern: string, index: number) { - return IsNonEscaped(pattern, index, '|') - } - function IsGroup(pattern: string) { - if (!(IsOpenParen(pattern, 0) && IsCloseParen(pattern, pattern.length - 1))) return false - let count = 0 - for (let index = 0; index < pattern.length; index++) { - if (IsOpenParen(pattern, index)) count += 1 - if (IsCloseParen(pattern, index)) count -= 1 - if (count === 0 && index !== pattern.length - 1) return false - } - return true - } - function InGroup(pattern: string) { - return pattern.slice(1, pattern.length - 1) - } - function IsPrecedenceOr(pattern: string) { - let count = 0 - for (let index = 0; index < pattern.length; index++) { - if (IsOpenParen(pattern, index)) count += 1 - if (IsCloseParen(pattern, index)) count -= 1 - if (IsSeparator(pattern, index) && count === 0) return true - } - return false - } - function IsPrecedenceAnd(pattern: string) { - for (let index = 0; index < pattern.length; index++) { - if (IsOpenParen(pattern, index)) return true - } - return false - } - function Or(pattern: string): Expression { - let [count, start] = [0, 0] - const expressions: Expression[] = [] - for (let index = 0; index < pattern.length; index++) { - if (IsOpenParen(pattern, index)) count += 1 - if (IsCloseParen(pattern, index)) count -= 1 - if (IsSeparator(pattern, index) && count === 0) { - const range = pattern.slice(start, index) - if (range.length > 0) expressions.push(Parse(range)) - start = index + 1 - } - } - const range = pattern.slice(start) - if (range.length > 0) expressions.push(Parse(range)) - if (expressions.length === 0) return { type: 'const', const: '' } - if (expressions.length === 1) return expressions[0] - return { type: 'or', expr: expressions } - } - function And(pattern: string): Expression { - function Group(value: string, index: number): [number, number] { - if (!IsOpenParen(value, index)) throw new TemplateLiteralParserError(`TemplateLiteralParser: Index must point to open parens`) - let count = 0 - for (let scan = index; scan < value.length; scan++) { - if (IsOpenParen(value, scan)) count += 1 - if (IsCloseParen(value, scan)) count -= 1 - if (count === 0) return [index, scan] - } - throw new TemplateLiteralParserError(`TemplateLiteralParser: Unclosed group parens in expression`) - } - function Range(pattern: string, index: number): [number, number] { - for (let scan = index; scan < pattern.length; scan++) { - if (IsOpenParen(pattern, scan)) return [index, scan] - } - return [index, pattern.length] - } - const expressions: Expression[] = [] - for (let index = 0; index < pattern.length; index++) { - if (IsOpenParen(pattern, index)) { - const [start, end] = Group(pattern, index) - const range = pattern.slice(start, end + 1) - expressions.push(Parse(range)) - index = end - } else { - const [start, end] = Range(pattern, index) - const range = pattern.slice(start, end) - if (range.length > 0) expressions.push(Parse(range)) - index = end - 1 - } - } - // prettier-ignore - return (expressions.length === 0) ? { type: 'const', const: '' } : - (expressions.length === 1) ? expressions[0] : - { type: 'and', expr: expressions } - } - /** Parses a pattern and returns an expression tree */ - export function Parse(pattern: string): Expression { - // prettier-ignore - return IsGroup(pattern) ? Parse(InGroup(pattern)) : - IsPrecedenceOr(pattern) ? Or(pattern) : - IsPrecedenceAnd(pattern) ? And(pattern) : - { type: 'const', const: pattern } - } - /** Parses a pattern and strips forward and trailing ^ and $ */ - export function ParseExact(pattern: string): Expression { - return Parse(pattern.slice(1, pattern.length - 1)) - } -} -// -------------------------------------------------------------------------------------- -// TemplateLiteralFinite -// -------------------------------------------------------------------------------------- -export class TemplateLiteralFiniteError extends TypeBoxError {} -export namespace TemplateLiteralFinite { - function Throw(message: string): never { - throw new TemplateLiteralFiniteError(message) - } - function IsNumber(expression: TemplateLiteralParser.Expression): boolean { - // prettier-ignore - return ( - expression.type === 'or' && - expression.expr.length === 2 && - expression.expr[0].type === 'const' && - expression.expr[0].const === '0' && - expression.expr[1].type === 'const' && - expression.expr[1].const === '[1-9][0-9]*' - ) - } - function IsBoolean(expression: TemplateLiteralParser.Expression): boolean { - // prettier-ignore - return ( - expression.type === 'or' && - expression.expr.length === 2 && - expression.expr[0].type === 'const' && - expression.expr[0].const === 'true' && - expression.expr[1].type === 'const' && - expression.expr[1].const === 'false' - ) - } - function IsString(expression: TemplateLiteralParser.Expression) { - return expression.type === 'const' && expression.const === '.*' - } - export function Check(expression: TemplateLiteralParser.Expression): boolean { - // prettier-ignore - return IsBoolean(expression) ? true : - IsNumber(expression) || IsString(expression) ? false : - (expression.type === 'and') ? expression.expr.every((expr) => Check(expr)) : - (expression.type === 'or') ? expression.expr.every((expr) => Check(expr)) : - (expression.type === 'const') ? true : - Throw(`Unknown expression type`) - } -} -// -------------------------------------------------------------------------------------- -// TemplateLiteralGenerator -// -------------------------------------------------------------------------------------- -export class TemplateLiteralGeneratorError extends TypeBoxError {} -export namespace TemplateLiteralGenerator { - function* Reduce(buffer: string[][]): IterableIterator { - if (buffer.length === 1) return yield* buffer[0] - for (const left of buffer[0]) { - for (const right of Reduce(buffer.slice(1))) { - yield `${left}${right}` - } - } - } - function* And(expression: TemplateLiteralParser.And): IterableIterator { - return yield* Reduce(expression.expr.map((expr) => [...Generate(expr)])) - } - function* Or(expression: TemplateLiteralParser.Or): IterableIterator { - for (const expr of expression.expr) yield* Generate(expr) - } - function* Const(expression: TemplateLiteralParser.Const): IterableIterator { - return yield expression.const - } - export function* Generate(expression: TemplateLiteralParser.Expression): IterableIterator { - // prettier-ignore - return ( - expression.type === 'and' ? yield* And(expression) : - expression.type === 'or' ? yield* Or(expression) : - expression.type === 'const' ? yield* Const(expression) : - (() => { throw new TemplateLiteralGeneratorError('Unknown expression') })() - ) - } -} -// --------------------------------------------------------------------- -// TemplateLiteralDslParser -// --------------------------------------------------------------------- -export namespace TemplateLiteralDslParser { - function* ParseUnion(template: string): IterableIterator { - const trim = template.trim().replace(/"|'/g, '') - // prettier-ignore - return ( - trim === 'boolean' ? yield Type.Boolean() : - trim === 'number' ? yield Type.Number() : - trim === 'bigint' ? yield Type.BigInt() : - trim === 'string' ? yield Type.String() : - yield (() => { - const literals = trim.split('|').map((literal) => Type.Literal(literal.trim())) - return ( - literals.length === 0 ? Type.Never() : - literals.length === 1 ? literals[0] : - Type.Union(literals) - ) - })() - ) - } - function* ParseTerminal(template: string): IterableIterator { - if (template[1] !== '{') { - const L = Type.Literal('$') - const R = ParseLiteral(template.slice(1)) - return yield* [L, ...R] - } - for (let i = 2; i < template.length; i++) { - if (template[i] === '}') { - const L = ParseUnion(template.slice(2, i)) - const R = ParseLiteral(template.slice(i + 1)) - return yield* [...L, ...R] - } - } - yield Type.Literal(template) - } - function* ParseLiteral(template: string): IterableIterator { - for (let i = 0; i < template.length; i++) { - if (template[i] === '$') { - const L = Type.Literal(template.slice(0, i)) - const R = ParseTerminal(template.slice(i)) - return yield* [L, ...R] - } - } - yield Type.Literal(template) - } - export function Parse(template_dsl: string): TTemplateLiteralKind[] { - return [...ParseLiteral(template_dsl)] - } -} -// --------------------------------------------------------------------- -// TransformBuilder -// --------------------------------------------------------------------- -export class TransformDecodeBuilder { - constructor(private readonly schema: T) {} - public Decode, U>>(decode: D): TransformEncodeBuilder { - return new TransformEncodeBuilder(this.schema, decode) - } -} -export class TransformEncodeBuilder { - constructor(private readonly schema: T, private readonly decode: D) {} - public Encode, StaticDecode>>(encode: E): TTransform> { - const schema = TypeClone.Type(this.schema) - // prettier-ignore - return ( - TypeGuard.TTransform(schema) ? (() => { - const Encode = (value: unknown) => schema[Transform].Encode(encode(value as any)) - const Decode = (value: unknown) => this.decode(schema[Transform].Decode(value)) - const Codec = { Encode: Encode, Decode: Decode } - return { ...schema, [Transform]: Codec } - })() : (() => { - const Codec = { Decode: this.decode, Encode: encode } - return { ...schema, [Transform]: Codec } - })() - ) as TTransform> - } -} -// -------------------------------------------------------------------------- -// TypeOrdinal: Used for auto $id generation -// -------------------------------------------------------------------------- -let TypeOrdinal = 0 -// -------------------------------------------------------------------------- -// TypeBuilder -// -------------------------------------------------------------------------- -export class TypeBuilderError extends TypeBoxError {} -export class TypeBuilder { - /** `[Internal]` Creates a schema without `static` and `params` types */ - protected Create(schema: Omit): T { - return schema as any - } - /** `[Internal]` Throws a TypeBuilder error with the given message */ - protected Throw(message: string): never { - throw new TypeBuilderError(message) - } - /** `[Internal]` Discards property keys from the given record type */ - protected Discard(record: Record, keys: PropertyKey[]) { - return keys.reduce((acc, key) => { - const { [key as any]: _, ...rest } = acc - return rest - }, record) as any - } - /** `[Json]` Omits compositing symbols from this schema */ - public Strict(schema: T): T { - return JSON.parse(JSON.stringify(schema)) - } -} -// -------------------------------------------------------------------------- -// JsonTypeBuilder -// -------------------------------------------------------------------------- -export class JsonTypeBuilder extends TypeBuilder { - // ------------------------------------------------------------------------ - // Modifiers - // ------------------------------------------------------------------------ - /** `[Json]` Creates a Readonly and Optional property */ - public ReadonlyOptional(schema: T): TReadonly> { - return this.Readonly(this.Optional(schema)) - } - /** `[Json]` Creates a Readonly property */ - public Readonly(schema: T): TReadonly { - return { ...TypeClone.Type(schema), [Readonly]: 'Readonly' } - } - /** `[Json]` Creates an Optional property */ - public Optional(schema: T): TOptional { - return { ...TypeClone.Type(schema), [Optional]: 'Optional' } - } - // ------------------------------------------------------------------------ - // Types - // ------------------------------------------------------------------------ - /** `[Json]` Creates an Any type */ - public Any(options: SchemaOptions = {}): TAny { - return this.Create({ ...options, [Kind]: 'Any' }) - } - /** `[Json]` Creates an Array type */ - public Array(schema: T, options: ArrayOptions = {}): TArray { - return this.Create({ ...options, [Kind]: 'Array', type: 'array', items: TypeClone.Type(schema) }) - } - /** `[Json]` Creates a Boolean type */ - public Boolean(options: SchemaOptions = {}): TBoolean { - return this.Create({ ...options, [Kind]: 'Boolean', type: 'boolean' }) - } - /** `[Json]` Intrinsic function to Capitalize LiteralString types */ - public Capitalize(schema: T, options: SchemaOptions = {}): TIntrinsic { - return { ...Intrinsic.Map(TypeClone.Type(schema), 'Capitalize'), ...options } - } - /** `[Json]` Creates a Composite object type */ - public Composite(objects: [...T], options?: ObjectOptions): TComposite { - const intersect: any = Type.Intersect(objects, {}) - const keys = KeyResolver.ResolveKeys(intersect, { includePatterns: false }) - const properties = keys.reduce((acc, key) => ({ ...acc, [key]: Type.Index(intersect, [key]) }), {} as TProperties) - return Type.Object(properties, options) as TComposite - } - /** `[Json]` Creates a Enum type */ - public Enum>(item: T, options: SchemaOptions = {}): TEnum { - if (ValueGuard.IsUndefined(item)) return this.Throw('Enum undefined or empty') - // prettier-ignore - const values1 = 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) => Type.Literal(value)) - return this.Union(anyOf, { ...options, [Hint]: 'Enum' }) as TEnum - } - /** `[Json]` Creates a Conditional type */ - public Extends(left: L, right: R, trueType: T, falseType: U, options: SchemaOptions = {}): TExtends { - switch (TypeExtends.Extends(left, right)) { - case TypeExtendsResult.Union: - return this.Union([TypeClone.Type(trueType, options), TypeClone.Type(falseType, options)]) as any as TExtends - case TypeExtendsResult.True: - return TypeClone.Type(trueType, options) as unknown as TExtends - case TypeExtendsResult.False: - return TypeClone.Type(falseType, options) as unknown as TExtends - } - } - /** `[Json]` Constructs a type by excluding from unionType all union members that are assignable to excludedMembers */ - public Exclude(unionType: L, excludedMembers: R, options: SchemaOptions = {}): TExclude { - // prettier-ignore - return ( - TypeGuard.TTemplateLiteral(unionType) ? this.Exclude(TemplateLiteralResolver.Resolve(unionType), excludedMembers, options) : - TypeGuard.TTemplateLiteral(excludedMembers) ? this.Exclude(unionType, TemplateLiteralResolver.Resolve(excludedMembers), options) : - TypeGuard.TUnion(unionType) ? (() => { - const narrowed = unionType.anyOf.filter((inner) => TypeExtends.Extends(inner, excludedMembers) === TypeExtendsResult.False) - return (narrowed.length === 1 ? TypeClone.Type(narrowed[0], options) : this.Union(narrowed, options)) as TExclude - })() : - TypeExtends.Extends(unionType, excludedMembers) !== TypeExtendsResult.False ? this.Never(options) : - TypeClone.Type(unionType, options) - ) as TExclude - } - /** `[Json]` Constructs a type by extracting from type all union members that are assignable to union */ - public Extract(type: L, union: R, options: SchemaOptions = {}): TExtract { - // prettier-ignore - return ( - TypeGuard.TTemplateLiteral(type) ? this.Extract(TemplateLiteralResolver.Resolve(type), union, options) : - TypeGuard.TTemplateLiteral(union) ? this.Extract(type, TemplateLiteralResolver.Resolve(union), options) : - TypeGuard.TUnion(type) ? (() => { - const narrowed = type.anyOf.filter((inner) => TypeExtends.Extends(inner, union) !== TypeExtendsResult.False) - return (narrowed.length === 1 ? TypeClone.Type(narrowed[0], options) : this.Union(narrowed, options)) - })() : - TypeExtends.Extends(type, union) !== TypeExtendsResult.False ? TypeClone.Type(type, options) : - this.Never(options) - ) as TExtract - } - /** `[Json]` Returns an Indexed property type for the given keys */ - public Index(schema: T, keys: K, options?: SchemaOptions): AssertType - /** `[Json]` Returns an Indexed property type for the given keys */ - public Index)[]>(schema: T, keys: [...K], options?: SchemaOptions): TIndex> - /** `[Json]` Returns an Indexed property type for the given keys */ - public Index(schema: T, keys: K, options?: SchemaOptions): UnionType> - /** `[Json]` Returns an Indexed property type for the given keys */ - public Index(schema: T, keys: K, options?: SchemaOptions): TIndex> - /** `[Json]` Returns an Indexed property type for the given keys */ - public Index>(schema: T, keys: K, options?: SchemaOptions): TIndex - /** `[Json]` Returns an Indexed property type for the given keys */ - public Index)[]>(schema: T, keys: [...K], options?: SchemaOptions): TIndex> - /** `[Json]` Returns an Indexed property type for the given keys */ - public Index[]>>(schema: T, keys: K, options?: SchemaOptions): TIndex> - /** `[Json]` Returns an Indexed property type for the given keys */ - public Index(schema: T, key: K, options?: SchemaOptions): TSchema - /** `[Json]` Returns an Indexed property type for the given keys */ - public Index(schema: TSchema, unresolved: any, options: SchemaOptions = {}): any { - // prettier-ignore - return ( - TypeGuard.TArray(schema) && TypeGuard.TNumber(unresolved) ? (() => { - return TypeClone.Type(schema.items, options) - })() : - TypeGuard.TTuple(schema) && TypeGuard.TNumber(unresolved) ? (() => { - const items = ValueGuard.IsUndefined(schema.items) ? [] : schema.items - const cloned = items.map((schema) => TypeClone.Type(schema)) - return this.Union(cloned, options) - })() : (() => { - const keys = KeyArrayResolver.Resolve(unresolved) - const clone = TypeClone.Type(schema) - return IndexedAccessor.Resolve(clone, keys, options) - })() - ) - } - /** `[Json]` Creates an Integer type */ - public Integer(options: NumericOptions = {}): TInteger { - return this.Create({ ...options, [Kind]: 'Integer', type: 'integer' }) - } - /** `[Json]` Creates an Intersect type */ - public Intersect(allOf: [], options?: SchemaOptions): TNever - /** `[Json]` Creates an Intersect type */ - public Intersect(allOf: [...T], options?: SchemaOptions): T[0] - /** `[Json]` Creates an Intersect type */ - public Intersect(allOf: [...T], options?: IntersectOptions): TIntersect - /** `[Json]` Creates an Intersect type */ - public Intersect(allOf: TSchema[], options: IntersectOptions = {}) { - if (allOf.length === 0) return Type.Never() - if (allOf.length === 1) return TypeClone.Type(allOf[0], options) - if (allOf.some((schema) => TypeGuard.TTransform(schema))) this.Throw('Cannot intersect transform types') - const objects = allOf.every((schema) => TypeGuard.TObject(schema)) - const cloned = TypeClone.Rest(allOf) - // prettier-ignore - const clonedUnevaluatedProperties = TypeGuard.TSchema(options.unevaluatedProperties) - ? { unevaluatedProperties: TypeClone.Type(options.unevaluatedProperties) } - : {} - return options.unevaluatedProperties === false || TypeGuard.TSchema(options.unevaluatedProperties) || objects - ? this.Create({ ...options, ...clonedUnevaluatedProperties, [Kind]: 'Intersect', type: 'object', allOf: cloned }) - : this.Create({ ...options, ...clonedUnevaluatedProperties, [Kind]: 'Intersect', allOf: cloned }) - } - /** `[Json]` Creates a KeyOf type */ - public KeyOf(schema: T, options: SchemaOptions = {}): TKeyOf { - // prettier-ignore - return ( - TypeGuard.TRecord(schema) ? (() => { - const pattern = Object.getOwnPropertyNames(schema.patternProperties)[0] - return ( - pattern === PatternNumberExact ? this.Number(options) : - pattern === PatternStringExact ? this.String(options) : - this.Throw('Unable to resolve key type from Record key pattern') - ) - })() : - TypeGuard.TTuple(schema) ? (() => { - const items = ValueGuard.IsUndefined(schema.items) ? [] : schema.items - const literals = items.map((_, index) => Type.Literal(index.toString())) - return this.Union(literals, options) - })() : - TypeGuard.TArray(schema) ? (() => { - return this.Number(options) - })() : (() => { - const keys = KeyResolver.ResolveKeys(schema, { includePatterns: false }) - if (keys.length === 0) return this.Never(options) as TKeyOf - const literals = keys.map((key) => this.Literal(key)) - return this.Union(literals, options) - })() - ) as unknown as TKeyOf - } - /** `[Json]` Creates a Literal type */ - public Literal(value: T, options: SchemaOptions = {}): TLiteral { - return this.Create({ ...options, [Kind]: 'Literal', const: value, type: typeof value as 'string' | 'number' | 'boolean' }) - } - /** `[Json]` Intrinsic function to Lowercase LiteralString types */ - public Lowercase(schema: T, options: SchemaOptions = {}): TIntrinsic { - return { ...Intrinsic.Map(TypeClone.Type(schema), 'Lowercase'), ...options } - } - /** `[Json]` Creates a Never type */ - public Never(options: SchemaOptions = {}): TNever { - return this.Create({ ...options, [Kind]: 'Never', not: {} }) - } - /** `[Json]` Creates a Not type */ - public Not(schema: T, options?: SchemaOptions): TNot { - return this.Create({ ...options, [Kind]: 'Not', not: TypeClone.Type(schema) }) - } - /** `[Json]` Creates a Null type */ - public Null(options: SchemaOptions = {}): TNull { - return this.Create({ ...options, [Kind]: 'Null', type: 'null' }) - } - /** `[Json]` Creates a Number type */ - public Number(options: NumericOptions = {}): TNumber { - return this.Create({ ...options, [Kind]: 'Number', type: 'number' }) - } - /** `[Json]` Creates an Object type */ - public Object(properties: T, options: ObjectOptions = {}): TObject { - const propertyKeys = Object.getOwnPropertyNames(properties) - const optionalKeys = propertyKeys.filter((key) => TypeGuard.TOptional(properties[key])) - const requiredKeys = propertyKeys.filter((name) => !optionalKeys.includes(name)) - const clonedAdditionalProperties = TypeGuard.TSchema(options.additionalProperties) ? { additionalProperties: TypeClone.Type(options.additionalProperties) } : {} - const clonedProperties = propertyKeys.reduce((acc, key) => ({ ...acc, [key]: TypeClone.Type(properties[key]) }), {} as TProperties) - return requiredKeys.length > 0 - ? this.Create({ ...options, ...clonedAdditionalProperties, [Kind]: 'Object', type: 'object', properties: clonedProperties, required: requiredKeys }) - : this.Create({ ...options, ...clonedAdditionalProperties, [Kind]: 'Object', type: 'object', properties: clonedProperties }) - } - /** `[Json]` Constructs a type whose keys are omitted from the given type */ - public Omit)[]>(schema: T, keys: readonly [...K], options?: SchemaOptions): TOmit - /** `[Json]` Constructs a type whose keys are omitted from the given type */ - public Omit[]>>(schema: T, keys: K, options?: SchemaOptions): TOmit[number]> - /** `[Json]` Constructs a type whose keys are omitted from the given type */ - public Omit>(schema: T, key: K, options?: SchemaOptions): TOmit - /** `[Json]` Constructs a type whose keys are omitted from the given type */ - public Omit(schema: T, key: K, options?: SchemaOptions): TOmit[number]> - /** `[Json]` Constructs a type whose keys are omitted from the given type */ - public Omit(schema: T, key: K, options?: SchemaOptions): TOmit - /** `[Json]` Constructs a type whose keys are omitted from the given type */ - public Omit(schema: TSchema, unresolved: any, options: SchemaOptions = {}): any { - const keys = KeyArrayResolver.Resolve(unresolved) - // prettier-ignore - return ObjectMap.Map(this.Discard(TypeClone.Type(schema), ['$id', Transform]), (object) => { - if (ValueGuard.IsArray(object.required)) { - object.required = object.required.filter((key: string) => !keys.includes(key as any)) - if (object.required.length === 0) delete object.required - } - for (const key of Object.getOwnPropertyNames(object.properties)) { - if (keys.includes(key as any)) delete object.properties[key] - } - return this.Create(object) - }, options) - } - /** `[Json]` Constructs a type where all properties are optional */ - public Partial(schema: T, options: ObjectOptions = {}): TPartial { - // prettier-ignore - return ObjectMap.Map(this.Discard(TypeClone.Type(schema), ['$id', Transform]), (object) => { - const properties = Object.getOwnPropertyNames(object.properties).reduce((acc, key) => { - return { ...acc, [key]: this.Optional(object.properties[key]) } - }, {} as TProperties) - return this.Object(properties, this.Discard(object, ['required']) /* object used as options to retain other constraints */) - }, options) - } - /** `[Json]` Constructs a type whose keys are picked from the given type */ - public Pick)[]>(schema: T, keys: readonly [...K], options?: SchemaOptions): TPick - /** `[Json]` Constructs a type whose keys are picked from the given type */ - public Pick[]>>(schema: T, keys: K, options?: SchemaOptions): TPick[number]> - /** `[Json]` Constructs a type whose keys are picked from the given type */ - public Pick>(schema: T, key: K, options?: SchemaOptions): TPick - /** `[Json]` Constructs a type whose keys are picked from the given type */ - public Pick(schema: T, key: K, options?: SchemaOptions): TPick[number]> - /** `[Json]` Constructs a type whose keys are picked from the given type */ - public Pick(schema: T, key: K, options?: SchemaOptions): TPick - /** `[Json]` Constructs a type whose keys are picked from the given type */ - public Pick(schema: TSchema, unresolved: any, options: SchemaOptions = {}): any { - const keys = KeyArrayResolver.Resolve(unresolved) - // prettier-ignore - return ObjectMap.Map(this.Discard(TypeClone.Type(schema), ['$id', Transform]), (object) => { - if (ValueGuard.IsArray(object.required)) { - object.required = object.required.filter((key: any) => keys.includes(key)) - if (object.required.length === 0) delete object.required - } - for (const key of Object.getOwnPropertyNames(object.properties)) { - if (!keys.includes(key as any)) delete object.properties[key] - } - return this.Create(object) - }, options) - } - /** `[Json]` Creates a Record type */ - public Record(key: K, schema: T, options: ObjectOptions = {}): TRecordResolve { - // prettier-ignore - return ( - TypeGuard.TTemplateLiteral(key) ? (() => { - const expression = TemplateLiteralParser.ParseExact(key.pattern) - // prettier-ignore - return TemplateLiteralFinite.Check(expression) - ? (this.Object([...TemplateLiteralGenerator.Generate(expression)].reduce((acc, key) => ({ ...acc, [key]: TypeClone.Type(schema) }), {} as TProperties), options)) - : this.Create({ ...options, [Kind]: 'Record', type: 'object', patternProperties: { [key.pattern]: TypeClone.Type(schema) }}) - })() : - TypeGuard.TUnion(key) ? (() => { - const union = UnionResolver.Resolve(key) - if (TypeGuard.TUnionLiteral(union)) { - const properties = union.anyOf.reduce((acc: any, literal: any) => ({ ...acc, [literal.const]: TypeClone.Type(schema) }), {} as TProperties) - return this.Object(properties, { ...options, [Hint]: 'Record' }) - } else this.Throw('Record key of type union contains non-literal types') - })() : - TypeGuard.TLiteral(key) ? (() => { - // prettier-ignore - return (ValueGuard.IsString(key.const) || ValueGuard.IsNumber(key.const)) - ? this.Object({ [key.const]: TypeClone.Type(schema) }, options) - : this.Throw('Record key of type literal is not of type string or number') - })() : - TypeGuard.TInteger(key) || TypeGuard.TNumber(key) ? (() => { - return this.Create({ ...options, [Kind]: 'Record', type: 'object', patternProperties: { [PatternNumberExact]: TypeClone.Type(schema) } }) - })() : - TypeGuard.TString(key) ? (() => { - const pattern = ValueGuard.IsUndefined(key.pattern) ? PatternStringExact : key.pattern - return this.Create({ ...options, [Kind]: 'Record', type: 'object', patternProperties: { [pattern]: TypeClone.Type(schema) } }) - })() : - this.Never() - ) - } - /** `[Json]` Creates a Recursive type */ - public Recursive(callback: (thisType: TThis) => T, options: SchemaOptions = {}): TRecursive { - if (ValueGuard.IsUndefined(options.$id)) (options as any).$id = `T${TypeOrdinal++}` - const thisType = callback({ [Kind]: 'This', $ref: `${options.$id}` } as any) - thisType.$id = options.$id - return this.Create({ ...options, [Hint]: 'Recursive', ...thisType } as any) - } - /** `[Json]` Creates a Ref type. The referenced type must contain a $id */ - public Ref(schema: T, options?: SchemaOptions): TRef - /** `[Json]` Creates a Ref type. */ - public Ref($ref: string, options?: SchemaOptions): TRef - /** `[Json]` Creates a Ref type. */ - public Ref(unresolved: TSchema | string, options: SchemaOptions = {}) { - if (ValueGuard.IsString(unresolved)) return this.Create({ ...options, [Kind]: 'Ref', $ref: unresolved }) - if (ValueGuard.IsUndefined(unresolved.$id)) this.Throw('Reference target type must specify an $id') - return this.Create({ ...options, [Kind]: 'Ref', $ref: unresolved.$id! }) - } - /** `[Json]` Constructs a type where all properties are required */ - public Required(schema: T, options: SchemaOptions = {}): TRequired { - // prettier-ignore - return ObjectMap.Map(this.Discard(TypeClone.Type(schema), ['$id', Transform]), (object) => { - const properties = Object.getOwnPropertyNames(object.properties).reduce((acc, key) => { - return { ...acc, [key]: this.Discard(object.properties[key], [Optional]) as TSchema } - }, {} as TProperties) - return this.Object(properties, object /* object used as options to retain other constraints */) - }, options) - } - /** `[Json]` Extracts interior Rest elements from Tuple, Intersect and Union types */ - public Rest(schema: T): TRest { - return ( - TypeGuard.TTuple(schema) && !ValueGuard.IsUndefined(schema.items) ? TypeClone.Rest(schema.items) : TypeGuard.TIntersect(schema) ? TypeClone.Rest(schema.allOf) : TypeGuard.TUnion(schema) ? TypeClone.Rest(schema.anyOf) : [] - ) as TRest - } - /** `[Json]` Creates a String type */ - public String(options: StringOptions = {}): TString { - return this.Create({ ...options, [Kind]: 'String', type: 'string' }) - } - /** `[Json]` Creates a TemplateLiteral type from template dsl string */ - public TemplateLiteral(templateDsl: T, options?: SchemaOptions): TTemplateLiteralDslParser - /** `[Json]` Creates a TemplateLiteral type */ - public TemplateLiteral(kinds: [...T], options?: SchemaOptions): TTemplateLiteral - /** `[Json]` Creates a TemplateLiteral type */ - public TemplateLiteral(unresolved: unknown, options: SchemaOptions = {}) { - // prettier-ignore - const pattern = ValueGuard.IsString(unresolved) - ? TemplateLiteralPattern.Create(TemplateLiteralDslParser.Parse(unresolved)) - : TemplateLiteralPattern.Create(unresolved as TTemplateLiteralKind[]) - return this.Create({ ...options, [Kind]: 'TemplateLiteral', type: 'string', pattern }) - } - /** `[Json]` Creates a Transform type */ - public Transform(schema: I): TransformDecodeBuilder { - return new TransformDecodeBuilder(schema) - } - /** `[Json]` Creates a Tuple type */ - public Tuple(items: [...T], options: SchemaOptions = {}): TTuple { - const [additionalItems, minItems, maxItems] = [false, items.length, items.length] - const clonedItems = TypeClone.Rest(items) - // prettier-ignore - const schema = (items.length > 0 ? - { ...options, [Kind]: 'Tuple', type: 'array', items: clonedItems, additionalItems, minItems, maxItems } : - { ...options, [Kind]: 'Tuple', type: 'array', minItems, maxItems }) as any - return this.Create(schema) - } - /** `[Json]` Intrinsic function to Uncapitalize LiteralString types */ - public Uncapitalize(schema: T, options: SchemaOptions = {}): TIntrinsic { - return { ...Intrinsic.Map(TypeClone.Type(schema), 'Uncapitalize'), ...options } - } - /** `[Json]` Creates a Union type */ - public Union(anyOf: [], options?: SchemaOptions): TNever - /** `[Json]` Creates a Union type */ - public Union(anyOf: [...T], options?: SchemaOptions): T[0] - /** `[Json]` Creates a Union type */ - public Union(anyOf: [...T], options?: SchemaOptions): TUnion - /** `[Json-Experimental]` Converts a TemplateLiteral into a Union */ - public Union(template: T): TUnionTemplateLiteral - /** `[Json]` Creates a Union type */ - public Union(union: TSchema[] | TTemplateLiteral, options: SchemaOptions = {}) { - // prettier-ignore - return TypeGuard.TTemplateLiteral(union) - ? TemplateLiteralResolver.Resolve(union) - : (() => { - const anyOf = union - if (anyOf.length === 0) return this.Never(options) - if (anyOf.length === 1) return this.Create(TypeClone.Type(anyOf[0], options)) - const clonedAnyOf = TypeClone.Rest(anyOf) - return this.Create({ ...options, [Kind]: 'Union', anyOf: clonedAnyOf }) - })() - } - /** `[Json]` Creates an Unknown type */ - public Unknown(options: SchemaOptions = {}): TUnknown { - return this.Create({ ...options, [Kind]: 'Unknown' }) - } - /** `[Json]` Creates a Unsafe type that will infers as the generic argument T */ - public Unsafe(options: UnsafeOptions = {}): TUnsafe { - return this.Create({ ...options, [Kind]: options[Kind] || 'Unsafe' }) - } - /** `[Json]` Intrinsic function to Uppercase LiteralString types */ - public Uppercase(schema: T, options: SchemaOptions = {}): TIntrinsic { - return { ...Intrinsic.Map(TypeClone.Type(schema), 'Uppercase'), ...options } - } -} -// -------------------------------------------------------------------------- -// JavaScriptTypeBuilder -// -------------------------------------------------------------------------- -export class JavaScriptTypeBuilder extends JsonTypeBuilder { - /** `[JavaScript]` Creates a AsyncIterator type */ - public AsyncIterator(items: T, options: SchemaOptions = {}): TAsyncIterator { - return this.Create({ ...options, [Kind]: 'AsyncIterator', type: 'AsyncIterator', items: TypeClone.Type(items) }) - } - /** `[JavaScript]` Constructs a type by recursively unwrapping Promise types */ - public Awaited(schema: T, options: SchemaOptions = {}): TAwaited { - // prettier-ignore - const Unwrap = (rest: TSchema[]): TSchema[] => rest.length > 0 ? (() => { - const [L, ...R] = rest - return [this.Awaited(L), ...Unwrap(R)] - })() : rest - // prettier-ignore - return ( - TypeGuard.TIntersect(schema) ? Type.Intersect(Unwrap(schema.allOf)) : - TypeGuard.TUnion(schema) ? Type.Union(Unwrap(schema.anyOf)) : - TypeGuard.TPromise(schema) ? this.Awaited(schema.item) : - TypeClone.Type(schema, options) - ) as TAwaited - } - /** `[JavaScript]` Creates a BigInt type */ - public BigInt(options: NumericOptions = {}): TBigInt { - return this.Create({ ...options, [Kind]: 'BigInt', type: 'bigint' }) - } - /** `[JavaScript]` Extracts the ConstructorParameters from the given Constructor type */ - public ConstructorParameters>(schema: T, options: SchemaOptions = {}): TConstructorParameters { - return this.Tuple([...schema.parameters], { ...options }) - } - /** `[JavaScript]` Creates a Constructor type */ - public Constructor(parameters: [...T], returns: U, options?: SchemaOptions): TConstructor { - const [clonedParameters, clonedReturns] = [TypeClone.Rest(parameters), TypeClone.Type(returns)] - return this.Create({ ...options, [Kind]: 'Constructor', type: 'Constructor', parameters: clonedParameters, returns: clonedReturns }) - } - /** `[JavaScript]` Creates a Date type */ - public Date(options: DateOptions = {}): TDate { - return this.Create({ ...options, [Kind]: 'Date', type: 'Date' }) - } - /** `[JavaScript]` Creates a Function type */ - public Function(parameters: [...T], returns: U, options?: SchemaOptions): TFunction { - const [clonedParameters, clonedReturns] = [TypeClone.Rest(parameters), TypeClone.Type(returns)] - return this.Create({ ...options, [Kind]: 'Function', type: 'Function', parameters: clonedParameters, returns: clonedReturns }) - } - /** `[JavaScript]` Extracts the InstanceType from the given Constructor type */ - public InstanceType>(schema: T, options: SchemaOptions = {}): TInstanceType { - return TypeClone.Type(schema.returns, options) - } - /** `[JavaScript]` Creates an Iterator type */ - public Iterator(items: T, options: SchemaOptions = {}): TIterator { - return this.Create({ ...options, [Kind]: 'Iterator', type: 'Iterator', items: TypeClone.Type(items) }) - } - /** `[JavaScript]` Extracts the Parameters from the given Function type */ - public Parameters>(schema: T, options: SchemaOptions = {}): TParameters { - return this.Tuple(schema.parameters, { ...options }) - } - /** `[JavaScript]` Creates a Promise type */ - public Promise(item: T, options: SchemaOptions = {}): TPromise { - return this.Create({ ...options, [Kind]: 'Promise', type: 'Promise', item: TypeClone.Type(item) }) - } - /** `[JavaScript]` Creates a String type from a Regular Expression pattern */ - public RegExp(pattern: string, options?: SchemaOptions): TString - /** `[JavaScript]` Creates a String type from a Regular Expression */ - public RegExp(regex: RegExp, options?: SchemaOptions): TString - /** `[Extended]` Creates a String type */ - public RegExp(unresolved: string | RegExp, options: SchemaOptions = {}) { - const pattern = ValueGuard.IsString(unresolved) ? unresolved : unresolved.source - return this.Create({ ...options, [Kind]: 'String', type: 'string', pattern }) - } - /** - * @deprecated Use `Type.RegExp` - */ - public RegEx(regex: RegExp, options: SchemaOptions = {}): TString { - return this.RegExp(regex, options) - } - /** `[JavaScript]` Extracts the ReturnType from the given Function type */ - public ReturnType>(schema: T, options: SchemaOptions = {}): TReturnType { - return TypeClone.Type(schema.returns, options) - } - /** `[JavaScript]` Creates a Symbol type */ - public Symbol(options?: SchemaOptions): TSymbol { - return this.Create({ ...options, [Kind]: 'Symbol', type: 'symbol' }) - } - /** `[JavaScript]` Creates a Undefined type */ - public Undefined(options: SchemaOptions = {}): TUndefined { - return this.Create({ ...options, [Kind]: 'Undefined', type: 'undefined' }) - } - /** `[JavaScript]` Creates a Uint8Array type */ - public Uint8Array(options: Uint8ArrayOptions = {}): TUint8Array { - return this.Create({ ...options, [Kind]: 'Uint8Array', type: 'Uint8Array' }) - } - /** `[JavaScript]` Creates a Void type */ - public Void(options: SchemaOptions = {}): TVoid { - return this.Create({ ...options, [Kind]: 'Void', type: 'void' }) - } -} -/** Json Type Builder with Static Resolution for TypeScript */ -export const JsonType = new JsonTypeBuilder() -/** JavaScript Type Builder with Static Resolution for TypeScript */ -export const Type = new JavaScriptTypeBuilder() diff --git a/src/value/cast.ts b/src/value/cast.ts index 16e3ec9cf..fb2cb60dc 100644 --- a/src/value/cast.ts +++ b/src/value/cast.ts @@ -27,31 +27,32 @@ THE SOFTWARE. ---------------------------------------------------------------------------*/ import { IsPlainObject, IsArray, IsString, IsNumber, IsNull } from './guard' +import { TypeRegistry } from '../type/registry/index' +import * as Types from '../type/index' import { Create } from './create' import { Check } from './check' import { Clone } from './clone' import { Deref } from './deref' -import * as Types from '../typebox' // -------------------------------------------------------------------------- // Errors // -------------------------------------------------------------------------- -export class ValueCastArrayUniqueItemsTypeError extends Types.TypeBoxError { +export class ValueCastArrayUniqueItemsTypeError extends Error { constructor(public readonly schema: Types.TSchema, public readonly value: unknown) { super('Array cast produced invalid data due to uniqueItems constraint') } } -export class ValueCastNeverTypeError extends Types.TypeBoxError { +export class ValueCastNeverTypeError extends Error { constructor(public readonly schema: Types.TSchema) { super('Never types cannot be cast') } } -export class ValueCastRecursiveTypeError extends Types.TypeBoxError { +export class ValueCastRecursiveTypeError extends Error { constructor(public readonly schema: Types.TSchema) { super('Cannot cast recursive schemas') } } -export class ValueCastUnknownTypeError extends Types.TypeBoxError { +export class ValueCastUnknownTypeError extends Error { constructor(public readonly schema: Types.TSchema) { super('Unknown type') } @@ -65,13 +66,13 @@ export class ValueCastUnknownTypeError extends Types.TypeBoxError { // -------------------------------------------------------------------------- namespace UnionCastCreate { function Score(schema: Types.TSchema, references: Types.TSchema[], value: any): number { - if (schema[Types.Kind] === 'Object' && typeof value === 'object' && !IsNull(value)) { + if (schema[Types.Symbols.Kind] === 'Object' && typeof value === 'object' && !IsNull(value)) { const object = schema as Types.TObject const keys = Object.getOwnPropertyNames(value) const entries = Object.entries(object.properties) const [point, max] = [1 / entries.length, entries.length] return entries.reduce((acc, [key, schema]) => { - const literal = schema[Types.Kind] === 'Literal' && schema.const === value[key] ? max : 0 + const literal = schema[Types.Symbols.Kind] === 'Literal' && schema.const === value[key] ? max : 0 const checks = Check(schema, references, value[key]) ? point : 0 const exists = keys.includes(key) ? point : 0 return acc + (literal + checks + exists) @@ -189,7 +190,7 @@ function TUnion(schema: Types.TUnion, references: Types.TSchema[], value: any): function Visit(schema: Types.TSchema, references: Types.TSchema[], value: any): any { const references_ = IsString(schema.$id) ? [...references, schema] : references const schema_ = schema as any - switch (schema[Types.Kind]) { + switch (schema[Types.Symbols.Kind]) { // ------------------------------------------------------ // Structural // ------------------------------------------------------ @@ -242,7 +243,7 @@ function Visit(schema: Types.TSchema, references: Types.TSchema[], value: any): case 'Void': return Default(schema_, references_, value) default: - if (!Types.TypeRegistry.Has(schema_[Types.Kind])) throw new ValueCastUnknownTypeError(schema_) + if (!TypeRegistry.Has(schema_[Types.Symbols.Kind])) throw new ValueCastUnknownTypeError(schema_) return Default(schema_, references_, value) } } diff --git a/src/value/check.ts b/src/value/check.ts index 7e987708c..f661cb114 100644 --- a/src/value/check.ts +++ b/src/value/check.ts @@ -30,12 +30,12 @@ import { IsArray, IsUint8Array, IsDate, IsPromise, IsFunction, IsAsyncIterator, import { TypeSystemPolicy } from '../system/index' import { Deref } from './deref' import { Hash } from './hash' -import * as Types from '../typebox' +import * as Types from '../type/index' // -------------------------------------------------------------------------- // Errors // -------------------------------------------------------------------------- -export class ValueCheckUnknownTypeError extends Types.TypeBoxError { +export class ValueCheckUnknownTypeError extends Error { constructor(public readonly schema: Types.TSchema) { super(`Unknown type`) } @@ -44,7 +44,7 @@ export class ValueCheckUnknownTypeError extends Types.TypeBoxError { // TypeGuards // -------------------------------------------------------------------------- function IsAnyOrUnknown(schema: Types.TSchema) { - return schema[Types.Kind] === 'Any' || schema[Types.Kind] === 'Unknown' + return schema[Types.Symbols.Kind] === 'Any' || schema[Types.Symbols.Kind] === 'Unknown' } // -------------------------------------------------------------------------- // Guards @@ -164,11 +164,11 @@ function TInteger(schema: Types.TInteger, references: Types.TSchema[], value: an function TIntersect(schema: Types.TIntersect, references: Types.TSchema[], value: any): boolean { const check1 = schema.allOf.every((schema) => Visit(schema, references, value)) if (schema.unevaluatedProperties === false) { - const keyPattern = new RegExp(Types.KeyResolver.ResolvePattern(schema)) + const keyPattern = new RegExp(Types.KeyOfStringResolvePattern(schema)) const check2 = Object.getOwnPropertyNames(value).every((key) => keyPattern.test(key)) return check1 && check2 } else if (Types.TypeGuard.TSchema(schema.unevaluatedProperties)) { - const keyCheck = new RegExp(Types.KeyResolver.ResolvePattern(schema)) + const keyCheck = new RegExp(Types.KeyOfStringResolvePattern(schema)) const check2 = Object.getOwnPropertyNames(value).every((key) => keyCheck.test(key) || Visit(schema.unevaluatedProperties as Types.TSchema, references, value[key])) return check1 && check2 } else { @@ -224,7 +224,7 @@ function TObject(schema: Types.TObject, references: Types.TSchema[], value: any) if (!Visit(property, references, value[knownKey])) { return false } - if ((Types.ExtendsUndefined.Check(property) || IsAnyOrUnknown(property)) && !(knownKey in value)) { + if ((Types.ExtendsUndefinedCheck(property) || IsAnyOrUnknown(property)) && !(knownKey in value)) { return false } } else { @@ -355,14 +355,14 @@ function TVoid(schema: Types.TVoid, references: Types.TSchema[], value: any): bo return TypeSystemPolicy.IsVoidLike(value) } function TKind(schema: Types.TSchema, references: Types.TSchema[], value: unknown): boolean { - if (!Types.TypeRegistry.Has(schema[Types.Kind])) return false - const func = Types.TypeRegistry.Get(schema[Types.Kind])! + if (!Types.TypeRegistry.Has(schema[Types.Symbols.Kind])) return false + const func = Types.TypeRegistry.Get(schema[Types.Symbols.Kind])! return func(schema, value) } function Visit(schema: T, references: Types.TSchema[], value: any): boolean { const references_ = IsDefined(schema.$id) ? [...references, schema] : references const schema_ = schema as any - switch (schema_[Types.Kind]) { + switch (schema_[Types.Symbols.Kind]) { case 'Any': return TAny(schema_, references_, value) case 'Array': @@ -424,7 +424,7 @@ function Visit(schema: T, references: Types.TSchema[], case 'Void': return TVoid(schema_, references_, value) default: - if (!Types.TypeRegistry.Has(schema_[Types.Kind])) throw new ValueCheckUnknownTypeError(schema_) + if (!Types.TypeRegistry.Has(schema_[Types.Symbols.Kind])) throw new ValueCheckUnknownTypeError(schema_) return TKind(schema_, references_, value) } } diff --git a/src/value/convert.ts b/src/value/convert.ts index 60ba2e1f3..b1142f61d 100644 --- a/src/value/convert.ts +++ b/src/value/convert.ts @@ -30,12 +30,12 @@ import { IsArray, IsObject, IsDate, IsUndefined, IsString, IsNumber, IsBoolean, import { Clone } from './clone' import { Check } from './check' import { Deref } from './deref' -import * as Types from '../typebox' +import * as Types from '../type/index' // -------------------------------------------------------------------------- // Errors // -------------------------------------------------------------------------- -export class ValueConvertUnknownTypeError extends Types.TypeBoxError { +export class ValueConvertUnknownTypeError extends Error { constructor(public readonly schema: Types.TSchema) { super('Unknown type') } @@ -239,7 +239,7 @@ function TUnion(schema: Types.TUnion, references: Types.TSchema[], value: any): function Visit(schema: Types.TSchema, references: Types.TSchema[], value: any): unknown { const references_ = IsString(schema.$id) ? [...references, schema] : references const schema_ = schema as any - switch (schema[Types.Kind]) { + switch (schema[Types.Symbols.Kind]) { // ------------------------------------------------------ // Structural // ------------------------------------------------------ @@ -279,23 +279,7 @@ function Visit(schema: Types.TSchema, references: Types.TSchema[], value: any): return TUndefined(schema_, references_, value) case 'Union': return TUnion(schema_, references_, value) - // ------------------------------------------------------ - // Default - // ------------------------------------------------------ - case 'Any': - case 'AsyncIterator': - case 'Constructor': - case 'Function': - case 'Iterator': - case 'Never': - case 'Promise': - case 'TemplateLiteral': - case 'Uint8Array': - case 'Unknown': - case 'Void': - return Default(value) default: - if (!Types.TypeRegistry.Has(schema_[Types.Kind])) throw new ValueConvertUnknownTypeError(schema_) return Default(value) } } diff --git a/src/value/create.ts b/src/value/create.ts index b36b42f41..a1fa03541 100644 --- a/src/value/create.ts +++ b/src/value/create.ts @@ -29,37 +29,37 @@ THE SOFTWARE. import { HasPropertyKey, IsString } from './guard' import { Check } from './check' import { Deref } from './deref' -import * as Types from '../typebox' +import * as Types from '../type/index' // -------------------------------------------------------------------------- // Errors // -------------------------------------------------------------------------- -export class ValueCreateUnknownTypeError extends Types.TypeBoxError { +export class ValueCreateUnknownTypeError extends Error { constructor(public readonly schema: Types.TSchema) { super('Unknown type') } } -export class ValueCreateNeverTypeError extends Types.TypeBoxError { +export class ValueCreateNeverTypeError extends Error { constructor(public readonly schema: Types.TSchema) { super('Never types cannot be created') } } -export class ValueCreateNotTypeError extends Types.TypeBoxError { +export class ValueCreateNotTypeError extends Error { constructor(public readonly schema: Types.TSchema) { super('Not types must have a default value') } } -export class ValueCreateIntersectTypeError extends Types.TypeBoxError { +export class ValueCreateIntersectTypeError extends Error { constructor(public readonly schema: Types.TSchema) { super('Intersect produced invalid value. Consider using a default value.') } } -export class ValueCreateTempateLiteralTypeError extends Types.TypeBoxError { +export class ValueCreateTempateLiteralTypeError extends Error { constructor(public readonly schema: Types.TSchema) { super('Can only create template literal values from patterns that produce finite sequences. Consider using a default value.') } } -export class ValueCreateRecursiveInstantiationError extends Types.TypeBoxError { +export class ValueCreateRecursiveInstantiationError extends Error { constructor(public readonly schema: Types.TSchema, public readonly recursiveMaxDepth: number) { super('Value cannot be created as recursive type may produce value of infinite size. Consider using a default.') } @@ -287,9 +287,9 @@ function TTemplateLiteral(schema: Types.TTemplateLiteral, references: Types.TSch if (HasPropertyKey(schema, 'default')) { return schema.default } - const expression = Types.TemplateLiteralParser.ParseExact(schema.pattern) - if (!Types.TemplateLiteralFinite.Check(expression)) throw new ValueCreateTempateLiteralTypeError(schema) - const sequence = Types.TemplateLiteralGenerator.Generate(expression) + const expression = Types.TemplateLiteralParseExact(schema.pattern) + if (!Types.IsTemplateLiteralFinite(expression)) throw new ValueCreateTempateLiteralTypeError(schema) + const sequence = Types.TemplateLiteralGenerate(expression) return sequence.next().value } function TThis(schema: Types.TThis, references: Types.TSchema[]): any { @@ -359,7 +359,7 @@ function TKind(schema: Types.TSchema, references: Types.TSchema[]): any { function Visit(schema: Types.TSchema, references: Types.TSchema[]): unknown { const references_ = IsString(schema.$id) ? [...references, schema] : references const schema_ = schema as any - switch (schema_[Types.Kind]) { + switch (schema_[Types.Symbols.Kind]) { case 'Any': return TAny(schema_, references_) case 'Array': @@ -421,7 +421,7 @@ function Visit(schema: Types.TSchema, references: Types.TSchema[]): unknown { case 'Void': return TVoid(schema_, references_) default: - if (!Types.TypeRegistry.Has(schema_[Types.Kind])) throw new ValueCreateUnknownTypeError(schema_) + if (!Types.TypeRegistry.Has(schema_[Types.Symbols.Kind])) throw new ValueCreateUnknownTypeError(schema_) return TKind(schema_, references_) } } diff --git a/src/value/delta.ts b/src/value/delta.ts index 5a2092dc0..d92ae194d 100644 --- a/src/value/delta.ts +++ b/src/value/delta.ts @@ -28,7 +28,7 @@ THE SOFTWARE. import { IsPlainObject, IsArray, IsTypedArray, IsValueType, IsSymbol, IsUndefined } from './guard' import type { ObjectType, ArrayType, TypedArrayType, ValueType } from './guard' -import { Type, Static } from '../typebox' +import { Type, Static } from '../type/index' import { ValuePointer } from './pointer' import { Clone } from './clone' diff --git a/src/value/deref.ts b/src/value/deref.ts index cf9ebd798..0ed6fc045 100644 --- a/src/value/deref.ts +++ b/src/value/deref.ts @@ -26,9 +26,9 @@ THE SOFTWARE. ---------------------------------------------------------------------------*/ -import { TypeBoxError, TSchema, TRef, TThis } from '../typebox' +import { TSchema, TRef, TThis } from '../type/index' -export class TypeDereferenceError extends TypeBoxError { +export class TypeDereferenceError extends Error { constructor(public readonly schema: TRef | TThis) { super(`Unable to dereference schema with $id '${schema.$id}'`) } diff --git a/src/value/transform.ts b/src/value/transform.ts index bb377f9a1..726375aee 100644 --- a/src/value/transform.ts +++ b/src/value/transform.ts @@ -30,27 +30,27 @@ import { IsString, IsPlainObject, IsArray, IsValueType, IsUndefined } from './gu import { ValueError } from '../errors/errors' import { Deref } from './deref' import { Check } from './check' -import * as Types from '../typebox' - +import * as Types from '../type/index' +Types.TypeGuard // ------------------------------------------------------------------------- // Errors // ------------------------------------------------------------------------- -export class TransformDecodeCheckError extends Types.TypeBoxError { +export class TransformDecodeCheckError extends Error { constructor(public readonly schema: Types.TSchema, public readonly value: unknown, public readonly error: ValueError) { super(`Unable to decode due to invalid value`) } } -export class TransformEncodeCheckError extends Types.TypeBoxError { +export class TransformEncodeCheckError extends Error { constructor(public readonly schema: Types.TSchema, public readonly value: unknown, public readonly error: ValueError) { super(`Unable to encode due to invalid value`) } } -export class TransformDecodeError extends Types.TypeBoxError { +export class TransformDecodeError extends Error { constructor(public readonly schema: Types.TSchema, public readonly value: unknown, error: any) { super(`${error instanceof Error ? error.message : 'Unknown error'}`) } } -export class TransformEncodeError extends Types.TypeBoxError { +export class TransformEncodeError extends Error { constructor(public readonly schema: Types.TSchema, public readonly value: unknown, error: any) { super(`${error instanceof Error ? error.message : 'Unknown error'}`) } @@ -113,7 +113,7 @@ export namespace HasTransform { const schema_ = schema as any if (schema.$id && visited.has(schema.$id)) return false if (schema.$id) visited.add(schema.$id) - switch (schema[Types.Kind]) { + switch (schema[Types.Symbols.Kind]) { case 'Array': return TArray(schema_, references_) case 'AsyncIterator': @@ -160,7 +160,7 @@ export namespace HasTransform { export namespace DecodeTransform { function Default(schema: Types.TSchema, value: any) { try { - return Types.TypeGuard.TTransform(schema) ? schema[Types.Transform].Decode(value) : value + return Types.TypeGuard.TTransform(schema) ? schema[Types.Symbols.Transform].Decode(value) : value } catch (error) { throw new TransformDecodeError(schema, value, error) } @@ -174,10 +174,10 @@ export namespace DecodeTransform { // prettier-ignore function TIntersect(schema: Types.TIntersect, references: Types.TSchema[], value: any) { if (!IsPlainObject(value) || IsValueType(value)) return Default(schema, value) - const knownKeys = Types.KeyResolver.ResolveKeys(schema, { includePatterns: false }) + const knownKeys = Types.KeyOfStringResolve(schema) as string[] const knownProperties = knownKeys.reduce((value, key) => { return (key in value) - ? { ...value, [key]: Visit(Types.IndexedAccessor.Resolve(schema, [key]), references, value[key]) } + ? { ...value, [key]: Visit(Types.IndexedTypeResolve(schema, [key]), references, value[key]) } : value }, value) if (!Types.TypeGuard.TTransform(schema.unevaluatedProperties)) { @@ -198,7 +198,7 @@ export namespace DecodeTransform { // prettier-ignore function TObject(schema: Types.TObject, references: Types.TSchema[], value: any) { if (!IsPlainObject(value)) return Default(schema, value) - const knownKeys = Types.KeyResolver.ResolveKeys(schema, { includePatterns: false }) + const knownKeys = Types.KeyOfStringResolve(schema) const knownProperties = knownKeys.reduce((value, key) => { return (key in value) ? { ...value, [key]: Visit(schema.properties[key], references, value[key]) } @@ -263,7 +263,7 @@ export namespace DecodeTransform { function Visit(schema: Types.TSchema, references: Types.TSchema[], value: any): any { const references_ = typeof schema.$id === 'string' ? [...references, schema] : references const schema_ = schema as any - switch (schema[Types.Kind]) { + switch (schema[Types.Symbols.Kind]) { case 'Array': return TArray(schema_, references_, value) case 'Intersect': @@ -299,7 +299,7 @@ export namespace DecodeTransform { export namespace EncodeTransform { function Default(schema: Types.TSchema, value: any) { try { - return Types.TypeGuard.TTransform(schema) ? schema[Types.Transform].Encode(value) : value + return Types.TypeGuard.TTransform(schema) ? schema[Types.Symbols.Transform].Encode(value) : value } catch (error) { throw new TransformEncodeError(schema, value, error) } @@ -315,10 +315,10 @@ export namespace EncodeTransform { function TIntersect(schema: Types.TIntersect, references: Types.TSchema[], value: any) { const defaulted = Default(schema, value) if (!IsPlainObject(value) || IsValueType(value)) return defaulted - const knownKeys = Types.KeyResolver.ResolveKeys(schema, { includePatterns: false }) + const knownKeys = Types.KeyOfStringResolve(schema) as string[] const knownProperties = knownKeys.reduce((value, key) => { return key in defaulted - ? { ...value, [key]: Visit(Types.IndexedAccessor.Resolve(schema, [key]), references, value[key]) } + ? { ...value, [key]: Visit(Types.IndexedTypeResolve(schema, [key]), references, value[key]) } : value }, defaulted) if (!Types.TypeGuard.TTransform(schema.unevaluatedProperties)) { @@ -339,7 +339,7 @@ export namespace EncodeTransform { function TObject(schema: Types.TObject, references: Types.TSchema[], value: any) { const defaulted = Default(schema, value) if (!IsPlainObject(value)) return defaulted - const knownKeys = Types.KeyResolver.ResolveKeys(schema, { includePatterns: false }) + const knownKeys = Types.KeyOfStringResolve(schema) as string[] const knownProperties = knownKeys.reduce((value, key) => { return key in value ? { ...value, [key]: Visit(schema.properties[key], references, value[key]) } @@ -410,7 +410,7 @@ export namespace EncodeTransform { function Visit(schema: Types.TSchema, references: Types.TSchema[], value: any): any { const references_ = typeof schema.$id === 'string' ? [...references, schema] : references const schema_ = schema as any - switch (schema[Types.Kind]) { + switch (schema[Types.Symbols.Kind]) { case 'Array': return TArray(schema_, references_, value) case 'Intersect': diff --git a/src/value/value.ts b/src/value/value.ts index 9cf27168b..86cf8f457 100644 --- a/src/value/value.ts +++ b/src/value/value.ts @@ -37,7 +37,7 @@ import * as ValueCreate from './create' import * as ValueCheck from './check' import * as ValueDelta from './delta' import * as ValueTransform from './transform' -import * as Types from '../typebox' +import * as Types from '../type/index' /** Functions to perform structural operations on JavaScript values */ export namespace Value { diff --git a/test/runtime/compiler-ajv/partial.ts b/test/runtime/compiler-ajv/partial.ts index 5e56d704a..7c8777f86 100644 --- a/test/runtime/compiler-ajv/partial.ts +++ b/test/runtime/compiler-ajv/partial.ts @@ -1,4 +1,4 @@ -import { Type, Readonly, Optional } from '@sinclair/typebox' +import { Type, Symbols } from '@sinclair/typebox' import { Ok } from './validate' import { Assert } from '../assert' @@ -29,12 +29,12 @@ describe('compiler-ajv/Partial', () => { { additionalProperties: false }, ) const T = Type.Partial(A) - Assert.IsEqual(T.properties.x[Readonly], 'Readonly') - Assert.IsEqual(T.properties.x[Optional], 'Optional') - Assert.IsEqual(T.properties.y[Readonly], 'Readonly') - Assert.IsEqual(T.properties.y[Optional], 'Optional') - Assert.IsEqual(T.properties.z[Optional], 'Optional') - Assert.IsEqual(T.properties.w[Optional], 'Optional') + Assert.IsEqual(T.properties.x[Symbols.Readonly], 'Readonly') + Assert.IsEqual(T.properties.x[Symbols.Optional], 'Optional') + Assert.IsEqual(T.properties.y[Symbols.Readonly], 'Readonly') + Assert.IsEqual(T.properties.y[Symbols.Optional], 'Optional') + Assert.IsEqual(T.properties.z[Symbols.Optional], 'Optional') + Assert.IsEqual(T.properties.w[Symbols.Optional], 'Optional') }) it('Should inherit options from the source object', () => { const A = Type.Object( diff --git a/test/runtime/compiler-ajv/required.ts b/test/runtime/compiler-ajv/required.ts index 7df4b1875..0a51e9a73 100644 --- a/test/runtime/compiler-ajv/required.ts +++ b/test/runtime/compiler-ajv/required.ts @@ -1,4 +1,4 @@ -import { Type, Readonly, Optional } from '@sinclair/typebox' +import { Type, Symbols } from '@sinclair/typebox' import { Ok, Fail } from './validate' import { Assert } from '../assert' @@ -26,10 +26,10 @@ describe('compiler-ajv/Required', () => { w: Type.Number(), }) const T = Type.Required(A) - Assert.IsEqual(T.properties.x[Readonly], 'Readonly') - Assert.IsEqual(T.properties.y[Readonly], 'Readonly') - Assert.IsEqual(T.properties.z[Optional], undefined) - Assert.IsEqual(T.properties.w[Optional], undefined) + Assert.IsEqual(T.properties.x[Symbols.Readonly], 'Readonly') + Assert.IsEqual(T.properties.y[Symbols.Readonly], 'Readonly') + Assert.IsEqual(T.properties.z[Symbols.Optional], undefined) + Assert.IsEqual(T.properties.w[Symbols.Optional], undefined) }) it('Should inherit options from the source object', () => { const A = Type.Object( diff --git a/test/runtime/compiler/kind.ts b/test/runtime/compiler/kind.ts index 1f0274b00..6853b30f5 100644 --- a/test/runtime/compiler/kind.ts +++ b/test/runtime/compiler/kind.ts @@ -1,4 +1,4 @@ -import { TypeRegistry, Type, Kind, TSchema } from '@sinclair/typebox' +import { TypeRegistry, Type, Symbols, TSchema } from '@sinclair/typebox' import { TypeCompiler } from '@sinclair/typebox/compiler' import { Ok, Fail } from './validate' import { Assert } from '../assert' @@ -13,39 +13,39 @@ describe('compiler/Kind', () => { // Tests // ------------------------------------------------------------ it('Should validate', () => { - const T = Type.Unsafe({ [Kind]: 'PI' }) + const T = Type.Unsafe({ [Symbols.Kind]: 'PI' }) Ok(T, Math.PI) }) it('Should not validate', () => { - const T = Type.Unsafe({ [Kind]: 'PI' }) + const T = Type.Unsafe({ [Symbols.Kind]: 'PI' }) Fail(T, Math.PI * 2) }) it('Should validate in object', () => { const T = Type.Object({ - x: Type.Unsafe({ [Kind]: 'PI' }), + x: Type.Unsafe({ [Symbols.Kind]: 'PI' }), }) Ok(T, { x: Math.PI }) }) it('Should not validate in object', () => { const T = Type.Object({ - x: Type.Unsafe({ [Kind]: 'PI' }), + x: Type.Unsafe({ [Symbols.Kind]: 'PI' }), }) Fail(T, { x: Math.PI * 2 }) }) it('Should validate in array', () => { - const T = Type.Array(Type.Unsafe({ [Kind]: 'PI' })) + const T = Type.Array(Type.Unsafe({ [Symbols.Kind]: 'PI' })) Ok(T, [Math.PI]) }) it('Should not validate in array', () => { - const T = Type.Array(Type.Unsafe({ [Kind]: 'PI' })) + const T = Type.Array(Type.Unsafe({ [Symbols.Kind]: 'PI' })) Fail(T, [Math.PI * 2]) }) it('Should validate in tuple', () => { - const T = Type.Tuple([Type.Unsafe({ [Kind]: 'PI' })]) + const T = Type.Tuple([Type.Unsafe({ [Symbols.Kind]: 'PI' })]) Ok(T, [Math.PI]) }) it('Should not validate in tuple', () => { - const T = Type.Tuple([Type.Unsafe({ [Kind]: 'PI' })]) + const T = Type.Tuple([Type.Unsafe({ [Symbols.Kind]: 'PI' })]) Fail(T, [Math.PI * 2]) }) // ------------------------------------------------------------ @@ -55,12 +55,12 @@ describe('compiler/Kind', () => { const stack: string[] = [] TypeRegistry.Set('Kind', (schema: unknown) => { // prettier-ignore - return (typeof schema === 'object' && schema !== null && Kind in schema && schema[Kind] === 'Kind' && '$id' in schema && typeof schema.$id === 'string') + return (typeof schema === 'object' && schema !== null && Symbols.Kind in schema && schema[Symbols.Kind] === 'Kind' && '$id' in schema && typeof schema.$id === 'string') ? (() => { stack.push(schema.$id); return true })() : false }) - const A = { [Kind]: 'Kind', $id: 'A' } as TSchema - const B = { [Kind]: 'Kind', $id: 'B' } as TSchema + const A = { [Symbols.Kind]: 'Kind', $id: 'A' } as TSchema + const B = { [Symbols.Kind]: 'Kind', $id: 'B' } as TSchema const T = Type.Object({ a: A, b: B }) const C = TypeCompiler.Compile(T) const R = C.Check({ a: null, b: null }) @@ -76,14 +76,14 @@ describe('compiler/Kind', () => { let stack: string[] = [] TypeRegistry.Set('Kind', (schema: unknown) => { // prettier-ignore - return (typeof schema === 'object' && schema !== null && Kind in schema && schema[Kind] === 'Kind' && '$id' in schema && typeof schema.$id === 'string') + return (typeof schema === 'object' && schema !== null && Symbols.Kind in schema && schema[Symbols.Kind] === 'Kind' && '$id' in schema && typeof schema.$id === 'string') ? (() => { stack.push(schema.$id); return true })() : false }) - const A = { [Kind]: 'Kind', $id: 'A' } as TSchema - const B = { [Kind]: 'Kind', $id: 'B' } as TSchema - const C = { [Kind]: 'Kind', $id: 'C' } as TSchema - const D = { [Kind]: 'Kind', $id: 'D' } as TSchema + const A = { [Symbols.Kind]: 'Kind', $id: 'A' } as TSchema + const B = { [Symbols.Kind]: 'Kind', $id: 'B' } as TSchema + const C = { [Symbols.Kind]: 'Kind', $id: 'C' } as TSchema + const D = { [Symbols.Kind]: 'Kind', $id: 'D' } as TSchema const T1 = Type.Object({ a: A, b: B }) const T2 = Type.Object({ a: C, b: D }) diff --git a/test/runtime/compiler/partial.ts b/test/runtime/compiler/partial.ts index 870e6979b..3b13dab15 100644 --- a/test/runtime/compiler/partial.ts +++ b/test/runtime/compiler/partial.ts @@ -1,5 +1,5 @@ import { TypeSystem } from '@sinclair/typebox/system' -import { Type, Kind, Optional, Readonly } from '@sinclair/typebox' +import { Type, Symbols, Optional, Readonly } from '@sinclair/typebox' import { Ok, Fail } from './validate' import { strictEqual } from 'assert' @@ -30,12 +30,12 @@ describe('compiler/Partial', () => { { additionalProperties: false }, ) const T = Type.Partial(A) - strictEqual(T.properties.x[Readonly], 'Readonly') - strictEqual(T.properties.x[Optional], 'Optional') - strictEqual(T.properties.y[Readonly], 'Readonly') - strictEqual(T.properties.y[Optional], 'Optional') - strictEqual(T.properties.z[Optional], 'Optional') - strictEqual(T.properties.w[Optional], 'Optional') + strictEqual(T.properties.x[Symbols.Readonly], 'Readonly') + strictEqual(T.properties.x[Symbols.Optional], 'Optional') + strictEqual(T.properties.y[Symbols.Readonly], 'Readonly') + strictEqual(T.properties.y[Symbols.Optional], 'Optional') + strictEqual(T.properties.z[Symbols.Optional], 'Optional') + strictEqual(T.properties.w[Symbols.Optional], 'Optional') }) it('Should inherit options from the source object', () => { const A = Type.Object( diff --git a/test/runtime/compiler/required.ts b/test/runtime/compiler/required.ts index 14ca1bf5f..39339e7b9 100644 --- a/test/runtime/compiler/required.ts +++ b/test/runtime/compiler/required.ts @@ -1,4 +1,4 @@ -import { Type, Readonly, Optional } from '@sinclair/typebox' +import { Type, Symbols } from '@sinclair/typebox' import { Ok, Fail } from './validate' import { strictEqual } from 'assert' @@ -26,10 +26,10 @@ describe('compiler/Required', () => { w: Type.Number(), }) const T = Type.Required(A) - strictEqual(T.properties.x[Readonly], 'Readonly') - strictEqual(T.properties.y[Readonly], 'Readonly') - strictEqual(T.properties.z[Optional], undefined) - strictEqual(T.properties.w[Optional], undefined) + strictEqual(T.properties.x[Symbols.Readonly], 'Readonly') + strictEqual(T.properties.y[Symbols.Readonly], 'Readonly') + strictEqual(T.properties.z[Symbols.Optional], undefined) + strictEqual(T.properties.w[Symbols.Optional], undefined) }) it('Should inherit options from the source object', () => { const A = Type.Object( diff --git a/test/runtime/errors/types/kind.ts b/test/runtime/errors/types/kind.ts index c8865353e..01a53dd0c 100644 --- a/test/runtime/errors/types/kind.ts +++ b/test/runtime/errors/types/kind.ts @@ -1,4 +1,4 @@ -import { TypeRegistry, Kind, TSchema } from '@sinclair/typebox' +import { TypeRegistry, Symbols, TSchema } from '@sinclair/typebox' import { ValueErrorType } from '@sinclair/typebox/errors' import { Resolve } from './resolve' import { Assert } from '../../assert' @@ -12,7 +12,7 @@ describe('errors/type/Kind', () => { // ---------------------------------------------------- // Test // ---------------------------------------------------- - const T = { [Kind]: 'Foo' } as TSchema + const T = { [Symbols.Kind]: 'Foo' } as TSchema it('Should pass 0', () => { const R = Resolve(T, 'foo') Assert.IsEqual(R.length, 0) diff --git a/test/runtime/type/extends/any.ts b/test/runtime/type/extends/any.ts index 3dd3e83ee..1c8294b5c 100644 --- a/test/runtime/type/extends/any.ts +++ b/test/runtime/type/extends/any.ts @@ -1,96 +1,96 @@ -import { TypeExtends, TypeExtendsResult } from '@sinclair/typebox' +import { ExtendsCheck, ExtendsResult } from '@sinclair/typebox/type' import { Type } from '@sinclair/typebox' import { Assert } from '../../assert/index' describe('type/extends/Any', () => { it('Should extend Any', () => { type T = any extends any ? 1 : 2 - const R = TypeExtends.Extends(Type.Any(), Type.Any()) - Assert.IsEqual(R, TypeExtendsResult.True) + const R = ExtendsCheck(Type.Any(), Type.Any()) + Assert.IsEqual(R, ExtendsResult.True) }) it('Should extend Unknown', () => { type T = any extends unknown ? 1 : 2 - const R = TypeExtends.Extends(Type.Any(), Type.Unknown()) - Assert.IsEqual(R, TypeExtendsResult.True) + const R = ExtendsCheck(Type.Any(), Type.Unknown()) + Assert.IsEqual(R, ExtendsResult.True) }) it('Should extend String', () => { type T = any extends string ? 1 : 2 - const R = TypeExtends.Extends(Type.Any(), Type.String()) - Assert.IsEqual(R, TypeExtendsResult.Union) + const R = ExtendsCheck(Type.Any(), Type.String()) + Assert.IsEqual(R, ExtendsResult.Union) }) it('Should extend Boolean', () => { type T = any extends boolean ? 1 : 2 - const R = TypeExtends.Extends(Type.Any(), Type.Boolean()) - Assert.IsEqual(R, TypeExtendsResult.Union) + const R = ExtendsCheck(Type.Any(), Type.Boolean()) + Assert.IsEqual(R, ExtendsResult.Union) }) it('Should extend Number', () => { type T = any extends number ? 1 : 2 - const R = TypeExtends.Extends(Type.Any(), Type.Number()) - Assert.IsEqual(R, TypeExtendsResult.Union) + const R = ExtendsCheck(Type.Any(), Type.Number()) + Assert.IsEqual(R, ExtendsResult.Union) }) it('Should extend Integer', () => { type T = any extends number ? 1 : 2 - const R = TypeExtends.Extends(Type.Any(), Type.Integer()) - Assert.IsEqual(R, TypeExtendsResult.Union) + const R = ExtendsCheck(Type.Any(), Type.Integer()) + Assert.IsEqual(R, ExtendsResult.Union) }) it('Should extend Array 1', () => { type T = any extends Array ? 1 : 2 - const R = TypeExtends.Extends(Type.Any(), Type.Array(Type.Any())) - Assert.IsEqual(R, TypeExtendsResult.Union) + const R = ExtendsCheck(Type.Any(), Type.Array(Type.Any())) + Assert.IsEqual(R, ExtendsResult.Union) }) it('Should extend Array 2', () => { type T = any extends Array ? 1 : 2 - const R = TypeExtends.Extends(Type.Any(), Type.Array(Type.String())) - Assert.IsEqual(R, TypeExtendsResult.Union) + const R = ExtendsCheck(Type.Any(), Type.Array(Type.String())) + Assert.IsEqual(R, ExtendsResult.Union) }) it('Should extend Tuple', () => { type T = any extends [number, number] ? 1 : 2 - const R = TypeExtends.Extends(Type.Any(), Type.Tuple([Type.Number(), Type.Number()])) - Assert.IsEqual(R, TypeExtendsResult.Union) + const R = ExtendsCheck(Type.Any(), Type.Tuple([Type.Number(), Type.Number()])) + Assert.IsEqual(R, ExtendsResult.Union) }) it('Should extend Object 1', () => { type T = any extends object ? 1 : 2 - const R = TypeExtends.Extends(Type.Any(), Type.Object({})) - Assert.IsEqual(R, TypeExtendsResult.Union) + const R = ExtendsCheck(Type.Any(), Type.Object({})) + Assert.IsEqual(R, ExtendsResult.Union) }) it('Should extend Object 2', () => { type T = any extends {} ? 1 : 2 - const R = TypeExtends.Extends(Type.Any(), Type.Object({})) - Assert.IsEqual(R, TypeExtendsResult.Union) + const R = ExtendsCheck(Type.Any(), Type.Object({})) + Assert.IsEqual(R, ExtendsResult.Union) }) it('Should extend Object 3', () => { type T = any extends { a: number } ? 1 : 2 - const R = TypeExtends.Extends(Type.Any(), Type.Object({ a: Type.Number() })) - Assert.IsEqual(R, TypeExtendsResult.Union) + const R = ExtendsCheck(Type.Any(), Type.Object({ a: Type.Number() })) + Assert.IsEqual(R, ExtendsResult.Union) }) it('Should extend Union 1', () => { type T = any extends number | string ? 1 : 2 - const R = TypeExtends.Extends(Type.Any(), Type.Union([Type.Number(), Type.String()])) - Assert.IsEqual(R, TypeExtendsResult.Union) + const R = ExtendsCheck(Type.Any(), Type.Union([Type.Number(), Type.String()])) + Assert.IsEqual(R, ExtendsResult.Union) }) it('Should extend Union 2', () => { type T = any extends any | number ? 1 : 2 - const R = TypeExtends.Extends(Type.Any(), Type.Union([Type.Any(), Type.String()])) - Assert.IsEqual(R, TypeExtendsResult.True) + const R = ExtendsCheck(Type.Any(), Type.Union([Type.Any(), Type.String()])) + Assert.IsEqual(R, ExtendsResult.True) }) it('Should extend Null', () => { type T = any extends null ? 1 : 2 - const R = TypeExtends.Extends(Type.Any(), Type.Null()) - Assert.IsEqual(R, TypeExtendsResult.Union) + const R = ExtendsCheck(Type.Any(), Type.Null()) + Assert.IsEqual(R, ExtendsResult.Union) }) it('Should extend Undefined', () => { type T = any extends undefined ? 1 : 2 - const R = TypeExtends.Extends(Type.Any(), Type.Undefined()) - Assert.IsEqual(R, TypeExtendsResult.Union) + const R = ExtendsCheck(Type.Any(), Type.Undefined()) + Assert.IsEqual(R, ExtendsResult.Union) }) it('Should extend Void', () => { type T = any extends void ? 1 : 2 - const R = TypeExtends.Extends(Type.Any(), Type.Void()) - Assert.IsEqual(R, TypeExtendsResult.Union) + const R = ExtendsCheck(Type.Any(), Type.Void()) + Assert.IsEqual(R, ExtendsResult.Union) }) it('Should extend Date', () => { type T = any extends Date ? 1 : 2 - const R = TypeExtends.Extends(Type.Any(), Type.Date()) - Assert.IsEqual(R, TypeExtendsResult.Union) + const R = ExtendsCheck(Type.Any(), Type.Date()) + Assert.IsEqual(R, ExtendsResult.Union) }) }) diff --git a/test/runtime/type/extends/array.ts b/test/runtime/type/extends/array.ts index b734bc8ab..3e07b234c 100644 --- a/test/runtime/type/extends/array.ts +++ b/test/runtime/type/extends/array.ts @@ -1,4 +1,4 @@ -import { TypeExtends, TypeExtendsResult } from '@sinclair/typebox' +import { ExtendsCheck, ExtendsResult } from '@sinclair/typebox/type' import { Type } from '@sinclair/typebox' import { Assert } from '../../assert/index' @@ -8,258 +8,258 @@ describe('type/extends/Array', () => { // ---------------------------------------------- it('Should extend Array Varying 1', () => { type T = Array extends Array ? 1 : 2 - const R = TypeExtends.Extends(Type.Array(Type.Any()), Type.Array(Type.Any())) - Assert.IsEqual(R, TypeExtendsResult.True) + const R = ExtendsCheck(Type.Array(Type.Any()), Type.Array(Type.Any())) + Assert.IsEqual(R, ExtendsResult.True) }) it('Should extend Array Varying 2', () => { type T = Array extends Array ? 1 : 2 - const R = TypeExtends.Extends(Type.Array(Type.String()), Type.Array(Type.Any())) - Assert.IsEqual(R, TypeExtendsResult.True) + const R = ExtendsCheck(Type.Array(Type.String()), Type.Array(Type.Any())) + Assert.IsEqual(R, ExtendsResult.True) }) it('Should extend Array Varying 3', () => { type T = Array extends Array ? 1 : 2 // 1 - const R = TypeExtends.Extends(Type.Array(Type.Any()), Type.Array(Type.String())) - Assert.IsEqual(R, TypeExtendsResult.True) + const R = ExtendsCheck(Type.Array(Type.Any()), Type.Array(Type.String())) + Assert.IsEqual(R, ExtendsResult.True) }) it('Should extend Array Varying 4', () => { type T = Array extends Array ? 1 : 2 - const R = TypeExtends.Extends(Type.Array(Type.Number()), Type.Array(Type.String())) - Assert.IsEqual(R, TypeExtendsResult.False) + const R = ExtendsCheck(Type.Array(Type.Number()), Type.Array(Type.String())) + Assert.IsEqual(R, ExtendsResult.False) }) // ---------------------------------------------- // Any // ---------------------------------------------- it('Should extend Any', () => { type T = Array extends any ? 1 : 2 - const R = TypeExtends.Extends(Type.Array(Type.Any()), Type.Any()) - Assert.IsEqual(R, TypeExtendsResult.True) + const R = ExtendsCheck(Type.Array(Type.Any()), Type.Any()) + Assert.IsEqual(R, ExtendsResult.True) }) it('Should extend Unknown', () => { type T = Array extends unknown ? 1 : 2 - const R = TypeExtends.Extends(Type.Array(Type.Any()), Type.Unknown()) - Assert.IsEqual(R, TypeExtendsResult.True) + const R = ExtendsCheck(Type.Array(Type.Any()), Type.Unknown()) + Assert.IsEqual(R, ExtendsResult.True) }) it('Should extend String', () => { type T = Array extends string ? 1 : 2 - const R = TypeExtends.Extends(Type.Array(Type.Any()), Type.String()) - Assert.IsEqual(R, TypeExtendsResult.False) + const R = ExtendsCheck(Type.Array(Type.Any()), Type.String()) + Assert.IsEqual(R, ExtendsResult.False) }) it('Should extend Boolean', () => { type T = Array extends boolean ? 1 : 2 - const R = TypeExtends.Extends(Type.Array(Type.Any()), Type.Boolean()) - Assert.IsEqual(R, TypeExtendsResult.False) + const R = ExtendsCheck(Type.Array(Type.Any()), Type.Boolean()) + Assert.IsEqual(R, ExtendsResult.False) }) it('Should extend Number', () => { type T = Array extends number ? 1 : 2 - const R = TypeExtends.Extends(Type.Array(Type.Any()), Type.Number()) - Assert.IsEqual(R, TypeExtendsResult.False) + const R = ExtendsCheck(Type.Array(Type.Any()), Type.Number()) + Assert.IsEqual(R, ExtendsResult.False) }) it('Should extend Integer', () => { type T = Array extends number ? 1 : 2 - const R = TypeExtends.Extends(Type.Array(Type.Any()), Type.Integer()) - Assert.IsEqual(R, TypeExtendsResult.False) + const R = ExtendsCheck(Type.Array(Type.Any()), Type.Integer()) + Assert.IsEqual(R, ExtendsResult.False) }) it('Should extend Array 1', () => { type T = Array extends Array ? 1 : 2 - const R = TypeExtends.Extends(Type.Array(Type.Any()), Type.Array(Type.Any())) - Assert.IsEqual(R, TypeExtendsResult.True) + const R = ExtendsCheck(Type.Array(Type.Any()), Type.Array(Type.Any())) + Assert.IsEqual(R, ExtendsResult.True) }) it('Should extend Array 2', () => { type T = Array extends Array ? 1 : 2 - const R = TypeExtends.Extends(Type.Array(Type.Any()), Type.Array(Type.Any())) - Assert.IsEqual(R, TypeExtendsResult.True) + const R = ExtendsCheck(Type.Array(Type.Any()), Type.Array(Type.Any())) + Assert.IsEqual(R, ExtendsResult.True) }) it('Should extend Array 3', () => { type T = Array extends Array ? 1 : 2 - const R = TypeExtends.Extends(Type.Array(Type.Any()), Type.Array(Type.Any())) - Assert.IsEqual(R, TypeExtendsResult.True) + const R = ExtendsCheck(Type.Array(Type.Any()), Type.Array(Type.Any())) + Assert.IsEqual(R, ExtendsResult.True) }) it('Should extend Tuple', () => { type T = Array extends [number, number] ? 1 : 2 - const R = TypeExtends.Extends(Type.Array(Type.Any()), Type.Tuple([Type.Number(), Type.Number()])) - Assert.IsEqual(R, TypeExtendsResult.False) + const R = ExtendsCheck(Type.Array(Type.Any()), Type.Tuple([Type.Number(), Type.Number()])) + Assert.IsEqual(R, ExtendsResult.False) }) it('Should extend Object 1', () => { type T = Array extends object ? 1 : 2 - const R = TypeExtends.Extends(Type.Array(Type.Any()), Type.Object({})) - Assert.IsEqual(R, TypeExtendsResult.True) + const R = ExtendsCheck(Type.Array(Type.Any()), Type.Object({})) + Assert.IsEqual(R, ExtendsResult.True) }) it('Should extend Object 2', () => { type T = Array extends {} ? 1 : 2 - const R = TypeExtends.Extends(Type.Array(Type.Any()), Type.Object({})) - Assert.IsEqual(R, TypeExtendsResult.True) + const R = ExtendsCheck(Type.Array(Type.Any()), Type.Object({})) + Assert.IsEqual(R, ExtendsResult.True) }) it('Should extend Object 3', () => { type T = Array extends { a: number } ? 1 : 2 - const R = TypeExtends.Extends(Type.Array(Type.Any()), Type.Object({ a: Type.Number() })) - Assert.IsEqual(R, TypeExtendsResult.False) + const R = ExtendsCheck(Type.Array(Type.Any()), Type.Object({ a: Type.Number() })) + Assert.IsEqual(R, ExtendsResult.False) }) it('Should extend Object 4', () => { type T = Array extends { length: '1' } ? 1 : 2 - const R = TypeExtends.Extends(Type.Array(Type.Any()), Type.Object({ length: Type.Literal('1') })) - Assert.IsEqual(R, TypeExtendsResult.False) + const R = ExtendsCheck(Type.Array(Type.Any()), Type.Object({ length: Type.Literal('1') })) + Assert.IsEqual(R, ExtendsResult.False) }) it('Should extend Object 5', () => { type T = Array extends { length: number } ? 1 : 2 - const R = TypeExtends.Extends(Type.Array(Type.Any()), Type.Object({ length: Type.Number() })) - Assert.IsEqual(R, TypeExtendsResult.True) + const R = ExtendsCheck(Type.Array(Type.Any()), Type.Object({ length: Type.Number() })) + Assert.IsEqual(R, ExtendsResult.True) }) it('Should extend Union 1', () => { type T = Array extends number | string ? 1 : 2 - const R = TypeExtends.Extends(Type.Array(Type.Any()), Type.Union([Type.Number(), Type.String()])) - Assert.IsEqual(R, TypeExtendsResult.False) + const R = ExtendsCheck(Type.Array(Type.Any()), Type.Union([Type.Number(), Type.String()])) + Assert.IsEqual(R, ExtendsResult.False) }) it('Should extend Union 2', () => { type T = Array extends any | number ? 1 : 2 - const R = TypeExtends.Extends(Type.Array(Type.Any()), Type.Union([Type.Any(), Type.Number()])) - Assert.IsEqual(R, TypeExtendsResult.True) + const R = ExtendsCheck(Type.Array(Type.Any()), Type.Union([Type.Any(), Type.Number()])) + Assert.IsEqual(R, ExtendsResult.True) }) it('Should extend Union 3', () => { type T = Array extends any | Array ? 1 : 2 - const R = TypeExtends.Extends(Type.Array(Type.Any()), Type.Union([Type.Any(), Type.Array(Type.Any())])) - Assert.IsEqual(R, TypeExtendsResult.True) + const R = ExtendsCheck(Type.Array(Type.Any()), Type.Union([Type.Any(), Type.Array(Type.Any())])) + Assert.IsEqual(R, ExtendsResult.True) }) it('Should extend Union 4', () => { type T = Array extends any | Array ? 1 : 2 - const R = TypeExtends.Extends(Type.Array(Type.String()), Type.Union([Type.Any(), Type.Array(Type.Any())])) - Assert.IsEqual(R, TypeExtendsResult.True) + const R = ExtendsCheck(Type.Array(Type.String()), Type.Union([Type.Any(), Type.Array(Type.Any())])) + Assert.IsEqual(R, ExtendsResult.True) }) it('Should extend Union 5', () => { type T = Array extends any | Array ? 1 : 2 - const R = TypeExtends.Extends(Type.Array(Type.Any()), Type.Union([Type.Any(), Type.Array(Type.String())])) - Assert.IsEqual(R, TypeExtendsResult.True) + const R = ExtendsCheck(Type.Array(Type.Any()), Type.Union([Type.Any(), Type.Array(Type.String())])) + Assert.IsEqual(R, ExtendsResult.True) }) it('Should extend Null', () => { type T = Array extends null ? 1 : 2 - const R = TypeExtends.Extends(Type.Array(Type.Any()), Type.Null()) - Assert.IsEqual(R, TypeExtendsResult.False) + const R = ExtendsCheck(Type.Array(Type.Any()), Type.Null()) + Assert.IsEqual(R, ExtendsResult.False) }) it('Should extend Undefined', () => { type T = Array extends undefined ? 1 : 2 - const R = TypeExtends.Extends(Type.Array(Type.Any()), Type.Undefined()) - Assert.IsEqual(R, TypeExtendsResult.False) + const R = ExtendsCheck(Type.Array(Type.Any()), Type.Undefined()) + Assert.IsEqual(R, ExtendsResult.False) }) // ---------------------------------------------- // Constrained // ---------------------------------------------- it('Should extend constrained Any', () => { type T = Array extends any ? 1 : 2 - const R = TypeExtends.Extends(Type.Array(Type.String()), Type.Any()) - Assert.IsEqual(R, TypeExtendsResult.True) + const R = ExtendsCheck(Type.Array(Type.String()), Type.Any()) + Assert.IsEqual(R, ExtendsResult.True) }) it('Should extend constrained Unknown', () => { type T = Array extends unknown ? 1 : 2 - const R = TypeExtends.Extends(Type.Array(Type.String()), Type.Unknown()) - Assert.IsEqual(R, TypeExtendsResult.True) + const R = ExtendsCheck(Type.Array(Type.String()), Type.Unknown()) + Assert.IsEqual(R, ExtendsResult.True) }) it('Should extend constrained String', () => { type T = Array extends string ? 1 : 2 - const R = TypeExtends.Extends(Type.Array(Type.String()), Type.String()) - Assert.IsEqual(R, TypeExtendsResult.False) + const R = ExtendsCheck(Type.Array(Type.String()), Type.String()) + Assert.IsEqual(R, ExtendsResult.False) }) it('Should extend constrained Boolean', () => { type T = Array extends boolean ? 1 : 2 - const R = TypeExtends.Extends(Type.Array(Type.String()), Type.Boolean()) - Assert.IsEqual(R, TypeExtendsResult.False) + const R = ExtendsCheck(Type.Array(Type.String()), Type.Boolean()) + Assert.IsEqual(R, ExtendsResult.False) }) it('Should extend constrained Number', () => { type T = Array extends number ? 1 : 2 - const R = TypeExtends.Extends(Type.Array(Type.String()), Type.Number()) - Assert.IsEqual(R, TypeExtendsResult.False) + const R = ExtendsCheck(Type.Array(Type.String()), Type.Number()) + Assert.IsEqual(R, ExtendsResult.False) }) it('Should extend constrained Integer', () => { type T = Array extends number ? 1 : 2 - const R = TypeExtends.Extends(Type.Array(Type.String()), Type.Integer()) - Assert.IsEqual(R, TypeExtendsResult.False) + const R = ExtendsCheck(Type.Array(Type.String()), Type.Integer()) + Assert.IsEqual(R, ExtendsResult.False) }) it('Should extend constrained Array 1', () => { type T = Array extends Array ? 1 : 2 - const R = TypeExtends.Extends(Type.Array(Type.String()), Type.Array(Type.Any())) - Assert.IsEqual(R, TypeExtendsResult.True) + const R = ExtendsCheck(Type.Array(Type.String()), Type.Array(Type.Any())) + Assert.IsEqual(R, ExtendsResult.True) }) it('Should extend constrained Array 2', () => { type T = Array extends Array ? 1 : 2 - const R = TypeExtends.Extends(Type.Array(Type.String()), Type.Array(Type.Any())) - Assert.IsEqual(R, TypeExtendsResult.True) + const R = ExtendsCheck(Type.Array(Type.String()), Type.Array(Type.Any())) + Assert.IsEqual(R, ExtendsResult.True) }) it('Should extend constrained Array 3', () => { type T = Array extends Array ? 1 : 2 - const R = TypeExtends.Extends(Type.Array(Type.String()), Type.Array(Type.Any())) - Assert.IsEqual(R, TypeExtendsResult.True) + const R = ExtendsCheck(Type.Array(Type.String()), Type.Array(Type.Any())) + Assert.IsEqual(R, ExtendsResult.True) }) it('Should extend constrained Tuple', () => { type T = Array extends [number, number] ? 1 : 2 - const R = TypeExtends.Extends(Type.Array(Type.String()), Type.Tuple([Type.Number(), Type.Number()])) - Assert.IsEqual(R, TypeExtendsResult.False) + const R = ExtendsCheck(Type.Array(Type.String()), Type.Tuple([Type.Number(), Type.Number()])) + Assert.IsEqual(R, ExtendsResult.False) }) it('Should extend constrained Object 1', () => { type T = Array extends object ? 1 : 2 - const R = TypeExtends.Extends(Type.Array(Type.String()), Type.Object({})) - Assert.IsEqual(R, TypeExtendsResult.True) + const R = ExtendsCheck(Type.Array(Type.String()), Type.Object({})) + Assert.IsEqual(R, ExtendsResult.True) }) it('Should extend constrained Object 2', () => { type T = Array extends {} ? 1 : 2 - const R = TypeExtends.Extends(Type.Array(Type.String()), Type.Object({})) - Assert.IsEqual(R, TypeExtendsResult.True) + const R = ExtendsCheck(Type.Array(Type.String()), Type.Object({})) + Assert.IsEqual(R, ExtendsResult.True) }) it('Should extend constrained Object 3', () => { type T = Array extends { a: number } ? 1 : 2 - const R = TypeExtends.Extends(Type.Array(Type.String()), Type.Object({ a: Type.Number() })) - Assert.IsEqual(R, TypeExtendsResult.False) + const R = ExtendsCheck(Type.Array(Type.String()), Type.Object({ a: Type.Number() })) + Assert.IsEqual(R, ExtendsResult.False) }) it('Should extend constrained Object 4', () => { type T = Array extends { length: '1' } ? 1 : 2 - const R = TypeExtends.Extends(Type.Array(Type.String()), Type.Object({ length: Type.Literal('1') })) - Assert.IsEqual(R, TypeExtendsResult.False) + const R = ExtendsCheck(Type.Array(Type.String()), Type.Object({ length: Type.Literal('1') })) + Assert.IsEqual(R, ExtendsResult.False) }) it('Should extend constrained Object 5', () => { type T = Array extends { length: number } ? 1 : 2 - const R = TypeExtends.Extends(Type.Array(Type.String()), Type.Object({ length: Type.Number() })) - Assert.IsEqual(R, TypeExtendsResult.True) + const R = ExtendsCheck(Type.Array(Type.String()), Type.Object({ length: Type.Number() })) + Assert.IsEqual(R, ExtendsResult.True) }) it('Should extend constrained Union 1', () => { type T = Array extends number | string ? 1 : 2 - const R = TypeExtends.Extends(Type.Array(Type.String()), Type.Union([Type.Null(), Type.String()])) - Assert.IsEqual(R, TypeExtendsResult.False) + const R = ExtendsCheck(Type.Array(Type.String()), Type.Union([Type.Null(), Type.String()])) + Assert.IsEqual(R, ExtendsResult.False) }) it('Should extend constrained Union 2', () => { type T = Array extends any | number ? 1 : 2 - const R = TypeExtends.Extends(Type.Array(Type.String()), Type.Union([Type.Any(), Type.String()])) - Assert.IsEqual(R, TypeExtendsResult.True) + const R = ExtendsCheck(Type.Array(Type.String()), Type.Union([Type.Any(), Type.String()])) + Assert.IsEqual(R, ExtendsResult.True) }) it('Should extend constrained Union 3', () => { type T = Array extends any | Array ? 1 : 2 - const R = TypeExtends.Extends(Type.Array(Type.String()), Type.Union([Type.Any(), Type.Array(Type.Any())])) - Assert.IsEqual(R, TypeExtendsResult.True) + const R = ExtendsCheck(Type.Array(Type.String()), Type.Union([Type.Any(), Type.Array(Type.Any())])) + Assert.IsEqual(R, ExtendsResult.True) }) it('Should extend constrained Union 4', () => { type T = Array extends any | Array ? 1 : 2 - const R = TypeExtends.Extends(Type.Array(Type.String()), Type.Union([Type.Any(), Type.Array(Type.Any())])) - Assert.IsEqual(R, TypeExtendsResult.True) + const R = ExtendsCheck(Type.Array(Type.String()), Type.Union([Type.Any(), Type.Array(Type.Any())])) + Assert.IsEqual(R, ExtendsResult.True) }) it('Should extend constrained Union 5', () => { type T = Array extends any | Array ? 1 : 2 - const R = TypeExtends.Extends(Type.Array(Type.String()), Type.Union([Type.Any(), Type.Array(Type.String())])) - Assert.IsEqual(R, TypeExtendsResult.True) + const R = ExtendsCheck(Type.Array(Type.String()), Type.Union([Type.Any(), Type.Array(Type.String())])) + Assert.IsEqual(R, ExtendsResult.True) }) it('Should extend constrained Null', () => { type T = Array extends null ? 1 : 2 - const R = TypeExtends.Extends(Type.Array(Type.String()), Type.Null()) - Assert.IsEqual(R, TypeExtendsResult.False) + const R = ExtendsCheck(Type.Array(Type.String()), Type.Null()) + Assert.IsEqual(R, ExtendsResult.False) }) it('Should extend constrained Undefined', () => { type T = Array extends undefined ? 1 : 2 - const R = TypeExtends.Extends(Type.Array(Type.String()), Type.Undefined()) - Assert.IsEqual(R, TypeExtendsResult.False) + const R = ExtendsCheck(Type.Array(Type.String()), Type.Undefined()) + Assert.IsEqual(R, ExtendsResult.False) }) it('Should extend constrained Void', () => { type T = Array extends void ? 1 : 2 - const R = TypeExtends.Extends(Type.Array(Type.String()), Type.Void()) - Assert.IsEqual(R, TypeExtendsResult.False) + const R = ExtendsCheck(Type.Array(Type.String()), Type.Void()) + Assert.IsEqual(R, ExtendsResult.False) }) it('Should extend Date', () => { type T = Array extends Date ? 1 : 2 - const R = TypeExtends.Extends(Type.Array(Type.String()), Type.Date()) - Assert.IsEqual(R, TypeExtendsResult.False) + const R = ExtendsCheck(Type.Array(Type.String()), Type.Date()) + Assert.IsEqual(R, ExtendsResult.False) }) }) diff --git a/test/runtime/type/extends/async-iterator.ts b/test/runtime/type/extends/async-iterator.ts index 4eba4c020..b4fd153fc 100644 --- a/test/runtime/type/extends/async-iterator.ts +++ b/test/runtime/type/extends/async-iterator.ts @@ -1,4 +1,4 @@ -import { TypeExtends, TypeExtendsResult } from '@sinclair/typebox' +import { ExtendsCheck, ExtendsResult } from '@sinclair/typebox/type' import { Type } from '@sinclair/typebox' import { Assert } from '../../assert/index' @@ -8,65 +8,65 @@ describe('type/extends/AsyncIterator', () => { // ---------------------------------------------- it('Should extend AsyncIterator 1', () => { type T = AsyncIterableIterator extends AsyncIterableIterator ? 1 : 2 - const R = TypeExtends.Extends(Type.AsyncIterator(Type.Any()), Type.AsyncIterator(Type.Any())) - Assert.IsEqual(R, TypeExtendsResult.True) + const R = ExtendsCheck(Type.AsyncIterator(Type.Any()), Type.AsyncIterator(Type.Any())) + Assert.IsEqual(R, ExtendsResult.True) }) it('Should extend AsyncIterator 2', () => { type T = AsyncIterableIterator extends AsyncIterableIterator ? 1 : 2 - const R = TypeExtends.Extends(Type.AsyncIterator(Type.String()), Type.AsyncIterator(Type.String())) - Assert.IsEqual(R, TypeExtendsResult.True) + const R = ExtendsCheck(Type.AsyncIterator(Type.String()), Type.AsyncIterator(Type.String())) + Assert.IsEqual(R, ExtendsResult.True) }) it('Should extend AsyncIterator 3', () => { type T = AsyncIterableIterator<'hello'> extends AsyncIterableIterator ? 1 : 2 - const R = TypeExtends.Extends(Type.AsyncIterator(Type.Literal('hello')), Type.AsyncIterator(Type.String())) - Assert.IsEqual(R, TypeExtendsResult.True) + const R = ExtendsCheck(Type.AsyncIterator(Type.Literal('hello')), Type.AsyncIterator(Type.String())) + Assert.IsEqual(R, ExtendsResult.True) }) it('Should extend AsyncIterator 4', () => { type T = AsyncIterableIterator extends AsyncIterableIterator<'hello'> ? 1 : 2 - const R = TypeExtends.Extends(Type.AsyncIterator(Type.String()), Type.AsyncIterator(Type.Literal('hello'))) - Assert.IsEqual(R, TypeExtendsResult.False) + const R = ExtendsCheck(Type.AsyncIterator(Type.String()), Type.AsyncIterator(Type.Literal('hello'))) + Assert.IsEqual(R, ExtendsResult.False) }) it('Should extend AsyncIterator 5', () => { type T = AsyncIterableIterator extends AsyncIterableIterator<'hello' | number> ? 1 : 2 - const R = TypeExtends.Extends(Type.AsyncIterator(Type.String()), Type.AsyncIterator(Type.Union([Type.Literal('hello'), Type.Number()]))) - Assert.IsEqual(R, TypeExtendsResult.False) + const R = ExtendsCheck(Type.AsyncIterator(Type.String()), Type.AsyncIterator(Type.Union([Type.Literal('hello'), Type.Number()]))) + Assert.IsEqual(R, ExtendsResult.False) }) it('Should extend AsyncIterator 6', () => { type T = AsyncIterableIterator<'hello' | number> extends AsyncIterableIterator ? 1 : 2 - const R = TypeExtends.Extends(Type.AsyncIterator(Type.Union([Type.Literal('hello'), Type.Number()])), Type.AsyncIterator(Type.String())) - Assert.IsEqual(R, TypeExtendsResult.False) + const R = ExtendsCheck(Type.AsyncIterator(Type.Union([Type.Literal('hello'), Type.Number()])), Type.AsyncIterator(Type.String())) + Assert.IsEqual(R, ExtendsResult.False) }) // -------------------------------------------------------------------- // Structural // -------------------------------------------------------------------- it('Should extends Any 1', () => { type T = AsyncIterableIterator extends any ? 1 : 2 - const R = TypeExtends.Extends(Type.AsyncIterator(Type.Number()), Type.Any()) - Assert.IsEqual(R, TypeExtendsResult.True) + const R = ExtendsCheck(Type.AsyncIterator(Type.Number()), Type.Any()) + Assert.IsEqual(R, ExtendsResult.True) }) it('Should extends Any 2', () => { type T = any extends AsyncIterableIterator ? 1 : 2 - const R = TypeExtends.Extends(Type.Any(), Type.AsyncIterator(Type.Number())) - Assert.IsEqual(R, TypeExtendsResult.Union) + const R = ExtendsCheck(Type.Any(), Type.AsyncIterator(Type.Number())) + Assert.IsEqual(R, ExtendsResult.Union) }) it('Should extends Unknown 1', () => { type T = AsyncIterableIterator extends unknown ? 1 : 2 - const R = TypeExtends.Extends(Type.AsyncIterator(Type.Number()), Type.Unknown()) - Assert.IsEqual(R, TypeExtendsResult.True) + const R = ExtendsCheck(Type.AsyncIterator(Type.Number()), Type.Unknown()) + Assert.IsEqual(R, ExtendsResult.True) }) it('Should extends Unknown 2', () => { type T = unknown extends AsyncIterableIterator ? 1 : 2 - const R = TypeExtends.Extends(Type.Unknown(), Type.AsyncIterator(Type.Number())) - Assert.IsEqual(R, TypeExtendsResult.False) + const R = ExtendsCheck(Type.Unknown(), Type.AsyncIterator(Type.Number())) + Assert.IsEqual(R, ExtendsResult.False) }) it('Should extends Never 1', () => { type T = AsyncIterableIterator extends never ? 1 : 2 - const R = TypeExtends.Extends(Type.AsyncIterator(Type.Number()), Type.Never()) - Assert.IsEqual(R, TypeExtendsResult.False) + const R = ExtendsCheck(Type.AsyncIterator(Type.Number()), Type.Never()) + Assert.IsEqual(R, ExtendsResult.False) }) it('Should extends Never 2', () => { type T = never extends AsyncIterableIterator ? 1 : 2 - const R = TypeExtends.Extends(Type.Never(), Type.AsyncIterator(Type.Number())) - Assert.IsEqual(R, TypeExtendsResult.True) + const R = ExtendsCheck(Type.Never(), Type.AsyncIterator(Type.Number())) + Assert.IsEqual(R, ExtendsResult.True) }) }) diff --git a/test/runtime/type/extends/bigint.ts b/test/runtime/type/extends/bigint.ts index 5346cfa39..bf3d3f4e0 100644 --- a/test/runtime/type/extends/bigint.ts +++ b/test/runtime/type/extends/bigint.ts @@ -1,101 +1,101 @@ -import { TypeExtends, TypeExtendsResult } from '@sinclair/typebox' +import { ExtendsCheck, ExtendsResult } from '@sinclair/typebox/type' import { Type } from '@sinclair/typebox' import { Assert } from '../../assert/index' describe('type/extends/BigInt', () => { it('Should extend Any', () => { type T = bigint extends any ? 1 : 2 - const R = TypeExtends.Extends(Type.BigInt(), Type.Any()) - Assert.IsEqual(R, TypeExtendsResult.True) + const R = ExtendsCheck(Type.BigInt(), Type.Any()) + Assert.IsEqual(R, ExtendsResult.True) }) it('Should extend Unknown', () => { type T = bigint extends unknown ? 1 : 2 - const R = TypeExtends.Extends(Type.BigInt(), Type.Unknown()) - Assert.IsEqual(R, TypeExtendsResult.True) + const R = ExtendsCheck(Type.BigInt(), Type.Unknown()) + Assert.IsEqual(R, ExtendsResult.True) }) it('Should extend String', () => { type T = bigint extends string ? 1 : 2 - const R = TypeExtends.Extends(Type.BigInt(), Type.String()) - Assert.IsEqual(R, TypeExtendsResult.False) + const R = ExtendsCheck(Type.BigInt(), Type.String()) + Assert.IsEqual(R, ExtendsResult.False) }) it('Should extend Boolean', () => { type T = bigint extends boolean ? 1 : 2 - const R = TypeExtends.Extends(Type.BigInt(), Type.Boolean()) - Assert.IsEqual(R, TypeExtendsResult.False) + const R = ExtendsCheck(Type.BigInt(), Type.Boolean()) + Assert.IsEqual(R, ExtendsResult.False) }) it('Should extend Number', () => { type T = bigint extends number ? 1 : 2 - const R = TypeExtends.Extends(Type.BigInt(), Type.Number()) - Assert.IsEqual(R, TypeExtendsResult.False) + const R = ExtendsCheck(Type.BigInt(), Type.Number()) + Assert.IsEqual(R, ExtendsResult.False) }) it('Should extend Integer', () => { type T = bigint extends number ? 1 : 2 - const R = TypeExtends.Extends(Type.BigInt(), Type.Integer()) - Assert.IsEqual(R, TypeExtendsResult.False) + const R = ExtendsCheck(Type.BigInt(), Type.Integer()) + Assert.IsEqual(R, ExtendsResult.False) }) it('Should extend Array', () => { type T = bigint extends Array ? 1 : 2 - const R = TypeExtends.Extends(Type.BigInt(), Type.Array(Type.Any())) - Assert.IsEqual(R, TypeExtendsResult.False) + const R = ExtendsCheck(Type.BigInt(), Type.Array(Type.Any())) + Assert.IsEqual(R, ExtendsResult.False) }) it('Should extend Tuple', () => { type T = bigint extends [number, number] ? 1 : 2 - const R = TypeExtends.Extends(Type.BigInt(), Type.Tuple([Type.Number(), Type.Number()])) - Assert.IsEqual(R, TypeExtendsResult.False) + const R = ExtendsCheck(Type.BigInt(), Type.Tuple([Type.Number(), Type.Number()])) + Assert.IsEqual(R, ExtendsResult.False) }) it('Should extend Record', () => { type T = bigint extends Record ? 1 : 2 - const R = TypeExtends.Extends(Type.BigInt(), Type.Record(Type.Number(), Type.Any())) - Assert.IsEqual(R, TypeExtendsResult.False) + const R = ExtendsCheck(Type.BigInt(), Type.Record(Type.Number(), Type.Any())) + Assert.IsEqual(R, ExtendsResult.False) }) it('Should extend Object 1', () => { type T = bigint extends {} ? 1 : 2 - const R = TypeExtends.Extends(Type.BigInt(), Type.Object({})) - Assert.IsEqual(R, TypeExtendsResult.True) + const R = ExtendsCheck(Type.BigInt(), Type.Object({})) + Assert.IsEqual(R, ExtendsResult.True) }) it('Should extend Object 2', () => { type T = bigint extends { a: 10 } ? 1 : 2 - const R = TypeExtends.Extends(Type.BigInt(), Type.Object({ a: Type.Literal(10) })) - Assert.IsEqual(R, TypeExtendsResult.False) + const R = ExtendsCheck(Type.BigInt(), Type.Object({ a: Type.Literal(10) })) + Assert.IsEqual(R, ExtendsResult.False) }) it('Should extend Union 1', () => { type T = bigint extends number | string ? 1 : 2 - const R = TypeExtends.Extends(Type.BigInt(), Type.Union([Type.Number(), Type.String()])) - Assert.IsEqual(R, TypeExtendsResult.False) + const R = ExtendsCheck(Type.BigInt(), Type.Union([Type.Number(), Type.String()])) + Assert.IsEqual(R, ExtendsResult.False) }) it('Should extend Union 2', () => { type T = bigint extends any | number ? 1 : 2 - const R = TypeExtends.Extends(Type.BigInt(), Type.Union([Type.Any(), Type.Number()])) - Assert.IsEqual(R, TypeExtendsResult.True) + const R = ExtendsCheck(Type.BigInt(), Type.Union([Type.Any(), Type.Number()])) + Assert.IsEqual(R, ExtendsResult.True) }) it('Should extend Union 3', () => { type T = bigint extends boolean | number ? 1 : 2 - const R = TypeExtends.Extends(Type.BigInt(), Type.Union([Type.Boolean(), Type.Number()])) - Assert.IsEqual(R, TypeExtendsResult.False) + const R = ExtendsCheck(Type.BigInt(), Type.Union([Type.Boolean(), Type.Number()])) + Assert.IsEqual(R, ExtendsResult.False) }) it('Should extend Union 4', () => { type T = bigint extends boolean | bigint ? 1 : 2 - const R = TypeExtends.Extends(Type.BigInt(), Type.Union([Type.Boolean(), Type.BigInt()])) - Assert.IsEqual(R, TypeExtendsResult.True) + const R = ExtendsCheck(Type.BigInt(), Type.Union([Type.Boolean(), Type.BigInt()])) + Assert.IsEqual(R, ExtendsResult.True) }) it('Should extend Null', () => { type T = bigint extends null ? 1 : 2 - const R = TypeExtends.Extends(Type.BigInt(), Type.Null()) - Assert.IsEqual(R, TypeExtendsResult.False) + const R = ExtendsCheck(Type.BigInt(), Type.Null()) + Assert.IsEqual(R, ExtendsResult.False) }) it('Should extend Undefined', () => { type T = bigint extends undefined ? 1 : 2 - const R = TypeExtends.Extends(Type.BigInt(), Type.Undefined()) - Assert.IsEqual(R, TypeExtendsResult.False) + const R = ExtendsCheck(Type.BigInt(), Type.Undefined()) + Assert.IsEqual(R, ExtendsResult.False) }) it('Should extend Void', () => { type T = bigint extends undefined ? 1 : 2 - const R = TypeExtends.Extends(Type.BigInt(), Type.Void()) - Assert.IsEqual(R, TypeExtendsResult.False) + const R = ExtendsCheck(Type.BigInt(), Type.Void()) + Assert.IsEqual(R, ExtendsResult.False) }) it('Should extend Date', () => { type T = bigint extends Date ? 1 : 2 - const R = TypeExtends.Extends(Type.BigInt(), Type.Date()) - Assert.IsEqual(R, TypeExtendsResult.False) + const R = ExtendsCheck(Type.BigInt(), Type.Date()) + Assert.IsEqual(R, ExtendsResult.False) }) }) diff --git a/test/runtime/type/extends/boolean.ts b/test/runtime/type/extends/boolean.ts index 1d56e21eb..cce393d6f 100644 --- a/test/runtime/type/extends/boolean.ts +++ b/test/runtime/type/extends/boolean.ts @@ -1,91 +1,91 @@ -import { TypeExtends, TypeExtendsResult } from '@sinclair/typebox' +import { ExtendsCheck, ExtendsResult } from '@sinclair/typebox/type' import { Type } from '@sinclair/typebox' import { Assert } from '../../assert/index' describe('type/extends/Boolean', () => { it('Should extend Any', () => { type T = boolean extends any ? 1 : 2 - const R = TypeExtends.Extends(Type.Boolean(), Type.Any()) - Assert.IsEqual(R, TypeExtendsResult.True) + const R = ExtendsCheck(Type.Boolean(), Type.Any()) + Assert.IsEqual(R, ExtendsResult.True) }) it('Should extend String', () => { type T = boolean extends string ? 1 : 2 - const R = TypeExtends.Extends(Type.Boolean(), Type.String()) - Assert.IsEqual(R, TypeExtendsResult.False) + const R = ExtendsCheck(Type.Boolean(), Type.String()) + Assert.IsEqual(R, ExtendsResult.False) }) it('Should extend Boolean', () => { type T = boolean extends boolean ? 1 : 2 - const R = TypeExtends.Extends(Type.Boolean(), Type.Boolean()) - Assert.IsEqual(R, TypeExtendsResult.True) + const R = ExtendsCheck(Type.Boolean(), Type.Boolean()) + Assert.IsEqual(R, ExtendsResult.True) }) it('Should extend Number', () => { type T = boolean extends number ? 1 : 2 - const R = TypeExtends.Extends(Type.Boolean(), Type.Number()) - Assert.IsEqual(R, TypeExtendsResult.False) + const R = ExtendsCheck(Type.Boolean(), Type.Number()) + Assert.IsEqual(R, ExtendsResult.False) }) it('Should extend Integer', () => { type T = boolean extends number ? 1 : 2 - const R = TypeExtends.Extends(Type.Boolean(), Type.Integer()) - Assert.IsEqual(R, TypeExtendsResult.False) + const R = ExtendsCheck(Type.Boolean(), Type.Integer()) + Assert.IsEqual(R, ExtendsResult.False) }) it('Should extend Array', () => { type T = boolean extends Array ? 1 : 2 - const R = TypeExtends.Extends(Type.Boolean(), Type.Array(Type.Any())) - Assert.IsEqual(R, TypeExtendsResult.False) + const R = ExtendsCheck(Type.Boolean(), Type.Array(Type.Any())) + Assert.IsEqual(R, ExtendsResult.False) }) it('Should extend Tuple', () => { type T = boolean extends [number, number] ? 1 : 2 - const R = TypeExtends.Extends(Type.Boolean(), Type.Tuple([Type.Number(), Type.Number()])) - Assert.IsEqual(R, TypeExtendsResult.False) + const R = ExtendsCheck(Type.Boolean(), Type.Tuple([Type.Number(), Type.Number()])) + Assert.IsEqual(R, ExtendsResult.False) }) it('Should extend Record', () => { type T = boolean extends Record ? 1 : 2 - const R = TypeExtends.Extends(Type.Number(), Type.Record(Type.Number(), Type.Any())) - Assert.IsEqual(R, TypeExtendsResult.False) + const R = ExtendsCheck(Type.Number(), Type.Record(Type.Number(), Type.Any())) + Assert.IsEqual(R, ExtendsResult.False) }) it('Should extend Object 1', () => { type T = boolean extends {} ? 1 : 2 - const R = TypeExtends.Extends(Type.Boolean(), Type.Object({}, { additionalProperties: false })) - Assert.IsEqual(R, TypeExtendsResult.True) + const R = ExtendsCheck(Type.Boolean(), Type.Object({}, { additionalProperties: false })) + Assert.IsEqual(R, ExtendsResult.True) }) it('Should extend Object 2', () => { type T = boolean extends { a: 10 } ? 1 : 2 - const R = TypeExtends.Extends(Type.Boolean(), Type.Object({ a: Type.Literal(10) }, { additionalProperties: true })) - Assert.IsEqual(R, TypeExtendsResult.False) + const R = ExtendsCheck(Type.Boolean(), Type.Object({ a: Type.Literal(10) }, { additionalProperties: true })) + Assert.IsEqual(R, ExtendsResult.False) }) it('Should extend Union 1', () => { type T = boolean extends number | string ? 1 : 2 - const R = TypeExtends.Extends(Type.Boolean(), Type.Union([Type.Number(), Type.String()])) - Assert.IsEqual(R, TypeExtendsResult.False) + const R = ExtendsCheck(Type.Boolean(), Type.Union([Type.Number(), Type.String()])) + Assert.IsEqual(R, ExtendsResult.False) }) it('Should extend Union 2', () => { type T = boolean extends any | number ? 1 : 2 - const R = TypeExtends.Extends(Type.Boolean(), Type.Union([Type.Any(), Type.Number()])) - Assert.IsEqual(R, TypeExtendsResult.True) + const R = ExtendsCheck(Type.Boolean(), Type.Union([Type.Any(), Type.Number()])) + Assert.IsEqual(R, ExtendsResult.True) }) it('Should extend Union 2', () => { type T = boolean extends boolean | number ? 1 : 2 - const R = TypeExtends.Extends(Type.Boolean(), Type.Union([Type.Boolean(), Type.Number()])) - Assert.IsEqual(R, TypeExtendsResult.True) + const R = ExtendsCheck(Type.Boolean(), Type.Union([Type.Boolean(), Type.Number()])) + Assert.IsEqual(R, ExtendsResult.True) }) it('Should extend Null', () => { type T = boolean extends null ? 1 : 2 - const R = TypeExtends.Extends(Type.Boolean(), Type.Null()) - Assert.IsEqual(R, TypeExtendsResult.False) + const R = ExtendsCheck(Type.Boolean(), Type.Null()) + Assert.IsEqual(R, ExtendsResult.False) }) it('Should extend Undefined', () => { type T = boolean extends undefined ? 1 : 2 - const R = TypeExtends.Extends(Type.Boolean(), Type.Undefined()) - Assert.IsEqual(R, TypeExtendsResult.False) + const R = ExtendsCheck(Type.Boolean(), Type.Undefined()) + Assert.IsEqual(R, ExtendsResult.False) }) it('Should extend Void', () => { type T = boolean extends void ? 1 : 2 - const R = TypeExtends.Extends(Type.Boolean(), Type.Void()) - Assert.IsEqual(R, TypeExtendsResult.False) + const R = ExtendsCheck(Type.Boolean(), Type.Void()) + Assert.IsEqual(R, ExtendsResult.False) }) it('Should extend Date', () => { type T = boolean extends Date ? 1 : 2 - const R = TypeExtends.Extends(Type.Boolean(), Type.Date()) - Assert.IsEqual(R, TypeExtendsResult.False) + const R = ExtendsCheck(Type.Boolean(), Type.Date()) + Assert.IsEqual(R, ExtendsResult.False) }) }) diff --git a/test/runtime/type/extends/constructor.ts b/test/runtime/type/extends/constructor.ts index f5b6151d9..1fb9e0a3a 100644 --- a/test/runtime/type/extends/constructor.ts +++ b/test/runtime/type/extends/constructor.ts @@ -1,211 +1,211 @@ -import { TypeExtends, TypeExtendsResult } from '@sinclair/typebox' +import { ExtendsCheck, ExtendsResult } from '@sinclair/typebox/type' import { Type } from '@sinclair/typebox' import { Assert } from '../../assert/index' describe('type/extends/Constructor', () => { it('Should extend Function', () => { type T = (new () => number) extends () => number ? 1 : 2 - const R = TypeExtends.Extends(Type.Constructor([], Type.Number()), Type.Function([], Type.Number())) - Assert.IsEqual(R, TypeExtendsResult.False) + const R = ExtendsCheck(Type.Constructor([], Type.Number()), Type.Function([], Type.Number())) + Assert.IsEqual(R, ExtendsResult.False) }) it('Should extend Constructor 1', () => { type T = (new () => number) extends new () => number ? 1 : 2 - const R = TypeExtends.Extends(Type.Constructor([], Type.Number()), Type.Constructor([], Type.Number())) - Assert.IsEqual(R, TypeExtendsResult.True) + const R = ExtendsCheck(Type.Constructor([], Type.Number()), Type.Constructor([], Type.Number())) + Assert.IsEqual(R, ExtendsResult.True) }) it('Should extend Constructor 2', () => { type T = (new () => any) extends new () => number ? 1 : 2 - const R = TypeExtends.Extends(Type.Constructor([], Type.Any()), Type.Constructor([], Type.Number())) - Assert.IsEqual(R, TypeExtendsResult.True) + const R = ExtendsCheck(Type.Constructor([], Type.Any()), Type.Constructor([], Type.Number())) + Assert.IsEqual(R, ExtendsResult.True) }) it('Should extend Constructor 3', () => { type T = (new () => number) extends new () => any ? 1 : 2 - const R = TypeExtends.Extends(Type.Constructor([], Type.Any()), Type.Constructor([], Type.Number())) - Assert.IsEqual(R, TypeExtendsResult.True) + const R = ExtendsCheck(Type.Constructor([], Type.Any()), Type.Constructor([], Type.Number())) + Assert.IsEqual(R, ExtendsResult.True) }) it('Should extend Constructor 4', () => { type T = (new (a: number) => number) extends new () => any ? 1 : 2 - const R = TypeExtends.Extends(Type.Constructor([Type.Number()], Type.Number()), Type.Constructor([], Type.Any())) - Assert.IsEqual(R, TypeExtendsResult.False) + const R = ExtendsCheck(Type.Constructor([Type.Number()], Type.Number()), Type.Constructor([], Type.Any())) + Assert.IsEqual(R, ExtendsResult.False) }) it('Should extend Constructor 5', () => { type T = (new (a: number | string) => number) extends new (a: number) => number ? 1 : 2 - const R = TypeExtends.Extends(Type.Constructor([Type.Union([Type.Number(), Type.String()])], Type.Number()), Type.Constructor([Type.Number()], Type.Any())) - Assert.IsEqual(R, TypeExtendsResult.True) + const R = ExtendsCheck(Type.Constructor([Type.Union([Type.Number(), Type.String()])], Type.Number()), Type.Constructor([Type.Number()], Type.Any())) + Assert.IsEqual(R, ExtendsResult.True) }) it('Should extend Constructor 6', () => { type T = (new (a: number) => number) extends new (a: number | string) => any ? 1 : 2 - const R = TypeExtends.Extends(Type.Constructor([Type.Number()], Type.Number()), Type.Constructor([Type.Union([Type.Number(), Type.String()])], Type.Any())) - Assert.IsEqual(R, TypeExtendsResult.False) + const R = ExtendsCheck(Type.Constructor([Type.Number()], Type.Number()), Type.Constructor([Type.Union([Type.Number(), Type.String()])], Type.Any())) + Assert.IsEqual(R, ExtendsResult.False) }) it('Should extend Constructor 7', () => { type T = (new (a: number, b: number) => number) extends new (a: number) => number ? 1 : 2 - const R = TypeExtends.Extends(Type.Constructor([Type.Number(), Type.Number()], Type.Number()), Type.Constructor([Type.Number()], Type.Number())) - Assert.IsEqual(R, TypeExtendsResult.False) + const R = ExtendsCheck(Type.Constructor([Type.Number(), Type.Number()], Type.Number()), Type.Constructor([Type.Number()], Type.Number())) + Assert.IsEqual(R, ExtendsResult.False) }) it('Should extend Constructor 8', () => { type T = (new (a: number) => number) extends new (a: number, b: number) => number ? 1 : 2 - const R = TypeExtends.Extends(Type.Constructor([Type.Number()], Type.Number()), Type.Constructor([Type.Number(), Type.Number()], Type.Number())) - Assert.IsEqual(R, TypeExtendsResult.True) + const R = ExtendsCheck(Type.Constructor([Type.Number()], Type.Number()), Type.Constructor([Type.Number(), Type.Number()], Type.Number())) + Assert.IsEqual(R, ExtendsResult.True) }) it('Should extend Constructor 9', () => { type T = (new () => number) extends new () => any ? 1 : 2 - const R = TypeExtends.Extends(Type.Constructor([], Type.Number()), Type.Constructor([], Type.Any())) - Assert.IsEqual(R, TypeExtendsResult.True) + const R = ExtendsCheck(Type.Constructor([], Type.Number()), Type.Constructor([], Type.Any())) + Assert.IsEqual(R, ExtendsResult.True) }) it('Should extend Constructor 9', () => { type T = (new () => any) extends new () => number ? 1 : 2 - const R = TypeExtends.Extends(Type.Constructor([], Type.Any()), Type.Constructor([], Type.Number())) - Assert.IsEqual(R, TypeExtendsResult.True) + const R = ExtendsCheck(Type.Constructor([], Type.Any()), Type.Constructor([], Type.Number())) + Assert.IsEqual(R, ExtendsResult.True) }) it('Should extend Constructor 10', () => { type T = (new () => Array) extends new () => object ? 1 : 2 - const R = TypeExtends.Extends(Type.Constructor([], Type.Array(Type.Any())), Type.Constructor([], Type.Object({}))) - Assert.IsEqual(R, TypeExtendsResult.True) + const R = ExtendsCheck(Type.Constructor([], Type.Array(Type.Any())), Type.Constructor([], Type.Object({}))) + Assert.IsEqual(R, ExtendsResult.True) }) it('Should extend Constructor 11', () => { type T = (new () => Array) extends new () => object ? 1 : 2 - const R = TypeExtends.Extends(Type.Constructor([], Type.Array(Type.String())), Type.Constructor([], Type.Object({}))) - Assert.IsEqual(R, TypeExtendsResult.True) + const R = ExtendsCheck(Type.Constructor([], Type.Array(Type.String())), Type.Constructor([], Type.Object({}))) + Assert.IsEqual(R, ExtendsResult.True) }) it('Should extend Constructor 12', () => { type T = (new () => object) extends new () => Array ? 1 : 2 - const R = TypeExtends.Extends(Type.Constructor([], Type.Object({})), Type.Constructor([], Type.Array(Type.Any()))) - Assert.IsEqual(R, TypeExtendsResult.False) + const R = ExtendsCheck(Type.Constructor([], Type.Object({})), Type.Constructor([], Type.Array(Type.Any()))) + Assert.IsEqual(R, ExtendsResult.False) }) it('Should extend Constructor 13', () => { type T = (new (a: unknown) => number) extends new (a: any) => number ? 1 : 2 - const R = TypeExtends.Extends(Type.Constructor([Type.Unknown()], Type.Number({})), Type.Constructor([Type.Any()], Type.Number({}))) - Assert.IsEqual(R, TypeExtendsResult.True) + const R = ExtendsCheck(Type.Constructor([Type.Unknown()], Type.Number({})), Type.Constructor([Type.Any()], Type.Number({}))) + Assert.IsEqual(R, ExtendsResult.True) }) it('Should extend Constructor 14', () => { type T = (new (a: any) => number) extends new (a: unknown) => number ? 1 : 2 - const R = TypeExtends.Extends(Type.Constructor([Type.Any()], Type.Number({})), Type.Constructor([Type.Unknown()], Type.Number({}))) - Assert.IsEqual(R, TypeExtendsResult.True) + const R = ExtendsCheck(Type.Constructor([Type.Any()], Type.Number({})), Type.Constructor([Type.Unknown()], Type.Number({}))) + Assert.IsEqual(R, ExtendsResult.True) }) it('Should extend Constructor 15', () => { type T = (new () => any) extends new () => unknown ? 1 : 2 - const R = TypeExtends.Extends(Type.Constructor([], Type.Any({})), Type.Constructor([], Type.Unknown({}))) - Assert.IsEqual(R, TypeExtendsResult.True) + const R = ExtendsCheck(Type.Constructor([], Type.Any({})), Type.Constructor([], Type.Unknown({}))) + Assert.IsEqual(R, ExtendsResult.True) }) it('Should extend Constructor 16', () => { type T = (new () => unknown) extends new () => any ? 1 : 2 - const R = TypeExtends.Extends(Type.Constructor([], Type.Unknown({})), Type.Constructor([], Type.Any({}))) - Assert.IsEqual(R, TypeExtendsResult.True) + const R = ExtendsCheck(Type.Constructor([], Type.Unknown({})), Type.Constructor([], Type.Any({}))) + Assert.IsEqual(R, ExtendsResult.True) }) it('Should extend Any', () => { type T = (new () => number) extends any ? 1 : 2 - const R = TypeExtends.Extends(Type.Constructor([], Type.Number()), Type.Any()) - Assert.IsEqual(R, TypeExtendsResult.True) + const R = ExtendsCheck(Type.Constructor([], Type.Number()), Type.Any()) + Assert.IsEqual(R, ExtendsResult.True) }) it('Should extend String', () => { type T = (new () => number) extends string ? 1 : 2 - const R = TypeExtends.Extends(Type.Constructor([], Type.Number()), Type.String()) - Assert.IsEqual(R, TypeExtendsResult.False) + const R = ExtendsCheck(Type.Constructor([], Type.Number()), Type.String()) + Assert.IsEqual(R, ExtendsResult.False) }) it('Should extend Boolean', () => { type T = (new () => number) extends boolean ? 1 : 2 - const R = TypeExtends.Extends(Type.Constructor([], Type.Number()), Type.Boolean()) - Assert.IsEqual(R, TypeExtendsResult.False) + const R = ExtendsCheck(Type.Constructor([], Type.Number()), Type.Boolean()) + Assert.IsEqual(R, ExtendsResult.False) }) it('Should extend Number', () => { type T = (new () => number) extends number ? 1 : 2 - const R = TypeExtends.Extends(Type.Constructor([], Type.Number()), Type.Number()) - Assert.IsEqual(R, TypeExtendsResult.False) + const R = ExtendsCheck(Type.Constructor([], Type.Number()), Type.Number()) + Assert.IsEqual(R, ExtendsResult.False) }) it('Should extend Integer', () => { type T = (new () => number) extends number ? 1 : 2 - const R = TypeExtends.Extends(Type.Constructor([], Type.Number()), Type.Integer()) - Assert.IsEqual(R, TypeExtendsResult.False) + const R = ExtendsCheck(Type.Constructor([], Type.Number()), Type.Integer()) + Assert.IsEqual(R, ExtendsResult.False) }) it('Should extend Array 1', () => { type T = (new () => number) extends Array ? 1 : 2 - const R = TypeExtends.Extends(Type.Constructor([], Type.Number()), Type.Array(Type.Any())) - Assert.IsEqual(R, TypeExtendsResult.False) + const R = ExtendsCheck(Type.Constructor([], Type.Number()), Type.Array(Type.Any())) + Assert.IsEqual(R, ExtendsResult.False) }) it('Should extend Array 2', () => { type T = (new () => number) extends Array ? 1 : 2 - const R = TypeExtends.Extends(Type.Constructor([], Type.Number()), Type.Array(Type.Any())) - Assert.IsEqual(R, TypeExtendsResult.False) + const R = ExtendsCheck(Type.Constructor([], Type.Number()), Type.Array(Type.Any())) + Assert.IsEqual(R, ExtendsResult.False) }) it('Should extend Array 3', () => { type T = (new () => number) extends Array ? 1 : 2 - const R = TypeExtends.Extends(Type.Constructor([], Type.Number()), Type.Array(Type.Any())) - Assert.IsEqual(R, TypeExtendsResult.False) + const R = ExtendsCheck(Type.Constructor([], Type.Number()), Type.Array(Type.Any())) + Assert.IsEqual(R, ExtendsResult.False) }) it('Should extend Tuple', () => { type T = (new () => number) extends [number, number] ? 1 : 2 - const R = TypeExtends.Extends(Type.Constructor([], Type.Number()), Type.Tuple([Type.Number(), Type.Number()])) - Assert.IsEqual(R, TypeExtendsResult.False) + const R = ExtendsCheck(Type.Constructor([], Type.Number()), Type.Tuple([Type.Number(), Type.Number()])) + Assert.IsEqual(R, ExtendsResult.False) }) it('Should extend Record', () => { type T = (() => number) extends Record ? 1 : 2 - const R = TypeExtends.Extends(Type.Constructor([], Type.Number()), Type.Record(Type.Number(), Type.Any())) - Assert.IsEqual(R, TypeExtendsResult.False) + const R = ExtendsCheck(Type.Constructor([], Type.Number()), Type.Record(Type.Number(), Type.Any())) + Assert.IsEqual(R, ExtendsResult.False) }) it('Should extend Object 1', () => { type T = (new () => number) extends object ? 1 : 2 - const R = TypeExtends.Extends(Type.Constructor([], Type.Number()), Type.Object({})) - Assert.IsEqual(R, TypeExtendsResult.True) + const R = ExtendsCheck(Type.Constructor([], Type.Number()), Type.Object({})) + Assert.IsEqual(R, ExtendsResult.True) }) it('Should extend Object 2', () => { type T = (new () => number) extends {} ? 1 : 2 - const R = TypeExtends.Extends(Type.Constructor([], Type.Number()), Type.Object({})) - Assert.IsEqual(R, TypeExtendsResult.True) + const R = ExtendsCheck(Type.Constructor([], Type.Number()), Type.Object({})) + Assert.IsEqual(R, ExtendsResult.True) }) it('Should extend Object 3', () => { type T = (new () => number) extends { a: number } ? 1 : 2 - const R = TypeExtends.Extends(Type.Constructor([], Type.Number()), Type.Object({ a: Type.Number() })) - Assert.IsEqual(R, TypeExtendsResult.False) + const R = ExtendsCheck(Type.Constructor([], Type.Number()), Type.Object({ a: Type.Number() })) + Assert.IsEqual(R, ExtendsResult.False) }) it('Should extend Object 4', () => { type T = (new () => number) extends { length: '1' } ? 1 : 2 - const R = TypeExtends.Extends(Type.Constructor([], Type.Number()), Type.Object({ length: Type.Literal('1') })) - Assert.IsEqual(R, TypeExtendsResult.False) + const R = ExtendsCheck(Type.Constructor([], Type.Number()), Type.Object({ length: Type.Literal('1') })) + Assert.IsEqual(R, ExtendsResult.False) }) it('Should extend Union 1', () => { type T = (new () => number) extends number | string ? 1 : 2 - const R = TypeExtends.Extends(Type.Constructor([], Type.Number()), Type.Union([Type.Null(), Type.String()])) - Assert.IsEqual(R, TypeExtendsResult.False) + const R = ExtendsCheck(Type.Constructor([], Type.Number()), Type.Union([Type.Null(), Type.String()])) + Assert.IsEqual(R, ExtendsResult.False) }) it('Should extend Union 2', () => { type T = (new () => number) extends any | number ? 1 : 2 - const R = TypeExtends.Extends(Type.Constructor([], Type.Number()), Type.Union([Type.Any(), Type.String()])) - Assert.IsEqual(R, TypeExtendsResult.True) + const R = ExtendsCheck(Type.Constructor([], Type.Number()), Type.Union([Type.Any(), Type.String()])) + Assert.IsEqual(R, ExtendsResult.True) }) it('Should extend Union 3', () => { type T = (new () => number) extends any | Array ? 1 : 2 - const R = TypeExtends.Extends(Type.Constructor([], Type.Number()), Type.Union([Type.Any(), Type.Array(Type.Any())])) - Assert.IsEqual(R, TypeExtendsResult.True) + const R = ExtendsCheck(Type.Constructor([], Type.Number()), Type.Union([Type.Any(), Type.Array(Type.Any())])) + Assert.IsEqual(R, ExtendsResult.True) }) it('Should extend Union 4', () => { type T = (new () => number) extends any | Array ? 1 : 2 - const R = TypeExtends.Extends(Type.Constructor([], Type.Number()), Type.Union([Type.Any(), Type.Array(Type.Any())])) - Assert.IsEqual(R, TypeExtendsResult.True) + const R = ExtendsCheck(Type.Constructor([], Type.Number()), Type.Union([Type.Any(), Type.Array(Type.Any())])) + Assert.IsEqual(R, ExtendsResult.True) }) it('Should extend Union 5', () => { type T = (new () => number) extends any | Array ? 1 : 2 - const R = TypeExtends.Extends(Type.Constructor([], Type.Number()), Type.Union([Type.Any(), Type.Array(Type.String())])) - Assert.IsEqual(R, TypeExtendsResult.True) + const R = ExtendsCheck(Type.Constructor([], Type.Number()), Type.Union([Type.Any(), Type.Array(Type.String())])) + Assert.IsEqual(R, ExtendsResult.True) }) it('Should extend Null', () => { type T = (new () => number) extends null ? 1 : 2 - const R = TypeExtends.Extends(Type.Constructor([], Type.Number()), Type.Null()) - Assert.IsEqual(R, TypeExtendsResult.False) + const R = ExtendsCheck(Type.Constructor([], Type.Number()), Type.Null()) + Assert.IsEqual(R, ExtendsResult.False) }) it('Should extend Undefined', () => { type T = (new () => number) extends undefined ? 1 : 2 - const R = TypeExtends.Extends(Type.Constructor([], Type.Number()), Type.Undefined()) - Assert.IsEqual(R, TypeExtendsResult.False) + const R = ExtendsCheck(Type.Constructor([], Type.Number()), Type.Undefined()) + Assert.IsEqual(R, ExtendsResult.False) }) it('Should extend Void', () => { type T = (new () => number) extends void ? 1 : 2 - const R = TypeExtends.Extends(Type.Constructor([], Type.Number()), Type.Void()) - Assert.IsEqual(R, TypeExtendsResult.False) + const R = ExtendsCheck(Type.Constructor([], Type.Number()), Type.Void()) + Assert.IsEqual(R, ExtendsResult.False) }) it('Should extend Date', () => { type T = (new () => number) extends Date ? 1 : 2 - const R = TypeExtends.Extends(Type.Constructor([], Type.Number()), Type.Date()) - Assert.IsEqual(R, TypeExtendsResult.False) + const R = ExtendsCheck(Type.Constructor([], Type.Number()), Type.Date()) + Assert.IsEqual(R, ExtendsResult.False) }) }) diff --git a/test/runtime/type/extends/date.ts b/test/runtime/type/extends/date.ts index 04df6c661..54c21d870 100644 --- a/test/runtime/type/extends/date.ts +++ b/test/runtime/type/extends/date.ts @@ -1,96 +1,96 @@ -import { TypeExtends, TypeExtendsResult } from '@sinclair/typebox' +import { ExtendsCheck, ExtendsResult } from '@sinclair/typebox/type' import { Type } from '@sinclair/typebox' import { Assert } from '../../assert/index' describe('type/extends/Date', () => { it('Should extend Any', () => { type T = Date extends any ? 1 : 2 - const R = TypeExtends.Extends(Type.Date(), Type.Any()) - Assert.IsEqual(R, TypeExtendsResult.True) + const R = ExtendsCheck(Type.Date(), Type.Any()) + Assert.IsEqual(R, ExtendsResult.True) }) it('Should extend Unknown', () => { type T = Date extends unknown ? 1 : 2 - const R = TypeExtends.Extends(Type.Date(), Type.Unknown()) - Assert.IsEqual(R, TypeExtendsResult.True) + const R = ExtendsCheck(Type.Date(), Type.Unknown()) + Assert.IsEqual(R, ExtendsResult.True) }) it('Should extend String', () => { type T = Date extends string ? 1 : 2 - const R = TypeExtends.Extends(Type.Date(), Type.String()) - Assert.IsEqual(R, TypeExtendsResult.False) + const R = ExtendsCheck(Type.Date(), Type.String()) + Assert.IsEqual(R, ExtendsResult.False) }) it('Should extend Boolean', () => { type T = Date extends boolean ? 1 : 2 - const R = TypeExtends.Extends(Type.Date(), Type.Boolean()) - Assert.IsEqual(R, TypeExtendsResult.False) + const R = ExtendsCheck(Type.Date(), Type.Boolean()) + Assert.IsEqual(R, ExtendsResult.False) }) it('Should extend Number', () => { type T = Date extends number ? 1 : 2 - const R = TypeExtends.Extends(Type.Date(), Type.Number()) - Assert.IsEqual(R, TypeExtendsResult.False) + const R = ExtendsCheck(Type.Date(), Type.Number()) + Assert.IsEqual(R, ExtendsResult.False) }) it('Should extend Integer', () => { type T = Date extends number ? 1 : 2 - const R = TypeExtends.Extends(Type.Date(), Type.Integer()) - Assert.IsEqual(R, TypeExtendsResult.False) + const R = ExtendsCheck(Type.Date(), Type.Integer()) + Assert.IsEqual(R, ExtendsResult.False) }) it('Should extend Array', () => { type T = Date extends Array ? 1 : 2 - const R = TypeExtends.Extends(Type.Date(), Type.Array(Type.Any())) - Assert.IsEqual(R, TypeExtendsResult.False) + const R = ExtendsCheck(Type.Date(), Type.Array(Type.Any())) + Assert.IsEqual(R, ExtendsResult.False) }) it('Should extend Tuple', () => { type T = Date extends [number, number] ? 1 : 2 - const R = TypeExtends.Extends(Type.Date(), Type.Tuple([Type.Number(), Type.Number()])) - Assert.IsEqual(R, TypeExtendsResult.False) + const R = ExtendsCheck(Type.Date(), Type.Tuple([Type.Number(), Type.Number()])) + Assert.IsEqual(R, ExtendsResult.False) }) it('Should extend Record', () => { type T = Date extends Record ? 1 : 2 - const R = TypeExtends.Extends(Type.Date(), Type.Record(Type.Number(), Type.Any())) - Assert.IsEqual(R, TypeExtendsResult.False) + const R = ExtendsCheck(Type.Date(), Type.Record(Type.Number(), Type.Any())) + Assert.IsEqual(R, ExtendsResult.False) }) it('Should extend Object 1', () => { type T = Date extends {} ? 1 : 2 - const R = TypeExtends.Extends(Type.Date(), Type.Object({})) - Assert.IsEqual(R, TypeExtendsResult.True) + const R = ExtendsCheck(Type.Date(), Type.Object({})) + Assert.IsEqual(R, ExtendsResult.True) }) it('Should extend Object 2', () => { type T = Date extends { a: 10 } ? 1 : 2 - const R = TypeExtends.Extends(Type.Date(), Type.Object({ a: Type.Literal(10) }, { additionalProperties: true })) - Assert.IsEqual(R, TypeExtendsResult.False) + const R = ExtendsCheck(Type.Date(), Type.Object({ a: Type.Literal(10) }, { additionalProperties: true })) + Assert.IsEqual(R, ExtendsResult.False) }) it('Should extend Union 1', () => { type T = Date extends number | string ? 1 : 2 - const R = TypeExtends.Extends(Type.Date(), Type.Union([Type.Number(), Type.String()])) - Assert.IsEqual(R, TypeExtendsResult.False) + const R = ExtendsCheck(Type.Date(), Type.Union([Type.Number(), Type.String()])) + Assert.IsEqual(R, ExtendsResult.False) }) it('Should extend Union 2', () => { type T = Date extends any | number ? 1 : 2 - const R = TypeExtends.Extends(Type.Date(), Type.Union([Type.Any(), Type.Number()])) - Assert.IsEqual(R, TypeExtendsResult.True) + const R = ExtendsCheck(Type.Date(), Type.Union([Type.Any(), Type.Number()])) + Assert.IsEqual(R, ExtendsResult.True) }) it('Should extend Union 3', () => { type T = Date extends boolean | number ? 1 : 2 - const R = TypeExtends.Extends(Type.Date(), Type.Union([Type.Boolean(), Type.Number()])) - Assert.IsEqual(R, TypeExtendsResult.False) + const R = ExtendsCheck(Type.Date(), Type.Union([Type.Boolean(), Type.Number()])) + Assert.IsEqual(R, ExtendsResult.False) }) it('Should extend Null', () => { type T = Date extends null ? 1 : 2 - const R = TypeExtends.Extends(Type.Date(), Type.Null()) - Assert.IsEqual(R, TypeExtendsResult.False) + const R = ExtendsCheck(Type.Date(), Type.Null()) + Assert.IsEqual(R, ExtendsResult.False) }) it('Should extend Undefined', () => { type T = Date extends undefined ? 1 : 2 - const R = TypeExtends.Extends(Type.Date(), Type.Undefined()) - Assert.IsEqual(R, TypeExtendsResult.False) + const R = ExtendsCheck(Type.Date(), Type.Undefined()) + Assert.IsEqual(R, ExtendsResult.False) }) it('Should extend Void', () => { type T = Date extends void ? 1 : 2 - const R = TypeExtends.Extends(Type.Date(), Type.Void()) - Assert.IsEqual(R, TypeExtendsResult.False) + const R = ExtendsCheck(Type.Date(), Type.Void()) + Assert.IsEqual(R, ExtendsResult.False) }) it('Should extend Date', () => { type T = Date extends Date ? 1 : 2 - const R = TypeExtends.Extends(Type.Date(), Type.Date()) - Assert.IsEqual(R, TypeExtendsResult.True) + const R = ExtendsCheck(Type.Date(), Type.Date()) + Assert.IsEqual(R, ExtendsResult.True) }) }) diff --git a/test/runtime/type/extends/function.ts b/test/runtime/type/extends/function.ts index 0b334087d..683ee7ef6 100644 --- a/test/runtime/type/extends/function.ts +++ b/test/runtime/type/extends/function.ts @@ -1,211 +1,211 @@ -import { TypeExtends, TypeExtendsResult } from '@sinclair/typebox' +import { ExtendsCheck, ExtendsResult } from '@sinclair/typebox/type' import { Type } from '@sinclair/typebox' import { Assert } from '../../assert/index' describe('type/extends/Function', () => { it('Should extend Constructor 1', () => { type T = (() => number) extends new () => number ? 1 : 2 - const R = TypeExtends.Extends(Type.Function([], Type.Number()), Type.Constructor([], Type.Number())) - Assert.IsEqual(R, TypeExtendsResult.False) + const R = ExtendsCheck(Type.Function([], Type.Number()), Type.Constructor([], Type.Number())) + Assert.IsEqual(R, ExtendsResult.False) }) it('Should extend Function 1', () => { type T = (() => number) extends () => number ? 1 : 2 - const R = TypeExtends.Extends(Type.Function([], Type.Number()), Type.Function([], Type.Number())) - Assert.IsEqual(R, TypeExtendsResult.True) + const R = ExtendsCheck(Type.Function([], Type.Number()), Type.Function([], Type.Number())) + Assert.IsEqual(R, ExtendsResult.True) }) it('Should extend Function 2', () => { type T = (() => any) extends () => number ? 1 : 2 - const R = TypeExtends.Extends(Type.Function([], Type.Any()), Type.Function([], Type.Number())) - Assert.IsEqual(R, TypeExtendsResult.True) + const R = ExtendsCheck(Type.Function([], Type.Any()), Type.Function([], Type.Number())) + Assert.IsEqual(R, ExtendsResult.True) }) it('Should extend Function 3', () => { type T = (() => number) extends () => any ? 1 : 2 - const R = TypeExtends.Extends(Type.Function([], Type.Any()), Type.Function([], Type.Number())) - Assert.IsEqual(R, TypeExtendsResult.True) + const R = ExtendsCheck(Type.Function([], Type.Any()), Type.Function([], Type.Number())) + Assert.IsEqual(R, ExtendsResult.True) }) it('Should extend Function 4', () => { type T = ((a: number) => number) extends () => any ? 1 : 2 - const R = TypeExtends.Extends(Type.Function([Type.Number()], Type.Number()), Type.Function([], Type.Any())) - Assert.IsEqual(R, TypeExtendsResult.False) + const R = ExtendsCheck(Type.Function([Type.Number()], Type.Number()), Type.Function([], Type.Any())) + Assert.IsEqual(R, ExtendsResult.False) }) it('Should extend Function 5', () => { type T = ((a: number | string) => number) extends (a: number) => number ? 1 : 2 - const R = TypeExtends.Extends(Type.Function([Type.Union([Type.Number(), Type.String()])], Type.Number()), Type.Function([Type.Number()], Type.Any())) - Assert.IsEqual(R, TypeExtendsResult.True) + const R = ExtendsCheck(Type.Function([Type.Union([Type.Number(), Type.String()])], Type.Number()), Type.Function([Type.Number()], Type.Any())) + Assert.IsEqual(R, ExtendsResult.True) }) it('Should extend Function 6', () => { type T = ((a: number) => number) extends (a: number | string) => any ? 1 : 2 - const R = TypeExtends.Extends(Type.Function([Type.Number()], Type.Number()), Type.Function([Type.Union([Type.Number(), Type.String()])], Type.Any())) - Assert.IsEqual(R, TypeExtendsResult.False) + const R = ExtendsCheck(Type.Function([Type.Number()], Type.Number()), Type.Function([Type.Union([Type.Number(), Type.String()])], Type.Any())) + Assert.IsEqual(R, ExtendsResult.False) }) it('Should extend Function 7', () => { type T = ((a: number, b: number) => number) extends (a: number) => number ? 1 : 2 - const R = TypeExtends.Extends(Type.Function([Type.Number(), Type.Number()], Type.Number()), Type.Function([Type.Number()], Type.Number())) - Assert.IsEqual(R, TypeExtendsResult.False) + const R = ExtendsCheck(Type.Function([Type.Number(), Type.Number()], Type.Number()), Type.Function([Type.Number()], Type.Number())) + Assert.IsEqual(R, ExtendsResult.False) }) it('Should extend Function 8', () => { type T = ((a: number) => number) extends (a: number, b: number) => number ? 1 : 2 - const R = TypeExtends.Extends(Type.Function([Type.Number()], Type.Number()), Type.Function([Type.Number(), Type.Number()], Type.Number())) - Assert.IsEqual(R, TypeExtendsResult.True) + const R = ExtendsCheck(Type.Function([Type.Number()], Type.Number()), Type.Function([Type.Number(), Type.Number()], Type.Number())) + Assert.IsEqual(R, ExtendsResult.True) }) it('Should extend Function 9', () => { type T = (() => number) extends () => any ? 1 : 2 - const R = TypeExtends.Extends(Type.Function([], Type.Number()), Type.Function([], Type.Any())) - Assert.IsEqual(R, TypeExtendsResult.True) + const R = ExtendsCheck(Type.Function([], Type.Number()), Type.Function([], Type.Any())) + Assert.IsEqual(R, ExtendsResult.True) }) it('Should extend Function 9', () => { type T = (() => any) extends () => number ? 1 : 2 - const R = TypeExtends.Extends(Type.Function([], Type.Any()), Type.Function([], Type.Number())) - Assert.IsEqual(R, TypeExtendsResult.True) + const R = ExtendsCheck(Type.Function([], Type.Any()), Type.Function([], Type.Number())) + Assert.IsEqual(R, ExtendsResult.True) }) it('Should extend Function 10', () => { type T = (() => Array) extends () => object ? 1 : 2 - const R = TypeExtends.Extends(Type.Function([], Type.Array(Type.Any())), Type.Function([], Type.Object({}))) - Assert.IsEqual(R, TypeExtendsResult.True) + const R = ExtendsCheck(Type.Function([], Type.Array(Type.Any())), Type.Function([], Type.Object({}))) + Assert.IsEqual(R, ExtendsResult.True) }) it('Should extend Function 11', () => { type T = (() => Array) extends () => object ? 1 : 2 - const R = TypeExtends.Extends(Type.Function([], Type.Array(Type.String())), Type.Function([], Type.Object({}))) - Assert.IsEqual(R, TypeExtendsResult.True) + const R = ExtendsCheck(Type.Function([], Type.Array(Type.String())), Type.Function([], Type.Object({}))) + Assert.IsEqual(R, ExtendsResult.True) }) it('Should extend Function 12', () => { type T = (() => object) extends () => Array ? 1 : 2 - const R = TypeExtends.Extends(Type.Function([], Type.Object({})), Type.Function([], Type.Array(Type.Any()))) - Assert.IsEqual(R, TypeExtendsResult.False) + const R = ExtendsCheck(Type.Function([], Type.Object({})), Type.Function([], Type.Array(Type.Any()))) + Assert.IsEqual(R, ExtendsResult.False) }) it('Should extend Function 13', () => { type T = ((a: unknown) => number) extends (a: any) => number ? 1 : 2 - const R = TypeExtends.Extends(Type.Function([Type.Unknown()], Type.Number({})), Type.Function([Type.Any()], Type.Number({}))) - Assert.IsEqual(R, TypeExtendsResult.True) + const R = ExtendsCheck(Type.Function([Type.Unknown()], Type.Number({})), Type.Function([Type.Any()], Type.Number({}))) + Assert.IsEqual(R, ExtendsResult.True) }) it('Should extend Function 14', () => { type T = ((a: any) => number) extends (a: unknown) => number ? 1 : 2 - const R = TypeExtends.Extends(Type.Function([Type.Any()], Type.Number({})), Type.Function([Type.Unknown()], Type.Number({}))) - Assert.IsEqual(R, TypeExtendsResult.True) + const R = ExtendsCheck(Type.Function([Type.Any()], Type.Number({})), Type.Function([Type.Unknown()], Type.Number({}))) + Assert.IsEqual(R, ExtendsResult.True) }) it('Should extend Function 15', () => { type T = (() => any) extends () => unknown ? 1 : 2 - const R = TypeExtends.Extends(Type.Function([], Type.Any({})), Type.Function([], Type.Unknown({}))) - Assert.IsEqual(R, TypeExtendsResult.True) + const R = ExtendsCheck(Type.Function([], Type.Any({})), Type.Function([], Type.Unknown({}))) + Assert.IsEqual(R, ExtendsResult.True) }) it('Should extend Function 16', () => { type T = (() => unknown) extends () => any ? 1 : 2 - const R = TypeExtends.Extends(Type.Function([], Type.Unknown({})), Type.Function([], Type.Any({}))) - Assert.IsEqual(R, TypeExtendsResult.True) + const R = ExtendsCheck(Type.Function([], Type.Unknown({})), Type.Function([], Type.Any({}))) + Assert.IsEqual(R, ExtendsResult.True) }) it('Should extend Any', () => { type T = (() => number) extends any ? 1 : 2 - const R = TypeExtends.Extends(Type.Function([], Type.Number()), Type.Any()) - Assert.IsEqual(R, TypeExtendsResult.True) + const R = ExtendsCheck(Type.Function([], Type.Number()), Type.Any()) + Assert.IsEqual(R, ExtendsResult.True) }) it('Should extend String', () => { type T = (() => number) extends string ? 1 : 2 - const R = TypeExtends.Extends(Type.Function([], Type.Number()), Type.String()) - Assert.IsEqual(R, TypeExtendsResult.False) + const R = ExtendsCheck(Type.Function([], Type.Number()), Type.String()) + Assert.IsEqual(R, ExtendsResult.False) }) it('Should extend Boolean', () => { type T = (() => number) extends boolean ? 1 : 2 - const R = TypeExtends.Extends(Type.Function([], Type.Number()), Type.Boolean()) - Assert.IsEqual(R, TypeExtendsResult.False) + const R = ExtendsCheck(Type.Function([], Type.Number()), Type.Boolean()) + Assert.IsEqual(R, ExtendsResult.False) }) it('Should extend Number', () => { type T = (() => number) extends number ? 1 : 2 - const R = TypeExtends.Extends(Type.Function([], Type.Number()), Type.Number()) - Assert.IsEqual(R, TypeExtendsResult.False) + const R = ExtendsCheck(Type.Function([], Type.Number()), Type.Number()) + Assert.IsEqual(R, ExtendsResult.False) }) it('Should extend Integer', () => { type T = (() => number) extends number ? 1 : 2 - const R = TypeExtends.Extends(Type.Function([], Type.Number()), Type.Integer()) - Assert.IsEqual(R, TypeExtendsResult.False) + const R = ExtendsCheck(Type.Function([], Type.Number()), Type.Integer()) + Assert.IsEqual(R, ExtendsResult.False) }) it('Should extend Array 1', () => { type T = (() => number) extends Array ? 1 : 2 - const R = TypeExtends.Extends(Type.Function([], Type.Number()), Type.Array(Type.Any())) - Assert.IsEqual(R, TypeExtendsResult.False) + const R = ExtendsCheck(Type.Function([], Type.Number()), Type.Array(Type.Any())) + Assert.IsEqual(R, ExtendsResult.False) }) it('Should extend Array 2', () => { type T = (() => number) extends Array ? 1 : 2 - const R = TypeExtends.Extends(Type.Function([], Type.Number()), Type.Array(Type.Any())) - Assert.IsEqual(R, TypeExtendsResult.False) + const R = ExtendsCheck(Type.Function([], Type.Number()), Type.Array(Type.Any())) + Assert.IsEqual(R, ExtendsResult.False) }) it('Should extend Array 3', () => { type T = (() => number) extends Array ? 1 : 2 - const R = TypeExtends.Extends(Type.Function([], Type.Number()), Type.Array(Type.Any())) - Assert.IsEqual(R, TypeExtendsResult.False) + const R = ExtendsCheck(Type.Function([], Type.Number()), Type.Array(Type.Any())) + Assert.IsEqual(R, ExtendsResult.False) }) it('Should extend Tuple', () => { type T = (() => number) extends [number, number] ? 1 : 2 - const R = TypeExtends.Extends(Type.Function([], Type.Number()), Type.Tuple([Type.Number(), Type.Number()])) - Assert.IsEqual(R, TypeExtendsResult.False) + const R = ExtendsCheck(Type.Function([], Type.Number()), Type.Tuple([Type.Number(), Type.Number()])) + Assert.IsEqual(R, ExtendsResult.False) }) it('Should extend Record', () => { type T = (() => number) extends Record ? 1 : 2 - const R = TypeExtends.Extends(Type.Function([], Type.Number()), Type.Record(Type.Number(), Type.Any())) - Assert.IsEqual(R, TypeExtendsResult.False) + const R = ExtendsCheck(Type.Function([], Type.Number()), Type.Record(Type.Number(), Type.Any())) + Assert.IsEqual(R, ExtendsResult.False) }) it('Should extend Object 1', () => { type T = (() => number) extends object ? 1 : 2 - const R = TypeExtends.Extends(Type.Function([], Type.Number()), Type.Object({})) - Assert.IsEqual(R, TypeExtendsResult.True) + const R = ExtendsCheck(Type.Function([], Type.Number()), Type.Object({})) + Assert.IsEqual(R, ExtendsResult.True) }) it('Should extend Object 2', () => { type T = (() => number) extends {} ? 1 : 2 - const R = TypeExtends.Extends(Type.Function([], Type.Number()), Type.Object({})) - Assert.IsEqual(R, TypeExtendsResult.True) + const R = ExtendsCheck(Type.Function([], Type.Number()), Type.Object({})) + Assert.IsEqual(R, ExtendsResult.True) }) it('Should extend Object 3', () => { type T = (() => number) extends { a: number } ? 1 : 2 - const R = TypeExtends.Extends(Type.Function([], Type.Number()), Type.Object({ a: Type.Number() })) - Assert.IsEqual(R, TypeExtendsResult.False) + const R = ExtendsCheck(Type.Function([], Type.Number()), Type.Object({ a: Type.Number() })) + Assert.IsEqual(R, ExtendsResult.False) }) it('Should extend Object 4', () => { type T = (() => number) extends { length: '1' } ? 1 : 2 - const R = TypeExtends.Extends(Type.Function([], Type.Number()), Type.Object({ length: Type.Literal('1') })) - Assert.IsEqual(R, TypeExtendsResult.False) + const R = ExtendsCheck(Type.Function([], Type.Number()), Type.Object({ length: Type.Literal('1') })) + Assert.IsEqual(R, ExtendsResult.False) }) it('Should extend Object 5', () => { type T = (() => number) extends { length: number } ? 1 : 2 - const R = TypeExtends.Extends(Type.Function([], Type.Number()), Type.Object({ length: Type.Number() })) - Assert.IsEqual(R, TypeExtendsResult.True) + const R = ExtendsCheck(Type.Function([], Type.Number()), Type.Object({ length: Type.Number() })) + Assert.IsEqual(R, ExtendsResult.True) }) it('Should extend Union 1', () => { type T = (() => number) extends number | string ? 1 : 2 - const R = TypeExtends.Extends(Type.Function([], Type.Number()), Type.Union([Type.Null(), Type.String()])) - Assert.IsEqual(R, TypeExtendsResult.False) + const R = ExtendsCheck(Type.Function([], Type.Number()), Type.Union([Type.Null(), Type.String()])) + Assert.IsEqual(R, ExtendsResult.False) }) it('Should extend Union 2', () => { type T = (() => number) extends any | number ? 1 : 2 - const R = TypeExtends.Extends(Type.Function([], Type.Number()), Type.Union([Type.Any(), Type.String()])) - Assert.IsEqual(R, TypeExtendsResult.True) + const R = ExtendsCheck(Type.Function([], Type.Number()), Type.Union([Type.Any(), Type.String()])) + Assert.IsEqual(R, ExtendsResult.True) }) it('Should extend Union 3', () => { type T = (() => number) extends any | Array ? 1 : 2 - const R = TypeExtends.Extends(Type.Function([], Type.Number()), Type.Union([Type.Any(), Type.Array(Type.Any())])) - Assert.IsEqual(R, TypeExtendsResult.True) + const R = ExtendsCheck(Type.Function([], Type.Number()), Type.Union([Type.Any(), Type.Array(Type.Any())])) + Assert.IsEqual(R, ExtendsResult.True) }) it('Should extend Union 4', () => { type T = (() => number) extends any | Array ? 1 : 2 - const R = TypeExtends.Extends(Type.Function([], Type.Number()), Type.Union([Type.Any(), Type.Array(Type.Any())])) - Assert.IsEqual(R, TypeExtendsResult.True) + const R = ExtendsCheck(Type.Function([], Type.Number()), Type.Union([Type.Any(), Type.Array(Type.Any())])) + Assert.IsEqual(R, ExtendsResult.True) }) it('Should extend Union 5', () => { type T = (() => number) extends any | Array ? 1 : 2 - const R = TypeExtends.Extends(Type.Function([], Type.Number()), Type.Union([Type.Any(), Type.Array(Type.String())])) - Assert.IsEqual(R, TypeExtendsResult.True) + const R = ExtendsCheck(Type.Function([], Type.Number()), Type.Union([Type.Any(), Type.Array(Type.String())])) + Assert.IsEqual(R, ExtendsResult.True) }) it('Should extend Null', () => { type T = (() => number) extends null ? 1 : 2 - const R = TypeExtends.Extends(Type.Function([], Type.Number()), Type.Null()) - Assert.IsEqual(R, TypeExtendsResult.False) + const R = ExtendsCheck(Type.Function([], Type.Number()), Type.Null()) + Assert.IsEqual(R, ExtendsResult.False) }) it('Should extend Void', () => { type T = (() => number) extends undefined ? 1 : 2 - const R = TypeExtends.Extends(Type.Function([], Type.Number()), Type.Void()) - Assert.IsEqual(R, TypeExtendsResult.False) + const R = ExtendsCheck(Type.Function([], Type.Number()), Type.Void()) + Assert.IsEqual(R, ExtendsResult.False) }) it('Should extend Date', () => { type T = (() => number) extends Date ? 1 : 2 - const R = TypeExtends.Extends(Type.Constructor([], Type.Number()), Type.Date()) - Assert.IsEqual(R, TypeExtendsResult.False) + const R = ExtendsCheck(Type.Constructor([], Type.Number()), Type.Date()) + Assert.IsEqual(R, ExtendsResult.False) }) }) diff --git a/test/runtime/type/extends/integer.ts b/test/runtime/type/extends/integer.ts index 1c5d00995..a429f4c8a 100644 --- a/test/runtime/type/extends/integer.ts +++ b/test/runtime/type/extends/integer.ts @@ -1,96 +1,96 @@ -import { TypeExtends, TypeExtendsResult } from '@sinclair/typebox' +import { ExtendsCheck, ExtendsResult } from '@sinclair/typebox/type' import { Type } from '@sinclair/typebox' import { Assert } from '../../assert/index' describe('type/extends/Integer', () => { it('Should extend Any', () => { type T = number extends any ? 1 : 2 - const R = TypeExtends.Extends(Type.Integer(), Type.Any()) - Assert.IsEqual(R, TypeExtendsResult.True) + const R = ExtendsCheck(Type.Integer(), Type.Any()) + Assert.IsEqual(R, ExtendsResult.True) }) it('Should extend Unknown', () => { type T = number extends unknown ? 1 : 2 - const R = TypeExtends.Extends(Type.Integer(), Type.Unknown()) - Assert.IsEqual(R, TypeExtendsResult.True) + const R = ExtendsCheck(Type.Integer(), Type.Unknown()) + Assert.IsEqual(R, ExtendsResult.True) }) it('Should extend String', () => { type T = number extends string ? 1 : 2 - const R = TypeExtends.Extends(Type.Integer(), Type.String()) - Assert.IsEqual(R, TypeExtendsResult.False) + const R = ExtendsCheck(Type.Integer(), Type.String()) + Assert.IsEqual(R, ExtendsResult.False) }) it('Should extend Boolean', () => { type T = number extends boolean ? 1 : 2 - const R = TypeExtends.Extends(Type.Integer(), Type.Boolean()) - Assert.IsEqual(R, TypeExtendsResult.False) + const R = ExtendsCheck(Type.Integer(), Type.Boolean()) + Assert.IsEqual(R, ExtendsResult.False) }) it('Should extend Number', () => { type T = number extends number ? 1 : 2 - const R = TypeExtends.Extends(Type.Integer(), Type.Number()) - Assert.IsEqual(R, TypeExtendsResult.True) + const R = ExtendsCheck(Type.Integer(), Type.Number()) + Assert.IsEqual(R, ExtendsResult.True) }) it('Should extend Integer', () => { type T = number extends number ? 1 : 2 - const R = TypeExtends.Extends(Type.Integer(), Type.Integer()) - Assert.IsEqual(R, TypeExtendsResult.True) + const R = ExtendsCheck(Type.Integer(), Type.Integer()) + Assert.IsEqual(R, ExtendsResult.True) }) it('Should extend Array', () => { type T = number extends Array ? 1 : 2 - const R = TypeExtends.Extends(Type.Integer(), Type.Array(Type.Any())) - Assert.IsEqual(R, TypeExtendsResult.False) + const R = ExtendsCheck(Type.Integer(), Type.Array(Type.Any())) + Assert.IsEqual(R, ExtendsResult.False) }) it('Should extend Tuple', () => { type T = number extends [number, number] ? 1 : 2 - const R = TypeExtends.Extends(Type.Integer(), Type.Tuple([Type.Number(), Type.Number()])) - Assert.IsEqual(R, TypeExtendsResult.False) + const R = ExtendsCheck(Type.Integer(), Type.Tuple([Type.Number(), Type.Number()])) + Assert.IsEqual(R, ExtendsResult.False) }) it('Should extend Record', () => { type T = number extends Record ? 1 : 2 - const R = TypeExtends.Extends(Type.Integer(), Type.Record(Type.Number(), Type.Any())) - Assert.IsEqual(R, TypeExtendsResult.False) + const R = ExtendsCheck(Type.Integer(), Type.Record(Type.Number(), Type.Any())) + Assert.IsEqual(R, ExtendsResult.False) }) it('Should extend Object 1', () => { type T = number extends {} ? 1 : 2 - const R = TypeExtends.Extends(Type.Integer(), Type.Object({})) - Assert.IsEqual(R, TypeExtendsResult.True) + const R = ExtendsCheck(Type.Integer(), Type.Object({})) + Assert.IsEqual(R, ExtendsResult.True) }) it('Should extend Object 2', () => { type T = number extends { a: 10 } ? 1 : 2 - const R = TypeExtends.Extends(Type.Integer(), Type.Object({ a: Type.Literal(10) })) - Assert.IsEqual(R, TypeExtendsResult.False) + const R = ExtendsCheck(Type.Integer(), Type.Object({ a: Type.Literal(10) })) + Assert.IsEqual(R, ExtendsResult.False) }) it('Should extend Union 1', () => { type T = number extends number | string ? 1 : 2 - const R = TypeExtends.Extends(Type.Integer(), Type.Union([Type.Number(), Type.String()])) - Assert.IsEqual(R, TypeExtendsResult.True) + const R = ExtendsCheck(Type.Integer(), Type.Union([Type.Number(), Type.String()])) + Assert.IsEqual(R, ExtendsResult.True) }) it('Should extend Union 2', () => { type T = number extends any | number ? 1 : 2 - const R = TypeExtends.Extends(Type.Integer(), Type.Union([Type.Any(), Type.Number()])) - Assert.IsEqual(R, TypeExtendsResult.True) + const R = ExtendsCheck(Type.Integer(), Type.Union([Type.Any(), Type.Number()])) + Assert.IsEqual(R, ExtendsResult.True) }) it('Should extend Union 2', () => { type T = number extends boolean | number ? 1 : 2 - const R = TypeExtends.Extends(Type.Integer(), Type.Union([Type.Boolean(), Type.Number()])) - Assert.IsEqual(R, TypeExtendsResult.True) + const R = ExtendsCheck(Type.Integer(), Type.Union([Type.Boolean(), Type.Number()])) + Assert.IsEqual(R, ExtendsResult.True) }) it('Should extend Null', () => { type T = number extends null ? 1 : 2 - const R = TypeExtends.Extends(Type.Integer(), Type.Null()) - Assert.IsEqual(R, TypeExtendsResult.False) + const R = ExtendsCheck(Type.Integer(), Type.Null()) + Assert.IsEqual(R, ExtendsResult.False) }) it('Should extend Undefined', () => { type T = number extends undefined ? 1 : 2 - const R = TypeExtends.Extends(Type.Integer(), Type.Undefined()) - Assert.IsEqual(R, TypeExtendsResult.False) + const R = ExtendsCheck(Type.Integer(), Type.Undefined()) + Assert.IsEqual(R, ExtendsResult.False) }) it('Should extend Void', () => { type T = number extends undefined ? 1 : 2 - const R = TypeExtends.Extends(Type.Integer(), Type.Void()) - Assert.IsEqual(R, TypeExtendsResult.False) + const R = ExtendsCheck(Type.Integer(), Type.Void()) + Assert.IsEqual(R, ExtendsResult.False) }) it('Should extend Date', () => { type T = number extends Date ? 1 : 2 - const R = TypeExtends.Extends(Type.Number(), Type.Date()) - Assert.IsEqual(R, TypeExtendsResult.False) + const R = ExtendsCheck(Type.Number(), Type.Date()) + Assert.IsEqual(R, ExtendsResult.False) }) }) diff --git a/test/runtime/type/extends/iterator.ts b/test/runtime/type/extends/iterator.ts index 1cf5b6bfd..9ad67081d 100644 --- a/test/runtime/type/extends/iterator.ts +++ b/test/runtime/type/extends/iterator.ts @@ -1,4 +1,4 @@ -import { TypeExtends, TypeExtendsResult } from '@sinclair/typebox' +import { ExtendsCheck, ExtendsResult } from '@sinclair/typebox/type' import { Type } from '@sinclair/typebox' import { Assert } from '../../assert/index' @@ -8,65 +8,65 @@ describe('type/extends/Iterator', () => { // ---------------------------------------------- it('Should extend Iterator 1', () => { type T = IterableIterator extends IterableIterator ? 1 : 2 - const R = TypeExtends.Extends(Type.Iterator(Type.Any()), Type.Iterator(Type.Any())) - Assert.IsEqual(R, TypeExtendsResult.True) + const R = ExtendsCheck(Type.Iterator(Type.Any()), Type.Iterator(Type.Any())) + Assert.IsEqual(R, ExtendsResult.True) }) it('Should extend Iterator 2', () => { type T = IterableIterator extends IterableIterator ? 1 : 2 - const R = TypeExtends.Extends(Type.Iterator(Type.String()), Type.Iterator(Type.String())) - Assert.IsEqual(R, TypeExtendsResult.True) + const R = ExtendsCheck(Type.Iterator(Type.String()), Type.Iterator(Type.String())) + Assert.IsEqual(R, ExtendsResult.True) }) it('Should extend Iterator 3', () => { type T = IterableIterator<'hello'> extends IterableIterator ? 1 : 2 - const R = TypeExtends.Extends(Type.Iterator(Type.Literal('hello')), Type.Iterator(Type.String())) - Assert.IsEqual(R, TypeExtendsResult.True) + const R = ExtendsCheck(Type.Iterator(Type.Literal('hello')), Type.Iterator(Type.String())) + Assert.IsEqual(R, ExtendsResult.True) }) it('Should extend Iterator 4', () => { type T = IterableIterator extends IterableIterator<'hello'> ? 1 : 2 - const R = TypeExtends.Extends(Type.Iterator(Type.String()), Type.Iterator(Type.Literal('hello'))) - Assert.IsEqual(R, TypeExtendsResult.False) + const R = ExtendsCheck(Type.Iterator(Type.String()), Type.Iterator(Type.Literal('hello'))) + Assert.IsEqual(R, ExtendsResult.False) }) it('Should extend Iterator 5', () => { type T = IterableIterator extends IterableIterator<'hello' | number> ? 1 : 2 - const R = TypeExtends.Extends(Type.Iterator(Type.String()), Type.Iterator(Type.Union([Type.Literal('hello'), Type.Number()]))) - Assert.IsEqual(R, TypeExtendsResult.False) + const R = ExtendsCheck(Type.Iterator(Type.String()), Type.Iterator(Type.Union([Type.Literal('hello'), Type.Number()]))) + Assert.IsEqual(R, ExtendsResult.False) }) it('Should extend Iterator 6', () => { type T = IterableIterator<'hello' | number> extends IterableIterator ? 1 : 2 - const R = TypeExtends.Extends(Type.Iterator(Type.Union([Type.Literal('hello'), Type.Number()])), Type.Iterator(Type.String())) - Assert.IsEqual(R, TypeExtendsResult.False) + const R = ExtendsCheck(Type.Iterator(Type.Union([Type.Literal('hello'), Type.Number()])), Type.Iterator(Type.String())) + Assert.IsEqual(R, ExtendsResult.False) }) // -------------------------------------------------------------------- // Structural // -------------------------------------------------------------------- it('Should extends Any 1', () => { type T = IterableIterator extends any ? 1 : 2 - const R = TypeExtends.Extends(Type.Iterator(Type.Number()), Type.Any()) - Assert.IsEqual(R, TypeExtendsResult.True) + const R = ExtendsCheck(Type.Iterator(Type.Number()), Type.Any()) + Assert.IsEqual(R, ExtendsResult.True) }) it('Should extends Any 2', () => { type T = any extends IterableIterator ? 1 : 2 - const R = TypeExtends.Extends(Type.Any(), Type.Iterator(Type.Number())) - Assert.IsEqual(R, TypeExtendsResult.Union) + const R = ExtendsCheck(Type.Any(), Type.Iterator(Type.Number())) + Assert.IsEqual(R, ExtendsResult.Union) }) it('Should extends Unknown 1', () => { type T = IterableIterator extends unknown ? 1 : 2 - const R = TypeExtends.Extends(Type.Iterator(Type.Number()), Type.Unknown()) - Assert.IsEqual(R, TypeExtendsResult.True) + const R = ExtendsCheck(Type.Iterator(Type.Number()), Type.Unknown()) + Assert.IsEqual(R, ExtendsResult.True) }) it('Should extends Unknown 2', () => { type T = unknown extends IterableIterator ? 1 : 2 - const R = TypeExtends.Extends(Type.Unknown(), Type.Iterator(Type.Number())) - Assert.IsEqual(R, TypeExtendsResult.False) + const R = ExtendsCheck(Type.Unknown(), Type.Iterator(Type.Number())) + Assert.IsEqual(R, ExtendsResult.False) }) it('Should extends Never 1', () => { type T = IterableIterator extends never ? 1 : 2 - const R = TypeExtends.Extends(Type.Iterator(Type.Number()), Type.Never()) - Assert.IsEqual(R, TypeExtendsResult.False) + const R = ExtendsCheck(Type.Iterator(Type.Number()), Type.Never()) + Assert.IsEqual(R, ExtendsResult.False) }) it('Should extends Never 2', () => { type T = never extends IterableIterator ? 1 : 2 - const R = TypeExtends.Extends(Type.Never(), Type.Iterator(Type.Number())) - Assert.IsEqual(R, TypeExtendsResult.True) + const R = ExtendsCheck(Type.Never(), Type.Iterator(Type.Number())) + Assert.IsEqual(R, ExtendsResult.True) }) }) diff --git a/test/runtime/type/extends/literal.ts b/test/runtime/type/extends/literal.ts index 7c23890fc..8d5e9358b 100644 --- a/test/runtime/type/extends/literal.ts +++ b/test/runtime/type/extends/literal.ts @@ -1,4 +1,4 @@ -import { TypeExtends, TypeExtendsResult } from '@sinclair/typebox' +import { ExtendsCheck, ExtendsResult } from '@sinclair/typebox/type' import { Type } from '@sinclair/typebox' import { Assert } from '../../assert/index' @@ -8,258 +8,258 @@ describe('type/extends/Literal', () => { // ------------------------------------------------------------------- it('Should extend Any (String)', () => { type T = 'hello' extends any ? 1 : 2 - const R = TypeExtends.Extends(Type.Literal('hello'), Type.Any()) - Assert.IsEqual(R, TypeExtendsResult.True) + const R = ExtendsCheck(Type.Literal('hello'), Type.Any()) + Assert.IsEqual(R, ExtendsResult.True) }) it('Should extend Unknown (String)', () => { type T = 'hello' extends unknown ? 1 : 2 - const R = TypeExtends.Extends(Type.Literal('hello'), Type.Unknown()) - Assert.IsEqual(R, TypeExtendsResult.True) + const R = ExtendsCheck(Type.Literal('hello'), Type.Unknown()) + Assert.IsEqual(R, ExtendsResult.True) }) it('Should extend String (String)', () => { type T = 'hello' extends string ? 1 : 2 - const R = TypeExtends.Extends(Type.Literal('hello'), Type.String()) - Assert.IsEqual(R, TypeExtendsResult.True) + const R = ExtendsCheck(Type.Literal('hello'), Type.String()) + Assert.IsEqual(R, ExtendsResult.True) }) it('Should extend Boolean (String)', () => { type T = 'hello' extends boolean ? 1 : 2 - const R = TypeExtends.Extends(Type.Literal('hello'), Type.Boolean()) - Assert.IsEqual(R, TypeExtendsResult.False) + const R = ExtendsCheck(Type.Literal('hello'), Type.Boolean()) + Assert.IsEqual(R, ExtendsResult.False) }) it('Should extend Number (String)', () => { type T = 'hello' extends number ? 1 : 2 - const R = TypeExtends.Extends(Type.Literal('hello'), Type.Number()) - Assert.IsEqual(R, TypeExtendsResult.False) + const R = ExtendsCheck(Type.Literal('hello'), Type.Number()) + Assert.IsEqual(R, ExtendsResult.False) }) it('Should extend Integer (String)', () => { type T = 'hello' extends number ? 1 : 2 - const R = TypeExtends.Extends(Type.Literal('hello'), Type.Integer()) - Assert.IsEqual(R, TypeExtendsResult.False) + const R = ExtendsCheck(Type.Literal('hello'), Type.Integer()) + Assert.IsEqual(R, ExtendsResult.False) }) it('Should extend Array (String)', () => { type T = 'hello' extends Array ? 1 : 2 - const R = TypeExtends.Extends(Type.Literal('hello'), Type.Array(Type.Any())) - Assert.IsEqual(R, TypeExtendsResult.False) + const R = ExtendsCheck(Type.Literal('hello'), Type.Array(Type.Any())) + Assert.IsEqual(R, ExtendsResult.False) }) it('Should extend Tuple (String)', () => { type T = 'hello' extends [number, number] ? 1 : 2 - const R = TypeExtends.Extends(Type.Literal('hello'), Type.Tuple([Type.Number(), Type.Number()])) - Assert.IsEqual(R, TypeExtendsResult.False) + const R = ExtendsCheck(Type.Literal('hello'), Type.Tuple([Type.Number(), Type.Number()])) + Assert.IsEqual(R, ExtendsResult.False) }) it('Should extend Object 1 (String)', () => { type T = 'hello' extends {} ? 1 : 2 - const R = TypeExtends.Extends(Type.Literal('hello'), Type.Object({}, { additionalProperties: false })) - Assert.IsEqual(R, TypeExtendsResult.True) + const R = ExtendsCheck(Type.Literal('hello'), Type.Object({}, { additionalProperties: false })) + Assert.IsEqual(R, ExtendsResult.True) }) it('Should extend Object 2 (String)', () => { type T = 'hello' extends { a: 10 } ? 1 : 2 - const R = TypeExtends.Extends(Type.Literal('hello'), Type.Object({ a: Type.Literal(10) }, { additionalProperties: true })) - Assert.IsEqual(R, TypeExtendsResult.False) + const R = ExtendsCheck(Type.Literal('hello'), Type.Object({ a: Type.Literal(10) }, { additionalProperties: true })) + Assert.IsEqual(R, ExtendsResult.False) }) it('Should extend Union 1 (String)', () => { type T = 'hello' extends number | string ? 1 : 2 - const R = TypeExtends.Extends(Type.Literal('hello'), Type.Union([Type.Number(), Type.String()])) - Assert.IsEqual(R, TypeExtendsResult.True) + const R = ExtendsCheck(Type.Literal('hello'), Type.Union([Type.Number(), Type.String()])) + Assert.IsEqual(R, ExtendsResult.True) }) it('Should extend Union 2 (String)', () => { type T = 'hello' extends any | number ? 1 : 2 - const R = TypeExtends.Extends(Type.Literal('hello'), Type.Union([Type.Any(), Type.Number()])) - Assert.IsEqual(R, TypeExtendsResult.True) + const R = ExtendsCheck(Type.Literal('hello'), Type.Union([Type.Any(), Type.Number()])) + Assert.IsEqual(R, ExtendsResult.True) }) it('Should extend Union 3 (String)', () => { type T = 'hello' extends boolean | number ? 1 : 2 - const R = TypeExtends.Extends(Type.Literal('hello'), Type.Union([Type.Boolean(), Type.Number()])) - Assert.IsEqual(R, TypeExtendsResult.False) + const R = ExtendsCheck(Type.Literal('hello'), Type.Union([Type.Boolean(), Type.Number()])) + Assert.IsEqual(R, ExtendsResult.False) }) it('Should extend Null (String)', () => { type T = 'hello' extends null ? 1 : 2 - const R = TypeExtends.Extends(Type.Literal('hello'), Type.Null()) - Assert.IsEqual(R, TypeExtendsResult.False) + const R = ExtendsCheck(Type.Literal('hello'), Type.Null()) + Assert.IsEqual(R, ExtendsResult.False) }) it('Should extend Undefined (String)', () => { type T = 'hello' extends undefined ? 1 : 2 - const R = TypeExtends.Extends(Type.Literal('hello'), Type.Undefined()) - Assert.IsEqual(R, TypeExtendsResult.False) + const R = ExtendsCheck(Type.Literal('hello'), Type.Undefined()) + Assert.IsEqual(R, ExtendsResult.False) }) // ------------------------------------------------------------------- // Number Literal // ------------------------------------------------------------------- it('Should extend Any (Number)', () => { type T = 10 extends any ? 1 : 2 - const R = TypeExtends.Extends(Type.Literal(10), Type.Any()) - Assert.IsEqual(R, TypeExtendsResult.True) + const R = ExtendsCheck(Type.Literal(10), Type.Any()) + Assert.IsEqual(R, ExtendsResult.True) }) it('Should extend Unknown (Number)', () => { type T = 10 extends unknown ? 1 : 2 - const R = TypeExtends.Extends(Type.Literal(10), Type.Unknown()) - Assert.IsEqual(R, TypeExtendsResult.True) + const R = ExtendsCheck(Type.Literal(10), Type.Unknown()) + Assert.IsEqual(R, ExtendsResult.True) }) it('Should extend String (Number)', () => { type T = 10 extends string ? 1 : 2 - const R = TypeExtends.Extends(Type.Literal(10), Type.String()) - Assert.IsEqual(R, TypeExtendsResult.False) + const R = ExtendsCheck(Type.Literal(10), Type.String()) + Assert.IsEqual(R, ExtendsResult.False) }) it('Should extend Boolean (Number)', () => { type T = 10 extends boolean ? 1 : 2 - const R = TypeExtends.Extends(Type.Literal(10), Type.Boolean()) - Assert.IsEqual(R, TypeExtendsResult.False) + const R = ExtendsCheck(Type.Literal(10), Type.Boolean()) + Assert.IsEqual(R, ExtendsResult.False) }) it('Should extend Number (Number)', () => { type T = 10 extends number ? 1 : 2 - const R = TypeExtends.Extends(Type.Literal(10), Type.Number()) - Assert.IsEqual(R, TypeExtendsResult.True) + const R = ExtendsCheck(Type.Literal(10), Type.Number()) + Assert.IsEqual(R, ExtendsResult.True) }) it('Should extend Integer (Number)', () => { type T = 10 extends number ? 1 : 2 - const R = TypeExtends.Extends(Type.Literal(10), Type.Integer()) - Assert.IsEqual(R, TypeExtendsResult.True) + const R = ExtendsCheck(Type.Literal(10), Type.Integer()) + Assert.IsEqual(R, ExtendsResult.True) }) it('Should extend Array (Number)', () => { type T = 10 extends Array ? 1 : 2 - const R = TypeExtends.Extends(Type.Literal(10), Type.Array(Type.Any())) - Assert.IsEqual(R, TypeExtendsResult.False) + const R = ExtendsCheck(Type.Literal(10), Type.Array(Type.Any())) + Assert.IsEqual(R, ExtendsResult.False) }) it('Should extend Tuple (Number)', () => { type T = 10 extends [number, number] ? 1 : 2 - const R = TypeExtends.Extends(Type.Literal(10), Type.Tuple([Type.Number(), Type.Number()])) - Assert.IsEqual(R, TypeExtendsResult.False) + const R = ExtendsCheck(Type.Literal(10), Type.Tuple([Type.Number(), Type.Number()])) + Assert.IsEqual(R, ExtendsResult.False) }) it('Should extend Object 1 (Number)', () => { type T = 10 extends {} ? 1 : 2 - const R = TypeExtends.Extends(Type.Literal(10), Type.Object({}, { additionalProperties: false })) - Assert.IsEqual(R, TypeExtendsResult.True) + const R = ExtendsCheck(Type.Literal(10), Type.Object({}, { additionalProperties: false })) + Assert.IsEqual(R, ExtendsResult.True) }) it('Should extend Object 2 (Number)', () => { type T = 10 extends { a: 10 } ? 1 : 2 - const R = TypeExtends.Extends(Type.Literal(10), Type.Object({ a: Type.Literal(10) }, { additionalProperties: true })) - Assert.IsEqual(R, TypeExtendsResult.False) + const R = ExtendsCheck(Type.Literal(10), Type.Object({ a: Type.Literal(10) }, { additionalProperties: true })) + Assert.IsEqual(R, ExtendsResult.False) }) it('Should extend Union 1 (Number)', () => { type T = 10 extends number | string ? 1 : 2 - const R = TypeExtends.Extends(Type.Literal(10), Type.Union([Type.Number(), Type.String()])) - Assert.IsEqual(R, TypeExtendsResult.True) + const R = ExtendsCheck(Type.Literal(10), Type.Union([Type.Number(), Type.String()])) + Assert.IsEqual(R, ExtendsResult.True) }) it('Should extend Union 2 (Number)', () => { type T = 10 extends any | number ? 1 : 2 - const R = TypeExtends.Extends(Type.Literal(10), Type.Union([Type.Any(), Type.Number()])) - Assert.IsEqual(R, TypeExtendsResult.True) + const R = ExtendsCheck(Type.Literal(10), Type.Union([Type.Any(), Type.Number()])) + Assert.IsEqual(R, ExtendsResult.True) }) it('Should extend Union 3 (Number)', () => { type T = 10 extends boolean | number ? 1 : 2 - const R = TypeExtends.Extends(Type.Literal(10), Type.Union([Type.Boolean(), Type.Number()])) - Assert.IsEqual(R, TypeExtendsResult.True) + const R = ExtendsCheck(Type.Literal(10), Type.Union([Type.Boolean(), Type.Number()])) + Assert.IsEqual(R, ExtendsResult.True) }) it('Should extend Null (Number)', () => { type T = 10 extends null ? 1 : 2 - const R = TypeExtends.Extends(Type.Literal(10), Type.Null()) - Assert.IsEqual(R, TypeExtendsResult.False) + const R = ExtendsCheck(Type.Literal(10), Type.Null()) + Assert.IsEqual(R, ExtendsResult.False) }) it('Should extend Undefined (Number)', () => { type T = 10 extends undefined ? 1 : 2 - const R = TypeExtends.Extends(Type.Literal(10), Type.Undefined()) - Assert.IsEqual(R, TypeExtendsResult.False) + const R = ExtendsCheck(Type.Literal(10), Type.Undefined()) + Assert.IsEqual(R, ExtendsResult.False) }) // ------------------------------------------------------------------- // Boolean Literal // ------------------------------------------------------------------- it('Should extend Any (Boolean)', () => { type T = true extends any ? 1 : 2 - const R = TypeExtends.Extends(Type.Literal(true), Type.Any()) - Assert.IsEqual(R, TypeExtendsResult.True) + const R = ExtendsCheck(Type.Literal(true), Type.Any()) + Assert.IsEqual(R, ExtendsResult.True) }) it('Should extend Unknown (Boolean)', () => { type T = true extends unknown ? 1 : 2 - const R = TypeExtends.Extends(Type.Literal(true), Type.Unknown()) - Assert.IsEqual(R, TypeExtendsResult.True) + const R = ExtendsCheck(Type.Literal(true), Type.Unknown()) + Assert.IsEqual(R, ExtendsResult.True) }) it('Should extend String (Boolean)', () => { type T = true extends string ? 1 : 2 - const R = TypeExtends.Extends(Type.Literal(true), Type.String()) - Assert.IsEqual(R, TypeExtendsResult.False) + const R = ExtendsCheck(Type.Literal(true), Type.String()) + Assert.IsEqual(R, ExtendsResult.False) }) it('Should extend Boolean (Boolean)', () => { type T = true extends boolean ? 1 : 2 - const R = TypeExtends.Extends(Type.Literal(true), Type.Boolean()) - Assert.IsEqual(R, TypeExtendsResult.True) + const R = ExtendsCheck(Type.Literal(true), Type.Boolean()) + Assert.IsEqual(R, ExtendsResult.True) }) it('Should extend Number (Boolean)', () => { type T = true extends number ? 1 : 2 - const R = TypeExtends.Extends(Type.Literal(true), Type.Number()) - Assert.IsEqual(R, TypeExtendsResult.False) + const R = ExtendsCheck(Type.Literal(true), Type.Number()) + Assert.IsEqual(R, ExtendsResult.False) }) it('Should extend Integer (Boolean)', () => { type T = true extends number ? 1 : 2 - const R = TypeExtends.Extends(Type.Literal(true), Type.Integer()) - Assert.IsEqual(R, TypeExtendsResult.False) + const R = ExtendsCheck(Type.Literal(true), Type.Integer()) + Assert.IsEqual(R, ExtendsResult.False) }) it('Should extend Array (Boolean)', () => { type T = true extends Array ? 1 : 2 - const R = TypeExtends.Extends(Type.Literal(true), Type.Array(Type.Any())) - Assert.IsEqual(R, TypeExtendsResult.False) + const R = ExtendsCheck(Type.Literal(true), Type.Array(Type.Any())) + Assert.IsEqual(R, ExtendsResult.False) }) it('Should extend Tuple (Boolean)', () => { type T = true extends [number, number] ? 1 : 2 - const R = TypeExtends.Extends(Type.Literal(true), Type.Tuple([Type.Number(), Type.Number()])) - Assert.IsEqual(R, TypeExtendsResult.False) + const R = ExtendsCheck(Type.Literal(true), Type.Tuple([Type.Number(), Type.Number()])) + Assert.IsEqual(R, ExtendsResult.False) }) it('Should extend Record 1', () => { type T = 'hello' extends Record ? 1 : 2 - const R = TypeExtends.Extends(Type.Literal('hello'), Type.Record(Type.Number(), Type.Any())) - Assert.IsEqual(R, TypeExtendsResult.True) + const R = ExtendsCheck(Type.Literal('hello'), Type.Record(Type.Number(), Type.Any())) + Assert.IsEqual(R, ExtendsResult.True) }) it('Should extend Record 2', () => { type T = 10 extends Record ? 1 : 2 - const R = TypeExtends.Extends(Type.Literal(10), Type.Record(Type.Number(), Type.Any())) - Assert.IsEqual(R, TypeExtendsResult.False) + const R = ExtendsCheck(Type.Literal(10), Type.Record(Type.Number(), Type.Any())) + Assert.IsEqual(R, ExtendsResult.False) }) it('Should extend Record 3', () => { type T = true extends Record ? 1 : 2 - const R = TypeExtends.Extends(Type.Literal(true), Type.Record(Type.Number(), Type.Any())) - Assert.IsEqual(R, TypeExtendsResult.False) + const R = ExtendsCheck(Type.Literal(true), Type.Record(Type.Number(), Type.Any())) + Assert.IsEqual(R, ExtendsResult.False) }) it('Should extend Object 1 (Boolean)', () => { type T = true extends {} ? 1 : 2 - const R = TypeExtends.Extends(Type.Literal(true), Type.Object({}, { additionalProperties: false })) - Assert.IsEqual(R, TypeExtendsResult.True) + const R = ExtendsCheck(Type.Literal(true), Type.Object({}, { additionalProperties: false })) + Assert.IsEqual(R, ExtendsResult.True) }) it('Should extend Object 2 (Boolean)', () => { type T = true extends { a: 10 } ? 1 : 2 - const R = TypeExtends.Extends(Type.Literal(true), Type.Object({ a: Type.Literal(10) }, { additionalProperties: true })) - Assert.IsEqual(R, TypeExtendsResult.False) + const R = ExtendsCheck(Type.Literal(true), Type.Object({ a: Type.Literal(10) }, { additionalProperties: true })) + Assert.IsEqual(R, ExtendsResult.False) }) it('Should extend Union 1 (Boolean)', () => { type T = true extends number | string ? 1 : 2 - const R = TypeExtends.Extends(Type.Literal(true), Type.Union([Type.Number(), Type.String()])) - Assert.IsEqual(R, TypeExtendsResult.False) + const R = ExtendsCheck(Type.Literal(true), Type.Union([Type.Number(), Type.String()])) + Assert.IsEqual(R, ExtendsResult.False) }) it('Should extend Union 2 (Boolean)', () => { type T = true extends any | number ? 1 : 2 - const R = TypeExtends.Extends(Type.Literal(true), Type.Union([Type.Any(), Type.Number()])) - Assert.IsEqual(R, TypeExtendsResult.True) + const R = ExtendsCheck(Type.Literal(true), Type.Union([Type.Any(), Type.Number()])) + Assert.IsEqual(R, ExtendsResult.True) }) it('Should extend Union 3 (Boolean)', () => { type T = true extends boolean | number ? 1 : 2 - const R = TypeExtends.Extends(Type.Literal(true), Type.Union([Type.Boolean(), Type.Number()])) - Assert.IsEqual(R, TypeExtendsResult.True) + const R = ExtendsCheck(Type.Literal(true), Type.Union([Type.Boolean(), Type.Number()])) + Assert.IsEqual(R, ExtendsResult.True) }) it('Should extend Null (Boolean)', () => { type T = true extends null ? 1 : 2 - const R = TypeExtends.Extends(Type.Literal(true), Type.Null()) - Assert.IsEqual(R, TypeExtendsResult.False) + const R = ExtendsCheck(Type.Literal(true), Type.Null()) + Assert.IsEqual(R, ExtendsResult.False) }) it('Should extend Undefined (Boolean)', () => { type T = true extends undefined ? 1 : 2 - const R = TypeExtends.Extends(Type.Literal(true), Type.Undefined()) - Assert.IsEqual(R, TypeExtendsResult.False) + const R = ExtendsCheck(Type.Literal(true), Type.Undefined()) + Assert.IsEqual(R, ExtendsResult.False) }) it('Should extend Void', () => { type T = true extends void ? 1 : 2 - const R = TypeExtends.Extends(Type.Literal(true), Type.Void()) - Assert.IsEqual(R, TypeExtendsResult.False) + const R = ExtendsCheck(Type.Literal(true), Type.Void()) + Assert.IsEqual(R, ExtendsResult.False) }) it('Should extend Date', () => { type T = true extends Date ? 1 : 2 - const R = TypeExtends.Extends(Type.Literal(true), Type.Date()) - Assert.IsEqual(R, TypeExtendsResult.False) + const R = ExtendsCheck(Type.Literal(true), Type.Date()) + Assert.IsEqual(R, ExtendsResult.False) }) }) diff --git a/test/runtime/type/extends/not.ts b/test/runtime/type/extends/not.ts index 53f8d1e40..ad33cf8c7 100644 --- a/test/runtime/type/extends/not.ts +++ b/test/runtime/type/extends/not.ts @@ -1,4 +1,4 @@ -import { TypeExtends, TypeExtendsResult } from '@sinclair/typebox' +import { ExtendsCheck, ExtendsResult } from '@sinclair/typebox/type' import { Type } from '@sinclair/typebox' import { Assert } from '../../assert/index' @@ -18,8 +18,8 @@ describe('type/extends/Not', () => { it('Should extend with unknown assignability check', () => { const A = Type.Number() const B = Type.Not(Type.Number()) - const R = TypeExtends.Extends(A, B) - Assert.IsEqual(R, TypeExtendsResult.True) // we would expect false + const R = ExtendsCheck(A, B) + Assert.IsEqual(R, ExtendsResult.True) // we would expect false }) // --------------------------------------------------------------------------- // Nested @@ -31,17 +31,17 @@ describe('type/extends/Not', () => { const T4 = Type.Not(T3) const T5 = Type.Not(T4) - const R1 = TypeExtends.Extends(T1, Type.String()) - const R2 = TypeExtends.Extends(T2, Type.String()) - const R3 = TypeExtends.Extends(T3, Type.String()) - const R4 = TypeExtends.Extends(T4, Type.String()) - const R5 = TypeExtends.Extends(T5, Type.String()) + const R1 = ExtendsCheck(T1, Type.String()) + const R2 = ExtendsCheck(T2, Type.String()) + const R3 = ExtendsCheck(T3, Type.String()) + const R4 = ExtendsCheck(T4, Type.String()) + const R5 = ExtendsCheck(T5, Type.String()) - Assert.IsEqual(R1, TypeExtendsResult.True) - Assert.IsEqual(R2, TypeExtendsResult.False) - Assert.IsEqual(R3, TypeExtendsResult.True) - Assert.IsEqual(R4, TypeExtendsResult.False) - Assert.IsEqual(R5, TypeExtendsResult.True) + Assert.IsEqual(R1, ExtendsResult.True) + Assert.IsEqual(R2, ExtendsResult.False) + Assert.IsEqual(R3, ExtendsResult.True) + Assert.IsEqual(R4, ExtendsResult.False) + Assert.IsEqual(R5, ExtendsResult.True) }) // --------------------------------------------------------------------------- @@ -49,97 +49,97 @@ describe('type/extends/Not', () => { // --------------------------------------------------------------------------- it('Should extend Any', () => { type T = unknown extends any ? 1 : 2 - const R = TypeExtends.Extends(Type.Not(Type.Number()), Type.Any()) - Assert.IsEqual(R, TypeExtendsResult.True) + const R = ExtendsCheck(Type.Not(Type.Number()), Type.Any()) + Assert.IsEqual(R, ExtendsResult.True) }) it('Should extend Unknown', () => { type T = unknown extends unknown ? 1 : 2 - const R = TypeExtends.Extends(Type.Not(Type.Number()), Type.Unknown()) - Assert.IsEqual(R, TypeExtendsResult.True) + const R = ExtendsCheck(Type.Not(Type.Number()), Type.Unknown()) + Assert.IsEqual(R, ExtendsResult.True) }) it('Should extend String', () => { type T = unknown extends string ? 1 : 2 - const R = TypeExtends.Extends(Type.Not(Type.Number()), Type.String()) - Assert.IsEqual(R, TypeExtendsResult.False) + const R = ExtendsCheck(Type.Not(Type.Number()), Type.String()) + Assert.IsEqual(R, ExtendsResult.False) }) it('Should extend Boolean', () => { type T = unknown extends boolean ? 1 : 2 - const R = TypeExtends.Extends(Type.Not(Type.Number()), Type.Boolean()) - Assert.IsEqual(R, TypeExtendsResult.False) + const R = ExtendsCheck(Type.Not(Type.Number()), Type.Boolean()) + Assert.IsEqual(R, ExtendsResult.False) }) it('Should extend Number', () => { type T = unknown extends number ? 1 : 2 - const R = TypeExtends.Extends(Type.Not(Type.Number()), Type.Number()) - Assert.IsEqual(R, TypeExtendsResult.False) + const R = ExtendsCheck(Type.Not(Type.Number()), Type.Number()) + Assert.IsEqual(R, ExtendsResult.False) }) it('Should extend Integer', () => { type T = unknown extends number ? 1 : 2 - const R = TypeExtends.Extends(Type.Not(Type.Number()), Type.Integer()) - Assert.IsEqual(R, TypeExtendsResult.False) + const R = ExtendsCheck(Type.Not(Type.Number()), Type.Integer()) + Assert.IsEqual(R, ExtendsResult.False) }) it('Should extend Array 1', () => { type T = unknown extends Array ? 1 : 2 - const R = TypeExtends.Extends(Type.Not(Type.Number()), Type.Array(Type.Any())) - Assert.IsEqual(R, TypeExtendsResult.False) + const R = ExtendsCheck(Type.Not(Type.Number()), Type.Array(Type.Any())) + Assert.IsEqual(R, ExtendsResult.False) }) it('Should extend Array 2', () => { type T = unknown extends Array ? 1 : 2 - const R = TypeExtends.Extends(Type.Not(Type.Number()), Type.Array(Type.String())) - Assert.IsEqual(R, TypeExtendsResult.False) + const R = ExtendsCheck(Type.Not(Type.Number()), Type.Array(Type.String())) + Assert.IsEqual(R, ExtendsResult.False) }) it('Should extend Tuple', () => { type T = unknown extends [number, number] ? 1 : 2 - const R = TypeExtends.Extends(Type.Not(Type.Number()), Type.Tuple([Type.Number(), Type.Number()])) - Assert.IsEqual(R, TypeExtendsResult.False) + const R = ExtendsCheck(Type.Not(Type.Number()), Type.Tuple([Type.Number(), Type.Number()])) + Assert.IsEqual(R, ExtendsResult.False) }) it('Should extend Object 1', () => { type T = unknown extends {} ? 1 : 2 - const R = TypeExtends.Extends(Type.Not(Type.Number()), Type.Object({})) - Assert.IsEqual(R, TypeExtendsResult.False) + const R = ExtendsCheck(Type.Not(Type.Number()), Type.Object({})) + Assert.IsEqual(R, ExtendsResult.False) }) it('Should extend Object 2', () => { type T = unknown extends { a: number } ? 1 : 2 - const R = TypeExtends.Extends(Type.Not(Type.Number()), Type.Object({ a: Type.Number() })) - Assert.IsEqual(R, TypeExtendsResult.False) + const R = ExtendsCheck(Type.Not(Type.Number()), Type.Object({ a: Type.Number() })) + Assert.IsEqual(R, ExtendsResult.False) }) it('Should extend Union 1', () => { type T = unknown extends number | string ? 1 : 2 - const R = TypeExtends.Extends(Type.Not(Type.Number()), Type.Union([Type.Number(), Type.String()])) - Assert.IsEqual(R, TypeExtendsResult.False) + const R = ExtendsCheck(Type.Not(Type.Number()), Type.Union([Type.Number(), Type.String()])) + Assert.IsEqual(R, ExtendsResult.False) }) it('Should extend Union 2', () => { type T = unknown extends any | number ? 1 : 2 // 1 - const R = TypeExtends.Extends(Type.Not(Type.Number()), Type.Union([Type.Any(), Type.String()])) - Assert.IsEqual(R, TypeExtendsResult.True) + const R = ExtendsCheck(Type.Not(Type.Number()), Type.Union([Type.Any(), Type.String()])) + Assert.IsEqual(R, ExtendsResult.True) }) it('Should extend Union 3', () => { type T = unknown extends unknown | number ? 1 : 2 // 1 - const R = TypeExtends.Extends(Type.Not(Type.Number()), Type.Union([Type.Unknown(), Type.String()])) - Assert.IsEqual(R, TypeExtendsResult.True) + const R = ExtendsCheck(Type.Not(Type.Number()), Type.Union([Type.Unknown(), Type.String()])) + Assert.IsEqual(R, ExtendsResult.True) }) it('Should extend Union 4', () => { type T = unknown extends unknown | any ? 1 : 2 // 1 - const R = TypeExtends.Extends(Type.Not(Type.Number()), Type.Union([Type.Unknown(), Type.String()])) - Assert.IsEqual(R, TypeExtendsResult.True) + const R = ExtendsCheck(Type.Not(Type.Number()), Type.Union([Type.Unknown(), Type.String()])) + Assert.IsEqual(R, ExtendsResult.True) }) it('Should extend Null', () => { type T = unknown extends null ? 1 : 2 - const R = TypeExtends.Extends(Type.Not(Type.Number()), Type.Null()) - Assert.IsEqual(R, TypeExtendsResult.False) + const R = ExtendsCheck(Type.Not(Type.Number()), Type.Null()) + Assert.IsEqual(R, ExtendsResult.False) }) it('Should extend Undefined', () => { type T = unknown extends undefined ? 1 : 2 - const R = TypeExtends.Extends(Type.Not(Type.Number()), Type.Undefined()) - Assert.IsEqual(R, TypeExtendsResult.False) + const R = ExtendsCheck(Type.Not(Type.Number()), Type.Undefined()) + Assert.IsEqual(R, ExtendsResult.False) }) it('Should extend Void', () => { type T = unknown extends void ? 1 : 2 - const R = TypeExtends.Extends(Type.Not(Type.Number()), Type.Void()) - Assert.IsEqual(R, TypeExtendsResult.False) + const R = ExtendsCheck(Type.Not(Type.Number()), Type.Void()) + Assert.IsEqual(R, ExtendsResult.False) }) it('Should extend Date', () => { type T = unknown extends Date ? 1 : 2 - const R = TypeExtends.Extends(Type.Not(Type.Number()), Type.Date()) - Assert.IsEqual(R, TypeExtendsResult.False) + const R = ExtendsCheck(Type.Not(Type.Number()), Type.Date()) + Assert.IsEqual(R, ExtendsResult.False) }) }) diff --git a/test/runtime/type/extends/null.ts b/test/runtime/type/extends/null.ts index 702e16271..7178d9721 100644 --- a/test/runtime/type/extends/null.ts +++ b/test/runtime/type/extends/null.ts @@ -1,101 +1,101 @@ -import { TypeExtends, TypeExtendsResult } from '@sinclair/typebox' +import { ExtendsCheck, ExtendsResult } from '@sinclair/typebox/type' import { Type } from '@sinclair/typebox' import { Assert } from '../../assert/index' describe('type/extends/Null', () => { it('Should extend Any', () => { type T = null extends any ? 1 : 2 - const R = TypeExtends.Extends(Type.Null(), Type.Any()) - Assert.IsEqual(R, TypeExtendsResult.True) + const R = ExtendsCheck(Type.Null(), Type.Any()) + Assert.IsEqual(R, ExtendsResult.True) }) it('Should extend Unknown', () => { type T = null extends unknown ? 1 : 2 - const R = TypeExtends.Extends(Type.Null(), Type.Unknown()) - Assert.IsEqual(R, TypeExtendsResult.True) + const R = ExtendsCheck(Type.Null(), Type.Unknown()) + Assert.IsEqual(R, ExtendsResult.True) }) it('Should extend String', () => { type T = null extends string ? 1 : 2 - const R = TypeExtends.Extends(Type.Null(), Type.String()) - Assert.IsEqual(R, TypeExtendsResult.False) + const R = ExtendsCheck(Type.Null(), Type.String()) + Assert.IsEqual(R, ExtendsResult.False) }) it('Should extend Boolean', () => { type T = null extends boolean ? 1 : 2 - const R = TypeExtends.Extends(Type.Null(), Type.Boolean()) - Assert.IsEqual(R, TypeExtendsResult.False) + const R = ExtendsCheck(Type.Null(), Type.Boolean()) + Assert.IsEqual(R, ExtendsResult.False) }) it('Should extend Number', () => { type T = null extends number ? 1 : 2 - const R = TypeExtends.Extends(Type.Null(), Type.Number()) - Assert.IsEqual(R, TypeExtendsResult.False) + const R = ExtendsCheck(Type.Null(), Type.Number()) + Assert.IsEqual(R, ExtendsResult.False) }) it('Should extend Integer', () => { type T = null extends number ? 1 : 2 - const R = TypeExtends.Extends(Type.Null(), Type.Integer()) - Assert.IsEqual(R, TypeExtendsResult.False) + const R = ExtendsCheck(Type.Null(), Type.Integer()) + Assert.IsEqual(R, ExtendsResult.False) }) it('Should extend Array', () => { type T = null extends Array ? 1 : 2 - const R = TypeExtends.Extends(Type.Null(), Type.Array(Type.Any())) - Assert.IsEqual(R, TypeExtendsResult.False) + const R = ExtendsCheck(Type.Null(), Type.Array(Type.Any())) + Assert.IsEqual(R, ExtendsResult.False) }) it('Should extend Tuple', () => { type T = null extends [number, number] ? 1 : 2 - const R = TypeExtends.Extends(Type.Null(), Type.Tuple([Type.Number(), Type.Number()])) - Assert.IsEqual(R, TypeExtendsResult.False) + const R = ExtendsCheck(Type.Null(), Type.Tuple([Type.Number(), Type.Number()])) + Assert.IsEqual(R, ExtendsResult.False) }) it('Should extend Record', () => { type T = null extends Record ? 1 : 2 - const R = TypeExtends.Extends(Type.Null(), Type.Record(Type.Number(), Type.Any())) - Assert.IsEqual(R, TypeExtendsResult.False) + const R = ExtendsCheck(Type.Null(), Type.Record(Type.Number(), Type.Any())) + Assert.IsEqual(R, ExtendsResult.False) }) it('Should extend Object 1', () => { type T = null extends {} ? 1 : 2 - const R = TypeExtends.Extends(Type.Null(), Type.Object({}, { additionalProperties: false })) - Assert.IsEqual(R, TypeExtendsResult.False) + const R = ExtendsCheck(Type.Null(), Type.Object({}, { additionalProperties: false })) + Assert.IsEqual(R, ExtendsResult.False) }) it('Should extend Object 2', () => { type T = null extends { a: 10 } ? 1 : 2 - const R = TypeExtends.Extends(Type.Null(), Type.Object({ a: Type.Literal(10) }, { additionalProperties: true })) - Assert.IsEqual(R, TypeExtendsResult.False) + const R = ExtendsCheck(Type.Null(), Type.Object({ a: Type.Literal(10) }, { additionalProperties: true })) + Assert.IsEqual(R, ExtendsResult.False) }) it('Should extend Object 3', () => { type T = null extends object ? 1 : 2 - const R = TypeExtends.Extends(Type.Null(), Type.Object({})) - Assert.IsEqual(R, TypeExtendsResult.False) + const R = ExtendsCheck(Type.Null(), Type.Object({})) + Assert.IsEqual(R, ExtendsResult.False) }) it('Should extend Union 1', () => { type T = null extends number | string ? 1 : 2 - const R = TypeExtends.Extends(Type.Null(), Type.Union([Type.Number(), Type.String()])) - Assert.IsEqual(R, TypeExtendsResult.False) + const R = ExtendsCheck(Type.Null(), Type.Union([Type.Number(), Type.String()])) + Assert.IsEqual(R, ExtendsResult.False) }) it('Should extend Union 2', () => { type T = null extends any | number ? 1 : 2 - const R = TypeExtends.Extends(Type.Null(), Type.Union([Type.Any(), Type.Number()])) - Assert.IsEqual(R, TypeExtendsResult.True) + const R = ExtendsCheck(Type.Null(), Type.Union([Type.Any(), Type.Number()])) + Assert.IsEqual(R, ExtendsResult.True) }) it('Should extend Union 2', () => { type T = null extends boolean | number ? 1 : 2 - const R = TypeExtends.Extends(Type.Null(), Type.Union([Type.Boolean(), Type.Number()])) - Assert.IsEqual(R, TypeExtendsResult.False) + const R = ExtendsCheck(Type.Null(), Type.Union([Type.Boolean(), Type.Number()])) + Assert.IsEqual(R, ExtendsResult.False) }) it('Should extend Null', () => { type T = null extends null ? 1 : 2 - const R = TypeExtends.Extends(Type.Null(), Type.Null()) - Assert.IsEqual(R, TypeExtendsResult.True) + const R = ExtendsCheck(Type.Null(), Type.Null()) + Assert.IsEqual(R, ExtendsResult.True) }) it('Should extend Undefined', () => { type T = null extends undefined ? 1 : 2 - const R = TypeExtends.Extends(Type.Null(), Type.Undefined()) - Assert.IsEqual(R, TypeExtendsResult.False) + const R = ExtendsCheck(Type.Null(), Type.Undefined()) + Assert.IsEqual(R, ExtendsResult.False) }) it('Should extend Void', () => { type T = null extends void ? 1 : 2 - const R = TypeExtends.Extends(Type.Null(), Type.Void()) - Assert.IsEqual(R, TypeExtendsResult.False) + const R = ExtendsCheck(Type.Null(), Type.Void()) + Assert.IsEqual(R, ExtendsResult.False) }) it('Should extend Date', () => { type T = null extends Date ? 1 : 2 - const R = TypeExtends.Extends(Type.Null(), Type.Date()) - Assert.IsEqual(R, TypeExtendsResult.False) + const R = ExtendsCheck(Type.Null(), Type.Date()) + Assert.IsEqual(R, ExtendsResult.False) }) }) diff --git a/test/runtime/type/extends/number.ts b/test/runtime/type/extends/number.ts index aa647eca6..73c7fe835 100644 --- a/test/runtime/type/extends/number.ts +++ b/test/runtime/type/extends/number.ts @@ -1,96 +1,96 @@ -import { TypeExtends, TypeExtendsResult } from '@sinclair/typebox' +import { ExtendsCheck, ExtendsResult } from '@sinclair/typebox/type' import { Type } from '@sinclair/typebox' import { Assert } from '../../assert/index' describe('type/extends/Number', () => { it('Should extend Any', () => { type T = number extends any ? 1 : 2 - const R = TypeExtends.Extends(Type.Number(), Type.Any()) - Assert.IsEqual(R, TypeExtendsResult.True) + const R = ExtendsCheck(Type.Number(), Type.Any()) + Assert.IsEqual(R, ExtendsResult.True) }) it('Should extend Unknown', () => { type T = number extends unknown ? 1 : 2 - const R = TypeExtends.Extends(Type.Number(), Type.Unknown()) - Assert.IsEqual(R, TypeExtendsResult.True) + const R = ExtendsCheck(Type.Number(), Type.Unknown()) + Assert.IsEqual(R, ExtendsResult.True) }) it('Should extend String', () => { type T = number extends string ? 1 : 2 - const R = TypeExtends.Extends(Type.Number(), Type.String()) - Assert.IsEqual(R, TypeExtendsResult.False) + const R = ExtendsCheck(Type.Number(), Type.String()) + Assert.IsEqual(R, ExtendsResult.False) }) it('Should extend Boolean', () => { type T = number extends boolean ? 1 : 2 - const R = TypeExtends.Extends(Type.Number(), Type.Boolean()) - Assert.IsEqual(R, TypeExtendsResult.False) + const R = ExtendsCheck(Type.Number(), Type.Boolean()) + Assert.IsEqual(R, ExtendsResult.False) }) it('Should extend Number', () => { type T = number extends number ? 1 : 2 - const R = TypeExtends.Extends(Type.Number(), Type.Number()) - Assert.IsEqual(R, TypeExtendsResult.True) + const R = ExtendsCheck(Type.Number(), Type.Number()) + Assert.IsEqual(R, ExtendsResult.True) }) it('Should extend Integer', () => { type T = number extends number ? 1 : 2 - const R = TypeExtends.Extends(Type.Number(), Type.Integer()) - Assert.IsEqual(R, TypeExtendsResult.True) + const R = ExtendsCheck(Type.Number(), Type.Integer()) + Assert.IsEqual(R, ExtendsResult.True) }) it('Should extend Array', () => { type T = number extends Array ? 1 : 2 - const R = TypeExtends.Extends(Type.Number(), Type.Array(Type.Any())) - Assert.IsEqual(R, TypeExtendsResult.False) + const R = ExtendsCheck(Type.Number(), Type.Array(Type.Any())) + Assert.IsEqual(R, ExtendsResult.False) }) it('Should extend Tuple', () => { type T = number extends [number, number] ? 1 : 2 - const R = TypeExtends.Extends(Type.Number(), Type.Tuple([Type.Number(), Type.Number()])) - Assert.IsEqual(R, TypeExtendsResult.False) + const R = ExtendsCheck(Type.Number(), Type.Tuple([Type.Number(), Type.Number()])) + Assert.IsEqual(R, ExtendsResult.False) }) it('Should extend Record', () => { type T = number extends Record ? 1 : 2 - const R = TypeExtends.Extends(Type.Number(), Type.Record(Type.Number(), Type.Any())) - Assert.IsEqual(R, TypeExtendsResult.False) + const R = ExtendsCheck(Type.Number(), Type.Record(Type.Number(), Type.Any())) + Assert.IsEqual(R, ExtendsResult.False) }) it('Should extend Object 1', () => { type T = number extends {} ? 1 : 2 - const R = TypeExtends.Extends(Type.Number(), Type.Object({}, { additionalProperties: false })) - Assert.IsEqual(R, TypeExtendsResult.True) + const R = ExtendsCheck(Type.Number(), Type.Object({}, { additionalProperties: false })) + Assert.IsEqual(R, ExtendsResult.True) }) it('Should extend Object 2', () => { type T = number extends { a: 10 } ? 1 : 2 - const R = TypeExtends.Extends(Type.Number(), Type.Object({ a: Type.Literal(10) }, { additionalProperties: true })) - Assert.IsEqual(R, TypeExtendsResult.False) + const R = ExtendsCheck(Type.Number(), Type.Object({ a: Type.Literal(10) }, { additionalProperties: true })) + Assert.IsEqual(R, ExtendsResult.False) }) it('Should extend Union 1', () => { type T = number extends number | string ? 1 : 2 - const R = TypeExtends.Extends(Type.Number(), Type.Union([Type.Number(), Type.String()])) - Assert.IsEqual(R, TypeExtendsResult.True) + const R = ExtendsCheck(Type.Number(), Type.Union([Type.Number(), Type.String()])) + Assert.IsEqual(R, ExtendsResult.True) }) it('Should extend Union 2', () => { type T = number extends any | number ? 1 : 2 - const R = TypeExtends.Extends(Type.Number(), Type.Union([Type.Any(), Type.Number()])) - Assert.IsEqual(R, TypeExtendsResult.True) + const R = ExtendsCheck(Type.Number(), Type.Union([Type.Any(), Type.Number()])) + Assert.IsEqual(R, ExtendsResult.True) }) it('Should extend Union 2', () => { type T = number extends boolean | number ? 1 : 2 - const R = TypeExtends.Extends(Type.Number(), Type.Union([Type.Boolean(), Type.Number()])) - Assert.IsEqual(R, TypeExtendsResult.True) + const R = ExtendsCheck(Type.Number(), Type.Union([Type.Boolean(), Type.Number()])) + Assert.IsEqual(R, ExtendsResult.True) }) it('Should extend Null', () => { type T = number extends null ? 1 : 2 - const R = TypeExtends.Extends(Type.Number(), Type.Null()) - Assert.IsEqual(R, TypeExtendsResult.False) + const R = ExtendsCheck(Type.Number(), Type.Null()) + Assert.IsEqual(R, ExtendsResult.False) }) it('Should extend Undefined', () => { type T = number extends undefined ? 1 : 2 - const R = TypeExtends.Extends(Type.Number(), Type.Undefined()) - Assert.IsEqual(R, TypeExtendsResult.False) + const R = ExtendsCheck(Type.Number(), Type.Undefined()) + Assert.IsEqual(R, ExtendsResult.False) }) it('Should extend Void', () => { type T = number extends void ? 1 : 2 - const R = TypeExtends.Extends(Type.Number(), Type.Void()) - Assert.IsEqual(R, TypeExtendsResult.False) + const R = ExtendsCheck(Type.Number(), Type.Void()) + Assert.IsEqual(R, ExtendsResult.False) }) it('Should extend Date', () => { type T = number extends Date ? 1 : 2 - const R = TypeExtends.Extends(Type.Number(), Type.Date()) - Assert.IsEqual(R, TypeExtendsResult.False) + const R = ExtendsCheck(Type.Number(), Type.Date()) + Assert.IsEqual(R, ExtendsResult.False) }) }) diff --git a/test/runtime/type/extends/object.ts b/test/runtime/type/extends/object.ts index 8bc3a6e63..88ad26871 100644 --- a/test/runtime/type/extends/object.ts +++ b/test/runtime/type/extends/object.ts @@ -1,4 +1,4 @@ -import { TypeExtends, TypeExtendsResult } from '@sinclair/typebox' +import { ExtendsCheck, ExtendsResult } from '@sinclair/typebox/type' import { Type } from '@sinclair/typebox' import { Assert } from '../../assert/index' @@ -10,43 +10,43 @@ describe('type/extends/Object', () => { type T = { x: number; y: number } extends { x: number } ? 1 : 2 const A = Type.Object({ x: Type.Number(), y: Type.Number() }) const B = Type.Object({ x: Type.Number() }) - const R = TypeExtends.Extends(A, B) - Assert.IsEqual(R, TypeExtendsResult.True) + const R = ExtendsCheck(A, B) + Assert.IsEqual(R, ExtendsResult.True) }) it('Should extend Object 2', () => { type T = { x: number } extends { x: number; y: number } ? 1 : 2 const A = Type.Object({ x: Type.Number() }) const B = Type.Object({ x: Type.Number(), y: Type.Number() }) - const R = TypeExtends.Extends(A, B) - Assert.IsEqual(R, TypeExtendsResult.False) + const R = ExtendsCheck(A, B) + Assert.IsEqual(R, ExtendsResult.False) }) it('Should extend Object 3', () => { type T = { x: number; y: string } extends { x: number } ? 1 : 2 const A = Type.Object({ x: Type.Number(), y: Type.String() }) const B = Type.Object({ x: Type.Number() }) - const R = TypeExtends.Extends(A, B) - Assert.IsEqual(R, TypeExtendsResult.True) + const R = ExtendsCheck(A, B) + Assert.IsEqual(R, ExtendsResult.True) }) it('Should extend Object 4', () => { type T = { x: number } extends { x: number; y: string } ? 1 : 2 const A = Type.Object({ x: Type.Number() }) const B = Type.Object({ x: Type.Number(), y: Type.String() }) - const R = TypeExtends.Extends(A, B) - Assert.IsEqual(R, TypeExtendsResult.False) + const R = ExtendsCheck(A, B) + Assert.IsEqual(R, ExtendsResult.False) }) it('Should extend Object 5', () => { type T = { x: number | string } extends { x: number } ? 1 : 2 const A = Type.Object({ x: Type.Union([Type.Number(), Type.String()]) }) const B = Type.Object({ x: Type.Number() }) - const R = TypeExtends.Extends(A, B) - Assert.IsEqual(R, TypeExtendsResult.False) + const R = ExtendsCheck(A, B) + Assert.IsEqual(R, ExtendsResult.False) }) it('Should extend Object 6', () => { type T = { x: number } extends { x: number | string } ? 1 : 2 const A = Type.Object({ x: Type.Number() }) const B = Type.Object({ x: Type.Union([Type.Number(), Type.String()]) }) - const R = TypeExtends.Extends(A, B) - Assert.IsEqual(R, TypeExtendsResult.True) + const R = ExtendsCheck(A, B) + Assert.IsEqual(R, ExtendsResult.True) }) // ---------------------------------------------------------- // Record @@ -55,124 +55,124 @@ describe('type/extends/Object', () => { type T = { a: number; b: number } extends Record ? 1 : 2 const A = Type.Object({ a: Type.Number(), b: Type.Number() }) const B = Type.Record(Type.String(), Type.Number()) - const R = TypeExtends.Extends(A, B) - Assert.IsEqual(R, TypeExtendsResult.True) + const R = ExtendsCheck(A, B) + Assert.IsEqual(R, ExtendsResult.True) }) it('Should extend Record 3', () => { type T = { a: number; b: number } extends Record ? 1 : 2 const A = Type.Object({ a: Type.Number(), b: Type.Number() }) const B = Type.Record(Type.Number(), Type.Number()) - const R = TypeExtends.Extends(A, B) - Assert.IsEqual(R, TypeExtendsResult.True) + const R = ExtendsCheck(A, B) + Assert.IsEqual(R, ExtendsResult.True) }) it('Should extend Record 4', () => { type T = { a: number; b: number } extends Record<'a' | 'b', number> ? 1 : 2 const A = Type.Object({ a: Type.Number(), b: Type.Number() }) const B = Type.Record(Type.Union([Type.Literal('a'), Type.Literal('b')]), Type.Number()) - const R = TypeExtends.Extends(A, B) - Assert.IsEqual(R, TypeExtendsResult.True) + const R = ExtendsCheck(A, B) + Assert.IsEqual(R, ExtendsResult.True) }) it('Should extend Record 5', () => { type T = { a: number; b: number } extends Record<'a' | 'b', number> ? 1 : 2 const A = Type.Object({ a: Type.Number(), b: Type.Number() }) const B = Type.Record(Type.String(), Type.Number()) - const R = TypeExtends.Extends(A, B) - Assert.IsEqual(R, TypeExtendsResult.True) + const R = ExtendsCheck(A, B) + Assert.IsEqual(R, ExtendsResult.True) }) it('Should extend Record 6', () => { type T = { a: number; b: number } extends Record<'a' | 'b', number> ? 1 : 2 const A = Type.Object({ a: Type.Number(), b: Type.Number() }) const B = Type.Record(Type.Number(), Type.Number()) - const R = TypeExtends.Extends(A, B) - Assert.IsEqual(R, TypeExtendsResult.True) + const R = ExtendsCheck(A, B) + Assert.IsEqual(R, ExtendsResult.True) }) // ---------------------------------------------------------- // Standard // ---------------------------------------------------------- it('Should extend Any', () => { type T = { a: number } extends any ? 1 : 2 - const R = TypeExtends.Extends(Type.Object({ a: Type.Number() }), Type.Any()) - Assert.IsEqual(R, TypeExtendsResult.True) + const R = ExtendsCheck(Type.Object({ a: Type.Number() }), Type.Any()) + Assert.IsEqual(R, ExtendsResult.True) }) it('Should extend String', () => { type T = { a: number } extends string ? 1 : 2 - const R = TypeExtends.Extends(Type.Object({ a: Type.Number() }), Type.String()) - Assert.IsEqual(R, TypeExtendsResult.False) + const R = ExtendsCheck(Type.Object({ a: Type.Number() }), Type.String()) + Assert.IsEqual(R, ExtendsResult.False) }) it('Should extend Boolean', () => { type T = { a: number } extends boolean ? 1 : 2 - const R = TypeExtends.Extends(Type.Object({ a: Type.Number() }), Type.Boolean()) - Assert.IsEqual(R, TypeExtendsResult.False) + const R = ExtendsCheck(Type.Object({ a: Type.Number() }), Type.Boolean()) + Assert.IsEqual(R, ExtendsResult.False) }) it('Should extend Number', () => { type T = { a: number } extends number ? 1 : 2 - const R = TypeExtends.Extends(Type.Object({ a: Type.Number() }), Type.Number()) - Assert.IsEqual(R, TypeExtendsResult.False) + const R = ExtendsCheck(Type.Object({ a: Type.Number() }), Type.Number()) + Assert.IsEqual(R, ExtendsResult.False) }) it('Should extend Integer', () => { type T = { a: number } extends number ? 1 : 2 - const R = TypeExtends.Extends(Type.Object({ a: Type.Number() }), Type.Integer()) - Assert.IsEqual(R, TypeExtendsResult.False) + const R = ExtendsCheck(Type.Object({ a: Type.Number() }), Type.Integer()) + Assert.IsEqual(R, ExtendsResult.False) }) it('Should extend Array', () => { type T = { a: number } extends Array ? 1 : 2 - const R = TypeExtends.Extends(Type.Object({ a: Type.Number() }), Type.Array(Type.Any())) - Assert.IsEqual(R, TypeExtendsResult.False) + const R = ExtendsCheck(Type.Object({ a: Type.Number() }), Type.Array(Type.Any())) + Assert.IsEqual(R, ExtendsResult.False) }) it('Should extend Tuple', () => { type T = { a: number } extends [number, number] ? 1 : 2 - const R = TypeExtends.Extends(Type.Object({ a: Type.Number() }), Type.Tuple([Type.Number(), Type.Number()])) - Assert.IsEqual(R, TypeExtendsResult.False) + const R = ExtendsCheck(Type.Object({ a: Type.Number() }), Type.Tuple([Type.Number(), Type.Number()])) + Assert.IsEqual(R, ExtendsResult.False) }) it('Should extend Object 1', () => { type T = { a: number } extends {} ? 1 : 2 - const R = TypeExtends.Extends(Type.Object({ a: Type.Number() }), Type.Object({}, { additionalProperties: false })) - Assert.IsEqual(R, TypeExtendsResult.True) + const R = ExtendsCheck(Type.Object({ a: Type.Number() }), Type.Object({}, { additionalProperties: false })) + Assert.IsEqual(R, ExtendsResult.True) }) it('Should extend Object 2', () => { type T = { a: number } extends { a: 10 } ? 1 : 2 - const R = TypeExtends.Extends(Type.Object({ a: Type.Number() }), Type.Object({ a: Type.Literal(10) })) - Assert.IsEqual(R, TypeExtendsResult.False) + const R = ExtendsCheck(Type.Object({ a: Type.Number() }), Type.Object({ a: Type.Literal(10) })) + Assert.IsEqual(R, ExtendsResult.False) }) it('Should extend Object 3', () => { type T = { a: number } extends object ? 1 : 2 - const R = TypeExtends.Extends(Type.Object({ a: Type.Number() }), Type.Object({})) - Assert.IsEqual(R, TypeExtendsResult.True) + const R = ExtendsCheck(Type.Object({ a: Type.Number() }), Type.Object({})) + Assert.IsEqual(R, ExtendsResult.True) }) it('Should extend Union 1', () => { type T = { a: number } extends number | string ? 1 : 2 - const R = TypeExtends.Extends(Type.Object({ a: Type.Number() }), Type.Union([Type.Null(), Type.String()])) - Assert.IsEqual(R, TypeExtendsResult.False) + const R = ExtendsCheck(Type.Object({ a: Type.Number() }), Type.Union([Type.Null(), Type.String()])) + Assert.IsEqual(R, ExtendsResult.False) }) it('Should extend Union 2', () => { type T = { a: number } extends any | number ? 1 : 2 - const R = TypeExtends.Extends(Type.Object({ a: Type.Number() }), Type.Union([Type.Any(), Type.Number()])) - Assert.IsEqual(R, TypeExtendsResult.True) + const R = ExtendsCheck(Type.Object({ a: Type.Number() }), Type.Union([Type.Any(), Type.Number()])) + Assert.IsEqual(R, ExtendsResult.True) }) it('Should extend Union 2', () => { type T = { a: number } extends boolean | number ? 1 : 2 - const R = TypeExtends.Extends(Type.Object({ a: Type.Number() }), Type.Union([Type.Boolean(), Type.Number()])) - Assert.IsEqual(R, TypeExtendsResult.False) + const R = ExtendsCheck(Type.Object({ a: Type.Number() }), Type.Union([Type.Boolean(), Type.Number()])) + Assert.IsEqual(R, ExtendsResult.False) }) it('Should extend Null', () => { type T = { a: number } extends null ? 1 : 2 - const R = TypeExtends.Extends(Type.Object({ a: Type.Number() }), Type.Null()) - Assert.IsEqual(R, TypeExtendsResult.False) + const R = ExtendsCheck(Type.Object({ a: Type.Number() }), Type.Null()) + Assert.IsEqual(R, ExtendsResult.False) }) it('Should extend Undefined', () => { type T = { a: number } extends undefined ? 1 : 2 - const R = TypeExtends.Extends(Type.Object({ a: Type.Number() }), Type.Undefined()) - Assert.IsEqual(R, TypeExtendsResult.False) + const R = ExtendsCheck(Type.Object({ a: Type.Number() }), Type.Undefined()) + Assert.IsEqual(R, ExtendsResult.False) }) it('Should extend Void', () => { type T = { a: number } extends void ? 1 : 2 - const R = TypeExtends.Extends(Type.Object({ a: Type.Number() }), Type.Void()) - Assert.IsEqual(R, TypeExtendsResult.False) + const R = ExtendsCheck(Type.Object({ a: Type.Number() }), Type.Void()) + Assert.IsEqual(R, ExtendsResult.False) }) it('Should extend Date', () => { type T = { a: number } extends Date ? 1 : 2 - const R = TypeExtends.Extends(Type.Object({ a: Type.Number() }), Type.Date()) - Assert.IsEqual(R, TypeExtendsResult.False) + const R = ExtendsCheck(Type.Object({ a: Type.Number() }), Type.Date()) + Assert.IsEqual(R, ExtendsResult.False) }) // ---------------------------------------------------------------- // Optional @@ -180,14 +180,14 @@ describe('type/extends/Object', () => { it('Should extend optional 1', () => { const A = Type.Object({ a: Type.Number() }) const B = Type.Object({ a: Type.Optional(Type.Number()) }) - const C = TypeExtends.Extends(A, B) - Assert.IsEqual(C, TypeExtendsResult.True) + const C = ExtendsCheck(A, B) + Assert.IsEqual(C, ExtendsResult.True) }) it('Should extend optional 2', () => { const A = Type.Object({ a: Type.Number() }) const B = Type.Object({ a: Type.Optional(Type.Number()) }) - const C = TypeExtends.Extends(B, A) - Assert.IsEqual(C, TypeExtendsResult.False) + const C = ExtendsCheck(B, A) + Assert.IsEqual(C, ExtendsResult.False) }) it('Should extend optional 3', () => { const A = Type.Object({ @@ -198,8 +198,8 @@ describe('type/extends/Object', () => { y: Type.Number(), z: Type.Number(), }) - const R = TypeExtends.Extends(A, B) - Assert.IsEqual(R, TypeExtendsResult.False) + const R = ExtendsCheck(A, B) + Assert.IsEqual(R, ExtendsResult.False) }) it('Should extend optional 4', () => { const A = Type.Object({ @@ -210,8 +210,8 @@ describe('type/extends/Object', () => { y: Type.Number(), z: Type.Number(), }) - const R = TypeExtends.Extends(A, B) - Assert.IsEqual(R, TypeExtendsResult.False) + const R = ExtendsCheck(A, B) + Assert.IsEqual(R, ExtendsResult.False) }) it('Should extend optional 5', () => { const A = Type.Object({ @@ -222,7 +222,7 @@ describe('type/extends/Object', () => { y: Type.Number(), z: Type.Optional(Type.Number()), }) - const R = TypeExtends.Extends(A, B) - Assert.IsEqual(R, TypeExtendsResult.True) + const R = ExtendsCheck(A, B) + Assert.IsEqual(R, ExtendsResult.True) }) }) diff --git a/test/runtime/type/extends/promise.ts b/test/runtime/type/extends/promise.ts index 843786a64..bbc469a77 100644 --- a/test/runtime/type/extends/promise.ts +++ b/test/runtime/type/extends/promise.ts @@ -1,4 +1,4 @@ -import { TypeExtends, TypeExtendsResult } from '@sinclair/typebox' +import { ExtendsCheck, ExtendsResult } from '@sinclair/typebox/type' import { Type } from '@sinclair/typebox' import { Assert } from '../../assert/index' @@ -8,203 +8,203 @@ describe('type/extends/Promise', () => { // ---------------------------------------------- it('Should extend Promise Varying 1', () => { type T = Promise extends Promise ? 1 : 2 - const R = TypeExtends.Extends(Type.Promise(Type.Any()), Type.Promise(Type.Any())) - Assert.IsEqual(R, TypeExtendsResult.True) + const R = ExtendsCheck(Type.Promise(Type.Any()), Type.Promise(Type.Any())) + Assert.IsEqual(R, ExtendsResult.True) }) it('Should extend Promise Varying 2', () => { type T = Promise extends Promise ? 1 : 2 - const R = TypeExtends.Extends(Type.Promise(Type.String()), Type.Promise(Type.Any())) - Assert.IsEqual(R, TypeExtendsResult.True) + const R = ExtendsCheck(Type.Promise(Type.String()), Type.Promise(Type.Any())) + Assert.IsEqual(R, ExtendsResult.True) }) it('Should extend Promise Varying 3', () => { type T = Promise extends Promise ? 1 : 2 // 1 - const R = TypeExtends.Extends(Type.Promise(Type.Any()), Type.Promise(Type.String())) - Assert.IsEqual(R, TypeExtendsResult.True) + const R = ExtendsCheck(Type.Promise(Type.Any()), Type.Promise(Type.String())) + Assert.IsEqual(R, ExtendsResult.True) }) it('Should extend Promise Varying 4', () => { type T = Promise extends Promise ? 1 : 2 - const R = TypeExtends.Extends(Type.Promise(Type.Number()), Type.Promise(Type.String())) - Assert.IsEqual(R, TypeExtendsResult.False) + const R = ExtendsCheck(Type.Promise(Type.Number()), Type.Promise(Type.String())) + Assert.IsEqual(R, ExtendsResult.False) }) // ---------------------------------------------- // Any // ---------------------------------------------- it('Should extend Any', () => { type T = Promise extends any ? 1 : 2 - const R = TypeExtends.Extends(Type.Promise(Type.Any()), Type.Any()) - Assert.IsEqual(R, TypeExtendsResult.True) + const R = ExtendsCheck(Type.Promise(Type.Any()), Type.Any()) + Assert.IsEqual(R, ExtendsResult.True) }) it('Should extend Unknown', () => { type T = Promise extends unknown ? 1 : 2 - const R = TypeExtends.Extends(Type.Promise(Type.Any()), Type.Unknown()) - Assert.IsEqual(R, TypeExtendsResult.True) + const R = ExtendsCheck(Type.Promise(Type.Any()), Type.Unknown()) + Assert.IsEqual(R, ExtendsResult.True) }) it('Should extend String', () => { type T = Promise extends string ? 1 : 2 - const R = TypeExtends.Extends(Type.Promise(Type.Any()), Type.String()) - Assert.IsEqual(R, TypeExtendsResult.False) + const R = ExtendsCheck(Type.Promise(Type.Any()), Type.String()) + Assert.IsEqual(R, ExtendsResult.False) }) it('Should extend Boolean', () => { type T = Promise extends boolean ? 1 : 2 - const R = TypeExtends.Extends(Type.Promise(Type.Any()), Type.Boolean()) - Assert.IsEqual(R, TypeExtendsResult.False) + const R = ExtendsCheck(Type.Promise(Type.Any()), Type.Boolean()) + Assert.IsEqual(R, ExtendsResult.False) }) it('Should extend Number', () => { type T = Promise extends number ? 1 : 2 - const R = TypeExtends.Extends(Type.Promise(Type.Any()), Type.Number()) - Assert.IsEqual(R, TypeExtendsResult.False) + const R = ExtendsCheck(Type.Promise(Type.Any()), Type.Number()) + Assert.IsEqual(R, ExtendsResult.False) }) it('Should extend Integer', () => { type T = Promise extends number ? 1 : 2 - const R = TypeExtends.Extends(Type.Promise(Type.Any()), Type.Integer()) - Assert.IsEqual(R, TypeExtendsResult.False) + const R = ExtendsCheck(Type.Promise(Type.Any()), Type.Integer()) + Assert.IsEqual(R, ExtendsResult.False) }) it('Should extend Array', () => { type T = Promise extends Array ? 1 : 2 - const R = TypeExtends.Extends(Type.Promise(Type.Any()), Type.Array(Type.Any())) - Assert.IsEqual(R, TypeExtendsResult.False) + const R = ExtendsCheck(Type.Promise(Type.Any()), Type.Array(Type.Any())) + Assert.IsEqual(R, ExtendsResult.False) }) it('Should extend Tuple', () => { type T = Promise extends [number, number] ? 1 : 2 - const R = TypeExtends.Extends(Type.Promise(Type.Any()), Type.Tuple([Type.Number(), Type.Number()])) - Assert.IsEqual(R, TypeExtendsResult.False) + const R = ExtendsCheck(Type.Promise(Type.Any()), Type.Tuple([Type.Number(), Type.Number()])) + Assert.IsEqual(R, ExtendsResult.False) }) it('Should extend Record', () => { type T = Promise extends Record ? 1 : 2 - const R = TypeExtends.Extends(Type.Promise(Type.Any()), Type.Record(Type.Number(), Type.Any())) - Assert.IsEqual(R, TypeExtendsResult.False) + const R = ExtendsCheck(Type.Promise(Type.Any()), Type.Record(Type.Number(), Type.Any())) + Assert.IsEqual(R, ExtendsResult.False) }) it('Should extend Object 1', () => { type T = Promise extends {} ? 1 : 2 - const R = TypeExtends.Extends(Type.Promise(Type.Any()), Type.Object({}, { additionalProperties: false })) - Assert.IsEqual(R, TypeExtendsResult.True) + const R = ExtendsCheck(Type.Promise(Type.Any()), Type.Object({}, { additionalProperties: false })) + Assert.IsEqual(R, ExtendsResult.True) }) it('Should extend Object 2', () => { type T = Promise extends { a: 10 } ? 1 : 2 - const R = TypeExtends.Extends(Type.Promise(Type.Any()), Type.Object({ a: Type.Literal(10) }, { additionalProperties: true })) - Assert.IsEqual(R, TypeExtendsResult.False) + const R = ExtendsCheck(Type.Promise(Type.Any()), Type.Object({ a: Type.Literal(10) }, { additionalProperties: true })) + Assert.IsEqual(R, ExtendsResult.False) }) it('Should extend Object 3', () => { type T = Promise extends object ? 1 : 2 - const R = TypeExtends.Extends(Type.Promise(Type.Any()), Type.Object({})) - Assert.IsEqual(R, TypeExtendsResult.True) + const R = ExtendsCheck(Type.Promise(Type.Any()), Type.Object({})) + Assert.IsEqual(R, ExtendsResult.True) }) it('Should extend Union 1', () => { type T = Promise extends number | string ? 1 : 2 - const R = TypeExtends.Extends(Type.Promise(Type.Any()), Type.Union([Type.Number(), Type.String()])) - Assert.IsEqual(R, TypeExtendsResult.False) + const R = ExtendsCheck(Type.Promise(Type.Any()), Type.Union([Type.Number(), Type.String()])) + Assert.IsEqual(R, ExtendsResult.False) }) it('Should extend Union 2', () => { type T = Promise extends any | number ? 1 : 2 - const R = TypeExtends.Extends(Type.Promise(Type.Any()), Type.Union([Type.Any(), Type.Number()])) - Assert.IsEqual(R, TypeExtendsResult.True) + const R = ExtendsCheck(Type.Promise(Type.Any()), Type.Union([Type.Any(), Type.Number()])) + Assert.IsEqual(R, ExtendsResult.True) }) it('Should extend Union 2', () => { type T = Promise extends boolean | number ? 1 : 2 - const R = TypeExtends.Extends(Type.Promise(Type.Any()), Type.Union([Type.Boolean(), Type.Number()])) - Assert.IsEqual(R, TypeExtendsResult.False) + const R = ExtendsCheck(Type.Promise(Type.Any()), Type.Union([Type.Boolean(), Type.Number()])) + Assert.IsEqual(R, ExtendsResult.False) }) it('Should extend Null', () => { type T = Promise extends null ? 1 : 2 - const R = TypeExtends.Extends(Type.Promise(Type.Any()), Type.Null()) - Assert.IsEqual(R, TypeExtendsResult.False) + const R = ExtendsCheck(Type.Promise(Type.Any()), Type.Null()) + Assert.IsEqual(R, ExtendsResult.False) }) it('Should extend Undefined', () => { type T = Promise extends undefined ? 1 : 2 - const R = TypeExtends.Extends(Type.Promise(Type.Any()), Type.Undefined()) - Assert.IsEqual(R, TypeExtendsResult.False) + const R = ExtendsCheck(Type.Promise(Type.Any()), Type.Undefined()) + Assert.IsEqual(R, ExtendsResult.False) }) // ---------------------------------------------- // Constrained // ---------------------------------------------- it('Should extend constrained Any', () => { type T = Promise extends any ? 1 : 2 - const R = TypeExtends.Extends(Type.Promise(Type.Number()), Type.Any()) - Assert.IsEqual(R, TypeExtendsResult.True) + const R = ExtendsCheck(Type.Promise(Type.Number()), Type.Any()) + Assert.IsEqual(R, ExtendsResult.True) }) it('Should extend constrained Unknown', () => { type T = Promise extends unknown ? 1 : 2 - const R = TypeExtends.Extends(Type.Promise(Type.Number()), Type.Unknown()) - Assert.IsEqual(R, TypeExtendsResult.True) + const R = ExtendsCheck(Type.Promise(Type.Number()), Type.Unknown()) + Assert.IsEqual(R, ExtendsResult.True) }) it('Should extend constrained String', () => { type T = Promise extends string ? 1 : 2 - const R = TypeExtends.Extends(Type.Promise(Type.Number()), Type.String()) - Assert.IsEqual(R, TypeExtendsResult.False) + const R = ExtendsCheck(Type.Promise(Type.Number()), Type.String()) + Assert.IsEqual(R, ExtendsResult.False) }) it('Should extend constrained Boolean', () => { type T = Promise extends boolean ? 1 : 2 - const R = TypeExtends.Extends(Type.Promise(Type.Number()), Type.Boolean()) - Assert.IsEqual(R, TypeExtendsResult.False) + const R = ExtendsCheck(Type.Promise(Type.Number()), Type.Boolean()) + Assert.IsEqual(R, ExtendsResult.False) }) it('Should extend constrained Number', () => { type T = Promise extends number ? 1 : 2 - const R = TypeExtends.Extends(Type.Promise(Type.Any()), Type.Number()) - Assert.IsEqual(R, TypeExtendsResult.False) + const R = ExtendsCheck(Type.Promise(Type.Any()), Type.Number()) + Assert.IsEqual(R, ExtendsResult.False) }) it('Should extend constrained Integer', () => { type T = Promise extends number ? 1 : 2 - const R = TypeExtends.Extends(Type.Promise(Type.Number()), Type.Integer()) - Assert.IsEqual(R, TypeExtendsResult.False) + const R = ExtendsCheck(Type.Promise(Type.Number()), Type.Integer()) + Assert.IsEqual(R, ExtendsResult.False) }) it('Should extend constrained Array', () => { type T = Promise extends Array ? 1 : 2 - const R = TypeExtends.Extends(Type.Promise(Type.Number()), Type.Array(Type.Any())) - Assert.IsEqual(R, TypeExtendsResult.False) + const R = ExtendsCheck(Type.Promise(Type.Number()), Type.Array(Type.Any())) + Assert.IsEqual(R, ExtendsResult.False) }) it('Should extend constrained Tuple', () => { type T = Promise extends [number, number] ? 1 : 2 - const R = TypeExtends.Extends(Type.Promise(Type.Number()), Type.Tuple([Type.Number(), Type.Number()])) - Assert.IsEqual(R, TypeExtendsResult.False) + const R = ExtendsCheck(Type.Promise(Type.Number()), Type.Tuple([Type.Number(), Type.Number()])) + Assert.IsEqual(R, ExtendsResult.False) }) it('Should extend constrained Object 1', () => { type T = Promise extends {} ? 1 : 2 - const R = TypeExtends.Extends(Type.Promise(Type.Number()), Type.Object({}, { additionalProperties: false })) - Assert.IsEqual(R, TypeExtendsResult.True) + const R = ExtendsCheck(Type.Promise(Type.Number()), Type.Object({}, { additionalProperties: false })) + Assert.IsEqual(R, ExtendsResult.True) }) it('Should extend constrained Object 2', () => { type T = Promise extends { a: 10 } ? 1 : 2 - const R = TypeExtends.Extends(Type.Promise(Type.Number()), Type.Object({ a: Type.Literal(10) }, { additionalProperties: true })) - Assert.IsEqual(R, TypeExtendsResult.False) + const R = ExtendsCheck(Type.Promise(Type.Number()), Type.Object({ a: Type.Literal(10) }, { additionalProperties: true })) + Assert.IsEqual(R, ExtendsResult.False) }) it('Should extend constrained Object 3', () => { type T = Promise extends object ? 1 : 2 - const R = TypeExtends.Extends(Type.Promise(Type.Number()), Type.Object({})) - Assert.IsEqual(R, TypeExtendsResult.True) + const R = ExtendsCheck(Type.Promise(Type.Number()), Type.Object({})) + Assert.IsEqual(R, ExtendsResult.True) }) it('Should extend constrained Union 1', () => { type T = Promise extends number | string ? 1 : 2 - const R = TypeExtends.Extends(Type.Promise(Type.Number()), Type.Union([Type.Number(), Type.String()])) - Assert.IsEqual(R, TypeExtendsResult.False) + const R = ExtendsCheck(Type.Promise(Type.Number()), Type.Union([Type.Number(), Type.String()])) + Assert.IsEqual(R, ExtendsResult.False) }) it('Should extend constrained Union 2', () => { type T = Promise extends any | number ? 1 : 2 - const R = TypeExtends.Extends(Type.Promise(Type.Number()), Type.Union([Type.Any(), Type.Number()])) - Assert.IsEqual(R, TypeExtendsResult.True) + const R = ExtendsCheck(Type.Promise(Type.Number()), Type.Union([Type.Any(), Type.Number()])) + Assert.IsEqual(R, ExtendsResult.True) }) it('Should extend constrained Union 2', () => { type T = Promise extends boolean | number ? 1 : 2 - const R = TypeExtends.Extends(Type.Promise(Type.Number()), Type.Union([Type.Boolean(), Type.Number()])) - Assert.IsEqual(R, TypeExtendsResult.False) + const R = ExtendsCheck(Type.Promise(Type.Number()), Type.Union([Type.Boolean(), Type.Number()])) + Assert.IsEqual(R, ExtendsResult.False) }) it('Should extend constrained Null', () => { type T = Promise extends null ? 1 : 2 - const R = TypeExtends.Extends(Type.Promise(Type.Number()), Type.Null()) - Assert.IsEqual(R, TypeExtendsResult.False) + const R = ExtendsCheck(Type.Promise(Type.Number()), Type.Null()) + Assert.IsEqual(R, ExtendsResult.False) }) it('Should extend constrained Undefined', () => { type T = Promise extends undefined ? 1 : 2 - const R = TypeExtends.Extends(Type.Promise(Type.Number()), Type.Undefined()) - Assert.IsEqual(R, TypeExtendsResult.False) + const R = ExtendsCheck(Type.Promise(Type.Number()), Type.Undefined()) + Assert.IsEqual(R, ExtendsResult.False) }) it('Should extend Void', () => { type T = Promise extends void ? 1 : 2 - const R = TypeExtends.Extends(Type.Promise(Type.Number()), Type.Void()) - Assert.IsEqual(R, TypeExtendsResult.False) + const R = ExtendsCheck(Type.Promise(Type.Number()), Type.Void()) + Assert.IsEqual(R, ExtendsResult.False) }) it('Should extend Date', () => { type T = Promise extends Date ? 1 : 2 - const R = TypeExtends.Extends(Type.Promise(Type.Number()), Type.Date()) - Assert.IsEqual(R, TypeExtendsResult.False) + const R = ExtendsCheck(Type.Promise(Type.Number()), Type.Date()) + Assert.IsEqual(R, ExtendsResult.False) }) }) diff --git a/test/runtime/type/extends/record.ts b/test/runtime/type/extends/record.ts index 7ac3301c2..d9fd33042 100644 --- a/test/runtime/type/extends/record.ts +++ b/test/runtime/type/extends/record.ts @@ -1,4 +1,4 @@ -import { TypeExtends, TypeExtendsResult } from '@sinclair/typebox' +import { ExtendsCheck, ExtendsResult } from '@sinclair/typebox/type' import { Type } from '@sinclair/typebox' import { Assert } from '../../assert/index' @@ -7,194 +7,194 @@ describe('type/extends/Record', () => { type T = Record<'a' | 'b', number> extends { a: number; b: number } ? 1 : 2 const A = Type.Record(Type.Union([Type.Literal('a'), Type.Literal('b')]), Type.Number()) const B = Type.Object({ a: Type.Number(), b: Type.Number() }) - const R = TypeExtends.Extends(A, B) - Assert.IsEqual(R, TypeExtendsResult.True) + const R = ExtendsCheck(A, B) + Assert.IsEqual(R, ExtendsResult.True) }) it('Should extend Record 2', () => { type T = Record extends { a: number; b: number } ? 1 : 2 const A = Type.Record(Type.String(), Type.Number()) const B = Type.Object({ a: Type.Number(), b: Type.Number() }) - const R = TypeExtends.Extends(A, B) - Assert.IsEqual(R, TypeExtendsResult.False) + const R = ExtendsCheck(A, B) + Assert.IsEqual(R, ExtendsResult.False) }) it('Should extend Record 3', () => { type T = Record extends { a: number; b: number } ? 1 : 2 const A = Type.Record(Type.Number(), Type.Number()) const B = Type.Object({ a: Type.Number(), b: Type.Number() }) - const R = TypeExtends.Extends(A, B) - Assert.IsEqual(R, TypeExtendsResult.False) + const R = ExtendsCheck(A, B) + Assert.IsEqual(R, ExtendsResult.False) }) it('Should extend Record 4', () => { type T = Record<'a' | 'b', number> extends { a: number; b: number } ? 1 : 2 const A = Type.Record(Type.Union([Type.Literal('a'), Type.Literal('b')]), Type.Number()) const B = Type.Object({ a: Type.Number(), b: Type.Number() }) - const R = TypeExtends.Extends(A, B) - Assert.IsEqual(R, TypeExtendsResult.True) + const R = ExtendsCheck(A, B) + Assert.IsEqual(R, ExtendsResult.True) }) it('Should extend Record 5', () => { type T = Record<'a' | 'b', number> extends { a: number; b: number } ? 1 : 2 const A = Type.Record(Type.Union([Type.Literal('a'), Type.Literal('b')]), Type.Number()) const B = Type.Object({ a: Type.Number(), b: Type.Number() }) - const R = TypeExtends.Extends(A, B) - Assert.IsEqual(R, TypeExtendsResult.True) + const R = ExtendsCheck(A, B) + Assert.IsEqual(R, ExtendsResult.True) }) it('Should extend Record 6', () => { type T = Record extends Record<'a' | 'b', number> ? true : false const A = Type.Record(Type.String(), Type.Number()) const B = Type.Record(Type.Union([Type.Literal('a'), Type.Literal('b')]), Type.Number()) - const R = TypeExtends.Extends(A, B) - Assert.IsEqual(R, TypeExtendsResult.True) + const R = ExtendsCheck(A, B) + Assert.IsEqual(R, ExtendsResult.True) }) it('Should extend Record 7', () => { type T = Record extends Record ? 1 : 2 const A = Type.Record(Type.String(), Type.Number()) const B = Type.Record(Type.String(), Type.Number()) - const R = TypeExtends.Extends(A, B) - Assert.IsEqual(R, TypeExtendsResult.True) + const R = ExtendsCheck(A, B) + Assert.IsEqual(R, ExtendsResult.True) }) it('Should extend Record 8', () => { type T = Record extends Record ? 1 : 2 const A = Type.Record(Type.String(), Type.Number()) const B = Type.Record(Type.Number(), Type.Number()) - const R = TypeExtends.Extends(A, B) - Assert.IsEqual(R, TypeExtendsResult.True) + const R = ExtendsCheck(A, B) + Assert.IsEqual(R, ExtendsResult.True) }) it('Should extend Record 9', () => { type T = Record extends Record<'a' | 'b', number> ? 1 : 2 const A = Type.Record(Type.Number(), Type.Number()) const B = Type.Record(Type.Union([Type.Literal('a'), Type.Literal('b')]), Type.Number()) - const R = TypeExtends.Extends(A, B) - Assert.IsEqual(R, TypeExtendsResult.False) + const R = ExtendsCheck(A, B) + Assert.IsEqual(R, ExtendsResult.False) }) it('Should extend Record 10', () => { type T = Record extends Record ? 1 : 2 const A = Type.Record(Type.Number(), Type.Number()) const B = Type.Record(Type.String(), Type.Number()) - const R = TypeExtends.Extends(A, B) - Assert.IsEqual(R, TypeExtendsResult.True) + const R = ExtendsCheck(A, B) + Assert.IsEqual(R, ExtendsResult.True) }) it('Should extend Record 11', () => { type T = Record extends Record ? 1 : 2 const A = Type.Record(Type.Number(), Type.Number()) const B = Type.Record(Type.Number(), Type.Number()) - const R = TypeExtends.Extends(A, B) - Assert.IsEqual(R, TypeExtendsResult.True) + const R = ExtendsCheck(A, B) + Assert.IsEqual(R, ExtendsResult.True) }) // ----- it('Should extend Record 12', () => { type T = Record extends Record ? 1 : 2 const A = Type.Record(Type.String(), Type.Number()) const B = Type.Record(Type.Integer(), Type.Number()) - const R = TypeExtends.Extends(A, B) - Assert.IsEqual(R, TypeExtendsResult.True) + const R = ExtendsCheck(A, B) + Assert.IsEqual(R, ExtendsResult.True) }) it('Should extend Record 13', () => { type T = Record extends Record<'a' | 'b', number> ? 1 : 2 const A = Type.Record(Type.Integer(), Type.Number()) const B = Type.Record(Type.Union([Type.Literal('a'), Type.Literal('b')]), Type.Number()) - const R = TypeExtends.Extends(A, B) - Assert.IsEqual(R, TypeExtendsResult.False) + const R = ExtendsCheck(A, B) + Assert.IsEqual(R, ExtendsResult.False) }) it('Should extend Record 14', () => { type T = Record extends Record ? 1 : 2 const A = Type.Record(Type.Integer(), Type.Number()) const B = Type.Record(Type.String(), Type.Number()) - const R = TypeExtends.Extends(A, B) - Assert.IsEqual(R, TypeExtendsResult.True) + const R = ExtendsCheck(A, B) + Assert.IsEqual(R, ExtendsResult.True) }) it('Should extend Record 15', () => { type T = Record extends Record ? 1 : 2 const A = Type.Record(Type.Integer(), Type.Number()) const B = Type.Record(Type.Integer(), Type.Number()) - const R = TypeExtends.Extends(A, B) - Assert.IsEqual(R, TypeExtendsResult.True) + const R = ExtendsCheck(A, B) + Assert.IsEqual(R, ExtendsResult.True) }) // ------------------------------------------------------------------- // Standard // ------------------------------------------------------------------- it('Should extend Any', () => { type T = Record extends any ? 1 : 2 - const R = TypeExtends.Extends(Type.Record(Type.Number(), Type.Number()), Type.Any()) - Assert.IsEqual(R, TypeExtendsResult.True) + const R = ExtendsCheck(Type.Record(Type.Number(), Type.Number()), Type.Any()) + Assert.IsEqual(R, ExtendsResult.True) }) it('Should extend Unknown', () => { type T = Record extends unknown ? 1 : 2 - const R = TypeExtends.Extends(Type.Record(Type.Number(), Type.Number()), Type.Unknown()) - Assert.IsEqual(R, TypeExtendsResult.True) + const R = ExtendsCheck(Type.Record(Type.Number(), Type.Number()), Type.Unknown()) + Assert.IsEqual(R, ExtendsResult.True) }) it('Should extend String', () => { type T = Record extends string ? 1 : 2 - const R = TypeExtends.Extends(Type.Record(Type.Number(), Type.Number()), Type.String()) - Assert.IsEqual(R, TypeExtendsResult.False) + const R = ExtendsCheck(Type.Record(Type.Number(), Type.Number()), Type.String()) + Assert.IsEqual(R, ExtendsResult.False) }) it('Should extend Boolean', () => { type T = Record extends boolean ? 1 : 2 - const R = TypeExtends.Extends(Type.Record(Type.Number(), Type.Number()), Type.Boolean()) - Assert.IsEqual(R, TypeExtendsResult.False) + const R = ExtendsCheck(Type.Record(Type.Number(), Type.Number()), Type.Boolean()) + Assert.IsEqual(R, ExtendsResult.False) }) it('Should extend Number', () => { type T = Record extends number ? 1 : 2 - const R = TypeExtends.Extends(Type.Record(Type.Number(), Type.Number()), Type.Number()) - Assert.IsEqual(R, TypeExtendsResult.False) + const R = ExtendsCheck(Type.Record(Type.Number(), Type.Number()), Type.Number()) + Assert.IsEqual(R, ExtendsResult.False) }) it('Should extend Integer', () => { type T = Record extends number ? 1 : 2 - const R = TypeExtends.Extends(Type.Record(Type.Number(), Type.Number()), Type.Integer()) - Assert.IsEqual(R, TypeExtendsResult.False) + const R = ExtendsCheck(Type.Record(Type.Number(), Type.Number()), Type.Integer()) + Assert.IsEqual(R, ExtendsResult.False) }) it('Should extend Array 1', () => { type T = Record extends Array ? 1 : 2 - const R = TypeExtends.Extends(Type.Record(Type.Number(), Type.Number()), Type.Array(Type.Any())) - Assert.IsEqual(R, TypeExtendsResult.False) + const R = ExtendsCheck(Type.Record(Type.Number(), Type.Number()), Type.Array(Type.Any())) + Assert.IsEqual(R, ExtendsResult.False) }) it('Should extend Array 2', () => { type T = Record extends Array ? 1 : 2 - const R = TypeExtends.Extends(Type.Record(Type.Number(), Type.Number()), Type.Array(Type.String())) - Assert.IsEqual(R, TypeExtendsResult.False) + const R = ExtendsCheck(Type.Record(Type.Number(), Type.Number()), Type.Array(Type.String())) + Assert.IsEqual(R, ExtendsResult.False) }) it('Should extend Tuple', () => { type T = Record extends [number, number] ? 1 : 2 - const R = TypeExtends.Extends(Type.Record(Type.Number(), Type.Number()), Type.Tuple([Type.Number(), Type.Number()])) - Assert.IsEqual(R, TypeExtendsResult.False) + const R = ExtendsCheck(Type.Record(Type.Number(), Type.Number()), Type.Tuple([Type.Number(), Type.Number()])) + Assert.IsEqual(R, ExtendsResult.False) }) it('Should extend Object 2', () => { type T = Record extends {} ? 1 : 2 - const R = TypeExtends.Extends(Type.Record(Type.Number(), Type.Number()), Type.Object({})) - Assert.IsEqual(R, TypeExtendsResult.True) + const R = ExtendsCheck(Type.Record(Type.Number(), Type.Number()), Type.Object({})) + Assert.IsEqual(R, ExtendsResult.True) }) it('Should extend Object 3', () => { type T = Record extends { a: number } ? 1 : 2 - const R = TypeExtends.Extends(Type.Record(Type.Number(), Type.Number()), Type.Object({ a: Type.Number() })) - Assert.IsEqual(R, TypeExtendsResult.False) + const R = ExtendsCheck(Type.Record(Type.Number(), Type.Number()), Type.Object({ a: Type.Number() })) + Assert.IsEqual(R, ExtendsResult.False) }) it('Should extend Union 1', () => { type T = Record extends number | string ? 1 : 2 - const R = TypeExtends.Extends(Type.Record(Type.Number(), Type.Number()), Type.Union([Type.Number(), Type.String()])) - Assert.IsEqual(R, TypeExtendsResult.False) + const R = ExtendsCheck(Type.Record(Type.Number(), Type.Number()), Type.Union([Type.Number(), Type.String()])) + Assert.IsEqual(R, ExtendsResult.False) }) it('Should extend Union 2', () => { type T = Record extends any | number ? 1 : 2 - const R = TypeExtends.Extends(Type.Record(Type.Number(), Type.Number()), Type.Union([Type.Any(), Type.String()])) - Assert.IsEqual(R, TypeExtendsResult.True) + const R = ExtendsCheck(Type.Record(Type.Number(), Type.Number()), Type.Union([Type.Any(), Type.String()])) + Assert.IsEqual(R, ExtendsResult.True) }) it('Should extend Null', () => { type T = Record extends null ? 1 : 2 - const R = TypeExtends.Extends(Type.Record(Type.Number(), Type.Number()), Type.Null()) - Assert.IsEqual(R, TypeExtendsResult.False) + const R = ExtendsCheck(Type.Record(Type.Number(), Type.Number()), Type.Null()) + Assert.IsEqual(R, ExtendsResult.False) }) it('Should extend Undefined', () => { type T = Record extends undefined ? 1 : 2 - const R = TypeExtends.Extends(Type.Record(Type.Number(), Type.Number()), Type.Undefined()) - Assert.IsEqual(R, TypeExtendsResult.False) + const R = ExtendsCheck(Type.Record(Type.Number(), Type.Number()), Type.Undefined()) + Assert.IsEqual(R, ExtendsResult.False) }) it('Should extend Void', () => { type T = Record extends void ? 1 : 2 - const R = TypeExtends.Extends(Type.Record(Type.Number(), Type.Number()), Type.Void()) - Assert.IsEqual(R, TypeExtendsResult.False) + const R = ExtendsCheck(Type.Record(Type.Number(), Type.Number()), Type.Void()) + Assert.IsEqual(R, ExtendsResult.False) }) it('Should extend Date', () => { type T = Record extends Date ? 1 : 2 - const R = TypeExtends.Extends(Type.Record(Type.Number(), Type.Number()), Type.Date()) - Assert.IsEqual(R, TypeExtendsResult.False) + const R = ExtendsCheck(Type.Record(Type.Number(), Type.Number()), Type.Date()) + Assert.IsEqual(R, ExtendsResult.False) }) }) diff --git a/test/runtime/type/extends/string.ts b/test/runtime/type/extends/string.ts index 0dd95ecbe..480827671 100644 --- a/test/runtime/type/extends/string.ts +++ b/test/runtime/type/extends/string.ts @@ -1,111 +1,111 @@ -import { TypeExtends, TypeExtendsResult } from '@sinclair/typebox' +import { ExtendsCheck, ExtendsResult } from '@sinclair/typebox/type' import { Type } from '@sinclair/typebox' import { Assert } from '../../assert/index' describe('type/extends/String', () => { it('Should extend Any', () => { type T = string extends any ? 1 : 2 - const R = TypeExtends.Extends(Type.String(), Type.Any()) - Assert.IsEqual(R, TypeExtendsResult.True) + const R = ExtendsCheck(Type.String(), Type.Any()) + Assert.IsEqual(R, ExtendsResult.True) }) it('Should extend Unknown', () => { type T = string extends unknown ? 1 : 2 - const R = TypeExtends.Extends(Type.String(), Type.Unknown()) - Assert.IsEqual(R, TypeExtendsResult.True) + const R = ExtendsCheck(Type.String(), Type.Unknown()) + Assert.IsEqual(R, ExtendsResult.True) }) it('Should extend String', () => { type T = string extends string ? 1 : 2 - const R = TypeExtends.Extends(Type.String(), Type.String()) - Assert.IsEqual(R, TypeExtendsResult.True) + const R = ExtendsCheck(Type.String(), Type.String()) + Assert.IsEqual(R, ExtendsResult.True) }) it('Should extend Boolean', () => { type T = string extends boolean ? 1 : 2 - const R = TypeExtends.Extends(Type.String(), Type.Boolean()) - Assert.IsEqual(R, TypeExtendsResult.False) + const R = ExtendsCheck(Type.String(), Type.Boolean()) + Assert.IsEqual(R, ExtendsResult.False) }) it('Should extend Number', () => { type T = string extends number ? 1 : 2 - const R = TypeExtends.Extends(Type.String(), Type.Number()) - Assert.IsEqual(R, TypeExtendsResult.False) + const R = ExtendsCheck(Type.String(), Type.Number()) + Assert.IsEqual(R, ExtendsResult.False) }) it('Should extend Integer', () => { type T = string extends number ? 1 : 2 - const R = TypeExtends.Extends(Type.String(), Type.Integer()) - Assert.IsEqual(R, TypeExtendsResult.False) + const R = ExtendsCheck(Type.String(), Type.Integer()) + Assert.IsEqual(R, ExtendsResult.False) }) it('Should extend Array', () => { type T = string extends Array ? 1 : 2 - const R = TypeExtends.Extends(Type.String(), Type.Array(Type.Any())) - Assert.IsEqual(R, TypeExtendsResult.False) + const R = ExtendsCheck(Type.String(), Type.Array(Type.Any())) + Assert.IsEqual(R, ExtendsResult.False) }) it('Should extend Tuple', () => { type T = string extends [number, number] ? 1 : 2 - const R = TypeExtends.Extends(Type.String(), Type.Tuple([Type.Number(), Type.Number()])) - Assert.IsEqual(R, TypeExtendsResult.False) + const R = ExtendsCheck(Type.String(), Type.Tuple([Type.Number(), Type.Number()])) + Assert.IsEqual(R, ExtendsResult.False) }) it('Should extend Record 1', () => { type T = string extends Record ? 1 : 2 - const R = TypeExtends.Extends(Type.String(), Type.Record(Type.Number(), Type.Any())) - Assert.IsEqual(R, TypeExtendsResult.True) + const R = ExtendsCheck(Type.String(), Type.Record(Type.Number(), Type.Any())) + Assert.IsEqual(R, ExtendsResult.True) }) it('Should extend Record 2', () => { type T = string extends Record ? 1 : 2 - const R = TypeExtends.Extends(Type.String(), Type.Record(Type.Number(), Type.Unknown())) - Assert.IsEqual(R, TypeExtendsResult.True) + const R = ExtendsCheck(Type.String(), Type.Record(Type.Number(), Type.Unknown())) + Assert.IsEqual(R, ExtendsResult.True) }) it('Should extend Record 3', () => { type T = string extends Record ? 1 : 2 - const R = TypeExtends.Extends(Type.String(), Type.Record(Type.Number(), Type.String())) - Assert.IsEqual(R, TypeExtendsResult.True) + const R = ExtendsCheck(Type.String(), Type.Record(Type.Number(), Type.String())) + Assert.IsEqual(R, ExtendsResult.True) }) it('Should extend Record 4', () => { type T = string extends Record ? 1 : 2 - const R = TypeExtends.Extends(Type.String(), Type.Record(Type.Number(), Type.Number())) - Assert.IsEqual(R, TypeExtendsResult.False) + const R = ExtendsCheck(Type.String(), Type.Record(Type.Number(), Type.Number())) + Assert.IsEqual(R, ExtendsResult.False) }) it('Should extend Object 1', () => { type T = string extends {} ? 1 : 2 - const R = TypeExtends.Extends(Type.String(), Type.Object({}, { additionalProperties: false })) - Assert.IsEqual(R, TypeExtendsResult.True) + const R = ExtendsCheck(Type.String(), Type.Object({}, { additionalProperties: false })) + Assert.IsEqual(R, ExtendsResult.True) }) it('Should extend Object 2', () => { type T = string extends { a: 10 } ? 1 : 2 - const R = TypeExtends.Extends(Type.String(), Type.Object({ a: Type.Literal(10) }, { additionalProperties: true })) - Assert.IsEqual(R, TypeExtendsResult.False) + const R = ExtendsCheck(Type.String(), Type.Object({ a: Type.Literal(10) }, { additionalProperties: true })) + Assert.IsEqual(R, ExtendsResult.False) }) it('Should extend Union 1', () => { type T = number extends number | string ? 1 : 2 - const R = TypeExtends.Extends(Type.Number(), Type.Union([Type.Number(), Type.String()])) - Assert.IsEqual(R, TypeExtendsResult.True) + const R = ExtendsCheck(Type.Number(), Type.Union([Type.Number(), Type.String()])) + Assert.IsEqual(R, ExtendsResult.True) }) it('Should extend Union 2', () => { type T = number extends any | number ? 1 : 2 - const R = TypeExtends.Extends(Type.Number(), Type.Union([Type.Any(), Type.Number()])) - Assert.IsEqual(R, TypeExtendsResult.True) + const R = ExtendsCheck(Type.Number(), Type.Union([Type.Any(), Type.Number()])) + Assert.IsEqual(R, ExtendsResult.True) }) it('Should extend Union 3', () => { type T = number extends boolean | number ? 1 : 2 - const R = TypeExtends.Extends(Type.Number(), Type.Union([Type.Boolean(), Type.Number()])) - Assert.IsEqual(R, TypeExtendsResult.True) + const R = ExtendsCheck(Type.Number(), Type.Union([Type.Boolean(), Type.Number()])) + Assert.IsEqual(R, ExtendsResult.True) }) it('Should extend Null', () => { type T = number extends null ? 1 : 2 - const R = TypeExtends.Extends(Type.Number(), Type.Null()) - Assert.IsEqual(R, TypeExtendsResult.False) + const R = ExtendsCheck(Type.Number(), Type.Null()) + Assert.IsEqual(R, ExtendsResult.False) }) it('Should extend Undefined', () => { type T = number extends undefined ? 1 : 2 - const R = TypeExtends.Extends(Type.Number(), Type.Undefined()) - Assert.IsEqual(R, TypeExtendsResult.False) + const R = ExtendsCheck(Type.Number(), Type.Undefined()) + Assert.IsEqual(R, ExtendsResult.False) }) it('Should extend Void', () => { type T = number extends void ? 1 : 2 - const R = TypeExtends.Extends(Type.Number(), Type.Void()) - Assert.IsEqual(R, TypeExtendsResult.False) + const R = ExtendsCheck(Type.Number(), Type.Void()) + Assert.IsEqual(R, ExtendsResult.False) }) it('Should extend Date', () => { type T = number extends Date ? 1 : 2 - const R = TypeExtends.Extends(Type.Number(), Type.Date()) - Assert.IsEqual(R, TypeExtendsResult.False) + const R = ExtendsCheck(Type.Number(), Type.Date()) + Assert.IsEqual(R, ExtendsResult.False) }) }) diff --git a/test/runtime/type/extends/symbol.ts b/test/runtime/type/extends/symbol.ts index 03dc7aaf0..690f112ac 100644 --- a/test/runtime/type/extends/symbol.ts +++ b/test/runtime/type/extends/symbol.ts @@ -1,106 +1,106 @@ -import { TypeExtends, TypeExtendsResult } from '@sinclair/typebox' +import { ExtendsCheck, ExtendsResult } from '@sinclair/typebox/type' import { Type } from '@sinclair/typebox' import { Assert } from '../../assert/index' describe('type/extends/Symbol', () => { it('Should extend Any', () => { type T = symbol extends any ? 1 : 2 - const R = TypeExtends.Extends(Type.Symbol(), Type.Any()) - Assert.IsEqual(R, TypeExtendsResult.True) + const R = ExtendsCheck(Type.Symbol(), Type.Any()) + Assert.IsEqual(R, ExtendsResult.True) }) it('Should extend Unknown', () => { type T = symbol extends unknown ? 1 : 2 - const R = TypeExtends.Extends(Type.Symbol(), Type.Unknown()) - Assert.IsEqual(R, TypeExtendsResult.True) + const R = ExtendsCheck(Type.Symbol(), Type.Unknown()) + Assert.IsEqual(R, ExtendsResult.True) }) it('Should extend String', () => { type T = symbol extends string ? 1 : 2 - const R = TypeExtends.Extends(Type.Symbol(), Type.String()) - Assert.IsEqual(R, TypeExtendsResult.False) + const R = ExtendsCheck(Type.Symbol(), Type.String()) + Assert.IsEqual(R, ExtendsResult.False) }) it('Should extend Boolean', () => { type T = symbol extends boolean ? 1 : 2 - const R = TypeExtends.Extends(Type.Symbol(), Type.Boolean()) - Assert.IsEqual(R, TypeExtendsResult.False) + const R = ExtendsCheck(Type.Symbol(), Type.Boolean()) + Assert.IsEqual(R, ExtendsResult.False) }) it('Should extend Number', () => { type T = symbol extends number ? 1 : 2 - const R = TypeExtends.Extends(Type.Symbol(), Type.Number()) - Assert.IsEqual(R, TypeExtendsResult.False) + const R = ExtendsCheck(Type.Symbol(), Type.Number()) + Assert.IsEqual(R, ExtendsResult.False) }) it('Should extend Integer', () => { type T = symbol extends number ? 1 : 2 - const R = TypeExtends.Extends(Type.Symbol(), Type.Integer()) - Assert.IsEqual(R, TypeExtendsResult.False) + const R = ExtendsCheck(Type.Symbol(), Type.Integer()) + Assert.IsEqual(R, ExtendsResult.False) }) it('Should extend Array', () => { type T = symbol extends Array ? 1 : 2 - const R = TypeExtends.Extends(Type.Symbol(), Type.Array(Type.Any())) - Assert.IsEqual(R, TypeExtendsResult.False) + const R = ExtendsCheck(Type.Symbol(), Type.Array(Type.Any())) + Assert.IsEqual(R, ExtendsResult.False) }) it('Should extend Tuple', () => { type T = symbol extends [number, number] ? 1 : 2 - const R = TypeExtends.Extends(Type.Symbol(), Type.Tuple([Type.Number(), Type.Number()])) - Assert.IsEqual(R, TypeExtendsResult.False) + const R = ExtendsCheck(Type.Symbol(), Type.Tuple([Type.Number(), Type.Number()])) + Assert.IsEqual(R, ExtendsResult.False) }) it('Should extend Record', () => { type T = symbol extends Record ? 1 : 2 - const R = TypeExtends.Extends(Type.Symbol(), Type.Record(Type.Number(), Type.Any())) - Assert.IsEqual(R, TypeExtendsResult.False) + const R = ExtendsCheck(Type.Symbol(), Type.Record(Type.Number(), Type.Any())) + Assert.IsEqual(R, ExtendsResult.False) }) it('Should extend Object 1', () => { type T = symbol extends {} ? 1 : 2 - const R = TypeExtends.Extends(Type.Symbol(), Type.Object({})) - Assert.IsEqual(R, TypeExtendsResult.True) + const R = ExtendsCheck(Type.Symbol(), Type.Object({})) + Assert.IsEqual(R, ExtendsResult.True) }) it('Should extend Object 2', () => { type T = symbol extends { a: 10 } ? 1 : 2 - const R = TypeExtends.Extends(Type.Symbol(), Type.Object({ a: Type.Literal(10) })) - Assert.IsEqual(R, TypeExtendsResult.False) + const R = ExtendsCheck(Type.Symbol(), Type.Object({ a: Type.Literal(10) })) + Assert.IsEqual(R, ExtendsResult.False) }) it('Should extend Union 1', () => { type T = symbol extends number | string ? 1 : 2 - const R = TypeExtends.Extends(Type.Symbol(), Type.Union([Type.Number(), Type.String()])) - Assert.IsEqual(R, TypeExtendsResult.False) + const R = ExtendsCheck(Type.Symbol(), Type.Union([Type.Number(), Type.String()])) + Assert.IsEqual(R, ExtendsResult.False) }) it('Should extend Union 2', () => { type T = symbol extends any | number ? 1 : 2 - const R = TypeExtends.Extends(Type.Symbol(), Type.Union([Type.Any(), Type.Number()])) - Assert.IsEqual(R, TypeExtendsResult.True) + const R = ExtendsCheck(Type.Symbol(), Type.Union([Type.Any(), Type.Number()])) + Assert.IsEqual(R, ExtendsResult.True) }) it('Should extend Union 3', () => { type T = symbol extends boolean | number ? 1 : 2 - const R = TypeExtends.Extends(Type.Symbol(), Type.Union([Type.Boolean(), Type.Number()])) - Assert.IsEqual(R, TypeExtendsResult.False) + const R = ExtendsCheck(Type.Symbol(), Type.Union([Type.Boolean(), Type.Number()])) + Assert.IsEqual(R, ExtendsResult.False) }) it('Should extend Union 4', () => { type T = symbol extends boolean | symbol ? 1 : 2 - const R = TypeExtends.Extends(Type.Symbol(), Type.Union([Type.Boolean(), Type.Symbol()])) - Assert.IsEqual(R, TypeExtendsResult.True) + const R = ExtendsCheck(Type.Symbol(), Type.Union([Type.Boolean(), Type.Symbol()])) + Assert.IsEqual(R, ExtendsResult.True) }) it('Should extend Null', () => { type T = symbol extends null ? 1 : 2 - const R = TypeExtends.Extends(Type.Symbol(), Type.Null()) - Assert.IsEqual(R, TypeExtendsResult.False) + const R = ExtendsCheck(Type.Symbol(), Type.Null()) + Assert.IsEqual(R, ExtendsResult.False) }) it('Should extend Undefined', () => { type T = symbol extends undefined ? 1 : 2 - const R = TypeExtends.Extends(Type.Symbol(), Type.Undefined()) - Assert.IsEqual(R, TypeExtendsResult.False) + const R = ExtendsCheck(Type.Symbol(), Type.Undefined()) + Assert.IsEqual(R, ExtendsResult.False) }) it('Should extend Void', () => { type T = symbol extends undefined ? 1 : 2 - const R = TypeExtends.Extends(Type.Symbol(), Type.Void()) - Assert.IsEqual(R, TypeExtendsResult.False) + const R = ExtendsCheck(Type.Symbol(), Type.Void()) + Assert.IsEqual(R, ExtendsResult.False) }) it('Should extend Date', () => { type T = symbol extends Date ? 1 : 2 - const R = TypeExtends.Extends(Type.Symbol(), Type.Date()) - Assert.IsEqual(R, TypeExtendsResult.False) + const R = ExtendsCheck(Type.Symbol(), Type.Date()) + Assert.IsEqual(R, ExtendsResult.False) }) it('Should extend Symbol', () => { type T = symbol extends symbol ? 1 : 2 - const R = TypeExtends.Extends(Type.Symbol(), Type.Symbol()) - Assert.IsEqual(R, TypeExtendsResult.True) + const R = ExtendsCheck(Type.Symbol(), Type.Symbol()) + Assert.IsEqual(R, ExtendsResult.True) }) }) diff --git a/test/runtime/type/extends/template-literal.ts b/test/runtime/type/extends/template-literal.ts index 3dd6ff3d2..a5608e0ed 100644 --- a/test/runtime/type/extends/template-literal.ts +++ b/test/runtime/type/extends/template-literal.ts @@ -1,4 +1,4 @@ -import { TypeExtends, TypeExtendsResult } from '@sinclair/typebox' +import { ExtendsCheck, ExtendsResult } from '@sinclair/typebox/type' import { Type } from '@sinclair/typebox' import { Assert } from '../../assert/index' @@ -8,155 +8,155 @@ describe('type/extends/TemplateLiteral', () => { // ------------------------------------------------------------------- it('Should extend Any (hello)', () => { type T = 'hello' extends any ? 1 : 2 - const R = TypeExtends.Extends(Type.TemplateLiteral([Type.Literal('hello')]), Type.Any()) - Assert.IsEqual(R, TypeExtendsResult.True) + const R = ExtendsCheck(Type.TemplateLiteral([Type.Literal('hello')]), Type.Any()) + Assert.IsEqual(R, ExtendsResult.True) }) it('Should extend Unknown (hello)', () => { type T = 'hello' extends unknown ? 1 : 2 - const R = TypeExtends.Extends(Type.TemplateLiteral([Type.Literal('hello')]), Type.Unknown()) - Assert.IsEqual(R, TypeExtendsResult.True) + const R = ExtendsCheck(Type.TemplateLiteral([Type.Literal('hello')]), Type.Unknown()) + Assert.IsEqual(R, ExtendsResult.True) }) it('Should extend String (hello)', () => { type T = 'hello' extends string ? 1 : 2 - const R = TypeExtends.Extends(Type.TemplateLiteral([Type.Literal('hello')]), Type.String()) - Assert.IsEqual(R, TypeExtendsResult.True) + const R = ExtendsCheck(Type.TemplateLiteral([Type.Literal('hello')]), Type.String()) + Assert.IsEqual(R, ExtendsResult.True) }) it('Should extend Boolean (hello)', () => { type T = 'hello' extends boolean ? 1 : 2 - const R = TypeExtends.Extends(Type.TemplateLiteral([Type.Literal('hello')]), Type.Boolean()) - Assert.IsEqual(R, TypeExtendsResult.False) + const R = ExtendsCheck(Type.TemplateLiteral([Type.Literal('hello')]), Type.Boolean()) + Assert.IsEqual(R, ExtendsResult.False) }) it('Should extend Number (hello)', () => { type T = 'hello' extends number ? 1 : 2 - const R = TypeExtends.Extends(Type.TemplateLiteral([Type.Literal('hello')]), Type.Number()) - Assert.IsEqual(R, TypeExtendsResult.False) + const R = ExtendsCheck(Type.TemplateLiteral([Type.Literal('hello')]), Type.Number()) + Assert.IsEqual(R, ExtendsResult.False) }) it('Should extend Integer (hello)', () => { type T = 'hello' extends number ? 1 : 2 - const R = TypeExtends.Extends(Type.TemplateLiteral([Type.Literal('hello')]), Type.Integer()) - Assert.IsEqual(R, TypeExtendsResult.False) + const R = ExtendsCheck(Type.TemplateLiteral([Type.Literal('hello')]), Type.Integer()) + Assert.IsEqual(R, ExtendsResult.False) }) it('Should extend Array (hello)', () => { type T = 'hello' extends Array ? 1 : 2 - const R = TypeExtends.Extends(Type.TemplateLiteral([Type.Literal('hello')]), Type.Array(Type.Any())) - Assert.IsEqual(R, TypeExtendsResult.False) + const R = ExtendsCheck(Type.TemplateLiteral([Type.Literal('hello')]), Type.Array(Type.Any())) + Assert.IsEqual(R, ExtendsResult.False) }) it('Should extend Tuple (hello)', () => { type T = 'hello' extends [number, number] ? 1 : 2 - const R = TypeExtends.Extends(Type.TemplateLiteral([Type.Literal('hello')]), Type.Tuple([Type.Number(), Type.Number()])) - Assert.IsEqual(R, TypeExtendsResult.False) + const R = ExtendsCheck(Type.TemplateLiteral([Type.Literal('hello')]), Type.Tuple([Type.Number(), Type.Number()])) + Assert.IsEqual(R, ExtendsResult.False) }) it('Should extend Object 1 (hello)', () => { type T = 'hello' extends {} ? 1 : 2 - const R = TypeExtends.Extends(Type.TemplateLiteral([Type.Literal('hello')]), Type.Object({}, { additionalProperties: false })) - Assert.IsEqual(R, TypeExtendsResult.True) + const R = ExtendsCheck(Type.TemplateLiteral([Type.Literal('hello')]), Type.Object({}, { additionalProperties: false })) + Assert.IsEqual(R, ExtendsResult.True) }) it('Should extend Object 2 (hello)', () => { type T = 'hello' extends { a: 10 } ? 1 : 2 - const R = TypeExtends.Extends(Type.TemplateLiteral([Type.Literal('hello')]), Type.Object({ a: Type.Literal(10) }, { additionalProperties: true })) - Assert.IsEqual(R, TypeExtendsResult.False) + const R = ExtendsCheck(Type.TemplateLiteral([Type.Literal('hello')]), Type.Object({ a: Type.Literal(10) }, { additionalProperties: true })) + Assert.IsEqual(R, ExtendsResult.False) }) it('Should extend Union 1 (hello)', () => { type T = 'hello' extends number | string ? 1 : 2 - const R = TypeExtends.Extends(Type.TemplateLiteral([Type.Literal('hello')]), Type.Union([Type.Number(), Type.String()])) - Assert.IsEqual(R, TypeExtendsResult.True) + const R = ExtendsCheck(Type.TemplateLiteral([Type.Literal('hello')]), Type.Union([Type.Number(), Type.String()])) + Assert.IsEqual(R, ExtendsResult.True) }) it('Should extend Union 2 (hello)', () => { type T = 'hello' extends any | number ? 1 : 2 - const R = TypeExtends.Extends(Type.TemplateLiteral([Type.Literal('hello')]), Type.Union([Type.Any(), Type.Number()])) - Assert.IsEqual(R, TypeExtendsResult.True) + const R = ExtendsCheck(Type.TemplateLiteral([Type.Literal('hello')]), Type.Union([Type.Any(), Type.Number()])) + Assert.IsEqual(R, ExtendsResult.True) }) it('Should extend Union 3 (hello)', () => { type T = 'hello' extends boolean | number ? 1 : 2 - const R = TypeExtends.Extends(Type.TemplateLiteral([Type.Literal('hello')]), Type.Union([Type.Boolean(), Type.Number()])) - Assert.IsEqual(R, TypeExtendsResult.False) + const R = ExtendsCheck(Type.TemplateLiteral([Type.Literal('hello')]), Type.Union([Type.Boolean(), Type.Number()])) + Assert.IsEqual(R, ExtendsResult.False) }) it('Should extend Null (hello)', () => { type T = 'hello' extends null ? 1 : 2 - const R = TypeExtends.Extends(Type.TemplateLiteral([Type.Literal('hello')]), Type.Null()) - Assert.IsEqual(R, TypeExtendsResult.False) + const R = ExtendsCheck(Type.TemplateLiteral([Type.Literal('hello')]), Type.Null()) + Assert.IsEqual(R, ExtendsResult.False) }) it('Should extend Undefined (hello)', () => { type T = 'hello' extends undefined ? 1 : 2 - const R = TypeExtends.Extends(Type.TemplateLiteral([Type.Literal('hello')]), Type.Undefined()) - Assert.IsEqual(R, TypeExtendsResult.False) + const R = ExtendsCheck(Type.TemplateLiteral([Type.Literal('hello')]), Type.Undefined()) + Assert.IsEqual(R, ExtendsResult.False) }) // ------------------------------------------------------------------- // String Literal 'hello' | 'world' // ------------------------------------------------------------------- it('Should extend Any (hello | world)', () => { type T = 'hello' | 'world' extends any ? 1 : 2 - const R = TypeExtends.Extends(Type.TemplateLiteral([Type.Union([Type.Literal('hello'), Type.Literal('world')])]), Type.Any()) - Assert.IsEqual(R, TypeExtendsResult.True) + const R = ExtendsCheck(Type.TemplateLiteral([Type.Union([Type.Literal('hello'), Type.Literal('world')])]), Type.Any()) + Assert.IsEqual(R, ExtendsResult.True) }) it('Should extend Unknown (hello | world)', () => { type T = 'hello' | 'world' extends unknown ? 1 : 2 - const R = TypeExtends.Extends(Type.TemplateLiteral([Type.Union([Type.Literal('hello'), Type.Literal('world')])]), Type.Unknown()) - Assert.IsEqual(R, TypeExtendsResult.True) + const R = ExtendsCheck(Type.TemplateLiteral([Type.Union([Type.Literal('hello'), Type.Literal('world')])]), Type.Unknown()) + Assert.IsEqual(R, ExtendsResult.True) }) it('Should extend String (hello | world)', () => { type T = 'hello' | 'world' extends string ? 1 : 2 - const R = TypeExtends.Extends(Type.TemplateLiteral([Type.Union([Type.Literal('hello'), Type.Literal('world')])]), Type.String()) - Assert.IsEqual(R, TypeExtendsResult.True) + const R = ExtendsCheck(Type.TemplateLiteral([Type.Union([Type.Literal('hello'), Type.Literal('world')])]), Type.String()) + Assert.IsEqual(R, ExtendsResult.True) }) it('Should extend Boolean (hello | world)', () => { type T = 'hello' | 'world' extends boolean ? 1 : 2 - const R = TypeExtends.Extends(Type.TemplateLiteral([Type.Union([Type.Literal('hello'), Type.Literal('world')])]), Type.Boolean()) - Assert.IsEqual(R, TypeExtendsResult.False) + const R = ExtendsCheck(Type.TemplateLiteral([Type.Union([Type.Literal('hello'), Type.Literal('world')])]), Type.Boolean()) + Assert.IsEqual(R, ExtendsResult.False) }) it('Should extend Number (hello | world)', () => { type T = 'hello' | 'world' extends number ? 1 : 2 - const R = TypeExtends.Extends(Type.TemplateLiteral([Type.Union([Type.Literal('hello'), Type.Literal('world')])]), Type.Number()) - Assert.IsEqual(R, TypeExtendsResult.False) + const R = ExtendsCheck(Type.TemplateLiteral([Type.Union([Type.Literal('hello'), Type.Literal('world')])]), Type.Number()) + Assert.IsEqual(R, ExtendsResult.False) }) it('Should extend Integer (hello | world)', () => { type T = 'hello' | 'world' extends number ? 1 : 2 - const R = TypeExtends.Extends(Type.TemplateLiteral([Type.Union([Type.Literal('hello'), Type.Literal('world')])]), Type.Integer()) - Assert.IsEqual(R, TypeExtendsResult.False) + const R = ExtendsCheck(Type.TemplateLiteral([Type.Union([Type.Literal('hello'), Type.Literal('world')])]), Type.Integer()) + Assert.IsEqual(R, ExtendsResult.False) }) it('Should extend Array (hello | world)', () => { type T = 'hello' | 'world' extends Array ? 1 : 2 - const R = TypeExtends.Extends(Type.TemplateLiteral([Type.Union([Type.Literal('hello'), Type.Literal('world')])]), Type.Array(Type.Any())) - Assert.IsEqual(R, TypeExtendsResult.False) + const R = ExtendsCheck(Type.TemplateLiteral([Type.Union([Type.Literal('hello'), Type.Literal('world')])]), Type.Array(Type.Any())) + Assert.IsEqual(R, ExtendsResult.False) }) it('Should extend Tuple (hello | world)', () => { type T = 'hello' | 'world' extends [number, number] ? 1 : 2 - const R = TypeExtends.Extends(Type.TemplateLiteral([Type.Union([Type.Literal('hello'), Type.Literal('world')])]), Type.Tuple([Type.Number(), Type.Number()])) - Assert.IsEqual(R, TypeExtendsResult.False) + const R = ExtendsCheck(Type.TemplateLiteral([Type.Union([Type.Literal('hello'), Type.Literal('world')])]), Type.Tuple([Type.Number(), Type.Number()])) + Assert.IsEqual(R, ExtendsResult.False) }) it('Should extend Object 1 (hello | world)', () => { type T = 'hello' | 'world' extends {} ? 1 : 2 - const R = TypeExtends.Extends(Type.TemplateLiteral([Type.Union([Type.Literal('hello'), Type.Literal('world')])]), Type.Object({}, { additionalProperties: false })) - Assert.IsEqual(R, TypeExtendsResult.True) + const R = ExtendsCheck(Type.TemplateLiteral([Type.Union([Type.Literal('hello'), Type.Literal('world')])]), Type.Object({}, { additionalProperties: false })) + Assert.IsEqual(R, ExtendsResult.True) }) it('Should extend Object 2 (hello | world)', () => { type T = 'hello' | 'world' extends { a: 10 } ? 1 : 2 - const R = TypeExtends.Extends(Type.TemplateLiteral([Type.Union([Type.Literal('hello'), Type.Literal('world')])]), Type.Object({ a: Type.Literal(10) }, { additionalProperties: true })) - Assert.IsEqual(R, TypeExtendsResult.False) + const R = ExtendsCheck(Type.TemplateLiteral([Type.Union([Type.Literal('hello'), Type.Literal('world')])]), Type.Object({ a: Type.Literal(10) }, { additionalProperties: true })) + Assert.IsEqual(R, ExtendsResult.False) }) it('Should extend Union 1 (hello | world)', () => { type T = 'hello' | 'world' extends number | string ? 1 : 2 - const R = TypeExtends.Extends(Type.TemplateLiteral([Type.Union([Type.Literal('hello'), Type.Literal('world')])]), Type.Union([Type.Number(), Type.String()])) - Assert.IsEqual(R, TypeExtendsResult.True) + const R = ExtendsCheck(Type.TemplateLiteral([Type.Union([Type.Literal('hello'), Type.Literal('world')])]), Type.Union([Type.Number(), Type.String()])) + Assert.IsEqual(R, ExtendsResult.True) }) it('Should extend Union 2 (hello | world)', () => { type T = 'hello' | 'world' extends any | number ? 1 : 2 - const R = TypeExtends.Extends(Type.TemplateLiteral([Type.Union([Type.Literal('hello'), Type.Literal('world')])]), Type.Union([Type.Any(), Type.Number()])) - Assert.IsEqual(R, TypeExtendsResult.True) + const R = ExtendsCheck(Type.TemplateLiteral([Type.Union([Type.Literal('hello'), Type.Literal('world')])]), Type.Union([Type.Any(), Type.Number()])) + Assert.IsEqual(R, ExtendsResult.True) }) it('Should extend Union 3 (hello | world)', () => { type T = 'hello' | 'world' extends boolean | number ? 1 : 2 - const R = TypeExtends.Extends(Type.TemplateLiteral([Type.Union([Type.Literal('hello'), Type.Literal('world')])]), Type.Union([Type.Boolean(), Type.Number()])) - Assert.IsEqual(R, TypeExtendsResult.False) + const R = ExtendsCheck(Type.TemplateLiteral([Type.Union([Type.Literal('hello'), Type.Literal('world')])]), Type.Union([Type.Boolean(), Type.Number()])) + Assert.IsEqual(R, ExtendsResult.False) }) it('Should extend Null (hello | world)', () => { type T = 'hello' | 'world' extends null ? 1 : 2 - const R = TypeExtends.Extends(Type.TemplateLiteral([Type.Union([Type.Literal('hello'), Type.Literal('world')])]), Type.Null()) - Assert.IsEqual(R, TypeExtendsResult.False) + const R = ExtendsCheck(Type.TemplateLiteral([Type.Union([Type.Literal('hello'), Type.Literal('world')])]), Type.Null()) + Assert.IsEqual(R, ExtendsResult.False) }) it('Should extend Undefined (hello | world)', () => { type T = 'hello' | 'world' extends undefined ? 1 : 2 - const R = TypeExtends.Extends(Type.TemplateLiteral([Type.Union([Type.Literal('hello'), Type.Literal('world')])]), Type.Undefined()) - Assert.IsEqual(R, TypeExtendsResult.False) + const R = ExtendsCheck(Type.TemplateLiteral([Type.Union([Type.Literal('hello'), Type.Literal('world')])]), Type.Undefined()) + Assert.IsEqual(R, ExtendsResult.False) }) }) diff --git a/test/runtime/type/extends/tuple.ts b/test/runtime/type/extends/tuple.ts index b297655ab..8be058b21 100644 --- a/test/runtime/type/extends/tuple.ts +++ b/test/runtime/type/extends/tuple.ts @@ -1,161 +1,161 @@ -import { TypeExtends, TypeExtendsResult } from '@sinclair/typebox' +import { ExtendsCheck, ExtendsResult } from '@sinclair/typebox/type' import { Type } from '@sinclair/typebox' import { Assert } from '../../assert/index' describe('type/extends/Tuple', () => { it('Should extend Any', () => { type T = [string, number] extends any ? 1 : 2 - const R = TypeExtends.Extends(Type.Tuple([Type.String(), Type.Number()]), Type.Any()) - Assert.IsEqual(R, TypeExtendsResult.True) + const R = ExtendsCheck(Type.Tuple([Type.String(), Type.Number()]), Type.Any()) + Assert.IsEqual(R, ExtendsResult.True) }) it('Should extend String', () => { type T = [string, number] extends string ? 1 : 2 - const R = TypeExtends.Extends(Type.Tuple([Type.String(), Type.Number()]), Type.String()) - Assert.IsEqual(R, TypeExtendsResult.False) + const R = ExtendsCheck(Type.Tuple([Type.String(), Type.Number()]), Type.String()) + Assert.IsEqual(R, ExtendsResult.False) }) it('Should extend Boolean', () => { type T = [string, number] extends boolean ? 1 : 2 - const R = TypeExtends.Extends(Type.Tuple([Type.String(), Type.Number()]), Type.Boolean()) - Assert.IsEqual(R, TypeExtendsResult.False) + const R = ExtendsCheck(Type.Tuple([Type.String(), Type.Number()]), Type.Boolean()) + Assert.IsEqual(R, ExtendsResult.False) }) it('Should extend Number', () => { type T = [string, number] extends number ? 1 : 2 - const R = TypeExtends.Extends(Type.Tuple([Type.String(), Type.Number()]), Type.Number()) - Assert.IsEqual(R, TypeExtendsResult.False) + const R = ExtendsCheck(Type.Tuple([Type.String(), Type.Number()]), Type.Number()) + Assert.IsEqual(R, ExtendsResult.False) }) it('Should extend Integer', () => { type T = [string, number] extends number ? 1 : 2 - const R = TypeExtends.Extends(Type.Tuple([Type.String(), Type.Number()]), Type.Integer()) - Assert.IsEqual(R, TypeExtendsResult.False) + const R = ExtendsCheck(Type.Tuple([Type.String(), Type.Number()]), Type.Integer()) + Assert.IsEqual(R, ExtendsResult.False) }) it('Should extend Array 1', () => { type T = [string, number] extends Array ? 1 : 2 // 1 - const R = TypeExtends.Extends(Type.Tuple([Type.String(), Type.Number()]), Type.Array(Type.Any())) - Assert.IsEqual(R, TypeExtendsResult.True) + const R = ExtendsCheck(Type.Tuple([Type.String(), Type.Number()]), Type.Array(Type.Any())) + Assert.IsEqual(R, ExtendsResult.True) }) it('Should extend Array 2', () => { type T = [string, number] extends Array ? 1 : 2 // 2 - const R = TypeExtends.Extends(Type.Tuple([Type.String(), Type.Number()]), Type.Array(Type.String())) - Assert.IsEqual(R, TypeExtendsResult.False) + const R = ExtendsCheck(Type.Tuple([Type.String(), Type.Number()]), Type.Array(Type.String())) + Assert.IsEqual(R, ExtendsResult.False) }) it('Should extend Array 3', () => { type T = [string, number] extends Array ? 1 : 2 // 1 - const R = TypeExtends.Extends(Type.Tuple([Type.String(), Type.Number()]), Type.Array(Type.Union([Type.String(), Type.Number()]))) - Assert.IsEqual(R, TypeExtendsResult.True) + const R = ExtendsCheck(Type.Tuple([Type.String(), Type.Number()]), Type.Array(Type.Union([Type.String(), Type.Number()]))) + Assert.IsEqual(R, ExtendsResult.True) }) it('Should extend Array 4', () => { type T = [string, number] extends Array ? 1 : 2 // 1 - const R = TypeExtends.Extends(Type.Tuple([Type.String(), Type.Number()]), Type.Array(Type.Union([Type.String(), Type.Number(), Type.Boolean()]))) - Assert.IsEqual(R, TypeExtendsResult.True) + const R = ExtendsCheck(Type.Tuple([Type.String(), Type.Number()]), Type.Array(Type.Union([Type.String(), Type.Number(), Type.Boolean()]))) + Assert.IsEqual(R, ExtendsResult.True) }) it('Should extend Tuple 1', () => { type T = [string, number] extends [string, number] ? 1 : 2 - const R = TypeExtends.Extends(Type.Tuple([Type.String(), Type.Number()]), Type.Tuple([Type.String(), Type.Number()])) - Assert.IsEqual(R, TypeExtendsResult.True) + const R = ExtendsCheck(Type.Tuple([Type.String(), Type.Number()]), Type.Tuple([Type.String(), Type.Number()])) + Assert.IsEqual(R, ExtendsResult.True) }) it('Should extend Tuple 2', () => { type T = [string, number] extends [number, number] ? 1 : 2 - const R = TypeExtends.Extends(Type.Tuple([Type.String(), Type.Number()]), Type.Tuple([Type.Number(), Type.Number()])) - Assert.IsEqual(R, TypeExtendsResult.False) + const R = ExtendsCheck(Type.Tuple([Type.String(), Type.Number()]), Type.Tuple([Type.Number(), Type.Number()])) + Assert.IsEqual(R, ExtendsResult.False) }) it('Should extend Tuple 3', () => { type T = [string, any] extends [number, number] ? 1 : 2 - const R = TypeExtends.Extends(Type.Tuple([Type.String(), Type.Any()]), Type.Tuple([Type.Number(), Type.Number()])) - Assert.IsEqual(R, TypeExtendsResult.False) + const R = ExtendsCheck(Type.Tuple([Type.String(), Type.Any()]), Type.Tuple([Type.Number(), Type.Number()])) + Assert.IsEqual(R, ExtendsResult.False) }) it('Should extend Tuple 4', () => { type T = [string, number] extends [string, any] ? 1 : 2 - const R = TypeExtends.Extends(Type.Tuple([Type.String(), Type.Number()]), Type.Tuple([Type.String(), Type.Any()])) - Assert.IsEqual(R, TypeExtendsResult.True) + const R = ExtendsCheck(Type.Tuple([Type.String(), Type.Number()]), Type.Tuple([Type.String(), Type.Any()])) + Assert.IsEqual(R, ExtendsResult.True) }) it('Should extend Tuple 5', () => { type T = [string, unknown] extends [number, number] ? 1 : 2 - const R = TypeExtends.Extends(Type.Tuple([Type.String(), Type.Unknown()]), Type.Tuple([Type.Number(), Type.Number()])) - Assert.IsEqual(R, TypeExtendsResult.False) + const R = ExtendsCheck(Type.Tuple([Type.String(), Type.Unknown()]), Type.Tuple([Type.Number(), Type.Number()])) + Assert.IsEqual(R, ExtendsResult.False) }) it('Should extend Tuple 6', () => { type T = [string, number] extends [string, unknown] ? 1 : 2 - const R = TypeExtends.Extends(Type.Tuple([Type.String(), Type.Number()]), Type.Tuple([Type.String(), Type.Unknown()])) - Assert.IsEqual(R, TypeExtendsResult.True) + const R = ExtendsCheck(Type.Tuple([Type.String(), Type.Number()]), Type.Tuple([Type.String(), Type.Unknown()])) + Assert.IsEqual(R, ExtendsResult.True) }) it('Should extend Tuple 7', () => { type T = [] extends [string, number] ? 1 : 2 - const R = TypeExtends.Extends(Type.Tuple([]), Type.Tuple([Type.String(), Type.Number()])) - Assert.IsEqual(R, TypeExtendsResult.False) + const R = ExtendsCheck(Type.Tuple([]), Type.Tuple([Type.String(), Type.Number()])) + Assert.IsEqual(R, ExtendsResult.False) }) it('Should extend Tuple 8', () => { type T = [string, number] extends [] ? 1 : 2 - const R = TypeExtends.Extends(Type.Tuple([Type.String(), Type.Number()]), Type.Tuple([])) - Assert.IsEqual(R, TypeExtendsResult.False) + const R = ExtendsCheck(Type.Tuple([Type.String(), Type.Number()]), Type.Tuple([])) + Assert.IsEqual(R, ExtendsResult.False) }) it('Should extend Record 1', () => { type T = [string, number] extends Record ? 1 : 2 - const R = TypeExtends.Extends(Type.String(), Type.Record(Type.Number(), Type.Any())) - Assert.IsEqual(R, TypeExtendsResult.True) + const R = ExtendsCheck(Type.String(), Type.Record(Type.Number(), Type.Any())) + Assert.IsEqual(R, ExtendsResult.True) }) it('Should extend Record 2', () => { type T = [string, number] extends Record ? 1 : 2 - const R = TypeExtends.Extends(Type.String(), Type.Record(Type.Number(), Type.Unknown())) - Assert.IsEqual(R, TypeExtendsResult.True) + const R = ExtendsCheck(Type.String(), Type.Record(Type.Number(), Type.Unknown())) + Assert.IsEqual(R, ExtendsResult.True) }) it('Should extend Record 3', () => { type T = [string, number] extends Record ? 1 : 2 - const R = TypeExtends.Extends(Type.String(), Type.Record(Type.Number(), Type.String())) - Assert.IsEqual(R, TypeExtendsResult.True) + const R = ExtendsCheck(Type.String(), Type.Record(Type.Number(), Type.String())) + Assert.IsEqual(R, ExtendsResult.True) }) it('Should extend Record 4', () => { type T = [string, number] extends Record ? 1 : 2 - const R = TypeExtends.Extends(Type.String(), Type.Record(Type.Number(), Type.Number())) - Assert.IsEqual(R, TypeExtendsResult.False) + const R = ExtendsCheck(Type.String(), Type.Record(Type.Number(), Type.Number())) + Assert.IsEqual(R, ExtendsResult.False) }) it('Should extend Object 1', () => { type T = [string, number] extends {} ? 1 : 2 - const R = TypeExtends.Extends(Type.Tuple([Type.String(), Type.Number()]), Type.Object({}, { additionalProperties: false })) - Assert.IsEqual(R, TypeExtendsResult.True) + const R = ExtendsCheck(Type.Tuple([Type.String(), Type.Number()]), Type.Object({}, { additionalProperties: false })) + Assert.IsEqual(R, ExtendsResult.True) }) it('Should extend Object 2', () => { type T = [string, number] extends { a: 10 } ? 1 : 2 - const R = TypeExtends.Extends(Type.Tuple([Type.String(), Type.Number()]), Type.Object({ a: Type.Literal(10) }, { additionalProperties: true })) - Assert.IsEqual(R, TypeExtendsResult.False) + const R = ExtendsCheck(Type.Tuple([Type.String(), Type.Number()]), Type.Object({ a: Type.Literal(10) }, { additionalProperties: true })) + Assert.IsEqual(R, ExtendsResult.False) }) it('Should extend Object 3', () => { type T = [string, number] extends object ? 1 : 2 - const R = TypeExtends.Extends(Type.Tuple([Type.String(), Type.Number()]), Type.Object({})) - Assert.IsEqual(R, TypeExtendsResult.True) + const R = ExtendsCheck(Type.Tuple([Type.String(), Type.Number()]), Type.Object({})) + Assert.IsEqual(R, ExtendsResult.True) }) it('Should extend Union 1', () => { type T = [string, number] extends number | string ? 1 : 2 - const R = TypeExtends.Extends(Type.Tuple([Type.String(), Type.Number()]), Type.Union([Type.Number(), Type.String()])) - Assert.IsEqual(R, TypeExtendsResult.False) + const R = ExtendsCheck(Type.Tuple([Type.String(), Type.Number()]), Type.Union([Type.Number(), Type.String()])) + Assert.IsEqual(R, ExtendsResult.False) }) it('Should extend Union 2', () => { type T = [string, number] extends any | number ? 1 : 2 - const R = TypeExtends.Extends(Type.Tuple([Type.String(), Type.Number()]), Type.Union([Type.Any(), Type.Number()])) - Assert.IsEqual(R, TypeExtendsResult.True) + const R = ExtendsCheck(Type.Tuple([Type.String(), Type.Number()]), Type.Union([Type.Any(), Type.Number()])) + Assert.IsEqual(R, ExtendsResult.True) }) it('Should extend Union 2', () => { type T = [string, number] extends boolean | number ? 1 : 2 - const R = TypeExtends.Extends(Type.Tuple([Type.String(), Type.Number()]), Type.Union([Type.Boolean(), Type.Number()])) - Assert.IsEqual(R, TypeExtendsResult.False) + const R = ExtendsCheck(Type.Tuple([Type.String(), Type.Number()]), Type.Union([Type.Boolean(), Type.Number()])) + Assert.IsEqual(R, ExtendsResult.False) }) it('Should extend Null', () => { type T = [string, number] extends null ? 1 : 2 - const R = TypeExtends.Extends(Type.Tuple([Type.String(), Type.Number()]), Type.Null()) - Assert.IsEqual(R, TypeExtendsResult.False) + const R = ExtendsCheck(Type.Tuple([Type.String(), Type.Number()]), Type.Null()) + Assert.IsEqual(R, ExtendsResult.False) }) it('Should extend Undefined', () => { type T = [string, number] extends undefined ? 1 : 2 - const R = TypeExtends.Extends(Type.Tuple([Type.String(), Type.Number()]), Type.Undefined()) - Assert.IsEqual(R, TypeExtendsResult.False) + const R = ExtendsCheck(Type.Tuple([Type.String(), Type.Number()]), Type.Undefined()) + Assert.IsEqual(R, ExtendsResult.False) }) it('Should extend Void', () => { type T = [string, number] extends void ? 1 : 2 - const R = TypeExtends.Extends(Type.Tuple([Type.String(), Type.Number()]), Type.Void()) - Assert.IsEqual(R, TypeExtendsResult.False) + const R = ExtendsCheck(Type.Tuple([Type.String(), Type.Number()]), Type.Void()) + Assert.IsEqual(R, ExtendsResult.False) }) it('Should extend Date', () => { type T = [string, number] extends Date ? 1 : 2 - const R = TypeExtends.Extends(Type.Tuple([Type.String(), Type.Number()]), Type.Date()) - Assert.IsEqual(R, TypeExtendsResult.False) + const R = ExtendsCheck(Type.Tuple([Type.String(), Type.Number()]), Type.Date()) + Assert.IsEqual(R, ExtendsResult.False) }) }) diff --git a/test/runtime/type/extends/uint8array.ts b/test/runtime/type/extends/uint8array.ts index 828163dd1..f5952e10d 100644 --- a/test/runtime/type/extends/uint8array.ts +++ b/test/runtime/type/extends/uint8array.ts @@ -1,96 +1,96 @@ -import { TypeExtends, TypeExtendsResult } from '@sinclair/typebox' +import { ExtendsCheck, ExtendsResult } from '@sinclair/typebox/type' import { Type } from '@sinclair/typebox' import { Assert } from '../../assert/index' describe('type/extends/Uint8Array', () => { it('Should extend Any', () => { type T = Uint8Array extends any ? 1 : 2 - const R = TypeExtends.Extends(Type.Uint8Array(), Type.Any()) - Assert.IsEqual(R, TypeExtendsResult.True) + const R = ExtendsCheck(Type.Uint8Array(), Type.Any()) + Assert.IsEqual(R, ExtendsResult.True) }) it('Should extend Unknown', () => { type T = Uint8Array extends unknown ? 1 : 2 - const R = TypeExtends.Extends(Type.Uint8Array(), Type.Unknown()) - Assert.IsEqual(R, TypeExtendsResult.True) + const R = ExtendsCheck(Type.Uint8Array(), Type.Unknown()) + Assert.IsEqual(R, ExtendsResult.True) }) it('Should extend String', () => { type T = Uint8Array extends string ? 1 : 2 - const R = TypeExtends.Extends(Type.Uint8Array(), Type.String()) - Assert.IsEqual(R, TypeExtendsResult.False) + const R = ExtendsCheck(Type.Uint8Array(), Type.String()) + Assert.IsEqual(R, ExtendsResult.False) }) it('Should extend Boolean', () => { type T = Uint8Array extends boolean ? 1 : 2 - const R = TypeExtends.Extends(Type.Uint8Array(), Type.Boolean()) - Assert.IsEqual(R, TypeExtendsResult.False) + const R = ExtendsCheck(Type.Uint8Array(), Type.Boolean()) + Assert.IsEqual(R, ExtendsResult.False) }) it('Should extend Number', () => { type T = Uint8Array extends number ? 1 : 2 - const R = TypeExtends.Extends(Type.Uint8Array(), Type.Number()) - Assert.IsEqual(R, TypeExtendsResult.False) + const R = ExtendsCheck(Type.Uint8Array(), Type.Number()) + Assert.IsEqual(R, ExtendsResult.False) }) it('Should extend Integer', () => { type T = Uint8Array extends number ? 1 : 2 - const R = TypeExtends.Extends(Type.Uint8Array(), Type.Integer()) - Assert.IsEqual(R, TypeExtendsResult.False) + const R = ExtendsCheck(Type.Uint8Array(), Type.Integer()) + Assert.IsEqual(R, ExtendsResult.False) }) it('Should extend Array', () => { type T = Uint8Array extends Array ? 1 : 2 - const R = TypeExtends.Extends(Type.Uint8Array(), Type.Array(Type.Any())) - Assert.IsEqual(R, TypeExtendsResult.False) + const R = ExtendsCheck(Type.Uint8Array(), Type.Array(Type.Any())) + Assert.IsEqual(R, ExtendsResult.False) }) it('Should extend Tuple', () => { type T = Uint8Array extends [number, number] ? 1 : 2 - const R = TypeExtends.Extends(Type.Uint8Array(), Type.Tuple([Type.Number(), Type.Number()])) - Assert.IsEqual(R, TypeExtendsResult.False) + const R = ExtendsCheck(Type.Uint8Array(), Type.Tuple([Type.Number(), Type.Number()])) + Assert.IsEqual(R, ExtendsResult.False) }) it('Should extend Record', () => { type T = Uint8Array extends Record ? 1 : 2 - const R = TypeExtends.Extends(Type.Uint8Array(), Type.Record(Type.Number(), Type.Any())) - Assert.IsEqual(R, TypeExtendsResult.True) + const R = ExtendsCheck(Type.Uint8Array(), Type.Record(Type.Number(), Type.Any())) + Assert.IsEqual(R, ExtendsResult.True) }) it('Should extend Object 1', () => { type T = Uint8Array extends {} ? 1 : 2 - const R = TypeExtends.Extends(Type.Uint8Array(), Type.Object({}, { additionalProperties: false })) - Assert.IsEqual(R, TypeExtendsResult.True) + const R = ExtendsCheck(Type.Uint8Array(), Type.Object({}, { additionalProperties: false })) + Assert.IsEqual(R, ExtendsResult.True) }) it('Should extend Object 2', () => { type T = Uint8Array extends { a: 10 } ? 1 : 2 - const R = TypeExtends.Extends(Type.Uint8Array(), Type.Object({ a: Type.Literal(10) }, { additionalProperties: true })) - Assert.IsEqual(R, TypeExtendsResult.False) + const R = ExtendsCheck(Type.Uint8Array(), Type.Object({ a: Type.Literal(10) }, { additionalProperties: true })) + Assert.IsEqual(R, ExtendsResult.False) }) it('Should extend Union 1', () => { type T = Uint8Array extends number | string ? 1 : 2 - const R = TypeExtends.Extends(Type.Uint8Array(), Type.Union([Type.Number(), Type.String()])) - Assert.IsEqual(R, TypeExtendsResult.False) + const R = ExtendsCheck(Type.Uint8Array(), Type.Union([Type.Number(), Type.String()])) + Assert.IsEqual(R, ExtendsResult.False) }) it('Should extend Union 2', () => { type T = Uint8Array extends any | number ? 1 : 2 - const R = TypeExtends.Extends(Type.Uint8Array(), Type.Union([Type.Any(), Type.Number()])) - Assert.IsEqual(R, TypeExtendsResult.True) + const R = ExtendsCheck(Type.Uint8Array(), Type.Union([Type.Any(), Type.Number()])) + Assert.IsEqual(R, ExtendsResult.True) }) it('Should extend Union 3', () => { type T = Uint8Array extends boolean | number ? 1 : 2 - const R = TypeExtends.Extends(Type.Uint8Array(), Type.Union([Type.Boolean(), Type.Number()])) - Assert.IsEqual(R, TypeExtendsResult.False) + const R = ExtendsCheck(Type.Uint8Array(), Type.Union([Type.Boolean(), Type.Number()])) + Assert.IsEqual(R, ExtendsResult.False) }) it('Should extend Null', () => { type T = Uint8Array extends null ? 1 : 2 - const R = TypeExtends.Extends(Type.Uint8Array(), Type.Null()) - Assert.IsEqual(R, TypeExtendsResult.False) + const R = ExtendsCheck(Type.Uint8Array(), Type.Null()) + Assert.IsEqual(R, ExtendsResult.False) }) it('Should extend Undefined', () => { type T = Uint8Array extends undefined ? 1 : 2 - const R = TypeExtends.Extends(Type.Uint8Array(), Type.Undefined()) - Assert.IsEqual(R, TypeExtendsResult.False) + const R = ExtendsCheck(Type.Uint8Array(), Type.Undefined()) + Assert.IsEqual(R, ExtendsResult.False) }) it('Should extend Void', () => { type T = Uint8Array extends void ? 1 : 2 - const R = TypeExtends.Extends(Type.Uint8Array(), Type.Void()) - Assert.IsEqual(R, TypeExtendsResult.False) + const R = ExtendsCheck(Type.Uint8Array(), Type.Void()) + Assert.IsEqual(R, ExtendsResult.False) }) it('Should extend Date', () => { type T = Uint8Array extends Date ? 1 : 2 - const R = TypeExtends.Extends(Type.Uint8Array(), Type.Date()) - Assert.IsEqual(R, TypeExtendsResult.False) + const R = ExtendsCheck(Type.Uint8Array(), Type.Date()) + Assert.IsEqual(R, ExtendsResult.False) }) }) diff --git a/test/runtime/type/extends/undefined.ts b/test/runtime/type/extends/undefined.ts index 664126124..5a9e84b27 100644 --- a/test/runtime/type/extends/undefined.ts +++ b/test/runtime/type/extends/undefined.ts @@ -1,91 +1,91 @@ -import { TypeExtends, TypeExtendsResult } from '@sinclair/typebox' +import { ExtendsCheck, ExtendsResult } from '@sinclair/typebox/type' import { Type } from '@sinclair/typebox' import { Assert } from '../../assert/index' describe('type/extends/Undefined', () => { it('Should extend Any', () => { type T = undefined extends any ? 1 : 2 - const R = TypeExtends.Extends(Type.Undefined(), Type.Any()) - Assert.IsEqual(R, TypeExtendsResult.True) + const R = ExtendsCheck(Type.Undefined(), Type.Any()) + Assert.IsEqual(R, ExtendsResult.True) }) it('Should extend String', () => { type T = undefined extends string ? 1 : 2 - const R = TypeExtends.Extends(Type.Undefined(), Type.String()) - Assert.IsEqual(R, TypeExtendsResult.False) + const R = ExtendsCheck(Type.Undefined(), Type.String()) + Assert.IsEqual(R, ExtendsResult.False) }) it('Should extend Boolean', () => { type T = undefined extends boolean ? 1 : 2 - const R = TypeExtends.Extends(Type.Undefined(), Type.Boolean()) - Assert.IsEqual(R, TypeExtendsResult.False) + const R = ExtendsCheck(Type.Undefined(), Type.Boolean()) + Assert.IsEqual(R, ExtendsResult.False) }) it('Should extend Number', () => { type T = undefined extends number ? 1 : 2 - const R = TypeExtends.Extends(Type.Undefined(), Type.Number()) - Assert.IsEqual(R, TypeExtendsResult.False) + const R = ExtendsCheck(Type.Undefined(), Type.Number()) + Assert.IsEqual(R, ExtendsResult.False) }) it('Should extend Integer', () => { type T = undefined extends number ? 1 : 2 - const R = TypeExtends.Extends(Type.Undefined(), Type.Integer()) - Assert.IsEqual(R, TypeExtendsResult.False) + const R = ExtendsCheck(Type.Undefined(), Type.Integer()) + Assert.IsEqual(R, ExtendsResult.False) }) it('Should extend Array', () => { type T = undefined extends Array ? 1 : 2 - const R = TypeExtends.Extends(Type.Undefined(), Type.Array(Type.Any())) - Assert.IsEqual(R, TypeExtendsResult.False) + const R = ExtendsCheck(Type.Undefined(), Type.Array(Type.Any())) + Assert.IsEqual(R, ExtendsResult.False) }) it('Should extend Tuple', () => { type T = undefined extends [number, number] ? 1 : 2 - const R = TypeExtends.Extends(Type.Undefined(), Type.Tuple([Type.Number(), Type.Number()])) - Assert.IsEqual(R, TypeExtendsResult.False) + const R = ExtendsCheck(Type.Undefined(), Type.Tuple([Type.Number(), Type.Number()])) + Assert.IsEqual(R, ExtendsResult.False) }) it('Should extend Object 1', () => { type T = undefined extends {} ? 1 : 2 - const R = TypeExtends.Extends(Type.Undefined(), Type.Object({}, { additionalProperties: false })) - Assert.IsEqual(R, TypeExtendsResult.False) + const R = ExtendsCheck(Type.Undefined(), Type.Object({}, { additionalProperties: false })) + Assert.IsEqual(R, ExtendsResult.False) }) it('Should extend Object 2', () => { type T = undefined extends { a: 10 } ? 1 : 2 - const R = TypeExtends.Extends(Type.Undefined(), Type.Object({ a: Type.Literal(10) }, { additionalProperties: true })) - Assert.IsEqual(R, TypeExtendsResult.False) + const R = ExtendsCheck(Type.Undefined(), Type.Object({ a: Type.Literal(10) }, { additionalProperties: true })) + Assert.IsEqual(R, ExtendsResult.False) }) it('Should extend Object 3', () => { type T = undefined extends object ? 1 : 2 - const R = TypeExtends.Extends(Type.Undefined(), Type.Object({})) - Assert.IsEqual(R, TypeExtendsResult.False) + const R = ExtendsCheck(Type.Undefined(), Type.Object({})) + Assert.IsEqual(R, ExtendsResult.False) }) it('Should extend Union 1', () => { type T = undefined extends number | string ? 1 : 2 - const R = TypeExtends.Extends(Type.Undefined(), Type.Union([Type.Number(), Type.String()])) - Assert.IsEqual(R, TypeExtendsResult.False) + const R = ExtendsCheck(Type.Undefined(), Type.Union([Type.Number(), Type.String()])) + Assert.IsEqual(R, ExtendsResult.False) }) it('Should extend Union 2', () => { type T = undefined extends any | number ? 1 : 2 - const R = TypeExtends.Extends(Type.Undefined(), Type.Union([Type.Any(), Type.Number()])) - Assert.IsEqual(R, TypeExtendsResult.True) + const R = ExtendsCheck(Type.Undefined(), Type.Union([Type.Any(), Type.Number()])) + Assert.IsEqual(R, ExtendsResult.True) }) it('Should extend Union 2', () => { type T = undefined extends boolean | number ? 1 : 2 - const R = TypeExtends.Extends(Type.Undefined(), Type.Union([Type.Boolean(), Type.Number()])) - Assert.IsEqual(R, TypeExtendsResult.False) + const R = ExtendsCheck(Type.Undefined(), Type.Union([Type.Boolean(), Type.Number()])) + Assert.IsEqual(R, ExtendsResult.False) }) it('Should extend Null', () => { type T = undefined extends null ? 1 : 2 - const R = TypeExtends.Extends(Type.Undefined(), Type.Null()) - Assert.IsEqual(R, TypeExtendsResult.False) + const R = ExtendsCheck(Type.Undefined(), Type.Null()) + Assert.IsEqual(R, ExtendsResult.False) }) it('Should extend Undefined', () => { type T = undefined extends undefined ? 1 : 2 - const R = TypeExtends.Extends(Type.Undefined(), Type.Undefined()) - Assert.IsEqual(R, TypeExtendsResult.True) + const R = ExtendsCheck(Type.Undefined(), Type.Undefined()) + Assert.IsEqual(R, ExtendsResult.True) }) it('Should extend Void', () => { type T = undefined extends void ? 1 : 2 - const R = TypeExtends.Extends(Type.Undefined(), Type.Void()) - Assert.IsEqual(R, TypeExtendsResult.True) + const R = ExtendsCheck(Type.Undefined(), Type.Void()) + Assert.IsEqual(R, ExtendsResult.True) }) it('Should extend Date', () => { type T = undefined extends Date ? 1 : 2 - const R = TypeExtends.Extends(Type.Undefined(), Type.Date()) - Assert.IsEqual(R, TypeExtendsResult.False) + const R = ExtendsCheck(Type.Undefined(), Type.Date()) + Assert.IsEqual(R, ExtendsResult.False) }) }) diff --git a/test/runtime/type/extends/union.ts b/test/runtime/type/extends/union.ts index e9eb05cef..006e946b8 100644 --- a/test/runtime/type/extends/union.ts +++ b/test/runtime/type/extends/union.ts @@ -1,136 +1,136 @@ -import { TypeExtends, TypeExtendsResult } from '@sinclair/typebox' +import { ExtendsCheck, ExtendsResult } from '@sinclair/typebox/type' import { Type } from '@sinclair/typebox' import { Assert } from '../../assert/index' describe('type/extends/Union', () => { it('Should extend Any', () => { type T = number | string extends any ? 1 : 2 - const R = TypeExtends.Extends(Type.Union([Type.Number(), Type.String()]), Type.Any()) - Assert.IsEqual(R, TypeExtendsResult.True) + const R = ExtendsCheck(Type.Union([Type.Number(), Type.String()]), Type.Any()) + Assert.IsEqual(R, ExtendsResult.True) }) it('Should extend String', () => { type T = number | string extends string ? 1 : 2 - const R = TypeExtends.Extends(Type.Union([Type.Number(), Type.String()]), Type.String()) - Assert.IsEqual(R, TypeExtendsResult.False) + const R = ExtendsCheck(Type.Union([Type.Number(), Type.String()]), Type.String()) + Assert.IsEqual(R, ExtendsResult.False) }) it('Should extend Boolean', () => { type T = number | string extends boolean ? 1 : 2 - const R = TypeExtends.Extends(Type.Union([Type.Number(), Type.String()]), Type.Boolean()) - Assert.IsEqual(R, TypeExtendsResult.False) + const R = ExtendsCheck(Type.Union([Type.Number(), Type.String()]), Type.Boolean()) + Assert.IsEqual(R, ExtendsResult.False) }) it('Should extend Number', () => { type T = number | string extends number ? 1 : 2 - const R = TypeExtends.Extends(Type.Union([Type.Number(), Type.String()]), Type.Number()) - Assert.IsEqual(R, TypeExtendsResult.False) + const R = ExtendsCheck(Type.Union([Type.Number(), Type.String()]), Type.Number()) + Assert.IsEqual(R, ExtendsResult.False) }) it('Should extend Integer', () => { type T = number | string extends number ? 1 : 2 - const R = TypeExtends.Extends(Type.Union([Type.Number(), Type.String()]), Type.Integer()) - Assert.IsEqual(R, TypeExtendsResult.False) + const R = ExtendsCheck(Type.Union([Type.Number(), Type.String()]), Type.Integer()) + Assert.IsEqual(R, ExtendsResult.False) }) it('Should extend Array', () => { type T = number | string extends Array ? 1 : 2 - const R = TypeExtends.Extends(Type.Union([Type.Number(), Type.String()]), Type.Array(Type.Any())) - Assert.IsEqual(R, TypeExtendsResult.False) + const R = ExtendsCheck(Type.Union([Type.Number(), Type.String()]), Type.Array(Type.Any())) + Assert.IsEqual(R, ExtendsResult.False) }) it('Should extend Tuple', () => { type T = number | string extends [number, number] ? 1 : 2 - const R = TypeExtends.Extends(Type.Union([Type.Number(), Type.String()]), Type.Tuple([Type.Number(), Type.Number()])) - Assert.IsEqual(R, TypeExtendsResult.False) + const R = ExtendsCheck(Type.Union([Type.Number(), Type.String()]), Type.Tuple([Type.Number(), Type.Number()])) + Assert.IsEqual(R, ExtendsResult.False) }) it('Should extend Object 1', () => { type T = number | string extends {} ? 1 : 2 - const R = TypeExtends.Extends(Type.Union([Type.Number(), Type.String()]), Type.Object({}, { additionalProperties: false })) - Assert.IsEqual(R, TypeExtendsResult.True) + const R = ExtendsCheck(Type.Union([Type.Number(), Type.String()]), Type.Object({}, { additionalProperties: false })) + Assert.IsEqual(R, ExtendsResult.True) }) it('Should extend Object 2', () => { type T = number | string extends { a: 10 } ? 1 : 2 - const R = TypeExtends.Extends(Type.Union([Type.Number(), Type.String()]), Type.Object({ a: Type.Literal(10) }, { additionalProperties: true })) - Assert.IsEqual(R, TypeExtendsResult.False) + const R = ExtendsCheck(Type.Union([Type.Number(), Type.String()]), Type.Object({ a: Type.Literal(10) }, { additionalProperties: true })) + Assert.IsEqual(R, ExtendsResult.False) }) it('Should extend Union 1', () => { type T = number | string extends number | string ? 1 : 2 - const R = TypeExtends.Extends(Type.Union([Type.Number(), Type.String()]), Type.Union([Type.Number(), Type.String()])) - Assert.IsEqual(R, TypeExtendsResult.True) + const R = ExtendsCheck(Type.Union([Type.Number(), Type.String()]), Type.Union([Type.Number(), Type.String()])) + Assert.IsEqual(R, ExtendsResult.True) }) it('Should extend Union 2', () => { type T = number | string extends any | number ? 1 : 2 - const R = TypeExtends.Extends(Type.Union([Type.Number(), Type.String()]), Type.Union([Type.Any(), Type.Number()])) - Assert.IsEqual(R, TypeExtendsResult.True) + const R = ExtendsCheck(Type.Union([Type.Number(), Type.String()]), Type.Union([Type.Any(), Type.Number()])) + Assert.IsEqual(R, ExtendsResult.True) }) it('Should extend Union 3', () => { type T = number | string extends boolean | number ? 1 : 2 - const R = TypeExtends.Extends(Type.Union([Type.Number(), Type.String()]), Type.Union([Type.Boolean(), Type.Number()])) - Assert.IsEqual(R, TypeExtendsResult.False) + const R = ExtendsCheck(Type.Union([Type.Number(), Type.String()]), Type.Union([Type.Boolean(), Type.Number()])) + Assert.IsEqual(R, ExtendsResult.False) }) it('Should extend Union 4', () => { type T = any | boolean extends boolean | number ? 1 : 2 - const R = TypeExtends.Extends(Type.Any(), Type.Union([Type.Boolean(), Type.Number()])) - Assert.IsEqual(R, TypeExtendsResult.Union) + const R = ExtendsCheck(Type.Any(), Type.Union([Type.Boolean(), Type.Number()])) + Assert.IsEqual(R, ExtendsResult.Union) }) it('Should extend Union 5', () => { type T = any | string extends boolean | number ? 1 : 2 - const R = TypeExtends.Extends(Type.Any(), Type.Union([Type.Boolean(), Type.Number()])) - Assert.IsEqual(R, TypeExtendsResult.Union) + const R = ExtendsCheck(Type.Any(), Type.Union([Type.Boolean(), Type.Number()])) + Assert.IsEqual(R, ExtendsResult.Union) }) it('Should extend Union 6', () => { type T = any | {} extends {} ? 1 : 2 - const R = TypeExtends.Extends(Type.Any(), Type.Union([Type.Boolean(), Type.Number()])) - Assert.IsEqual(R, TypeExtendsResult.Union) + const R = ExtendsCheck(Type.Any(), Type.Union([Type.Boolean(), Type.Number()])) + Assert.IsEqual(R, ExtendsResult.Union) }) it('Should extend Union 7', () => { type T = any extends boolean | number ? 1 : 2 - const R = TypeExtends.Extends(Type.Any(), Type.Union([Type.Boolean(), Type.Number()])) - Assert.IsEqual(R, TypeExtendsResult.Union) + const R = ExtendsCheck(Type.Any(), Type.Union([Type.Boolean(), Type.Number()])) + Assert.IsEqual(R, ExtendsResult.Union) }) it('Should extend Union 8', () => { type T = unknown | string extends boolean | number ? 1 : 2 - const R = TypeExtends.Extends(Type.Union([Type.Unknown(), Type.String()]), Type.Union([Type.Boolean(), Type.Number()])) - Assert.IsEqual(R, TypeExtendsResult.False) + const R = ExtendsCheck(Type.Union([Type.Unknown(), Type.String()]), Type.Union([Type.Boolean(), Type.Number()])) + Assert.IsEqual(R, ExtendsResult.False) }) it('Should extend Union 9', () => { type T = unknown extends boolean | number ? 1 : 2 - const R = TypeExtends.Extends(Type.Unknown(), Type.Union([Type.Boolean(), Type.Number()])) - Assert.IsEqual(R, TypeExtendsResult.False) + const R = ExtendsCheck(Type.Unknown(), Type.Union([Type.Boolean(), Type.Number()])) + Assert.IsEqual(R, ExtendsResult.False) }) it('Should extend Null', () => { type T = number | string extends null ? 1 : 2 - const R = TypeExtends.Extends(Type.Union([Type.Number(), Type.String()]), Type.Null()) - Assert.IsEqual(R, TypeExtendsResult.False) + const R = ExtendsCheck(Type.Union([Type.Number(), Type.String()]), Type.Null()) + Assert.IsEqual(R, ExtendsResult.False) }) it('Should extend Undefined', () => { type T = number | string extends undefined ? 1 : 2 - const R = TypeExtends.Extends(Type.Union([Type.Number(), Type.String()]), Type.Undefined()) - Assert.IsEqual(R, TypeExtendsResult.False) + const R = ExtendsCheck(Type.Union([Type.Number(), Type.String()]), Type.Undefined()) + Assert.IsEqual(R, ExtendsResult.False) }) it('Should extend Void', () => { type T = number | string extends void ? 1 : 2 - const R = TypeExtends.Extends(Type.Union([Type.Number(), Type.String()]), Type.Void()) - Assert.IsEqual(R, TypeExtendsResult.False) + const R = ExtendsCheck(Type.Union([Type.Number(), Type.String()]), Type.Void()) + Assert.IsEqual(R, ExtendsResult.False) }) it('Should extend Void 2', () => { type T = number | string | void extends void ? 1 : 2 - const R = TypeExtends.Extends(Type.Union([Type.Number(), Type.String()]), Type.Void()) - Assert.IsEqual(R, TypeExtendsResult.False) + const R = ExtendsCheck(Type.Union([Type.Number(), Type.String()]), Type.Void()) + Assert.IsEqual(R, ExtendsResult.False) }) it('Should extend Date', () => { type T = number | string | void extends Date ? 1 : 2 - const R = TypeExtends.Extends(Type.Union([Type.Number(), Type.String()]), Type.Date()) - Assert.IsEqual(R, TypeExtendsResult.False) + const R = ExtendsCheck(Type.Union([Type.Number(), Type.String()]), Type.Date()) + Assert.IsEqual(R, ExtendsResult.False) }) it('Should extend Date 2', () => { type T = Date | number | string | void extends Date ? 1 : 2 - const R = TypeExtends.Extends(Type.Union([Type.Date(), Type.Number(), Type.String()]), Type.Date()) - Assert.IsEqual(R, TypeExtendsResult.False) + const R = ExtendsCheck(Type.Union([Type.Date(), Type.Number(), Type.String()]), Type.Date()) + Assert.IsEqual(R, ExtendsResult.False) }) it('Should extend BigInt', () => { type T = bigint | number | string | void extends Date ? 1 : 2 - const R = TypeExtends.Extends(Type.Union([Type.BigInt(), Type.Number(), Type.String()]), Type.Date()) - Assert.IsEqual(R, TypeExtendsResult.False) + const R = ExtendsCheck(Type.Union([Type.BigInt(), Type.Number(), Type.String()]), Type.Date()) + Assert.IsEqual(R, ExtendsResult.False) }) it('Should extend Symbol', () => { type T = symbol | number | string | void extends Date ? 1 : 2 - const R = TypeExtends.Extends(Type.Union([Type.Symbol(), Type.Number(), Type.String()]), Type.Date()) - Assert.IsEqual(R, TypeExtendsResult.False) + const R = ExtendsCheck(Type.Union([Type.Symbol(), Type.Number(), Type.String()]), Type.Date()) + Assert.IsEqual(R, ExtendsResult.False) }) }) diff --git a/test/runtime/type/extends/unknown.ts b/test/runtime/type/extends/unknown.ts index 85dbf8654..c875a12e2 100644 --- a/test/runtime/type/extends/unknown.ts +++ b/test/runtime/type/extends/unknown.ts @@ -1,101 +1,101 @@ -import { TypeExtends, TypeExtendsResult } from '@sinclair/typebox' +import { ExtendsCheck, ExtendsResult } from '@sinclair/typebox/type' import { Type } from '@sinclair/typebox' import { Assert } from '../../assert/index' describe('type/extends/Unknown', () => { it('Should extend Any', () => { type T = unknown extends any ? 1 : 2 - const R = TypeExtends.Extends(Type.Unknown(), Type.Any()) - Assert.IsEqual(R, TypeExtendsResult.True) + const R = ExtendsCheck(Type.Unknown(), Type.Any()) + Assert.IsEqual(R, ExtendsResult.True) }) it('Should extend Unknown', () => { type T = unknown extends unknown ? 1 : 2 - const R = TypeExtends.Extends(Type.Unknown(), Type.Unknown()) - Assert.IsEqual(R, TypeExtendsResult.True) + const R = ExtendsCheck(Type.Unknown(), Type.Unknown()) + Assert.IsEqual(R, ExtendsResult.True) }) it('Should extend String', () => { type T = unknown extends string ? 1 : 2 - const R = TypeExtends.Extends(Type.Unknown(), Type.String()) - Assert.IsEqual(R, TypeExtendsResult.False) + const R = ExtendsCheck(Type.Unknown(), Type.String()) + Assert.IsEqual(R, ExtendsResult.False) }) it('Should extend Boolean', () => { type T = unknown extends boolean ? 1 : 2 - const R = TypeExtends.Extends(Type.Unknown(), Type.Boolean()) - Assert.IsEqual(R, TypeExtendsResult.False) + const R = ExtendsCheck(Type.Unknown(), Type.Boolean()) + Assert.IsEqual(R, ExtendsResult.False) }) it('Should extend Number', () => { type T = unknown extends number ? 1 : 2 - const R = TypeExtends.Extends(Type.Unknown(), Type.Number()) - Assert.IsEqual(R, TypeExtendsResult.False) + const R = ExtendsCheck(Type.Unknown(), Type.Number()) + Assert.IsEqual(R, ExtendsResult.False) }) it('Should extend Integer', () => { type T = unknown extends number ? 1 : 2 - const R = TypeExtends.Extends(Type.Unknown(), Type.Integer()) - Assert.IsEqual(R, TypeExtendsResult.False) + const R = ExtendsCheck(Type.Unknown(), Type.Integer()) + Assert.IsEqual(R, ExtendsResult.False) }) it('Should extend Array 1', () => { type T = unknown extends Array ? 1 : 2 - const R = TypeExtends.Extends(Type.Unknown(), Type.Array(Type.Any())) - Assert.IsEqual(R, TypeExtendsResult.False) + const R = ExtendsCheck(Type.Unknown(), Type.Array(Type.Any())) + Assert.IsEqual(R, ExtendsResult.False) }) it('Should extend Array 2', () => { type T = unknown extends Array ? 1 : 2 - const R = TypeExtends.Extends(Type.Unknown(), Type.Array(Type.String())) - Assert.IsEqual(R, TypeExtendsResult.False) + const R = ExtendsCheck(Type.Unknown(), Type.Array(Type.String())) + Assert.IsEqual(R, ExtendsResult.False) }) it('Should extend Tuple', () => { type T = unknown extends [number, number] ? 1 : 2 - const R = TypeExtends.Extends(Type.Unknown(), Type.Tuple([Type.Number(), Type.Number()])) - Assert.IsEqual(R, TypeExtendsResult.False) + const R = ExtendsCheck(Type.Unknown(), Type.Tuple([Type.Number(), Type.Number()])) + Assert.IsEqual(R, ExtendsResult.False) }) it('Should extend Object 1', () => { type T = unknown extends {} ? 1 : 2 - const R = TypeExtends.Extends(Type.Unknown(), Type.Object({})) - Assert.IsEqual(R, TypeExtendsResult.False) + const R = ExtendsCheck(Type.Unknown(), Type.Object({})) + Assert.IsEqual(R, ExtendsResult.False) }) it('Should extend Object 2', () => { type T = unknown extends { a: number } ? 1 : 2 - const R = TypeExtends.Extends(Type.Unknown(), Type.Object({ a: Type.Number() })) - Assert.IsEqual(R, TypeExtendsResult.False) + const R = ExtendsCheck(Type.Unknown(), Type.Object({ a: Type.Number() })) + Assert.IsEqual(R, ExtendsResult.False) }) it('Should extend Union 1', () => { type T = unknown extends number | string ? 1 : 2 - const R = TypeExtends.Extends(Type.Unknown(), Type.Union([Type.Number(), Type.String()])) - Assert.IsEqual(R, TypeExtendsResult.False) + const R = ExtendsCheck(Type.Unknown(), Type.Union([Type.Number(), Type.String()])) + Assert.IsEqual(R, ExtendsResult.False) }) it('Should extend Union 2', () => { type T = unknown extends any | number ? 1 : 2 // 1 - const R = TypeExtends.Extends(Type.Unknown(), Type.Union([Type.Any(), Type.String()])) - Assert.IsEqual(R, TypeExtendsResult.True) + const R = ExtendsCheck(Type.Unknown(), Type.Union([Type.Any(), Type.String()])) + Assert.IsEqual(R, ExtendsResult.True) }) it('Should extend Union 3', () => { type T = unknown extends unknown | number ? 1 : 2 // 1 - const R = TypeExtends.Extends(Type.Unknown(), Type.Union([Type.Unknown(), Type.String()])) - Assert.IsEqual(R, TypeExtendsResult.True) + const R = ExtendsCheck(Type.Unknown(), Type.Union([Type.Unknown(), Type.String()])) + Assert.IsEqual(R, ExtendsResult.True) }) it('Should extend Union 4', () => { type T = unknown extends unknown | any ? 1 : 2 // 1 - const R = TypeExtends.Extends(Type.Unknown(), Type.Union([Type.Unknown(), Type.String()])) - Assert.IsEqual(R, TypeExtendsResult.True) + const R = ExtendsCheck(Type.Unknown(), Type.Union([Type.Unknown(), Type.String()])) + Assert.IsEqual(R, ExtendsResult.True) }) it('Should extend Null', () => { type T = unknown extends null ? 1 : 2 - const R = TypeExtends.Extends(Type.Unknown(), Type.Null()) - Assert.IsEqual(R, TypeExtendsResult.False) + const R = ExtendsCheck(Type.Unknown(), Type.Null()) + Assert.IsEqual(R, ExtendsResult.False) }) it('Should extend Undefined', () => { type T = unknown extends undefined ? 1 : 2 - const R = TypeExtends.Extends(Type.Unknown(), Type.Undefined()) - Assert.IsEqual(R, TypeExtendsResult.False) + const R = ExtendsCheck(Type.Unknown(), Type.Undefined()) + Assert.IsEqual(R, ExtendsResult.False) }) it('Should extend Void', () => { type T = unknown extends void ? 1 : 2 - const R = TypeExtends.Extends(Type.Unknown(), Type.Void()) - Assert.IsEqual(R, TypeExtendsResult.False) + const R = ExtendsCheck(Type.Unknown(), Type.Void()) + Assert.IsEqual(R, ExtendsResult.False) }) it('Should extend Date', () => { type T = unknown extends Date ? 1 : 2 - const R = TypeExtends.Extends(Type.Unknown(), Type.Date()) - Assert.IsEqual(R, TypeExtendsResult.False) + const R = ExtendsCheck(Type.Unknown(), Type.Date()) + Assert.IsEqual(R, ExtendsResult.False) }) }) diff --git a/test/runtime/type/extends/void.ts b/test/runtime/type/extends/void.ts index 106e1759e..ab7b63309 100644 --- a/test/runtime/type/extends/void.ts +++ b/test/runtime/type/extends/void.ts @@ -1,106 +1,106 @@ -import { TypeExtends, TypeExtendsResult } from '@sinclair/typebox' +import { ExtendsCheck, ExtendsResult } from '@sinclair/typebox/type' import { Type } from '@sinclair/typebox' import { Assert } from '../../assert/index' describe('type/extends/Void', () => { it('Should extend Any', () => { type T = void extends any ? 1 : 2 - const R = TypeExtends.Extends(Type.Void(), Type.Any()) - Assert.IsEqual(R, TypeExtendsResult.True) + const R = ExtendsCheck(Type.Void(), Type.Any()) + Assert.IsEqual(R, ExtendsResult.True) }) it('Should extend Unknown', () => { type T = void extends unknown ? 1 : 2 - const R = TypeExtends.Extends(Type.Void(), Type.Unknown()) - Assert.IsEqual(R, TypeExtendsResult.True) + const R = ExtendsCheck(Type.Void(), Type.Unknown()) + Assert.IsEqual(R, ExtendsResult.True) }) it('Should extend String', () => { type T = void extends string ? 1 : 2 - const R = TypeExtends.Extends(Type.Void(), Type.String()) - Assert.IsEqual(R, TypeExtendsResult.False) + const R = ExtendsCheck(Type.Void(), Type.String()) + Assert.IsEqual(R, ExtendsResult.False) }) it('Should extend Boolean', () => { type T = void extends boolean ? 1 : 2 - const R = TypeExtends.Extends(Type.Void(), Type.Boolean()) - Assert.IsEqual(R, TypeExtendsResult.False) + const R = ExtendsCheck(Type.Void(), Type.Boolean()) + Assert.IsEqual(R, ExtendsResult.False) }) it('Should extend Number', () => { type T = void extends number ? 1 : 2 - const R = TypeExtends.Extends(Type.Void(), Type.Number()) - Assert.IsEqual(R, TypeExtendsResult.False) + const R = ExtendsCheck(Type.Void(), Type.Number()) + Assert.IsEqual(R, ExtendsResult.False) }) it('Should extend Integer', () => { type T = void extends number ? 1 : 2 - const R = TypeExtends.Extends(Type.Void(), Type.Integer()) - Assert.IsEqual(R, TypeExtendsResult.False) + const R = ExtendsCheck(Type.Void(), Type.Integer()) + Assert.IsEqual(R, ExtendsResult.False) }) it('Should extend Array 1', () => { type T = void extends Array ? 1 : 2 - const R = TypeExtends.Extends(Type.Void(), Type.Array(Type.Any())) - Assert.IsEqual(R, TypeExtendsResult.False) + const R = ExtendsCheck(Type.Void(), Type.Array(Type.Any())) + Assert.IsEqual(R, ExtendsResult.False) }) it('Should extend Array 2', () => { type T = void extends Array ? 1 : 2 - const R = TypeExtends.Extends(Type.Void(), Type.Array(Type.String())) - Assert.IsEqual(R, TypeExtendsResult.False) + const R = ExtendsCheck(Type.Void(), Type.Array(Type.String())) + Assert.IsEqual(R, ExtendsResult.False) }) it('Should extend Tuple', () => { type T = void extends [number, number] ? 1 : 2 - const R = TypeExtends.Extends(Type.Void(), Type.Tuple([Type.Number(), Type.Number()])) - Assert.IsEqual(R, TypeExtendsResult.False) + const R = ExtendsCheck(Type.Void(), Type.Tuple([Type.Number(), Type.Number()])) + Assert.IsEqual(R, ExtendsResult.False) }) it('Should extend Object 1', () => { type T = void extends object ? 1 : 2 - const R = TypeExtends.Extends(Type.Void(), Type.Object({})) - Assert.IsEqual(R, TypeExtendsResult.False) + const R = ExtendsCheck(Type.Void(), Type.Object({})) + Assert.IsEqual(R, ExtendsResult.False) }) it('Should extend Object 2', () => { type T = void extends {} ? 1 : 2 - const R = TypeExtends.Extends(Type.Void(), Type.Object({})) - Assert.IsEqual(R, TypeExtendsResult.False) + const R = ExtendsCheck(Type.Void(), Type.Object({})) + Assert.IsEqual(R, ExtendsResult.False) }) it('Should extend Object 3', () => { type T = void extends { a: number } ? 1 : 2 - const R = TypeExtends.Extends(Type.Void(), Type.Object({ a: Type.Number() })) - Assert.IsEqual(R, TypeExtendsResult.False) + const R = ExtendsCheck(Type.Void(), Type.Object({ a: Type.Number() })) + Assert.IsEqual(R, ExtendsResult.False) }) it('Should extend Union 1', () => { type T = void extends number | string ? 1 : 2 - const R = TypeExtends.Extends(Type.Void(), Type.Union([Type.Number(), Type.String()])) - Assert.IsEqual(R, TypeExtendsResult.False) + const R = ExtendsCheck(Type.Void(), Type.Union([Type.Number(), Type.String()])) + Assert.IsEqual(R, ExtendsResult.False) }) it('Should extend Union 2', () => { type T = void extends any | number ? 1 : 2 // 1 - const R = TypeExtends.Extends(Type.Void(), Type.Union([Type.Any(), Type.String()])) - Assert.IsEqual(R, TypeExtendsResult.True) + const R = ExtendsCheck(Type.Void(), Type.Union([Type.Any(), Type.String()])) + Assert.IsEqual(R, ExtendsResult.True) }) it('Should extend Union 3', () => { type T = void extends unknown | number ? 1 : 2 // 1 - const R = TypeExtends.Extends(Type.Void(), Type.Union([Type.Unknown(), Type.String()])) - Assert.IsEqual(R, TypeExtendsResult.True) + const R = ExtendsCheck(Type.Void(), Type.Union([Type.Unknown(), Type.String()])) + Assert.IsEqual(R, ExtendsResult.True) }) it('Should extend Union 4', () => { type T = void extends unknown | any ? 1 : 2 // 1 - const R = TypeExtends.Extends(Type.Void(), Type.Union([Type.Unknown(), Type.String()])) - Assert.IsEqual(R, TypeExtendsResult.True) + const R = ExtendsCheck(Type.Void(), Type.Union([Type.Unknown(), Type.String()])) + Assert.IsEqual(R, ExtendsResult.True) }) it('Should extend Null', () => { type T = void extends null ? 1 : 2 - const R = TypeExtends.Extends(Type.Void(), Type.Null()) - Assert.IsEqual(R, TypeExtendsResult.False) + const R = ExtendsCheck(Type.Void(), Type.Null()) + Assert.IsEqual(R, ExtendsResult.False) }) it('Should extend Undefined', () => { type T = void extends undefined ? 1 : 2 - const R = TypeExtends.Extends(Type.Void(), Type.Undefined()) - Assert.IsEqual(R, TypeExtendsResult.False) + const R = ExtendsCheck(Type.Void(), Type.Undefined()) + Assert.IsEqual(R, ExtendsResult.False) }) it('Should extend Void', () => { type T = void extends void ? 1 : 2 - const R = TypeExtends.Extends(Type.Void(), Type.Void()) - Assert.IsEqual(R, TypeExtendsResult.True) + const R = ExtendsCheck(Type.Void(), Type.Void()) + Assert.IsEqual(R, ExtendsResult.True) }) it('Should extend Date', () => { type T = void extends Date ? 1 : 2 - const R = TypeExtends.Extends(Type.Void(), Type.Date()) - Assert.IsEqual(R, TypeExtendsResult.False) + const R = ExtendsCheck(Type.Void(), Type.Date()) + Assert.IsEqual(R, ExtendsResult.False) }) }) diff --git a/test/runtime/type/guard/indexed.ts b/test/runtime/type/guard/indexed.ts index 2a680f843..fa7bb47b6 100644 --- a/test/runtime/type/guard/indexed.ts +++ b/test/runtime/type/guard/indexed.ts @@ -311,8 +311,17 @@ describe('type/guard/TIndex', () => { }) it('Should Index 34', () => { const T = Type.String() - // @ts-ignore const I = Type.Index(T, ['x']) Assert.IsTrue(TypeGuard.TNever(I)) }) + it('Should Index 35', () => { + const T = Type.Array(Type.String()) + const I = Type.Index(T, Type.Number()) + Assert.IsTrue(TypeGuard.TString(I)) + }) + it('Should Index 36', () => { + const T = Type.Array(Type.String()) + const I = Type.Index(T, ['[number]']) + Assert.IsTrue(TypeGuard.TString(I)) + }) }) diff --git a/test/runtime/type/guard/kind.ts b/test/runtime/type/guard/kind.ts index 52c87f883..3c18cd13b 100644 --- a/test/runtime/type/guard/kind.ts +++ b/test/runtime/type/guard/kind.ts @@ -1,9 +1,9 @@ -import { TypeGuard, Kind } from '@sinclair/typebox' +import { TypeGuard, Symbols } from '@sinclair/typebox' import { Assert } from '../../assert/index' describe('type/guard/TKind', () => { it('Should guard 1', () => { - const T = { [Kind]: 'Kind' } + const T = { [Symbols.Kind]: 'Kind' } Assert.IsTrue(TypeGuard.TKind(T)) }) it('Should guard 2', () => { diff --git a/test/runtime/type/guard/omit.ts b/test/runtime/type/guard/omit.ts index 7b19d146c..f0d75e84f 100644 --- a/test/runtime/type/guard/omit.ts +++ b/test/runtime/type/guard/omit.ts @@ -1,4 +1,4 @@ -import { TypeGuard, Type, Kind, Transform } from '@sinclair/typebox' +import { TypeGuard, Type, Symbols, Transform } from '@sinclair/typebox' import { Assert } from '../../assert/index' describe('type/guard/TOmit', () => { @@ -10,7 +10,7 @@ describe('type/guard/TOmit', () => { Assert.IsEqual(T.required, ['y']) }) it('Should support TUnsafe omit properties with unregistered Kind', () => { - const T = Type.Omit(Type.Object({ x: Type.Unsafe({ x: 1, [Kind]: 'UnknownOmitType' }), y: Type.Number() }), ['x']) + const T = Type.Omit(Type.Object({ x: Type.Unsafe({ x: 1, [Symbols.Kind]: 'UnknownOmitType' }), y: Type.Number() }), ['x']) Assert.IsEqual(T.required, ['y']) }) // ------------------------------------------------------------------------- @@ -124,6 +124,6 @@ describe('type/guard/TOmit', () => { .Decode((value) => value) .Encode((value) => value) const R = Type.Omit(S, ['x']) - Assert.IsFalse(Transform in R) + Assert.IsFalse(Symbols.Transform in R) }) }) diff --git a/test/runtime/type/guard/partial.ts b/test/runtime/type/guard/partial.ts index cd248bb31..0c1d9febc 100644 --- a/test/runtime/type/guard/partial.ts +++ b/test/runtime/type/guard/partial.ts @@ -1,4 +1,4 @@ -import { TypeGuard, TypeRegistry, Type, Kind, Transform } from '@sinclair/typebox' +import { TypeGuard, TypeRegistry, Type, Symbols, Transform } from '@sinclair/typebox' import { Assert } from '../../assert/index' describe('type/guard/TPartial', () => { @@ -14,12 +14,12 @@ describe('type/guard/TPartial', () => { Assert.IsEqual(T.required, undefined) }) it('Should support TUnsafe partial properties with unknown Kind', () => { - const T = Type.Partial(Type.Object({ x: Type.Unsafe({ [Kind]: 'UnknownPartialType', x: 1 }) })) + const T = Type.Partial(Type.Object({ x: Type.Unsafe({ [Symbols.Kind]: 'UnknownPartialType', x: 1 }) })) Assert.IsEqual(T.required, undefined) }) it('Should support TUnsafe partial properties with known Kind', () => { TypeRegistry.Set('KnownPartialType', () => true) - const T = Type.Partial(Type.Object({ x: Type.Unsafe({ [Kind]: 'KnownPartialType', x: 1 }) })) + const T = Type.Partial(Type.Object({ x: Type.Unsafe({ [Symbols.Kind]: 'KnownPartialType', x: 1 }) })) Assert.IsEqual(T.required, undefined) }) it('Should support applying partial to intersect', () => { @@ -62,6 +62,6 @@ describe('type/guard/TPartial', () => { .Decode((value) => value) .Encode((value) => value) const R = Type.Partial(S) - Assert.IsFalse(Transform in R) + Assert.IsFalse(Symbols.Transform in R) }) }) diff --git a/test/runtime/type/guard/pick.ts b/test/runtime/type/guard/pick.ts index 0fcd90573..0de990bea 100644 --- a/test/runtime/type/guard/pick.ts +++ b/test/runtime/type/guard/pick.ts @@ -1,4 +1,4 @@ -import { TypeGuard, Type, Kind, Transform } from '@sinclair/typebox' +import { TypeGuard, Type, Symbols, Transform } from '@sinclair/typebox' import { Assert } from '../../assert/index' describe('type/guard/TPick', () => { @@ -16,7 +16,7 @@ describe('type/guard/TPick', () => { Assert.IsEqual(T.required, ['x']) }) it('Should support TUnsafe omit properties with unregistered Kind', () => { - const T = Type.Pick(Type.Object({ x: Type.Unsafe({ x: 1, [Kind]: 'UnknownPickType' }), y: Type.Number() }), ['x']) + const T = Type.Pick(Type.Object({ x: Type.Unsafe({ x: 1, [Symbols.Kind]: 'UnknownPickType' }), y: Type.Number() }), ['x']) Assert.IsEqual(T.required, ['x']) }) // ------------------------------------------------------------------------- @@ -126,6 +126,6 @@ describe('type/guard/TPick', () => { .Decode((value) => value) .Encode((value) => value) const R = Type.Pick(S, ['x']) - Assert.IsFalse(Transform in R) + Assert.IsFalse(Symbols.Transform in R) }) }) diff --git a/test/runtime/type/guard/record.ts b/test/runtime/type/guard/record.ts index 987d8bd84..b9b59589a 100644 --- a/test/runtime/type/guard/record.ts +++ b/test/runtime/type/guard/record.ts @@ -1,4 +1,4 @@ -import { TypeGuard, PatternNumberExact, PatternStringExact, PatternString, PatternNumber } from '@sinclair/typebox' +import { TypeGuard, PatternNumberExact, PatternStringExact, PatternString, PatternNumber } from '@sinclair/typebox/type' import { Type } from '@sinclair/typebox' import { Assert } from '../../assert/index' diff --git a/test/runtime/type/guard/required.ts b/test/runtime/type/guard/required.ts index 5af8134d5..44e30b148 100644 --- a/test/runtime/type/guard/required.ts +++ b/test/runtime/type/guard/required.ts @@ -1,4 +1,4 @@ -import { TypeGuard, TypeRegistry, Type, Kind, Transform } from '@sinclair/typebox' +import { TypeGuard, TypeRegistry, Type, Symbols, Transform } from '@sinclair/typebox' import { Assert } from '../../assert/index' describe('type/guard/TRequired', () => { @@ -11,12 +11,12 @@ describe('type/guard/TRequired', () => { Assert.IsEqual(T.required, ['x']) }) it('Should support TUnsafe required properties with unknown Kind', () => { - const T = Type.Required(Type.Object({ x: Type.Optional(Type.Unsafe({ [Kind]: 'UnknownRequiredType', x: 1 })) })) + const T = Type.Required(Type.Object({ x: Type.Optional(Type.Unsafe({ [Symbols.Kind]: 'UnknownRequiredType', x: 1 })) })) Assert.IsEqual(T.required, ['x']) }) it('Should support TUnsafe required properties with known Kind', () => { TypeRegistry.Set('KnownRequiredType', () => true) - const T = Type.Required(Type.Object({ x: Type.Optional(Type.Unsafe({ [Kind]: 'KnownRequiredType', x: 1 })) })) + const T = Type.Required(Type.Object({ x: Type.Optional(Type.Unsafe({ [Symbols.Kind]: 'KnownRequiredType', x: 1 })) })) Assert.IsEqual(T.required, ['x']) }) it('Should support applying required to intersect', () => { @@ -59,6 +59,6 @@ describe('type/guard/TRequired', () => { .Decode((value) => value) .Encode((value) => value) const R = Type.Required(S) - Assert.IsFalse(Transform in R) + Assert.IsFalse(Symbols.Transform in R) }) }) diff --git a/test/runtime/type/guard/union.ts b/test/runtime/type/guard/union.ts index 62b485e40..0a52c57c6 100644 --- a/test/runtime/type/guard/union.ts +++ b/test/runtime/type/guard/union.ts @@ -1,4 +1,4 @@ -import { TypeGuard } from '@sinclair/typebox' +import { TSchema, TypeGuard } from '@sinclair/typebox' import { Type } from '@sinclair/typebox' import { Assert } from '../../assert/index' @@ -46,7 +46,7 @@ describe('type/guard/TUnion', () => { Type.Object({ x: Type.Number(), }), - {} as any, + {} as TSchema, ]), ) Assert.IsFalse(R) diff --git a/test/runtime/type/guard/unsafe.ts b/test/runtime/type/guard/unsafe.ts index f43a2d78d..7f8745993 100644 --- a/test/runtime/type/guard/unsafe.ts +++ b/test/runtime/type/guard/unsafe.ts @@ -1,4 +1,4 @@ -import { Kind, TypeGuard, TypeRegistry } from '@sinclair/typebox' +import { Symbols, TypeGuard, TypeRegistry } from '@sinclair/typebox' import { Type } from '@sinclair/typebox' import { Assert } from '../../assert/index' @@ -15,13 +15,13 @@ describe('type/guard/TUnsafe', () => { }) it('Should guard override TUnsafe as TSchema when registered', () => { TypeRegistry.Set('UnsafeType', () => true) - const T = Type.Unsafe({ [Kind]: 'UnsafeType' }) + const T = Type.Unsafe({ [Symbols.Kind]: 'UnsafeType' }) const R = TypeGuard.TSchema(T) Assert.IsTrue(R) TypeRegistry.Delete('UnsafeType') }) it('Should not guard TUnsafe with unregistered kind', () => { - const T = Type.Unsafe({ [Kind]: 'UnsafeType' }) + const T = Type.Unsafe({ [Symbols.Kind]: 'UnsafeType' }) const R = TypeGuard.TUnsafe(T) Assert.IsFalse(R) }) diff --git a/test/runtime/type/intrinsic/intrinsic.ts b/test/runtime/type/intrinsic/intrinsic.ts index 3ff191aee..5cf3346ca 100644 --- a/test/runtime/type/intrinsic/intrinsic.ts +++ b/test/runtime/type/intrinsic/intrinsic.ts @@ -1,21 +1,22 @@ -import { TypeGuard, Intrinsic } from '@sinclair/typebox' +import { TypeGuard } from '@sinclair/typebox' +import { IntrinsicResolve } from '@sinclair/typebox/type' import { Type } from '@sinclair/typebox' import { Assert } from '../../assert/index' -describe('type/intrinsic/Map', () => { +describe('type/intrinsic/IntrinsicResolve', () => { // ---------------------------------------------------- // Passthrough // ---------------------------------------------------- it('Should passthrough 1', () => { - const T = Intrinsic.Map(Type.String(), 'Capitalize') + const T = IntrinsicResolve(Type.String(), 'Capitalize') Assert.IsTrue(TypeGuard.TString(T)) }) it('Should passthrough 2', () => { - const T = Intrinsic.Map(Type.Number(), 'Capitalize') + const T = IntrinsicResolve(Type.Number(), 'Capitalize') Assert.IsTrue(TypeGuard.TNumber(T)) }) it('Should passthrough 3', () => { - const T = Intrinsic.Map( + const T = IntrinsicResolve( Type.Object({ x: Type.Number(), }), @@ -30,7 +31,7 @@ describe('type/intrinsic/Map', () => { const A = Type.Object({ x: Type.Number() }) const B = Type.Literal('hello') const U = Type.Union([A, B]) - const T = Intrinsic.Map(U, 'Capitalize') + const T = IntrinsicResolve(U, 'Capitalize') Assert.IsTrue(TypeGuard.TUnion(T)) Assert.IsTrue(TypeGuard.TObject(T.anyOf[0])) Assert.IsTrue(TypeGuard.TLiteral(T.anyOf[1])) @@ -40,22 +41,22 @@ describe('type/intrinsic/Map', () => { // Mode: Literal // ---------------------------------------------------- it('Should map literal: Capitalize', () => { - const T = Intrinsic.Map(Type.Literal('hello'), 'Capitalize') + const T = IntrinsicResolve(Type.Literal('hello'), 'Capitalize') Assert.IsTrue(TypeGuard.TLiteral(T)) Assert.IsEqual(T.const, 'Hello') }) it('Should map literal: Uncapitalize', () => { - const T = Intrinsic.Map(Type.Literal('HELLO'), 'Uncapitalize') + const T = IntrinsicResolve(Type.Literal('HELLO'), 'Uncapitalize') Assert.IsTrue(TypeGuard.TLiteral(T)) Assert.IsEqual(T.const, 'hELLO') }) it('Should map literal: Uppercase', () => { - const T = Intrinsic.Map(Type.Literal('hello'), 'Uppercase') + const T = IntrinsicResolve(Type.Literal('hello'), 'Uppercase') Assert.IsTrue(TypeGuard.TLiteral(T)) Assert.IsEqual(T.const, 'HELLO') }) it('Should map literal: Lowercase', () => { - const T = Intrinsic.Map(Type.Literal('HELLO'), 'Lowercase') + const T = IntrinsicResolve(Type.Literal('HELLO'), 'Lowercase') Assert.IsTrue(TypeGuard.TLiteral(T)) Assert.IsEqual(T.const, 'hello') }) @@ -63,25 +64,25 @@ describe('type/intrinsic/Map', () => { // Mode: Literal Union // ---------------------------------------------------- it('Should map literal union: Capitalize', () => { - const T = Intrinsic.Map(Type.Union([Type.Literal('hello'), Type.Literal('world')]), 'Capitalize') + const T = IntrinsicResolve(Type.Union([Type.Literal('hello'), Type.Literal('world')]), 'Capitalize') Assert.IsTrue(TypeGuard.TUnion(T)) Assert.IsEqual(T.anyOf[0].const, 'Hello') Assert.IsEqual(T.anyOf[1].const, 'World') }) it('Should map literal union: Uncapitalize', () => { - const T = Intrinsic.Map(Type.Union([Type.Literal('Hello'), Type.Literal('World')]), 'Uncapitalize') + const T = IntrinsicResolve(Type.Union([Type.Literal('Hello'), Type.Literal('World')]), 'Uncapitalize') Assert.IsTrue(TypeGuard.TUnion(T)) Assert.IsEqual(T.anyOf[0].const, 'hello') Assert.IsEqual(T.anyOf[1].const, 'world') }) it('Should map literal union: Uppercase', () => { - const T = Intrinsic.Map(Type.Union([Type.Literal('hello'), Type.Literal('world')]), 'Uppercase') + const T = IntrinsicResolve(Type.Union([Type.Literal('hello'), Type.Literal('world')]), 'Uppercase') Assert.IsTrue(TypeGuard.TUnion(T)) Assert.IsEqual(T.anyOf[0].const, 'HELLO') Assert.IsEqual(T.anyOf[1].const, 'WORLD') }) it('Should map literal union: Lowercase', () => { - const T = Intrinsic.Map(Type.Union([Type.Literal('HELLO'), Type.Literal('WORLD')]), 'Lowercase') + const T = IntrinsicResolve(Type.Union([Type.Literal('HELLO'), Type.Literal('WORLD')]), 'Lowercase') Assert.IsTrue(TypeGuard.TUnion(T)) Assert.IsEqual(T.anyOf[0].const, 'hello') Assert.IsEqual(T.anyOf[1].const, 'world') @@ -90,22 +91,22 @@ describe('type/intrinsic/Map', () => { // Mode: TemplateLiteral // ---------------------------------------------------- it('Should map template literal: Capitalize', () => { - const T = Intrinsic.Map(Type.TemplateLiteral('hello${1|2}world'), 'Capitalize') + const T = IntrinsicResolve(Type.TemplateLiteral('hello${1|2}world'), 'Capitalize') Assert.IsTrue(TypeGuard.TTemplateLiteral(T)) Assert.IsEqual(T.pattern, '^(Hello1world|Hello2world)$') }) it('Should map template literal: Uncapitalize', () => { - const T = Intrinsic.Map(Type.TemplateLiteral('HELLO${1|2}WORLD'), 'Uncapitalize') + const T = IntrinsicResolve(Type.TemplateLiteral('HELLO${1|2}WORLD'), 'Uncapitalize') Assert.IsTrue(TypeGuard.TTemplateLiteral(T)) Assert.IsEqual(T.pattern, '^(hELLO1WORLD|hELLO2WORLD)$') }) it('Should map template literal: Uppercase', () => { - const T = Intrinsic.Map(Type.TemplateLiteral('hello${1|2}world'), 'Uppercase') + const T = IntrinsicResolve(Type.TemplateLiteral('hello${1|2}world'), 'Uppercase') Assert.IsTrue(TypeGuard.TTemplateLiteral(T)) Assert.IsEqual(T.pattern, '^(HELLO1WORLD|HELLO2WORLD)$') }) it('Should map template literal: Lowercase', () => { - const T = Intrinsic.Map(Type.TemplateLiteral('HELLO${1|2}WORLD'), 'Lowercase') + const T = IntrinsicResolve(Type.TemplateLiteral('HELLO${1|2}WORLD'), 'Lowercase') Assert.IsTrue(TypeGuard.TTemplateLiteral(T)) Assert.IsEqual(T.pattern, '^(hello1world|hello2world)$') }) @@ -113,22 +114,22 @@ describe('type/intrinsic/Map', () => { // Mode: TemplateLiteral Numeric // ---------------------------------------------------- it('Should map template literal numeric: Capitalize', () => { - const T = Intrinsic.Map(Type.TemplateLiteral([Type.Literal('hello'), Type.Union([Type.Literal(1), Type.Literal(2)])]), 'Capitalize') + const T = IntrinsicResolve(Type.TemplateLiteral([Type.Literal('hello'), Type.Union([Type.Literal(1), Type.Literal(2)])]), 'Capitalize') Assert.IsTrue(TypeGuard.TTemplateLiteral(T)) Assert.IsEqual(T.pattern, '^(Hello1|Hello2)$') }) it('Should map template literal numeric: Uncapitalize', () => { - const T = Intrinsic.Map(Type.TemplateLiteral([Type.Literal('HELLO'), Type.Union([Type.Literal(1), Type.Literal(2)])]), 'Uncapitalize') + const T = IntrinsicResolve(Type.TemplateLiteral([Type.Literal('HELLO'), Type.Union([Type.Literal(1), Type.Literal(2)])]), 'Uncapitalize') Assert.IsTrue(TypeGuard.TTemplateLiteral(T)) Assert.IsEqual(T.pattern, '^(hELLO1|hELLO2)$') }) it('Should map template literal numeric: Uppercase', () => { - const T = Intrinsic.Map(Type.TemplateLiteral([Type.Literal('hello'), Type.Union([Type.Literal(1), Type.Literal(2)])]), 'Uppercase') + const T = IntrinsicResolve(Type.TemplateLiteral([Type.Literal('hello'), Type.Union([Type.Literal(1), Type.Literal(2)])]), 'Uppercase') Assert.IsTrue(TypeGuard.TTemplateLiteral(T)) Assert.IsEqual(T.pattern, '^(HELLO1|HELLO2)$') }) it('Should map template literal numeric: Lowercase', () => { - const T = Intrinsic.Map(Type.TemplateLiteral([Type.Literal('HELLO'), Type.Union([Type.Literal(1), Type.Literal(2)])]), 'Lowercase') + const T = IntrinsicResolve(Type.TemplateLiteral([Type.Literal('HELLO'), Type.Union([Type.Literal(1), Type.Literal(2)])]), 'Lowercase') Assert.IsTrue(TypeGuard.TTemplateLiteral(T)) Assert.IsEqual(T.pattern, '^(hello1|hello2)$') }) @@ -136,27 +137,27 @@ describe('type/intrinsic/Map', () => { // Mode: TemplateLiteral Patterns // ---------------------------------------------------- it('Should map template literal patterns 1', () => { - const T = Intrinsic.Map(Type.TemplateLiteral('HELLO${string}WORLD'), 'Lowercase') + const T = IntrinsicResolve(Type.TemplateLiteral('HELLO${string}WORLD'), 'Lowercase') Assert.IsTrue(TypeGuard.TTemplateLiteral(T)) Assert.IsEqual(T.pattern, '^hello(.*)world$') }) it('Should map template literal patterns 2', () => { - const T = Intrinsic.Map(Type.TemplateLiteral('HELLO${number}WORLD'), 'Lowercase') + const T = IntrinsicResolve(Type.TemplateLiteral('HELLO${number}WORLD'), 'Lowercase') Assert.IsTrue(TypeGuard.TTemplateLiteral(T)) Assert.IsEqual(T.pattern, '^hello(0|[1-9][0-9]*)world$') }) it('Should map template literal patterns 3', () => { - const T = Intrinsic.Map(Type.TemplateLiteral('${number}${string}'), 'Lowercase') + const T = IntrinsicResolve(Type.TemplateLiteral('${number}${string}'), 'Lowercase') Assert.IsTrue(TypeGuard.TTemplateLiteral(T)) Assert.IsEqual(T.pattern, '^(0|[1-9][0-9]*)(.*)$') }) it('Should map template literal patterns 3', () => { - const T = Intrinsic.Map(Type.TemplateLiteral('${number}HELLO${string}'), 'Lowercase') + const T = IntrinsicResolve(Type.TemplateLiteral('${number}HELLO${string}'), 'Lowercase') Assert.IsTrue(TypeGuard.TTemplateLiteral(T)) Assert.IsEqual(T.pattern, '^(0|[1-9][0-9]*)hello(.*)$') }) it('Should map template literal patterns 3', () => { - const T = Intrinsic.Map(Type.TemplateLiteral('${string|number}HELLO'), 'Lowercase') + const T = IntrinsicResolve(Type.TemplateLiteral('${string|number}HELLO'), 'Lowercase') Assert.IsTrue(TypeGuard.TTemplateLiteral(T)) Assert.IsEqual(T.pattern, '^(stringhello|numberhello)$') }) diff --git a/test/runtime/type/template/finite.ts b/test/runtime/type/template/finite.ts index 53028dff9..11df30049 100644 --- a/test/runtime/type/template/finite.ts +++ b/test/runtime/type/template/finite.ts @@ -1,71 +1,71 @@ -import { PatternString, PatternBoolean, PatternNumber, TemplateLiteralParser, TemplateLiteralFinite } from '@sinclair/typebox' +import { TemplateLiteralParse, IsTemplateLiteralFinite, PatternString, PatternBoolean, PatternNumber } from '@sinclair/typebox/type' import { Assert } from '../../assert/index' -describe('type/templateliteral/TemplateLiteralFinite', () => { +describe('type/templateliteral/IsTemplateLiteralFinite', () => { // --------------------------------------------------------------- // Finite // --------------------------------------------------------------- it('Finite 1', () => { - const E = TemplateLiteralParser.Parse(`A`) - const R = TemplateLiteralFinite.Check(E) + const E = TemplateLiteralParse(`A`) + const R = IsTemplateLiteralFinite(E) Assert.IsTrue(R) }) it('Finite 2', () => { - const E = TemplateLiteralParser.Parse(`A|B`) - const R = TemplateLiteralFinite.Check(E) + const E = TemplateLiteralParse(`A|B`) + const R = IsTemplateLiteralFinite(E) Assert.IsTrue(R) }) it('Finite 3', () => { - const E = TemplateLiteralParser.Parse(`A(B|C)`) - const R = TemplateLiteralFinite.Check(E) + const E = TemplateLiteralParse(`A(B|C)`) + const R = IsTemplateLiteralFinite(E) Assert.IsTrue(R) }) it('Finite 4', () => { - const E = TemplateLiteralParser.Parse(`${PatternBoolean}`) - const R = TemplateLiteralFinite.Check(E) + const E = TemplateLiteralParse(`${PatternBoolean}`) + const R = IsTemplateLiteralFinite(E) Assert.IsTrue(R) }) it('Finite 5', () => { - const E = TemplateLiteralParser.Parse(`\\.\\*`) - const R = TemplateLiteralFinite.Check(E) + const E = TemplateLiteralParse(`\\.\\*`) + const R = IsTemplateLiteralFinite(E) Assert.IsTrue(R) }) // --------------------------------------------------------------- // Infinite // --------------------------------------------------------------- it('Infinite 1', () => { - const E = TemplateLiteralParser.Parse(`${PatternString}`) - const R = TemplateLiteralFinite.Check(E) + const E = TemplateLiteralParse(`${PatternString}`) + const R = IsTemplateLiteralFinite(E) Assert.IsFalse(R) }) it('Infinite 2', () => { - const E = TemplateLiteralParser.Parse(`${PatternNumber}`) - const R = TemplateLiteralFinite.Check(E) + const E = TemplateLiteralParse(`${PatternNumber}`) + const R = IsTemplateLiteralFinite(E) Assert.IsFalse(R) }) it('Infinite 3', () => { - const E = TemplateLiteralParser.Parse(`A|${PatternString}`) - const R = TemplateLiteralFinite.Check(E) + const E = TemplateLiteralParse(`A|${PatternString}`) + const R = IsTemplateLiteralFinite(E) Assert.IsFalse(R) }) it('Infinite 4', () => { - const E = TemplateLiteralParser.Parse(`A|${PatternNumber}`) - const R = TemplateLiteralFinite.Check(E) + const E = TemplateLiteralParse(`A|${PatternNumber}`) + const R = IsTemplateLiteralFinite(E) Assert.IsFalse(R) }) it('Infinite 5', () => { - const E = TemplateLiteralParser.Parse(`A(${PatternString})`) - const R = TemplateLiteralFinite.Check(E) + const E = TemplateLiteralParse(`A(${PatternString})`) + const R = IsTemplateLiteralFinite(E) Assert.IsFalse(R) }) it('Infinite 6', () => { - const E = TemplateLiteralParser.Parse(`A(${PatternNumber})`) - const R = TemplateLiteralFinite.Check(E) + const E = TemplateLiteralParse(`A(${PatternNumber})`) + const R = IsTemplateLiteralFinite(E) Assert.IsFalse(R) }) it('Infinite 7', () => { - const E = TemplateLiteralParser.Parse(`${PatternString}_foo`) - const R = TemplateLiteralFinite.Check(E) + const E = TemplateLiteralParse(`${PatternString}_foo`) + const R = IsTemplateLiteralFinite(E) Assert.IsFalse(R) }) }) diff --git a/test/runtime/type/template/generate.ts b/test/runtime/type/template/generate.ts index 73aa9cfc3..53a3404ff 100644 --- a/test/runtime/type/template/generate.ts +++ b/test/runtime/type/template/generate.ts @@ -1,4 +1,4 @@ -import { TemplateLiteralParser, TemplateLiteralGenerator } from '@sinclair/typebox' +import { TemplateLiteralParse, TemplateLiteralGenerate } from '@sinclair/typebox/type' import { Assert } from '../../assert/index' describe('type/templateliteral/TemplateLiteralGenerator', () => { @@ -6,194 +6,194 @@ describe('type/templateliteral/TemplateLiteralGenerator', () => { // Exact (No Default Unwrap) // --------------------------------------------------------------- it('Exact 1', () => { - const E = TemplateLiteralParser.Parse('^$') - const R = [...TemplateLiteralGenerator.Generate(E)] + const E = TemplateLiteralParse('^$') + const R = [...TemplateLiteralGenerate(E)] Assert.IsEqual(R, ['^$']) }) it('Exact 2', () => { - const E = TemplateLiteralParser.Parse('^A$') - const R = [...TemplateLiteralGenerator.Generate(E)] + const E = TemplateLiteralParse('^A$') + const R = [...TemplateLiteralGenerate(E)] Assert.IsEqual(R, ['^A$']) }) // --------------------------------------------------------------- // Patterns // --------------------------------------------------------------- it('Pattern 1', () => { - const E = TemplateLiteralParser.Parse('(true|false)') - const R = [...TemplateLiteralGenerator.Generate(E)] + const E = TemplateLiteralParse('(true|false)') + const R = [...TemplateLiteralGenerate(E)] Assert.IsEqual(R, ['true', 'false']) }) it('Pattern 2', () => { - const E = TemplateLiteralParser.Parse('(0|[1-9][0-9]*)') - const R = [...TemplateLiteralGenerator.Generate(E)] + const E = TemplateLiteralParse('(0|[1-9][0-9]*)') + const R = [...TemplateLiteralGenerate(E)] Assert.IsEqual(R, ['0', '[1-9][0-9]*']) }) it('Pattern 3', () => { - const E = TemplateLiteralParser.Parse('.*') - const R = [...TemplateLiteralGenerator.Generate(E)] + const E = TemplateLiteralParse('.*') + const R = [...TemplateLiteralGenerate(E)] Assert.IsEqual(R, ['.*']) }) // --------------------------------------------------------------- // Expression // --------------------------------------------------------------- it('Expression 1', () => { - const E = TemplateLiteralParser.Parse(')') - const R = [...TemplateLiteralGenerator.Generate(E)] + const E = TemplateLiteralParse(')') + const R = [...TemplateLiteralGenerate(E)] Assert.IsEqual(R, [')']) }) it('Expression 2', () => { - const E = TemplateLiteralParser.Parse('\\)') - const R = [...TemplateLiteralGenerator.Generate(E)] + const E = TemplateLiteralParse('\\)') + const R = [...TemplateLiteralGenerate(E)] Assert.IsEqual(R, ['\\)']) }) it('Expression 3', () => { - const E = TemplateLiteralParser.Parse('\\(') - const R = [...TemplateLiteralGenerator.Generate(E)] + const E = TemplateLiteralParse('\\(') + const R = [...TemplateLiteralGenerate(E)] Assert.IsEqual(R, ['\\(']) }) it('Expression 4', () => { - const E = TemplateLiteralParser.Parse('') - const R = [...TemplateLiteralGenerator.Generate(E)] + const E = TemplateLiteralParse('') + const R = [...TemplateLiteralGenerate(E)] Assert.IsEqual(R, ['']) }) it('Expression 5', () => { - const E = TemplateLiteralParser.Parse('\\') - const R = [...TemplateLiteralGenerator.Generate(E)] + const E = TemplateLiteralParse('\\') + const R = [...TemplateLiteralGenerate(E)] Assert.IsEqual(R, ['\\']) }) it('Expression 6', () => { - const E = TemplateLiteralParser.Parse('()') - const R = [...TemplateLiteralGenerator.Generate(E)] + const E = TemplateLiteralParse('()') + const R = [...TemplateLiteralGenerate(E)] Assert.IsEqual(R, ['']) }) it('Expression 7', () => { - const E = TemplateLiteralParser.Parse('(a)') - const R = [...TemplateLiteralGenerator.Generate(E)] + const E = TemplateLiteralParse('(a)') + const R = [...TemplateLiteralGenerate(E)] Assert.IsEqual(R, ['a']) }) it('Expression 8', () => { - const E = TemplateLiteralParser.Parse('()))') - const R = [...TemplateLiteralGenerator.Generate(E)] + const E = TemplateLiteralParse('()))') + const R = [...TemplateLiteralGenerate(E)] Assert.IsEqual(R, ['))']) }) it('Expression 9', () => { - const E = TemplateLiteralParser.Parse('())') - const R = [...TemplateLiteralGenerator.Generate(E)] + const E = TemplateLiteralParse('())') + const R = [...TemplateLiteralGenerate(E)] Assert.IsEqual(R, [')']) }) it('Expression 10', () => { - const E = TemplateLiteralParser.Parse('A|B') - const R = [...TemplateLiteralGenerator.Generate(E)] + const E = TemplateLiteralParse('A|B') + const R = [...TemplateLiteralGenerate(E)] Assert.IsEqual(R, ['A', 'B']) }) it('Expression 11', () => { - const E = TemplateLiteralParser.Parse('A|(B)') - const R = [...TemplateLiteralGenerator.Generate(E)] + const E = TemplateLiteralParse('A|(B)') + const R = [...TemplateLiteralGenerate(E)] Assert.IsEqual(R, ['A', 'B']) }) it('Expression 12', () => { - const E = TemplateLiteralParser.Parse('A(B)') - const R = [...TemplateLiteralGenerator.Generate(E)] + const E = TemplateLiteralParse('A(B)') + const R = [...TemplateLiteralGenerate(E)] Assert.IsEqual(R, ['AB']) }) it('Expression 13', () => { - const E = TemplateLiteralParser.Parse('(A)B') - const R = [...TemplateLiteralGenerator.Generate(E)] + const E = TemplateLiteralParse('(A)B') + const R = [...TemplateLiteralGenerate(E)] Assert.IsEqual(R, ['AB']) }) it('Expression 14', () => { - const E = TemplateLiteralParser.Parse('(A)|B') - const R = [...TemplateLiteralGenerator.Generate(E)] + const E = TemplateLiteralParse('(A)|B') + const R = [...TemplateLiteralGenerate(E)] Assert.IsEqual(R, ['A', 'B']) }) it('Expression 15', () => { - const E = TemplateLiteralParser.Parse('|') - const R = [...TemplateLiteralGenerator.Generate(E)] + const E = TemplateLiteralParse('|') + const R = [...TemplateLiteralGenerate(E)] Assert.IsEqual(R, ['']) }) it('Expression 16', () => { - const E = TemplateLiteralParser.Parse('||') - const R = [...TemplateLiteralGenerator.Generate(E)] + const E = TemplateLiteralParse('||') + const R = [...TemplateLiteralGenerate(E)] Assert.IsEqual(R, ['']) }) it('Expression 17', () => { - const E = TemplateLiteralParser.Parse('||A') - const R = [...TemplateLiteralGenerator.Generate(E)] + const E = TemplateLiteralParse('||A') + const R = [...TemplateLiteralGenerate(E)] Assert.IsEqual(R, ['A']) }) it('Expression 18', () => { - const E = TemplateLiteralParser.Parse('A||') - const R = [...TemplateLiteralGenerator.Generate(E)] + const E = TemplateLiteralParse('A||') + const R = [...TemplateLiteralGenerate(E)] Assert.IsEqual(R, ['A']) }) it('Expression 19', () => { - const E = TemplateLiteralParser.Parse('A||B') - const R = [...TemplateLiteralGenerator.Generate(E)] + const E = TemplateLiteralParse('A||B') + const R = [...TemplateLiteralGenerate(E)] Assert.IsEqual(R, ['A', 'B']) }) it('Expression 20', () => { - const E = TemplateLiteralParser.Parse('A|()|B') - const R = [...TemplateLiteralGenerator.Generate(E)] + const E = TemplateLiteralParse('A|()|B') + const R = [...TemplateLiteralGenerate(E)] Assert.IsEqual(R, ['A', '', 'B']) }) it('Expression 21', () => { - const E = TemplateLiteralParser.Parse('A|(|)|B') - const R = [...TemplateLiteralGenerator.Generate(E)] + const E = TemplateLiteralParse('A|(|)|B') + const R = [...TemplateLiteralGenerate(E)] Assert.IsEqual(R, ['A', '', 'B']) }) it('Expression 22', () => { - const E = TemplateLiteralParser.Parse('A|(||)|B') - const R = [...TemplateLiteralGenerator.Generate(E)] + const E = TemplateLiteralParse('A|(||)|B') + const R = [...TemplateLiteralGenerate(E)] Assert.IsEqual(R, ['A', '', 'B']) }) it('Expression 23', () => { - const E = TemplateLiteralParser.Parse('|A(||)B|') - const R = [...TemplateLiteralGenerator.Generate(E)] + const E = TemplateLiteralParse('|A(||)B|') + const R = [...TemplateLiteralGenerate(E)] Assert.IsEqual(R, ['AB']) }) it('Expression 24', () => { - const E = TemplateLiteralParser.Parse('A(B)(C)') - const R = [...TemplateLiteralGenerator.Generate(E)] + const E = TemplateLiteralParse('A(B)(C)') + const R = [...TemplateLiteralGenerate(E)] Assert.IsEqual(R, ['ABC']) }) it('Expression 25', () => { - const E = TemplateLiteralParser.Parse('A(B)|(C)') - const R = [...TemplateLiteralGenerator.Generate(E)] + const E = TemplateLiteralParse('A(B)|(C)') + const R = [...TemplateLiteralGenerate(E)] Assert.IsEqual(R, ['AB', 'C']) }) it('Expression 26', () => { - const E = TemplateLiteralParser.Parse('A(B|C)') - const R = [...TemplateLiteralGenerator.Generate(E)] + const E = TemplateLiteralParse('A(B|C)') + const R = [...TemplateLiteralGenerate(E)] Assert.IsEqual(R, ['AB', 'AC']) }) it('Expression 27', () => { - const E = TemplateLiteralParser.Parse('A|(B|C)') - const R = [...TemplateLiteralGenerator.Generate(E)] + const E = TemplateLiteralParse('A|(B|C)') + const R = [...TemplateLiteralGenerate(E)] Assert.IsEqual(R, ['A', 'B', 'C']) }) it('Expression 28', () => { - const E = TemplateLiteralParser.Parse('((A)B)C') - const R = [...TemplateLiteralGenerator.Generate(E)] + const E = TemplateLiteralParse('((A)B)C') + const R = [...TemplateLiteralGenerate(E)] Assert.IsEqual(R, ['ABC']) }) it('Expression 29', () => { - const E = TemplateLiteralParser.Parse('(0|1)(0|1)') - const R = [...TemplateLiteralGenerator.Generate(E)] + const E = TemplateLiteralParse('(0|1)(0|1)') + const R = [...TemplateLiteralGenerate(E)] Assert.IsEqual(R, ['00', '01', '10', '11']) }) it('Expression 30', () => { - const E = TemplateLiteralParser.Parse('(0|1)|(0|1)') - const R = [...TemplateLiteralGenerator.Generate(E)] + const E = TemplateLiteralParse('(0|1)|(0|1)') + const R = [...TemplateLiteralGenerate(E)] Assert.IsEqual(R, ['0', '1', '0', '1']) }) it('Expression 31', () => { - const E = TemplateLiteralParser.Parse('(0|(1|0)|1)') - const R = [...TemplateLiteralGenerator.Generate(E)] + const E = TemplateLiteralParse('(0|(1|0)|1)') + const R = [...TemplateLiteralGenerate(E)] Assert.IsEqual(R, ['0', '1', '0', '1']) }) it('Expression 32', () => { - const E = TemplateLiteralParser.Parse('(0(1|0)1)') - const R = [...TemplateLiteralGenerator.Generate(E)] + const E = TemplateLiteralParse('(0(1|0)1)') + const R = [...TemplateLiteralGenerate(E)] Assert.IsEqual(R, ['011', '001']) }) }) diff --git a/test/runtime/type/template/parser.ts b/test/runtime/type/template/parser.ts index 5ab50afbf..34dafcd19 100644 --- a/test/runtime/type/template/parser.ts +++ b/test/runtime/type/template/parser.ts @@ -1,4 +1,4 @@ -import { TemplateLiteralParser } from '@sinclair/typebox' +import { TemplateLiteralParse } from '@sinclair/typebox/type' import { Assert } from '../../assert/index' describe('type/templateliteral/TemplateLiteralParser', () => { @@ -6,23 +6,23 @@ describe('type/templateliteral/TemplateLiteralParser', () => { // Throws // --------------------------------------------------------------- it('Throw 1', () => { - Assert.Throws(() => TemplateLiteralParser.Parse('(')) + Assert.Throws(() => TemplateLiteralParse('(')) }) it('Throw 2', () => { - Assert.Throws(() => TemplateLiteralParser.Parse('(')) + Assert.Throws(() => TemplateLiteralParse('(')) }) // --------------------------------------------------------------- // Exact (No Default Unwrap) // --------------------------------------------------------------- it('Exact 1', () => { - const E = TemplateLiteralParser.Parse('^$') + const E = TemplateLiteralParse('^$') Assert.IsEqual(E, { type: 'const', const: '^$', }) }) it('Exact 2', () => { - const E = TemplateLiteralParser.Parse('^A$') + const E = TemplateLiteralParse('^A$') Assert.IsEqual(E, { type: 'const', const: '^A$', @@ -32,7 +32,7 @@ describe('type/templateliteral/TemplateLiteralParser', () => { // Patterns // --------------------------------------------------------------- it('Pattern 1', () => { - const E = TemplateLiteralParser.Parse('(true|false)') + const E = TemplateLiteralParse('(true|false)') Assert.IsEqual(E, { type: 'or', expr: [ @@ -48,7 +48,7 @@ describe('type/templateliteral/TemplateLiteralParser', () => { }) }) it('Pattern 2', () => { - const E = TemplateLiteralParser.Parse('(0|[1-9][0-9]*)') + const E = TemplateLiteralParse('(0|[1-9][0-9]*)') Assert.IsEqual(E, { type: 'or', expr: [ @@ -64,7 +64,7 @@ describe('type/templateliteral/TemplateLiteralParser', () => { }) }) it('Pattern 3', () => { - const E = TemplateLiteralParser.Parse('.*') + const E = TemplateLiteralParse('.*') Assert.IsEqual(E, { type: 'const', const: '.*', @@ -74,56 +74,56 @@ describe('type/templateliteral/TemplateLiteralParser', () => { // Expression // --------------------------------------------------------------- it('Expression 1', () => { - const E = TemplateLiteralParser.Parse(')') + const E = TemplateLiteralParse(')') Assert.IsEqual(E, { type: 'const', const: ')', }) }) it('Expression 2', () => { - const E = TemplateLiteralParser.Parse('\\)') + const E = TemplateLiteralParse('\\)') Assert.IsEqual(E, { type: 'const', const: '\\)', }) }) it('Expression 3', () => { - const E = TemplateLiteralParser.Parse('\\(') + const E = TemplateLiteralParse('\\(') Assert.IsEqual(E, { type: 'const', const: '\\(', }) }) it('Expression 4', () => { - const E = TemplateLiteralParser.Parse('') + const E = TemplateLiteralParse('') Assert.IsEqual(E, { type: 'const', const: '', }) }) it('Expression 5', () => { - const E = TemplateLiteralParser.Parse('\\') + const E = TemplateLiteralParse('\\') Assert.IsEqual(E, { type: 'const', const: '\\', }) }) it('Expression 6', () => { - const E = TemplateLiteralParser.Parse('()') + const E = TemplateLiteralParse('()') Assert.IsEqual(E, { type: 'const', const: '', }) }) it('Expression 7', () => { - const E = TemplateLiteralParser.Parse('(a)') + const E = TemplateLiteralParse('(a)') Assert.IsEqual(E, { type: 'const', const: 'a', }) }) it('Expression 8', () => { - const E = TemplateLiteralParser.Parse('()))') + const E = TemplateLiteralParse('()))') Assert.IsEqual(E, { type: 'and', expr: [ @@ -139,7 +139,7 @@ describe('type/templateliteral/TemplateLiteralParser', () => { }) }) it('Expression 9', () => { - const E = TemplateLiteralParser.Parse('())') + const E = TemplateLiteralParse('())') Assert.IsEqual(E, { type: 'and', expr: [ @@ -155,7 +155,7 @@ describe('type/templateliteral/TemplateLiteralParser', () => { }) }) it('Expression 10', () => { - const E = TemplateLiteralParser.Parse('A|B') + const E = TemplateLiteralParse('A|B') Assert.IsEqual(E, { type: 'or', expr: [ @@ -171,7 +171,7 @@ describe('type/templateliteral/TemplateLiteralParser', () => { }) }) it('Expression 11', () => { - const E = TemplateLiteralParser.Parse('A|(B)') + const E = TemplateLiteralParse('A|(B)') Assert.IsEqual(E, { type: 'or', expr: [ @@ -187,7 +187,7 @@ describe('type/templateliteral/TemplateLiteralParser', () => { }) }) it('Expression 12', () => { - const E = TemplateLiteralParser.Parse('A(B)') + const E = TemplateLiteralParse('A(B)') Assert.IsEqual(E, { type: 'and', expr: [ @@ -203,7 +203,7 @@ describe('type/templateliteral/TemplateLiteralParser', () => { }) }) it('Expression 13', () => { - const E = TemplateLiteralParser.Parse('(A)B') + const E = TemplateLiteralParse('(A)B') Assert.IsEqual(E, { type: 'and', expr: [ @@ -219,7 +219,7 @@ describe('type/templateliteral/TemplateLiteralParser', () => { }) }) it('Expression 14', () => { - const E = TemplateLiteralParser.Parse('(A)|B') + const E = TemplateLiteralParse('(A)|B') Assert.IsEqual(E, { type: 'or', expr: [ @@ -235,35 +235,35 @@ describe('type/templateliteral/TemplateLiteralParser', () => { }) }) it('Expression 15', () => { - const E = TemplateLiteralParser.Parse('|') + const E = TemplateLiteralParse('|') Assert.IsEqual(E, { type: 'const', const: '', }) }) it('Expression 16', () => { - const E = TemplateLiteralParser.Parse('||') + const E = TemplateLiteralParse('||') Assert.IsEqual(E, { type: 'const', const: '', }) }) it('Expression 17', () => { - const E = TemplateLiteralParser.Parse('||A') + const E = TemplateLiteralParse('||A') Assert.IsEqual(E, { type: 'const', const: 'A', }) }) it('Expression 18', () => { - const E = TemplateLiteralParser.Parse('A||') + const E = TemplateLiteralParse('A||') Assert.IsEqual(E, { type: 'const', const: 'A', }) }) it('Expression 19', () => { - const E = TemplateLiteralParser.Parse('A||B') + const E = TemplateLiteralParse('A||B') Assert.IsEqual(E, { type: 'or', expr: [ @@ -279,7 +279,7 @@ describe('type/templateliteral/TemplateLiteralParser', () => { }) }) it('Expression 20', () => { - const E = TemplateLiteralParser.Parse('A|()|B') + const E = TemplateLiteralParse('A|()|B') Assert.IsEqual(E, { type: 'or', expr: [ @@ -299,7 +299,7 @@ describe('type/templateliteral/TemplateLiteralParser', () => { }) }) it('Expression 21', () => { - const E = TemplateLiteralParser.Parse('A|(|)|B') + const E = TemplateLiteralParse('A|(|)|B') Assert.IsEqual(E, { type: 'or', expr: [ @@ -319,7 +319,7 @@ describe('type/templateliteral/TemplateLiteralParser', () => { }) }) it('Expression 22', () => { - const E = TemplateLiteralParser.Parse('A|(||)|B') + const E = TemplateLiteralParse('A|(||)|B') Assert.IsEqual(E, { type: 'or', expr: [ @@ -339,7 +339,7 @@ describe('type/templateliteral/TemplateLiteralParser', () => { }) }) it('Expression 23', () => { - const E = TemplateLiteralParser.Parse('|A(||)B|') + const E = TemplateLiteralParse('|A(||)B|') Assert.IsEqual(E, { type: 'and', expr: [ @@ -359,7 +359,7 @@ describe('type/templateliteral/TemplateLiteralParser', () => { }) }) it('Expression 24', () => { - const E = TemplateLiteralParser.Parse('A(B)(C)') + const E = TemplateLiteralParse('A(B)(C)') Assert.IsEqual(E, { type: 'and', expr: [ @@ -379,7 +379,7 @@ describe('type/templateliteral/TemplateLiteralParser', () => { }) }) it('Expression 25', () => { - const E = TemplateLiteralParser.Parse('A(B)|(C)') + const E = TemplateLiteralParse('A(B)|(C)') Assert.IsEqual(E, { type: 'or', expr: [ @@ -404,7 +404,7 @@ describe('type/templateliteral/TemplateLiteralParser', () => { }) }) it('Expression 26', () => { - const E = TemplateLiteralParser.Parse('A(B|C)') + const E = TemplateLiteralParse('A(B|C)') Assert.IsEqual(E, { type: 'and', expr: [ @@ -429,7 +429,7 @@ describe('type/templateliteral/TemplateLiteralParser', () => { }) }) it('Expression 27', () => { - const E = TemplateLiteralParser.Parse('A|(B|C)') + const E = TemplateLiteralParse('A|(B|C)') Assert.IsEqual(E, { type: 'or', expr: [ @@ -454,7 +454,7 @@ describe('type/templateliteral/TemplateLiteralParser', () => { }) }) it('Expression 28', () => { - const E = TemplateLiteralParser.Parse('((A)B)C') + const E = TemplateLiteralParse('((A)B)C') Assert.IsEqual(E, { type: 'and', expr: [ @@ -479,7 +479,7 @@ describe('type/templateliteral/TemplateLiteralParser', () => { }) }) it('Expression 29', () => { - const E = TemplateLiteralParser.Parse('(0|1)(0|1)') + const E = TemplateLiteralParse('(0|1)(0|1)') Assert.IsEqual(E, { type: 'and', expr: [ @@ -513,7 +513,7 @@ describe('type/templateliteral/TemplateLiteralParser', () => { }) }) it('Expression 30', () => { - const E = TemplateLiteralParser.Parse('(0|1)|(0|1)') + const E = TemplateLiteralParse('(0|1)|(0|1)') Assert.IsEqual(E, { type: 'or', expr: [ @@ -547,7 +547,7 @@ describe('type/templateliteral/TemplateLiteralParser', () => { }) }) it('Expression 31', () => { - const E = TemplateLiteralParser.Parse('(0|(1|0)|1)') + const E = TemplateLiteralParse('(0|(1|0)|1)') Assert.IsEqual(E, { type: 'or', expr: [ @@ -576,7 +576,7 @@ describe('type/templateliteral/TemplateLiteralParser', () => { }) }) it('Expression 32', () => { - const E = TemplateLiteralParser.Parse('(0(1|0)1)') + const E = TemplateLiteralParse('(0(1|0)1)') Assert.IsEqual(E, { type: 'and', expr: [ diff --git a/test/runtime/type/template/pattern.ts b/test/runtime/type/template/pattern.ts index 6fdf85ca7..e0fc54d0f 100644 --- a/test/runtime/type/template/pattern.ts +++ b/test/runtime/type/template/pattern.ts @@ -1,4 +1,4 @@ -import { Type, TTemplateLiteral, PatternNumber, PatternString, PatternBoolean } from '@sinclair/typebox' +import { Type, TTemplateLiteral, PatternNumber, PatternString, PatternBoolean } from '@sinclair/typebox/type' import { Assert } from '../../assert/index' describe('type/templateliteral/TemplateLiteralPattern', () => { diff --git a/test/runtime/value/cast/kind.ts b/test/runtime/value/cast/kind.ts index 42cffc618..1fb1fa099 100644 --- a/test/runtime/value/cast/kind.ts +++ b/test/runtime/value/cast/kind.ts @@ -1,5 +1,5 @@ import { Value } from '@sinclair/typebox/value' -import { Type, Kind, TypeRegistry } from '@sinclair/typebox' +import { Type, Symbols, TypeRegistry } from '@sinclair/typebox' import { Assert } from '../../assert/index' describe('value/cast/Kind', () => { @@ -11,7 +11,7 @@ describe('value/cast/Kind', () => { // --------------------------------------------------------- // Tests // --------------------------------------------------------- - const T = Type.Unsafe({ [Kind]: 'Kind', default: 'hello' }) + const T = Type.Unsafe({ [Symbols.Kind]: 'Kind', default: 'hello' }) const E = 'hello' it('Should upcast from string', () => { const value = 'hello' diff --git a/test/runtime/value/check/kind.ts b/test/runtime/value/check/kind.ts index 9a16eed65..067d4ff35 100644 --- a/test/runtime/value/check/kind.ts +++ b/test/runtime/value/check/kind.ts @@ -1,5 +1,5 @@ import { Value } from '@sinclair/typebox/value' -import { TypeRegistry, Type, Kind, TSchema } from '@sinclair/typebox' +import { TypeRegistry, Type, Symbols, TSchema } from '@sinclair/typebox' import { Assert } from '../../assert' describe('value/check/Kind', () => { @@ -12,39 +12,39 @@ describe('value/check/Kind', () => { // Tests // ------------------------------------------------------------ it('Should validate', () => { - const T = Type.Unsafe({ [Kind]: 'PI' }) + const T = Type.Unsafe({ [Symbols.Kind]: 'PI' }) Assert.IsTrue(Value.Check(T, Math.PI)) }) it('Should not validate', () => { - const T = Type.Unsafe({ [Kind]: 'PI' }) + const T = Type.Unsafe({ [Symbols.Kind]: 'PI' }) Assert.IsFalse(Value.Check(T, Math.PI * 2)) }) it('Should validate in object', () => { const T = Type.Object({ - x: Type.Unsafe({ [Kind]: 'PI' }), + x: Type.Unsafe({ [Symbols.Kind]: 'PI' }), }) Assert.IsTrue(Value.Check(T, { x: Math.PI })) }) it('Should not validate in object', () => { const T = Type.Object({ - x: Type.Unsafe({ [Kind]: 'PI' }), + x: Type.Unsafe({ [Symbols.Kind]: 'PI' }), }) Assert.IsFalse(Value.Check(T, { x: Math.PI * 2 })) }) it('Should validate in array', () => { - const T = Type.Array(Type.Unsafe({ [Kind]: 'PI' })) + const T = Type.Array(Type.Unsafe({ [Symbols.Kind]: 'PI' })) Assert.IsTrue(Value.Check(T, [Math.PI])) }) it('Should not validate in array', () => { - const T = Type.Array(Type.Unsafe({ [Kind]: 'PI' })) + const T = Type.Array(Type.Unsafe({ [Symbols.Kind]: 'PI' })) Assert.IsFalse(Value.Check(T, [Math.PI * 2])) }) it('Should validate in tuple', () => { - const T = Type.Tuple([Type.Unsafe({ [Kind]: 'PI' })]) + const T = Type.Tuple([Type.Unsafe({ [Symbols.Kind]: 'PI' })]) Assert.IsTrue(Value.Check(T, [Math.PI])) }) it('Should not validate in tuple', () => { - const T = Type.Tuple([Type.Unsafe({ [Kind]: 'PI' })]) + const T = Type.Tuple([Type.Unsafe({ [Symbols.Kind]: 'PI' })]) Assert.IsFalse(Value.Check(T, [Math.PI * 2])) }) // ------------------------------------------------------------ @@ -54,12 +54,12 @@ describe('value/check/Kind', () => { const stack: string[] = [] TypeRegistry.Set('Kind', (schema: unknown) => { // prettier-ignore - return (typeof schema === 'object' && schema !== null && Kind in schema && schema[Kind] === 'Kind' && '$id' in schema && typeof schema.$id === 'string') + return (typeof schema === 'object' && schema !== null && Symbols.Kind in schema && schema[Symbols.Kind] === 'Kind' && '$id' in schema && typeof schema.$id === 'string') ? (() => { stack.push(schema.$id); return true })() : false }) - const A = { [Kind]: 'Kind', $id: 'A' } as TSchema - const B = { [Kind]: 'Kind', $id: 'B' } as TSchema + const A = { [Symbols.Kind]: 'Kind', $id: 'A' } as TSchema + const B = { [Symbols.Kind]: 'Kind', $id: 'B' } as TSchema const T = Type.Object({ a: A, b: B }) const R = Value.Check(T, { a: null, b: null }) Assert.IsTrue(R) @@ -71,14 +71,14 @@ describe('value/check/Kind', () => { let stack: string[] = [] TypeRegistry.Set('Kind', (schema: unknown) => { // prettier-ignore - return (typeof schema === 'object' && schema !== null && Kind in schema && schema[Kind] === 'Kind' && '$id' in schema && typeof schema.$id === 'string') + return (typeof schema === 'object' && schema !== null && Symbols.Kind in schema && schema[Symbols.Kind] === 'Kind' && '$id' in schema && typeof schema.$id === 'string') ? (() => { stack.push(schema.$id); return true })() : false }) - const A = { [Kind]: 'Kind', $id: 'A' } as TSchema - const B = { [Kind]: 'Kind', $id: 'B' } as TSchema - const C = { [Kind]: 'Kind', $id: 'C' } as TSchema - const D = { [Kind]: 'Kind', $id: 'D' } as TSchema + const A = { [Symbols.Kind]: 'Kind', $id: 'A' } as TSchema + const B = { [Symbols.Kind]: 'Kind', $id: 'B' } as TSchema + const C = { [Symbols.Kind]: 'Kind', $id: 'C' } as TSchema + const D = { [Symbols.Kind]: 'Kind', $id: 'D' } as TSchema const T1 = Type.Object({ a: A, b: B }) const T2 = Type.Object({ a: C, b: D }) // run T1 check diff --git a/test/runtime/value/convert/kind.ts b/test/runtime/value/convert/kind.ts index 116178c9b..8afcdfec2 100644 --- a/test/runtime/value/convert/kind.ts +++ b/test/runtime/value/convert/kind.ts @@ -1,5 +1,5 @@ import { Value } from '@sinclair/typebox/value' -import { TypeRegistry, Kind, TSchema } from '@sinclair/typebox' +import { TypeRegistry, Symbols, TSchema } from '@sinclair/typebox' import { Assert } from '../../assert/index' describe('value/convert/Kind', () => { @@ -12,27 +12,27 @@ describe('value/convert/Kind', () => { // Test // --------------------------------------------------------- it('Should not convert value 1', () => { - const T = { [Kind]: 'Kind' } as TSchema + const T = { [Symbols.Kind]: 'Kind' } as TSchema const R = Value.Convert(T, true) Assert.IsEqual(R, true) }) it('Should not convert value 2', () => { - const T = { [Kind]: 'Kind' } as TSchema + const T = { [Symbols.Kind]: 'Kind' } as TSchema const R = Value.Convert(T, 42) Assert.IsEqual(R, 42) }) it('Should not convert value 3', () => { - const T = { [Kind]: 'Kind' } as TSchema + const T = { [Symbols.Kind]: 'Kind' } as TSchema const R = Value.Convert(T, 'hello') Assert.IsEqual(R, 'hello') }) it('Should not convert value 4', () => { - const T = { [Kind]: 'Kind' } as TSchema + const T = { [Symbols.Kind]: 'Kind' } as TSchema const R = Value.Convert(T, { x: 1 }) Assert.IsEqual(R, { x: 1 }) }) it('Should not convert value 5', () => { - const T = { [Kind]: 'Kind' } as TSchema + const T = { [Symbols.Kind]: 'Kind' } as TSchema const R = Value.Convert(T, [0, 1]) Assert.IsEqual(R, [0, 1]) }) diff --git a/test/runtime/value/create/kind.ts b/test/runtime/value/create/kind.ts index 3bb42d242..ab10bad55 100644 --- a/test/runtime/value/create/kind.ts +++ b/test/runtime/value/create/kind.ts @@ -1,5 +1,5 @@ import { Value } from '@sinclair/typebox/value' -import { Type, Kind, TypeRegistry } from '@sinclair/typebox' +import { Type, Symbols, TypeRegistry } from '@sinclair/typebox' import { Assert } from '../../assert/index' describe('value/create/Kind', () => { @@ -12,12 +12,12 @@ describe('value/create/Kind', () => { // Tests // --------------------------------------------------------- it('Should create custom value with default', () => { - const T = Type.Unsafe({ [Kind]: 'Kind', default: 'hello' }) + const T = Type.Unsafe({ [Symbols.Kind]: 'Kind', default: 'hello' }) Assert.IsEqual(Value.Create(T), 'hello') }) it('Should throw when no default value is specified', () => { TypeRegistry.Set('Kind', () => true) - const T = Type.Unsafe({ [Kind]: 'Kind' }) + const T = Type.Unsafe({ [Symbols.Kind]: 'Kind' }) Assert.Throws(() => Value.Create(T)) }) }) diff --git a/test/runtime/value/transform/unsafe.ts b/test/runtime/value/transform/unsafe.ts index f679e01c9..3fa6b5aa7 100644 --- a/test/runtime/value/transform/unsafe.ts +++ b/test/runtime/value/transform/unsafe.ts @@ -1,7 +1,7 @@ import * as Encoder from './_encoder' import { Assert } from '../../assert' import { Value } from '@sinclair/typebox/value' -import { Type, Kind, TypeRegistry } from '@sinclair/typebox' +import { Type, Symbols, TypeRegistry } from '@sinclair/typebox' describe('value/transform/Unsafe', () => { // -------------------------------------------------------- @@ -9,7 +9,7 @@ describe('value/transform/Unsafe', () => { // -------------------------------------------------------- beforeEach(() => TypeRegistry.Set('Foo', (schema, value) => value !== null)) // throw on null afterEach(() => TypeRegistry.Delete('Foo')) - const Foo = Type.Unsafe({ [Kind]: 'Foo' }) + const Foo = Type.Unsafe({ [Symbols.Kind]: 'Foo' }) // -------------------------------------------------------- // Identity // -------------------------------------------------------- diff --git a/test/static/indexed.ts b/test/static/indexed.ts index a33af5130..fe5875b7b 100644 --- a/test/static/indexed.ts +++ b/test/static/indexed.ts @@ -54,13 +54,13 @@ import { Type, Static } from '@sinclair/typebox' const A = Type.Object({}) const R = Type.Index(A, Type.BigInt()) // Support Overload type O = Static - Expect(R).ToStatic() + Expect(R).ToStaticNever() } { const A = Type.Array(Type.Number()) const R = Type.Index(A, Type.BigInt()) // Support Overload type O = Static - Expect(R).ToStatic() + Expect(R).ToStaticNever() } // ------------------------------------------------------------------ // Intersections @@ -174,6 +174,9 @@ import { Type, Static } from '@sinclair/typebox' const D = Type.Object({ x: Type.String() }) const I = Type.Intersect([Type.Intersect([A, B]), Type.Intersect([C, D])]) const R = Type.Index(I, ['x', 'y']) + + // TUnion<[TIntersect<[TIntersect<[TString, TNumber]>, TIntersect<[TString, TString]>]>, TIntersect<[TIntersect<[TLiteral<...>, TNumber]>, TNumber]>]> + // TUnion<[TUnion<[TString, TNumber, TString, TString]>, TUnion<[TLiteral<1>, TNumber, TNumber]>]> type O = Static Expect(R).ToStatic<1>() } @@ -191,6 +194,10 @@ import { Type, Static } from '@sinclair/typebox' const D = Type.Object({ x: Type.String() }) const I = Type.Intersect([Type.Union([A, B]), Type.Intersect([C, D])]) const R = Type.Index(I, ['x', 'y']) + + // TUnion<[TIntersect<[TUnion<[TString, TNumber]>, TIntersect<[TString, TIntersect<[TString, TIntersect<[]>]>, TIntersect<[]>]>]>, TIntersect<...>]> + // TUnion<[TIntersect<[TUnion<[TString, TNumber]>, TIntersect<[TString, TString]>]>, TIntersect<[TUnion<[TLiteral<1>, TNumber]>, TNumber]>]> + // TUnion<[TIntersect<[TUnion<[TString, TNumber]>, TString, TString]>, TIntersect<[TUnion<[TLiteral<1>, TNumber]>, TNumber]>]> type O = Static Expect(R).ToStatic() } @@ -207,7 +214,7 @@ import { Type, Static } from '@sinclair/typebox' const C = Type.Object({ x: Type.Literal('C'), y: Type.Number() }) const D = Type.Object({ x: Type.Literal('D') }) const I = Type.Union([A, B, C, D]) - const R = Type.Index(I, Type.Union([Type.Literal('x')])) + const R = Type.Index(I, ['x']) type O = Static Expect(R).ToStatic<'A' | 'B' | 'C' | 'D'>() } @@ -243,7 +250,7 @@ import { Type, Static } from '@sinclair/typebox' } { const T = Type.Object({ - 0: Type.Number(), + '0': Type.Number(), '1': Type.String(), }) const R = Type.Index(T, Type.KeyOf(T)) @@ -257,3 +264,13 @@ import { Type, Static } from '@sinclair/typebox' }) Expect(R).ToStatic<{ x: number | string }>() } +{ + const T = Type.Array(Type.String()) + const I = Type.Index(T, Type.Number()) + Expect(I).ToStatic() +} +{ + const T = Type.Array(Type.String()) + const I = Type.Index(T, ['[number]']) + Expect(I).ToStatic() +} diff --git a/test/static/transform.ts b/test/static/transform.ts index 917628a67..1f4176289 100644 --- a/test/static/transform.ts +++ b/test/static/transform.ts @@ -215,12 +215,12 @@ import { Expect } from './assert' // should decode within generic function context // https://github.com/sinclairzx81/typebox/issues/554 // prettier-ignore - const ArrayOrSingle = (schema: T) => - Type.Transform(Type.Union([schema, Type.Array(schema)])) - .Decode((value) => (Array.isArray(value) ? value : [value])) - .Encode((value) => (value.length === 1 ? value[0] : value) as Static[]); - const T = ArrayOrSingle(Type.String()) - Expect(T).ToStaticDecode() + // const ArrayOrSingle = (schema: T) => + // Type.Transform(Type.Union([schema, Type.Array(schema)])[0]) + // .Decode((value) => (Array.isArray(value) ? value : [value])) + // .Encode((value) => (value.length === 1 ? value[0] : value) as Static[]); + // const T = ArrayOrSingle(Type.String()) + // Expect(T).ToStaticDecode() } { // should correctly decode record keys diff --git a/todo.md b/todo.md new file mode 100644 index 000000000..15f842e1a --- /dev/null +++ b/todo.md @@ -0,0 +1,7 @@ +- TemplateLiteral need to be able to compose with themselves. This works + for general composition (i think) but not for key generation. +- Investigate Transform Issue: https://github.com/sinclairzx81/typebox/issues/554 +- Clean up Composite (Should technically support Intersect and Union) +- Exclude, Extract and Extends could use a clean up +- Look for invalid import references +- The Symbols Change May be a bit too breaking. Move Kind, Hint, and others to the top (again) \ No newline at end of file diff --git a/tsconfig.json b/tsconfig.json index ec148af39..1ef1b8be9 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -16,6 +16,9 @@ "@sinclair/typebox/system": [ "src/system/index.ts" ], + "@sinclair/typebox/type": [ + "src/type/index.ts" + ], "@sinclair/typebox/value/cast": [ "src/value/cast.ts" ], @@ -56,7 +59,7 @@ "src/value/index.ts" ], "@sinclair/typebox": [ - "src/typebox.ts" + "src/index.ts" ], } }