diff --git a/changelog/0.34.0.md b/changelog/0.34.0.md
new file mode 100644
index 0000000..fdc9a75
--- /dev/null
+++ b/changelog/0.34.0.md
@@ -0,0 +1,196 @@
+## [0.34.0](https://www.npmjs.com/package/@sinclair/typebox/v/0.34.0)
+
+## Overview
+
+Revision 0.34.0 represents a significant milestone for the TypeBox project. This update changes how TypeBox manages type references (Ref) and introduces a new Module type to support mutual recursion and self-referencing types. Additionally, it includes a new submodule for parsing TypeScript syntax directly into TypeBox types.
+
+Please note that this release includes breaking changes to Ref and some deprecations. These updates require a minor semver revision.
+
+## Contents
+
+- [Enhancements](#Enhancements)
+ - [Module Types](#Module-Types)
+ - [Syntax Types](#Syntax-Types)
+- [Breaking Changes](#Breaking-Changes)
+ - [Ref](#Ref)
+ - [Deref](#Deref)
+ - [Strict](#Strict)
+
+
+
+
+## Enhancements
+
+Below are the enhancements introduced in Version 0.34.0.
+
+
+
+### Module Types
+
+Revision 0.34.0 introduces a new type, called Module. Modules are represented as JSON Schema $def schematics, specifically designed to support both mutual and self-recursive types. This addition resolves a longstanding issue in TypeBox, where complex recursive structures often encountered "definition order" problems, making certain recursive structures difficult to represent cleanly. With Modules, you can now define schematics within a Module context, allowing them to be referenced within the type system through a separate inference operation.
+
+```typescript
+// The following creates a circular recursive type.
+
+const Module = Type.Module({
+ A: Type.Object({
+ b: Type.Ref('B') // Ref B:
+ }),
+ B: Type.Object({
+ c: Type.Ref('C') // Ref C:
+ }),
+ C: Type.Object({
+ a: Type.Ref('A') // Ref A:
+ }),
+})
+
+// Module types must be imported before use.
+
+const A = Module.Import('A') // const A: TImport<{...}, 'A'>
+
+type A = Static // type A = {
+ // b: {
+ // c: {
+ // a: {
+ // b: ...
+ // }
+ // }
+ // }
+ // }
+```
+
+
+
+### Syntax Types
+
+
+Revision 0.34.0 introduces a new submodule for parsing TypeScript syntax directly into TypeBox types, implemented both at runtime and within the type system. This feature was made possible through the development of a separate project, [ParseBox](https://github.com/sinclairzx81/parsebox) (MIT-licensed), which provides a symmetric runtime and type-level parsing infrastructure.
+
+As of 0.34.0, Syntax Types are available as an opt-in feature, with the parsing infrastructure adding approximately 10kb (minified) to the existing type builder. With further optimizations, this feature may be elevated to a top-level import in future updates to minimize bundling size.
+
+To use Syntax Types, import them from the `@sinclair/typebox/syntax` path.
+
+```typescript
+import { Parse } from '@sinclair/typebox/syntax'
+
+// All primitive types are supported
+
+const A = Parse('string') // const A: TString
+const B = Parse('number') // const B: TNumber
+const C = Parse('boolean') // const C: TBoolean
+
+// ... Multiline parsing is supported (but comments are not)
+
+const T = Parse(`{
+ x: number
+ y: number
+ z: number
+}`)
+
+
+// ... Parametertized parsing is supported
+const O = Parse({ T }, `T & { w: number }`) // const O: TIntersect<[
+ // TObject<{
+ // x: TNumber,
+ // y: TNumber,
+ // z: TNumber,
+ // }>,
+ // TObject<{
+ // w: TNumber
+ // }>
+ // ]>
+
+// ... Module parsing is also supported.
+
+const Math = Parse(`module Math {
+ export interface X {
+ x: number
+ }
+ export interface Y {
+ y: number
+ }
+ export interface Z {
+ z: number
+ }
+ export interface Vector extends X, Y, Z {
+ type: 'Vector'
+ }
+}`)
+
+const Vector = Math.Import('Vector')
+```
+
+Runtime parsing performance should be quite good; however, static parsing performance could be improved. TypeScript will invoke the parser for each property accessed at design time. Ongoing efforts within the ParseBox project aim to optimize string parsing in TypeScript, with additional research underway into type-level caching strategies within the TypeScript compiler. Additional optimizations will be explored over the course of 0.34.x.
+
+
+
+## Breaking Changes
+
+The following are the breaking changes in Revision 0.34.0.
+
+
+
+### Ref
+
+Revision 0.34.0 introduces a breaking change to Ref, modifying its signature to accept only constant string values. Previously, Ref could accept an existing TypeBox type, provided it had an $id assigned.
+
+```typescript
+
+// Revision 0.33.0
+
+const T = Type.String({ $id: 'T' })
+
+const R = Type.Ref(T)
+
+type R = Static // type R = string
+
+// Revision 0.34.0
+
+const T = Type.String({ $id: 'T' })
+
+const R = Type.Ref('T')
+
+type R = Static // type R = unknown
+
+```
+
+In Revision 0.34.0, the inferred type for Ref is now unknown. Implementations using the previous version of Ref can switch to Unsafe to type the reference to the target value.
+
+```typescript
+// Revision 0.34.0
+
+const T = Type.String({ $id: 'T' })
+
+const R = Type.Unsafe>(Type.Ref('T'))
+
+type R = Static // type R = string
+```
+
+
+
+### Deref
+
+Revision 0.34.0 removes the Deref type, which was previously used to dereference schematics. Since the Ref signature has changed from TSchema to string, there is no longer a way to resolve reference types accurately. TypeBox may provide a prototype example of this type upon request.
+
+
+
+### Strict
+
+Revision 0.34.0 removes the Strict type from the Type Builder, which was deprecated in version 0.33.8. This type was introduced several years ago in response to a change in Ajv that prohibited unknown keywords. At that time, TypeBox used string property keys for `kind` and `modifier`, which required either Ajv configuration or the use of Strict. These properties have since been updated to Symbol properties, resolving the issues with Ajv. However, the Strict type remained due to some use in ecosystem projects, which has since reduced.
+
+For those who still need Strict, the recommended approach is to use the JSON stringify/parse method outlined in the deprecation notice.
+
+```typescript
+/**
+ * @deprecated `[Json]` Omits compositing symbols from this schema. It is recommended
+ * to use the JSON parse/stringify to remove compositing symbols if needed. This
+ * is how Strict works internally.
+ *
+ * ```typescript
+ * JSON.parse(JSON.stringify(Type.String()))
+ * ```
+ */
+export function Strict(schema: T): TStrict {
+ return JSON.parse(JSON.stringify(schema))
+}
+```
\ No newline at end of file
diff --git a/example/prototypes/index.ts b/example/prototypes/index.ts
index cb81ad0..179da98 100644
--- a/example/prototypes/index.ts
+++ b/example/prototypes/index.ts
@@ -27,7 +27,6 @@ THE SOFTWARE.
---------------------------------------------------------------------------*/
export * from './from-schema'
-export * from './module'
export * from './partial-deep'
export * from './union-enum'
export * from './union-oneof'
diff --git a/example/prototypes/module.ts b/example/prototypes/module.ts
deleted file mode 100644
index e56dcb2..0000000
--- a/example/prototypes/module.ts
+++ /dev/null
@@ -1,166 +0,0 @@
-/*--------------------------------------------------------------------------
-
-@sinclair/typebox/prototypes
-
-The MIT License (MIT)
-
-Copyright (c) 2017-2024 Haydn Paterson (sinclair)
-
-Permission is hereby granted, free of charge, to any person obtaining a copy
-of this software and associated documentation files (the "Software"), to deal
-in the Software without restriction, including without limitation the rights
-to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-copies of the Software, and to permit persons to whom the Software is
-furnished to do so, subject to the following conditions:
-
-The above copyright notice and this permission notice shall be included in
-all copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-THE SOFTWARE.
-
----------------------------------------------------------------------------*/
-
-import * as Types from '@sinclair/typebox'
-import { Check } from '@sinclair/typebox/value'
-// ------------------------------------------------------------------
-// Infer
-// ------------------------------------------------------------------
-// prettier-ignore
-export type InferImport = (
- Infer
-)
-// prettier-ignore
-export type InferModuleRef[ = (
- Ref extends keyof Module ? Infer : never
-)
-// prettier-ignore
-export type InferObject = {
- [K in keyof Properties]: Infer
-} & {}
-// prettier-ignore
-export type InferConstructor = Types.Ensure<
- new (...args: InferTuple) => Infer
->
-// prettier-ignore
-export type InferFunction = Types.Ensure<
- (...args: InferTuple) => Infer
->
-// prettier-ignore
-export type InferTuple = (
- Types extends [infer L extends Types.TSchema, ...infer R extends Types.TSchema[]]
- ? InferTuple]>
- : Result
-)
-// prettier-ignore
-export type InferIntersect = (
- Types extends [infer L extends Types.TSchema, ...infer R extends Types.TSchema[]]
- ? InferIntersect>
- : Result
-)
-// prettier-ignore
-export type InferUnion = (
- Types extends [infer L extends Types.TSchema, ...infer R extends Types.TSchema[]]
- ? InferUnion>
- : Result
-)
-// prettier-ignore
-export type InferArray = (
- Types.Ensure>>
-)
-// prettier-ignore
-export type InferAsyncIterator = (
- Types.Ensure>>
-)
-// prettier-ignore
-export type InferIterator = (
- Types.Ensure>>
-)
-// prettier-ignore
-type Infer = (
- Type extends TImport ? InferImport] :
- Type extends TModuleRef ? InferModuleRef :
- Type extends Types.TObject ? InferObject :
- Type extends Types.TConstructor ? InferConstructor :
- Type extends Types.TFunction ? InferFunction :
- Type extends Types.TTuple ? InferTuple :
- Type extends Types.TIntersect ? InferIntersect :
- Type extends Types.TUnion ? InferUnion :
- Type extends Types.TArray ? InferArray :
- Type extends Types.TAsyncIterator ? InferAsyncIterator :
- Type extends Types.TIterator ? InferIterator :
- Type extends Types.TTemplateLiteral ? Types.Static> :
- Type extends Types.TLiteral ? S :
- Type extends Types.TAny ? any :
- Type extends Types.TBigInt ? bigint :
- Type extends Types.TBoolean ? boolean :
- Type extends Types.TDate ? Date :
- Type extends Types.TInteger ? number :
- Type extends Types.TNever ? never :
- Type extends Types.TNumber ? number :
- Type extends Types.TRegExp ? string :
- Type extends Types.TString ? string :
- Type extends Types.TSymbol ? symbol :
- Type extends Types.TNull ? null :
- Type extends Types.TUint8Array ? Uint8Array :
- Type extends Types.TUndefined ? undefined :
- Type extends Types.TUnknown ? unknown :
- Type extends Types.TVoid ? void :
- never
-)
-// ------------------------------------------------------------------
-// ModuleRef
-// ------------------------------------------------------------------
-// prettier-ignore
-export interface TModuleRef[ extends Types.TSchema {
- [Types.Kind]: 'ModuleRef'
- $ref: Ref
-}
-// prettier-ignore
-export function ModuleRef][($ref: Ref): TModuleRef][ {
- return Types.Type.Ref($ref) as never
-}
-// ------------------------------------------------------------------
-// Import
-// ------------------------------------------------------------------
-// prettier-ignore
-Types.TypeRegistry.Set('Import', (module: TImport, value: unknown) => {
- const keys = Object.getOwnPropertyNames(module.$defs)
- const references = keys.map(key => module.$defs[key as never]) as Types.TSchema[]
- const schema = module.$defs[module.$ref]
- return Check(schema, references, value)
-})
-// prettier-ignore
-export type TModuleProperties = Record
-
-// prettier-ignore
-export interface TImport extends Types.TSchema {
- [Types.Kind]: 'Import'
- static: InferImport
- $defs: Definitions
- $ref: Key
-}
-// ------------------------------------------------------------------
-// Module
-// ------------------------------------------------------------------
-// prettier-ignore
-export class ModuleInstance {
- constructor(private readonly properties: Properties) {}
- public Import(key: Key): TImport {
- const $defs = globalThis.Object.getOwnPropertyNames(this.properties).reduce((Result, Key) => (
- { ...Result, [Key]: { ...this.properties[Key], $id: Key }}
- ), {})
- return { [Types.Kind]: 'Import', $defs, $ref: key } as never
- }
-}
-export function Module(properties: Properties): ModuleInstance {
- return new ModuleInstance(properties)
-}
-
-
-
diff --git a/example/prototypes/readme.md b/example/prototypes/readme.md
index 7c7c429..cd95b34 100644
--- a/example/prototypes/readme.md
+++ b/example/prototypes/readme.md
@@ -2,46 +2,6 @@
TypeBox prototypes are a set of types that are either under consideration for inclusion into the library, or have been requested by users but cannot be added to the library either due to complexity, using schematics that fall outside the supported TypeBox or should be expressed by users via advanced type composition.
-## Module, ModuleRef and Import
-
-The Module type as a candidate referencing system for TypeBox. Modules enable deferred cross type referencing and support mutual recursive inference. Module types must be instanced via `M.Import(...)` which constructs a `$def` schematic containing each definition required to validate, and a self referential `$ref` to one of the type being imported.
-
-```typescript
-import { Module, ModuleRef } from './prototypes'
-
-// ------------------------------------------------------------------
-// Module, ModuleRef
-// ------------------------------------------------------------------
-const Math = Module({
- Vector2: Type.Object({
- x: Type.Number(),
- y: Type.Number(),
- }),
- Vector3: Type.Object({
- x: Type.Number(),
- y: Type.Number(),
- z: Type.Number()
- }),
- Vertex: Type.Object({
- position: ModuleRef('Vector3'),
- normal: ModuleRef('Vector3'),
- texcoord: ModuleRef('Vector2')
- }),
- Geometry: Type.Object({
- vertices: Type.Array(ModuleRef('Vertex')),
- indices: Type.Array(Type.Integer())
- })
-})
-
-// ------------------------------------------------------------------
-// Import
-// -----------------------------------------------------------------
-
-const Vector2 = Math.Import('Vector2')
-const Vector3 = Math.Import('Vector2')
-const Vertex = Math.Import('Vertex')
-const Geometry = Math.Import('Geometry')
-```
## PartialDeep
diff --git a/package-lock.json b/package-lock.json
index 262945a..fbacace 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1,12 +1,12 @@
{
"name": "@sinclair/typebox",
- "version": "0.33.22",
+ "version": "0.34.0",
"lockfileVersion": 2,
"requires": true,
"packages": {
"": {
"name": "@sinclair/typebox",
- "version": "0.33.22",
+ "version": "0.34.0",
"license": "MIT",
"devDependencies": {
"@arethetypeswrong/cli": "^0.13.2",
diff --git a/package.json b/package.json
index 1a8dff9..44b16b8 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "@sinclair/typebox",
- "version": "0.33.22",
+ "version": "0.34.0",
"description": "Json Schema Type Builder with Static Type Resolution for TypeScript",
"keywords": [
"typescript",
diff --git a/readme.md b/readme.md
index 5836c10..39fd650 100644
--- a/readme.md
+++ b/readme.md
@@ -68,8 +68,7 @@ License MIT
- [Options](#types-options)
- [Properties](#types-properties)
- [Generics](#types-generics)
- - [References](#types-references)
- - [Recursive](#types-recursive)
+ - [Modules](#types-modules)
- [Template Literal](#types-template-literal)
- [Indexed](#types-indexed)
- [Mapped](#types-mapped)
@@ -79,7 +78,9 @@ License MIT
- [Unsafe](#types-unsafe)
- [Syntax](#syntax)
- [Parse](#syntax-parse)
+ - [Compose](#syntax-compose)
- [Context](#syntax-context)
+ - [Module](#syntax-module)
- [Static](#syntax-static)
- [Limits](#syntax-limits)
- [Values](#values)
@@ -769,103 +770,40 @@ const T = Nullable(Type.String()) // const T = {
type T = Static // type T = string | null
```
-
+
-### Reference Types
+### Module Types
-Reference types can be created with Ref. These types infer the same as the target type but only store a named `$ref` to the target type.
+TypeBox Modules are containers for related types. They function as namespaces and enable internal types to reference each other via string references. Modules support both singular and mutually recursive types. They provide a mechanism to create circular types irrespective of the order in which types are defined.
```typescript
-const Vector = Type.Object({ // const Vector = {
- x: Type.Number(), // type: 'object',
- y: Type.Number(), // required: ['x', 'y', 'z'],
-}, { $id: 'Vector' }) // properties: {
- // x: { type: 'number' },
- // y: { type: 'number' }
- // },
- // $id: 'Vector'
- // }
+// The following creates a circular recursive type.
-const VectorRef = Type.Ref(Vector) // const VectorRef = {
- // $ref: 'Vector'
- // }
+const Module = Type.Module({
+ A: Type.Object({
+ b: Type.Ref('B') // Ref B:
+ }),
+ B: Type.Object({
+ c: Type.Ref('C') // Ref C:
+ }),
+ C: Type.Object({
+ a: Type.Ref('A') // Ref A:
+ }),
+})
-type VectorRef = Static // type VectorRef = {
- // x: number,
- // y: number
- // }
-```
-Use Deref to dereference a type. This function will replace any interior reference with the target type.
-```typescript
-const Vertex = Type.Object({ // const Vertex = {
- position: VectorRef, // type: 'object',
- texcoord: VectorRef, // required: ['position', 'texcoord'],
-}) // properties: {
- // position: { $ref: 'Vector' },
- // texcoord: { $ref: 'Vector' }
- // }
- // }
+// Module types must be imported before use.
-const VertexDeref = Type.Deref(Vertex, [Vector]) // const VertexDeref = {
- // type: 'object',
- // required: ['position', 'texcoord'],
- // properties: {
- // position: {
- // type: 'object',
- // required: ['x', 'y', 'z'],
- // properties: {
- // x: { type: 'number' },
- // y: { type: 'number' }
- // }
- // },
- // texcoord: {
- // type: 'object',
- // required: ['x', 'y', 'z'],
- // properties: {
- // x: { type: 'number' },
- // y: { type: 'number' }
- // }
- // }
- // }
- // }
-```
-Note that Ref types do not store structural information about the type they're referencing. Because of this, these types cannot be used with some mapping types (such as Partial or Pick). For applications that require mapping on Ref, use Deref to normalize the type first.
+const A = Module.Import('A') // const A: TImport<{...}, 'A'>
-
-
-### Recursive Types
-
-TypeBox supports recursive data structures with Recursive. This type wraps an interior type and provides it a `this` context that allows the type to reference itself. The following creates a recursive type. Singular recursive inference is also supported.
-
-```typescript
-const Node = Type.Recursive(This => Type.Object({ // const Node = {
- id: Type.String(), // $id: 'Node',
- nodes: Type.Array(This) // type: 'object',
-}), { $id: 'Node' }) // properties: {
- // id: {
- // type: 'string'
- // },
- // nodes: {
- // type: 'array',
- // items: {
- // $ref: 'Node'
- // }
- // }
- // },
- // required: [
- // 'id',
- // 'nodes'
- // ]
- // }
-
-type Node = Static // type Node = {
- // id: string
- // nodes: Node[]
- // }
-
-function test(node: Node) {
- const id = node.nodes[0].nodes[0].id // id is string
-}
+type A = Static // type A = {
+ // b: {
+ // c: {
+ // a: {
+ // b: ...
+ // }
+ // }
+ // }
+ // }
```
@@ -1084,11 +1022,11 @@ if(TypeGuard.IsString(T)) {
-## Syntax
+## Syntax Types
-TypeBox supports parsing TypeScript type annotation syntax directly into TypeBox types, providing an alternative to the Type.* API for type construction. This feature functions at runtime and within the TypeScript type system, enabling types encoded as strings to be inferred as equivalent TypeBox types.
+TypeBox provides support for Syntax Types, enabling it to parse TypeScript syntax directly into TypeBox types. Syntax Types serve as a DSL frontend for TypeBox's type builder and are useful for converting existing TypeScript type definitions into Json Schema schematics.
-TypeScript syntax parsing is provided as an optional import.
+Syntax Types are provided via optional import.
```typescript
import { Parse } from '@sinclair/typebox/syntax'
@@ -1098,9 +1036,7 @@ import { Parse } from '@sinclair/typebox/syntax'
### Parse
-The Parse function can be used to parse TypeScript code into TypeBox types. The left hand result will be a inferred TypeBox type of TSchema. Invalid syntax will result in an undefined return value.
-
-[TypeScript Link Here](https://www.typescriptlang.org/play/?moduleResolution=99&module=199#code/JYWwDg9gTgLgBAbzgBQIZQM4FM4F84BmUEIcA5AAIbAB2AxgDarBQD0MAnmFgEYQAerDBxoxU-MgChJdCDQzwAgnAC8KdNgAUZBVFoBzMgEo4ps+YuXLrVnFnylALjgAVAMow9NfdPsK4AEKq6phY2gDaAIwANHAATLEAzAC6xlbpGTZ2cv4Bzi4uAK5gDFgAPOGSGdU1tdVZpi4AMsAwWFCoDGWRAHzRVXWDQ5m2jS1tHV1xfQPDc3MNruPtnWWJPbPzW7VZyRsyOfAAwsFooZoABkj8zjSFIDztsRy3949QeBcm6Vl+x-kAeR4ACssHQYGUEJttjCrIsbq4AHJvdrQ2Ho0yLF5IlFQNEY2FZXD7IA)
+Use the Parse function to convert a TypeScript string into a TypeBox type. TypeBox will infer the appropriate TSchema type or return undefined if there is a syntax error.
```typescript
const A = Parse('string') // const A: TString
@@ -1117,64 +1053,96 @@ const C = Parse(`{ x: number, y: number }`) // const C: TObject<{
// }>
```
+
+
+
+
+### Compose
+
+Syntax Types are designed to be interchangeable with standard Types.
+
+```typescript
+const T = Type.Object({ // const T: TObject<{
+ x: Parse('number'), // x: TNumber,
+ y: Parse('number'), // y: TNumber,
+ z: Parse('number') // z: TNumber
+}) // }>
+```
+
+
+
+### Module
+
+Syntax Types support Module parsing, which is useful for processing multiple TypeScript types. Module parsing supports type alias and interface definitions. Generics are currently unsupported as of 0.34.0.
+
+```typescript
+const Foo = Parse(`module Foo {
+
+ export type A = string
+
+ export type B = number
+
+ export type C = A | B
+
+}`)
+
+const C = Foo.Import('C') // const C: TImport<{
+ // ...
+ // }, 'C'>
+```
+
### Context
-The Parse function accepts an optional context parameter that enables external types to be referenced within the syntax.
-
-[TypeScript Link Here](https://www.typescriptlang.org/play/?moduleResolution=99&module=199#code/JYWwDg9gTgLgBAbzgBQIZQM4FM4F84BmUEIcA5AAIbAB2AxgDarBQD0MAnmFgEYQAerDBxoxU-MgChQkWIjgAVLjnxES5KrUbM2nbnwmTJdCDQzwFcALyLlAOgDyPAFZY6MABRI4P33-8BgayscCYArgwAJnA8OADuUMAwMFg0cKgYAFwo6NgeAAYIkj782UrcdgByYSCxUB4AlAA0ga1tbcG+pXA0NXVNxXAcZfbVtVj1ze3TM50+wz19EwM+AF4jFWN1jTO7rXNr2b3jUJK4DXuXV-6duPkNRiZm8ACC1jmYWF6KeC35aLBgKgGAAeBQAPnuV06T3McBeZScrncIKK13R1wO3QUDjAMGApmBYK2E3BKwxFNmIXmiLxBJoRIUJKgZMGlPZQWpcHWilx+MJoKZSxZbI5Yp8t3Bj1McIAQu8AXkkJZcH8ANZYDgQAiKKHomEy+CysoAVRo9JBAG1ReKOQcFAAZJITIlkCSs222+1OlJQV0cMgez1i73Ov2gsirQM24MYzoAXSlxkNcAAwgrcl9lb84PlLAAyeRxI7CvB6zmhFOpsoASVEE2wKMtOJcbhgqJjscxXLg2OZAG5O13LgchmUB0Ph7tRzyhSdB1OKZKWi3ke20Yv9T3i4oJ5ut3hwYmjEA)
+The Parse function accepts an initial Context argument, allowing external types to be passed into the parser.
```typescript
const T = Type.Object({ // could be written as: Parse(`{
x: Type.Number(), // x: number,
y: Type.Number(), // y: number,
- z: Type.Number() // z: number
+ z: Type.Number() // z: number
}) // }`)
-const A = Parse({ T }, `Partial`) // const A: TObject<{
+const A = Parse({ T }, 'Partial') // const A: TObject<{
// x: TOptional,
// y: TOptional,
// z: TOptional
// }>
-const B = Parse({ T }, `keyof T`) // const B: TUnion<[
+const B = Parse({ T }, 'keyof T') // const B: TUnion<[
// TLiteral<'x'>,
// TLiteral<'y'>,
// TLiteral<'z'>
// ]>
-const C = Parse({ T }, `T & { w: number }`) // const C: TIntersect<[TObject<{
+const C = Parse({ T }, 'T & { w: number }') // const C: TIntersect<[TObject<{
// x: TNumber;
// y: TNumber;
// z: TNumber;
// }>, TObject<{
// w: TNumber;
// }>]>
-
-
```
### Static
-TypeBox provides two Static types for inferring TypeScript syntax directly from strings.
-
-[TypeScript Link Here](https://www.typescriptlang.org/play/?moduleResolution=99&module=199#code/JYWwDg9gTgLgBAbzgZRgQxsAxgBTVAZwFMBBA5LACyJDQBoV1Nd9iyAVATzCLgF84AMygQQcAOQABAsAB2WADZpgUAPQxuRAEYQAHqoKdZ6XeLgAoc6tVwA6sAUK4cwUShw0BD3HYVqtSw0eFDgAXkYMbDxCUnIqGjQAHgQ+BgADJF0ALjhZAFcQLTd+NIA+OArrOCDeZBz2AHktACsiLBhk8wrunt6+-oHBgaqK7J8AOQKiqC6hufmF3qq+Ussq+0dnWVd3T28awM0fMIjmaLYCLh5k1LgMuDH8wuK+MqWbGuPwhFnFv--3qMck9pr8AeDFiM4EA)
+Syntax Types provide two Static types for inferring TypeScript syntax from strings.
```typescript
import { StaticParseAsSchema, StaticParseAsType } from '@sinclair/typebox/syntax'
// Will infer as a TSchema
-type S = StaticParseAsSchema<{}, `{ x: number }`> // type S: TObject<{
+type S = StaticParseAsSchema<{}, '{ x: number }'> // type S: TObject<{
// x: TNumber
// }>
// Will infer as a type
-type T = StaticParseAsType<{}, `{ x: number }`> // type T = {
+type T = StaticParseAsType<{}, '{ x: number }'> // type T = {
// x: number
//
```
@@ -1182,9 +1150,9 @@ type T = StaticParseAsType<{}, `{ x: number }`> // type T = {
-### Limits
+### Limitations
-The Parse function works by TypeBox parsing TypeScript syntax within the type system itself. This can place some additional demand on the TypeScript compiler, which may affect language service (LSP) responsiveness when working with especially large or complex types. In particular, very wide structures or deeply nested types may approach TypeScript’s instantiation limits.
+Syntax Types work by having TypeBox parse TypeScript syntax within the TypeScript type system. This approach can place some strain on the TypeScript compiler and language service, potentially affecting responsiveness. While TypeBox makes a best-effort attempt to optimize for Syntax Types, users should be mindful of the following structures:
```typescript
// Excessively wide structures will result in instantiation limits exceeding
@@ -1211,12 +1179,12 @@ const B = Parse(`{
}`)
```
-For parsing especially complex types, TypeBox provides the ParseOnly function, which parses strings at runtime and returns a non-inferred TSchema type. ParseOnly allows for arbitrarily complex types without reaching instantiation limits, making it useful for cases where TypeScript types need to be directly converted to Json Schema.
+In cases where Syntax Types busts through TypeScript instantiation limits, TypeBox offers a fallback ParseOnly function which will Parse the types at runtime, but not infer the type. This function can also be used for parsing non-constant strings.
```typescript
import { ParseOnly } from '@sinclair/typebox/syntax'
-// ok: but where A is TSchema | undefined
+// Where A is TSchema | undefined
const A = ParseOnly(`{
x: {
@@ -1229,7 +1197,7 @@ const A = ParseOnly(`{
}`)
```
-Optimizing TypeScript string parsing performance is an ongoing area of research. For more information, see the [ParseBox](https://github.com/sinclairzx81/parsebox) project, which documents TypeBox’s parsing infrastructure and focuses efforts to improve parsing performance.
+For more information on TypeBox's parsing infrastructure, refer to the [ParseBox](https://github.com/sinclairzx81/parsebox) project.
@@ -1914,12 +1882,12 @@ The following table lists esbuild compiled and minified sizes for each TypeBox m
┌──────────────────────┬────────────┬────────────┬─────────────┐
│ (index) │ Compiled │ Minified │ Compression │
├──────────────────────┼────────────┼────────────┼─────────────┤
-│ typebox/compiler │ '119.8 kb' │ ' 52.6 kb' │ '2.28 x' │
-│ typebox/errors │ ' 74.4 kb' │ ' 33.1 kb' │ '2.25 x' │
-│ typebox/syntax │ '115.3 kb' │ ' 48.3 kb' │ '2.39 x' │
+│ typebox/compiler │ '121.7 kb' │ ' 53.4 kb' │ '2.28 x' │
+│ typebox/errors │ ' 75.3 kb' │ ' 33.4 kb' │ '2.25 x' │
+│ typebox/syntax │ '120.1 kb' │ ' 50.5 kb' │ '2.38 x' │
│ typebox/system │ ' 7.4 kb' │ ' 3.2 kb' │ '2.33 x' │
-│ typebox/value │ '157.2 kb' │ ' 66.1 kb' │ '2.38 x' │
-│ typebox │ ' 98.9 kb' │ ' 41.2 kb' │ '2.40 x' │
+│ typebox/value │ '160.3 kb' │ ' 67.4 kb' │ '2.38 x' │
+│ typebox │ ' 96.2 kb' │ ' 40.2 kb' │ '2.39 x' │
└──────────────────────┴────────────┴────────────┴─────────────┘
```
diff --git a/src/compiler/compiler.ts b/src/compiler/compiler.ts
index bc1fd8b..6e43870 100644
--- a/src/compiler/compiler.ts
+++ b/src/compiler/compiler.ts
@@ -47,6 +47,7 @@ import type { TBoolean } from '../type/boolean/index'
import type { TDate } from '../type/date/index'
import type { TConstructor } from '../type/constructor/index'
import type { TFunction } from '../type/function/index'
+import type { TImport } from '../type/module/index'
import type { TInteger } from '../type/integer/index'
import type { TIntersect } from '../type/intersect/index'
import type { TIterator } from '../type/iterator/index'
@@ -110,7 +111,7 @@ export class TypeCheck {
return (this.hasTransform ? TransformDecode(this.schema, this.references, value) : value) as never
}
/** Encodes a value or throws if error */
- public Encode, Result extends Static = Static>(value: unknown): Result {
+ public Encode, Result extends Static = Static>(value: unknown): Result {
const encoded = this.hasTransform ? TransformEncode(this.schema, this.references, value) : value
if (!this.checkFunc(encoded)) throw new TransformEncodeCheckError(this.schema, value, this.Errors(value).First()!)
return encoded as never
@@ -288,6 +289,11 @@ export namespace TypeCompiler {
function* FromFunction(schema: TFunction, references: TSchema[], value: string): IterableIterator {
yield `(typeof ${value} === 'function')`
}
+ function* FromImport(schema: TImport, references: TSchema[], value: string): IterableIterator {
+ const definitions = globalThis.Object.values(schema.$defs) as TSchema[]
+ const target = schema.$defs[schema.$ref] as TSchema
+ yield* Visit(target, [...references, ...definitions], value)
+ }
function* FromInteger(schema: TInteger, references: TSchema[], value: string): IterableIterator {
yield `Number.isInteger(${value})`
if (IsNumber(schema.exclusiveMaximum)) yield `${value} < ${schema.exclusiveMaximum}`
@@ -385,8 +391,12 @@ export namespace TypeCompiler {
function* FromRef(schema: TRef, references: TSchema[], value: string): IterableIterator {
const target = Deref(schema, references)
// Reference: If we have seen this reference before we can just yield and return the function call.
- // If this isn't the case we defer to visit to generate and set the function for subsequent passes.
- if (state.functions.has(schema.$ref)) return yield `${CreateFunctionName(schema.$ref)}(${value})`
+ // If this isn't the case we defer to visit to generate and set the _recursion_end_for_ for subsequent
+ // passes. This operation is very awkward as we are using the functions state to store values to
+ // enable self referential types to terminate. This needs to be refactored.
+ const recursiveEnd = `_recursion_end_for_${schema.$ref}`
+ if (state.functions.has(recursiveEnd)) return yield `${CreateFunctionName(schema.$ref)}(${value})`
+ state.functions.set(recursiveEnd, '') // terminate recursion here by setting the name.
yield* Visit(target, references, value)
}
function* FromRegExp(schema: TRegExp, references: TSchema[], value: string): IterableIterator {
@@ -485,6 +495,8 @@ export namespace TypeCompiler {
return yield* FromDate(schema_, references_, value)
case 'Function':
return yield* FromFunction(schema_, references_, value)
+ case 'Import':
+ return yield* FromImport(schema_, references_, value)
case 'Integer':
return yield* FromInteger(schema_, references_, value)
case 'Intersect':
diff --git a/src/errors/errors.ts b/src/errors/errors.ts
index 44a8b02..9bb1f6c 100644
--- a/src/errors/errors.ts
+++ b/src/errors/errors.ts
@@ -46,6 +46,7 @@ import type { TBoolean } from '../type/boolean/index'
import type { TDate } from '../type/date/index'
import type { TConstructor } from '../type/constructor/index'
import type { TFunction } from '../type/function/index'
+import type { TImport } from '../type/module/index'
import type { TInteger } from '../type/integer/index'
import type { TIntersect } from '../type/intersect/index'
import type { TIterator } from '../type/iterator/index'
@@ -302,6 +303,11 @@ function* FromDate(schema: TDate, references: TSchema[], path: string, value: an
function* FromFunction(schema: TFunction, references: TSchema[], path: string, value: any): IterableIterator {
if (!IsFunction(value)) yield Create(ValueErrorType.Function, schema, path, value)
}
+function* FromImport(schema: TImport, references: TSchema[], path: string, value: any): IterableIterator {
+ const definitions = globalThis.Object.values(schema.$defs) as TSchema[]
+ const target = schema.$defs[schema.$ref] as TSchema
+ yield* Visit(target, [...references, ...definitions], path, value)
+}
function* FromInteger(schema: TInteger, references: TSchema[], path: string, value: any): IterableIterator {
if (!IsInteger(value)) return yield Create(ValueErrorType.Integer, schema, path, value)
if (IsDefined(schema.exclusiveMaximum) && !(value < schema.exclusiveMaximum)) {
@@ -566,6 +572,8 @@ function* Visit(schema: T, references: TSchema[], path: strin
return yield* FromDate(schema_, references_, path, value)
case 'Function':
return yield* FromFunction(schema_, references_, path, value)
+ case 'Import':
+ return yield* FromImport(schema_, references_, path, value)
case 'Integer':
return yield* FromInteger(schema_, references_, path, value)
case 'Intersect':
diff --git a/src/index.ts b/src/index.ts
index 6a99799..90525bd 100644
--- a/src/index.ts
+++ b/src/index.ts
@@ -53,7 +53,6 @@ export * from './type/const/index'
export * from './type/constructor/index'
export * from './type/constructor-parameters/index'
export * from './type/date/index'
-export * from './type/deref/index'
export * from './type/enum/index'
export * from './type/exclude/index'
export * from './type/extends/index'
@@ -67,6 +66,7 @@ export * from './type/iterator/index'
export * from './type/intrinsic/index'
export * from './type/keyof/index'
export * from './type/literal/index'
+export * from './type/module/index'
export * from './type/mapped/index'
export * from './type/never/index'
export * from './type/not/index'
@@ -90,7 +90,6 @@ export * from './type/rest/index'
export * from './type/return-type/index'
export * from './type/schema/index'
export * from './type/static/index'
-export * from './type/strict/index'
export * from './type/string/index'
export * from './type/symbol/index'
export * from './type/template-literal/index'
diff --git a/src/syntax/parse.ts b/src/syntax/parse.ts
index 4605b9c..1ec0d41 100644
--- a/src/syntax/parse.ts
+++ b/src/syntax/parse.ts
@@ -26,36 +26,35 @@ THE SOFTWARE.
---------------------------------------------------------------------------*/
+import * as Types from '../type/index'
import { Static } from './parsebox/index'
-import { CreateType } from '../type/create/type'
-import { TSchema, SchemaOptions } from '../type/schema/index'
-import { StaticDecode } from '../type/static/index'
import { Module } from './runtime'
-import { Type } from './static'
+import { Main } from './static'
-/** `[Experimental]` Infers a TypeBox type from TypeScript syntax. */
-export type StaticParseAsSchema, Code extends string> = Static.Parse[0]
+/** `[Syntax]` Infers a TypeBox type from TypeScript syntax. */
+export type StaticParseAsSchema, Code extends string> = Static.Parse[0]
-/** `[Experimental]` Infers a TypeScript type from TypeScript syntax. */
-export type StaticParseAsType, Code extends string> = StaticParseAsSchema extends infer Type extends TSchema ? StaticDecode : undefined
+/** `[Syntax]` Infers a TypeScript type from TypeScript syntax. */
+export type StaticParseAsType, Code extends string> = StaticParseAsSchema extends infer Type extends Types.TSchema ? Types.StaticDecode : undefined
-/** `[Experimental]` Parses a TypeBox type from TypeScript syntax. */
-export function Parse, Code extends string>(context: Context, code: Code, options?: SchemaOptions): StaticParseAsSchema
-/** `[Experimental]` Parses a TypeBox type from TypeScript syntax. */
-export function Parse](code: Code, options?: SchemaOptions): StaticParseAsSchema<{}, Code>
-/** `[Experimental]` Parses a TypeBox type from TypeScript syntax. */
+/** `[Syntax]` Parses a TypeBox type from TypeScript syntax. */
+export function Parse, Code extends string>(context: Context, code: Code, options?: Types.SchemaOptions): StaticParseAsSchema
+/** `[Syntax]` Parses a TypeBox type from TypeScript syntax. */
+export function Parse(code: Code, options?: Types.SchemaOptions): StaticParseAsSchema<{}, Code>
+/** `[Syntax]` Parses a TypeBox type from TypeScript syntax. */
export function Parse(...args: any[]): never {
return ParseOnly.apply(null, args as never) as never
}
-/** `[Experimental]` Parses a TypeBox TSchema from TypeScript syntax. This function does not infer the type. */
-export function ParseOnly, Code extends string>(context: Context, code: Code, options?: SchemaOptions): TSchema | undefined
-/** `[Experimental]` Parses a TypeBox TSchema from TypeScript syntax */
-export function ParseOnly(code: Code, options?: SchemaOptions): TSchema | undefined
-/** `[Experimental]` Parses a TypeBox TSchema from TypeScript syntax. This function does not infer the type. */
-export function ParseOnly(...args: any[]): TSchema | undefined {
+/** `[Syntax]` Parses a TypeBox TSchema from TypeScript syntax. This function does not infer the type. */
+export function ParseOnly, Code extends string>(context: Context, code: Code, options?: Types.SchemaOptions): Types.TSchema | undefined
+/** `[Syntax]` Parses a TypeBox TSchema from TypeScript syntax */
+export function ParseOnly(code: Code, options?: Types.SchemaOptions): Types.TSchema | undefined
+/** `[Syntax]` Parses a TypeBox TSchema from TypeScript syntax. This function does not infer the type. */
+export function ParseOnly(...args: any[]): Types.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
+ const type = Module.Parse('Main', code, context)[0] as Types.TSchema | undefined
+ // Note: Parsing may return either a ModuleInstance or Type. We only apply options on the Type.
+ return Types.KindGuard.IsSchema(type) ? Types.CloneType(type, options) : type
}
diff --git a/src/syntax/runtime.ts b/src/syntax/runtime.ts
index 0d28dbb..15001ee 100644
--- a/src/syntax/runtime.ts
+++ b/src/syntax/runtime.ts
@@ -48,6 +48,7 @@ const SemiColon = ';'
const SingleQuote = "'"
const DoubleQuote = '"'
const Tilde = '`'
+const Equals = '='
// ------------------------------------------------------------------
// DestructureRight
@@ -59,13 +60,140 @@ function DestructureRight(values: T[]): [T[], T | undefined] {
: [values, undefined]
}
// ------------------------------------------------------------------
+// Deref
+// ------------------------------------------------------------------
+const Deref = (context: Types.TProperties, key: string): Types.TSchema => {
+ return key in context ? context[key] : Types.Ref(key)
+}
+// ------------------------------------------------------------------
+// ExportModifier
+// ------------------------------------------------------------------
+// prettier-ignore
+const ExportModifierMapping = (values: unknown[]) => {
+ return values.length === 1
+}
+// prettier-ignore
+const ExportModifier = Runtime.Union([
+ Runtime.Tuple([Runtime.Const('export')]), Runtime.Tuple([])
+], ExportModifierMapping)
+
+// ------------------------------------------------------------------
+// TypeAliasDeclaration
+// ------------------------------------------------------------------
+// prettier-ignore
+const TypeAliasDeclarationMapping = (_Export: boolean, _Keyword: 'type', Ident: string, _Equals: typeof Equals, Type: Types.TSchema) => {
+ return { [Ident]: Type }
+}
+// prettier-ignore
+const TypeAliasDeclaration = Runtime.Tuple([
+ Runtime.Ref('ExportModifier'),
+ Runtime.Const('type'),
+ Runtime.Ident(),
+ Runtime.Const(Equals),
+ Runtime.Ref('Type')
+], value => TypeAliasDeclarationMapping(...value))
+
+// ------------------------------------------------------------------
+// HeritageList
+// ------------------------------------------------------------------
+// prettier-ignore (note, heritage list should disallow trailing comma)
+const HeritageListDelimiter = Runtime.Union([Runtime.Tuple([Runtime.Const(Comma), Runtime.Const(Newline)]), Runtime.Tuple([Runtime.Const(Comma)])])
+// prettier-ignore
+const HeritageListMapping = (values: string[], context: Types.TProperties): Types.TSchema[] => {
+ return (
+ values.length === 3 ? [Deref(context, values[0]), ...values[2] as never] :
+ values.length === 1 ? [Deref(context, values[0])] :
+ []
+ ) as never
+}
+// prettier-ignore
+const HeritageList = Runtime.Union([
+ Runtime.Tuple([Runtime.Ident(), HeritageListDelimiter, Runtime.Ref('HeritageList')]),
+ Runtime.Tuple([Runtime.Ident()]),
+ Runtime.Tuple([])
+], HeritageListMapping)
+// ------------------------------------------------------------------
+// Heritage
+// ------------------------------------------------------------------
+// prettier-ignore
+const HeritageMapping = (values: unknown[]): unknown[] => {
+ return (values.length === 2 ? values[1] : []) as never
+}
+// prettier-ignore
+const Heritage = Runtime.Union([
+ Runtime.Tuple([Runtime.Const('extends'), Runtime.Ref('HeritageList')]),
+ Runtime.Tuple([])
+], HeritageMapping)
+// ------------------------------------------------------------------
+// InterfaceDeclaration
+// ------------------------------------------------------------------
+// prettier-ignore
+const InterfaceDeclarationMapping = (_0: boolean, _1: 'interface', Ident: string, Heritage: Types.TRef[], _4: typeof LBrace, Properties: Types.TProperties, _6: typeof RBrace) => {
+ return { [Ident]: Types.Intersect([...Heritage, Types.Object(Properties)]) }
+}
+// prettier-ignore
+const InterfaceDeclaration = Runtime.Tuple([
+ Runtime.Ref('ExportModifier'),
+ Runtime.Const('interface'),
+ Runtime.Ident(),
+ Runtime.Ref('Heritage'),
+ Runtime.Const(LBrace),
+ Runtime.Ref('Properties'),
+ Runtime.Const(RBrace),
+], values => InterfaceDeclarationMapping(...values))
+
+// ------------------------------------------------------------------
+// ModuleType
+// ------------------------------------------------------------------
+// prettier-ignore
+const ModuleType = Runtime.Union([
+ Runtime.Ref('InterfaceDeclaration'),
+ Runtime.Ref('TypeAliasDeclaration')
+])
+// ------------------------------------------------------------------
+// ModuleProperties
+// ------------------------------------------------------------------
+// prettier-ignore
+const ModulePropertiesDelimiter = Runtime.Union([
+ Runtime.Tuple([Runtime.Const(SemiColon), Runtime.Const(Newline)]),
+ Runtime.Tuple([Runtime.Const(SemiColon)]),
+ Runtime.Tuple([Runtime.Const(Newline)]),
+])
+// prettier-ignore
+const ModulePropertiesMapping = (values: unknown[]): Types.TProperties => {
+ return (
+ values.length === 3 ? { ...values[0] as Types.TProperties, ...values[2] as Types.TProperties }:
+ values.length === 1 ? values[0] as Types.TProperties :
+ {} as Types.TProperties
+ )
+}
+// prettier-ignore
+const ModuleProperties = Runtime.Union([
+ Runtime.Tuple([Runtime.Ref('ModuleType'), ModulePropertiesDelimiter, Runtime.Ref('ModuleProperties')]),
+ Runtime.Tuple([Runtime.Ref('ModuleType')]),
+ Runtime.Tuple([]),
+], ModulePropertiesMapping)
+// ------------------------------------------------------------------
+// ModuleDeclaration
+// ------------------------------------------------------------------
+// prettier-ignore
+const ModuleIdentifier = Runtime.Union([
+ Runtime.Tuple([Runtime.Ident()]),
+ Runtime.Tuple([])
+])
+// prettier-ignore
+const ModuleDeclarationMapping = (_1: boolean, _2: 'module', _Ident: string[], _3: typeof LBrace, Properties: Types.TProperties, _5: typeof RBrace) => {
+ return Types.Module(Properties)
+}
+// prettier-ignore
+const ModuleDeclaration = Runtime.Tuple([
+ Runtime.Ref('ExportModifier'), Runtime.Const('module'), ModuleIdentifier, Runtime.Const(LBrace), Runtime.Ref('ModuleProperties'), Runtime.Const(RBrace)
+], values => ModuleDeclarationMapping(...values))
+// ------------------------------------------------------------------
// Reference
// ------------------------------------------------------------------
// prettier-ignore
-const Reference = Runtime.Ident((value, context: Record) => {
- return value in context ? context[value] : Types.Ref(value)
-})
-
+const Reference = Runtime.Ident((value, context: Types.TProperties) => Deref(context, value))
// ------------------------------------------------------------------
// Literal
// ------------------------------------------------------------------
@@ -75,7 +203,6 @@ const Literal = Runtime.Union([
Runtime.Number(value => Types.Literal(parseFloat(value))),
Runtime.String([SingleQuote, DoubleQuote, Tilde], value => Types.Literal(value))
])
-
// ------------------------------------------------------------------
// Keyword
// ------------------------------------------------------------------
@@ -94,7 +221,6 @@ const Keyword = Runtime.Union([
Runtime.Const('unknown', Runtime.As(Types.Unknown())),
Runtime.Const('void', Runtime.As(Types.Void())),
])
-
// ------------------------------------------------------------------
// KeyOf
// ------------------------------------------------------------------
@@ -106,7 +232,6 @@ const KeyOfMapping = (values: unknown[]) => (
const KeyOf = Runtime.Union([
Runtime.Tuple([Runtime.Const('keyof')]), Runtime.Tuple([])
], KeyOfMapping)
-
// ------------------------------------------------------------------
// IndexArray
// ------------------------------------------------------------------
@@ -137,7 +262,6 @@ 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
// ------------------------------------------------------------------
@@ -219,7 +343,6 @@ const Factor = Runtime.Tuple([
Runtime.Ref('IndexArray'),
Runtime.Ref('Extends')
], values => FactorMapping(...values))
-
// ------------------------------------------------------------------
// Expr
// ------------------------------------------------------------------
@@ -266,30 +389,26 @@ const Expr = Runtime.Tuple([
// Type
// ------------------------------------------------------------------
const Type = Runtime.Ref('Expr')
-
// ------------------------------------------------------------------
// Properties
// ------------------------------------------------------------------
-// prettier-ignore
const PropertyKey = Runtime.Union([Runtime.Ident(), Runtime.String([SingleQuote, DoubleQuote])])
+const Readonly = Runtime.Union([Runtime.Tuple([Runtime.Const('readonly')]), Runtime.Tuple([])], (value) => value.length > 0)
+const Optional = Runtime.Union([Runtime.Tuple([Runtime.Const(Question)]), Runtime.Tuple([])], (value) => value.length > 0)
// 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) => ({
+const PropertyMapping = (IsReadonly: boolean, Key: string, IsOptional: boolean, _: typeof Colon, Type: Types.TSchema) => ({
[Key]: (
- Readonly && Optional ? Types.ReadonlyOptional(Type) :
- Readonly && !Optional ? Types.Readonly(Type) :
- !Readonly && Optional ? Types.Optional(Type) :
+ IsReadonly && IsOptional ? Types.ReadonlyOptional(Type) :
+ IsReadonly && !IsOptional ? Types.Readonly(Type) :
+ !IsReadonly && IsOptional ? Types.Optional(Type) :
Type
)
})
// prettier-ignore
const Property = Runtime.Tuple([
- Runtime.Ref('PropertyReadonly'),
+ Runtime.Ref('Readonly'),
Runtime.Ref('PropertyKey'),
- Runtime.Ref('PropertyOptional'),
+ Runtime.Ref('Optional'),
Runtime.Const(Colon),
Runtime.Ref('Type'),
], value => PropertyMapping(...value))
@@ -303,30 +422,27 @@ const PropertyDelimiter = Runtime.Union([
])
// 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([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]] :
- []
+ values.length === 3 ? { ...values[0], ...values[2] } :
+ values.length === 2 ? values[0] :
+ values.length === 1 ? values[0] :
+ {}
))
-
// ------------------------------------------------------------------
// Object
// ------------------------------------------------------------------
// prettier-ignore
-const ObjectMapping = (values: Record[]) => Types.Object(values.reduce((properties, record) => {
- return { ...properties, ...record }
-}, {} as Types.TProperties))
+const ObjectMapping = (_0: typeof LBrace, Properties: Types.TProperties, _2: typeof RBrace) => Types.Object(Properties)
// prettier-ignore
const _Object = Runtime.Tuple([
Runtime.Const(LBrace),
- Runtime.Ref[]>('Properties'),
+ Runtime.Ref('Properties'),
Runtime.Const(RBrace)
-], values => ObjectMapping(values[1]))
+], values => ObjectMapping(...values))
// ------------------------------------------------------------------
// Tuple
@@ -401,7 +517,15 @@ const MappedMapping = (values: unknown[]) => {
}
// prettier-ignore
const Mapped = Runtime.Tuple([
- Runtime.Const(LBrace), Runtime.Const(LBracket), Runtime.Ident(), Runtime.Const('in'), Runtime.Ref('Type'), Runtime.Const(RBracket), Runtime.Const(Colon), Runtime.Ref('Type'), Runtime.Const(RBrace)
+ Runtime.Const(LBrace),
+ Runtime.Const(LBracket),
+ Runtime.Ident(),
+ Runtime.Const('in'),
+ Runtime.Ref('Type'),
+ Runtime.Const(RBracket),
+ Runtime.Const(Colon),
+ Runtime.Ref('Type'),
+ Runtime.Const(RBrace)
], MappedMapping)
// ------------------------------------------------------------------
// AsyncIterator
@@ -621,11 +745,37 @@ const Date = Runtime.Const('Date', Runtime.As(Types.Date()))
// Uint8Array
// ------------------------------------------------------------------
const Uint8Array = Runtime.Const('Uint8Array', Runtime.As(Types.Uint8Array()))
+
+// ------------------------------------------------------------------
+// Main
+// ------------------------------------------------------------------
+// prettier-ignore
+const Main = Runtime.Union([
+ ModuleDeclaration,
+ TypeAliasDeclaration,
+ InterfaceDeclaration,
+ Type
+])
// ------------------------------------------------------------------
// Module
// ------------------------------------------------------------------
// prettier-ignore
export const Module = new Runtime.Module({
+ // ----------------------------------------------------------------
+ // Modules, Interfaces and Type Aliases
+ // ----------------------------------------------------------------
+ ExportModifier,
+ HeritageList,
+ Heritage,
+ InterfaceDeclaration,
+ TypeAliasDeclaration,
+ ModuleType,
+ ModuleProperties,
+ ModuleDeclaration,
+
+ // ----------------------------------------------------------------
+ // Type Expressions
+ // ----------------------------------------------------------------
Literal,
Keyword,
KeyOf,
@@ -637,10 +787,10 @@ export const Module = new Runtime.Module({
ExprTerm,
ExprTail,
Expr,
- Type,
+ Type, // Alias for Expr
PropertyKey,
- PropertyReadonly,
- PropertyOptional,
+ Readonly,
+ Optional,
Property,
PropertyDelimiter,
Properties,
@@ -674,5 +824,10 @@ export const Module = new Runtime.Module({
Uncapitalize,
Date,
Uint8Array,
- Reference
+ Reference,
+
+ // ----------------------------------------------------------------
+ // Main
+ // ----------------------------------------------------------------
+ Main
})
diff --git a/src/syntax/static.ts b/src/syntax/static.ts
index ff75dca..0b30b8e 100644
--- a/src/syntax/static.ts
+++ b/src/syntax/static.ts
@@ -48,6 +48,7 @@ type SemiColon = ';'
type SingleQuote = "'"
type DoubleQuote = '"'
type Tilde = '`'
+type Equals = '='
// ------------------------------------------------------------------
// Delimit
@@ -135,18 +136,156 @@ type Delimit =
], DelimitMapping>
)
// ------------------------------------------------------------------
+// Deref
+// ------------------------------------------------------------------
+// prettier-ignore
+type Deref = (
+ Ref extends keyof Context ? Context[Ref] : Types.TRef[
+)
+// ------------------------------------------------------------------
+// ExportModifier
+// ------------------------------------------------------------------
+// prettier-ignore
+interface ExportModifierMapping extends Static.IMapping {
+ output: this['input'] extends [string] ? true : false
+}
+// prettier-ignore
+type ExportModifier = Static.Union<[
+ Static.Tuple<[Static.Const<'export'>]>,
+ Static.Tuple<[]>,
+], ExportModifierMapping>
+
+// ------------------------------------------------------------------
+// TypeAliasDeclaration
+// ------------------------------------------------------------------
+// prettier-ignore
+interface TypeAliasDeclarationMapping extends Static.IMapping {
+ output: this['input'] extends [infer _Export extends boolean, 'type', infer Ident extends string, Equals, infer Type extends Types.TSchema]
+ ? { [_ in Ident]: Type }
+ : never
+}
+// prettier-ignore
+type TypeAliasDeclaration = Static.Tuple<[
+ ExportModifier, Static.Const<'type'>, Static.Ident, Static.Const, Type
+], TypeAliasDeclarationMapping>
+
+// ------------------------------------------------------------------
+// HeritageList
+// ------------------------------------------------------------------
+// prettier-ignore (note, heritage list should disallow trailing comma)
+type HeritageListDelimiter = Static.Union<[Static.Tuple<[Static.Const, Static.Const]>, Static.Tuple<[Static.Const]>]>
+// prettier-ignore
+type HeritageListReduce = (
+ Values extends [infer Ref extends string, ...infer Rest extends string[]]
+ ? HeritageListReduce]>
+ : Result
+)
+// prettier-ignore
+interface HeritageListMapping extends Static.IMapping {
+ output: (
+ this['context'] extends Types.TProperties ?
+ this['input'] extends string[]
+ ? HeritageListReduce
+ : []
+ : []
+ )
+}
+// prettier-ignore
+type HeritageList = Static.Union<[Delimit], HeritageListMapping>
+// ------------------------------------------------------------------
+// Heritage
+// ------------------------------------------------------------------
+// prettier-ignore
+interface HeritageMapping extends Static.IMapping {
+ output: this['input'] extends ['extends', infer List extends Types.TSchema[]] ? List : []
+}
+// prettier-ignore
+type Heritage = Static.Union<[
+ Static.Tuple<[Static.Const<'extends'>, HeritageList]>,
+ Static.Tuple<[]>
+], HeritageMapping>
+// ------------------------------------------------------------------
+// InterfaceDeclaration
+// ------------------------------------------------------------------
+// prettier-ignore
+interface InterfaceDeclarationMapping extends Static.IMapping {
+ output: this['input'] extends [boolean, 'interface', infer Ident extends string, infer Heritage extends Types.TSchema[], LBrace, infer Properties extends Types.TProperties, RBrace]
+ ? { [_ in Ident]: Types.TIntersectEvaluated<[...Heritage, Types.TObject]> }
+ : never
+}
+// prettier-ignore
+type InterfaceDeclaration = Static.Tuple<[
+ ExportModifier,
+ Static.Const<'interface'>,
+ Static.Ident,
+ Heritage,
+ Static.Const,
+ Properties,
+ Static.Const,
+], InterfaceDeclarationMapping>
+// ------------------------------------------------------------------
+// ModuleType
+// ------------------------------------------------------------------
+// prettier-ignore
+type ModuleType = Static.Union<[
+ InterfaceDeclaration,
+ TypeAliasDeclaration
+]>
+// ------------------------------------------------------------------
+// ModuleProperties
+// ------------------------------------------------------------------
+// prettier-ignore
+type ModulePropertiesDelimiter = Static.Union<[
+ Static.Tuple<[Static.Const, Static.Const]>,
+ Static.Tuple<[Static.Const]>,
+ Static.Tuple<[Static.Const]>,
+]>
+// prettier-ignore
+type ModulePropertiesReduce = (
+ Value extends [infer ModuleType extends Types.TProperties, unknown[], ...infer Rest extends unknown[]] ? ModulePropertiesReduce :
+ Value extends [infer ModuleType extends Types.TProperties] ? ModulePropertiesReduce<[], Result & ModuleType> :
+ Types.Evaluate
+)
+// prettier-ignore
+interface ModulePropertiesMapping extends Static.IMapping {
+ output: this['input'] extends unknown[] ? ModulePropertiesReduce : never
+}
+// prettier-ignore
+type ModuleProperties = Static.Union<[
+ Static.Tuple<[ModuleType, ModulePropertiesDelimiter, ModuleProperties]>,
+ Static.Tuple<[ModuleType]>,
+ Static.Tuple<[]>,
+], ModulePropertiesMapping>
+// ------------------------------------------------------------------
+// ModuleDeclaration
+// ------------------------------------------------------------------
+// prettier-ignore
+type ModuleIdentifier = Static.Union<[
+ Static.Tuple<[Static.Ident]>,
+ Static.Tuple<[]>
+]>
+// prettier-ignore
+interface ModuleDeclarationMapping extends Static.IMapping {
+ output: this['input'] extends [boolean, 'module', infer _Ident extends string[], LBrace, infer Properties extends Types.TProperties, RBrace]
+ ? Types.TModule
+ : never
+}
+// prettier-ignore
+type ModuleDeclaration = Static.Tuple<[
+ ExportModifier, Static.Const<'module'>, ModuleIdentifier, Static.Const, ModuleProperties, Static.Const
+], ModuleDeclarationMapping>
+// ------------------------------------------------------------------
// 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
- : never
+ output: this['context'] extends Types.TProperties
+ ? this['input'] extends string
+ ? Deref
+ : never
+ : never
}
-type Reference = Static.Tuple<[Static.Ident], ReferenceMapping>
-
+type Reference = Static.Ident
// ------------------------------------------------------------------
// Literal
// ------------------------------------------------------------------
@@ -198,7 +337,6 @@ type KeyOf = Static.Union<[
Static.Tuple<[Static.Const<'keyof'>]>,
Static.Tuple<[]>
], KeyOfMapping>
-
// ------------------------------------------------------------------
// IndexArray
// ------------------------------------------------------------------
@@ -231,7 +369,6 @@ type Extends = Static.Union<[
Static.Tuple<[Static.Const<'extends'>, Type, Static.Const, Type, Static.Const, Type]>,
Static.Tuple<[]>
], ExtendsMapping>
-
// ------------------------------------------------------------------
// Base
// ------------------------------------------------------------------
@@ -361,7 +498,7 @@ type Expr = Static.Tuple<[
// ------------------------------------------------------------------
// Type
// ------------------------------------------------------------------
-export type Type = Expr
+type Type = Expr
// ------------------------------------------------------------------
// Properties
// ------------------------------------------------------------------
@@ -370,34 +507,30 @@ 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 {
+interface ReadonlyMapping extends Static.IMapping {
output: this['input'] extends ['readonly'] ? true : false
}
-type PropertyReadonly = Static.Union<[Static.Tuple<[Static.Const<'readonly'>]>, Static.Tuple<[]>], PropertyReadonlyMapping>
+type Readonly = Static.Union<[Static.Tuple<[Static.Const<'readonly'>]>, Static.Tuple<[]>], ReadonlyMapping>
// prettier-ignore
-interface PropertyOptionalMapping extends Static.IMapping {
+interface OptionalMapping extends Static.IMapping {
output: this['input'] extends [Question] ? true : false
}
-type PropertyOptional = Static.Union<[Static.Tuple<[Static.Const]>, Static.Tuple<[]>], PropertyOptionalMapping>
+type Optional = Static.Union<[Static.Tuple<[Static.Const]>, Static.Tuple<[]>], OptionalMapping>
// 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]
+ output: this['input'] extends [infer IsReadonly extends boolean, infer Key extends string, infer IsOptional extends boolean, string, infer Type extends Types.TSchema]
? {
[_ in Key]: (
- [Readonly, Optional] extends [true, true] ? Types.TReadonlyOptional :
- [Readonly, Optional] extends [true, false] ? Types.TReadonly :
- [Readonly, Optional] extends [false, true] ? Types.TOptional :
+ [IsReadonly, IsOptional] extends [true, true] ? Types.TReadonlyOptional :
+ [IsReadonly, IsOptional] extends [true, false] ? Types.TReadonly :
+ [IsReadonly, IsOptional] extends [false, true] ? Types.TOptional :
Type
)
} : never
}
-
-type Property = Static.Tuple<[PropertyReadonly, PropertyKey, PropertyOptional, Static.Const, Type], PropertyMapping>
-
-type PropertiesEvaluate = { [K in keyof T]: T[K] } & {}
+type Property = Static.Tuple<[Readonly, PropertyKey, Optional, Static.Const, Type], PropertyMapping>
// prettier-ignore
type PropertyDelimiter = Static.Union<[
Static.Tuple<[Static.Const, Static.Const]>,
@@ -409,7 +542,7 @@ type PropertyDelimiter = Static.Union<[
// prettier-ignore
type PropertiesReduce = (
PropertiesArray extends [infer Left extends Types.TProperties, ...infer Right extends Types.TProperties[]]
- ? PropertiesReduce>
+ ? PropertiesReduce>
: Result
)
// prettier-ignore
@@ -485,7 +618,7 @@ type Constructor = Static.Tuple<[
// ------------------------------------------------------------------
// 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]
+ 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']
}
@@ -762,3 +895,14 @@ type Date = Static.Const<'Date', Static.As>
// Uint8Array
// ------------------------------------------------------------------
type Uint8Array = Static.Const<'Uint8Array', Static.As>
+
+// ------------------------------------------------------------------
+// Main
+// ------------------------------------------------------------------
+// prettier-ignore
+export type Main = Static.Union<[
+ ModuleDeclaration,
+ TypeAliasDeclaration,
+ InterfaceDeclaration,
+ Type
+]>
diff --git a/src/type/deref/deref.ts b/src/type/deref/deref.ts
deleted file mode 100644
index 76d626a..0000000
--- a/src/type/deref/deref.ts
+++ /dev/null
@@ -1,174 +0,0 @@
-/*--------------------------------------------------------------------------
-
-@sinclair/typebox/type
-
-The MIT License (MIT)
-
-Copyright (c) 2017-2024 Haydn Paterson (sinclair)
-
-Permission is hereby granted, free of charge, to any person obtaining a copy
-of this software and associated documentation files (the "Software"), to deal
-in the Software without restriction, including without limitation the rights
-to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-copies of the Software, and to permit persons to whom the Software is
-furnished to do so, subject to the following conditions:
-
-The above copyright notice and this permission notice shall be included in
-all copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-THE SOFTWARE.
-
----------------------------------------------------------------------------*/
-
-import type { TSchema } from '../schema/index'
-import type { Evaluate } from '../helpers/index'
-import type { TTuple } from '../tuple/index'
-import type { TIntersect } from '../intersect/index'
-import type { TUnion } from '../union/index'
-import type { TPromise } from '../promise/index'
-import type { TAsyncIterator } from '../async-iterator/index'
-import type { TIterator } from '../iterator/index'
-import type { TArray } from '../array/index'
-import type { TConstructor } from '../constructor/index'
-import type { TFunction } from '../function/index'
-import type { TRef } from '../ref/index'
-import type { TObject, TProperties } from '../object/index'
-import { CloneType, CloneRest } from '../clone/type'
-import { Discard } from '../discard/index'
-import { IsUndefined } from '../guard/value'
-
-// ------------------------------------------------------------------
-// TypeGuard
-// ------------------------------------------------------------------
-import { IsConstructor, IsFunction, IsIntersect, IsUnion, IsTuple, IsArray, IsObject, IsPromise, IsAsyncIterator, IsIterator, IsRef } from '../guard/kind'
-// ------------------------------------------------------------------
-// FromRest
-// ------------------------------------------------------------------
-// prettier-ignore
-export type TFromRest = (
- T extends [infer L extends TSchema, ...infer R extends TSchema[]]
- ? TFromRest]>
- : Acc
-)
-function FromRest(schema: [...T], references: TSchema[]): TFromRest {
- return schema.map((schema) => Deref(schema, references)) as never
-}
-// ------------------------------------------------------------------
-// FromProperties
-// ------------------------------------------------------------------
-// prettier-ignore
-type FromProperties = Evaluate<{
- [K in keyof T]: TDeref
-}>
-// prettier-ignore
-function FromProperties(properties: TProperties, references: TSchema[]) {
- const Acc = {} as TProperties
- for(const K of globalThis.Object.getOwnPropertyNames(properties)) {
- Acc[K] = Deref(properties[K], references)
- }
- return Acc as never
-}
-// prettier-ignore
-function FromConstructor(schema: TConstructor, references: TSchema[]) {
- schema.parameters = FromRest(schema.parameters, references)
- schema.returns = Deref(schema.returns, references)
- return schema
-}
-// prettier-ignore
-function FromFunction(schema: TFunction, references: TSchema[]) {
- schema.parameters = FromRest(schema.parameters, references)
- schema.returns = Deref(schema.returns, references)
- return schema
-}
-// prettier-ignore
-function FromIntersect(schema: TIntersect, references: TSchema[]) {
- schema.allOf = FromRest(schema.allOf, references)
- return schema
-}
-// prettier-ignore
-function FromUnion(schema: TUnion, references: TSchema[]) {
- schema.anyOf = FromRest(schema.anyOf, references)
- return schema
-}
-// prettier-ignore
-function FromTuple(schema: TTuple, references: TSchema[]) {
- if(IsUndefined(schema.items)) return schema
- schema.items = FromRest(schema.items, references)
- return schema
-}
-// prettier-ignore
-function FromArray(schema: TArray, references: TSchema[]) {
- schema.items = Deref(schema.items, references)
- return schema
-}
-// prettier-ignore
-function FromObject(schema: TObject, references: TSchema[]) {
- schema.properties = FromProperties(schema.properties, references)
- return schema
-}
-// prettier-ignore
-function FromPromise(schema: TPromise, references: TSchema[]) {
- schema.item = Deref(schema.item, references)
- return schema
-}
-// prettier-ignore
-function FromAsyncIterator(schema: TAsyncIterator, references: TSchema[]) {
- schema.items = Deref(schema.items, references)
- return schema
-}
-// prettier-ignore
-function FromIterator(schema: TIterator, references: TSchema[]) {
- schema.items = Deref(schema.items, references)
- return schema
-}
-// prettier-ignore
-function FromRef(schema: TRef, references: TSchema[]) {
- const target = references.find(remote => remote.$id === schema.$ref)
- if(target === undefined) throw Error(`Unable to dereference schema with $id ${schema.$ref}`)
- const discard = Discard(target, ['$id']) as TSchema
- return Deref(discard, references)
-}
-// prettier-ignore
-function DerefResolve(schema: T, references: TSchema[]): TDeref {
- return (
- IsConstructor(schema) ? FromConstructor(schema, references) :
- IsFunction(schema) ? FromFunction(schema, references) :
- IsIntersect(schema) ? FromIntersect(schema, references) :
- IsUnion(schema) ? FromUnion(schema, references) :
- IsTuple(schema) ? FromTuple(schema, references) :
- IsArray(schema) ? FromArray(schema, references) :
- IsObject(schema) ? FromObject(schema, references) :
- IsPromise(schema) ? FromPromise(schema, references) :
- IsAsyncIterator(schema) ? FromAsyncIterator(schema, references) :
- IsIterator(schema) ? FromIterator(schema, references) :
- IsRef(schema) ? FromRef(schema, references) :
- schema
- ) as never
-}
-// prettier-ignore
-export type TDeref =
- T extends TConstructor ? TConstructor, TDeref> :
- T extends TFunction ? TFunction, TDeref> :
- T extends TIntersect ? TIntersect> :
- T extends TUnion ? TUnion> :
- T extends TTuple ? TTuple> :
- T extends TObject ? TObject> :
- T extends TArray ? TArray> :
- T extends TPromise ? TPromise> :
- T extends TAsyncIterator ? TAsyncIterator> :
- T extends TIterator ? TIterator> :
- T extends TRef ? TDeref] :
- T
-// ------------------------------------------------------------------
-// TDeref
-// ------------------------------------------------------------------
-/** `[Json]` Creates a dereferenced type */
-export function Deref(schema: T, references: TSchema[]): TDeref {
- return DerefResolve(CloneType(schema), CloneRest(references))
-}
diff --git a/src/type/guard/kind.ts b/src/type/guard/kind.ts
index b68f01b..2e61a1d 100644
--- a/src/type/guard/kind.ts
+++ b/src/type/guard/kind.ts
@@ -40,6 +40,7 @@ import type { TAsyncIterator } from '../async-iterator/index'
import type { TBigInt } from '../bigint/index'
import type { TConstructor } from '../constructor/index'
import type { TFunction } from '../function/index'
+import type { TImport } from '../module/index'
import type { TInteger } from '../integer/index'
import type { TIntersect } from '../intersect/index'
import type { TIterator } from '../iterator/index'
@@ -107,6 +108,10 @@ export function IsFunction(value: unknown): value is TFunction {
return IsKindOf(value, 'Function')
}
/** `[Kind-Only]` Returns true if the given value is TInteger */
+export function IsImport(value: unknown): value is TImport {
+ return IsKindOf(value, 'Import')
+}
+/** `[Kind-Only]` Returns true if the given value is TInteger */
export function IsInteger(value: unknown): value is TInteger {
return IsKindOf(value, 'Integer')
}
diff --git a/src/type/guard/type.ts b/src/type/guard/type.ts
index b2e9daa..ed8eb54 100644
--- a/src/type/guard/type.ts
+++ b/src/type/guard/type.ts
@@ -41,6 +41,7 @@ import type { TAsyncIterator } from '../async-iterator/index'
import type { TBigInt } from '../bigint/index'
import type { TConstructor } from '../constructor/index'
import type { TFunction } from '../function/index'
+import type { TImport } from '../module/index'
import type { TInteger } from '../integer/index'
import type { TIntersect } from '../intersect/index'
import type { TIterator } from '../iterator/index'
@@ -253,6 +254,19 @@ export function IsFunction(value: unknown): value is TFunction {
IsSchema(value.returns)
)
}
+/** Returns true if the given value is TImport */
+export function IsImport(value: unknown): value is TImport {
+ // prettier-ignore
+ return (
+ IsKindOf(value, 'Import') &&
+ ValueGuard.HasPropertyKey(value, '$defs') &&
+ ValueGuard.IsObject(value.$defs) &&
+ IsProperties(value.$defs) &&
+ ValueGuard.HasPropertyKey(value, '$ref') &&
+ ValueGuard.IsString(value.$ref) &&
+ value.$ref in value.$defs // required
+ )
+}
/** Returns true if the given value is TInteger */
export function IsInteger(value: unknown): value is TInteger {
return (
diff --git a/src/type/index.ts b/src/type/index.ts
index b69a1fa..d9d5d50 100644
--- a/src/type/index.ts
+++ b/src/type/index.ts
@@ -38,7 +38,6 @@ export * from './const/index'
export * from './constructor/index'
export * from './constructor-parameters/index'
export * from './date/index'
-export * from './deref/index'
export * from './discard/index'
export * from './enum/index'
export * from './error/index'
@@ -57,6 +56,7 @@ export * from './iterator/index'
export * from './keyof/index'
export * from './literal/index'
export * from './mapped/index'
+export * from './module/index'
export * from './never/index'
export * from './not/index'
export * from './null/index'
@@ -82,7 +82,6 @@ export * from './return-type/index'
export * from './schema/index'
export * from './sets/index'
export * from './static/index'
-export * from './strict/index'
export * from './string/index'
export * from './symbol/index'
export * from './symbols/index'
diff --git a/src/type/deref/index.ts b/src/type/module/index.ts
similarity index 98%
rename from src/type/deref/index.ts
rename to src/type/module/index.ts
index 28c03fc..ce46d5a 100644
--- a/src/type/deref/index.ts
+++ b/src/type/module/index.ts
@@ -26,4 +26,4 @@ THE SOFTWARE.
---------------------------------------------------------------------------*/
-export * from './deref'
+export * from './module'
diff --git a/src/type/module/module.ts b/src/type/module/module.ts
new file mode 100644
index 0000000..3fef83c
--- /dev/null
+++ b/src/type/module/module.ts
@@ -0,0 +1,189 @@
+/*--------------------------------------------------------------------------
+
+@sinclair/typebox/type
+
+The MIT License (MIT)
+
+Copyright (c) 2017-2024 Haydn Paterson (sinclair)
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+
+---------------------------------------------------------------------------*/
+
+import { Ensure } from '../helpers/index'
+import { CreateType } from '../create/index'
+import { Kind } from '../symbols/index'
+import { SchemaOptions, TSchema } from '../schema/index'
+import { TObject, TProperties } from '../object/index'
+import { TConstructor } from '../constructor/index'
+import { TFunction } from '../function/index'
+import { TTuple } from '../tuple/index'
+import { TIntersect } from '../intersect/index'
+import { TUnion } from '../union/index'
+import { TArray } from '../array/index'
+import { TAsyncIterator } from '../async-iterator/index'
+import { TIterator } from '../iterator/index'
+import { TLiteral, TLiteralValue } from '../literal/index'
+import { TAny } from '../any/index'
+import { TBigInt } from '../bigint/index'
+import { TBoolean } from '../boolean/index'
+import { TDate } from '../date/index'
+import { TInteger } from '../integer/index'
+import { TNever } from '../never/index'
+import { TNumber } from '../number/index'
+import { TNull } from '../null/index'
+import { TRef } from '../ref/index'
+import { TRegExp } from '../regexp/index'
+import { TString } from '../string/index'
+import { TSymbol } from '../symbol/index'
+import { TTemplateLiteral, TTemplateLiteralKind } from '../template-literal/index'
+import { TUint8Array } from '../uint8array/index'
+import { TUndefined } from '../undefined/index'
+import { TUnknown } from '../unknown/index'
+import { TVoid } from '../void/index'
+import { Static } from '../static/index'
+
+// ------------------------------------------------------------------
+// Infer
+// ------------------------------------------------------------------
+// prettier-ignore
+type InferImport = (
+ Infer
+)
+// prettier-ignore
+type InferRef[ = (
+ Ref extends keyof Properties ? Infer : never
+)
+// prettier-ignore
+type InferObject = {
+ [K in keyof Properties]: Infer
+} & {}
+// prettier-ignore
+type InferConstructor = Ensure<
+ new (...args: InferTuple) => Infer
+>
+// prettier-ignore
+type InferFunction = Ensure<
+ (...args: InferTuple) => Infer
+>
+// prettier-ignore
+type InferTuple = (
+ Types extends [infer L extends TSchema, ...infer R extends TSchema[]]
+ ? InferTuple]>
+ : Result
+)
+// prettier-ignore
+type InferIntersect = (
+ Types extends [infer L extends TSchema, ...infer R extends TSchema[]]
+ ? InferIntersect>
+ : Result
+)
+// prettier-ignore
+type InferUnion = (
+ Types extends [infer L extends TSchema, ...infer R extends TSchema[]]
+ ? InferUnion>
+ : Result
+)
+// prettier-ignore
+type InferArray = (
+ Ensure>>
+)
+// prettier-ignore
+type InferAsyncIterator = (
+ Ensure>>
+)
+// prettier-ignore
+type InferIterator = (
+ Ensure>>
+)
+// prettier-ignore
+type Infer = (
+ Type extends TImport ? InferImport] :
+ Type extends TRef