Revision 0.33.20 (#1062)

* Add Parse Infrastructure

* Version
This commit is contained in:
Haydn Paterson
2024-11-07 14:14:06 +09:00
committed by GitHub
parent e75af6daf0
commit 0144c8622c
27 changed files with 3175 additions and 10 deletions

View File

@@ -1,4 +1,6 @@
### 0.33.0
- [Revision 0.33.20](https://github.com/sinclairzx81/typebox/pull/1062)
- Add TypeScript Parsing Infrastructure. Add Parse API to top level import.
- [Revision 0.33.19](https://github.com/sinclairzx81/typebox/pull/1061)
- Preemptive fix for TypeScript 5.8.0-dev (Type Fix for Immutable Function)
- [Revision 0.33.18](https://github.com/sinclairzx81/typebox/pull/1060)

View File

@@ -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, Parse, TypeGuard, Kind, Static, TSchema } from '@sinclair/typebox'
// -----------------------------------------------------------
// Create: Type
@@ -17,6 +17,14 @@ type T = Static<typeof T>
console.log(T)
// -----------------------------------------------------------
// Parse: Type
// -----------------------------------------------------------
const S = Parse({ T }, `Partial<T>`)
type S = Static<typeof S>
// -----------------------------------------------------------
// Create: Value
// -----------------------------------------------------------

4
package-lock.json generated
View File

@@ -1,12 +1,12 @@
{
"name": "@sinclair/typebox",
"version": "0.33.19",
"version": "0.33.20",
"lockfileVersion": 2,
"requires": true,
"packages": {
"": {
"name": "@sinclair/typebox",
"version": "0.33.19",
"version": "0.33.20",
"license": "MIT",
"devDependencies": {
"@arethetypeswrong/cli": "^0.13.2",

View File

@@ -1,6 +1,6 @@
{
"name": "@sinclair/typebox",
"version": "0.33.19",
"version": "0.33.20",
"description": "Json Schema Type Builder with Static Type Resolution for TypeScript",
"keywords": [
"typescript",

View File

@@ -1760,11 +1760,12 @@ The following table lists esbuild compiled and minified sizes for each TypeBox m
┌──────────────────────┬────────────┬────────────┬─────────────┐
(index) Compiled Minified Compression
├──────────────────────┼────────────┼────────────┼─────────────┤
typebox/compiler '119.6 kb' ' 52.6 kb' '2.27 x'
typebox/errors ' 48.6 kb' ' 21.9 kb' '2.22 x'
typebox/compiler '119.8 kb' ' 52.6 kb' '2.28 x'
typebox/errors ' 74.4 kb' ' 33.1 kb' '2.25 x'
typebox/parse '115.3 kb' ' 48.3 kb' '2.39 x'
typebox/system ' 7.4 kb' ' 3.2 kb' '2.33 x'
typebox/value '157.8 kb' ' 66.6 kb' '2.37 x'
typebox ' 98.3 kb' ' 40.9 kb' '2.40 x'
typebox/value '157.2 kb' ' 66.1 kb' '2.38 x'
typebox '127.3 kb' ' 53.3 kb' '2.39 x'
└──────────────────────┴────────────┴────────────┴─────────────┘
```

View File

@@ -39,6 +39,10 @@ export * from './type/registry/index'
export * from './type/sets/index'
export * from './type/symbols/index'
// ------------------------------------------------------------------
// Parse
// ------------------------------------------------------------------
export * from './parse/index'
// ------------------------------------------------------------------
// Types
// ------------------------------------------------------------------
export * from './type/any/index'
@@ -102,6 +106,6 @@ export * from './type/unknown/index'
export * from './type/unsafe/index'
export * from './type/void/index'
// ------------------------------------------------------------------
// Namespace
// Type.*
// ------------------------------------------------------------------
export * from './type/type/index'

29
src/parse/index.ts Normal file
View File

@@ -0,0 +1,29 @@
/*--------------------------------------------------------------------------
@sinclair/typebox
The MIT License (MIT)
Copyright (c) 2017-2024 Haydn Paterson (sinclair) <haydn.developer@gmail.com>
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
---------------------------------------------------------------------------*/
export * from './parse'

54
src/parse/parse.ts Normal file
View File

@@ -0,0 +1,54 @@
/*--------------------------------------------------------------------------
@sinclair/typebox
The MIT License (MIT)
Copyright (c) 2017-2024 Haydn Paterson (sinclair) <haydn.developer@gmail.com>
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
---------------------------------------------------------------------------*/
import { Static } from './parsebox/index'
import { CreateType } from '../type/create/type'
import { TSchema, SchemaOptions } from '../type/schema/index'
import { Module } from './runtime'
import { Type } from './static'
/** `[Experimental]` Parses a TypeScript type annotation as an inferred TypeBox type */
export function Parse<Code extends string, Context extends Record<PropertyKey, TSchema> = {}>(context: Context, code: Code, options?: SchemaOptions): Static.Parse<Type, Code, Context>[0]
/** `[Experimental]` Parses a TypeScript type annotation as an inferred TypeBox type */
export function Parse<Code extends string>(code: Code, options?: SchemaOptions): Static.Parse<Type, Code, {}>[0]
/** `[Experimental]` Parses a TypeScript type annotation as an inferred TypeBox type */
export function Parse(...args: any[]): never {
return ParseOnly.apply(null, args as never) as never
}
/** `[Experimental]` Parses a TypeScript type annotation as TSchema */
export function ParseOnly<Code extends string, Context extends Record<PropertyKey, TSchema> = {}>(context: Context, code: Code, options?: SchemaOptions): TSchema | undefined
/** `[Experimental]` Parses a TypeScript type annotation as TSchema */
export function ParseOnly<Code extends string>(code: Code, options?: SchemaOptions): TSchema | undefined
/** `[Experimental]` Parses a TypeScript type annotation as TSchema */
export function ParseOnly(...args: any[]): TSchema | undefined {
const withContext = typeof args[0] === 'string' ? false : true
const [context, code, options] = withContext ? [args[0], args[1], args[2] || {}] : [{}, args[0], args[1] || {}]
const type = Module.Parse('Type', code, context)[0] as TSchema | undefined
return (type !== undefined ? CreateType(type, options) : undefined) as never
}

View File

@@ -0,0 +1,30 @@
/*--------------------------------------------------------------------------
@sinclair/parsebox
The MIT License (MIT)
Copyright (c) 2024 Haydn Paterson (sinclair) <haydn.developer@gmail.com>
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
---------------------------------------------------------------------------*/
export * as Runtime from './runtime/index'
export * as Static from './static/index'

View File

@@ -0,0 +1,96 @@
/*--------------------------------------------------------------------------
@sinclair/parsebox
The MIT License (MIT)
Copyright (c) 2024 Haydn Paterson (sinclair) <haydn.developer@gmail.com>
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
---------------------------------------------------------------------------*/
import { IIdent, INumber, IRef, IString, IConst, ITuple, IUnion } from './types'
// ------------------------------------------------------------------
// Value Guard
// ------------------------------------------------------------------
// prettier-ignore
function HasPropertyKey<Key extends PropertyKey>(value: Record<PropertyKey, unknown>, key: Key): value is Record<PropertyKey, unknown> & { [_ in Key]: unknown } {
return key in value
}
// prettier-ignore
function IsObjectValue(value: unknown): value is Record<PropertyKey, unknown> {
return typeof value === 'object' && value !== null
}
// prettier-ignore
function IsArrayValue(value: unknown): value is unknown[] {
return globalThis.Array.isArray(value)
}
// ------------------------------------------------------------------
// Parser Guard
// ------------------------------------------------------------------
/** Returns true if the value is a Tuple Parser */
// prettier-ignore
export function IsTuple(value: unknown): value is ITuple {
return IsObjectValue(value) && HasPropertyKey(value, 'type') && value.type === 'Tuple' && HasPropertyKey(value, 'parsers') && IsArrayValue(value.parsers)
}
/** Returns true if the value is a Union Parser */
// prettier-ignore
export function IsUnion(value: unknown): value is IUnion {
return IsObjectValue(value) && HasPropertyKey(value, 'type') && value.type === 'Union' && HasPropertyKey(value, 'parsers') && IsArrayValue(value.parsers)
}
/** Returns true if the value is a Const Parser */
// prettier-ignore
export function IsConst(value: unknown): value is IConst {
return IsObjectValue(value) && HasPropertyKey(value, 'type') && value.type === 'Const' && HasPropertyKey(value, 'value') && typeof value.value === 'string'
}
/** Returns true if the value is a Ident Parser */
// prettier-ignore
export function IsIdent(value: unknown): value is IIdent {
return IsObjectValue(value) && HasPropertyKey(value, 'type') && value.type === 'Ident'
}
/** Returns true if the value is a Number Parser */
// prettier-ignore
export function IsNumber(value: unknown): value is INumber {
return IsObjectValue(value) && HasPropertyKey(value, 'type') && value.type === 'Number'
}
/** Returns true if the value is a Ref Parser */
// prettier-ignore
export function IsRef(value: unknown): value is IRef {
return IsObjectValue(value) && HasPropertyKey(value, 'type') && value.type === 'Ref' && HasPropertyKey(value, 'ref') && typeof value.ref === 'string'
}
/** Returns true if the value is a String Parser */
// prettier-ignore
export function IsString(value: unknown): value is IString {
return IsObjectValue(value) && HasPropertyKey(value, 'type') && value.type === 'String' && HasPropertyKey(value, 'options') && IsArrayValue(value.options)
}
/** Returns true if the value is a Parser */
// prettier-ignore
export function IsParser(value: unknown) {
return (
IsTuple(value) ||
IsUnion(value) ||
IsConst(value) ||
IsIdent(value) ||
IsNumber(value) ||
IsRef(value) ||
IsString(value)
)
}

View File

@@ -0,0 +1,33 @@
/*--------------------------------------------------------------------------
@sinclair/parsebox
The MIT License (MIT)
Copyright (c) 2024 Haydn Paterson (sinclair) <haydn.developer@gmail.com>
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
---------------------------------------------------------------------------*/
export * as Guard from './guard'
export * as Token from './token'
export * from './types'
export * from './module'
export * from './parse'

View File

@@ -0,0 +1,51 @@
/*--------------------------------------------------------------------------
@sinclair/parsebox
The MIT License (MIT)
Copyright (c) 2024 Haydn Paterson (sinclair) <haydn.developer@gmail.com>
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
---------------------------------------------------------------------------*/
import * as Types from './types'
import { Parse } from './parse'
// ------------------------------------------------------------------
// Module
// ------------------------------------------------------------------
// prettier-ignore
export class Module<Properties extends Types.IModuleProperties = Types.IModuleProperties> {
constructor(private readonly properties: Properties) { }
/** Parses using one of the parsers defined on this instance */
public Parse<Key extends keyof Properties>(key: Key, code: string, context: unknown): [] | [Types.StaticParser<Properties[Key]>, string]
/** Parses using one of the parsers defined on this instance */
public Parse<Key extends keyof Properties>(key: Key, code: string): [] | [Types.StaticParser<Properties[Key]>, string]
/** Parses using one of the parsers defined on this instance */
public Parse(...args: any[]): never {
const [key, code, context] =
args.length === 3 ? [args[0], args[1], args[2]] :
args.length === 2 ? [args[0], args[1], undefined] :
(() => { throw Error('Invalid parse arguments') })()
return Parse(this.properties[key], this.properties, code, context) as never
}
}

View File

@@ -0,0 +1,141 @@
/*--------------------------------------------------------------------------
@sinclair/parsebox
The MIT License (MIT)
Copyright (c) 2024 Haydn Paterson (sinclair) <haydn.developer@gmail.com>
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
---------------------------------------------------------------------------*/
import * as Guard from './guard'
import * as Token from './token'
import * as Types from './types'
// ------------------------------------------------------------------
// Tuple
// ------------------------------------------------------------------
// prettier-ignore
function ParseTuple<Parsers extends Types.IParser[], Properties extends Types.IModuleProperties>(parsers: [...Parsers], properties: Properties, code: string, context: unknown): [] | [unknown[], string] {
const buffer = [] as unknown[]
let rest = code
for(const parser of parsers) {
const result = ParseParser(parser, properties, rest, context)
if(result.length === 0) return []
buffer.push(result[0])
rest = result[1]
}
return [buffer, rest]
}
// ------------------------------------------------------------------
// Union
// ------------------------------------------------------------------
// prettier-ignore
function ParseUnion<Parsers extends Types.IParser[], Properties extends Types.IModuleProperties>(parsers: [...Parsers], properties: Properties, code: string, context: unknown): [] | [unknown, string] {
for(const parser of parsers) {
const result = ParseParser(parser, properties, code, context)
if(result.length === 0) continue
return result
}
return []
}
// ------------------------------------------------------------------
// Const
// ------------------------------------------------------------------
// prettier-ignore
function ParseConst<Value extends string>(value: Value, code: string, context: unknown): [] | [Value, string] {
return Token.Const(value, code) as never
}
// ------------------------------------------------------------------
// Ref
// ------------------------------------------------------------------
// prettier-ignore
function ParseRef<Ref extends string, Properties extends Types.IModuleProperties>(ref: Ref, properties: Properties, code: string, context: unknown): [] | [string, string] {
const parser = properties[ref]
if(!Guard.IsParser(parser)) throw Error(`Cannot dereference parser '${ref}'`)
return ParseParser(parser, properties, code, context) as never
}
// ------------------------------------------------------------------
// String
// ------------------------------------------------------------------
// prettier-ignore
function ParseString(options: string[], code: string, _context: unknown): [] | [string, string] {
return Token.String(options, code)
}
// ------------------------------------------------------------------
// Number
// ------------------------------------------------------------------
// prettier-ignore
function ParseNumber(code: string, _context: unknown): [] | [string, string] {
return Token.Number(code)
}
// ------------------------------------------------------------------
// Ident
// ------------------------------------------------------------------
// prettier-ignore
function ParseIdent(code: string, _context: unknown): [] | [string, string] {
return Token.Ident(code)
}
// ------------------------------------------------------------------
// Parser
// ------------------------------------------------------------------
// prettier-ignore
function ParseParser<Parser extends Types.IParser>(parser: Parser, properties: Types.IModuleProperties, code: string, context: unknown): [] | [Types.StaticParser<Parser>, string] {
const result = (
Guard.IsTuple(parser) ? ParseTuple(parser.parsers, properties, code, context) :
Guard.IsUnion(parser) ? ParseUnion(parser.parsers, properties, code, context) :
Guard.IsConst(parser) ? ParseConst(parser.value, code, context) :
Guard.IsRef(parser) ? ParseRef(parser.ref, properties, code, context) :
Guard.IsString(parser) ? ParseString(parser.options, code, context) :
Guard.IsIdent(parser) ? ParseIdent(code, context) :
Guard.IsNumber(parser) ? ParseNumber(code, context) :
[]
)
return (
result.length === 2
? [parser.mapping(result[0], context), result[1]]
: result
) as never
}
// ------------------------------------------------------------------
// Parse
// ------------------------------------------------------------------
/** Parses content using the given parser */
// prettier-ignore
export function Parse<Parser extends Types.IParser>(parser: Parser, properties: Types.IModuleProperties, code: string, context: unknown): [] | [Types.StaticParser<Parser>, string]
/** Parses content using the given parser */
// prettier-ignore
export function Parse<Parser extends Types.IParser>(parser: Parser, properties: Types.IModuleProperties, code: string): [] | [Types.StaticParser<Parser>, string]
/** Parses content using the given parser */
// prettier-ignore
export function Parse<Parser extends Types.IParser>(parser: Parser, code: string, context: unknown): [] | [Types.StaticParser<Parser>, string]
/** Parses content using the given parser */
// prettier-ignore
export function Parse<Parser extends Types.IParser>(parser: Parser, code: string): [] | [Types.StaticParser<Parser>, string]
/** Parses content using the given parser */
// prettier-ignore
export function Parse(...args: any[]): never {
const withProperties = typeof args[1] === 'string' ? false : true
const [parser, properties, code, context] = withProperties
? [args[0], args[1], args[2], args[3]]
: [args[0], {}, args[1], args[2]]
return ParseParser(parser, properties, code, context) as never
}

View File

@@ -0,0 +1,247 @@
/*--------------------------------------------------------------------------
@sinclair/parsebox
The MIT License (MIT)
Copyright (c) 2024 Haydn Paterson (sinclair) <haydn.developer@gmail.com>
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
---------------------------------------------------------------------------*/
// ------------------------------------------------------------------
// Chars
// ------------------------------------------------------------------
// prettier-ignore
namespace Chars {
/** Returns true if the char code is a whitespace */
export function IsWhitespace(value: number): boolean {
return value === 32
}
/** Returns true if the char code is a newline */
export function IsNewline(value: number): boolean {
return value === 10
}
/** Returns true if the char code is a alpha */
export function IsAlpha(value: number): boolean {
return (
(value >= 65 && value <= 90) || // A-Z
(value >= 97 && value <= 122) // a-z
)
}
/** Returns true if the char code is zero */
export function IsZero(value: number): boolean {
return value === 48
}
/** Returns true if the char code is non-zero */
export function IsNonZero(value: number): boolean {
return value >= 49 && value <= 57
}
/** Returns true if the char code is a digit */
export function IsDigit(value: number): boolean {
return (
IsNonZero(value) ||
IsZero(value)
)
}
/** Returns true if the char code is a dot */
export function IsDot(value: number): boolean {
return value === 46
}
/** Returns true if this char code is a underscore */
export function IsUnderscore(value: unknown): boolean {
return value === 95
}
/** Returns true if this char code is a dollar sign */
export function IsDollarSign(value: unknown): boolean {
return value === 36
}
}
// ------------------------------------------------------------------
// Trim
// ------------------------------------------------------------------
// prettier-ignore
namespace Trim {
/** Trims Whitespace and retains Newline, Tabspaces, etc. */
export function TrimWhitespaceOnly(code: string): string {
for (let i = 0; i < code.length; i++) {
if (Chars.IsWhitespace(code.charCodeAt(i))) continue
return code.slice(i)
}
return code
}
/** Trims Whitespace including Newline, Tabspaces, etc. */
export function TrimAll(code: string): string {
return code.trimStart()
}
}
// ------------------------------------------------------------------
// Const
// ------------------------------------------------------------------
/** Checks the value matches the next string */
// prettier-ignore
function NextTokenCheck(value: string, code: string): boolean {
if (value.length > code.length) return false
for (let i = 0; i < value.length; i++) {
if (value.charCodeAt(i) !== code.charCodeAt(i)) return false
}
return true
}
/** Gets the next constant string value or empty if no match */
// prettier-ignore
function NextConst(value: string, code: string, ): [] | [string, string] {
return NextTokenCheck(value, code)
? [code.slice(0, value.length), code.slice(value.length)]
: []
}
/** Takes the next constant string value skipping any whitespace */
// prettier-ignore
export function Const(value: string, code: string): [] | [string, string] {
if(value.length === 0) return ['', code]
const char_0 = value.charCodeAt(0)
return (
Chars.IsNewline(char_0) ? NextConst(value, Trim.TrimWhitespaceOnly(code)) :
Chars.IsWhitespace(char_0) ? NextConst(value, code) :
NextConst(value, Trim.TrimAll(code))
)
}
// ------------------------------------------------------------------
// Ident
// ------------------------------------------------------------------
// prettier-ignore
function IdentIsFirst(char: number) {
return (
Chars.IsAlpha(char) ||
Chars.IsDollarSign(char) ||
Chars.IsUnderscore(char)
)
}
// prettier-ignore
function IdentIsRest(char: number) {
return (
Chars.IsAlpha(char) ||
Chars.IsDigit(char) ||
Chars.IsDollarSign(char) ||
Chars.IsUnderscore(char)
)
}
// prettier-ignore
function NextIdent(code: string): [] | [string, string] {
if (!IdentIsFirst(code.charCodeAt(0))) return []
for (let i = 1; i < code.length; i++) {
const char = code.charCodeAt(i)
if (IdentIsRest(char)) continue
const slice = code.slice(0, i)
const rest = code.slice(i)
return [slice, rest]
}
return [code, '']
}
/** Scans for the next Ident token */
// prettier-ignore
export function Ident(code: string): [] | [string, string] {
return NextIdent(Trim.TrimAll(code))
}
// ------------------------------------------------------------------
// Number
// ------------------------------------------------------------------
/** Checks that the next number is not a leading zero */
// prettier-ignore
function NumberLeadingZeroCheck(code: string, index: number) {
const char_0 = code.charCodeAt(index + 0)
const char_1 = code.charCodeAt(index + 1)
return (
(
// 1-9
Chars.IsNonZero(char_0)
) || (
// 0
Chars.IsZero(char_0) &&
!Chars.IsDigit(char_1)
) || (
// 0.
Chars.IsZero(char_0) &&
Chars.IsDot(char_1)
) || (
// .0
Chars.IsDot(char_0) &&
Chars.IsDigit(char_1)
)
)
}
/** Gets the next number token */
// prettier-ignore
function NextNumber(code: string): [] | [string, string] {
const negated = code.charAt(0) === '-'
const index = negated ? 1 : 0
if (!NumberLeadingZeroCheck(code, index)) {
return []
}
const dash = negated ? '-' : ''
let hasDot = false
for (let i = index; i < code.length; i++) {
const char_i = code.charCodeAt(i)
if (Chars.IsDigit(char_i)) {
continue
}
if (Chars.IsDot(char_i)) {
if (hasDot) {
const slice = code.slice(index, i)
const rest = code.slice(i)
return [`${dash}${slice}`, rest]
}
hasDot = true
continue
}
const slice = code.slice(index, i)
const rest = code.slice(i)
return [`${dash}${slice}`, rest]
}
return [code, '']
}
/** Scans for the next number token */
// prettier-ignore
export function Number(code: string) {
return NextNumber(Trim.TrimAll(code))
}
// ------------------------------------------------------------------
// String
// ------------------------------------------------------------------
// prettier-ignore
function NextString(options: string[], code: string): [] | [string, string] {
const first = code.charAt(0)
if(!options.includes(first)) return []
const quote = first
for(let i = 1; i < code.length; i++) {
const char = code.charAt(i)
if(char === quote) {
const slice = code.slice(1, i)
const rest = code.slice(i + 1)
return [slice, rest]
}
}
return []
}
/** Scans the next Literal String value */
// prettier-ignore
export function String(options: string[], code: string) {
return NextString(options, Trim.TrimAll(code))
}

View File

@@ -0,0 +1,169 @@
/*--------------------------------------------------------------------------
@sinclair/parsebox
The MIT License (MIT)
Copyright (c) 2024 Haydn Paterson (sinclair) <haydn.developer@gmail.com>
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
---------------------------------------------------------------------------*/
export type IModuleProperties = Record<PropertyKey, IParser>
// ------------------------------------------------------------------
// Static
// ------------------------------------------------------------------
/** Infers the Output Parameter for a Parser */
export type StaticParser<Parser extends IParser> = Parser extends IParser<infer Output extends unknown> ? Output : unknown
// ------------------------------------------------------------------
// Mapping
// ------------------------------------------------------------------
export type IMapping<Input extends unknown = any, Output extends unknown = unknown> = (input: Input, context: any) => Output
/** Maps input to output. This is the default Mapping */
export const Identity = (value: unknown) => value
/** Maps the output as the given parameter T */
export const As =
<T>(mapping: T): ((value: unknown) => T) =>
(_: unknown) =>
mapping
// ------------------------------------------------------------------
// Parser
// ------------------------------------------------------------------
export interface IParser<Output extends unknown = unknown> {
type: string
mapping: IMapping<any, Output>
}
// ------------------------------------------------------------------
// Tuple
// ------------------------------------------------------------------
export type TupleParameter<Parsers extends IParser[], Result extends unknown[] = []> = Parsers extends [infer L extends IParser, ...infer R extends IParser[]] ? TupleParameter<R, [...Result, StaticParser<L>]> : Result
export interface ITuple<Output extends unknown = unknown> extends IParser<Output> {
type: 'Tuple'
parsers: IParser[]
}
/** Creates a Tuple parser */
export function Tuple<Parsers extends IParser[], Mapping extends IMapping = IMapping<TupleParameter<Parsers>>>(parsers: [...Parsers], mapping: Mapping): ITuple<ReturnType<Mapping>>
/** Creates a Tuple parser */
export function Tuple<Parsers extends IParser[]>(parsers: [...Parsers]): ITuple<TupleParameter<Parsers>>
export function Tuple(...args: unknown[]): never {
const [parsers, mapping] = args.length === 2 ? [args[0], args[1]] : [args[0], Identity]
return { type: 'Tuple', parsers, mapping } as never
}
// ------------------------------------------------------------------
// Union
// ------------------------------------------------------------------
export type UnionParameter<Parsers extends IParser[], Result extends unknown = never> = Parsers extends [infer L extends IParser, ...infer R extends IParser[]] ? UnionParameter<R, Result | StaticParser<L>> : Result
export interface IUnion<Output extends unknown = unknown> extends IParser<Output> {
type: 'Union'
parsers: IParser[]
}
/** Creates a Union parser */
export function Union<Parsers extends IParser[], Mapping extends IMapping = IMapping<UnionParameter<Parsers>>>(parsers: [...Parsers], mapping: Mapping): IUnion<ReturnType<Mapping>>
/** Creates a Union parser */
export function Union<Parsers extends IParser[]>(parsers: [...Parsers]): IUnion<UnionParameter<Parsers>>
export function Union(...args: unknown[]): never {
const [parsers, mapping] = args.length === 2 ? [args[0], args[1]] : [args[0], Identity]
return { type: 'Union', parsers, mapping } as never
}
// ------------------------------------------------------------------
// Token
// ------------------------------------------------------------------
export interface IConst<Output extends unknown = unknown> extends IParser<Output> {
type: 'Const'
value: string
}
/** Creates a Const parser */
export function Const<Value extends string, Mapping extends IMapping<Value>>(value: Value, mapping: Mapping): IConst<ReturnType<Mapping>>
/** Creates a Const parser */
export function Const<Value extends string>(value: Value): IConst<Value>
export function Const(...args: unknown[]): never {
const [value, mapping] = args.length === 2 ? [args[0], args[1]] : [args[0], Identity]
return { type: 'Const', value, mapping } as never
}
// ------------------------------------------------------------------
// Ref
// ------------------------------------------------------------------
export interface IRef<Output extends unknown = unknown> extends IParser<Output> {
type: 'Ref'
ref: string
}
/** Creates a Ref parser */
export function Ref<Type extends unknown, Mapping extends IMapping<Type>>(ref: string, mapping: Mapping): IRef<ReturnType<Mapping>>
/** Creates a Ref parser */
export function Ref<Type extends unknown>(ref: string): IRef<Type>
export function Ref(...args: unknown[]): never {
const [ref, mapping] = args.length === 2 ? [args[0], args[1]] : [args[0], Identity]
return { type: 'Ref', ref, mapping } as never
}
// ------------------------------------------------------------------
// String
// ------------------------------------------------------------------
export interface IString<Output extends unknown = unknown> extends IParser<Output> {
type: 'String'
options: string[]
}
/** Creates a String Parser. Options are an array of permissable quote characters */
export function String<Mapping extends IMapping<string>>(options: string[], mapping: Mapping): IString<ReturnType<Mapping>>
/** Creates a String Parser. Options are an array of permissable quote characters */
export function String(options: string[]): IString<string>
export function String(...params: unknown[]): never {
const [options, mapping] = params.length === 2 ? [params[0], params[1]] : [params[0], Identity]
return { type: 'String', options, mapping } as never
}
// ------------------------------------------------------------------
// Ident
// ------------------------------------------------------------------
export interface IIdent<Output extends unknown = unknown> extends IParser<Output> {
type: 'Ident'
}
/** Creates an Ident parser */
export function Ident<Mapping extends IMapping<string>>(mapping: Mapping): IIdent<ReturnType<Mapping>>
/** Creates an Ident parser */
export function Ident(): IIdent<string>
export function Ident(...params: unknown[]): never {
const mapping = params.length === 1 ? params[0] : Identity
return { type: 'Ident', mapping } as never
}
// ------------------------------------------------------------------
// Number
// ------------------------------------------------------------------
export interface INumber<Output extends unknown = unknown> extends IParser<Output> {
type: 'Number'
}
/** Creates a Number parser */
export function Number<Mapping extends IMapping<string>>(mapping: Mapping): INumber<ReturnType<Mapping>>
/** Creates a Number parser */
export function Number(): INumber<string>
export function Number(...params: unknown[]): never {
const mapping = params.length === 1 ? params[0] : Identity
return { type: 'Number', mapping } as never
}

View File

@@ -0,0 +1,31 @@
/*--------------------------------------------------------------------------
@sinclair/parsebox
The MIT License (MIT)
Copyright (c) 2024 Haydn Paterson (sinclair) <haydn.developer@gmail.com>
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
---------------------------------------------------------------------------*/
export * as Token from './token'
export * from './parse'
export * from './types'

View File

@@ -0,0 +1,119 @@
/*--------------------------------------------------------------------------
@sinclair/parsebox
The MIT License (MIT)
Copyright (c) 2024 Haydn Paterson (sinclair) <haydn.developer@gmail.com>
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
---------------------------------------------------------------------------*/
import * as Tokens from './token'
import * as Types from './types'
// ------------------------------------------------------------------
// Tuple
// ------------------------------------------------------------------
// prettier-ignore
type TupleParser<Parsers extends Types.IParser[], Code extends string, Context extends unknown, Result extends unknown[] = []> = (
Parsers extends [infer Left extends Types.IParser, ...infer Right extends Types.IParser[]]
? Parse<Left, Code, Context> extends [infer Value extends unknown, infer Rest extends string]
? TupleParser<Right, Rest, Context, [...Result, Value]>
: []
: [Result, Code]
)
// ------------------------------------------------------------------
// Union
// ------------------------------------------------------------------
// prettier-ignore
type UnionParser<Parsers extends Types.IParser[], Code extends string, Context extends unknown> = (
Parsers extends [infer Left extends Types.IParser, ...infer Right extends Types.IParser[]]
? Parse<Left, Code, Context> extends [infer Value extends unknown, infer Rest extends string]
? [Value, Rest]
: UnionParser<Right, Code, Context>
: []
)
// ------------------------------------------------------------------
// Const
// ------------------------------------------------------------------
// prettier-ignore
type ConstParser<Value extends string, Code extends string, _Context extends unknown> = (
Tokens.Const<Value, Code> extends [infer Match extends Value, infer Rest extends string]
? [Match, Rest]
: []
)
// ------------------------------------------------------------------
// Ident
// ------------------------------------------------------------------
// prettier-ignore
type IdentParser<Code extends string, _Context extends unknown> = (
Tokens.Ident<Code> extends [infer Match extends string, infer Rest extends string]
? [Match, Rest]
: []
)
// ------------------------------------------------------------------
// Number
// ------------------------------------------------------------------
// prettier-ignore
type NumberParser<Code extends string, _Context extends unknown> = (
Tokens.Number<Code> extends [infer Match extends string, infer Rest extends string]
? [Match, Rest]
: []
)
// ------------------------------------------------------------------
// String
// ------------------------------------------------------------------
// prettier-ignore
type StringParser<Options extends string[], Code extends string, _Context extends unknown> = (
Tokens.String<Options, Code> extends [infer Match extends string, infer Rest extends string]
? [Match, Rest]
: []
)
// ------------------------------------------------------------------
// Parse
// ------------------------------------------------------------------
// prettier-ignore
type ParseCode<Type extends Types.IParser, Code extends string, Context extends unknown = unknown> = (
Type extends Types.Union<infer S extends Types.IParser[]> ? UnionParser<S, Code, Context> :
Type extends Types.Tuple<infer S extends Types.IParser[]> ? TupleParser<S, Code, Context> :
Type extends Types.Const<infer S extends string> ? ConstParser<S, Code, Context> :
Type extends Types.String<infer S extends string[]> ? StringParser<S, Code, Context> :
Type extends Types.Ident ? IdentParser<Code, Context> :
Type extends Types.Number ? NumberParser<Code, Context> :
[]
)
// prettier-ignore
type ParseMapping<Parser extends Types.IParser, Result extends unknown, Context extends unknown = unknown> = (
(Parser['mapping'] & { input: Result, context: Context })['output']
)
/** Parses code with the given parser */
// prettier-ignore
export type Parse<Type extends Types.IParser, Code extends string, Context extends unknown = unknown> = (
ParseCode<Type, Code, Context> extends [infer L extends unknown, infer R extends string]
? [ParseMapping<Type, L, Context>, R]
: []
)

View File

@@ -0,0 +1,213 @@
/*--------------------------------------------------------------------------
@sinclair/parsebox
The MIT License (MIT)
Copyright (c) 2024 Haydn Paterson (sinclair) <haydn.developer@gmail.com>
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
---------------------------------------------------------------------------*/
// ------------------------------------------------------------------
// Chars
// ------------------------------------------------------------------
// prettier-ignore
namespace Chars {
export type Empty = ''
export type Space = ' '
export type Newline = '\n'
export type Dot = '.'
export type Hyphen = '-'
export type Digit = [
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9'
]
export type Alpha = [
'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j',
'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't',
'u', 'v', 'w', 'x', 'y', 'z', 'A', 'B', 'C', 'D',
'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N',
'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X',
'Y', 'Z'
]
}
// ------------------------------------------------------------------
// Trim
// ------------------------------------------------------------------
// prettier-ignore
namespace Trim {
// ------------------------------------------------------------------
// Whitespace Filters
// ------------------------------------------------------------------
type W9 = `${W8}${W8}` // 512
type W8 = `${W7}${W7}` // 256
type W7 = `${W6}${W6}` // 128
type W6 = `${W5}${W5}` // 64
type W5 = `${W4}${W4}` // 32
type W4 = `${W3}${W3}` // 16
type W3 = `${W2}${W2}` // 8
type W2 = `${W1}${W1}` // 4
type W1 = `${W0}${W0}` // 2
type W0 = ` ` // 1
// ------------------------------------------------------------------
// TrimWhitespace
// ------------------------------------------------------------------
/** Trims whitespace only */
export type TrimWhitespace<Code extends string> = (
Code extends `${W4}${infer Rest extends string}` ? TrimWhitespace<Rest> :
Code extends `${W3}${infer Rest extends string}` ? TrimWhitespace<Rest> :
Code extends `${W1}${infer Rest extends string}` ? TrimWhitespace<Rest> :
Code extends `${W0}${infer Rest extends string}` ? TrimWhitespace<Rest> :
Code
)
// ------------------------------------------------------------------
// Trim
// ------------------------------------------------------------------
/** Trims Whitespace and Newline */
export type TrimAll<Code extends string> = (
Code extends `${W4}${infer Rest extends string}` ? TrimAll<Rest> :
Code extends `${W3}${infer Rest extends string}` ? TrimAll<Rest> :
Code extends `${W1}${infer Rest extends string}` ? TrimAll<Rest> :
Code extends `${W0}${infer Rest extends string}` ? TrimAll<Rest> :
Code extends `${Chars.Newline}${infer Rest extends string}` ? TrimAll<Rest> :
Code
)
}
// ------------------------------------------------------------------
// Union
// ------------------------------------------------------------------
/** Scans for the next match union */
// prettier-ignore
type NextUnion<Variants extends string[], Code extends string> = (
Variants extends [infer Variant extends string, ...infer Rest1 extends string[]]
? NextConst<Variant, Code> extends [infer Match extends string, infer Rest2 extends string]
? [Match, Rest2]
: NextUnion<Rest1, Code>
: []
)
// ------------------------------------------------------------------
// Const
// ------------------------------------------------------------------
// prettier-ignore
type NextConst<Value extends string, Code extends string> = (
Code extends `${Value}${infer Rest extends string}`
? [Value, Rest]
: []
)
/** Scans for the next constant value */
// prettier-ignore
export type Const<Value extends string, Code extends string> = (
Value extends '' ? ['', Code] :
Value extends `${infer First extends string}${string}`
? (
First extends Chars.Newline ? NextConst<Value, Trim.TrimWhitespace<Code>> :
First extends Chars.Space ? NextConst<Value, Code> :
NextConst<Value, Trim.TrimAll<Code>>
) : never
)
// ------------------------------------------------------------------
// Number
// ------------------------------------------------------------------
// prettier-ignore
type NextNumberNegate<Code extends string> = (
Code extends `${Chars.Hyphen}${infer Rest extends string}`
? [Chars.Hyphen, Rest]
: [Chars.Empty, Code]
)
// prettier-ignore
type NextNumberZeroCheck<Code extends string> = (
Code extends `0${infer Rest}`
? NextUnion<Chars.Digit, Rest> extends [string, string] ? false : true
: true
)
// prettier-ignore
type NextNumberScan<Code extends string, HasDecimal extends boolean = false, Result extends string = Chars.Empty> = (
NextUnion<[...Chars.Digit, Chars.Dot], Code> extends [infer Char extends string, infer Rest extends string]
? Char extends Chars.Dot
? HasDecimal extends false
? NextNumberScan<Rest, true, `${Result}${Char}`>
: [Result, `.${Rest}`]
: NextNumberScan<Rest, HasDecimal, `${Result}${Char}`>
: [Result, Code]
)
// prettier-ignore
export type NextNumber<Code extends string> = (
NextNumberNegate<Code> extends [infer Negate extends string, infer Rest extends string]
? NextNumberZeroCheck<Rest> extends true
? NextNumberScan<Rest> extends [infer Number extends string, infer Rest2 extends string]
? Number extends Chars.Empty
? []
: [`${Negate}${Number}`, Rest2]
: []
: []
: []
)
/** Scans for the next literal number */
export type Number<Code extends string> = NextNumber<Trim.TrimAll<Code>>
// ------------------------------------------------------------------
// String
// ------------------------------------------------------------------
type NextStringQuote<Options extends string[], Code extends string> = NextUnion<Options, Code>
// prettier-ignore
type NextStringBody<Code extends string, Quote extends string, Result extends string = Chars.Empty> = (
Code extends `${infer Char extends string}${infer Rest extends string}`
? Char extends Quote
? [Result, Rest]
: NextStringBody<Rest, Quote, `${Result}${Char}`>
: []
)
// prettier-ignore
type NextString<Options extends string[], Code extends string> = (
NextStringQuote<Options, Code> extends [infer Quote extends string, infer Rest extends string]
? NextStringBody<Rest, Quote> extends [infer String extends string, infer Rest extends string]
? [String, Rest]
: []
: []
)
/** Scans for the next literal string */
export type String<Options extends string[], Code extends string> = NextString<Options, Trim.TrimAll<Code>>
// ------------------------------------------------------------------
// Ident
// ------------------------------------------------------------------
type IdentLeft = [...Chars.Alpha, '_', '$'] // permissable first characters
type IdentRight = [...Chars.Digit, ...IdentLeft] // permissible subsequent characters
// prettier-ignore
type NextIdentScan<Code extends string, Result extends string = Chars.Empty> = (
NextUnion<IdentRight, Code> extends [infer Char extends string, infer Rest extends string]
? NextIdentScan<Rest, `${Result}${Char}`>
: [Result, Code]
)
// prettier-ignore
type NextIdent<Code extends string> = (
NextUnion<IdentLeft, Code> extends [infer Left extends string, infer Rest1 extends string]
? NextIdentScan<Rest1> extends [infer Right extends string, infer Rest2 extends string]
? [`${Left}${Right}`, Rest2]
: []
: []
)
/** Scans for the next Ident */
export type Ident<Code extends string> = NextIdent<Trim.TrimAll<Code>>

View File

@@ -0,0 +1,100 @@
/*--------------------------------------------------------------------------
@sinclair/typebox/parse
The MIT License (MIT)
Copyright (c) 2024 Haydn Paterson (sinclair) <haydn.developer@gmail.com>
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
---------------------------------------------------------------------------*/
// ------------------------------------------------------------------
// Mapping
// ------------------------------------------------------------------
export interface IMapping {
context: unknown
input: unknown
output: unknown
}
/** Maps input to output. This is the default Mapping */
export interface Identity extends IMapping {
output: this['input']
}
/** Maps the output as the given parameter T */
export interface As<T> extends IMapping {
output: T
}
// ------------------------------------------------------------------
// Parser
// ------------------------------------------------------------------
/** Base type Parser implemented by all other parsers */
export interface IParser<Mapping extends IMapping = Identity> {
type: string
mapping: Mapping
}
// ------------------------------------------------------------------
// Tuple
// ------------------------------------------------------------------
/** Creates a Tuple Parser */
export interface Tuple<Parsers extends IParser[] = [], Mapping extends IMapping = Identity> extends IParser<Mapping> {
type: 'Tuple'
parsers: [...Parsers]
}
// ------------------------------------------------------------------
// Union
// ------------------------------------------------------------------
/** Creates a Union Parser */
export interface Union<Parsers extends IParser[] = [], Mapping extends IMapping = Identity> extends IParser<Mapping> {
type: 'Union'
parsers: [...Parsers]
}
// ------------------------------------------------------------------
// Const
// ------------------------------------------------------------------
/** Creates a Const Parser */
export interface Const<Value extends string = string, Mapping extends IMapping = Identity> extends IParser<Mapping> {
type: 'Const'
value: Value
}
// ------------------------------------------------------------------
// String
// ------------------------------------------------------------------
/** Creates a String Parser. Options are an array of permissable quote characters */
export interface String<Options extends string[], Mapping extends IMapping = Identity> extends IParser<Mapping> {
type: 'String'
quote: Options
}
// ------------------------------------------------------------------
// Ident
// ------------------------------------------------------------------
/** Creates an Ident Parser. */
// prettier-ignore
export interface Ident<Mapping extends IMapping = Identity> extends IParser<Mapping> {
type: 'Ident'
}
// ------------------------------------------------------------------
// Number
// ------------------------------------------------------------------
/** Creates a Number Parser. */
// prettier-ignore
export interface Number<Mapping extends IMapping = Identity> extends IParser<Mapping> {
type: 'Number'
}

678
src/parse/runtime.ts Normal file
View File

@@ -0,0 +1,678 @@
/*--------------------------------------------------------------------------
@sinclair/typebox
The MIT License (MIT)
Copyright (c) 2017-2024 Haydn Paterson (sinclair) <haydn.developer@gmail.com>
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
---------------------------------------------------------------------------*/
import { Runtime } from './parsebox/index'
import * as Types from '../type/index'
// ------------------------------------------------------------------
// Tokens
// ------------------------------------------------------------------
const Newline = '\n'
const LBracket = '['
const RBracket = ']'
const LParen = '('
const RParen = ')'
const LBrace = '{'
const RBrace = '}'
const LAngle = '<'
const RAngle = '>'
const Question = '?'
const Colon = ':'
const Comma = ','
const SemiColon = ';'
const SingleQuote = "'"
const DoubleQuote = '"'
const Tilde = '`'
// ------------------------------------------------------------------
// DestructureRight
// ------------------------------------------------------------------
// prettier-ignore
function DestructureRight<T>(values: T[]): [T[], T | undefined] {
return (values.length > 0)
? [values.slice(0, values.length - 1), values[values.length - 1]]
: [values, undefined]
}
// ------------------------------------------------------------------
// Reference
// ------------------------------------------------------------------
// prettier-ignore
const Reference = Runtime.Ident((value, context: Record<PropertyKey, Types.TSchema>) => {
return value in context ? context[value] : Types.Ref(value)
})
// ------------------------------------------------------------------
// Literal
// ------------------------------------------------------------------
// prettier-ignore
const Literal = Runtime.Union([
Runtime.Union([Runtime.Const('true'), Runtime.Const('false')], value => Types.Literal(value === 'true')),
Runtime.Number(value => Types.Literal(parseFloat(value))),
Runtime.String([SingleQuote, DoubleQuote, Tilde], value => Types.Literal(value))
])
// ------------------------------------------------------------------
// Keyword
// ------------------------------------------------------------------
// prettier-ignore
const Keyword = Runtime.Union([
Runtime.Const('any', Runtime.As(Types.Any())),
Runtime.Const('bigint', Runtime.As(Types.BigInt())),
Runtime.Const('boolean', Runtime.As(Types.Boolean())),
Runtime.Const('integer', Runtime.As(Types.Integer())),
Runtime.Const('never', Runtime.As(Types.Never())),
Runtime.Const('null', Runtime.As(Types.Null())),
Runtime.Const('number', Runtime.As(Types.Number())),
Runtime.Const('string', Runtime.As(Types.String())),
Runtime.Const('symbol', Runtime.As(Types.Symbol())),
Runtime.Const('undefined', Runtime.As(Types.Undefined())),
Runtime.Const('unknown', Runtime.As(Types.Unknown())),
Runtime.Const('void', Runtime.As(Types.Void())),
])
// ------------------------------------------------------------------
// KeyOf
// ------------------------------------------------------------------
// prettier-ignore
const KeyOfMapping = (values: unknown[]) => (
values.length > 0
)
// prettier-ignore
const KeyOf = Runtime.Union([
Runtime.Tuple([Runtime.Const('keyof')]), Runtime.Tuple([])
], KeyOfMapping)
// ------------------------------------------------------------------
// IndexArray
// ------------------------------------------------------------------
// prettier-ignore
const IndexArrayMapping = (values: unknown[]) => (
values.length === 4 ? [[values[1]], ...values[3] as unknown[]] :
values.length === 3 ? [[], ...values[2] as unknown[]] :
[]
)
// prettier-ignore
const IndexArray = Runtime.Union([
Runtime.Tuple([Runtime.Const(LBracket), Runtime.Ref('Type'), Runtime.Const(RBracket), Runtime.Ref('IndexArray')]),
Runtime.Tuple([Runtime.Const(LBracket), Runtime.Const(RBracket), Runtime.Ref('IndexArray')]),
Runtime.Tuple([])
], value => IndexArrayMapping(value))
// ------------------------------------------------------------------
// Extends
// ------------------------------------------------------------------
// prettier-ignore
const ExtendsMapping = (values: unknown[]) => {
return values.length === 6
? [values[1], values[3], values[5]]
: []
}
// prettier-ignore
const Extends = Runtime.Union([
Runtime.Tuple([Runtime.Const('extends'), Runtime.Ref('Type'), Runtime.Const(Question), Runtime.Ref('Type'), Runtime.Const(Colon), Runtime.Ref('Type')]),
Runtime.Tuple([])
], ExtendsMapping)
// ------------------------------------------------------------------
// Base
// ------------------------------------------------------------------
// prettier-ignore
const BaseMapping = (values: unknown[]) => {
return values.length === 3 ? values[1] : values[0]
}
// prettier-ignore
const Base = Runtime.Union([
Runtime.Tuple([
Runtime.Const(LParen),
Runtime.Ref('Type'),
Runtime.Const(RParen)
]),
Runtime.Tuple([Runtime.Union([
Runtime.Ref('Literal'),
Runtime.Ref('Keyword'),
Runtime.Ref('Object'),
Runtime.Ref('Tuple'),
Runtime.Ref('Constructor'),
Runtime.Ref('Function'),
Runtime.Ref('Mapped'),
Runtime.Ref('AsyncIterator'),
Runtime.Ref('Iterator'),
Runtime.Ref('ConstructorParameters'),
Runtime.Ref('FunctionParameters'),
Runtime.Ref('InstanceType'),
Runtime.Ref('ReturnType'),
Runtime.Ref('Awaited'),
Runtime.Ref('Array'),
Runtime.Ref('Record'),
Runtime.Ref('Promise'),
Runtime.Ref('Partial'),
Runtime.Ref('Required'),
Runtime.Ref('Pick'),
Runtime.Ref('Omit'),
Runtime.Ref('Exclude'),
Runtime.Ref('Extract'),
Runtime.Ref('Uppercase'),
Runtime.Ref('Lowercase'),
Runtime.Ref('Capitalize'),
Runtime.Ref('Uncapitalize'),
Runtime.Ref('Date'),
Runtime.Ref('Uint8Array'),
Runtime.Ref('Reference')
])])
], BaseMapping)
// ------------------------------------------------------------------
// Factor
// ------------------------------------------------------------------
// prettier-ignore
const FactorExtends = (Type: Types.TSchema, Extends: Types.TSchema[]) => {
return Extends.length === 3
? Types.Extends(Type, Extends[0], Extends[1], Extends[2])
: Type
}
// prettier-ignore
const FactorIndexArray = (Type: Types.TSchema, IndexArray: unknown[]): Types.TSchema => {
const [Left, Right] = DestructureRight(IndexArray) as [unknown[], Types.TSchema[]]
return (
!Types.ValueGuard.IsUndefined(Right) ? (
Right.length === 1 ? Types.Index(FactorIndexArray(Type, Left), Right[0]) :
Right.length === 0 ? Types.Array(FactorIndexArray(Type, Left)) :
Types.Never()
) : Type
)
}
// prettier-ignore
const FactorMapping = (KeyOf: boolean, Type: Types.TSchema, IndexArray: unknown[], Extends: Types.TSchema[]) => {
return KeyOf
? FactorExtends(Types.KeyOf(FactorIndexArray(Type, IndexArray)), Extends)
: FactorExtends(FactorIndexArray(Type, IndexArray), Extends)
}
// prettier-ignore
const Factor = Runtime.Tuple([
Runtime.Ref<boolean>('KeyOf'),
Runtime.Ref<Types.TSchema>('Base'),
Runtime.Ref<unknown[]>('IndexArray'),
Runtime.Ref<Types.TSchema[]>('Extends')
], values => FactorMapping(...values))
// ------------------------------------------------------------------
// Expr
// ------------------------------------------------------------------
// prettier-ignore
function ExprBinaryMapping(Left: Types.TSchema, Rest: unknown[]): Types.TSchema {
return (
Rest.length === 3 ? (() => {
const [Operator, Right, Next] = Rest as [string, Types.TSchema, unknown[]]
const Schema = ExprBinaryMapping(Right, Next)
if (Operator === '&') {
return Types.TypeGuard.IsIntersect(Schema)
? Types.Intersect([Left, ...Schema.allOf])
: Types.Intersect([Left, Schema])
}
if (Operator === '|') {
return Types.TypeGuard.IsUnion(Schema)
? Types.Union([Left, ...Schema.anyOf])
: Types.Union([Left, Schema])
}
throw 1
})() : Left
)
}
// prettier-ignore
const ExprTermTail = Runtime.Union([
Runtime.Tuple([Runtime.Const('&'), Runtime.Ref('Factor'), Runtime.Ref('ExprTermTail')]),
Runtime.Tuple([])
])
// prettier-ignore
const ExprTerm = Runtime.Tuple([
Runtime.Ref<Types.TSchema>('Factor'), Runtime.Ref<unknown[]>('ExprTermTail')
], value => ExprBinaryMapping(...value))
// prettier-ignore
const ExprTail = Runtime.Union([
Runtime.Tuple([Runtime.Const('|'), Runtime.Ref('ExprTerm'), Runtime.Ref('ExprTail')]),
Runtime.Tuple([])
])
// prettier-ignore
const Expr = Runtime.Tuple([
Runtime.Ref<Types.TSchema>('ExprTerm'), Runtime.Ref<unknown[]>('ExprTail')
], value => ExprBinaryMapping(...value))
// ------------------------------------------------------------------
// Type
// ------------------------------------------------------------------
const Type = Runtime.Ref('Expr')
// ------------------------------------------------------------------
// Properties
// ------------------------------------------------------------------
// prettier-ignore
const PropertyKey = Runtime.Union([Runtime.Ident(), Runtime.String([SingleQuote, DoubleQuote])])
// prettier-ignore
const PropertyReadonly = Runtime.Union([Runtime.Tuple([Runtime.Const('readonly')]), Runtime.Tuple([])], value => value.length > 0)
// prettier-ignore
const PropertyOptional = Runtime.Union([Runtime.Tuple([Runtime.Const(Question)]), Runtime.Tuple([])], value => value.length > 0)
// prettier-ignore
const PropertyMapping = (Readonly: boolean, Key: string, Optional: boolean, _: typeof Colon, Type: Types.TSchema) => ({
[Key]: (
Readonly && Optional ? Types.ReadonlyOptional(Type) :
Readonly && !Optional ? Types.Readonly(Type) :
!Readonly && Optional ? Types.Optional(Type) :
Type
)
})
// prettier-ignore
const Property = Runtime.Tuple([
Runtime.Ref<boolean>('PropertyReadonly'),
Runtime.Ref<string>('PropertyKey'),
Runtime.Ref<boolean>('PropertyOptional'),
Runtime.Const(Colon),
Runtime.Ref<Types.TSchema>('Type'),
], value => PropertyMapping(...value))
// prettier-ignore
const PropertyDelimiter = Runtime.Union([
Runtime.Tuple([Runtime.Const(Comma), Runtime.Const(Newline)]),
Runtime.Tuple([Runtime.Const(SemiColon), Runtime.Const(Newline)]),
Runtime.Tuple([Runtime.Const(Comma)]),
Runtime.Tuple([Runtime.Const(SemiColon)]),
Runtime.Tuple([Runtime.Const(Newline)]),
])
// prettier-ignore
const Properties = Runtime.Union([
Runtime.Tuple([Runtime.Ref('Property'), Runtime.Ref('PropertyDelimiter'), Runtime.Ref('Properties')]),
Runtime.Tuple([Runtime.Ref('Property'), Runtime.Ref('PropertyDelimiter')]),
Runtime.Tuple([Runtime.Ref('Property')]),
Runtime.Tuple([])
], values => (
values.length === 3 ? [values[0], ...values[2] as unknown[]] :
values.length === 2 ? [values[0]] :
values.length === 1 ? [values[0]] :
[]
))
// ------------------------------------------------------------------
// Object
// ------------------------------------------------------------------
// prettier-ignore
const ObjectMapping = (values: Record<string, Types.TSchema>[]) => Types.Object(values.reduce((properties, record) => {
return { ...properties, ...record }
}, {} as Types.TProperties))
// prettier-ignore
const Object = Runtime.Tuple([
Runtime.Const(LBrace),
Runtime.Ref<Record<string, Types.TSchema>[]>('Properties'),
Runtime.Const(RBrace)
], values => ObjectMapping(values[1]))
// ------------------------------------------------------------------
// Tuple
// ------------------------------------------------------------------
// prettier-ignore
const Elements = Runtime.Union([
Runtime.Tuple([Runtime.Ref('Type'), Runtime.Const(Comma), Runtime.Ref<unknown[]>('Elements')]),
Runtime.Tuple([Runtime.Ref('Type'), Runtime.Const(Comma)]),
Runtime.Tuple([Runtime.Ref('Type')]),
Runtime.Tuple([]),
], value => (
value.length === 3 ? [value[0], ...value[2]] :
value.length === 2 ? [value[0]] :
value.length === 1 ? [value[0]] :
[]
))
// prettier-ignore
const Tuple = Runtime.Tuple([
Runtime.Const(LBracket),
Runtime.Ref<Types.TSchema[]>('Elements'),
Runtime.Const(RBracket)
], value => Types.Tuple(value[1]))
// ------------------------------------------------------------------
// Parameters
// ------------------------------------------------------------------
// prettier-ignore
const Parameter = Runtime.Tuple([
Runtime.Ident(), Runtime.Const(Colon), Runtime.Ref<Types.TSchema>('Type')
], value => value[2])
// prettier-ignore
const Parameters = Runtime.Union([
Runtime.Tuple([Runtime.Ref('Parameter'), Runtime.Const(Comma), Runtime.Ref<unknown[]>('Parameters')]),
Runtime.Tuple([Runtime.Ref('Parameter'), Runtime.Const(Comma)]),
Runtime.Tuple([Runtime.Ref('Parameter')]),
Runtime.Tuple([]),
], value => (
value.length === 3 ? [value[0], ...value[2]] :
value.length === 2 ? [value[0]] :
value.length === 1 ? [value[0]] :
[]
))
// ------------------------------------------------------------------
// Constructor
// ------------------------------------------------------------------
// prettier-ignore
const Constructor = Runtime.Tuple([
Runtime.Const('new'),
Runtime.Const(LParen),
Runtime.Ref<Types.TSchema[]>('Parameters'),
Runtime.Const(RParen),
Runtime.Const('=>'),
Runtime.Ref<Types.TSchema>('Type')
], value => Types.Constructor(value[2], value[5]))
// ------------------------------------------------------------------
// Function
// ------------------------------------------------------------------
// prettier-ignore
const Function = Runtime.Tuple([
Runtime.Const(LParen),
Runtime.Ref<Types.TSchema[]>('Parameters'),
Runtime.Const(RParen),
Runtime.Const('=>'),
Runtime.Ref<Types.TSchema>('Type')
], value => Types.Function(value[1], value[4]))
// ------------------------------------------------------------------
// Mapped (requires deferred types)
// ------------------------------------------------------------------
// prettier-ignore
const MappedMapping = (values: unknown[]) => {
return Types.Literal('Mapped types not supported')
}
// prettier-ignore
const Mapped = Runtime.Tuple([
Runtime.Const(LBrace), Runtime.Const(LBracket), Runtime.Ident(), Runtime.Const('in'), Runtime.Ref<Types.TSchema>('Type'), Runtime.Const(RBracket), Runtime.Const(Colon), Runtime.Ref<Types.TSchema>('Type'), Runtime.Const(RBrace)
], MappedMapping)
// ------------------------------------------------------------------
// AsyncIterator
// ------------------------------------------------------------------
// prettier-ignore
const AsyncIterator = Runtime.Tuple([
Runtime.Const('AsyncIterator'),
Runtime.Const(LAngle),
Runtime.Ref<Types.TSchema>('Type'),
Runtime.Const(RAngle),
], value => Types.AsyncIterator(value[2]))
// ------------------------------------------------------------------
// Iterator
// ------------------------------------------------------------------
// prettier-ignore
const Iterator = Runtime.Tuple([
Runtime.Const('Iterator'),
Runtime.Const(LAngle),
Runtime.Ref<Types.TSchema>('Type'),
Runtime.Const(RAngle),
], value => Types.Iterator(value[2]))
// ------------------------------------------------------------------
// ConstructorParameters
// ------------------------------------------------------------------
// prettier-ignore
const ConstructorParameters = Runtime.Tuple([
Runtime.Const('ConstructorParameters'),
Runtime.Const(LAngle),
Runtime.Ref<Types.TConstructor>('Type'),
Runtime.Const(RAngle),
], value => Types.ConstructorParameters(value[2]))
// ------------------------------------------------------------------
// Parameters
// ------------------------------------------------------------------
// prettier-ignore
const FunctionParameters = Runtime.Tuple([
Runtime.Const('Parameters'),
Runtime.Const(LAngle),
Runtime.Ref<Types.TFunction>('Type'),
Runtime.Const(RAngle),
], value => Types.Parameters(value[2]))
// ------------------------------------------------------------------
// InstanceType
// ------------------------------------------------------------------
// prettier-ignore
const InstanceType = Runtime.Tuple([
Runtime.Const('InstanceType'),
Runtime.Const(LAngle),
Runtime.Ref<Types.TConstructor>('Type'),
Runtime.Const(RAngle),
], value => Types.InstanceType(value[2]))
// ------------------------------------------------------------------
// ReturnType
// ------------------------------------------------------------------
// prettier-ignore
const ReturnType = Runtime.Tuple([
Runtime.Const('ReturnType'),
Runtime.Const(LAngle),
Runtime.Ref<Types.TFunction>('Type'),
Runtime.Const(RAngle),
], value => Types.ReturnType(value[2]))
// ------------------------------------------------------------------
// Awaited
// ------------------------------------------------------------------
// prettier-ignore
const Awaited = Runtime.Tuple([
Runtime.Const('Awaited'),
Runtime.Const(LAngle),
Runtime.Ref<Types.TSchema>('Type'),
Runtime.Const(RAngle),
], value => Types.Awaited(value[2]))
// ------------------------------------------------------------------
// Array
// ------------------------------------------------------------------
// prettier-ignore
const Array = Runtime.Tuple([
Runtime.Const('Array'),
Runtime.Const(LAngle),
Runtime.Ref<Types.TSchema>('Type'),
Runtime.Const(RAngle),
], value => Types.Array(value[2]))
// ------------------------------------------------------------------
// Record
// ------------------------------------------------------------------
// prettier-ignore
const Record = Runtime.Tuple([
Runtime.Const('Record'),
Runtime.Const(LAngle),
Runtime.Ref<Types.TSchema>('Type'),
Runtime.Const(Comma),
Runtime.Ref<Types.TSchema>('Type'),
Runtime.Const(RAngle),
], value => Types.Record(value[2], value[4]))
// ------------------------------------------------------------------
// Promise
// ------------------------------------------------------------------
// prettier-ignore
const Promise = Runtime.Tuple([
Runtime.Const('Promise'),
Runtime.Const(LAngle),
Runtime.Ref<Types.TSchema>('Type'),
Runtime.Const(RAngle),
], value => Types.Promise(value[2]))
// ------------------------------------------------------------------
// Partial
// ------------------------------------------------------------------
// prettier-ignore
const Partial = Runtime.Tuple([
Runtime.Const('Partial'),
Runtime.Const(LAngle),
Runtime.Ref<Types.TSchema>('Type'),
Runtime.Const(RAngle),
], value => Types.Partial(value[2]))
// ------------------------------------------------------------------
// Required
// ------------------------------------------------------------------
// prettier-ignore
const Required = Runtime.Tuple([
Runtime.Const('Required'),
Runtime.Const(LAngle),
Runtime.Ref<Types.TSchema>('Type'),
Runtime.Const(RAngle),
], value => Types.Required(value[2]))
// ------------------------------------------------------------------
// Pick
// ------------------------------------------------------------------
// prettier-ignore
const Pick = Runtime.Tuple([
Runtime.Const('Pick'),
Runtime.Const(LAngle),
Runtime.Ref<Types.TSchema>('Type'),
Runtime.Const(Comma),
Runtime.Ref<Types.TSchema>('Type'),
Runtime.Const(RAngle),
], value => Types.Pick(value[2], value[4]))
// ------------------------------------------------------------------
// Omit
// ------------------------------------------------------------------
// prettier-ignore
const Omit = Runtime.Tuple([
Runtime.Const('Omit'),
Runtime.Const(LAngle),
Runtime.Ref<Types.TSchema>('Type'),
Runtime.Const(Comma),
Runtime.Ref<Types.TSchema>('Type'),
Runtime.Const(RAngle),
], value => Types.Omit(value[2], value[4]))
// ------------------------------------------------------------------
// Exclude
// ------------------------------------------------------------------
// prettier-ignore
const Exclude = Runtime.Tuple([
Runtime.Const('Exclude'),
Runtime.Const(LAngle),
Runtime.Ref<Types.TSchema>('Type'),
Runtime.Const(Comma),
Runtime.Ref<Types.TSchema>('Type'),
Runtime.Const(RAngle),
], value => Types.Exclude(value[2], value[4]))
// ------------------------------------------------------------------
// Extract
// ------------------------------------------------------------------
// prettier-ignore
const Extract = Runtime.Tuple([
Runtime.Const('Extract'),
Runtime.Const(LAngle),
Runtime.Ref<Types.TSchema>('Type'),
Runtime.Const(Comma),
Runtime.Ref<Types.TSchema>('Type'),
Runtime.Const(RAngle),
], value => Types.Extract(value[2], value[4]))
// ------------------------------------------------------------------
// Uppercase
// ------------------------------------------------------------------
// prettier-ignore
const Uppercase = Runtime.Tuple([
Runtime.Const('Uppercase'),
Runtime.Const(LAngle),
Runtime.Ref<Types.TSchema>('Type'),
Runtime.Const(RAngle),
], value => Types.Uppercase(value[2]))
// ------------------------------------------------------------------
// Lowercase
// ------------------------------------------------------------------
// prettier-ignore
const Lowercase = Runtime.Tuple([
Runtime.Const('Lowercase'),
Runtime.Const(LAngle),
Runtime.Ref<Types.TSchema>('Type'),
Runtime.Const(RAngle),
], value => Types.Lowercase(value[2]))
// ------------------------------------------------------------------
// Capitalize
// ------------------------------------------------------------------
// prettier-ignore
const Capitalize = Runtime.Tuple([
Runtime.Const('Capitalize'),
Runtime.Const(LAngle),
Runtime.Ref<Types.TSchema>('Type'),
Runtime.Const(RAngle),
], value => Types.Capitalize(value[2]))
// ------------------------------------------------------------------
// Uncapitalize
// ------------------------------------------------------------------
// prettier-ignore
const Uncapitalize = Runtime.Tuple([
Runtime.Const('Uncapitalize'),
Runtime.Const(LAngle),
Runtime.Ref<Types.TSchema>('Type'),
Runtime.Const(RAngle),
], value => Types.Uncapitalize(value[2]))
// ------------------------------------------------------------------
// Date
// ------------------------------------------------------------------
const Date = Runtime.Const('Date', Runtime.As(Types.Date()))
// ------------------------------------------------------------------
// Uint8Array
// ------------------------------------------------------------------
const Uint8Array = Runtime.Const('Uint8Array', Runtime.As(Types.Uint8Array()))
// ------------------------------------------------------------------
// Module
// ------------------------------------------------------------------
// prettier-ignore
export const Module = new Runtime.Module({
Literal,
Keyword,
KeyOf,
IndexArray,
Extends,
Base,
Factor,
ExprTermTail,
ExprTerm,
ExprTail,
Expr,
Type,
PropertyKey,
PropertyReadonly,
PropertyOptional,
Property,
PropertyDelimiter,
Properties,
Object,
Elements,
Tuple,
Parameter,
Function,
Parameters,
Constructor,
Mapped,
AsyncIterator,
Iterator,
Awaited,
Array,
Record,
Promise,
ConstructorParameters,
FunctionParameters,
InstanceType,
ReturnType,
Partial,
Required,
Pick,
Omit,
Exclude,
Extract,
Uppercase,
Lowercase,
Capitalize,
Uncapitalize,
Date,
Uint8Array,
Reference
})

764
src/parse/static.ts Normal file
View File

@@ -0,0 +1,764 @@
/*--------------------------------------------------------------------------
@sinclair/typebox
The MIT License (MIT)
Copyright (c) 2017-2024 Haydn Paterson (sinclair) <haydn.developer@gmail.com>
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
---------------------------------------------------------------------------*/
import { Static } from './parsebox/index'
import * as Types from '../type/index'
// ------------------------------------------------------------------
// Tokens
// ------------------------------------------------------------------
type Newline = '\n'
type LBracket = '['
type RBracket = ']'
type LParen = '('
type RParen = ')'
type LBrace = '{'
type RBrace = '}'
type LAngle = '<'
type RAngle = '>'
type Question = '?'
type Colon = ':'
type Comma = ','
type SemiColon = ';'
type SingleQuote = "'"
type DoubleQuote = '"'
type Tilde = '`'
// ------------------------------------------------------------------
// Delimit
//
// This type is used to perform a partial breadth match for repeated
// elements in a sequence. It used to mitigate depth+1 traversal for
// each element which helps prevent reaching instantiation limits. The
// technique works by infering as wide as possible on the sequence
// enabling TS to hoist interior matches, but does come at slight
// inference performance cost. The current (infer=9) is configured
// to match 64 terminal tuple elements.
//
// for the given sequence
//
// [a, b, c, d, e, f, g]
//
// ------------------------------------------------------------------
//
// without breadth mapping (infer=1, depth=6)
//
// [infer a,
// [infer b,
// [infer c,
// [infer d,
// [infer e,
// [infer f,
// [infer g,
// []]]]]]]]
//
// ------------------------------------------------------------------
//
// with breadth mapping (infer=4, depth=2)
//
// [infer a, infer b, infer c, infer d,
// [infer e, infer f, infer g,
// []]]
//
//
// ------------------------------------------------------------------
// prettier-ignore
interface DelimitTailMapping<_ = unknown> extends Static.IMapping {
output: (
this['input'] extends [_, infer A, _, infer B, _, infer C, _, infer D, _, infer E, _, infer F, _, infer G, _, infer H, _, infer I, _, infer Rest extends unknown[]] ? [A, B, C, D, E, F, G, H, I, ...Rest] :
this['input'] extends [_, infer A, _, infer B, _, infer C, _, infer D, _, infer E, _, infer F, _, infer G, _, infer H, _, infer Rest extends unknown[]] ? [A, B, C, D, E, F, G, H, ...Rest] :
this['input'] extends [_, infer A, _, infer B, _, infer C, _, infer D, _, infer E, _, infer F, _, infer G, _, infer Rest extends unknown[]] ? [A, B, C, D, E, F, G, ...Rest] :
this['input'] extends [_, infer A, _, infer B, _, infer C, _, infer D, _, infer E, _, infer F, _, infer Rest extends unknown[]] ? [A, B, C, D, E, F, ...Rest] :
this['input'] extends [_, infer A, _, infer B, _, infer C, _, infer D, _, infer E, _, infer Rest extends unknown[]] ? [A, B, C, D, E, ...Rest] :
this['input'] extends [_, infer A, _, infer B, _, infer C, _, infer D, _, infer Rest extends unknown[]] ? [A, B, C, D, ...Rest] :
this['input'] extends [_, infer A, _, infer B, _, infer C, _, infer Rest extends unknown[]] ? [A, B, C, ...Rest] :
this['input'] extends [_, infer A, _, infer B, _, infer Rest extends unknown[]] ? [A, B, ...Rest] :
this['input'] extends [_, infer A, _, infer Rest extends unknown[]] ? [A, ...Rest] :
this['input'] extends [_, infer Rest extends unknown[]] ? [...Rest] :
this['input'] extends [_] ? [] :
[]
)
}
// prettier-ignore
type DelimitTail<T extends Static.IParser, _ extends Static.IParser> = Static.Union<[
Static.Tuple<[_, T, _, T, _, T, _, T, _, T, _, T, _, T, _, T, _, T, _, Delimit<T, _>]>,
Static.Tuple<[_, T, _, T, _, T, _, T, _, T, _, T, _, T, _, T, _, Delimit<T, _>]>,
Static.Tuple<[_, T, _, T, _, T, _, T, _, T, _, T, _, T, _, Delimit<T, _>]>,
Static.Tuple<[_, T, _, T, _, T, _, T, _, T, _, T, _, Delimit<T, _>]>,
Static.Tuple<[_, T, _, T, _, T, _, T, _, T, _, Delimit<T, _>]>,
Static.Tuple<[_, T, _, T, _, T, _, T, _, Delimit<T, _>]>,
Static.Tuple<[_, T, _, T, _, T, _,Delimit<T, _>]>,
Static.Tuple<[_, T, _, T, _, Delimit<T, _>]>,
Static.Tuple<[_, T, _, Delimit<T, _>]>,
Static.Tuple<[_, Delimit<T, _>]>,
Static.Tuple<[_]>,
Static.Tuple<[]>
], DelimitTailMapping>
// prettier-ignore
interface DelimitMapping extends Static.IMapping {
output: (
this['input'] extends [infer Element extends unknown, infer Rest extends unknown[]]
? [Element, ...Rest]
: []
)
}
// prettier-ignore
type Delimit<Parser extends Static.IParser, Delimiter extends Static.IParser> = (
Static.Union<[
Static.Tuple<[Parser, DelimitTail<Parser, Delimiter>]>,
Static.Tuple<[]>
], DelimitMapping>
)
// ------------------------------------------------------------------
// Reference
// ------------------------------------------------------------------
// prettier-ignore
interface ReferenceMapping extends Static.IMapping {
output: this['input'] extends [infer Key extends string]
? Key extends keyof this['context']
? this['context'][Key]
: Types.TRef<Types.TUnknown>
: never
}
type Reference = Static.Tuple<[Static.Ident], ReferenceMapping>
// ------------------------------------------------------------------
// Literal
// ------------------------------------------------------------------
// prettier-ignore
interface LiteralBooleanMapping extends Static.IMapping {
output: this['input'] extends `${infer S extends boolean}` ? Types.TLiteral<S> : never
}
// prettier-ignore
interface LiteralNumberMapping extends Static.IMapping {
output: this['input'] extends `${infer S extends number}` ? Types.TLiteral<S> : never
}
// prettier-ignore
interface LiteralStringMapping extends Static.IMapping {
output: this['input'] extends `${infer S extends string}` ? Types.TLiteral<S> : never
}
// prettier-ignore
type Literal = Static.Union<[
Static.Union<[Static.Const<'true'>, Static.Const<'false'>], LiteralBooleanMapping>,
Static.Number<LiteralNumberMapping>,
Static.String<[DoubleQuote, SingleQuote, Tilde], LiteralStringMapping>,
]>
// ------------------------------------------------------------------
// Keyword
// ------------------------------------------------------------------
// prettier-ignore
type Keyword = Static.Union<[
Static.Const<'any', Static.As<Types.TAny>>,
Static.Const<'bigint', Static.As<Types.TBigInt>>,
Static.Const<'boolean', Static.As<Types.TBoolean>>,
Static.Const<'integer', Static.As<Types.TInteger>>,
Static.Const<'never', Static.As<Types.TNever>>,
Static.Const<'null', Static.As<Types.TNull>>,
Static.Const<'number', Static.As<Types.TNumber>>,
Static.Const<'string', Static.As<Types.TString>>,
Static.Const<'symbol', Static.As<Types.TSymbol>>,
Static.Const<'undefined', Static.As<Types.TUndefined>>,
Static.Const<'unknown', Static.As<Types.TUnknown>>,
Static.Const<'void', Static.As<Types.TVoid>>,
]>
// ------------------------------------------------------------------
// KeyOf
// ------------------------------------------------------------------
// prettier-ignore
interface KeyOfMapping extends Static.IMapping {
output: this['input'] extends [] ? false : true
}
// prettier-ignore
type KeyOf = Static.Union<[
Static.Tuple<[Static.Const<'keyof'>]>,
Static.Tuple<[]>
], KeyOfMapping>
// ------------------------------------------------------------------
// IndexArray
// ------------------------------------------------------------------
// prettier-ignore
interface IndexArrayMapping extends Static.IMapping {
output: (
this['input'] extends [LBracket, infer Type extends Types.TSchema, RBracket, infer Rest extends unknown[]] ? [[Type], ...Rest] :
this['input'] extends [LBracket, RBracket, infer Rest extends unknown[]] ? [[], ...Rest] :
[]
)
}
// prettier-ignore
type IndexArray = Static.Union<[
Static.Tuple<[Static.Const<LBracket>, Type, Static.Const<RBracket>, IndexArray]>,
Static.Tuple<[Static.Const<LBracket>, Static.Const<RBracket>, IndexArray]>,
Static.Tuple<[]>
], IndexArrayMapping>
// ------------------------------------------------------------------
// Extends
// ------------------------------------------------------------------
// prettier-ignore
interface ExtendsMapping extends Static.IMapping {
output: this['input'] extends ['extends', infer Type extends Types.TSchema, Question, infer True extends Types.TSchema, Colon, infer False extends Types.TSchema]
? [Type, True, False]
: []
}
// prettier-ignore
type Extends = Static.Union<[
Static.Tuple<[Static.Const<'extends'>, Type, Static.Const<Question>, Type, Static.Const<Colon>, Type]>,
Static.Tuple<[]>
], ExtendsMapping>
// ------------------------------------------------------------------
// Base
// ------------------------------------------------------------------
// prettier-ignore
interface BaseMapping extends Static.IMapping {
output: (
this['input'] extends [LParen, infer Type extends Types.TSchema, RParen] ? Type :
this['input'] extends [infer Type extends Types.TSchema] ? Type :
never
)
}
// prettier-ignore
type Base = Static.Union<[
Static.Tuple<[
Static.Const<LParen>,
Type,
Static.Const<RParen>
]>,
Static.Tuple<[Static.Union<[
Literal,
Keyword,
Object,
Tuple,
Function,
Constructor,
Mapped,
AsyncIterator,
Iterator,
ConstructorParameters,
FunctionParameters,
InstanceType,
ReturnType,
Awaited,
Array,
Record,
Promise,
Partial,
Required,
Pick,
Omit,
Exclude,
Extract,
Lowercase,
Uppercase,
Capitalize,
Uncapitalize,
Date,
Uint8Array,
Reference
]>]>
], BaseMapping>
// ------------------------------------------------------------------
// Factor
// ------------------------------------------------------------------
// prettier-ignore
type FactorExtends<Type extends Types.TSchema, Extends extends unknown[]> = (
Extends extends [infer Right extends Types.TSchema, infer True extends Types.TSchema, infer False extends Types.TSchema]
? Types.TExtends<Type, Right, True, False>
: Type
)
// prettier-ignore
type FactorIndexArray<Type extends Types.TSchema, IndexArray extends unknown[]> = (
IndexArray extends [...infer Left extends unknown[], infer Right extends Types.TSchema[]] ? (
Right extends [infer Indexer extends Types.TSchema] ? Types.TIndex<FactorIndexArray<Type, Left>, Types.TIndexPropertyKeys<Indexer>> :
Right extends [] ? Types.TArray<FactorIndexArray<Type, Left>> :
Types.TNever
) : Type
)
// prettier-ignore
interface FactorMapping extends Static.IMapping {
output: this['input'] extends [infer KeyOf extends boolean, infer Type extends Types.TSchema, infer IndexArray extends unknown[], infer Extends extends unknown[]]
? KeyOf extends true
? FactorExtends<Types.TKeyOf<FactorIndexArray<Type, IndexArray>>, Extends>
: FactorExtends<FactorIndexArray<Type, IndexArray>, Extends>
: never
}
// prettier-ignore
type Factor = Static.Tuple<[
KeyOf, Base, IndexArray, Extends
], FactorMapping>
// ------------------------------------------------------------------
// Expr
// ------------------------------------------------------------------
// prettier-ignore
type ExprBinaryReduce<Left extends Types.TSchema, Rest extends unknown[]> = (
Rest extends [infer Operator extends unknown, infer Right extends Types.TSchema, infer Next extends unknown[]] ? (
ExprBinaryReduce<Right, Next> extends infer Schema extends Types.TSchema ? (
Operator extends '&' ? (
Schema extends Types.TIntersect<infer Types extends Types.TSchema[]>
? Types.TIntersect<[Left, ...Types]>
: Types.TIntersect<[Left, Schema]>
) :
Operator extends '|' ? (
Schema extends Types.TUnion<infer Types extends Types.TSchema[]>
? Types.TUnion<[Left, ...Types]>
: Types.TUnion<[Left, Schema]>
) : never
) : never
) : Left
)
// prettier-ignore
interface ExprBinaryMapping extends Static.IMapping {
output: (
this['input'] extends [infer Left extends Types.TSchema, infer Rest extends unknown[]]
? ExprBinaryReduce<Left, Rest>
: []
)
}
// prettier-ignore
type ExprTermTail = Static.Union<[
Static.Tuple<[Static.Const<'&'>, Factor, ExprTermTail]>,
Static.Tuple<[]>
]>
// prettier-ignore
type ExprTerm = Static.Tuple<[
Factor, ExprTermTail
], ExprBinaryMapping>
// prettier-ignore
type ExprTail = Static.Union<[
Static.Tuple<[Static.Const<'|'>, ExprTerm, ExprTail]>,
Static.Tuple<[]>
]>
// prettier-ignore
type Expr = Static.Tuple<[
ExprTerm, ExprTail
], ExprBinaryMapping>
// ------------------------------------------------------------------
// Type
// ------------------------------------------------------------------
export type Type = Expr
// ------------------------------------------------------------------
// Properties
// ------------------------------------------------------------------
// prettier-ignore
interface PropertyKeyStringMapping extends Static.IMapping {
output: this['input']
}
type PropertyKeyString = Static.String<[SingleQuote, DoubleQuote], PropertyKeyStringMapping>
type PropertyKey = Static.Union<[Static.Ident, PropertyKeyString]>
// prettier-ignore
interface PropertyReadonlyMapping extends Static.IMapping {
output: this['input'] extends ['readonly'] ? true : false
}
type PropertyReadonly = Static.Union<[Static.Tuple<[Static.Const<'readonly'>]>, Static.Tuple<[]>], PropertyReadonlyMapping>
// prettier-ignore
interface PropertyOptionalMapping extends Static.IMapping {
output: this['input'] extends [Question] ? true : false
}
type PropertyOptional = Static.Union<[Static.Tuple<[Static.Const<Question>]>, Static.Tuple<[]>], PropertyOptionalMapping>
// prettier-ignore
interface PropertyMapping extends Static.IMapping {
output: this['input'] extends [infer Readonly extends boolean, infer Key extends string, infer Optional extends boolean, string, infer Type extends Types.TSchema]
? {
[_ in Key]: (
[Readonly, Optional] extends [true, true] ? Types.TReadonlyOptional<Type> :
[Readonly, Optional] extends [true, false] ? Types.TReadonly<Type> :
[Readonly, Optional] extends [false, true] ? Types.TOptional<Type> :
Type
)
} : never
}
type Property = Static.Tuple<[PropertyReadonly, PropertyKey, PropertyOptional, Static.Const<Colon>, Type], PropertyMapping>
type PropertiesEvaluate<T> = { [K in keyof T]: T[K] } & {}
// prettier-ignore
type PropertyDelimiter = Static.Union<[
Static.Tuple<[Static.Const<Comma>, Static.Const<Newline>]>,
Static.Tuple<[Static.Const<SemiColon>, Static.Const<Newline>]>,
Static.Tuple<[Static.Const<Comma>]>,
Static.Tuple<[Static.Const<SemiColon>]>,
Static.Tuple<[Static.Const<Newline>]>,
]>
// prettier-ignore
type PropertiesReduce<PropertiesArray extends Types.TProperties[], Result extends Types.TProperties = {}> = (
PropertiesArray extends [infer Left extends Types.TProperties, ...infer Right extends Types.TProperties[]]
? PropertiesReduce<Right, PropertiesEvaluate<Result & Left>>
: Result
)
// prettier-ignore
interface PropertiesMapping extends Static.IMapping {
output: this['input'] extends Types.TProperties[] ? PropertiesReduce<this['input']> : never
}
type Properties = Static.Union<[Delimit<Property, PropertyDelimiter>], PropertiesMapping>
// ------------------------------------------------------------------
// Object
// ------------------------------------------------------------------
// prettier-ignore
interface ObjectMapping extends Static.IMapping {
output: this['input'] extends [unknown, infer Properties extends Types.TProperties, unknown]
? Types.TObject<Properties>
: never
}
// prettier-ignore
type Object = Static.Tuple<[
Static.Const<LBrace>, Properties, Static.Const<RBrace>
], ObjectMapping>
// ------------------------------------------------------------------
// Tuple
// ------------------------------------------------------------------
type Elements = Delimit<Type, Static.Const<Comma>>
// prettier-ignore
interface TupleMapping extends Static.IMapping {
output: this['input'] extends [unknown, infer Elements extends Types.TSchema[], unknown] ? Types.TTuple<Elements> : never
}
// prettier-ignore
type Tuple = Static.Tuple<[
Static.Const<LBracket>, Elements, Static.Const<RBracket>
], TupleMapping>
// ------------------------------------------------------------------
// Parameters
// ------------------------------------------------------------------
interface ParameterMapping extends Static.IMapping {
output: this['input'] extends [string, Colon, infer Type extends Types.TSchema] ? Type : never
}
// prettier-ignore
type Parameter = Static.Tuple<[
Static.Ident, Static.Const<Colon>, Type
], ParameterMapping>
type Parameters = Delimit<Parameter, Static.Const<Comma>>
// ------------------------------------------------------------------
// Function
// ------------------------------------------------------------------
// prettier-ignore
interface FunctionMapping extends Static.IMapping {
output: this['input'] extends [LParen, infer Parameters extends Types.TSchema[], RParen, '=>', infer ReturnType extends Types.TSchema]
? Types.TFunction<Parameters, ReturnType>
: never
}
// prettier-ignore
type Function = Static.Tuple<[
Static.Const<LParen>, Parameters, Static.Const<RParen>, Static.Const<'=>'>, Type
], FunctionMapping>
// ------------------------------------------------------------------
// Constructor
// ------------------------------------------------------------------
// prettier-ignore
interface ConstructorMapping extends Static.IMapping {
output: this['input'] extends ['new', LParen, infer Parameters extends Types.TSchema[], RParen, '=>', infer InstanceType extends Types.TSchema]
? Types.TConstructor<Parameters, InstanceType>
: never
}
// prettier-ignore
type Constructor = Static.Tuple<[
Static.Const<'new'>, Static.Const<LParen>, Parameters, Static.Const<RParen>, Static.Const<'=>'>, Type
], ConstructorMapping>
// ------------------------------------------------------------------
// Mapped (requires deferred types)
// ------------------------------------------------------------------
// prettier-ignore
interface MappedMapping extends Static.IMapping {
output: this['input'] extends [LBrace, LBracket, infer Key extends string, 'in', infer Right extends Types.TSchema, RBracket, Colon, infer Type extends Types.TSchema, RBrace]
? Types.TLiteral<'Mapped types not supported'>
: this['input']
}
// prettier-ignore
type Mapped = Static.Tuple<[
Static.Const<LBrace>, Static.Const<LBracket>, Static.Ident, Static.Const<'in'>, Type, Static.Const<RBracket>, Static.Const<Colon>, Type, Static.Const<RBrace>
], MappedMapping>
// ------------------------------------------------------------------
// Array
// ------------------------------------------------------------------
// prettier-ignore
interface ArrayMapping extends Static.IMapping {
output: this['input'] extends ['Array', LAngle, infer Type extends Types.TSchema, RAngle]
? Types.TArray<Type>
: never
}
// prettier-ignore
type Array = Static.Tuple<[
Static.Const<'Array'>, Static.Const<LAngle>, Type, Static.Const<RAngle>,
], ArrayMapping>
// ------------------------------------------------------------------
// AsyncIterator
// ------------------------------------------------------------------
// prettier-ignore
interface AsyncIteratorMapping extends Static.IMapping {
output: this['input'] extends ['AsyncIterator', LAngle, infer Type extends Types.TSchema, RAngle]
? Types.TAsyncIterator<Type>
: never
}
// prettier-ignore
type AsyncIterator = Static.Tuple<[
Static.Const<'AsyncIterator'>, Static.Const<LAngle>, Type, Static.Const<RAngle>,
], AsyncIteratorMapping>
// ------------------------------------------------------------------
// Iterator
// ------------------------------------------------------------------
// prettier-ignore
interface IteratorMapping extends Static.IMapping {
output: this['input'] extends ['Iterator', LAngle, infer Type extends Types.TSchema, RAngle]
? Types.TIterator<Type>
: never
}
// prettier-ignore
type Iterator = Static.Tuple<[
Static.Const<'Iterator'>, Static.Const<LAngle>, Type, Static.Const<RAngle>,
], IteratorMapping>
// ------------------------------------------------------------------
// ConstructorParameters
// ------------------------------------------------------------------
// prettier-ignore
interface ConstructorParametersMapping extends Static.IMapping {
output: this['input'] extends ['ConstructorParameters', LAngle, infer Type extends Types.TConstructor, RAngle]
? Types.TConstructorParameters<Type>
: never
}
// prettier-ignore
type ConstructorParameters = Static.Tuple<[
Static.Const<'ConstructorParameters'>, Static.Const<LAngle>, Type, Static.Const<RAngle>,
], ConstructorParametersMapping>
// ------------------------------------------------------------------
// FunctionParameters
// ------------------------------------------------------------------
// prettier-ignore
interface FunctionParametersMapping extends Static.IMapping {
output: this['input'] extends ['Parameters', LAngle, infer Type extends Types.TFunction, RAngle]
? Types.TParameters<Type>
: never
}
// prettier-ignore
type FunctionParameters = Static.Tuple<[
Static.Const<'Parameters'>, Static.Const<LAngle>, Type, Static.Const<RAngle>,
], FunctionParametersMapping>
// ------------------------------------------------------------------
// InstanceType
// ------------------------------------------------------------------
// prettier-ignore
interface InstanceTypeMapping extends Static.IMapping {
output: this['input'] extends ['InstanceType', LAngle, infer Type extends Types.TConstructor, RAngle]
? Types.TInstanceType<Type>
: never
}
// prettier-ignore
type InstanceType = Static.Tuple<[
Static.Const<'InstanceType'>, Static.Const<LAngle>, Type, Static.Const<RAngle>,
], InstanceTypeMapping>
// ------------------------------------------------------------------
// ReturnType
// ------------------------------------------------------------------
// prettier-ignore
interface ReturnTypeMapping extends Static.IMapping {
output: this['input'] extends ['ReturnType', LAngle, infer Type extends Types.TFunction, RAngle]
? Types.TReturnType<Type>
: never
}
// prettier-ignore
type ReturnType = Static.Tuple<[
Static.Const<'ReturnType'>, Static.Const<LAngle>, Type, Static.Const<RAngle>,
], ReturnTypeMapping>
// ------------------------------------------------------------------
// Awaited
// ------------------------------------------------------------------
// prettier-ignore
interface AwaitedMapping extends Static.IMapping {
output: this['input'] extends ['Awaited', LAngle, infer Type extends Types.TSchema, RAngle]
? Types.TAwaited<Type>
: never
}
// prettier-ignore
type Awaited = Static.Tuple<[
Static.Const<'Awaited'>, Static.Const<LAngle>, Type, Static.Const<RAngle>,
], AwaitedMapping>
// ------------------------------------------------------------------
// Promise
// ------------------------------------------------------------------
// prettier-ignore
interface PromiseMapping extends Static.IMapping {
output: this['input'] extends ['Promise', LAngle, infer Type extends Types.TSchema, RAngle]
? Types.TPromise<Type>
: never
}
// prettier-ignore
type Promise = Static.Tuple<[
Static.Const<'Promise'>, Static.Const<LAngle>, Type, Static.Const<RAngle>,
], PromiseMapping>
// ------------------------------------------------------------------
// Record
// ------------------------------------------------------------------
// prettier-ignore
interface RecordMapping extends Static.IMapping {
output: this['input'] extends ['Record', LAngle, infer Key extends Types.TSchema, Comma, infer Type extends Types.TSchema, RAngle]
? Types.TRecord<Key, Type>
: never
}
// prettier-ignore
type Record = Static.Tuple<[
Static.Const<'Record'>, Static.Const<LAngle>, Type, Static.Const<Comma>, Type, Static.Const<RAngle>,
], RecordMapping>
// ------------------------------------------------------------------
// Partial
// ------------------------------------------------------------------
// prettier-ignore
interface PartialMapping extends Static.IMapping {
output: this['input'] extends ['Partial', LAngle, infer Type extends Types.TSchema, RAngle]
? Types.TPartial<Type>
: never
}
// prettier-ignore
type Partial = Static.Tuple<[
Static.Const<'Partial'>, Static.Const<LAngle>, Type, Static.Const<RAngle>,
], PartialMapping>
// ------------------------------------------------------------------
// Required
// ------------------------------------------------------------------
// prettier-ignore
interface RequiredMapping extends Static.IMapping {
output: this['input'] extends ['Required', LAngle, infer Type extends Types.TSchema, RAngle]
? Types.TPartial<Type>
: never
}
// prettier-ignore
type Required = Static.Tuple<[
Static.Const<'Required'>, Static.Const<LAngle>, Type, Static.Const<RAngle>,
], RequiredMapping>
// ------------------------------------------------------------------
// Pick
// ------------------------------------------------------------------
// prettier-ignore
interface PickMapping extends Static.IMapping {
output: this['input'] extends ['Pick', LAngle, infer Type extends Types.TSchema, Comma, infer PropertyKey extends Types.TSchema, RAngle]
? Types.TPick<Type, Types.TIndexPropertyKeys<PropertyKey>>
: never
}
// prettier-ignore
type Pick = Static.Tuple<[
Static.Const<'Pick'>, Static.Const<LAngle>, Type, Static.Const<Comma>, Type, Static.Const<RAngle>,
], PickMapping>
// ------------------------------------------------------------------
// Omit
// ------------------------------------------------------------------
// prettier-ignore
interface OmitMapping extends Static.IMapping {
output: this['input'] extends ['Omit', LAngle, infer Type extends Types.TSchema, Comma, infer PropertyKey extends Types.TSchema, RAngle]
? Types.TOmit<Type, Types.TIndexPropertyKeys<PropertyKey>>
: never
}
// prettier-ignore
type Omit = Static.Tuple<[
Static.Const<'Omit'>, Static.Const<LAngle>, Type, Static.Const<Comma>, Type, Static.Const<RAngle>
], OmitMapping>
// ------------------------------------------------------------------
// Exclude
// ------------------------------------------------------------------
// prettier-ignore
interface ExcludeMapping extends Static.IMapping {
output: this['input'] extends ['Exclude', LAngle, infer Type extends Types.TSchema, Comma, infer PropertyKey extends Types.TSchema, RAngle]
? Types.TExclude<Type, PropertyKey>
: never
}
// prettier-ignore
type Exclude = Static.Tuple<[
Static.Const<'Exclude'>, Static.Const<LAngle>, Type, Static.Const<Comma>, Type, Static.Const<RAngle>
], ExcludeMapping>
// ------------------------------------------------------------------
// Extract
// ------------------------------------------------------------------
// prettier-ignore
interface ExtractMapping extends Static.IMapping {
output: this['input'] extends ['Extract', LAngle, infer Type extends Types.TSchema, Comma, infer PropertyKey extends Types.TSchema, RAngle]
? Types.TExtract<Type, PropertyKey>
: never
}
// prettier-ignore
type Extract = Static.Tuple<[
Static.Const<'Extract'>, Static.Const<LAngle>, Type, Static.Const<Comma>, Type, Static.Const<RAngle>
], ExtractMapping>
// ------------------------------------------------------------------
// Uppercase
// ------------------------------------------------------------------
// prettier-ignore
interface UppercaseMapping extends Static.IMapping {
output: this['input'] extends ['Uppercase', LAngle, infer Type extends Types.TSchema, RAngle]
? Types.TUppercase<Type>
: never
}
// prettier-ignore
type Uppercase = Static.Tuple<[
Static.Const<'Uppercase'>, Static.Const<LAngle>, Type, Static.Const<RAngle>,
], UppercaseMapping>
// ------------------------------------------------------------------
// Lowercase
// ------------------------------------------------------------------
// prettier-ignore
interface LowercaseMapping extends Static.IMapping {
output: this['input'] extends ['Lowercase', LAngle, infer Type extends Types.TSchema, RAngle]
? Types.TLowercase<Type>
: never
}
// prettier-ignore
type Lowercase = Static.Tuple<[
Static.Const<'Lowercase'>, Static.Const<LAngle>, Type, Static.Const<RAngle>,
], LowercaseMapping>
// ------------------------------------------------------------------
// Capitalize
// ------------------------------------------------------------------
// prettier-ignore
interface CapitalizeMapping extends Static.IMapping {
output: this['input'] extends ['Capitalize', LAngle, infer Type extends Types.TSchema, RAngle]
? Types.TCapitalize<Type>
: never
}
// prettier-ignore
type Capitalize = Static.Tuple<[
Static.Const<'Capitalize'>, Static.Const<LAngle>, Type, Static.Const<RAngle>,
], CapitalizeMapping>
// ------------------------------------------------------------------
// Uncapitalize
// ------------------------------------------------------------------
// prettier-ignore
interface UncapitalizeMapping extends Static.IMapping {
output: this['input'] extends ['Uncapitalize', LAngle, infer Type extends Types.TSchema, RAngle]
? Types.TUncapitalize<Type>
: never
}
// prettier-ignore
type Uncapitalize = Static.Tuple<[
Static.Const<'Uncapitalize'>, Static.Const<LAngle>, Type, Static.Const<RAngle>,
], UncapitalizeMapping>
// ------------------------------------------------------------------
// Date
// ------------------------------------------------------------------
type Date = Static.Const<'Date', Static.As<Types.TDate>>
// ------------------------------------------------------------------
// Uint8Array
// ------------------------------------------------------------------
type Uint8Array = Static.Const<'Uint8Array', Static.As<Types.TUint8Array>>

View File

@@ -0,0 +1,3 @@
import * as Parse from '@sinclair/typebox/parse'
console.log(Parse)

View File

@@ -32,7 +32,7 @@ import { createPackageJson } from './create-package-json'
/** Builds package.json and redirect directories */
export async function build(target: string) {
console.log('building...package.json')
const submodules = ['compiler', 'errors', 'system', 'type', 'value']
const submodules = ['compiler', 'errors', 'parse', 'system', 'type', 'value']
await createPackageJsonRedirect(target, submodules)
await createPackageJson(target, submodules)
}

View File

@@ -8,6 +8,7 @@ TypeSystemPolicy.InstanceMode = 'freeze'
import './compiler/index'
import './compiler-ajv/index'
import './errors/index'
import './parse/index'
import './system/index'
import './type/index'
import './value/index'

View File

@@ -0,0 +1 @@
import './parse'

389
test/runtime/parse/parse.ts Normal file
View File

@@ -0,0 +1,389 @@
import { TypeGuard } from '@sinclair/typebox'
import { Type, Parse } from '@sinclair/typebox'
import { Assert } from '../assert/index'
// prettier-ignore
describe('parse/Parse', () => {
it('Should parse Any', () => {
const T = Parse(`any`)
Assert.IsTrue(TypeGuard.IsAny(T))
})
it('Should parse Array 1', () => {
const T = Parse(`number[]`)
Assert.IsTrue(TypeGuard.IsArray(T))
Assert.IsTrue(TypeGuard.IsNumber(T.items))
})
it('Should parse Array 2', () => {
const T = Parse(`Array<number>`)
Assert.IsTrue(TypeGuard.IsArray(T))
Assert.IsTrue(TypeGuard.IsNumber(T.items))
})
it('Should parse AsyncIterator', () => {
const T = Parse(`AsyncIterator<number>`)
Assert.IsTrue(TypeGuard.IsAsyncIterator(T))
Assert.IsTrue(TypeGuard.IsNumber(T.items))
})
it('Should parse Awaited', () => {
const T = Parse(`Awaited<Promise<number>>`)
Assert.IsTrue(TypeGuard.IsNumber(T))
})
it('Should parse BigInt', () => {
const T = Parse(`bigint`)
Assert.IsTrue(TypeGuard.IsBigInt(T))
})
it('Should parse Boolean', () => {
const T = Parse(`boolean`)
Assert.IsTrue(TypeGuard.IsBoolean(T))
})
it('Should parse ConstructorParameters', () => {
const T = Parse(`ConstructorParameters<new (a: number, b: string) => boolean>`)
Assert.IsTrue(TypeGuard.IsTuple(T))
Assert.IsTrue(TypeGuard.IsNumber(T.items![0]))
Assert.IsTrue(TypeGuard.IsString(T.items![1]))
})
it('Should parse Constructor', () => {
const T = Parse(`new (a: number, b: string) => boolean`)
Assert.IsTrue(TypeGuard.IsConstructor(T))
Assert.IsTrue(TypeGuard.IsNumber(T.parameters[0]))
Assert.IsTrue(TypeGuard.IsString(T.parameters[1]))
Assert.IsTrue(TypeGuard.IsBoolean(T.returns))
})
it('Should parse Date', () => {
const T = Parse(`Date`)
Assert.IsTrue(TypeGuard.IsDate(T))
})
it('Should parse Exclude', () => {
const T = Parse(`Exclude<1 | 2 | 3, 1>`)
Assert.IsTrue(TypeGuard.IsUnion(T))
Assert.IsTrue(T.anyOf[0].const === 2)
Assert.IsTrue(T.anyOf[1].const === 3)
})
it('Should parse Extract', () => {
const T = Parse(`Extract<1 | 2 | 3, 1 | 2>`)
Assert.IsTrue(TypeGuard.IsUnion(T))
// @ts-ignore fix: incorrect union order (result of UnionToTuple, replace with Tuple destructuring)
Assert.IsTrue(T.anyOf[0].const === 1)
// @ts-ignore fix: incorrect union order (result of UnionToTuple, replace with Tuple destructuring)
Assert.IsTrue(T.anyOf[1].const === 2)
})
it('Should parse Function', () => {
const T = Parse(`(a: number, b: string) => boolean`)
Assert.IsTrue(TypeGuard.IsFunction(T))
Assert.IsTrue(TypeGuard.IsNumber(T.parameters[0]))
Assert.IsTrue(TypeGuard.IsString(T.parameters[1]))
Assert.IsTrue(TypeGuard.IsBoolean(T.returns))
})
it('Should parse Indexed 1', () => {
const T = Parse(`{ x: 1, y: 2, z: 3 }['x']`)
Assert.IsTrue(T.const === 1)
})
it('Should parse Indexed 2', () => {
const T = Parse(`{ x: 1, y: 2, z: 3 }['x' | 'y' | 'z']`)
Assert.IsTrue(TypeGuard.IsUnion(T))
Assert.IsTrue(T.anyOf[0].const === 1)
Assert.IsTrue(T.anyOf[1].const === 2)
Assert.IsTrue(T.anyOf[2].const === 3)
})
it('Should parse Indexed 3', () => {
const T = Parse(`{ x: 1, y: 2, z: 3 }`)
const S = Parse({ T }, `T[keyof T]`)
Assert.IsTrue(TypeGuard.IsUnion(S))
Assert.IsTrue(S.anyOf[0].const === 1)
Assert.IsTrue(S.anyOf[1].const === 2)
Assert.IsTrue(S.anyOf[2].const === 3)
})
it('Should parse Indexed 4', () => {
const T = Parse(`['A', 'B', 'C']`)
const S = Parse({ T }, `T[number]`)
Assert.IsTrue(TypeGuard.IsUnion(S))
Assert.IsTrue(S.anyOf[0].const === 'A')
Assert.IsTrue(S.anyOf[1].const === 'B')
Assert.IsTrue(S.anyOf[2].const === 'C')
})
it('Should parse Integer', () => {
const T = Parse(`integer`)
Assert.IsTrue(TypeGuard.IsInteger(T))
})
it('Should parse Intersect 1', () => {
const T = Parse(`1 & 2`)
Assert.IsTrue(TypeGuard.IsIntersect(T))
Assert.IsTrue(T.allOf[0].const === 1)
Assert.IsTrue(T.allOf[1].const === 2)
})
it('Should parse Intersect 2', () => {
const T = Parse(`1 & (2 & 3)`) // expect flatten
Assert.IsTrue(TypeGuard.IsIntersect(T))
Assert.IsTrue(T.allOf[0].const === 1)
Assert.IsTrue(T.allOf[1].const === 2)
Assert.IsTrue(T.allOf[2].const === 3)
})
it('Should parse Intersect 3', () => {
const T = Parse(`(1 | 2) & 3`) // operator precedence
Assert.IsTrue(TypeGuard.IsIntersect(T))
Assert.IsTrue(TypeGuard.IsUnion(T.allOf[0]))
Assert.IsTrue(T.allOf[1].const === 3)
})
it('Should parse InstanceType 1', () => {
const T = Parse(`InstanceType<new () => { x: 1, y: 2 }>`)
Assert.IsTrue(TypeGuard.IsObject(T))
Assert.IsTrue(T.properties.x.const === 1)
Assert.IsTrue(T.properties.y.const === 2)
})
it('Should parse InstanceType 2', () => {
const T = Parse(`InstanceType<number>`) // generalization issue
Assert.IsTrue(T === undefined)
})
it('Should parse Iterator', () => {
const T = Parse(`Iterator<number>`)
Assert.IsTrue(TypeGuard.IsIterator(T))
Assert.IsTrue(TypeGuard.IsNumber(T.items))
})
it('Should parse KeyOf 1', () => {
const T = Parse(`keyof { x: 1, y: 2 }`)
Assert.IsTrue(TypeGuard.IsUnion(T))
Assert.IsTrue(T.anyOf[0].const === 'x')
Assert.IsTrue(T.anyOf[1].const === 'y')
})
it('Should parse KeyOf 2', () => {
const T = Parse(`keyof [0, 1]`)
Assert.IsTrue(TypeGuard.IsUnion(T))
Assert.IsTrue(T.anyOf[0].const === '0')
Assert.IsTrue(T.anyOf[1].const === '1')
})
it('Should parse KeyOf 3', () => {
const T = Parse(`{ x: 1, y: 2 }`)
const S = Parse({ T }, `keyof T`)
Assert.IsTrue(TypeGuard.IsUnion(S))
Assert.IsTrue(S.anyOf[0].const === 'x')
Assert.IsTrue(S.anyOf[1].const === 'y')
})
it('Should parse Literal Boolean 1', () => {
const T = Parse(`true`)
Assert.IsTrue(T.const === true)
})
it('Should parse Literal Boolean 2', () => {
const T = Parse(`false`)
Assert.IsTrue(T.const === false)
})
it('Should parse Literal Number', () => {
const T = Parse(`1`)
Assert.IsTrue(T.const === 1)
})
it('Should parse Literal String', () => {
const T = Parse(`'1'`)
Assert.IsTrue(T.const === '1')
})
it('Should parse Mapped (Pending)', () => {
const T = Parse(`{ [K in 1 | 2 | 3]: K }`)
Assert.IsTrue(T.const === 'Mapped types not supported')
})
it('Should parse Never', () => {
const T = Parse(`never`)
Assert.IsTrue(TypeGuard.IsNever(T))
})
it('Should parse Null', () => {
const T = Parse(`null`)
Assert.IsTrue(TypeGuard.IsNull(T))
})
it('Should parse Number', () => {
const T = Parse(`number`)
Assert.IsTrue(TypeGuard.IsNumber(T))
})
it('Should parse Object 1', () => {
const T = Parse(`{x: boolean, y: number, z: string, }`)
Assert.IsTrue(TypeGuard.IsObject(T))
Assert.IsTrue(TypeGuard.IsBoolean(T.properties.x))
Assert.IsTrue(TypeGuard.IsNumber(T.properties.y))
Assert.IsTrue(TypeGuard.IsString(T.properties.z))
})
it('Should parse Object 2', () => {
const T = Parse(`{x: boolean; y: number; z: string; }`)
Assert.IsTrue(TypeGuard.IsObject(T))
Assert.IsTrue(TypeGuard.IsBoolean(T.properties.x))
Assert.IsTrue(TypeGuard.IsNumber(T.properties.y))
Assert.IsTrue(TypeGuard.IsString(T.properties.z))
})
it('Should parse Object 3', () => {
const T = Parse(`{
x: boolean
y: number
z: string
}`)
Assert.IsTrue(TypeGuard.IsObject(T))
Assert.IsTrue(TypeGuard.IsBoolean(T.properties.x))
Assert.IsTrue(TypeGuard.IsNumber(T.properties.y))
Assert.IsTrue(TypeGuard.IsString(T.properties.z))
})
it('Should parse Object 4', () => {
const T = Parse(`{
x: boolean;
y: number;
z: string;
}`)
Assert.IsTrue(TypeGuard.IsObject(T))
Assert.IsTrue(TypeGuard.IsBoolean(T.properties.x))
Assert.IsTrue(TypeGuard.IsNumber(T.properties.y))
Assert.IsTrue(TypeGuard.IsString(T.properties.z))
})
it('Should parse Object 5', () => {
const T = Parse(`{
x: boolean,
y: number,
z: string,
}`)
Assert.IsTrue(TypeGuard.IsObject(T))
Assert.IsTrue(TypeGuard.IsBoolean(T.properties.x))
Assert.IsTrue(TypeGuard.IsNumber(T.properties.y))
Assert.IsTrue(TypeGuard.IsString(T.properties.z))
})
it('Should parse Omit 1', () => {
const T = Parse(`Omit<{ x: boolean, y: number, z: string }, 'z'>`)
Assert.IsTrue(TypeGuard.IsObject(T))
Assert.IsTrue(TypeGuard.IsBoolean(T.properties.x))
Assert.IsTrue(TypeGuard.IsNumber(T.properties.y))
Assert.IsTrue(('z' in T.properties) === false)
})
it('Should parse Omit 2', () => {
const T = Parse(`Omit<{ x: boolean, y: number, z: string }, 'z' | 'y'>`)
Assert.IsTrue(TypeGuard.IsObject(T))
Assert.IsTrue(TypeGuard.IsBoolean(T.properties.x))
Assert.IsTrue(('y' in T.properties) === false)
Assert.IsTrue(('z' in T.properties) === false)
})
it('Should parse Parameters', () => {
const T = Parse(`Parameters<(a: number, b: string) => boolean>`)
Assert.IsTrue(TypeGuard.IsTuple(T))
Assert.IsTrue(TypeGuard.IsNumber(T.items![0]))
Assert.IsTrue(TypeGuard.IsString(T.items![1]))
})
it('Should parse Partial', () => {
const T = Parse(`Partial<{ x: boolean, y: number, z: string }>`)
Assert.IsTrue(TypeGuard.IsObject(T))
Assert.IsTrue(('required' in T) === false)
})
it('Should parse Pick 1', () => {
const T = Parse(`Pick<{ x: boolean, y: number, z: string }, 'x' | 'y'>`)
Assert.IsTrue(TypeGuard.IsObject(T))
Assert.IsTrue(TypeGuard.IsBoolean(T.properties.x))
Assert.IsTrue(TypeGuard.IsNumber(T.properties.y))
Assert.IsTrue(('z' in T.properties) === false)
})
it('Should parse Pick 2', () => {
const T = Parse(`Pick<{ x: boolean, y: number, z: string }, 'x'>`)
Assert.IsTrue(TypeGuard.IsObject(T))
Assert.IsTrue(TypeGuard.IsBoolean(T.properties.x))
Assert.IsTrue(('y' in T.properties) === false)
Assert.IsTrue(('z' in T.properties) === false)
})
it('Should parse Promise', () => {
const T = Parse(`Promise<number>`)
Assert.IsTrue(TypeGuard.IsPromise(T))
Assert.IsTrue(TypeGuard.IsNumber(T.item))
})
it('Should parse ReadonlyOptional', () => {
const T = Parse(`{ readonly x?: boolean, readonly y?: number }`)
Assert.IsTrue(TypeGuard.IsObject(T))
Assert.IsTrue(TypeGuard.IsBoolean(T.properties.x))
Assert.IsTrue(TypeGuard.IsReadonly(T.properties.x))
Assert.IsTrue(TypeGuard.IsOptional(T.properties.x))
Assert.IsTrue(TypeGuard.IsNumber(T.properties.y))
Assert.IsTrue(TypeGuard.IsReadonly(T.properties.y))
Assert.IsTrue(TypeGuard.IsOptional(T.properties.y))
})
it('Should parse Readonly', () => {
const T = Parse(`{ readonly x: boolean, readonly y: number }`)
Assert.IsTrue(TypeGuard.IsObject(T))
Assert.IsTrue(TypeGuard.IsBoolean(T.properties.x))
Assert.IsTrue(TypeGuard.IsReadonly(T.properties.x))
Assert.IsTrue(TypeGuard.IsNumber(T.properties.y))
Assert.IsTrue(TypeGuard.IsReadonly(T.properties.y))
})
it('Should parse Record 1', () => {
const T = Parse(`Record<string, number>`)
Assert.IsTrue(TypeGuard.IsRecord(T))
Assert.IsTrue(TypeGuard.IsNumber(T.patternProperties['^(.*)$']))
})
it('Should parse Record 2', () => {
const T = Parse(`Record<number, number>`)
Assert.IsTrue(TypeGuard.IsRecord(T))
Assert.IsTrue(TypeGuard.IsNumber(T.patternProperties['^(0|[1-9][0-9]*)$']))
})
it('Should parse Record 3', () => {
const T = Parse(`Record<'x' | 'y', number>`)
Assert.IsTrue(TypeGuard.IsObject(T))
Assert.IsTrue(TypeGuard.IsNumber(T.properties.x))
Assert.IsTrue(TypeGuard.IsNumber(T.properties.y))
})
it('Should parse Recursive', () => {
const T = Type.Recursive(This => Parse({ This }, `{ id: string, nodes: This[] }`))
Assert.IsTrue(TypeGuard.IsObject(T))
Assert.IsTrue(TypeGuard.IsString(T.properties.id))
Assert.IsTrue(TypeGuard.IsArray(T.properties.nodes))
Assert.IsTrue(TypeGuard.IsThis(T.properties.nodes.items))
})
it('Should parse Ref', () => {
const T = Parse('foo')
Assert.IsTrue(TypeGuard.IsRef(T))
Assert.IsTrue(T.$ref === 'foo')
})
it('Should parse Required', () => {
const T = Parse(`Required<{ x?: boolean, y?: number, z?: string }>`)
Assert.IsTrue(TypeGuard.IsObject(T))
Assert.IsEqual(T.required, ['x', 'y', 'z'])
})
it('Should parse ReturnType 1', () => {
const T = Parse(`ReturnType<() => { x: 1, y: 2 }>`)
Assert.IsTrue(TypeGuard.IsObject(T))
Assert.IsTrue(T.properties.x.const === 1)
Assert.IsTrue(T.properties.y.const === 2)
})
it('Should parse ReturnType 2', () => {
const T = Parse(`ReturnType<number>`) // generalization issue
Assert.IsTrue(T === undefined)
})
it('Should parse String', () => {
const T = Parse(`string`)
Assert.IsTrue(TypeGuard.IsString(T))
})
it('Should parse Symbol', () => {
const T = Parse(`symbol`)
Assert.IsTrue(TypeGuard.IsSymbol(T))
})
it('Should parse Tuple', () => {
const T = Parse(`[0, 1, 2, 3]`)
Assert.IsTrue(TypeGuard.IsTuple(T))
Assert.IsTrue(T.items![0].const === 0)
Assert.IsTrue(T.items![1].const === 1)
Assert.IsTrue(T.items![2].const === 2)
Assert.IsTrue(T.items![3].const === 3)
})
it('Should parse Uint8Array', () => {
const T = Parse(`Uint8Array`)
Assert.IsTrue(TypeGuard.IsUint8Array(T))
})
it('Should parse Undefined', () => {
const T = Parse(`undefined`)
Assert.IsTrue(TypeGuard.IsUndefined(T))
})
it('Should parse Union 1', () => {
const T = Parse(`1 | 2`)
Assert.IsTrue(TypeGuard.IsUnion(T))
Assert.IsTrue(T.anyOf[0].const === 1)
Assert.IsTrue(T.anyOf[1].const === 2)
})
it('Should parse Union 2', () => {
const T = Parse(`1 | (2 | 3)`)
Assert.IsTrue(TypeGuard.IsUnion(T))
Assert.IsTrue(T.anyOf[0].const === 1)
Assert.IsTrue(T.anyOf[1].const === 2)
Assert.IsTrue(T.anyOf[2].const === 3)
})
it('Should parse Unknown', () => {
const T = Parse(`unknown`)
Assert.IsTrue(TypeGuard.IsUnknown(T))
})
it('Should parse Void', () => {
const T = Parse(`void`)
Assert.IsTrue(TypeGuard.IsVoid(T))
})
})

View File

@@ -8,6 +8,7 @@
"paths": {
"@sinclair/typebox/compiler": ["src/compiler/index.ts"],
"@sinclair/typebox/errors": ["src/errors/index.ts"],
"@sinclair/typebox/parse": ["src/parse/index.ts"],
"@sinclair/typebox/system": ["src/system/index.ts"],
"@sinclair/typebox/type": ["src/type/index.ts"],
"@sinclair/typebox/value": ["src/value/index.ts"],