Revision 0.8.8 (#18)

* Reverse Syntax Mapping

* Minor Optimizations

* Documentation
This commit is contained in:
sinclairzx81
2025-02-01 03:16:00 +09:00
committed by GitHub
parent 6af5fde768
commit b6d6ac7e8b
29 changed files with 753 additions and 232 deletions

6
.vscode/settings.json vendored Normal file
View File

@@ -0,0 +1,6 @@
{
"files.exclude": {
"node_modules": true,
"package-lock.json": true
}
}

View File

@@ -1,9 +1,5 @@
import { TypeBox, Valibot, Zod } from '@sinclair/typemap'
// Parse Syntax | Parse Value
const R = Zod('string | number').parse('...') // const R: string | number
// Syntax Type
const S = `{

76
package-lock.json generated
View File

@@ -1,12 +1,12 @@
{
"name": "@sinclair/typemap",
"version": "0.8.7",
"version": "0.8.8",
"lockfileVersion": 2,
"requires": true,
"packages": {
"": {
"name": "@sinclair/typemap",
"version": "0.8.7",
"version": "0.8.8",
"license": "MIT",
"devDependencies": {
"@arethetypeswrong/cli": "^0.17.2",
@@ -18,7 +18,7 @@
"typescript": "^5.7.2"
},
"peerDependencies": {
"@sinclair/typebox": "^0.34.14",
"@sinclair/typebox": "^0.34.15",
"valibot": "^1.0.0-beta.14",
"zod": "^3.24.1"
}
@@ -170,9 +170,9 @@
}
},
"node_modules/@sinclair/typebox": {
"version": "0.34.14",
"resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.34.14.tgz",
"integrity": "sha512-TJ7Al17j3+by5y2QkTLcF/oBVMbgXBhILVgi9PuwpxQVZZvGh5BFRzWbJPmZVNKpbRLjuMzFuRwR+tdFPqCkvA==",
"version": "0.34.15",
"resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.34.15.tgz",
"integrity": "sha512-xeIzl3h1Znn9w/LTITqpiwag0gXjA+ldi2ZkXIBxGEppGCW211Tza+eL6D4pKqs10bj5z2umBWk5WL6spQ2OCQ==",
"peer": true
},
"node_modules/@sindresorhus/is": {
@@ -194,9 +194,9 @@
"dev": true
},
"node_modules/@types/node": {
"version": "22.10.9",
"resolved": "https://registry.npmjs.org/@types/node/-/node-22.10.9.tgz",
"integrity": "sha512-Ir6hwgsKyNESl/gLOcEz3krR4CBGgliDqBQ2ma4wIhEx0w+xnoeTq3tdrNw15kU3SxogDjOgv9sqdtLW8mIHaw==",
"version": "22.12.0",
"resolved": "https://registry.npmjs.org/@types/node/-/node-22.12.0.tgz",
"integrity": "sha512-Fll2FZ1riMjNmlmJOdAyY5pUbkftXslB5DgEzlIuNaiWhXd00FhWxVC/r4yV/4wBb9JfImTu+jiSvXTkJ7F/gA==",
"dev": true,
"dependencies": {
"undici-types": "~6.20.0"
@@ -385,9 +385,9 @@
}
},
"node_modules/cjs-module-lexer": {
"version": "1.4.1",
"resolved": "https://registry.npmjs.org/cjs-module-lexer/-/cjs-module-lexer-1.4.1.tgz",
"integrity": "sha512-cuSVIHi9/9E/+821Qjdvngor+xpnlwnuwIyZOaLmHBVdXL+gP+I6QQB9VkO7RI77YIcTV+S1W9AreJ5eN63JBA==",
"version": "1.4.3",
"resolved": "https://registry.npmjs.org/cjs-module-lexer/-/cjs-module-lexer-1.4.3.tgz",
"integrity": "sha512-9z8TZaGM1pfswYeXrUpzPrkx8UnWYdhJclsiYMm6x/w5+nN+8Tf/LnAgfLGQCm59qAOxU8WwHEq2vNwF6i4j+Q==",
"dev": true
},
"node_modules/cli-highlight": {
@@ -1272,24 +1272,24 @@
}
},
"node_modules/marked-terminal": {
"version": "7.2.1",
"resolved": "https://registry.npmjs.org/marked-terminal/-/marked-terminal-7.2.1.tgz",
"integrity": "sha512-rQ1MoMFXZICWNsKMiiHwP/Z+92PLKskTPXj+e7uwXmuMPkNn7iTqC+IvDekVm1MPeC9wYQeLxeFaOvudRR/XbQ==",
"version": "7.3.0",
"resolved": "https://registry.npmjs.org/marked-terminal/-/marked-terminal-7.3.0.tgz",
"integrity": "sha512-t4rBvPsHc57uE/2nJOLmMbZCQ4tgAccAED3ngXQqW6g+TxA488JzJ+FK3lQkzBQOI1mRV/r/Kq+1ZlJ4D0owQw==",
"dev": true,
"dependencies": {
"ansi-escapes": "^7.0.0",
"ansi-regex": "^6.1.0",
"chalk": "^5.3.0",
"chalk": "^5.4.1",
"cli-highlight": "^2.1.11",
"cli-table3": "^0.6.5",
"node-emoji": "^2.1.3",
"node-emoji": "^2.2.0",
"supports-hyperlinks": "^3.1.0"
},
"engines": {
"node": ">=16.0.0"
},
"peerDependencies": {
"marked": ">=1 <15"
"marked": ">=1 <16"
}
},
"node_modules/marked-terminal/node_modules/chalk": {
@@ -1664,9 +1664,9 @@
]
},
"node_modules/semver": {
"version": "7.6.3",
"resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz",
"integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==",
"version": "7.7.0",
"resolved": "https://registry.npmjs.org/semver/-/semver-7.7.0.tgz",
"integrity": "sha512-DrfFnPzblFmNrIZzg5RzHegbiRWg7KMR7btwi2yjHwx06zsUbO5g613sVwEV7FTwmzJu+Io0lJe2GJ3LxqpvBQ==",
"dev": true,
"bin": {
"semver": "bin/semver.js"
@@ -2264,9 +2264,9 @@
}
},
"@sinclair/typebox": {
"version": "0.34.14",
"resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.34.14.tgz",
"integrity": "sha512-TJ7Al17j3+by5y2QkTLcF/oBVMbgXBhILVgi9PuwpxQVZZvGh5BFRzWbJPmZVNKpbRLjuMzFuRwR+tdFPqCkvA==",
"version": "0.34.15",
"resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.34.15.tgz",
"integrity": "sha512-xeIzl3h1Znn9w/LTITqpiwag0gXjA+ldi2ZkXIBxGEppGCW211Tza+eL6D4pKqs10bj5z2umBWk5WL6spQ2OCQ==",
"peer": true
},
"@sindresorhus/is": {
@@ -2282,9 +2282,9 @@
"dev": true
},
"@types/node": {
"version": "22.10.9",
"resolved": "https://registry.npmjs.org/@types/node/-/node-22.10.9.tgz",
"integrity": "sha512-Ir6hwgsKyNESl/gLOcEz3krR4CBGgliDqBQ2ma4wIhEx0w+xnoeTq3tdrNw15kU3SxogDjOgv9sqdtLW8mIHaw==",
"version": "22.12.0",
"resolved": "https://registry.npmjs.org/@types/node/-/node-22.12.0.tgz",
"integrity": "sha512-Fll2FZ1riMjNmlmJOdAyY5pUbkftXslB5DgEzlIuNaiWhXd00FhWxVC/r4yV/4wBb9JfImTu+jiSvXTkJ7F/gA==",
"dev": true,
"requires": {
"undici-types": "~6.20.0"
@@ -2417,9 +2417,9 @@
}
},
"cjs-module-lexer": {
"version": "1.4.1",
"resolved": "https://registry.npmjs.org/cjs-module-lexer/-/cjs-module-lexer-1.4.1.tgz",
"integrity": "sha512-cuSVIHi9/9E/+821Qjdvngor+xpnlwnuwIyZOaLmHBVdXL+gP+I6QQB9VkO7RI77YIcTV+S1W9AreJ5eN63JBA==",
"version": "1.4.3",
"resolved": "https://registry.npmjs.org/cjs-module-lexer/-/cjs-module-lexer-1.4.3.tgz",
"integrity": "sha512-9z8TZaGM1pfswYeXrUpzPrkx8UnWYdhJclsiYMm6x/w5+nN+8Tf/LnAgfLGQCm59qAOxU8WwHEq2vNwF6i4j+Q==",
"dev": true
},
"cli-highlight": {
@@ -2954,17 +2954,17 @@
"dev": true
},
"marked-terminal": {
"version": "7.2.1",
"resolved": "https://registry.npmjs.org/marked-terminal/-/marked-terminal-7.2.1.tgz",
"integrity": "sha512-rQ1MoMFXZICWNsKMiiHwP/Z+92PLKskTPXj+e7uwXmuMPkNn7iTqC+IvDekVm1MPeC9wYQeLxeFaOvudRR/XbQ==",
"version": "7.3.0",
"resolved": "https://registry.npmjs.org/marked-terminal/-/marked-terminal-7.3.0.tgz",
"integrity": "sha512-t4rBvPsHc57uE/2nJOLmMbZCQ4tgAccAED3ngXQqW6g+TxA488JzJ+FK3lQkzBQOI1mRV/r/Kq+1ZlJ4D0owQw==",
"dev": true,
"requires": {
"ansi-escapes": "^7.0.0",
"ansi-regex": "^6.1.0",
"chalk": "^5.3.0",
"chalk": "^5.4.1",
"cli-highlight": "^2.1.11",
"cli-table3": "^0.6.5",
"node-emoji": "^2.1.3",
"node-emoji": "^2.2.0",
"supports-hyperlinks": "^3.1.0"
},
"dependencies": {
@@ -3235,9 +3235,9 @@
"dev": true
},
"semver": {
"version": "7.6.3",
"resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz",
"integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==",
"version": "7.7.0",
"resolved": "https://registry.npmjs.org/semver/-/semver-7.7.0.tgz",
"integrity": "sha512-DrfFnPzblFmNrIZzg5RzHegbiRWg7KMR7btwi2yjHwx06zsUbO5g613sVwEV7FTwmzJu+Io0lJe2GJ3LxqpvBQ==",
"dev": true
},
"serialize-javascript": {

View File

@@ -1,7 +1,7 @@
{
"name": "@sinclair/typemap",
"version": "0.8.7",
"description": "Unified Syntax and Type Compiler for Runtime Types",
"version": "0.8.8",
"description": "Syntax, Compiler and Translation System for Runtime Types",
"author": "sinclairzx81",
"license": "MIT",
"repository": {
@@ -18,7 +18,7 @@
"publish": "hammer task publish"
},
"peerDependencies": {
"@sinclair/typebox": "^0.34.14",
"@sinclair/typebox": "^0.34.15",
"valibot": "^1.0.0-beta.14",
"zod": "^3.24.1"
},

View File

@@ -2,7 +2,7 @@
<h1>TypeMap</h1>
<p>Uniform Syntax, Compiler and Mapping for Runtime Types</p>
<p>Syntax, Compiler and Translation System for Runtime Types</p>
<img src="./typemap.png" />
@@ -29,13 +29,13 @@ Parse and Compile Types from TypeScript Syntax ([Example](https://www.typescript
```typescript
import { Compile } from '@sinclair/typemap'
const result = Compile('string | null').Parse('Hello TypeMap')
const result = Compile('string | null').Parse('Hello World')
// │ │ │
// │ │ └─── Parse Value
// │ │
// │ └── Ast: TUnion<[TString, TNull]>
// │ └── TUnion<[TString, TNull]>
// │
// └── const result: string | null = 'Hello TypeMap'
// └── const result: string | null = 'Hello World'
```
## Overview
@@ -53,6 +53,7 @@ License: MIT
- [Overview](#Overview)
- [Example](#Example)
- [Mapping](#Mapping)
- [Syntax](#Syntax)
- [TypeBox](#TypeBox)
- [Valibot](#Valibot)
- [Zod](#Zod)
@@ -61,7 +62,6 @@ License: MIT
- [Options](#Options)
- [Parameters](#Parameters)
- [Generics](#Generics)
- [Performance](#Performance)
- [Static](#Static)
- [TreeShake](#TreeShake)
- [Compile](#Compile)
@@ -153,7 +153,20 @@ const R = C.Check({ // Iterations: 10_000_000
## Mapping
TypeMap is primarily a mapping system intended for type translation. It provides mapping functions per library which is used to translate remote types into types specific to that library. All mapping functions make a best attempt to retain semantics from each library. If no translation is possible, these functions return a `never` representation specific to the library being mapped.
TypeMap is designed for runtime type translation. It provides a single mapping functions per library which is used to translate remote types into types specific to that library. All mapping functions make a best attempt to retain semantics from each library. If no translation is possible, these functions return a `never` representation specific to the library being mapped.
### Syntax
Use the `Syntax` function to translate types into a Syntax string
```typescript
import { Syntax } from '@sinclair/typemap'
const S = Syntax('string[]') // const S: 'string[]' (Syntax)
const T = Syntax(t.Number()) // const T: 'number' (TypeBox)
const V = Syntax(v.string()) // const V: 'string' (Valibot)
const Z = Syntax(z.boolean()) // const Z: 'boolean' (Zod)
```
### TypeBox
@@ -166,7 +179,6 @@ const S = TypeBox('string[]') // const S: TArray<TStrin
const T = TypeBox(t.Number()) // const T: TNumber (TypeBox)
const V = TypeBox(v.string()) // const V: TString (Valibot)
const Z = TypeBox(z.boolean()) // const Z: TBoolean (Zod)
```
### Valibot
@@ -277,66 +289,6 @@ const S = Vector(Zod('string')) // const S: TObject<{
// }>
```
### Performance
TypeMap implements type level syntax parsing in the TypeScript type system. This feature puts a lot of additional demand on the TypeScript language service above and beyond the compute required to infer the underlying type library. One should approach this feature with some mindfulness to the computational overhead required parse and infer types from syntax. The following link can be used to test infer performance.
([Example](https://www.typescriptlang.org/play/?moduleResolution=99&module=199#code/JYWwDg9gTgLgBAbzgFQJ5gKYCEIA8A0cAyjAIYzADGcAvnAGZQQhwDkAAgM7AB2lANqWBQA9DHQYQpMKwBQskSLgBBMGH5VywCDxQTO8yjs7wAwhACuPGFFRwAvHsw5cACgAGsuGwByGAO5wAFoYpII8ACascAA+XmzKFiZQYcCk0TFw8axEljAAFnAA0tChGVnerABS0qQ85dmmdaQR6bEVbACqPMAwGBHEZH2cDZU+0P6kqBnZRP79GPWx8a4IdABkcMm8AOYAlLLuB7JGPCYqERFQGJycDk7YeKtw5lY2djSE7gjxyRgYMAAXFsbLt4pReqhgdseDt4pATEYIhhoaDYeDLNZbMDXljULIaEdDMZ4J1OBgoABJAaONDOJ6sGE7ViEJD0aBSIFsCwWYBRWjHU7nACiUmA-HudMebkZaOZrIYHPIwNYkiE-GiNEFJLgZIpkokLmeeqpEUIovVhGUl2ut1oXx+3iSFOpwJN1Pw8WdUB4pBAKJBUDB3jV4uBFvF8RaVxunGB1pjt3B13I-WBABFUwSiScdQAlCD8DAG+luTyVFogXjJcjQUZsfq9OvtbJgCwAIw0nHyFLkOaF8CIqBMkhNJelxvJUEIBaL9rg7jHm0dcCYRbjcFnGAA2gBdbPHRRwAAKFPZUCkfGLyBuMHk9CslAoOjgmCg58vlAwrm9wJIWkoAAecRMAgehiGHPoQBNAA+PZEHiL0pzgI9nTYAA6aIYAgOBhngXh6H1N8PzqL8CSAA))
```typescript
import { TypeBox, Static } from '@sinclair/typemap'
// Application Types
const Country = TypeBox(`
'New Zealand' |
'Australia' |
'South Korea' |
'Japan' |
'Canada' |
'United States' |
'Norway' |
'Sweden' |
({} & string)
`)
const Address = TypeBox({ Country }, `{
street: string
city: string
postcode: string
country: Country
}`)
const UserId = TypeBox('string', { format: 'uuid' })
const Email = TypeBox('string', { format: 'email' })
const User = TypeBox({ UserId, Email, Address }, `{
userId: UserId,
username: string
email: Email
address: Address
created: Date
}`)
const Role = TypeBox(`
'adminstrator' |
'editor' |
'publisher'
`)
const SystemUser = TypeBox({ User, Role }, `User & {
roles: Role[]
}`)
// Performance Test
function performance(user: Static<typeof SystemUser>) {
user // use '.' to test infer performance
}
```
## Static
Use Static to infer for library and syntax types
@@ -357,10 +309,10 @@ type Z = Static<typeof Z> // boolean
## TreeShake
TypeMap exports the top-level TypeBox, Valibot, and Zod functions, which broadly translate any type. However, applications are most likely going to be interested in translating between two libraries (at most) and in one specific direction (e.g., Zod to TypeBox). TypeMap provides specific functions that perform only a particular translation. Using these specific mapping functions allows bundlers to tree-shake unused type libraries.
TypeMap takes TypeBox, Valibot and Zod on as peer dependencies. If bundling for browser environments, it is recommended to import specific functions to handle specific translations. For example, the following imports a Zod to TypeBox translation. By doing this it will by-pass other library imports cause Valibot to be omitted from the bundle.
```typescript
import { TypeBoxFromZod } from '@sinclair/typemap' // Bundle TypeBox | Zod, Tree Shake Valibot
import { TypeBoxFromZod } from '@sinclair/typemap' // Include TypeBox & Zod, Tree Shake Valibot
import * as z from 'zod'

View File

@@ -30,22 +30,25 @@ import * as t from '@sinclair/typebox'
import * as v from 'valibot'
import * as z from 'zod'
/** Structural Type for Syntax */
export type SyntaxType = string
/** Structural Type for TypeBox */
export type TypeBoxType = t.TSchema
/** Structural Type for Valibot */
export type ValibotType = v.BaseSchema<any, any, v.BaseIssue<any>>
/** Structural Type for Zod */
export type ZodType = z.ZodTypeAny | z.ZodEffects<any>
// ------------------------------------------------------------------
// Syntax
// ------------------------------------------------------------------
/** Structural Type for Syntax */
export type SyntaxType = string
/** Returns true if the given value is a Syntax type */
export function IsSyntax(value: unknown): value is string {
return t.ValueGuard.IsString(value)
}
// ------------------------------------------------------------------
// TypeBox
// ------------------------------------------------------------------
/** Structural Type for TypeBox */
export type TypeBoxType = t.TSchema
/** Returns true if the given value is a TypeBox type */
export function IsTypeBox(type: unknown): type is t.TSchema {
return t.KindGuard.IsSchema(type)
@@ -53,9 +56,6 @@ export function IsTypeBox(type: unknown): type is t.TSchema {
// ------------------------------------------------------------------
// Valibot
// ------------------------------------------------------------------
/** Structural Type for Valibot */
export type ValibotType = v.BaseSchema<any, any, v.BaseIssue<any>>
/** Returns true if the given value is a Valibot type */
// prettier-ignore
export function IsValibot(type: unknown): type is v.AnySchema {
@@ -70,14 +70,6 @@ export function IsValibot(type: unknown): type is v.AnySchema {
// ------------------------------------------------------------------
// Zod
// ------------------------------------------------------------------
/** Structural Type for Zod */
export type ZodType = z.ZodTypeAny | z.ZodEffects<any>
/** Returns true if the given value is a Zod type */
// prettier-ignore
export type TIsZod<Type extends unknown> = (
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 {
@@ -92,20 +84,25 @@ export function IsZod(type: unknown): type is z.ZodTypeAny {
// ------------------------------------------------------------------
// Signature
// ------------------------------------------------------------------
// (parameter, syntax, options)
function Signature1(args: any[]) {
return args.length === 3 && t.ValueGuard.IsObject(args[0]) && t.ValueGuard.IsString(args[1]) && t.ValueGuard.IsObject(args[2])
}
// (syntax, options)
function Signature2(args: any[]) {
return args.length === 2 && t.ValueGuard.IsString(args[0]) && t.ValueGuard.IsObject(args[1])
}
// (parameter, options)
function Signature3(args: any[]) {
return args.length === 2 && t.ValueGuard.IsObject(args[0]) && t.ValueGuard.IsString(args[1])
}
// (syntax | type)
function Signature4(args: any[]) {
return args.length === 1 && (t.ValueGuard.IsString(args[0]) || t.ValueGuard.IsObject(args[0]))
}
/** Resolve common mapping signature parameters */
// prettier-ignore
export function Signature(args: any[]): [parameter: Record<PropertyKey, object>, type: string | object, options: object] {
// prettier-ignore
return (
Signature1(args) ? [args[0], args[1], args[2]] :
Signature2(args) ? [{}, args[0], args[1]] :

View File

@@ -38,6 +38,15 @@ export { type Static } from './static'
// ------------------------------------------------------------------
export * from './compile/compile'
// ------------------------------------------------------------------
// Syntax
// ------------------------------------------------------------------
export * from './syntax/syntax-from-syntax'
export * from './syntax/syntax-from-typebox'
export * from './syntax/syntax-from-valibot'
export * from './syntax/syntax-from-zod'
export { type TSyntax, Syntax } from './syntax/syntax'
// ------------------------------------------------------------------
// TypeBox
// ------------------------------------------------------------------

View File

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

View File

@@ -0,0 +1,365 @@
/*--------------------------------------------------------------------------
@sinclair/typemap
The MIT License (MIT)
Copyright (c) 2024-2025 Haydn Paterson (sinclair) <haydn.developer@gmail.com>
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
---------------------------------------------------------------------------*/
import * as t from '@sinclair/typebox'
// ------------------------------------------------------------------
// Characters
// ------------------------------------------------------------------
type TEmptyString = ''
type TAmpersand = '&'
type TComma = ','
type TPipe = '|'
const Ampersand = '&'
const Comma = ','
const Pipe = '|'
// ------------------------------------------------------------------
// Delmited
// ------------------------------------------------------------------
// prettier-ignore
type TFromDelimited<Values extends string[], Delimiter extends string, Result extends string = TEmptyString> = (
Values extends [infer Left extends string, ...infer Right extends string[]]
? Result extends TEmptyString
? TFromDelimited<Right, Delimiter, Left>
: TFromDelimited<Right, Delimiter, `${Result}${Delimiter} ${Left}`>
: Result
)
function FromDelimited(values: string[], delimiter: string): string {
return values.join(delimiter)
}
// ------------------------------------------------------------------
// Any
// ------------------------------------------------------------------
type TFromAny<_Type extends t.TAny> = 'any'
function FromAny(_type: t.TSchema): string {
return 'any'
}
// ------------------------------------------------------------------
// Array
// ------------------------------------------------------------------
// prettier-ignore
type TFromArray<Type extends t.TSchema,
Result extends string = `${TFromType<Type>}[]`
> = Result
function FromArray(type: t.TSchema): string {
return `${type}[]`
}
// ------------------------------------------------------------------
// BigInt
// ------------------------------------------------------------------
type TFromBigInt<_Type extends t.TBigInt> = 'bigint'
function FromBigInt(_type: t.TSchema): string {
return 'bigint'
}
// ------------------------------------------------------------------
// Boolean
// ------------------------------------------------------------------
type TFromBoolean<_Type extends t.TBoolean> = 'boolean'
function FromBoolean(_type: t.TSchema): string {
return 'boolean'
}
// ------------------------------------------------------------------
// Constructor
// ------------------------------------------------------------------
// prettier-ignore
type TFromConstructor<Parameters extends t.TSchema[], InstanceType extends t.TSchema,
MappedParameters extends string = TFromParameters<Parameters>,
MappedInstanceType extends string = TFromType<InstanceType>
> = `new ${MappedParameters} => ${MappedInstanceType}`
// prettier-ignore
function FromConstructor(parameters: t.TSchema[], instanceType: t.TSchema): string {
const mappedParameters = FromParameters(parameters)
const mappedInstanceType = FromType(instanceType)
return `new ${mappedParameters} => ${mappedInstanceType}`
}
// ------------------------------------------------------------------
// Function
// ------------------------------------------------------------------
// prettier-ignore
type TFromFunction<Parameters extends t.TSchema[], ReturnType extends t.TSchema,
MappedParameters extends string = TFromParameters<Parameters>,
MappedReturnType extends string = TFromType<ReturnType>
> = `${MappedParameters} => ${MappedReturnType}`
// prettier-ignore
function FromFunction(parameters: t.TSchema[], returnType: t.TSchema): string {
const mappedParameters = FromParameters(parameters)
const mappedReturnType = FromType(returnType)
return `${mappedParameters} => ${mappedReturnType}`
}
// ------------------------------------------------------------------
// Integer
// ------------------------------------------------------------------
type TFromInteger<_Type extends t.TInteger> = 'integer'
function FromInteger(_type: t.TSchema): string {
return 'integer'
}
// ------------------------------------------------------------------
// Intersect
// ------------------------------------------------------------------
// prettier-ignore
type TFromIntersect<Types extends t.TSchema[], Result extends string[] = []> = (
Types extends [infer Left extends t.TSchema, ...infer Right extends t.TSchema[]]
? TFromIntersect<Right, [...Result, TFromType<Left>]>
: `(${TFromDelimited<Result, ` ${TAmpersand}`>})`
)
function FromIntersect(types: t.TSchema[]): string {
const result = types.map((type) => FromType(type))
return `(${FromDelimited(result, ` ${Ampersand} `)})`
}
// ------------------------------------------------------------------
// Literal
// ------------------------------------------------------------------
// prettier-ignore
type TFromLiteral<Value extends t.TLiteralValue,
Result extends string = Value extends string ? `"${Value}"` : `${Value}`
> = Result
// prettier-ignore
function FromLiteral(value: t.TLiteralValue): string {
return t.ValueGuard.IsString(value) ? `"${value}"` : `${value}`
}
// ------------------------------------------------------------------
// Number
// ------------------------------------------------------------------
type TFromNumber<_Type extends t.TNumber> = 'number'
function FromNumber(_type: t.TSchema): string {
return 'number'
}
// ------------------------------------------------------------------
// Null
// ------------------------------------------------------------------
type TFromNull<_Type extends t.TNull> = 'null'
function FromNull(_type: t.TSchema): string {
return 'null'
}
// ------------------------------------------------------------------
// Object
// ------------------------------------------------------------------
// prettier-ignore
type TFromObject<Properties extends t.TProperties,
PropertyKeys extends PropertyKey[] = t.UnionToTuple<keyof Properties>,
Delimited extends string[] = TFromProperties<PropertyKeys, Properties>,
Result extends string = TFromDelimited<Delimited, TComma>
> = `{ ${Result} }`
function FromObject(properties: t.TProperties): string {
const propertyKeys = globalThis.Object.getOwnPropertyNames(properties)
const delimited = FromProperties(propertyKeys, properties)
const result = FromDelimited(delimited, Comma)
return `{ ${result} }`
}
// ------------------------------------------------------------------
// Parameters
// ------------------------------------------------------------------
// prettier-ignore
type TFromParameters<Parameters extends t.TSchema[], Index extends string = '0', Result extends string[] = []> = (
Parameters extends [infer Left extends t.TSchema, ...infer Right extends t.TSchema[]]
? TFromParameters<Right, t.TIncrement<Index>, [...Result, `arg${Index}: ${TFromType<Left>}`]>
: `(${TFromDelimited<Result, TComma>})`
)
function FromParameters(parameters: t.TSchema[]): string {
const result = parameters.map((parameter, index) => `arg${index}: ${FromType(parameter)}`)
return `(${FromDelimited(result, Comma)})`
}
// ------------------------------------------------------------------
// Property
// ------------------------------------------------------------------
// prettier-ignore
type TFromProperty<Key extends string, Type extends t.TSchema,
IsOptional extends boolean = Type extends t.TOptional<t.TSchema> ? true : false,
IsReadonly extends boolean = Type extends t.TReadonly<t.TSchema> ? true : false,
Mapped extends string = TFromType<Type>,
Result = (
[IsReadonly, IsOptional] extends [true, true] ? `readonly ${Key}?: ${Mapped}` :
[IsReadonly, IsOptional] extends [false, true] ? `${Key}?: ${Mapped}` :
[IsReadonly, IsOptional] extends [true, false] ? `readonly ${Key}: ${Mapped}` :
`${Key}: ${Mapped}`
)
> = Result
// prettier-ignore
function FromProperty(key: string, type: t.TSchema): string {
const isOptional = t.KindGuard.IsOptional(type)
const isReadonly = t.KindGuard.IsReadonly(type)
const mapped = FromType(type)
return (
isReadonly && isOptional ? `readonly ${key}?: ${mapped}` :
!isReadonly && isOptional ? `${key}?: ${mapped}` :
isReadonly && !isOptional ? `readonly ${key}: ${mapped}` :
`${key}: ${mapped}`
)
}
// ------------------------------------------------------------------
// Properties
// ------------------------------------------------------------------
// prettier-ignore
type TFromProperties<PropertyKeys extends PropertyKey[], Properties extends t.TProperties, Result extends string[] = []> = (
PropertyKeys extends [infer Left extends PropertyKey, ...infer Right extends PropertyKey[]]
? (Left extends infer Key extends string
? (Key extends keyof Properties
? TFromProperties<Right, Properties, [...Result, TFromProperty<Key, Properties[Key]>]>
: TFromProperties<Right, Properties, Result>
) : TFromProperties<Right, Properties, Result>
) : Result
)
// prettier-ignore
function FromProperties(propertyKeys: PropertyKey[], properties: t.TProperties): string[] {
return propertyKeys.reduce((result, left) => {
const key = t.ValueGuard.IsString(left) || t.ValueGuard.IsNumber(left) || t.ValueGuard.IsBoolean(left) ? `${left}` : undefined
return (
t.ValueGuard.IsString(key)
? (key in properties
? [...result, FromProperty(key, properties[key])]
: result
): result
)
}, [] as string[])
}
// ------------------------------------------------------------------
// String
// ------------------------------------------------------------------
type TFromString<_Type extends t.TString> = 'string'
function FromString(_type: t.TSchema): string {
return 'string'
}
// ------------------------------------------------------------------
// Symbol
// ------------------------------------------------------------------
type TFromSymbol<_Type extends t.TSymbol> = 'symbol'
function FromSymbol(_type: t.TSchema): string {
return 'symbol'
}
// ------------------------------------------------------------------
// Union
// ------------------------------------------------------------------
// prettier-ignore
type TFromTuple<Types extends t.TSchema[], Result extends string[] = []> = (
Types extends [infer Left extends t.TSchema, ...infer Right extends t.TSchema[]]
? TFromTuple<Right, [...Result, TFromType<Left>]>
: `[${TFromDelimited<Result, TComma>}]`
)
function FromTuple(types: t.TSchema[]): string {
const result = types.map((type) => FromType(type))
return `[${FromDelimited(result, Comma)}]`
}
// ------------------------------------------------------------------
// Undefined
// ------------------------------------------------------------------
type TFromUndefined<_Type extends t.TUndefined> = 'undefined'
function FromUndefined(type: t.TSchema): string {
return 'undefined'
}
// ------------------------------------------------------------------
// Union
// ------------------------------------------------------------------
// prettier-ignore
type TFromUnion<Types extends t.TSchema[], Result extends string[] = []> = (
Types extends [infer Left extends t.TSchema, ...infer Right extends t.TSchema[]]
? TFromUnion<Right, [...Result, TFromType<Left>]>
: `(${TFromDelimited<Result, ` ${TPipe}`>})`
)
function FromUnion(types: t.TSchema[]): string {
const result = types.map((type) => FromType(type))
return `(${FromDelimited(result, ` ${Pipe} `)})`
}
// ------------------------------------------------------------------
// Unknown
// ------------------------------------------------------------------
type TFromUnknown<Type extends t.TSchema> = 'unknown'
function FromUnknown(type: t.TSchema): string {
return 'unknown'
}
// ------------------------------------------------------------------
// Void
// ------------------------------------------------------------------
type TFromVoid<Type extends t.TSchema> = 'void'
function FromVoid(type: t.TSchema): string {
return 'void'
}
// ------------------------------------------------------------------
// FromType
// ------------------------------------------------------------------
// prettier-ignore
type TFromType<Type extends t.TSchema> = (
Type extends t.TAny ? TFromAny<Type> :
Type extends t.TArray<infer Type extends t.TSchema> ? TFromArray<Type> :
Type extends t.TBigInt ? TFromBigInt<Type> :
Type extends t.TBoolean ? TFromBoolean<Type> :
Type extends t.TConstructor<infer Parameters extends t.TSchema[], infer InstanceType extends t.TSchema> ? TFromConstructor<Parameters, InstanceType> :
Type extends t.TFunction<infer Parameters extends t.TSchema[], infer ReturnType extends t.TSchema> ? TFromFunction<Parameters, ReturnType> :
Type extends t.TInteger ? TFromInteger<Type> :
Type extends t.Intersect<infer Types extends t.TSchema[]> ? TFromIntersect<Types> :
Type extends t.TLiteral<infer Value extends t.TLiteralValue> ? TFromLiteral<Value> :
Type extends t.TNumber ? TFromNumber<Type> :
Type extends t.TNull ? TFromNull<Type> :
Type extends t.TObject<infer Properties extends t.TProperties> ? TFromObject<Properties> :
Type extends t.TString ? TFromString<Type> :
Type extends t.TSymbol ? TFromSymbol<Type> :
Type extends t.TTuple<infer Types extends t.TSchema[]> ? TFromTuple<Types> :
Type extends t.TUndefined ? TFromUndefined<Type> :
Type extends t.TUnion<infer Types extends t.TSchema[]> ? TFromUnion<Types> :
Type extends t.TUnknown ? TFromUnknown<Type> :
Type extends t.TVoid ? TFromVoid<Type> :
'never'
)
// prettier-ignore
function FromType<Type extends t.TSchema>(type: Type): TFromType<Type> {
return (
t.KindGuard.IsAny(type) ? FromAny(type) :
t.KindGuard.IsArray(type) ? FromArray(type.items) :
t.KindGuard.IsBigInt(type) ? FromBigInt(type) :
t.KindGuard.IsBoolean(type) ? FromBoolean(type) :
t.KindGuard.IsConstructor(type) ? FromConstructor(type.parameters, type.returns) :
t.KindGuard.IsFunction(type) ? FromFunction(type.parameters, type.returns) :
t.KindGuard.IsInteger(type) ? FromInteger(type) :
t.KindGuard.IsIntersect(type) ? FromIntersect(type.allOf) :
t.KindGuard.IsLiteral(type) ? FromLiteral(type.const) :
t.KindGuard.IsNumber(type) ? FromNumber(type) :
t.KindGuard.IsNull(type) ? FromNull(type) :
t.KindGuard.IsObject(type) ? FromObject(type.properties) :
t.KindGuard.IsString(type) ? FromString(type) :
t.KindGuard.IsSymbol(type) ? FromSymbol(type) :
t.KindGuard.IsTuple(type) ? FromTuple(type.items || []) :
t.KindGuard.IsUndefined(type) ? FromUndefined(type) :
t.KindGuard.IsUnion(type) ? FromUnion(type.anyOf) :
t.KindGuard.IsUnknown(type) ? FromUnknown(type) :
t.KindGuard.IsVoid(type) ? FromVoid(type) :
'never'
) as never
}
// ------------------------------------------------------------------
// SyntaxFromTypeBox
// ------------------------------------------------------------------
// prettier-ignore
export type TSyntaxFromTypeBox<Type extends t.TSchema,
Result extends string = TFromType<Type>
> = Result
export function SyntaxFromTypeBox<Type extends t.TSchema>(type: t.TSchema): TSyntaxFromTypeBox<Type> {
return FromType(type) as never
}

View File

@@ -0,0 +1,48 @@
/*--------------------------------------------------------------------------
@sinclair/typemap
The MIT License (MIT)
Copyright (c) 2024-2025 Haydn Paterson (sinclair) <haydn.developer@gmail.com>
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
---------------------------------------------------------------------------*/
import { type TTypeBoxFromValibot, TypeBoxFromValibot } from '../typebox/typebox-from-valibot'
import { type TSyntaxFromTypeBox, SyntaxFromTypeBox } from './syntax-from-typebox'
import * as t from '@sinclair/typebox'
import * as v from 'valibot'
/** Creates Syntax from Valibot */
// prettier-ignore
export type TSyntaxFromValibot<Type extends v.BaseSchema<any, any, any>,
TypeBox extends t.TSchema = TTypeBoxFromValibot<Type>,
Result extends string = TSyntaxFromTypeBox<TypeBox>
> = Result
/** Creates Syntax from Valibot */
// prettier-ignore
export function SyntaxFromValibot<Type extends v.BaseSchema<any, any, any>>(type: Type): TSyntaxFromValibot<Type> {
const typebox = TypeBoxFromValibot(type)
const result = SyntaxFromTypeBox(typebox)
return result as never
}

View File

@@ -0,0 +1,48 @@
/*--------------------------------------------------------------------------
@sinclair/typemap
The MIT License (MIT)
Copyright (c) 2024-2025 Haydn Paterson (sinclair) <haydn.developer@gmail.com>
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
---------------------------------------------------------------------------*/
import { type TTypeBoxFromZod, TypeBoxFromZod } from '../typebox/typebox-from-zod'
import { type TSyntaxFromTypeBox, SyntaxFromTypeBox } from './syntax-from-typebox'
import * as t from '@sinclair/typebox'
import * as z from 'zod'
/** Creates Syntax from Zod */
// prettier-ignore
export type TSyntaxFromZod<Type extends z.ZodTypeAny | z.ZodEffects<any>,
TypeBox extends t.TSchema = TTypeBoxFromZod<Type>,
Result extends string = TSyntaxFromTypeBox<TypeBox>
> = Result
/** Creates Syntax from Zod */
// prettier-ignore
export function SyntaxFromZod<Type extends z.ZodTypeAny | z.ZodEffects<any>>(type: Type): TSyntaxFromZod<Type> {
const typebox = TypeBoxFromZod(type)
const result = SyntaxFromTypeBox(typebox)
return result as never
}

69
src/syntax/syntax.ts Normal file
View File

@@ -0,0 +1,69 @@
/*--------------------------------------------------------------------------
@sinclair/typemap
The MIT License (MIT)
Copyright (c) 2024-2025 Haydn Paterson (sinclair) <haydn.developer@gmail.com>
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
---------------------------------------------------------------------------*/
import { type TSyntaxFromSyntax, SyntaxFromSyntax } from './syntax-from-syntax'
import { type TSyntaxFromTypeBox, SyntaxFromTypeBox } from './syntax-from-typebox'
import { type TSyntaxFromValibot, SyntaxFromValibot } from './syntax-from-valibot'
import { type TSyntaxFromZod, SyntaxFromZod } from './syntax-from-zod'
import { type TSyntaxOptions } from '../options'
import { type TParameter } from '../typebox/typebox'
import * as g from '../guard'
import * as z from 'zod'
// ------------------------------------------------------------------
// Zod
// ------------------------------------------------------------------
/** Creates Syntax by mapping from a remote Type */
// prettier-ignore
export type TSyntax<_Parameter extends TParameter, Type extends object | string, Result extends string = (
Type extends g.SyntaxType ? TSyntaxFromSyntax<Type> :
Type extends g.TypeBoxType ? TSyntaxFromTypeBox<Type> :
Type extends g.ValibotType ? TSyntaxFromValibot<Type> :
Type extends g.ZodType ? TSyntaxFromZod<Type> :
'never'
)> = Result
/** Creates Syntax by mapping from a remote Type */
export function Syntax<Parameter extends TParameter, Type extends string>(parameter: Parameter, type: Type, options?: TSyntaxOptions): TSyntax<Parameter, Type>
/** Creates Syntax by mapping from a remote Type */
export function Syntax<Type extends string>(type: Type, options?: TSyntaxOptions): TSyntax<{}, Type>
/** Creates Syntax by mapping from a remote Type */
export function Syntax<Type extends object>(type: Type, options?: TSyntaxOptions): TSyntax<{}, Type>
/** Creates Syntax by mapping from a remote Type */
// prettier-ignore
export function Syntax(...args: any[]): never {
const [_parameter, type, _options] = g.Signature(args)
return (
g.IsSyntax(type) ? SyntaxFromSyntax(type) :
g.IsTypeBox(type) ? SyntaxFromTypeBox(type) :
g.IsValibot(type) ? SyntaxFromValibot(type) :
g.IsZod(type) ? SyntaxFromZod(type) :
z.never()
) as never
}

View File

@@ -35,13 +35,13 @@ import * as t from '@sinclair/typebox'
// prettier-ignore
export type TTypeBoxFromSyntax<Context extends t.TProperties, Type extends string,
Mapped = StaticParseAsSchema<Context, Type>,
Result extends t.TSchema = Mapped extends t.TSchema ? Mapped : t.TNever
TypeBox = StaticParseAsSchema<Context, Type>,
Result extends t.TSchema = TypeBox extends t.TSchema ? TypeBox : t.TNever
> = Result
/** Creates a TypeBox Type From Syntax */
export function TypeBoxFromSyntax<Context extends t.TProperties, Type extends string>(context: Context, type: Type, options?: t.SchemaOptions): TTypeBoxFromSyntax<Context, Type> {
const parsed = t.ValueGuard.IsString(type) ? Parse(context, type, options) : t.Never()
const result = t.KindGuard.IsSchema(parsed) ? parsed : t.Never()
const typebox = t.ValueGuard.IsString(type) ? Parse(context, type, options) : t.Never()
const result = t.KindGuard.IsSchema(typebox) ? typebox : t.Never()
return result as never
}

View File

@@ -31,11 +31,12 @@ import * as t from '@sinclair/typebox'
// ------------------------------------------------------------------
// TypeBoxFromTypeBox
// ------------------------------------------------------------------
/** Creates a TypeBox type from TypeBox */
// prettier-ignore
export type TTypeBoxFromTypeBox<Type extends t.TSchema> = Type
/** Creates a TypeBox type from TypeBox */
// prettier-ignore
export function TypeBoxFromTypeBox<Type extends t.TSchema, Result extends TTypeBoxFromTypeBox<Type> = TTypeBoxFromTypeBox<Type>>(type: Type): Result {
return (t.KindGuard.IsSchema(type) ? type : t.Never()) as never
export function TypeBoxFromTypeBox<Type extends t.TSchema>(type: Type): TTypeBoxFromTypeBox<Type> {
return t.CloneType(type)
}

View File

@@ -841,13 +841,14 @@ function FromType<Type extends BaseSchema>(type: Type): TFromType<Type> {
// ------------------------------------------------------------------
// TypeBoxFromValibot
// ------------------------------------------------------------------
/** Creates a TypeBox type from Valibot */
// prettier-ignore
export type TTypeBoxFromValibot<Type extends v.BaseSchema<any, any, any>,
Result extends t.TSchema = TFromType<Type>
> = Result
/** Converts a Valibot Type to a TypeBox Type */
/** Creates a TypeBox type from Valibot */
// prettier-ignore
export function TypeBoxFromValibot<Type extends v.BaseSchema<any, any, any>, Result extends TTypeBoxFromValibot<Type> = TTypeBoxFromValibot<Type>>(type: Type): Result {
return (Guard.IsValibot(type) ? FromType(type) : t.Never()) as never
return FromType(type) as never
}

View File

@@ -28,7 +28,6 @@ THE SOFTWARE.
import * as t from '@sinclair/typebox'
import * as z from 'zod'
import * as Guard from '../guard'
// ------------------------------------------------------------------
// Options
@@ -135,6 +134,7 @@ function FromEffects<Type extends z.ZodEffects<z.ZodTypeAny, unknown>>(type: Typ
// ------------------------------------------------------------------
// Enum
// ------------------------------------------------------------------
/** prettier-ignore */
type TFromEnum<Variants extends string[], Result extends t.TLiteral[] = []> = Variants extends [infer Left extends string, ...infer Right extends string[]] ? TFromEnum<Right, [...Result, t.TLiteral<Left>]> : t.TUnion<Result>
function FromEnum<Def extends z.ZodEnumDef>(def: Def): t.TSchema {
const variants = def.values.map((value) => t.Literal(value))
@@ -405,11 +405,11 @@ function FromType<Type extends z.ZodType>(type: Type): t.TSchema {
// ------------------------------------------------------------------
// TypeBoxFromZod
// ------------------------------------------------------------------
/** Creates a TypeBox type from Zod */
export type TTypeBoxFromZod<Type extends z.ZodTypeAny | z.ZodEffects<any>, Result extends t.TSchema = TFromType<Type>> = Result
/** Creates a TypeBox type from Zod */
// prettier-ignore
export type TTypeBoxFromZod<Type extends z.ZodTypeAny | z.ZodEffects<any>,
Result extends t.TSchema = TFromType<Type>
> = Result
// prettier-ignore
export function TypeBoxFromZod<Type extends z.ZodTypeAny | z.ZodEffects<any>, Result extends TTypeBoxFromZod<Type> = TTypeBoxFromZod<Type>>(type: Type): Result {
export function TypeBoxFromZod<Type extends z.ZodTypeAny | z.ZodEffects<any>>(type: Type): TTypeBoxFromZod<Type> {
return FromType(type) as never
}

View File

@@ -31,6 +31,7 @@ import { type TTypeBoxFromTypeBox, TypeBoxFromTypeBox } from './typebox-from-typ
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'
@@ -40,7 +41,7 @@ import * as t from '@sinclair/typebox'
//
// 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.
// the remote types such that they can be mapped prior to syntax parsing.
//
// -------------------------------------------------------------------------------
export type TParameter = Record<PropertyKey, object>
@@ -64,7 +65,7 @@ export function ContextFromParameter<Parameter extends TParameter>(parameter: Pa
// ------------------------------------------------------------------
// TypeBox
// ------------------------------------------------------------------
/** Creates a TypeBox type from Syntax or another Type */
/** Creates a TypeBox type by mapping from a remote Type */
// prettier-ignore
export type TTypeBox<Parameter extends TParameter, Type extends object | string, Result = (
Type extends g.SyntaxType ? TTypeBoxFromSyntax<TContextFromParameter<Parameter>, Type> :
@@ -73,11 +74,11 @@ export type TTypeBox<Parameter extends TParameter, Type extends object | string,
Type extends g.ZodType ? TTypeBoxFromZod<Type> :
t.TNever
)> = Result
/** Creates a TypeBox type from Syntax or another Type */
/** Creates a TypeBox type by mapping from a remote Type */
export function TypeBox<Parameter extends TParameter, Type extends string>(parameter: Parameter, type: Type, options?: TSyntaxOptions): TTypeBox<Parameter, Type>
/** Creates a TypeBox type from Syntax or another Type */
/** Creates a TypeBox type by mapping from a remote Type */
export function TypeBox<Type extends object | string>(type: Type, options?: TSyntaxOptions): TTypeBox<{}, Type>
/** Creates a TypeBox type from Syntax or another Type */
/** Creates a TypeBox type by mapping from a remote Type */
// prettier-ignore
export function TypeBox(...args: any[]): never {
const [parameter, type, options] = g.Signature(args)

View File

@@ -35,15 +35,16 @@ import * as v from 'valibot'
// ------------------------------------------------------------------
// ValibotFromSyntax
// ------------------------------------------------------------------
/** Creates a Valibot type from Syntax */
// prettier-ignore
export type TValibotFromSyntax<Context extends t.TProperties, Type extends string,
Schema extends t.TSchema = TTypeBoxFromSyntax<Context, Type>,
Result extends v.BaseSchema<any, any, any> = TValibotFromTypeBox<Schema>
TypeBox extends t.TSchema = TTypeBoxFromSyntax<Context, Type>,
Result extends v.BaseSchema<any, any, any> = TValibotFromTypeBox<TypeBox>
> = Result
/** Creates a Valibot type from Syntax */
// prettier-ignore
export function ValibotFromSyntax<Context extends t.TProperties, Type extends string>(context: Context, type: Type, options?: t.SchemaOptions): TValibotFromSyntax<Context, Type> {
const schema = TypeBoxFromSyntax(context, type, options)
const result = ValibotFromTypeBox(schema)
const typebox = TypeBoxFromSyntax(context, type, options)
const result = ValibotFromTypeBox(typebox)
return result as never
}

View File

@@ -136,6 +136,7 @@ type TFromObject<Properties extends t.TProperties,
[Key in keyof Properties]: TFromType<Properties[Key]>
}, c.BaseError>
> = Result
// prettier-ignore
function FromObject(type: t.TObject): c.BaseSchema {
const { additionalProperties } = type
const constraints = CreateConstraints(type)
@@ -279,9 +280,10 @@ function FromUndefined(type: t.TUndefined): c.BaseSchema {
// Union
// ------------------------------------------------------------------
// prettier-ignore
type TFromUnion<Types extends t.TSchema[], Mapped extends c.BaseSchema[] = TFromTypes<Types>, Result = v.UnionSchema<Mapped, c.BaseError>> = (
Result
)
type TFromUnion<Types extends t.TSchema[],
Mapped extends c.BaseSchema[] = TFromTypes<Types>,
Result = v.UnionSchema<Mapped, c.BaseError>
> = Result
function FromUnion(type: t.TUnion): c.BaseSchema {
const mapped = FromTypes(type.anyOf) as [c.BaseSchema, c.BaseSchema, ...c.BaseSchema[]]
return CreateType(v.union(mapped), CreateConstraints(type))
@@ -396,6 +398,7 @@ function FromType(type: t.TSchema): c.BaseSchema {
// ------------------------------------------------------------------
// ValibotFromTypeBox
// ------------------------------------------------------------------
// prettier-ignore
export type TValibotFromTypeBox<Type extends t.TSchema,
Result extends c.BaseSchema = TFromType<Type>

View File

@@ -31,12 +31,13 @@ import * as v from 'valibot'
// ------------------------------------------------------------------
// ValibotFromValibot
// ------------------------------------------------------------------
/** Creates a Valibot type from Valibot */
// prettier-ignore
export type TValibotFromValibot<Type extends v.BaseSchema<any, any, any>,
Result extends v.BaseSchema<any, any, any> = Type
> = Result
/** Creates a Valibot type from Valibot */
// prettier-ignore
export function ValibotFromValibot<Type extends v.BaseSchema<any, any, any>>(type: Type): TValibotFromValibot<Type> {
return type

View File

@@ -36,12 +36,13 @@ import * as z from 'zod'
// ------------------------------------------------------------------
// ValibotFromZod
// ------------------------------------------------------------------
/** Creates a Valibot type from Zod */
// prettier-ignore
export type TValibotFromZod<Type extends z.ZodTypeAny | z.ZodEffects<any>,
TypeBox extends t.TSchema = TTypeBoxFromZod<Type>,
Result extends v.BaseSchema<any, any, any> = TValibotFromTypeBox<TypeBox>
> = Result
/** Creates a Valibot type from Zod */
// prettier-ignore
export function ValibotFromZod<Type extends z.ZodTypeAny | z.ZodEffects<any>,
Result extends v.BaseSchema<any, any, any> = TValibotFromZod<Type>

View File

@@ -31,17 +31,18 @@ import { type TValibotFromTypeBox, ValibotFromTypeBox } from './valibot-from-typ
import { type TValibotFromValibot, ValibotFromValibot } from './valibot-from-valibot'
import { type TValibotFromZod, ValibotFromZod } from './valibot-from-zod'
import { type TSyntaxOptions } from '../options'
import { type TParameter, type TContextFromParameter, ContextFromParameter } from '../typebox/typebox'
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 */
/** Creates a Valibot type by mapping from a remote Type */
// prettier-ignore
export type TValibot<Parameter extends TParameter, Type extends object | string, Result extends g.ValibotType = (
Type extends g.SyntaxType ? TValibotFromSyntax<TContextFromParameter<Parameter>, Type> :
@@ -51,13 +52,13 @@ export type TValibot<Parameter extends TParameter, Type extends object | string,
v.NeverSchema<c.BaseError>
)> = Result
/** Creates a Valibot type from Syntax or another Type */
/** Creates a Valibot type by mapping from a remote Type */
export function Valibot<Parameter extends TParameter, Type extends string>(parameter: Parameter, type: Type, options?: TSyntaxOptions): TValibot<Parameter, Type>
/** Creates a Valibot type from Syntax or another Type */
/** Creates a Valibot type by mapping from a remote Type */
export function Valibot<Type extends string>(type: Type, options?: TSyntaxOptions): TValibot<{}, Type>
/** Creates a Valibot type from Syntax or another Type */
/** Creates a Valibot type by mapping from a remote Type */
export function Valibot<Type extends object>(type: Type, options?: TSyntaxOptions): TValibot<{}, Type>
/** Creates a Valibot type from Syntax or another Type */
/** Creates a Valibot type by mapping from a remote Type */
// prettier-ignore
export function Valibot(...args: any[]): never {
const [parameter, type, options] = g.Signature(args)

View File

@@ -34,15 +34,15 @@ import * as z from 'zod'
// ------------------------------------------------------------------
// ZodFromSyntax
// ------------------------------------------------------------------
/** Creates a Zod type from Syntax */
// prettier-ignore
export type TZodFromSyntax<Context extends t.TProperties, Type extends string,
Schema extends t.TSchema = TTypeBoxFromSyntax<Context, Type>,
Result extends z.ZodTypeAny | z.ZodEffects<any> = TZodFromTypeBox<Schema>
TypeBox extends t.TSchema = TTypeBoxFromSyntax<Context, Type>,
Result extends z.ZodTypeAny | z.ZodEffects<any> = TZodFromTypeBox<TypeBox>
> = Result
/** Creates a Zod type from Syntax */
export function ZodFromSyntax<Context extends t.TProperties, Type extends string>(context: Context, type: Type, options?: t.SchemaOptions): TZodFromSyntax<Context, Type> {
const schema = TypeBoxFromSyntax(context, type, options)
const result = ZodFromTypeBox(schema)
const typebox = TypeBoxFromSyntax(context, type, options)
const result = ZodFromTypeBox(typebox)
return result as never
}

View File

@@ -106,9 +106,12 @@ function FromInteger(type: t.TInteger): z.ZodTypeAny {
// ------------------------------------------------------------------
// Intersect
// ------------------------------------------------------------------
type TFromIntersect<Types extends t.TSchema[], Result extends z.ZodTypeAny = z.ZodUnknown> = Types extends [infer Left extends t.TSchema, ...infer Right extends t.TSchema[]]
? TFromIntersect<Right, z.ZodIntersection<TFromType<Left>, Result>>
: Result
// prettier-ignore
type TFromIntersect<Types extends t.TSchema[], Result extends z.ZodTypeAny = z.ZodUnknown> = (
Types extends [infer Left extends t.TSchema, ...infer Right extends t.TSchema[]]
? TFromIntersect<Right, z.ZodIntersection<TFromType<Left>, Result>>
: Result
)
function FromIntersect(type: t.TIntersect): z.ZodTypeAny {
return type.allOf.reduce((result, left) => {
return z.intersection(FromType(left), result) as never
@@ -124,8 +127,8 @@ function FromLiteral(type: t.TLiteral): z.ZodTypeAny {
// ------------------------------------------------------------------
// Object
// ------------------------------------------------------------------
type TFromObject<
Properties extends t.TProperties,
// prettier-ignore
type TFromObject< Properties extends t.TProperties,
Result = z.ZodObject<{
[Key in keyof Properties]: TFromType<Properties[Key]>
}>,
@@ -160,7 +163,12 @@ function FromRegExp(type: t.TRegExp): z.ZodTypeAny {
// ------------------------------------------------------------------
// Record
// ------------------------------------------------------------------
type TFromRecord<Key extends t.TSchema, Value extends t.TSchema> = TFromType<Key> extends infer ZodKey extends z.KeySchema ? z.ZodRecord<ZodKey, TFromType<Value>> : z.ZodNever
// prettier-ignore
type TFromRecord<Key extends t.TSchema, Value extends t.TSchema> = (
TFromType<Key> extends infer ZodKey extends z.KeySchema
? z.ZodRecord<ZodKey, TFromType<Value>>
: z.ZodNever
)
// prettier-ignore
function FromRecord(type: t.TRecord): z.ZodTypeAny {
const pattern = globalThis.Object.getOwnPropertyNames(type.patternProperties)[0]
@@ -173,34 +181,6 @@ function FromRecord(type: t.TRecord): z.ZodTypeAny {
)
}
// ------------------------------------------------------------------
// Optional
// ------------------------------------------------------------------
// prettier-ignore
type TFromOptional<Type extends t.TOptional<t.TSchema>,
NonOptional extends t.TSchema = t.TOptionalWithFlag<Type, false>,
Mapped extends z.ZodTypeAny | z.ZodEffects<any> = TFromType<NonOptional>,
Result = z.ZodOptional<Mapped>
> = Result
function FromOptional(type: t.TOptional<t.TSchema>): z.ZodTypeAny {
const non_optional = t.Optional(type, false)
const mapped = FromType(non_optional)
return z.optional(mapped)
}
// ------------------------------------------------------------------
// Readonly
// ------------------------------------------------------------------
// prettier-ignore
type TFromReadonly<Type extends t.TReadonly<t.TSchema>,
NonReadonly extends t.TSchema = t.TReadonlyWithFlag<Type, false>,
Mapped extends z.ZodTypeAny | z.ZodEffects<any> = TFromType<NonReadonly>,
Result = z.ZodReadonly<Mapped>
> = Result
function FromReadonly(type: t.TReadonly<t.TSchema>): z.ZodTypeAny {
const non_readonly = t.Readonly(type, false)
const mapped = FromType(non_readonly)
return mapped // no mapping
}
// ------------------------------------------------------------------
// Never
// ------------------------------------------------------------------
type TFromNever<Result = z.ZodNever> = Result
@@ -321,7 +301,12 @@ function FromVoid(_type: t.TVoid): z.ZodTypeAny {
// ------------------------------------------------------------------
// Types
// ------------------------------------------------------------------
type TFromTypes<Types extends t.TSchema[], Result extends z.ZodTypeAny[] = []> = Types extends [infer Left extends t.TSchema, ...infer Right extends t.TSchema[]] ? TFromTypes<Right, [...Result, TFromType<Left>]> : Result
// prettier-ignore
type TFromTypes<Types extends t.TSchema[], Result extends z.ZodTypeAny[] = []> = (
Types extends [infer Left extends t.TSchema, ...infer Right extends t.TSchema[]]
? TFromTypes<Right, [...Result, TFromType<Left>]>
: Result
)
function FromTypes(types: t.TSchema[]): z.ZodTypeAny[] {
return types.map((type) => FromType(type))
}
@@ -373,8 +358,6 @@ function FromType(type: t.TSchema): z.ZodTypeAny | z.ZodEffects<any> {
if(!t.ValueGuard.IsUndefined(type.description)) constraints.push(input => input.describe(type.description!))
if(!t.ValueGuard.IsUndefined(type.default)) constraints.push(input => input.default(type.default))
const mapped = constraints.reduce((type, constraint) => constraint(type), (
t.KindGuard.IsReadonly(type) ? FromReadonly(type) :
t.KindGuard.IsOptional(type) ? FromOptional(type) :
t.KindGuard.IsAny(type) ? FromAny(type) :
t.KindGuard.IsArray(type) ? FromArray(type) :
t.KindGuard.IsBigInt(type) ? FromBigInt(type) :
@@ -414,10 +397,12 @@ function FromType(type: t.TSchema): z.ZodTypeAny | z.ZodEffects<any> {
// ------------------------------------------------------------------
// ZodFromTypeBox
// ------------------------------------------------------------------
/** Creates a Zod type from TypeBox */
// prettier-ignore
export type TZodFromTypeBox<Type extends t.TSchema,
Result extends z.ZodTypeAny | z.ZodEffects<any> = TFromType<Type>
> = Result
/** Creates a Zod type from TypeBox */
export function ZodFromTypeBox<Type extends t.TSchema>(type: Type): TZodFromTypeBox<Type> {
return (t.KindGuard.IsSchema(type) ? FromType(type) : z.never()) as never
return FromType(type) as never
}

View File

@@ -33,15 +33,17 @@ import * as t from '@sinclair/typebox'
import * as v from 'valibot'
import * as z from 'zod'
/** Creates a Zod type from Valibot */
// prettier-ignore
export type TZodFromValibot<Type extends v.BaseSchema<any, any, any>,
Schema extends t.TSchema = TTypeBoxFromValibot<Type>,
Result extends z.ZodTypeAny | z.ZodEffects<any> = TZodFromTypeBox<Schema>
TypeBox extends t.TSchema = TTypeBoxFromValibot<Type>,
Result extends z.ZodTypeAny | z.ZodEffects<any> = TZodFromTypeBox<TypeBox>
> = Result
/** Creates a Zod type from Valibot */
// prettier-ignore
export function ZodFromValibot<Type extends v.BaseSchema<any, any, any>>(type: Type): TZodFromValibot<Type> {
const schema = TypeBoxFromValibot(type)
const result = ZodFromTypeBox(schema)
const typebox = TypeBoxFromValibot(type)
const result = ZodFromTypeBox(typebox)
return result
}

View File

@@ -26,17 +26,16 @@ THE SOFTWARE.
---------------------------------------------------------------------------*/
import * as Guard from '../guard'
import * as z from 'zod'
type BaseType = z.ZodTypeAny | z.ZodEffects<any>
/** Creates a Zod type from Zod */
// prettier-ignore
export type TZodFromZod<Type extends object,
Result extends BaseType = Type extends BaseType ? Type : z.ZodNever
export type TZodFromZod<Type extends z.ZodTypeAny | z.ZodEffects<any>,
Result = Type
> = Result
/** Creates a Zod type from Zod */
// prettier-ignore
export function ZodFromZod<Type extends object>(type: Type): TZodFromZod<Type> {
return (Guard.IsZod(type) ? type : z.never()) as never
export function ZodFromZod<Type extends z.ZodTypeAny | z.ZodEffects<any>>(type: Type): TZodFromZod<Type> {
return type as never
}

View File

@@ -32,15 +32,15 @@ import { type TZodFromValibot, ZodFromValibot } from './zod-from-valibot'
import { type TZodFromZod, ZodFromZod } from './zod-from-zod'
import { type TSyntaxOptions } from '../options'
import { type TParameter, type TContextFromParameter, ContextFromParameter } from '../typebox/typebox'
import * as g from '../guard'
import * as z from 'zod'
import { TParameter, TContextFromParameter, ContextFromParameter } from '../typebox/typebox'
// ------------------------------------------------------------------
// Zod
// ------------------------------------------------------------------
/** Creates a Zod type from Syntax or another Type */
/** Creates a Zod type by mapping from a remote Type */
// prettier-ignore
export type TZod<Parameter extends TParameter, Type extends object | string, Result extends z.ZodTypeAny | z.ZodEffects<any> = (
Type extends g.SyntaxType ? TZodFromSyntax<TContextFromParameter<Parameter>, Type> :
@@ -50,13 +50,13 @@ export type TZod<Parameter extends TParameter, Type extends object | string, Res
z.ZodNever
)> = Result
/** Creates a Zod type from Syntax or another Type */
/** Creates a Zod type by mapping from a remote Type */
export function Zod<Parameter extends TParameter, Type extends string>(parameter: Parameter, type: Type, options?: TSyntaxOptions): TZod<Parameter, Type>
/** Creates a Zod type from Syntax or another Type */
/** Creates a Zod type by mapping from a remote Type */
export function Zod<Type extends string>(type: Type, options?: TSyntaxOptions): TZod<{}, Type>
/** Creates a Zod type from Syntax or another Type */
/** Creates a Zod type by mapping from a remote Type */
export function Zod<Type extends object>(type: Type, options?: TSyntaxOptions): TZod<{}, Type>
/** Creates a Zod type from Syntax or another Type */
/** Creates a Zod type by mapping from a remote Type */
// prettier-ignore
export function Zod(...args: any[]): never {
const [parameter, type, options] = g.Signature(args)

View File

@@ -36,6 +36,7 @@ function shouldSkipSpecifier(captured: string) {
const specifier = captured.slice(1, captured.length - 1)
return (
specifier.includes('.mjs') || // mitigate duplicate rewrite
specifier.startsWith("@sinclair/parsebox") ||
specifier.startsWith("@sinclair/typebox") ||
specifier.startsWith("valibot") ||
specifier.startsWith("zod")

View File

@@ -89,6 +89,7 @@ function resolveMetadata() {
author: packageJson.author,
license: packageJson.license,
repository: packageJson.repository,
// dependencies: packageJson.dependencies,
peerDependencies: packageJson.peerDependencies,
optionalDependencies: packageJson.optionalDependencies,
// flagged by socket.dev if not present