From e4e5335bf32eaba18dfaae5719a3c800ebbdf63b Mon Sep 17 00:00:00 2001 From: sinclair Date: Tue, 28 Nov 2023 16:35:46 +0900 Subject: [PATCH] Esm --- examples/index.ts | 3 +- src/type/exclude/exclude.ts | 4 +- src/type/extends/extends-check.ts | 4 +- src/type/extract/extract.ts | 4 +- src/type/index.ts | 1 - src/type/indexed/indexed-key.ts | 10 +- src/type/intrinsic/intrinsic.ts | 8 +- src/type/record/record.ts | 32 ++- src/type/template-literal/finite.ts | 93 ++++---- .../{generator.ts => generate.ts} | 98 ++++---- src/type/template-literal/index.ts | 3 +- src/type/template-literal/parser.ts | 219 ++++++++++-------- src/type/template-literal/static.ts | 54 ----- src/type/template-literal/template-literal.ts | 28 ++- src/type/template-literal/union.ts | 20 +- src/value/create.ts | 6 +- test/runtime/type/template/finite.ts | 52 ++--- test/runtime/type/template/generate.ts | 150 ++++++------ test/runtime/type/template/parser.ts | 80 +++---- 19 files changed, 437 insertions(+), 432 deletions(-) rename src/type/template-literal/{generator.ts => generate.ts} (63%) delete mode 100644 src/type/template-literal/static.ts diff --git a/examples/index.ts b/examples/index.ts index b56cec78..b099b39c 100644 --- a/examples/index.ts +++ b/examples/index.ts @@ -1,4 +1,3 @@ import { String } from '@sinclair/typebox/type' -console.log(String) -console.log('hello') +console.log(String()) diff --git a/src/type/exclude/exclude.ts b/src/type/exclude/exclude.ts index 7b75b86e..5f85be1a 100644 --- a/src/type/exclude/exclude.ts +++ b/src/type/exclude/exclude.ts @@ -60,8 +60,8 @@ export type ExcludeResolve = // prettier-ignore export function ExcludeResolve(L: L, R: R): ExcludeResolve { 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)) diff --git a/src/type/extends/extends-check.ts b/src/type/extends/extends-check.ts index b0ea697d..5990af9f 100644 --- a/src/type/extends/extends-check.ts +++ b/src/type/extends/extends-check.ts @@ -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') ) } diff --git a/src/type/extract/extract.ts b/src/type/extract/extract.ts index 9c08e868..f001ec37 100644 --- a/src/type/extract/extract.ts +++ b/src/type/extract/extract.ts @@ -63,8 +63,8 @@ export type ExtractResolve = ( // prettier-ignore export function ExtractResolve(L: L, R: R): ExtractResolve { 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)) diff --git a/src/type/index.ts b/src/type/index.ts index 119dc3fe..a270ca86 100644 --- a/src/type/index.ts +++ b/src/type/index.ts @@ -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' diff --git a/src/type/indexed/indexed-key.ts b/src/type/indexed/indexed-key.ts index 0c6ec23a..d8bbe5a3 100644 --- a/src/type/indexed/indexed-key.ts +++ b/src/type/indexed/indexed-key.ts @@ -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' @@ -38,16 +38,16 @@ import { TTemplateLiteral as IsTemplateLiteralType, TUnionLiteral as IsUnionLite // FromTemplateLiteral // ---------------------------------------------------------------- // prettier-ignore -type FromTemplateLiteral> = ( +type FromTemplateLiteral> = ( F extends true ? TemplateLiteralGenerate extends infer R extends string[] ? R : [] : [] ) // prettier-ignore function FromTemplateLiteral(T: T): FromTemplateLiteral { - 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) diff --git a/src/type/intrinsic/intrinsic.ts b/src/type/intrinsic/intrinsic.ts index d6cf2c36..824a6a07 100644 --- a/src/type/intrinsic/intrinsic.ts +++ b/src/type/intrinsic/intrinsic.ts @@ -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' @@ -69,10 +69,10 @@ export namespace IntrinsicResolver { 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 = 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) diff --git a/src/type/record/record.ts b/src/type/record/record.ts index 70b47bab..edc43644 100644 --- a/src/type/record/record.ts +++ b/src/type/record/record.ts @@ -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' @@ -62,18 +62,21 @@ export namespace RecordResolver { // FromTemplateLiteralKey (Fast Inference) // ---------------------------------------------------------------- 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 = 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 } // ---------------------------------------------------------------- @@ -83,35 +86,44 @@ export namespace RecordResolver { // ---------------------------------------------------------------- // 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> = ( TRecord ) + // prettier-ignore export function FromStringKey(K: K, T: T): FromStringKey { const pattern = IsUndefined(K.pattern) ? PatternStringExact : K.pattern return FromPattern(pattern, T) as FromStringKey @@ -119,24 +131,29 @@ export namespace RecordResolver { // ---------------------------------------------------------------- // FromIntegerKey // ---------------------------------------------------------------- + // prettier-ignore export type FromIntegerKey<_ extends TSchema, T extends TSchema> = ( TRecord ) + // 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> = ( TRecord ) + // prettier-ignore export function FromNumberKey(_: K, T: T): FromIntegerKey { return FromPattern(PatternNumberExact, T) as FromIntegerKey } // ---------------------------------------------------------------- // Resolve // ---------------------------------------------------------------- + // prettier-ignore export type Resolve = K extends TEnum ? FromEnumKey : // (Special: Ensure resolve Enum before Union) K extends TUnion ? FromUnionKey : @@ -146,6 +163,7 @@ export namespace RecordResolver { K extends TNumber ? FromNumberKey : K extends TString ? FromStringKey : TNever + // prettier-ignore export function Resolve(K: K, T: T): Resolve { return ( IsUnionType(K) ? FromUnionKey(K.anyOf, T) : @@ -158,7 +176,9 @@ export namespace RecordResolver { ) as unknown as Resolve } } - +// ------------------------------------------------------------------ +// TRecord +// ------------------------------------------------------------------ export interface TRecord extends TSchema { [Symbols.Kind]: 'Record' static: Record, string | number>, Static> diff --git a/src/type/template-literal/finite.ts b/src/type/template-literal/finite.ts index 22b556a4..5e30d049 100644 --- a/src/type/template-literal/finite.ts +++ b/src/type/template-literal/finite.ts @@ -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 = +function IsStringExpression(expression: Expression) { + return expression.type === 'const' && expression.const === '.*' +} +// ------------------------------------------------------------------ +// IsTemplateLiteralFinite +// ------------------------------------------------------------------ +// prettier-ignore +type IsTemplateLiteralFiniteCheck = T extends TTemplateLiteral ? IsTemplateLiteralFiniteArray : T extends TUnion ? IsTemplateLiteralFiniteArray : T extends TString ? false : @@ -51,7 +81,7 @@ export type IsTemplateLiteralFiniteCheck = T extends TLiteral ? true : false // prettier-ignore -export type IsTemplateLiteralFiniteArray = +type IsTemplateLiteralFiniteArray = T extends [infer L extends TTemplateLiteralKind, ...infer R extends TTemplateLiteralKind[]] ? IsTemplateLiteralFiniteCheck extends false ? false @@ -62,47 +92,14 @@ export type IsTemplateLiteralFinite = T extends TTemplateLiteral ? IsTemplateLiteralFiniteArray : 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`) })() + ) } diff --git a/src/type/template-literal/generator.ts b/src/type/template-literal/generate.ts similarity index 63% rename from src/type/template-literal/generator.ts rename to src/type/template-literal/generate.ts index 0bb9acb1..58715ee3 100644 --- a/src/type/template-literal/generator.ts +++ b/src/type/template-literal/generate.ts @@ -26,56 +26,84 @@ THE SOFTWARE. ---------------------------------------------------------------------------*/ -import type { TTemplateLiteral, TTemplateLiteralKind } from '../template-literal/index' +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' -import { TemplateLiteralParser } from './parser' // ------------------------------------------------------------------ -// Static: String Reduce +// StringReducers // ------------------------------------------------------------------ // StringReduceUnary<"A", ["B", "C"]> -> ["AB", "AC"] // prettier-ignore -export type StringReduceUnary = +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 -export type StringReduceBinary = +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 -export type StringReduceMany = +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 -export type StringReduce> = +type StringReduce> = 0 extends keyof O ? O[0] : [] -// ------------------------------------------------------------------ -// Static: Template Literal Generate -// ------------------------------------------------------------------ // prettier-ignore -export type TemplateLiteralReduceUnion = +type TemplateLiteralReduceUnion = T extends [infer L extends TLiteral, ...infer R extends TLiteral[]] ? [L['const'], ...TemplateLiteralReduceUnion] : [] // prettier-ignore -export type TemplateLiteralReduce = +type TemplateLiteralReduce = T extends [infer L extends TTemplateLiteralKind, ...infer R extends TTemplateLiteralKind[]] ? L extends TLiteral ? [[S], ...TemplateLiteralReduce] : - L extends TUnion ? [TemplateLiteralReduceUnion, ...TemplateLiteralReduce] : - [] + L extends TUnion + ? [TemplateLiteralReduceUnion, ...TemplateLiteralReduce] + : [] : [] + +// ------------------------------------------------------------------ +// TemplateLiteralExpressionGenerate +// ------------------------------------------------------------------ +// 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 +} +// ------------------------------------------------------------------ +// TemplateLiteralGenerate +// ------------------------------------------------------------------ +export class TemplateLiteralGenerateError extends Error {} + // prettier-ignore export type TemplateLiteralGenerate = T extends TTemplateLiteral @@ -83,35 +111,15 @@ export type TemplateLiteralGenerate = ? StringReduce : [] : [] -// ------------------------------------------------------------------------------ -// Runtime: TemplateLiteralGenerator -// ------------------------------------------------------------------------------ -export class TemplateLiteralGeneratorError extends Error {} -// prettier-ignore -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 { - return ( - expression.type === 'and' ? yield* And(expression) : - expression.type === 'or' ? yield* Or(expression) : - expression.type === 'const' ? yield* Const(expression) : - (() => { throw new TemplateLiteralGeneratorError('Unknown expression') })() - ) - } + +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 index d6626c6b..79501f95 100644 --- a/src/type/template-literal/index.ts +++ b/src/type/template-literal/index.ts @@ -27,10 +27,9 @@ THE SOFTWARE. ---------------------------------------------------------------------------*/ export * from './finite' -export * from './generator' +export * from './generate' export * from './syntax' export * from './parser' export * from './pattern' -export * from './static' export * from './union' export * from './template-literal' diff --git a/src/type/template-literal/parser.ts b/src/type/template-literal/parser.ts index 3f91c8ca..fe6279d7 100644 --- a/src/type/template-literal/parser.ts +++ b/src/type/template-literal/parser.ts @@ -29,119 +29,134 @@ THE SOFTWARE. // ------------------------------------------------------------------ // TemplateLiteralParser // ------------------------------------------------------------------ -export class TemplateLiteralParserError extends Error {} // prettier-ignore -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, '(') +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 } - function IsCloseParen(pattern: string, index: number) { - return IsNonEscaped(pattern, index, ')') + 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 } - function IsSeparator(pattern: string, index: number) { - return IsNonEscaped(pattern, index, '|') + return false +} +// prettier-ignore +function IsPrecedenceAnd(pattern: string) { + for (let index = 0; index < pattern.length; index++) { + if (IsOpenParen(pattern, index)) return true } - 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 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 } - return true - } - function InGroup(pattern: string) { - return pattern.slice(1, pattern.length - 1) } - function IsPrecedenceOr(pattern: string) { + 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 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 + 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] } - return false + throw new TemplateLiteralParserError(`TemplateLiteralParser: Unclosed group parens in expression`) } - 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 - } + function Range(pattern: string, index: number): [number, number] { + for (let scan = index; scan < pattern.length; scan++) { + if (IsOpenParen(pattern, scan)) return [index, scan] } - 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 } + return [index, pattern.length] } - 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 - } + 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 */ - export function Parse(pattern: string): Expression { - 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)) } + return ( + (expressions.length === 0) ? { type: 'const', const: '' } : + (expressions.length === 1) ? expressions[0] : + { type: 'and', expr: expressions } + ) +} +// ------------------------------------------------------------------ +// TemplateLiteralParse +// ------------------------------------------------------------------ +export class TemplateLiteralParserError extends Error {} + +/** 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/static.ts b/src/type/template-literal/static.ts deleted file mode 100644 index 1934952b..00000000 --- a/src/type/template-literal/static.ts +++ /dev/null @@ -1,54 +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. - ----------------------------------------------------------------------------*/ - -import type { TTemplateLiteral, TTemplateLiteralKind } from '../template-literal/index' -import type { Static } from '../static/index' -import type { TUnion } from '../union/index' -import type { TLiteral } from '../literal/index' -import type { TBoolean } from '../boolean/index' -import type { TBigInt } from '../bigint/index' -import type { TNumber } from '../number/index' -import type { TString } from '../string/index' -import type { Assert } from '../helpers/index' - -// prettier-ignore -export namespace TemplateLiteralStatic { - export type TTemplateLiteralConst = - T extends TUnion ? { [K in keyof U]: Resolve, 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 Resolve = - T extends [infer L, ...infer R] ? `${TTemplateLiteralConst}${Resolve, Acc>}` : - Acc -} diff --git a/src/type/template-literal/template-literal.ts b/src/type/template-literal/template-literal.ts index 9222cc0a..013b1742 100644 --- a/src/type/template-literal/template-literal.ts +++ b/src/type/template-literal/template-literal.ts @@ -27,6 +27,7 @@ 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' @@ -35,14 +36,35 @@ 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 { TemplateLiteralStatic } from './static' 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 + +// ------------------------------------------------------------------ +// TemplateLiteral +// ------------------------------------------------------------------ // prettier-ignore export type TTemplateLiteralKind = | TTemplateLiteral @@ -54,9 +76,11 @@ export type TTemplateLiteralKind = | TString | TBoolean | TNever + +// prettier-ignore export interface TTemplateLiteral extends TSchema { [Symbols.Kind]: 'TemplateLiteral' - static: TemplateLiteralStatic.Resolve + static: TemplateLiteralResolve type: 'string' pattern: string // todo: it may be possible to infer this pattern } diff --git a/src/type/template-literal/union.ts b/src/type/template-literal/union.ts index f284cd77..a08a7376 100644 --- a/src/type/template-literal/union.ts +++ b/src/type/template-literal/union.ts @@ -31,19 +31,17 @@ 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 { TemplateLiteralGenerator } from './generator' -import { TemplateLiteralParser } from './parser' -import { TemplateLiteralFinite } from './finite' +import { TemplateLiteralGenerate } from './generate' +import { TemplateLiteralParseExact } from './parser' +import { IsTemplateLiteralFinite } from './finite' // ------------------------------------------------------------------------------ // TemplateLiteralToUnion // ------------------------------------------------------------------------------ -export namespace TemplateLiteralToUnion { - /** Resolves a template literal as a TUnion */ - export function Resolve(template: TTemplateLiteral): TNever | TString | TUnion { - const expression = TemplateLiteralParser.ParseExact(template.pattern) - if (!TemplateLiteralFinite.Check(expression)) return String() - const literals = [...TemplateLiteralGenerator.Generate(expression)].map((value) => Literal(value)) - return Union(literals) - } +/** 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/value/create.ts b/src/value/create.ts index 1c229dd3..a1fa0354 100644 --- a/src/value/create.ts +++ b/src/value/create.ts @@ -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 { diff --git a/test/runtime/type/template/finite.ts b/test/runtime/type/template/finite.ts index 0eb8fa1f..11df3004 100644 --- a/test/runtime/type/template/finite.ts +++ b/test/runtime/type/template/finite.ts @@ -1,71 +1,71 @@ -import { TemplateLiteralParser, TemplateLiteralFinite, PatternString, PatternBoolean, PatternNumber } from '@sinclair/typebox/type' +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 6ec65932..53a3404f 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/type' +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 1e05b650..34dafcd1 100644 --- a/test/runtime/type/template/parser.ts +++ b/test/runtime/type/template/parser.ts @@ -1,4 +1,4 @@ -import { TemplateLiteralParser } from '@sinclair/typebox/type' +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: [