diff --git a/design/typemap.blend b/design/typemap.blend
index f2223f8..97ab8c7 100644
Binary files a/design/typemap.blend and b/design/typemap.blend differ
diff --git a/design/typemap.blend1 b/design/typemap.blend1
index f270d64..3e58072 100644
Binary files a/design/typemap.blend1 and b/design/typemap.blend1 differ
diff --git a/example/index.ts b/example/index.ts
index 08cb705..b12032a 100644
--- a/example/index.ts
+++ b/example/index.ts
@@ -1,6 +1,10 @@
import { TypeBox, Valibot, Zod } from '@sinclair/typemap'
-// TypeScript Syntax Type
+// Parse Syntax | Parse Value
+
+const R = Zod('string | number').parse('...') // const R: string | number
+
+// Syntax Type
const S = `{
x: number,
@@ -8,8 +12,6 @@ const S = `{
z: number
}`
-// Construct Library Types from Syntax
-
const T = TypeBox(S) // const T: TObject<{
// x: TNumber,
// y: TNumber,
@@ -29,6 +31,3 @@ const Z = Zod(S) // const Z: ZodObject<{
// z: ZodNumber
// }, ...>
-// Parse Syntax | Parse Value
-
-const R = Zod('string | number').parse('...') // const R: string | number
\ No newline at end of file
diff --git a/hammer.mjs b/hammer.mjs
index 824fc27..073d9d8 100644
--- a/hammer.mjs
+++ b/hammer.mjs
@@ -23,7 +23,7 @@ export async function start() {
// Format
// -------------------------------------------------------------------------------
export async function format() {
- await shell('prettier --no-semi --single-quote --print-width 240 --trailing-comma all --write test src example/index.ts')
+ await shell('prettier --no-semi --single-quote --print-width 240 --trailing-comma all --write test src')
}
// ------------------------------------------------------------------
// Test
diff --git a/package-lock.json b/package-lock.json
index 256ff65..25e5127 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1,12 +1,12 @@
{
"name": "@sinclair/typemap",
- "version": "0.8.3",
+ "version": "0.8.4",
"lockfileVersion": 2,
"requires": true,
"packages": {
"": {
"name": "@sinclair/typemap",
- "version": "0.8.3",
+ "version": "0.8.4",
"license": "MIT",
"devDependencies": {
"@arethetypeswrong/cli": "^0.17.2",
diff --git a/package.json b/package.json
index c999314..dc3a57a 100644
--- a/package.json
+++ b/package.json
@@ -1,7 +1,7 @@
{
"name": "@sinclair/typemap",
- "version": "0.8.3",
- "description": "Uniform Syntax, Mapping and Compiler Library for TypeBox, Valibot and Zod",
+ "version": "0.8.4",
+ "description": "Unified Syntax and Type Compiler for Runtime Type Systems",
"author": "sinclairzx81",
"license": "MIT",
"repository": {
diff --git a/readme.md b/readme.md
index b62ce61..1acc79d 100644
--- a/readme.md
+++ b/readme.md
@@ -2,9 +2,9 @@
TypeMap
-Uniform Syntax, Mapping and Compiler Library for TypeBox, Valibot and Zod
+Unified Syntax and Type Compiler for Runtime Type Systems
-
+
@@ -22,16 +22,62 @@
$ npm install @sinclair/typemap --save
```
+## Usage
+
+Create and Compile Runtime Types using TypeScript syntax.
+
+```typescript
+import { Zod, Compile } from '@sinclair/typemap'
+
+const T = Zod(`string`) // ZodString
+
+const R = Compile(T).Check('Hello from TypeMap')
+```
+
+## Overview
+
+TypeMap is a syntax frontend and compiler backend for the [TypeBox](https://github.com/sinclairzx81/typebox), [Valibot](https://github.com/fabian-hiller/valibot) and [Zod](https://github.com/colinhacks/zod) type libraries. It provides a uniform syntax for creating types, a runtime compiler for high-performance validation and enables types written in one library to be transformed to another.
+
+TypeMap is built as an advanced adapter system for the TypeBox project. It enables Valibot and Zod to be integrated on TypeBox validation infrastructure as well as enabling TypeBox to be integrated on Zod infrastructure via reverse type mapping.
+
+License: MIT
+
+
+
+## Contents
+
+- [Install](#Install)
+- [Usage](#Usage)
+- [Overview](#Overview)
+- [Example](#Example)
+- [Libraries](#Libraries)
+ - [TypeBox](#TypeBox)
+ - [Valibot](#Valibot)
+ - [Zod](#Zod)
+- [Syntax](#Syntax)
+ - [Types](#Types)
+ - [Options](#Options)
+ - [Parameters](#Parameters)
+ - [Generics](#Generics)
+- [Static](#Static)
+- [Compile](#Compile)
+- [Benchmark](#Benchmark)
+- [Contribute](#Contribute)
+
## Example
-Use TypeScript syntax to construct types for TypeBox, Valibot and Zod ...
+Construct types for TypeBox, Valibot and Zod using a common TypeScript syntax
-[Example Link](https://www.typescriptlang.org/play/?moduleResolution=99&module=199#code/JYWwDg9gTgLgBAbzgFQJ5gKYCEIA8A0cAagIYA2wARhDIQFoQAmcAvnAGZQQhwDkAAgGdgAOwDGZEsCgB6GOgwgSYXgChVMmSgUBlMVGBh4O1CJglc2zOrEQRg43AC8cAAYJVcOLgBccEQCuIJQYUPiecKh+gcGh4V4AXtFBIVCqLK7qmnAAwnYOUAFi8AAyVFAkUKhWGIIcXDwmZhY2+fDIzjU4uAAUOgCUXkPDI6NjI9m29u1+yADylABWGMUAPB7jm1vbO17ZXr4oAHIpcRG7F5fj+5GzJ7Fh51fPVzdJx6dpL9+X2SwAfK1psROqQKNQYH1Bj9tpM2sQ-AtlsU9AALRQkdZPGE4iZaA5+e6pNEY1ZYEiCDAAUSgXCg-3iuKZwxuUTgRNCJKUZIp1Np0AZ2OZOLehM+XMx5MpNLpgOFwr+hAAdCrAUCHHA6J0GIwofLNnDgXQ-DqkSsYFj9UybocdRzHlbcayTUx7YzHT9RZrXZ8hR7floWMrVX7nhotAAFSqUuBNcyWAA+cCjUBjaEwcHV8AAStqmFClWBoxgerwVUreNCYYaNdm-Bt-d8bckHgBuUON2H427+T7tzsvL0xVL9gevQNAA)
+[Example Link](https://www.typescriptlang.org/play/?moduleResolution=99&module=199#code/JYWwDg9gTgLgBAbzgFQJ5gKYCEIA8A0cAagIYA2wARhDIQFoQAmcAvnAGZQQhwDkAAgGdgAOwDGZEsCgB6GOgwgSYXgChVMmXAAKJKIIxwAyqhEwSuOAB8deg8XIBXQ+rEQRg+ACU4AXjgMjAAUvJ5QogDm1nAijiCUGFC8AJQAdGB2GCGpOSlw+QVwmnBuHt4AXHBhkdGx8YnqxQDC3CDuxqbmlmiYcF4YYFAYBmYkMMDuru6exn5wAAYIqvm4lXUJUPjLcKhrcRtb+QBee-VQqizzU2Uocz3YeEFGyYWvb+8f+cWlM8iVyAB5SgAKwwYhgAB4lp8YbC4TDiit-gA5faJQ7wzFYz6InYotGbbbY4nE3EnFCos5Ekk0uHFFgAPmuMyIc1IFGoMCeL1psO+03gREqQNB4KMYgAFooSFDqbz5a9cas4JSNuKpUoITlUgyMQr9QVcbsVQT1dKtTldXKDfKyZVVYkzZrtUybTb6YQXepVD94HQ5oFuW6cVpfQFKoERWDIdDgwqlRGmA7CXH41p8sbAsm9amaXaAkmCdbc1iPXAXUA)
```typescript
import { TypeBox, Valibot, Zod } from '@sinclair/typemap'
-// TypeScript Syntax Type
+// Parse Syntax | Parse Value
+
+const R = Zod('string | number').parse('...') // const R: string | number
+
+// Common Syntax Type Representation
const S = `{
x: number,
@@ -39,8 +85,6 @@ const S = `{
z: number
}`
-// Construct Library Types from Syntax
-
const T = TypeBox(S) // const T: TObject<{
// x: TNumber,
// y: TNumber,
@@ -59,80 +103,55 @@ const Z = Zod(S) // const Z: ZodObject<{
// y: ZodNumber,
// z: ZodNumber
// }, ...>
-
-// Parse Syntax | Parse Value
-
-const R = Zod('string | number').parse('...') // const R: string | number
```
-... or structurally remap types from one library to another
+Transform types between TypeBox, Valibot and Zod
-[Example Link](https://www.typescriptlang.org/play/?moduleResolution=99&module=199#code/JYWwDg9gTgLgBAbzgFQJ5gKYCEIA8A0cAagIYA2wARhDIQFoQAmcAvnAGZQQhwDkAAgGdgAOwDGZEsCgB6GOgwgSYXgChVMmXADKqETBK44APjgNmp0hWrxTaTDlzqxEEYPjI4AXhQLHACisqGn9zfwADBFU4OFwALjgRAFcQSgwofGi4VATk1PTMmIAvXJS0qFUWcIBKWqA)
+[Example Link](https://www.typescriptlang.org/play/?moduleResolution=99&module=199#code/JYWwDg9gTgLgBAbzgFQJ5gKYCEIA8A0cAagIYA2wARhDIQFoQAmcAvnAGZQQhwDkAAgGdgAOwDGZEsCgB6GOgwgSYXgChVYiCMHwAUoK0BlMQAtFJOAF4UCnLgAUpCtRj2GjewAMEquHFwAXHAiAK4glBhQ+L5wqEGh4ZHRfgBe8WERUKosngCU+UA)
```typescript
import { TypeBox, Valibot, Zod } from '@sinclair/typemap'
-// Syntax > Zod > Valibot > TypeBox
-
-const T = TypeBox(Valibot(Zod(`{
+const JsonSchema = TypeBox(Valibot(Zod(`{
x: number,
y: number,
z: number
}`)))
```
-... or compile types for high performance runtime type checking
+Compile Zod and Valibot on TypeBox validation infrastructure
-[Example Link](https://www.typescriptlang.org/play/?moduleResolution=99&module=199#code/JYWwDg9gTgLgBAbzgYQuYAbApnAvnAMyjTgHIABAZ2ADsBjDAQ2CgHoYBPMLERsUgFADQkWHABehYiDLiIAE0EC6EGpXgAVOAF4JAOggAjAFZY6MABRI4N23butWcFWs0AufQC0FAeRNmYAB4kARsADw9xPRoAVxBDLCgLAEoAGnsMzLhHWwivBQA5OISoVNC4Dkjo4sSU9KyG7KcbSvz5IvjEsptxKtjOpLTGhpyequ92mtKBXGTh+cac3AA+IRd1FB0UNDBMLAsNOYWm51UN5A8ANUYMYHlGGGhAjT9Tc2Dy46+HZrg8jQ6JW63xBJxaHgBU2BoK+owkEMBiU+MIWS2Wy1sazO8AASltkHpkAALMwAays3xy61xHkMEAg2EYNDgAFo4AAJYAAcyJcAACokCNBePQcMSybQuQBCcp5ACMwNaACZ0uVenAAMwzZJAA)
+[Example Link](https://www.typescriptlang.org/play/?moduleResolution=99&module=199&ssl=17&ssc=3&pln=1&pc=1#code/JYWwDg9gTgLgBAbzgYQuYAbApnAvnAMyjTgHIABAZ2ADsBjDAQ2CgHoYBPMLERsUgFADQkWHABehYiDLiIAE0EDWrFGjCYcALQVwAKlyxC6EGpXjI4AXjXpsACnEA6CACMAVljox7SOP4DAoOCAlTgTMwsALjgANUYMYHlGGGgAHj0AeQ8vGDS-AX8ADxjnGgBXEFcsKHsASgAaEOaW1tDVYpi9ADlK6qgmwMK4DlKnCqqa+sG22dmw-1H9XsmB4fExif7pud3WhYkulf6BXDq6vcur-zDcAD47gOHr3YEI8zgAJWsUJ2QACy8AGtfC89mEAJIwGopYCmSgxACMAAYAPrIjHojHDEpwREzMGEm6sYZLABMBKJYLCOnkzRiABYMciQJQ4PY+GBiEU6usYgBmKlCsIGbgAWT4gUZLLZ-g5YC5EB5pzqQA)
```typescript
import { Compile } from '@sinclair/typemap'
import z from 'zod'
-const T = Compile(z.object({ // const T: Validator>
-const R = T.Check({ // High Performance Check
- x: 1,
- y: 2,
- z: 3
+const R = C.Check({ // Iterations: 10_000_000
+ x: 1, //
+ y: 2, // Zod : 4000ms (approx)
+ z: 3 // TypeMap : 40ms (approx)
})
```
-
-
-## Overview
-
-TypeMap is a type mapping library developed for the [TypeBox](https://github.com/sinclairzx81/typebox), [Valibot](https://github.com/fabian-hiller/valibot) and [Zod](https://github.com/colinhacks/zod) runtime type libraries. It is designed to make these libraries cross compatible by structurally remapping types from one library to another. TypeMap also provides a uniform frontend syntax for creating types, as well as uniform type compilation for high-performance validation via the TypeBox compiler infrastructure.
-
-TypeMap is built to be a simple tool to let Valibot and Zod to integrate with TypeBox and Json Schema infrastructure. It is also written to enable TypeBox to integrate with systems using Valibot and Zod for validation.
-
-License: MIT
-
-## Contents
-
-- [Install](#Install)
-- [Overview](#Overview)
-- [Libraries](#Libraries)
- - [TypeBox](#TypeBox)
- - [Valibot](#Valibot)
- - [Zod](#Zod)
-- [Static](#Static)
-- [Compile](#Compile)
-- [Benchmark](#Benchmark)
-- [Contribute](#Contribute)
-
## Libraries
-TypeMap exports mapping functions named after the library they map for. Each function can accept a type from any other library, where the function will attempt to map the type or return a `never` representation if a mapping is not possible.
+TypeMap, at its core, is a runtime type mapping library. It is specifically designed to transform types from one library into types for another.
+
+TypeMap performs deep type mapping both statically (within the type system) and at runtime. As a rule, if a type cannot be mapped during traversal, the library function returns a never representation specific to the library being mapped for.
### TypeBox
-Use the TypeBox function to map the parameter into a TypeBox type
+Use the TypeBox function to map a parameter into a TypeBox type.
```typescript
import { TypeBox } from '@sinclair/typemap'
@@ -169,9 +188,90 @@ const C = Zod(z.boolean()) // const C: z.ZodBoolean (Zod)
const D = Zod('string[]') // const D: z.ZodArray<...> (Syntax)
```
+## Syntax
+
+TypeMap provides an optional syntax that can be used to construct runtime type representations. Syntax mapping is based on [Syntax Type](https://github.com/sinclairzx81/typebox?#syntax) provided by TypeBox.
+
+### Types
+
+Pass a constant string parameter with an embedded TypeScript type annotion to construct a type. If there is a syntax error, the function return type will be `never`.
+
+[Example Link](https://www.typescriptlang.org/play/?moduleResolution=99&module=199#code/JYWwDg9gTgLgBAbzgLQgEzgXzgMyhEOAcgAEBnYAOwGMAbAQ2CgHoYBPMAUxHrCICh+zZnADCUTvRic49FOjjsusyhgAK9KGRnAYg6hEpl4EsgFda8ALzy0ACiJIAHgC44ARixEAlADowmtp2zm6emN5AA)
+
+```typescript
+import { Zod } from '@sinclair/typemap'
+
+// Create a Zod type and Parse it
+
+const result = Zod('{ x: 1 }').parse({ x: 1 })
+```
+
+### Options
+
+Options can be passed on the last parameter of a syntax type. TypeMap understands Json Schema keyword constraints. Known constraints will be mapped to analogs structures for the target library if possible.
+
+```typescript
+import { Zod } from '@sinclair/typemap'
+
+// const T = z.string().email()
+
+const T = Zod('string', {
+ format: 'email'
+})
+
+// const S = z.object({ x: z.number() }).strict()
+
+const S = Zod('{ x: number }', {
+ additionalProperties: false
+})
+
+```
+
+### Parameters
+
+Syntax types can be parameterized to accept exterior types. The following injects a Zod type into a Valibot vector structure.
+
+[Example Link](https://www.typescriptlang.org/play/?moduleResolution=99&module=199#code/JYWwDg9gTgLgBAbzgNQIYBtgCMIwDRwBaEAJnAL5wBmUEIcA5AAIDOwAdgMbqrBQD0MAJ5gApiFRgGAKGn9+cAMIR2LGFACuneABVZnFWrg64AXiKkAFA3YaQWUVAYBKWfLgAFVCxbG4MCDgAZX1DeCCzFAxsXEskE3ICAAMkAA8ALmMCIUydAgAvXIok5yA)
+
+```typescript
+import { Valibot, Zod } from '@sinclair/typemap'
+
+// Construct T
+
+const T = Zod('number')
+
+// Pass T to S
+
+const S = Valibot({ T }, `{ x: T, y: T, z: T }`)
+```
+
+### Generics
+
+Using type parameters, you can construct generic via functions.
+
+[Example Link](https://www.typescriptlang.org/play/?moduleResolution=99&module=199#code/JYWwDg9gTgLgBAbzgFQJ5gKYCEIA8A0cAagIYA2wARhDIQFoQAmcAvnAGZQQhwDkAAgGdgAOwDGZEsCgB6GOgwgSYXgChVMmXADiGERijAxxDGJjQUCuAB84AMQCu4mMAgj1Yt4PhFT5qHAAvHAAPMhwGLgweoyCcBCUAFZ+AHwAFMgAXCgAlEEpxORUNGlI4SyEqnBwAAZIuNnIhKiNhABejaw1qjnqmnAAcg4glAYmZhZomB5e8EMjBr4TAcFL-hkKOLhpvCLDo1C8Ob0aWgDKMIYiAObj-pbTqp4i3nAXV9drFqt+0GkMjB23g+RxyQA)
+
+```typescript
+import { TypeBox, Valibot, Zod } from '@sinclair/typemap'
+
+// Generic Vector Type | Function
+
+const Vector = (T: T) => Valibot({ T },
+ `{ x: T, y: T, z: T }`
+)
+
+// Number Vector Type
+
+const NumberVector = Vector(TypeBox('number'))
+
+// String Vector Type
+
+const StringVector = Vector(Zod('string'))
+```
+
## Static
-TypeMap can statically infer for TypeBox, Valibot, Zod and Syntax with the `Static` type.
+Use Static to uniformly infer for syntax and library types
```typescript
import { type Static } from '@sinclair/typemap'
@@ -189,32 +289,33 @@ type S = Static // string[]
## Compile
-TypeMap offers JIT compilation of TypeBox, Valibot, Zod and Syntax using the `Compile` function. This function will internally use the TypeBox TypeCompiler for high performance checking. This function will also gracefully degrade to dynamic checking if the runtime does not support JavaScript evaluation.
-
-The `Compile` function returns a validator object that implements the [standard-schema](https://github.com/standard-schema/standard-schema) interface.
+Use the Compile function to compile Zod and Valibot on TypeBox validation infrastructure.
```typescript
-import { Compile } from '@sinclair/typemap'
+import { Compile, Zod } from '@sinclair/typemap'
-// Pass TypeBox, Valibot, Zod or Syntax to JIT Compile the type.
-const V = Compile(`{
- x: number
- y: number,
- z: number
-}`)
+// Compile Zod Type
+
+const V = Compile(Zod(`{
+ x: number,
+ y: number,
+ z: number
+}`))
+
+// TypeMap Check Function
-// TypeMap Interface
const R1 = V.Check({ x: 1, y: 2, z: 3 })
-// Standard Schema Interface
+// Standard Schema Interface Check Function
+
const R2 = V['~standard'].validate({ x: 1, y: 2, z: 3 })
```
## Benchmark
-This project manages a benchmark that evaluates type-check performance using Zod, Valibot, and TypeBox validators. The benchmark is set up to run 10 million check operations per library-validator pairing and reports the elapsed time taken to complete.
+This project manages a small benchmark that compares validation performance using Zod, Valibot, and TypeBox validators. For more comprehensive community benchmarks, refer to the [runtime-type-benchmarks](https://github.com/moltar/typescript-runtime-type-benchmarks) project.
-### Type
+### Test
Benchmarks are run for the following type.
@@ -224,7 +325,7 @@ type T = { x: number, y: string, z: boolean }
### Results
-Results show validate performance for the type.
+Results show the approximate elapsed time to complete the given iterations
```typescript
┌─────────┬────────────────┬────────────────────┬────────────┬────────────┐
@@ -243,9 +344,9 @@ Results show validate performance for the type.
└─────────┴────────────────┴────────────────────┴────────────┴────────────┘
```
-For community benchmarks, refer to the [runtime-type-benchmarks](https://github.com/moltar/typescript-runtime-type-benchmarks) project.
+
## Contribute
-This project is open to community contributions. Please ensure you submit an open issue before creating a pull request. TypeMap encourages open community discussion before accepting new features.
+This project is open to community contributions. Please ensure you submit an open issue before creating a pull request. TypeBox and associated projects preference open community discussion before accepting new features.
diff --git a/src/compile/compile.ts b/src/compile/compile.ts
index fd48672..892a54a 100644
--- a/src/compile/compile.ts
+++ b/src/compile/compile.ts
@@ -29,8 +29,8 @@ THE SOFTWARE.
import { TypeCompiler, TypeCheck, ValueErrorIterator } from '@sinclair/typebox/compiler'
import { Value } from '@sinclair/typebox/value'
import { TypeBox, TTypeBox } from '../typebox/typebox'
-import { StandardSchemaV1 } from './standard'
import { IsEvalSupported } from './environment'
+import { StandardSchemaV1 } from './standard'
import * as t from '@sinclair/typebox'
// ------------------------------------------------------------------
@@ -112,9 +112,8 @@ function CompileDynamic(type: Type, references: t.TSchem
/** Compiles a type for high performance validation */
// prettier-ignore
type TCompile,
- Result extends Validator = Validator
-> = Result
+ Schema extends t.TSchema = TTypeBox<{}, Type>,
+> = Validator
/** Compiles a type for high performance validation */
// prettier-ignore
export function Compile(type: Type): TCompile {
diff --git a/src/guard.ts b/src/guard.ts
index 8e62da1..059df32 100644
--- a/src/guard.ts
+++ b/src/guard.ts
@@ -30,20 +30,14 @@ import * as t from '@sinclair/typebox'
import * as v from 'valibot'
import * as z from 'zod'
-// ------------------------------------------------------------------
-// Syntax
-// ------------------------------------------------------------------
-/** Returns true if the given value is a Syntax type */
-export type TIsSyntax = Type extends string ? true : false
-/** Returns true if the given value is a Syntax type */
-export function IsSyntax(type: unknown): type is string {
- return t.ValueGuard.IsString(type)
-}
// ------------------------------------------------------------------
// TypeBox
// ------------------------------------------------------------------
/** Returns true if the given value is a TypeBox type */
-export type TIsTypeBox = Type extends t.TSchema ? true : false
+// prettier-ignore
+export type TIsTypeBox = (
+ Type extends t.TSchema ? true : false
+)
/** Returns true if the given value is a TypeBox type */
export function IsTypeBox(type: unknown): type is t.TSchema {
return t.KindGuard.IsSchema(type)
@@ -74,12 +68,44 @@ export function IsValibot(type: unknown): type is v.AnySchema {
// ------------------------------------------------------------------
// Zod
// ------------------------------------------------------------------
-// prettier-ignore
/** Returns true if the given value is a Zod type */
+// prettier-ignore
export type TIsZod = (
Type extends z.ZodTypeAny ? true : false
)
/** Returns true if the given value is a Zod type */
+// prettier-ignore
export function IsZod(type: unknown): type is z.ZodTypeAny {
- return t.ValueGuard.IsObject(type) && t.ValueGuard.HasPropertyKey(type, '~standard') && t.ValueGuard.IsObject(type['~standard']) && t.ValueGuard.HasPropertyKey(type['~standard'], 'vendor') && type['~standard'].vendor === 'zod'
+ return (
+ t.ValueGuard.IsObject(type) &&
+ t.ValueGuard.HasPropertyKey(type, '~standard') &&
+ t.ValueGuard.IsObject(type['~standard']) &&
+ t.ValueGuard.HasPropertyKey(type['~standard'], 'vendor') &&
+ type['~standard'].vendor === 'zod'
+ )
}
+// ------------------------------------------------------------------
+// Signature
+// ------------------------------------------------------------------
+function Signature1(args: any[]) {
+ return args.length === 3 && t.ValueGuard.IsObject(args[0]) && t.ValueGuard.IsString(args[1]) && t.ValueGuard.IsObject(args[2])
+}
+function Signature2(args: any[]) {
+ return args.length === 2 && t.ValueGuard.IsString(args[0]) && t.ValueGuard.IsObject(args[1])
+}
+function Signature3(args: any[]) {
+ return args.length === 2 && t.ValueGuard.IsObject(args[0]) && t.ValueGuard.IsString(args[1])
+}
+function Signature4(args: any[]) {
+ return args.length === 1 && (t.ValueGuard.IsString(args[0]) || t.ValueGuard.IsObject(args[0]))
+}
+export function Signature(args: any[]): [parameter: Record, type: string | object, options: object] {
+ // prettier-ignore
+ return (
+ Signature1(args) ? [args[0], args[1], args[2]] :
+ Signature2(args) ? [{}, args[0], args[1]] :
+ Signature3(args) ? [args[0], args[1], {}] :
+ Signature4(args) ? [{}, args[0], {}] :
+ [{}, 'never', {}]
+ )
+}
\ No newline at end of file
diff --git a/src/index.ts b/src/index.ts
index feff60e..95662ca 100644
--- a/src/index.ts
+++ b/src/index.ts
@@ -27,6 +27,7 @@ THE SOFTWARE.
---------------------------------------------------------------------------*/
export { type Static } from './static'
+export { type TSyntaxOptions } from './options'
export * from './compile/compile'
export * from './typebox/typebox'
export * from './valibot/valibot'
diff --git a/src/options.ts b/src/options.ts
new file mode 100644
index 0000000..362f085
--- /dev/null
+++ b/src/options.ts
@@ -0,0 +1,40 @@
+/*--------------------------------------------------------------------------
+
+@sinclair/typemap
+
+The MIT License (MIT)
+
+Copyright (c) 2024-2025 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 t from '@sinclair/typebox'
+
+/** Syntax Options and Constraints */
+// prettier-ignore
+export type TSyntaxOptions = (
+ t.ObjectOptions
+ & t.ArrayOptions
+ & t.NumberOptions
+ & t.IntegerOptions
+ & t.StringOptions
+ & t.DateOptions
+)
diff --git a/src/typebox/typebox-from-syntax.ts b/src/typebox/typebox-from-syntax.ts
index 122b7fd..4c964cf 100644
--- a/src/typebox/typebox-from-syntax.ts
+++ b/src/typebox/typebox-from-syntax.ts
@@ -29,16 +29,18 @@ THE SOFTWARE.
import { StaticParseAsSchema, Parse } from '@sinclair/typebox/syntax'
import * as t from '@sinclair/typebox'
+// ------------------------------------------------------------------
+// TypeBoxFromSyntax
+// ------------------------------------------------------------------
// prettier-ignore
-export type TTypeBoxFromSyntax<
- Type extends string | object,
- Parsed = Type extends string ? StaticParseAsSchema<{}, Type> : t.TNever,
- Result extends t.TSchema = Parsed extends t.TSchema ? Parsed : t.TNever
+export type TTypeBoxFromSyntax : t.TNever,
+ Result extends t.TSchema = Mapped extends t.TSchema ? Mapped : t.TNever
> = Result
-// prettier-ignore
-export function TypeBoxFromSyntax(type: Type): TTypeBoxFromSyntax {
- const parsed = t.ValueGuard.IsString(type) ? Parse(type) : t.Never()
+/** Creates a TypeBox Type From Syntax */
+export function TypeBoxFromSyntax(context: Context, type: Type, options?: t.SchemaOptions): TTypeBoxFromSyntax {
+ const parsed = t.ValueGuard.IsString(type) ? Parse(context, type, options) : t.Never()
const result = t.KindGuard.IsSchema(parsed) ? parsed : t.Never()
return result as never
}
diff --git a/src/typebox/typebox.ts b/src/typebox/typebox.ts
index ac387aa..1e1626e 100644
--- a/src/typebox/typebox.ts
+++ b/src/typebox/typebox.ts
@@ -26,39 +26,77 @@ THE SOFTWARE.
---------------------------------------------------------------------------*/
-import { TTypeBoxFromSyntax, TypeBoxFromSyntax } from './typebox-from-syntax'
-import { TTypeBoxFromTypeBox, TypeBoxFromTypeBox } from './typebox-from-typebox'
-import { TTypeBoxFromValibot, TypeBoxFromValibot } from './typebox-from-valibot'
-import { TTypeBoxFromZod, TypeBoxFromZod } from './typebox-from-zod'
-import * as Guard from '../guard'
+import { type TTypeBoxFromSyntax, TypeBoxFromSyntax } from './typebox-from-syntax'
+import { type TTypeBoxFromTypeBox, TypeBoxFromTypeBox } from './typebox-from-typebox'
+import { type TTypeBoxFromValibot, TypeBoxFromValibot } from './typebox-from-valibot'
+import { type TTypeBoxFromZod, TypeBoxFromZod } from './typebox-from-zod'
+import { type TSyntaxOptions } from '../options'
+import * as g from '../guard'
import * as t from '@sinclair/typebox'
+// ------------------------------------------------------------------------------
+//
+// TParameter: Shared
+//
+// TypeBox supports Type injection via a Context parameter. Because the Context
+// only accepts types of TSchema, we need to an intermediate structure to hold
+// remote types such that they can be mapped prior to syntax parsing.
+//
+// -------------------------------------------------------------------------------
+export type TParameter = Record
+
+// ------------------------------------------------------------------
+// ContextFromParameter
+// ------------------------------------------------------------------
+// prettier-ignore
+export type TContextFromParameter
+ }
+> = Result
+// prettier-ignore
+export function ContextFromParameter(parameter: Parameter): TContextFromParameter {
+ return globalThis.Object.getOwnPropertyNames(parameter).reduce((result, key) => {
+ return { ...result, [key]: TypeBox(parameter[key] as never) }
+ }, {} as t.TProperties) as never
+}
+
+// ------------------------------------------------------------------
+// TypeBox
+// ------------------------------------------------------------------
/** Creates a TypeBox type from Syntax or another Type */
// prettier-ignore
-export type TTypeBox extends true ? TTypeBoxFromSyntax :
- Guard.TIsTypeBox extends true ? TTypeBoxFromTypeBox :
- Guard.TIsValibot extends true ? TTypeBoxFromValibot :
- Guard.TIsZod extends true ? TTypeBoxFromZod :
+export type TTypeBox, Type> :
+ g.TIsTypeBox extends true ? TTypeBoxFromTypeBox :
+ g.TIsValibot extends true ? TTypeBoxFromValibot :
+ g.TIsZod extends true ? TTypeBoxFromZod :
t.TNever
)> = Result
-
+/** Creates a TypeBox type from Syntax or another Type */
+export function TypeBox(parameter: Parameter, type: Type, options?: TSyntaxOptions): TTypeBox
+/** Creates a TypeBox type from Syntax or another Type */
+export function TypeBox(type: Type, options?: TSyntaxOptions): TTypeBox<{}, Type>
/** Creates a TypeBox type from Syntax or another Type */
// prettier-ignore
-export function TypeBox(type: Type): TTypeBox {
- return (
- Guard.IsSyntax(type) ? TypeBoxFromSyntax(type) :
- Guard.IsTypeBox(type) ? TypeBoxFromTypeBox(type) :
- Guard.IsValibot(type) ? TypeBoxFromValibot(type) :
- Guard.IsZod(type) ? TypeBoxFromZod(type) :
- t.Never()
- ) as never
+export function TypeBox(...args: any[]): never {
+ const [parameter, type, options] = g.Signature(args)
+ return t.CloneType(
+ t.ValueGuard.IsString(type) ? TypeBoxFromSyntax(ContextFromParameter(parameter), type, options) :
+ g.IsTypeBox(type) ? TypeBoxFromTypeBox(type) :
+ g.IsValibot(type) ? TypeBoxFromValibot(type) :
+ g.IsZod(type) ? TypeBoxFromZod(type) :
+ t.Never(),
+ options) as never
}
-/**
- * Creates a TypeBox type from Syntax or another Type
- * @deprecated Use TypeBox() export instead
- */
-export function Box, Result extends Mapped = Mapped>(type: Type): Result {
- return TypeBox(type) as never
-}
+
+/** Creates a TypeBox type from Syntax or another Type */
+export function Type(parameter: Parameter, type: Type, options?: TSyntaxOptions): TTypeBox
+/** Creates a TypeBox type from Syntax or another Type */
+export function Type(type: Type, options?: TSyntaxOptions): TTypeBox<{}, Type>
+/** Creates a TypeBox type from Syntax or another Type */
+// prettier-ignore
+export function Type(...args: any[]): never {
+ return TypeBox.apply(null, args as never) as never
+}
\ No newline at end of file
diff --git a/src/valibot/valibot-from-syntax.ts b/src/valibot/valibot-from-syntax.ts
index 185cfa9..bc37fb6 100644
--- a/src/valibot/valibot-from-syntax.ts
+++ b/src/valibot/valibot-from-syntax.ts
@@ -32,15 +32,18 @@ import { ValibotFromTypeBox, TValibotFromTypeBox } from './valibot-from-typebox'
import * as t from '@sinclair/typebox'
import * as c from './common'
+// ------------------------------------------------------------------
+// ValibotFromSyntax
+// ------------------------------------------------------------------
// prettier-ignore
-export type TValibotFromSyntax,
+export type TValibotFromSyntax,
Result extends c.BaseSchema = TValibotFromTypeBox
> = Result
// prettier-ignore
-export function ValibotFromSyntax(type: Type): TValibotFromSyntax {
- const schema = TypeBoxFromSyntax(type)
+export function ValibotFromSyntax(context: Context, type: Type, options?: t.SchemaOptions): TValibotFromSyntax {
+ const schema = TypeBoxFromSyntax(context, type, options)
const result = ValibotFromTypeBox(schema)
- return result
+ return result as never
}
diff --git a/src/valibot/valibot.ts b/src/valibot/valibot.ts
index f780c85..5430226 100644
--- a/src/valibot/valibot.ts
+++ b/src/valibot/valibot.ts
@@ -30,27 +30,42 @@ import { type TValibotFromSyntax, ValibotFromSyntax } from './valibot-from-synta
import { type TValibotFromTypeBox, ValibotFromTypeBox } from './valibot-from-typebox'
import { type TValibotFromValibot, ValibotFromValibot } from './valibot-from-valibot'
import { type TValibotFromZod, ValibotFromZod } from './valibot-from-zod'
-import * as Guard from '../guard'
+import { type TSyntaxOptions } from '../options'
+import * as g from '../guard'
+import * as t from '@sinclair/typebox'
import * as v from 'valibot'
import * as c from './common'
+import { TParameter, TContextFromParameter, ContextFromParameter } from '../typebox/typebox'
+
+// ------------------------------------------------------------------
+// Valibot
+// ------------------------------------------------------------------
/** Creates a Valibot type from Syntax or another Type */
// prettier-ignore
-export type TValibot extends true ? TValibotFromSyntax :
- Guard.TIsTypeBox extends true ? TValibotFromTypeBox :
- Guard.TIsValibot extends true ? TValibotFromValibot :
- Guard.TIsZod extends true ? TValibotFromZod :
+export type TValibot, Type> :
+ g.TIsTypeBox extends true ? TValibotFromTypeBox :
+ g.TIsValibot extends true ? TValibotFromValibot :
+ g.TIsZod extends true ? TValibotFromZod :
v.NeverSchema
)> = Result
+
+/** Creates a Valibot type from Syntax or another Type */
+export function Valibot(parameter: Parameter, type: Type, options?: TSyntaxOptions): TValibot
+/** Creates a Valibot type from Syntax or another Type */
+export function Valibot(type: Type, options?: TSyntaxOptions): TValibot<{}, Type>
+/** Creates a Valibot type from Syntax or another Type */
+export function Valibot(type: Type, options?: TSyntaxOptions): TValibot<{}, Type>
/** Creates a Valibot type from Syntax or another Type */
// prettier-ignore
-export function Valibot, Result extends Mapped = Mapped>(type: Type): Result {
+export function Valibot(...args: any[]): never {
+ const [parameter, type, options] = g.Signature(args)
return (
- Guard.IsSyntax(type) ? ValibotFromSyntax(type) :
- Guard.IsTypeBox(type) ? ValibotFromTypeBox(type) :
- Guard.IsValibot(type) ? ValibotFromValibot(type) :
- Guard.IsZod(type) ? ValibotFromZod(type as any) :
+ t.ValueGuard.IsString(type) ? ValibotFromSyntax(ContextFromParameter(parameter), type, options) :
+ g.IsTypeBox(type) ? ValibotFromTypeBox(type) :
+ g.IsValibot(type) ? ValibotFromValibot(type) :
+ g.IsZod(type) ? ValibotFromZod(type as any) :
v.never()
) as never
}
diff --git a/src/zod/zod-from-syntax.ts b/src/zod/zod-from-syntax.ts
index 42554d2..fc0aceb 100644
--- a/src/zod/zod-from-syntax.ts
+++ b/src/zod/zod-from-syntax.ts
@@ -31,15 +31,17 @@ import { ZodFromTypeBox, TZodFromTypeBox } from './zod-from-typebox'
import * as t from '@sinclair/typebox'
import * as z from 'zod'
+// ------------------------------------------------------------------
+// ZodFromSyntax
+// ------------------------------------------------------------------
// prettier-ignore
-export type TZodFromSyntax,
+export type TZodFromSyntax,
Result extends z.ZodTypeAny | z.ZodEffects = TZodFromTypeBox
> = Result
-// prettier-ignore
-export function ZodFromSyntax(type: Type): TZodFromSyntax {
- const schema = TypeBoxFromSyntax(type)
+export function ZodFromSyntax(context: Context, type: Type, options?: t.SchemaOptions): TZodFromSyntax {
+ const schema = TypeBoxFromSyntax(context, type, options)
const result = ZodFromTypeBox(schema)
- return result
+ return result as never
}
diff --git a/src/zod/zod.ts b/src/zod/zod.ts
index f8024e6..f6bb44b 100644
--- a/src/zod/zod.ts
+++ b/src/zod/zod.ts
@@ -30,27 +30,42 @@ import { type TZodFromSyntax, ZodFromSyntax } from './zod-from-syntax'
import { type TZodFromTypeBox, ZodFromTypeBox } from './zod-from-typebox'
import { type TZodFromValibot, ZodFromValibot } from './zod-from-valibot'
import { type TZodFromZod, ZodFromZod } from './zod-from-zod'
-import * as Guard from '../guard'
+import { type TSyntaxOptions } from '../options'
+
+import * as g from '../guard'
+import * as t from '@sinclair/typebox'
import * as z from 'zod'
+import { TParameter, TContextFromParameter, ContextFromParameter } from '../typebox/typebox'
+
+// ------------------------------------------------------------------
+// Zod
+// ------------------------------------------------------------------
/** Creates a Zod type from Syntax or another Type */
// prettier-ignore
-export type TZod extends true ? TZodFromSyntax :
- Guard.TIsTypeBox extends true ? TZodFromTypeBox :
- Guard.TIsValibot extends true ? TZodFromValibot :
- Guard.TIsZod extends true ? TZodFromZod :
+export type TZod, Type> :
+ g.TIsTypeBox extends true ? TZodFromTypeBox :
+ g.TIsValibot extends true ? TZodFromValibot :
+ g.TIsZod extends true ? TZodFromZod :
z.ZodNever
)> = Result
+/** Creates a Zod type from Syntax or another Type */
+export function Zod(parameter: Parameter, type: Type, options?: TSyntaxOptions): TZod
+/** Creates a Zod type from Syntax or another Type */
+export function Zod(type: Type, options?: TSyntaxOptions): TZod<{}, Type>
+/** Creates a Zod type from Syntax or another Type */
+export function Zod(type: Type, options?: TSyntaxOptions): TZod<{}, Type>
/** Creates a Zod type from Syntax or another Type */
// prettier-ignore
-export function Zod, Result extends Mapped = Mapped>(type: Type): Result {
+export function Zod(...args: any[]): never {
+ const [parameter, type, options] = g.Signature(args)
return (
- Guard.IsSyntax(type) ? ZodFromSyntax(type) :
- Guard.IsTypeBox(type) ? ZodFromTypeBox(type) :
- Guard.IsValibot(type) ? ZodFromValibot(type) :
- Guard.IsZod(type) ? ZodFromZod(type) :
+ t.ValueGuard.IsString(type) ? ZodFromSyntax(ContextFromParameter(parameter), type, options) :
+ g.IsTypeBox(type) ? ZodFromTypeBox(type) :
+ g.IsValibot(type) ? ZodFromValibot(type) :
+ g.IsZod(type) ? ZodFromZod(type) :
z.never()
) as never
}
diff --git a/test/index.ts b/test/index.ts
index aea66b0..58b4c2c 100644
--- a/test/index.ts
+++ b/test/index.ts
@@ -1,3 +1,5 @@
+import './options'
+import './parameters'
import './typebox-from-zod'
import './typebox-from-valibot'
import './valibot-from-typebox'
diff --git a/test/options.ts b/test/options.ts
new file mode 100644
index 0000000..69ad6a9
--- /dev/null
+++ b/test/options.ts
@@ -0,0 +1,17 @@
+import { Assert } from './assert'
+import { TypeBox, Valibot, Zod } from '@sinclair/typemap'
+
+describe('SyntaxOptions', () => {
+ it('Should map Options (Zod)', () => {
+ const A = TypeBox('string', { minLength: 10 })
+ const B = Zod(A)
+ const C = TypeBox(B)
+ Assert.IsEqual(C.minLength, 10)
+ })
+ it('Should map Options (Valibot)', () => {
+ const A = TypeBox('string', { minLength: 10 })
+ const B = Valibot(A)
+ const C = TypeBox(B)
+ Assert.IsEqual(C.minLength, 10)
+ })
+})
diff --git a/test/parameters.ts b/test/parameters.ts
new file mode 100644
index 0000000..5d47575
--- /dev/null
+++ b/test/parameters.ts
@@ -0,0 +1,32 @@
+import { Assert } from './assert'
+import { TypeBox, Valibot, Zod } from '@sinclair/typemap'
+import { KindGuard } from '@sinclair/typebox'
+
+describe('Parameters', () => {
+ it('Should map Parameters (Zod)', () => {
+ const A = TypeBox('string')
+ const B = Zod({ A }, 'A')
+ const C = TypeBox(B)
+ Assert.IsTrue(KindGuard.IsString(C))
+ })
+ it('Should map Parameters (Valibot)', () => {
+ const A = TypeBox('string')
+ const B = Valibot({ A }, 'A')
+ const C = TypeBox(B)
+ Assert.IsTrue(KindGuard.IsString(C))
+ })
+ it('Should map Parameters With Constraints (Zod)', () => {
+ const A = TypeBox('string', { minLength: 10 })
+ const B = Zod({ A }, 'A')
+ const C = TypeBox(B)
+ Assert.IsTrue(KindGuard.IsString(C))
+ Assert.IsEqual(C.minLength, 10)
+ })
+ it('Should map Parameters With Constraints (Valibot)', () => {
+ const A = TypeBox('string', { minLength: 10 })
+ const B = Valibot({ A }, 'A')
+ const C = TypeBox(B)
+ Assert.IsTrue(KindGuard.IsString(C))
+ Assert.IsEqual(C.minLength, 10)
+ })
+})
diff --git a/typemap.png b/typemap.png
index 530bcd4..0f3ac28 100644
Binary files a/typemap.png and b/typemap.png differ