Skip to content

Commit

Permalink
Esm
Browse files Browse the repository at this point in the history
  • Loading branch information
sinclairzx81 committed Nov 28, 2023
1 parent 9a44521 commit e4e5335
Show file tree
Hide file tree
Showing 19 changed files with 437 additions and 432 deletions.
3 changes: 1 addition & 2 deletions examples/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import { String } from '@sinclair/typebox/type'

console.log(String)
console.log('hello')
console.log(String())
4 changes: 2 additions & 2 deletions src/type/exclude/exclude.ts
Original file line number Diff line number Diff line change
Expand Up @@ -60,8 +60,8 @@ export type ExcludeResolve<T extends TSchema, U extends TSchema> =
// prettier-ignore
export function ExcludeResolve<L extends TSchema, R extends TSchema>(L: L, R: R): ExcludeResolve<L, R> {
return (
IsTemplateLiteralType(L) ? ExcludeResolve(TemplateLiteralToUnion.Resolve(L), R) :
IsTemplateLiteralType(R) ? ExcludeResolve(L, TemplateLiteralToUnion.Resolve(R)) :
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))
Expand Down
4 changes: 2 additions & 2 deletions src/type/extends/extends-check.ts
Original file line number Diff line number Diff line change
Expand Up @@ -595,8 +595,8 @@ function TTemplateLiteral(left: TSchema, right: TSchema) {
// for infinite expressions. Here we call to TemplateLiteralResolver to resolve for
// either type and continue evaluating.
return (
TypeGuard.TTemplateLiteral(left) ? Visit(TemplateLiteralToUnion.Resolve(left), right) :
TypeGuard.TTemplateLiteral(right) ? Visit(left, TemplateLiteralToUnion.Resolve(right)) :
TypeGuard.TTemplateLiteral(left) ? Visit(TemplateLiteralToUnion(left), right) :
TypeGuard.TTemplateLiteral(right) ? Visit(left, TemplateLiteralToUnion(right)) :
Throw('Invalid fallthrough for TemplateLiteral')
)
}
Expand Down
4 changes: 2 additions & 2 deletions src/type/extract/extract.ts
Original file line number Diff line number Diff line change
Expand Up @@ -63,8 +63,8 @@ export type ExtractResolve<T extends TSchema, U extends TSchema> = (
// prettier-ignore
export function ExtractResolve<L extends TSchema, R extends TSchema>(L: L, R: R): ExtractResolve<L, R> {
return (
IsTemplateLiteralType(L) ? ExtractResolve(TemplateLiteralToUnion.Resolve(L), R) :
IsTemplateLiteralType(R) ? ExtractResolve(L, TemplateLiteralToUnion.Resolve(R) as any) :
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))
Expand Down
1 change: 0 additions & 1 deletion src/type/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,6 @@ THE SOFTWARE.
// export { type TRecursive, type TThis, Recursive } from './recursive/index'
// export { type TRef, Ref } from './ref/index'
// export { type TRegExp, RegExp } from './regexp/index'

// export { type TRequired, Required } from './required/index'
// export { type TRest, Rest } from './rest/index'
// export { type TReturnType, ReturnType } from './return-type/index'
Expand Down
10 changes: 5 additions & 5 deletions src/type/indexed/indexed-key.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ THE SOFTWARE.
---------------------------------------------------------------------------*/

import { type TTemplateLiteral, TemplateLiteralGenerate, TemplateLiteralParser, TemplateLiteralFinite, TemplateLiteralToUnion, IsTemplateLiteralFiniteCheck } from '../template-literal/index'
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'
Expand All @@ -38,16 +38,16 @@ import { TTemplateLiteral as IsTemplateLiteralType, TUnionLiteral as IsUnionLite
// FromTemplateLiteral
// ----------------------------------------------------------------
// prettier-ignore
type FromTemplateLiteral<T extends TTemplateLiteral, F = IsTemplateLiteralFiniteCheck<T>> = (
type FromTemplateLiteral<T extends TTemplateLiteral, F = IsTemplateLiteralFinite<T>> = (
F extends true
? TemplateLiteralGenerate<T> extends infer R extends string[] ? R : []
: []
)
// prettier-ignore
function FromTemplateLiteral<T extends TTemplateLiteral>(T: T): FromTemplateLiteral<T> {
const E = TemplateLiteralParser.ParseExact(T.pattern)
const F = TemplateLiteralFinite.Check(E)
const S = TemplateLiteralToUnion.Resolve(T)
const E = TemplateLiteralParseExact(T.pattern)
const F = IsTemplateLiteralFinite(E)
const S = TemplateLiteralToUnion(T)
return (
F === true
? IsUnionLiteralType(S)
Expand Down
8 changes: 4 additions & 4 deletions src/type/intrinsic/intrinsic.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ THE SOFTWARE.
---------------------------------------------------------------------------*/

import type { TSchema, SchemaOptions } from '../schema/index'
import { type TTemplateLiteral, type TTemplateLiteralKind, TemplateLiteral, TemplateLiteralParser, TemplateLiteralFinite, TemplateLiteralGenerator } from '../template-literal/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 { CloneType } from '../clone/type'
Expand Down Expand Up @@ -69,10 +69,10 @@ export namespace IntrinsicResolver {
function FromTemplateLiteral<T extends TTemplateLiteralKind[], M extends IntrinsicMode>(schema: TTemplateLiteral, mode: IntrinsicMode): FromTemplateLIteral<T, M> {
// 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)
const expression = TemplateLiteralParseExact(schema.pattern)
const finite = IsTemplateLiteralFinite(expression)
if (!finite) return { ...schema, pattern: FromLiteralValue(schema.pattern, mode) } as any
const strings = [...TemplateLiteralGenerator.Generate(expression)]
const strings = [...TemplateLiteralGenerate(expression)]
const literals = strings.map((value) => Literal(value))
const mapped = FromRest(literals as any, mode)
const union = Union(mapped)
Expand Down
32 changes: 26 additions & 6 deletions src/type/record/record.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ import { type TInteger } from '../integer/index'
import { type TNumber } from '../number/index'
import { type TEnum } from '../enum/index'

import { TTemplateLiteral, IsTemplateLiteralFinite, TemplateLiteralFinite, TemplateLiteralParser } from '../template-literal/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'
Expand All @@ -62,18 +62,21 @@ export namespace RecordResolver {
// FromTemplateLiteralKey (Fast Inference)
// ----------------------------------------------------------------
export type FromTemplateLiteralKeyInfinite<_ extends TTemplateLiteral, T extends TSchema> = Ensure<TRecord<TString, T>>
// prettier-ignore
export type FromTemplateLiteralKeyFinite<K extends TTemplateLiteral, T extends TSchema, I extends string = Static<K>> = (
Ensure<TObject<Evaluate<{ [_ in I]: T }>>>
)
// prettier-ignore
export type FromTemplateLiteralKey<K extends TTemplateLiteral, T extends TSchema> = IsTemplateLiteralFinite<K> extends false
? FromTemplateLiteralKeyInfinite<K, T>
: FromTemplateLiteralKeyFinite<K, T>
// prettier-ignore
export function FromTemplateLiteralKey<K extends TTemplateLiteral, T extends TSchema>(K: K, T: T): FromTemplateLiteralKey<K, T> {
const expression = TemplateLiteralParser.ParseExact(K.pattern)
const expression = TemplateLiteralParseExact(K.pattern)
return (
TemplateLiteralFinite.Check(expression)
? FromKeys(IndexedKeyResolve(K), T)
: FromPattern(K.pattern, T)
IsTemplateLiteralFinite(expression)
? FromKeys(IndexedKeyResolve(K), T)
: FromPattern(K.pattern, T)
) as FromTemplateLiteralKey<K, T>
}
// ----------------------------------------------------------------
Expand All @@ -83,60 +86,74 @@ export namespace RecordResolver {
// ----------------------------------------------------------------
// FromUnionKey
// ----------------------------------------------------------------
// prettier-ignore
export type FromUnionKeyLiteralString<K extends TLiteral<string>, T extends TSchema> = { [_ in K['const']]: T }
// prettier-ignore
export type FromUnionKeyLiteralNumber<K extends TLiteral<number>, T extends TSchema> = { [_ in K['const']]: T }
// prettier-ignore
export type FromUnionKeyRest<K extends TSchema[], T extends TSchema> =
K extends [infer L extends TSchema, ...infer R extends TSchema[]] ? (
L extends TUnion<infer S> ? FromUnionKeyRest<S, T> & FromUnionKeyRest<R, T> :
L extends TLiteral<string> ? FromUnionKeyLiteralString<L, T> & FromUnionKeyRest<R, T> :
L extends TLiteral<number> ? FromUnionKeyLiteralNumber<L, T> & FromUnionKeyRest<R, T> :
{}) : {}
// prettier-ignore
export type FromUnionKey<K extends TSchema[], T extends TSchema, P extends TProperties = FromUnionKeyRest<K, T>> = (
Ensure<TObject<P>>
)
// prettier-ignore
export function FromUnionKey<K extends TSchema[], T extends TSchema>(K: K, T: T): FromUnionKey<K, T> {
return FromKeys(IndexedKeyResolve(Union(K)), T) as FromUnionKey<K, T>
}
// ----------------------------------------------------------------
// FromLiteralKey
// ----------------------------------------------------------------
// prettier-ignore
export type FromLiteralKey<K extends TLiteralValue, T extends TSchema> = (
Ensure<TObject<{ [_ in Assert<K, PropertyKey>]: T }>>
)
// prettier-ignore
export function FromLiteralKey<K extends TLiteralValue, T extends TSchema>(K: K, T: T): FromLiteralKey<K, T> {
return FromKeys([K.toString()], T) as FromLiteralKey<K, T>
}
// ----------------------------------------------------------------
// FromStringKey
// ----------------------------------------------------------------
// prettier-ignore
export type FromStringKey<_ extends TString, T extends TSchema> = (
TRecord<TString, T>
)
// prettier-ignore
export function FromStringKey<K extends TString, T extends TSchema>(K: K, T: T): FromStringKey<K, T> {
const pattern = IsUndefined(K.pattern) ? PatternStringExact : K.pattern
return FromPattern(pattern, T) as FromStringKey<K, T>
}
// ----------------------------------------------------------------
// FromIntegerKey
// ----------------------------------------------------------------
// prettier-ignore
export type FromIntegerKey<_ extends TSchema, T extends TSchema> = (
TRecord<TNumber, T>
)
// prettier-ignore
export function FromIntegerKey<K extends TInteger, T extends TSchema>(_: K, T: T): FromIntegerKey<K, T> {
return FromPattern(PatternNumberExact, T) as FromIntegerKey<K, T>
}
// ----------------------------------------------------------------
// FromNumberKey
// ----------------------------------------------------------------
// prettier-ignore
export type FromNumberKey<_ extends TSchema, T extends TSchema> = (
TRecord<TNumber, T>
)
// prettier-ignore
export function FromNumberKey<K extends TNumber, T extends TSchema>(_: K, T: T): FromIntegerKey<K, T> {
return FromPattern(PatternNumberExact, T) as FromIntegerKey<K, T>
}
// ----------------------------------------------------------------
// Resolve
// ----------------------------------------------------------------
// prettier-ignore
export type Resolve<K extends TSchema, T extends TSchema> =
K extends TEnum<infer S> ? FromEnumKey<S, T> : // (Special: Ensure resolve Enum before Union)
K extends TUnion<infer S> ? FromUnionKey<S, T> :
Expand All @@ -146,6 +163,7 @@ export namespace RecordResolver {
K extends TNumber ? FromNumberKey<K, T> :
K extends TString ? FromStringKey<K, T> :
TNever
// prettier-ignore
export function Resolve<K extends TSchema, T extends TSchema>(K: K, T: T): Resolve<K, T> {
return (
IsUnionType(K) ? FromUnionKey(K.anyOf, T) :
Expand All @@ -158,7 +176,9 @@ export namespace RecordResolver {
) as unknown as Resolve<K, T>
}
}

// ------------------------------------------------------------------
// TRecord
// ------------------------------------------------------------------
export interface TRecord<K extends TSchema = TSchema, T extends TSchema = TSchema> extends TSchema {
[Symbols.Kind]: 'Record'
static: Record<Assert<Static<K>, string | number>, Static<T, this['params']>>
Expand Down
93 changes: 45 additions & 48 deletions src/type/template-literal/finite.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,13 +34,43 @@ 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 { TemplateLiteralParser } from './parser'
import type { Expression } from './parser'

// ------------------------------------------------------------------------------
// Static: IsTemplateLiteralFinite
// ------------------------------------------------------------------------------
// ------------------------------------------------------------------
// ExpressionChecks
// ------------------------------------------------------------------
export class TemplateLiteralFiniteError extends Error {}
// 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
export type IsTemplateLiteralFiniteCheck<T> =
function IsStringExpression(expression: Expression) {
return expression.type === 'const' && expression.const === '.*'
}
// ------------------------------------------------------------------
// IsTemplateLiteralFinite
// ------------------------------------------------------------------
// prettier-ignore
type IsTemplateLiteralFiniteCheck<T> =
T extends TTemplateLiteral<infer U extends TTemplateLiteralKind[]> ? IsTemplateLiteralFiniteArray<U> :
T extends TUnion<infer U extends TTemplateLiteralKind[]> ? IsTemplateLiteralFiniteArray<U> :
T extends TString ? false :
Expand All @@ -51,7 +81,7 @@ export type IsTemplateLiteralFiniteCheck<T> =
T extends TLiteral ? true :
false
// prettier-ignore
export type IsTemplateLiteralFiniteArray<T extends TTemplateLiteralKind[]> =
type IsTemplateLiteralFiniteArray<T extends TTemplateLiteralKind[]> =
T extends [infer L extends TTemplateLiteralKind, ...infer R extends TTemplateLiteralKind[]]
? IsTemplateLiteralFiniteCheck<L> extends false
? false
Expand All @@ -62,47 +92,14 @@ export type IsTemplateLiteralFinite<T> =
T extends TTemplateLiteral<infer U>
? IsTemplateLiteralFiniteArray<U>
: false

// ------------------------------------------------------------------------------
// Runtime: TemplateLiteralFinite
// ------------------------------------------------------------------------------
export class TemplateLiteralFiniteError extends Error {}
// prettier-ignore
export namespace TemplateLiteralFinite {
function Throw(message: string): never {
throw new TemplateLiteralFiniteError(message)
}
function IsNumber(expression: TemplateLiteralParser.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]*'
)
}
function IsBoolean(expression: TemplateLiteralParser.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'
)
}
function IsString(expression: TemplateLiteralParser.Expression) {
return expression.type === 'const' && expression.const === '.*'
}
export function Check(expression: TemplateLiteralParser.Expression): boolean {
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`)
)
}
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`) })()
)
}
Loading

0 comments on commit e4e5335

Please sign in to comment.