Revision 0.8.0 (#9)

- Rename to TypeMap
This commit is contained in:
sinclairzx81
2025-01-26 03:27:38 +09:00
committed by GitHub
parent d24876b2ac
commit 5ce19b2f4f
52 changed files with 3769 additions and 1228 deletions

Binary file not shown.

BIN
design/typemap.blend Normal file

Binary file not shown.

BIN
design/typemap.blend1 Normal file

Binary file not shown.

BIN
design/typescript.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 56 KiB

View File

@@ -1,23 +1,25 @@
import { Box } from '@sinclair/typebox-adapter'
import * as v from 'valibot'
import * as z from 'zod'
import { TypeBox, Zod, Valibot } from '@sinclair/typemap'
// Valibot to TypeBox (Runtime)
// const T: TObject<{ ... }>
const V = Box(
v.object({
x: v.number(),
y: v.number(),
z: v.number(),
}),
)
const T = TypeBox(`{
x: number,
y: number,
z: number
}`)
// Zod to TypeBox (Static)
// const V: ObjectSchema<{ ... }>
const Z = Box(
z.object({
a: z.string(),
b: z.string(),
c: z.string(),
}),
)
const V = Valibot(`{
x: number,
y: number,
z: number
}`)
// const Z: ZodObject<{ ... }>
const Z = Zod(`{
x: number,
y: number,
z: number
}`)

View File

@@ -1,345 +1,345 @@
/*--------------------------------------------------------------------------
// /*--------------------------------------------------------------------------
@sinclair/typebox-adapter
// @sinclair/typemap
The MIT License (MIT)
// The MIT License (MIT)
Copyright (c) 2024 Haydn Paterson (sinclair) <haydn.developer@gmail.com>
// Copyright (c) 2024 Haydn Paterson (sinclair) <haydn.developer@gmail.com>
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
// 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 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.
// 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 { Schema as et } from '@effect/schema/Schema'
import { Schema as es } from '@effect/schema'
import * as ast from '@effect/schema/AST'
import * as tb from '@sinclair/typebox'
// import { Schema as et } from '@effect/schema/Schema'
// import { Schema as es } from '@effect/schema'
// import * as ast from '@effect/schema/AST'
// import * as tb from '@sinclair/typebox'
// ------------------------------------------------------------------
// Effect Guard
// ------------------------------------------------------------------
function IsBigInt(type: ast.Annotated) {
return type.annotations[ast.IdentifierAnnotationId] === 'bigint'
}
function IsDate(type: ast.Annotated) {
return type.annotations[ast.IdentifierAnnotationId] === 'Date'
}
function IsInt(type: ast.Annotated) {
return type.annotations[ast.IdentifierAnnotationId] === 'Int'
}
function IsNull(type: ast.Annotated) {
return type instanceof ast.Literal && tb.ValueGuard.IsNull(type.literal)
}
function IsOptional(type: ast.Annotated) {
return 'isOptional' in type && type.isOptional === true
}
function IsUint8Array(type: ast.Annotated) {
return type.annotations[ast.IdentifierAnnotationId] === 'Uint8Array'
}
function IsNumberFromString(type: ast.Annotated) {
return type.annotations[ast.IdentifierAnnotationId] === 'NumberFromString'
}
function IsArray(type: ast.Annotated): type is ast.TupleType {
return type instanceof ast.TupleType && type.rest.length > 0 && type.elements.length === 0
}
function IsTuple(type: ast.Annotated): type is ast.TupleType {
return type instanceof ast.TupleType && type.rest.length === 0
}
// ------------------------------------------------------------------
// Any
// ------------------------------------------------------------------
type TFromAny<_Type> = tb.TAny
function FromAny(_type: ast.AnyKeyword): tb.TSchema {
return tb.Any()
}
// ------------------------------------------------------------------
// Array
// ------------------------------------------------------------------
type TFromArray<Type, Result extends tb.TSchema = tb.TArray<TFromType<Type>>> = Result
function FromArray(_type: ast.TupleType): tb.TSchema {
return tb.Array(FromType(_type.rest[0].type))
}
// ------------------------------------------------------------------
// BigInt
// ------------------------------------------------------------------
type TFromBigInt<_Type> = tb.TBigInt
function FromBigInt(_type: ast.Annotated): tb.TSchema {
return tb.BigInt()
}
// ------------------------------------------------------------------
// Boolean
// ------------------------------------------------------------------
type TFromBoolean<_Type> = tb.TBoolean
function FromBoolean(_type: ast.BooleanKeyword): tb.TSchema {
return tb.Boolean()
}
// ------------------------------------------------------------------
// Date
// ------------------------------------------------------------------
type TFromDate<_Type> = tb.TDate
function FromDate(_type: ast.Annotated): tb.TSchema {
return tb.Date()
}
// ------------------------------------------------------------------
// Integer
// ------------------------------------------------------------------
type TFromInteger<_Type> = tb.TNumber
function FromInteger(_type: ast.Annotated): tb.TSchema {
return tb.Number({ multipleOf: 1 })
}
// ------------------------------------------------------------------
// Literal: Effect literal types may be union
// ------------------------------------------------------------------
// prettier-ignore
type TFromLiteral<Value extends readonly unknown[], Result extends tb.TSchema[] = []> = (
Value extends [infer Left extends unknown, ...infer Right extends unknown[]]
? (
Left extends tb.TLiteralValue
? TFromLiteral<Right, [...Result, tb.TLiteral<Left>]>
: TFromLiteral<Right, [...Result]>
) : tb.TUnionEvaluated<Result>
)
function FromLiteral(type: ast.Literal): tb.TSchema {
return tb.KindGuard.IsLiteralValue(type.literal) ? tb.Literal(type.literal) : tb.Unknown()
}
// ------------------------------------------------------------------
// FromNever
// ------------------------------------------------------------------
function FromNever(_type: ast.NeverKeyword): tb.TSchema {
return tb.Never()
}
type TFromNever<_Type, Result extends tb.TSchema = tb.TNever> = Result
// ------------------------------------------------------------------
// NullishOr
// ------------------------------------------------------------------
type TFromNullishOr<Type, Result extends tb.TSchema = tb.TUnion<[TFromType<Type>, tb.TNull, tb.TUndefined]>> = Result
// ------------------------------------------------------------------
// NullOr
// ------------------------------------------------------------------
type TFromNullOr<Type, Result extends tb.TSchema = tb.TUnion<[TFromType<Type>, tb.TNull]>> = Result
// ------------------------------------------------------------------
// Null
// ------------------------------------------------------------------
type TFromNull<_Type> = tb.TNull
function FromNull(_type: ast.Annotated): tb.TSchema {
return tb.Null()
}
// ------------------------------------------------------------------
// Number
// ------------------------------------------------------------------
type TFromNumber<_Type> = tb.TNumber
function FromNumber(_type: ast.NumberKeyword): tb.TSchema {
return tb.Number()
}
// ------------------------------------------------------------------
// Object
// ------------------------------------------------------------------
type TFromObject<_Type> = tb.TObject
function FromObject(type: ast.ObjectKeyword): tb.TSchema {
return tb.Object({})
}
// ------------------------------------------------------------------
// Optional
// ------------------------------------------------------------------
type TFromOptional<Type, Mapped extends tb.TSchema = TFromType<Type>, Result = tb.TOptional<Mapped>> = Result
function FromOptional(type: ast.Annotated): tb.TSchema {
return tb.Optional(FromType(type))
}
// ------------------------------------------------------------------
// Record
// ------------------------------------------------------------------
type TFromRecord<Key, Value> = tb.TRecordOrObject<TFromType<Key>, TFromType<Value>>
// ------------------------------------------------------------------
// SchemaClass: TypeLiteral
// ------------------------------------------------------------------
type TFromSchemaClass<Properties, Result = tb.TUnsafe<Properties>> = Result
// ------------------------------------------------------------------
// String
// ------------------------------------------------------------------
type TFromString<_Type> = tb.TString
function FromString(_type: ast.Annotated): tb.TSchema {
return tb.String()
}
// ------------------------------------------------------------------
// Struct
// ------------------------------------------------------------------
// prettier-ignore
type TFromStruct<Properties extends Record<PropertyKey, unknown>,
Mapped extends tb.TProperties = { [Key in keyof Properties]: TFromType<Properties[Key]> },
Result = tb.TObject<Mapped>
> = Result
// prettier-ignore
function FromStruct(type: ast.TypeLiteral): tb.TSchema {
const properties = type.propertySignatures.reduce((result, property) => {
const mappedProperty = property.isOptional ? tb.Optional(FromType(property.type)) : FromType(property.type)
return { ...result, [property.name]: mappedProperty }
}, {} as tb.TProperties) as tb.TProperties
return tb.Object(properties)
}
// ------------------------------------------------------------------
// Symbol
// ------------------------------------------------------------------
type TFromSymbol<_Type> = tb.TSymbol
function FromSymbol(_type: ast.Annotated): tb.TSchema {
return tb.Symbol()
}
// ------------------------------------------------------------------
// Tuple
// ------------------------------------------------------------------
// prettier-ignore
type TFromTuple<Types extends readonly unknown[], Result extends tb.TSchema[] = []> = (
Types extends [infer Left extends unknown, ...infer Right extends unknown[]]
? TFromTuple<Right, [...Result, TFromType<Left>]>
: tb.TTuple<Result>
)
function FromTuple(type: ast.TupleType): tb.TSchema {
return tb.Tuple(type.elements.map((type) => FromType(type.type)))
}
// ------------------------------------------------------------------
// UndefinedOr
// ------------------------------------------------------------------
type TFromUndefinedOr<Type, Result extends tb.TSchema = tb.TUnion<[TFromType<Type>, tb.TUndefined]>> = Result
// ------------------------------------------------------------------
// Undefined
// ------------------------------------------------------------------
type TFromUndefined<_Type> = tb.TUndefined
function FromUndefined(_type: ast.Annotated): tb.TSchema {
return tb.Undefined()
}
// ------------------------------------------------------------------
// Uint8Array
// ------------------------------------------------------------------
type TFromUint8Array<_Type> = tb.TUint8Array
function FromUint8Array(_type: ast.Annotated): tb.TSchema {
return tb.Uint8Array()
}
// ------------------------------------------------------------------
// Unknown
// ------------------------------------------------------------------
type TFromUnknown<_Type> = tb.TUnknown
function FromUnknown(_type: ast.Annotated): tb.TSchema {
return tb.Unknown()
}
// ------------------------------------------------------------------
// Union
// ------------------------------------------------------------------
// prettier-ignore
type TFromUnion<Variants extends readonly unknown[], Result extends tb.TSchema[] = []> = (
Variants extends [infer Left extends unknown, ...infer Right extends unknown[]]
? TFromUnion<Right, [...Result, TFromType<Left>]>
: tb.TUnionEvaluated<Result>
)
function FromUnion(type: ast.Union): tb.TSchema {
return tb.Union(type.types.map((type) => FromType(type)))
}
// ------------------------------------------------------------------
// Void
// ------------------------------------------------------------------
type TFromVoid<_Type> = tb.TVoid
function FromVoid(_type: ast.VoidKeyword): tb.TSchema {
return tb.Void()
}
// ------------------------------------------------------------------
// Type
//
// Note: Type differentition in Effect is quite challenging as the
// library doesn't provide discriminable types in all cases. An
// example would be Number and Integer where both are observed
// as Number. Unions also provide challenges for NullishOr and
// similar types. The order in which we resolve is important.
// ------------------------------------------------------------------
// prettier-ignore
type TFromType<Type> = (
Type extends es.optional<infer Type> ? TFromOptional<Type> :
Type extends es.Tuple<infer Types> ? TFromTuple<Types> :
Type extends es.Record$<infer Key, infer Value> ? TFromRecord<Key, Value> :
Type extends es.Array$<infer Type> ? TFromArray<Type> :
Type extends es.Date ? TFromDate<Type> :
Type extends es.Struct<infer Properties> ? TFromStruct<Properties> :
Type extends es.SchemaClass<infer Properties> ? TFromSchemaClass<Properties> :
Type extends es.Literal<infer Value> ? TFromLiteral<Value> :
Type extends es.Int ? TFromInteger<Type> :
Type extends es.BigInt ? TFromBigInt<Type> :
Type extends es.Boolean ? TFromBoolean<Type> :
Type extends es.Object ? TFromObject<Type> :
Type extends es.Never ? TFromNever<Type> :
Type extends es.Null ? TFromNull<Type> :
Type extends es.Number ? TFromNumber<Type> :
Type extends es.String ? TFromString<Type> :
Type extends es.Symbol ? TFromSymbol<Type> :
Type extends et<Uint8Array, any> ? TFromUint8Array<Type> :
Type extends es.Undefined ? TFromUndefined<Type> :
Type extends es.Void ? TFromVoid<Type> :
// Union-Like
Type extends es.UndefinedOr<infer Type> ? TFromUndefinedOr<Type> :
Type extends es.NullishOr<infer Type> ? TFromNullishOr<Type> :
Type extends es.NullOr<infer Type> ? TFromNullOr<Type> :
Type extends es.Union<infer Variants> ? TFromUnion<Variants> :
// Fallthrough
Type extends es.Unknown ? TFromUnknown<Type> :
Type extends es.Any ? TFromAny<Type> :
tb.TUnknown
)
// prettier-ignore
function FromType(type: ast.Annotated): tb.TSchema {
const schema = (
// Non-Differentiable
IsOptional(type) ? FromOptional(type) :
IsArray(type) ? FromArray(type) :
IsBigInt(type) ? FromBigInt(type) :
IsDate(type) ? FromDate(type) :
IsInt(type) ? FromInteger(type) :
IsNull(type) ? FromNull(type) :
IsTuple(type) ? FromTuple(type) :
IsUint8Array(type) ? FromUint8Array(type) :
// Differentiable
type instanceof ast.AnyKeyword ? FromAny(type) :
type instanceof ast.BooleanKeyword ? FromBoolean(type) :
type instanceof ast.Literal ? FromLiteral(type) :
type instanceof ast.NeverKeyword ? FromNever(type) :
type instanceof ast.NumberKeyword ? FromNumber(type) :
type instanceof ast.ObjectKeyword ? FromObject(type) :
type instanceof ast.StringKeyword ? FromString(type) :
type instanceof ast.SymbolKeyword ? FromSymbol(type) :
type instanceof ast.TypeLiteral ? FromStruct(type) :
type instanceof ast.UndefinedKeyword ? FromUndefined(type) :
type instanceof ast.UnknownKeyword ? FromUnknown(type) :
type instanceof ast.Union ? FromUnion(type) :
type instanceof ast.VoidKeyword ? FromVoid(type) :
tb.Unknown()
)
return schema
}
// ------------------------------------------------------------------
// Box
// ------------------------------------------------------------------
/** Converts an Effect Type to a TypeBox Type */
// prettier-ignore
export type TBox<Type extends unknown> = (
Type extends es.Any ? TFromType<Type> : undefined
)
/** Converts an Effect Type to a TypeBox Type */
// prettier-ignore
export function Box<Type>(type: Type): TBox<Type> {
return (
es.isSchema(type)
? FromType(type.ast)
: undefined
) as never
}
// // ------------------------------------------------------------------
// // Effect Guard
// // ------------------------------------------------------------------
// function IsBigInt(type: ast.Annotated) {
// return type.annotations[ast.IdentifierAnnotationId] === 'bigint'
// }
// function IsDate(type: ast.Annotated) {
// return type.annotations[ast.IdentifierAnnotationId] === 'Date'
// }
// function IsInt(type: ast.Annotated) {
// return type.annotations[ast.IdentifierAnnotationId] === 'Int'
// }
// function IsNull(type: ast.Annotated) {
// return type instanceof ast.Literal && tb.ValueGuard.IsNull(type.literal)
// }
// function IsOptional(type: ast.Annotated) {
// return 'isOptional' in type && type.isOptional === true
// }
// function IsUint8Array(type: ast.Annotated) {
// return type.annotations[ast.IdentifierAnnotationId] === 'Uint8Array'
// }
// function IsNumberFromString(type: ast.Annotated) {
// return type.annotations[ast.IdentifierAnnotationId] === 'NumberFromString'
// }
// function IsArray(type: ast.Annotated): type is ast.TupleType {
// return type instanceof ast.TupleType && type.rest.length > 0 && type.elements.length === 0
// }
// function IsTuple(type: ast.Annotated): type is ast.TupleType {
// return type instanceof ast.TupleType && type.rest.length === 0
// }
// // ------------------------------------------------------------------
// // Any
// // ------------------------------------------------------------------
// type TFromAny<_Type> = tb.TAny
// function FromAny(_type: ast.AnyKeyword): tb.TSchema {
// return tb.Any()
// }
// // ------------------------------------------------------------------
// // Array
// // ------------------------------------------------------------------
// type TFromArray<Type, Result extends tb.TSchema = tb.TArray<TFromType<Type>>> = Result
// function FromArray(_type: ast.TupleType): tb.TSchema {
// return tb.Array(FromType(_type.rest[0].type))
// }
// // ------------------------------------------------------------------
// // BigInt
// // ------------------------------------------------------------------
// type TFromBigInt<_Type> = tb.TBigInt
// function FromBigInt(_type: ast.Annotated): tb.TSchema {
// return tb.BigInt()
// }
// // ------------------------------------------------------------------
// // Boolean
// // ------------------------------------------------------------------
// type TFromBoolean<_Type> = tb.TBoolean
// function FromBoolean(_type: ast.BooleanKeyword): tb.TSchema {
// return tb.Boolean()
// }
// // ------------------------------------------------------------------
// // Date
// // ------------------------------------------------------------------
// type TFromDate<_Type> = tb.TDate
// function FromDate(_type: ast.Annotated): tb.TSchema {
// return tb.Date()
// }
// // ------------------------------------------------------------------
// // Integer
// // ------------------------------------------------------------------
// type TFromInteger<_Type> = tb.TNumber
// function FromInteger(_type: ast.Annotated): tb.TSchema {
// return tb.Number({ multipleOf: 1 })
// }
// // ------------------------------------------------------------------
// // Literal: Effect literal types may be union
// // ------------------------------------------------------------------
// // prettier-ignore
// type TFromLiteral<Value extends readonly unknown[], Result extends tb.TSchema[] = []> = (
// Value extends [infer Left extends unknown, ...infer Right extends unknown[]]
// ? (
// Left extends tb.TLiteralValue
// ? TFromLiteral<Right, [...Result, tb.TLiteral<Left>]>
// : TFromLiteral<Right, [...Result]>
// ) : tb.TUnionEvaluated<Result>
// )
// function FromLiteral(type: ast.Literal): tb.TSchema {
// return tb.KindGuard.IsLiteralValue(type.literal) ? tb.Literal(type.literal) : tb.Unknown()
// }
// // ------------------------------------------------------------------
// // FromNever
// // ------------------------------------------------------------------
// function FromNever(_type: ast.NeverKeyword): tb.TSchema {
// return tb.Never()
// }
// type TFromNever<_Type, Result extends tb.TSchema = tb.TNever> = Result
// // ------------------------------------------------------------------
// // NullishOr
// // ------------------------------------------------------------------
// type TFromNullishOr<Type, Result extends tb.TSchema = tb.TUnion<[TFromType<Type>, tb.TNull, tb.TUndefined]>> = Result
// // ------------------------------------------------------------------
// // NullOr
// // ------------------------------------------------------------------
// type TFromNullOr<Type, Result extends tb.TSchema = tb.TUnion<[TFromType<Type>, tb.TNull]>> = Result
// // ------------------------------------------------------------------
// // Null
// // ------------------------------------------------------------------
// type TFromNull<_Type> = tb.TNull
// function FromNull(_type: ast.Annotated): tb.TSchema {
// return tb.Null()
// }
// // ------------------------------------------------------------------
// // Number
// // ------------------------------------------------------------------
// type TFromNumber<_Type> = tb.TNumber
// function FromNumber(_type: ast.NumberKeyword): tb.TSchema {
// return tb.Number()
// }
// // ------------------------------------------------------------------
// // Object
// // ------------------------------------------------------------------
// type TFromObject<_Type> = tb.TObject
// function FromObject(type: ast.ObjectKeyword): tb.TSchema {
// return tb.Object({})
// }
// // ------------------------------------------------------------------
// // Optional
// // ------------------------------------------------------------------
// type TFromOptional<Type, Mapped extends tb.TSchema = TFromType<Type>, Result = tb.TOptional<Mapped>> = Result
// function FromOptional(type: ast.Annotated): tb.TSchema {
// return tb.Optional(FromType(type))
// }
// // ------------------------------------------------------------------
// // Record
// // ------------------------------------------------------------------
// type TFromRecord<Key, Value> = tb.TRecordOrObject<TFromType<Key>, TFromType<Value>>
// // ------------------------------------------------------------------
// // SchemaClass: TypeLiteral
// // ------------------------------------------------------------------
// type TFromSchemaClass<Properties, Result = tb.TUnsafe<Properties>> = Result
// // ------------------------------------------------------------------
// // String
// // ------------------------------------------------------------------
// type TFromString<_Type> = tb.TString
// function FromString(_type: ast.Annotated): tb.TSchema {
// return tb.String()
// }
// // ------------------------------------------------------------------
// // Struct
// // ------------------------------------------------------------------
// // prettier-ignore
// type TFromStruct<Properties extends Record<PropertyKey, unknown>,
// Mapped extends tb.TProperties = { [Key in keyof Properties]: TFromType<Properties[Key]> },
// Result = tb.TObject<Mapped>
// > = Result
// // prettier-ignore
// function FromStruct(type: ast.TypeLiteral): tb.TSchema {
// const properties = type.propertySignatures.reduce((result, property) => {
// const mappedProperty = property.isOptional ? tb.Optional(FromType(property.type)) : FromType(property.type)
// return { ...result, [property.name]: mappedProperty }
// }, {} as tb.TProperties) as tb.TProperties
// return tb.Object(properties)
// }
// // ------------------------------------------------------------------
// // Symbol
// // ------------------------------------------------------------------
// type TFromSymbol<_Type> = tb.TSymbol
// function FromSymbol(_type: ast.Annotated): tb.TSchema {
// return tb.Symbol()
// }
// // ------------------------------------------------------------------
// // Tuple
// // ------------------------------------------------------------------
// // prettier-ignore
// type TFromTuple<Types extends readonly unknown[], Result extends tb.TSchema[] = []> = (
// Types extends [infer Left extends unknown, ...infer Right extends unknown[]]
// ? TFromTuple<Right, [...Result, TFromType<Left>]>
// : tb.TTuple<Result>
// )
// function FromTuple(type: ast.TupleType): tb.TSchema {
// return tb.Tuple(type.elements.map((type) => FromType(type.type)))
// }
// // ------------------------------------------------------------------
// // UndefinedOr
// // ------------------------------------------------------------------
// type TFromUndefinedOr<Type, Result extends tb.TSchema = tb.TUnion<[TFromType<Type>, tb.TUndefined]>> = Result
// // ------------------------------------------------------------------
// // Undefined
// // ------------------------------------------------------------------
// type TFromUndefined<_Type> = tb.TUndefined
// function FromUndefined(_type: ast.Annotated): tb.TSchema {
// return tb.Undefined()
// }
// // ------------------------------------------------------------------
// // Uint8Array
// // ------------------------------------------------------------------
// type TFromUint8Array<_Type> = tb.TUint8Array
// function FromUint8Array(_type: ast.Annotated): tb.TSchema {
// return tb.Uint8Array()
// }
// // ------------------------------------------------------------------
// // Unknown
// // ------------------------------------------------------------------
// type TFromUnknown<_Type> = tb.TUnknown
// function FromUnknown(_type: ast.Annotated): tb.TSchema {
// return tb.Unknown()
// }
// // ------------------------------------------------------------------
// // Union
// // ------------------------------------------------------------------
// // prettier-ignore
// type TFromUnion<Variants extends readonly unknown[], Result extends tb.TSchema[] = []> = (
// Variants extends [infer Left extends unknown, ...infer Right extends unknown[]]
// ? TFromUnion<Right, [...Result, TFromType<Left>]>
// : tb.TUnionEvaluated<Result>
// )
// function FromUnion(type: ast.Union): tb.TSchema {
// return tb.Union(type.types.map((type) => FromType(type)))
// }
// // ------------------------------------------------------------------
// // Void
// // ------------------------------------------------------------------
// type TFromVoid<_Type> = tb.TVoid
// function FromVoid(_type: ast.VoidKeyword): tb.TSchema {
// return tb.Void()
// }
// // ------------------------------------------------------------------
// // Type
// //
// // Note: Type differentition in Effect is quite challenging as the
// // library doesn't provide discriminable types in all cases. An
// // example would be Number and Integer where both are observed
// // as Number. Unions also provide challenges for NullishOr and
// // similar types. The order in which we resolve is important.
// // ------------------------------------------------------------------
// // prettier-ignore
// type TFromType<Type> = (
// Type extends es.optional<infer Type> ? TFromOptional<Type> :
// Type extends es.Tuple<infer Types> ? TFromTuple<Types> :
// Type extends es.Record$<infer Key, infer Value> ? TFromRecord<Key, Value> :
// Type extends es.Array$<infer Type> ? TFromArray<Type> :
// Type extends es.Date ? TFromDate<Type> :
// Type extends es.Struct<infer Properties> ? TFromStruct<Properties> :
// Type extends es.SchemaClass<infer Properties> ? TFromSchemaClass<Properties> :
// Type extends es.Literal<infer Value> ? TFromLiteral<Value> :
// Type extends es.Int ? TFromInteger<Type> :
// Type extends es.BigInt ? TFromBigInt<Type> :
// Type extends es.Boolean ? TFromBoolean<Type> :
// Type extends es.Object ? TFromObject<Type> :
// Type extends es.Never ? TFromNever<Type> :
// Type extends es.Null ? TFromNull<Type> :
// Type extends es.Number ? TFromNumber<Type> :
// Type extends es.String ? TFromString<Type> :
// Type extends es.Symbol ? TFromSymbol<Type> :
// Type extends et<Uint8Array, any> ? TFromUint8Array<Type> :
// Type extends es.Undefined ? TFromUndefined<Type> :
// Type extends es.Void ? TFromVoid<Type> :
// // Union-Like
// Type extends es.UndefinedOr<infer Type> ? TFromUndefinedOr<Type> :
// Type extends es.NullishOr<infer Type> ? TFromNullishOr<Type> :
// Type extends es.NullOr<infer Type> ? TFromNullOr<Type> :
// Type extends es.Union<infer Variants> ? TFromUnion<Variants> :
// // Fallthrough
// Type extends es.Unknown ? TFromUnknown<Type> :
// Type extends es.Any ? TFromAny<Type> :
// tb.TUnknown
// )
// // prettier-ignore
// function FromType(type: ast.Annotated): tb.TSchema {
// const schema = (
// // Non-Differentiable
// IsOptional(type) ? FromOptional(type) :
// IsArray(type) ? FromArray(type) :
// IsBigInt(type) ? FromBigInt(type) :
// IsDate(type) ? FromDate(type) :
// IsInt(type) ? FromInteger(type) :
// IsNull(type) ? FromNull(type) :
// IsTuple(type) ? FromTuple(type) :
// IsUint8Array(type) ? FromUint8Array(type) :
// // Differentiable
// type instanceof ast.AnyKeyword ? FromAny(type) :
// type instanceof ast.BooleanKeyword ? FromBoolean(type) :
// type instanceof ast.Literal ? FromLiteral(type) :
// type instanceof ast.NeverKeyword ? FromNever(type) :
// type instanceof ast.NumberKeyword ? FromNumber(type) :
// type instanceof ast.ObjectKeyword ? FromObject(type) :
// type instanceof ast.StringKeyword ? FromString(type) :
// type instanceof ast.SymbolKeyword ? FromSymbol(type) :
// type instanceof ast.TypeLiteral ? FromStruct(type) :
// type instanceof ast.UndefinedKeyword ? FromUndefined(type) :
// type instanceof ast.UnknownKeyword ? FromUnknown(type) :
// type instanceof ast.Union ? FromUnion(type) :
// type instanceof ast.VoidKeyword ? FromVoid(type) :
// tb.Unknown()
// )
// return schema
// }
// // ------------------------------------------------------------------
// // Box
// // ------------------------------------------------------------------
// /** Converts an Effect Type to a TypeBox Type */
// // prettier-ignore
// export type TBox<Type extends unknown> = (
// Type extends es.Any ? TFromType<Type> : undefined
// )
// /** Converts an Effect Type to a TypeBox Type */
// // prettier-ignore
// export function Box<Type>(type: Type): TBox<Type> {
// return (
// es.isSchema(type)
// ? FromType(type.ast)
// : undefined
// ) as never
// }

View File

@@ -1 +0,0 @@
export * as Effect from './effect'

View File

@@ -19,14 +19,12 @@ export async function clean() {
export async function start() {
await shell('hammer run example/index.ts --dist target/example')
}
// -------------------------------------------------------------------------------
// Format
// -------------------------------------------------------------------------------
export async function format() {
await shell('prettier --no-semi --single-quote --print-width 240 --trailing-comma all --write test src example/index.ts')
}
// ------------------------------------------------------------------
// Test
// ------------------------------------------------------------------
@@ -39,7 +37,7 @@ export async function test(filter = '') {
// ------------------------------------------------------------------
export async function build_check(target = 'target/build') {
const { version } = JSON.parse(Fs.readFileSync('package.json', 'utf8'))
await shell(`cd ${target} && attw sinclair-typebox-adapter-${version}.tgz`)
await shell(`cd ${target} && attw sinclair-typemap-${version}.tgz`)
}
export async function build(target = 'target/build') {
await test()
@@ -60,7 +58,7 @@ export async function build(target = 'target/build') {
export async function publish(otp, target = 'target/build') {
const { version } = JSON.parse(Fs.readFileSync('package.json', 'utf8'))
if(version.includes('-dev')) throw Error(`package version should not include -dev specifier`)
await shell(`cd ${target} && npm publish sinclair-typebox-adapter-${version}.tgz --access=public --otp ${otp}`)
await shell(`cd ${target} && npm publish sinclair-typemap-${version}.tgz --access=public --otp ${otp}`)
await shell(`git tag ${version}`)
await shell(`git push origin ${version}`)
}
@@ -70,5 +68,5 @@ export async function publish(otp, target = 'target/build') {
export async function publish_dev(otp, target = 'target/build') {
const { version } = JSON.parse(Fs.readFileSync(`${target}/package.json`, 'utf8'))
if(!version.includes('-dev')) throw Error(`development package version should include -dev specifier`)
await shell(`cd ${target} && npm publish sinclair-typebox-adapter-${version}.tgz --access=public --otp ${otp} --tag dev`)
await shell(`cd ${target} && npm publish sinclair-typemap-${version}.tgz --access=public --otp ${otp} --tag dev`)
}

View File

@@ -1,4 +1,4 @@
@sinclair/typebox-adapter
@sinclair/typemap
The MIT License (MIT)

318
package-lock.json generated
View File

@@ -1,20 +1,15 @@
{
"name": "@sinclair/typebox-adapter",
"version": "0.9.1",
"name": "@sinclair/typemap",
"version": "0.8.0",
"lockfileVersion": 2,
"requires": true,
"packages": {
"": {
"name": "@sinclair/typebox-adapter",
"version": "0.9.1",
"name": "@sinclair/typemap",
"version": "0.8.0",
"license": "MIT",
"dependencies": {
"valibot": "^1.0.0-beta.13",
"zod": "^3.24.1"
},
"devDependencies": {
"@arethetypeswrong/cli": "^0.17.2",
"@effect/schema": "^0.75.5",
"@sinclair/hammer": "^0.18.0",
"@types/mocha": "^10.0.10",
"@types/node": "^22.10.2",
@@ -22,12 +17,10 @@
"prettier": "^3.4.2",
"typescript": "^5.7.2"
},
"optionalDependencies": {
"peerDependencies": {
"@sinclair/typebox": "^0.34.14",
"valibot": "^1.0.0-beta.13",
"zod": "^3.24.1"
},
"peerDependencies": {
"@sinclair/typebox": "^0.34.14"
}
},
"node_modules/@andrewbranch/untar.js": {
@@ -98,18 +91,6 @@
"node": ">=0.1.90"
}
},
"node_modules/@effect/schema": {
"version": "0.75.5",
"resolved": "https://registry.npmjs.org/@effect/schema/-/schema-0.75.5.tgz",
"integrity": "sha512-TQInulTVCuF+9EIbJpyLP6dvxbQJMphrnRqgexm/Ze39rSjfhJuufF7XvU3SxTgg3HnL7B/kpORTJbHhlE6thw==",
"dev": true,
"dependencies": {
"fast-check": "^3.21.0"
},
"peerDependencies": {
"effect": "^3.9.2"
}
},
"node_modules/@esbuild/linux-loong64": {
"version": "0.15.7",
"resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.15.7.tgz",
@@ -213,9 +194,9 @@
"dev": true
},
"node_modules/@types/node": {
"version": "22.10.7",
"resolved": "https://registry.npmjs.org/@types/node/-/node-22.10.7.tgz",
"integrity": "sha512-V09KvXxFiutGp6B7XkpaDXlNadZxrzajcY50EuoLIpQ6WWYCSvf19lVIazzfIzQvhUN2HjX12spLojTnhuKlGg==",
"version": "22.10.9",
"resolved": "https://registry.npmjs.org/@types/node/-/node-22.10.9.tgz",
"integrity": "sha512-Ir6hwgsKyNESl/gLOcEz3krR4CBGgliDqBQ2ma4wIhEx0w+xnoeTq3tdrNw15kU3SxogDjOgv9sqdtLW8mIHaw==",
"dev": true,
"dependencies": {
"undici-types": "~6.20.0"
@@ -579,16 +560,6 @@
"integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==",
"dev": true
},
"node_modules/effect": {
"version": "3.12.6",
"resolved": "https://registry.npmjs.org/effect/-/effect-3.12.6.tgz",
"integrity": "sha512-4gNxRpXduuvVv03528sPLGglkCAX9szGBUA6oIG3YL+6ap82JmbVp4OIa+xTurype+H9b4/I4M2ubxDxJJ01Og==",
"dev": true,
"peer": true,
"dependencies": {
"fast-check": "^3.23.1"
}
},
"node_modules/emoji-regex": {
"version": "8.0.0",
"resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
@@ -990,28 +961,6 @@
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/fast-check": {
"version": "3.23.2",
"resolved": "https://registry.npmjs.org/fast-check/-/fast-check-3.23.2.tgz",
"integrity": "sha512-h5+1OzzfCC3Ef7VbtKdcv7zsstUQwUDlYpUTvjeUsJAssPgLn7QzbboPtL5ro04Mq0rPOsMzl7q5hIbRs2wD1A==",
"dev": true,
"funding": [
{
"type": "individual",
"url": "https://github.com/sponsors/dubzzz"
},
{
"type": "opencollective",
"url": "https://opencollective.com/fast-check"
}
],
"dependencies": {
"pure-rand": "^6.1.0"
},
"engines": {
"node": ">=8.0.0"
}
},
"node_modules/fflate": {
"version": "0.8.2",
"resolved": "https://registry.npmjs.org/fflate/-/fflate-0.8.2.tgz",
@@ -1377,9 +1326,9 @@
}
},
"node_modules/mocha": {
"version": "11.0.1",
"resolved": "https://registry.npmjs.org/mocha/-/mocha-11.0.1.tgz",
"integrity": "sha512-+3GkODfsDG71KSCQhc4IekSW+ItCK/kiez1Z28ksWvYhKXV/syxMlerR/sC7whDp7IyreZ4YxceMLdTs5hQE8A==",
"version": "11.1.0",
"resolved": "https://registry.npmjs.org/mocha/-/mocha-11.1.0.tgz",
"integrity": "sha512-8uJR5RTC2NgpY3GrYcgpZrsEd9zKbPDpob1RezyR2upGHRQtHWofmzTMzTMSV6dru3tj5Ukt0+Vnq1qhFEEwAg==",
"dev": true,
"dependencies": {
"ansi-colors": "^4.1.3",
@@ -1399,8 +1348,8 @@
"strip-json-comments": "^3.1.1",
"supports-color": "^8.1.1",
"workerpool": "^6.5.1",
"yargs": "^16.2.0",
"yargs-parser": "^20.2.9",
"yargs": "^17.7.2",
"yargs-parser": "^21.1.1",
"yargs-unparser": "^2.0.0"
},
"bin": {
@@ -1411,6 +1360,41 @@
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
}
},
"node_modules/mocha/node_modules/ansi-regex": {
"version": "5.0.1",
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz",
"integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==",
"dev": true,
"engines": {
"node": ">=8"
}
},
"node_modules/mocha/node_modules/cliui": {
"version": "8.0.1",
"resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz",
"integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==",
"dev": true,
"dependencies": {
"string-width": "^4.2.0",
"strip-ansi": "^6.0.1",
"wrap-ansi": "^7.0.0"
},
"engines": {
"node": ">=12"
}
},
"node_modules/mocha/node_modules/strip-ansi": {
"version": "6.0.1",
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz",
"integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==",
"dev": true,
"dependencies": {
"ansi-regex": "^5.0.1"
},
"engines": {
"node": ">=8"
}
},
"node_modules/mocha/node_modules/supports-color": {
"version": "8.1.1",
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz",
@@ -1426,6 +1410,41 @@
"url": "https://github.com/chalk/supports-color?sponsor=1"
}
},
"node_modules/mocha/node_modules/wrap-ansi": {
"version": "7.0.0",
"resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz",
"integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==",
"dev": true,
"dependencies": {
"ansi-styles": "^4.0.0",
"string-width": "^4.1.0",
"strip-ansi": "^6.0.0"
},
"engines": {
"node": ">=10"
},
"funding": {
"url": "https://github.com/chalk/wrap-ansi?sponsor=1"
}
},
"node_modules/mocha/node_modules/yargs": {
"version": "17.7.2",
"resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz",
"integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==",
"dev": true,
"dependencies": {
"cliui": "^8.0.1",
"escalade": "^3.1.1",
"get-caller-file": "^2.0.5",
"require-directory": "^2.1.1",
"string-width": "^4.2.3",
"y18n": "^5.0.5",
"yargs-parser": "^21.1.1"
},
"engines": {
"node": ">=12"
}
},
"node_modules/ms": {
"version": "2.1.3",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
@@ -1594,22 +1613,6 @@
"url": "https://github.com/prettier/prettier?sponsor=1"
}
},
"node_modules/pure-rand": {
"version": "6.1.0",
"resolved": "https://registry.npmjs.org/pure-rand/-/pure-rand-6.1.0.tgz",
"integrity": "sha512-bVWawvoZoBYpp6yIoQtQXHZjmz35RSVHnUOTefl8Vcjr8snTPY1wnpSPMWekcFwbxI6gtmT7rSYPFvz71ldiOA==",
"dev": true,
"funding": [
{
"type": "individual",
"url": "https://github.com/sponsors/dubzzz"
},
{
"type": "opencollective",
"url": "https://opencollective.com/fast-check"
}
]
},
"node_modules/randombytes": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz",
@@ -1936,10 +1939,10 @@
}
},
"node_modules/valibot": {
"version": "1.0.0-beta.13",
"resolved": "https://registry.npmjs.org/valibot/-/valibot-1.0.0-beta.13.tgz",
"integrity": "sha512-WCAqfG126/nadCrK36lOgVHrYWeWJfxb52PYE48gqg/8clLTy9sWjE6v/W43cVtgR+rSt30J1IAswk6ovT48pQ==",
"optional": true,
"version": "1.0.0-beta.14",
"resolved": "https://registry.npmjs.org/valibot/-/valibot-1.0.0-beta.14.tgz",
"integrity": "sha512-tLyV2rE5QL6U29MFy3xt4AqMrn+/HErcp2ZThASnQvPMwfSozjV1uBGKIGiegtZIGjinJqn0SlBdannf18wENA==",
"peer": true,
"peerDependencies": {
"typescript": ">=5"
},
@@ -2098,12 +2101,12 @@
}
},
"node_modules/yargs-parser": {
"version": "20.2.9",
"resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.9.tgz",
"integrity": "sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==",
"version": "21.1.1",
"resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz",
"integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==",
"dev": true,
"engines": {
"node": ">=10"
"node": ">=12"
}
},
"node_modules/yargs-unparser": {
@@ -2121,6 +2124,15 @@
"node": ">=10"
}
},
"node_modules/yargs/node_modules/yargs-parser": {
"version": "20.2.9",
"resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.9.tgz",
"integrity": "sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==",
"dev": true,
"engines": {
"node": ">=10"
}
},
"node_modules/yocto-queue": {
"version": "0.1.0",
"resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz",
@@ -2137,7 +2149,7 @@
"version": "3.24.1",
"resolved": "https://registry.npmjs.org/zod/-/zod-3.24.1.tgz",
"integrity": "sha512-muH7gBL9sI1nciMZV67X5fTKKBLtwpZ5VBp1vsOQzj1MhrBZ4wlVCm3gedKZWLp0Oyel8sIGfeiz54Su+OVT+A==",
"optional": true,
"peer": true,
"funding": {
"url": "https://github.com/sponsors/colinhacks"
}
@@ -2195,15 +2207,6 @@
"dev": true,
"optional": true
},
"@effect/schema": {
"version": "0.75.5",
"resolved": "https://registry.npmjs.org/@effect/schema/-/schema-0.75.5.tgz",
"integrity": "sha512-TQInulTVCuF+9EIbJpyLP6dvxbQJMphrnRqgexm/Ze39rSjfhJuufF7XvU3SxTgg3HnL7B/kpORTJbHhlE6thw==",
"dev": true,
"requires": {
"fast-check": "^3.21.0"
}
},
"@esbuild/linux-loong64": {
"version": "0.15.7",
"resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.15.7.tgz",
@@ -2279,9 +2282,9 @@
"dev": true
},
"@types/node": {
"version": "22.10.7",
"resolved": "https://registry.npmjs.org/@types/node/-/node-22.10.7.tgz",
"integrity": "sha512-V09KvXxFiutGp6B7XkpaDXlNadZxrzajcY50EuoLIpQ6WWYCSvf19lVIazzfIzQvhUN2HjX12spLojTnhuKlGg==",
"version": "22.10.9",
"resolved": "https://registry.npmjs.org/@types/node/-/node-22.10.9.tgz",
"integrity": "sha512-Ir6hwgsKyNESl/gLOcEz3krR4CBGgliDqBQ2ma4wIhEx0w+xnoeTq3tdrNw15kU3SxogDjOgv9sqdtLW8mIHaw==",
"dev": true,
"requires": {
"undici-types": "~6.20.0"
@@ -2541,16 +2544,6 @@
"integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==",
"dev": true
},
"effect": {
"version": "3.12.6",
"resolved": "https://registry.npmjs.org/effect/-/effect-3.12.6.tgz",
"integrity": "sha512-4gNxRpXduuvVv03528sPLGglkCAX9szGBUA6oIG3YL+6ap82JmbVp4OIa+xTurype+H9b4/I4M2ubxDxJJ01Og==",
"dev": true,
"peer": true,
"requires": {
"fast-check": "^3.23.1"
}
},
"emoji-regex": {
"version": "8.0.0",
"resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
@@ -2750,15 +2743,6 @@
"integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==",
"dev": true
},
"fast-check": {
"version": "3.23.2",
"resolved": "https://registry.npmjs.org/fast-check/-/fast-check-3.23.2.tgz",
"integrity": "sha512-h5+1OzzfCC3Ef7VbtKdcv7zsstUQwUDlYpUTvjeUsJAssPgLn7QzbboPtL5ro04Mq0rPOsMzl7q5hIbRs2wD1A==",
"dev": true,
"requires": {
"pure-rand": "^6.1.0"
}
},
"fflate": {
"version": "0.8.2",
"resolved": "https://registry.npmjs.org/fflate/-/fflate-0.8.2.tgz",
@@ -3008,9 +2992,9 @@
"dev": true
},
"mocha": {
"version": "11.0.1",
"resolved": "https://registry.npmjs.org/mocha/-/mocha-11.0.1.tgz",
"integrity": "sha512-+3GkODfsDG71KSCQhc4IekSW+ItCK/kiez1Z28ksWvYhKXV/syxMlerR/sC7whDp7IyreZ4YxceMLdTs5hQE8A==",
"version": "11.1.0",
"resolved": "https://registry.npmjs.org/mocha/-/mocha-11.1.0.tgz",
"integrity": "sha512-8uJR5RTC2NgpY3GrYcgpZrsEd9zKbPDpob1RezyR2upGHRQtHWofmzTMzTMSV6dru3tj5Ukt0+Vnq1qhFEEwAg==",
"dev": true,
"requires": {
"ansi-colors": "^4.1.3",
@@ -3030,11 +3014,37 @@
"strip-json-comments": "^3.1.1",
"supports-color": "^8.1.1",
"workerpool": "^6.5.1",
"yargs": "^16.2.0",
"yargs-parser": "^20.2.9",
"yargs": "^17.7.2",
"yargs-parser": "^21.1.1",
"yargs-unparser": "^2.0.0"
},
"dependencies": {
"ansi-regex": {
"version": "5.0.1",
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz",
"integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==",
"dev": true
},
"cliui": {
"version": "8.0.1",
"resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz",
"integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==",
"dev": true,
"requires": {
"string-width": "^4.2.0",
"strip-ansi": "^6.0.1",
"wrap-ansi": "^7.0.0"
}
},
"strip-ansi": {
"version": "6.0.1",
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz",
"integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==",
"dev": true,
"requires": {
"ansi-regex": "^5.0.1"
}
},
"supports-color": {
"version": "8.1.1",
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz",
@@ -3043,6 +3053,32 @@
"requires": {
"has-flag": "^4.0.0"
}
},
"wrap-ansi": {
"version": "7.0.0",
"resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz",
"integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==",
"dev": true,
"requires": {
"ansi-styles": "^4.0.0",
"string-width": "^4.1.0",
"strip-ansi": "^6.0.0"
}
},
"yargs": {
"version": "17.7.2",
"resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz",
"integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==",
"dev": true,
"requires": {
"cliui": "^8.0.1",
"escalade": "^3.1.1",
"get-caller-file": "^2.0.5",
"require-directory": "^2.1.1",
"string-width": "^4.2.3",
"y18n": "^5.0.5",
"yargs-parser": "^21.1.1"
}
}
}
},
@@ -3168,12 +3204,6 @@
"integrity": "sha512-e9MewbtFo+Fevyuxn/4rrcDAaq0IYxPGLvObpQjiZBMAzB9IGmzlnG9RZy3FFas+eBMu2vA0CszMeduow5dIuQ==",
"dev": true
},
"pure-rand": {
"version": "6.1.0",
"resolved": "https://registry.npmjs.org/pure-rand/-/pure-rand-6.1.0.tgz",
"integrity": "sha512-bVWawvoZoBYpp6yIoQtQXHZjmz35RSVHnUOTefl8Vcjr8snTPY1wnpSPMWekcFwbxI6gtmT7rSYPFvz71ldiOA==",
"dev": true
},
"randombytes": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz",
@@ -3402,10 +3432,10 @@
"dev": true
},
"valibot": {
"version": "1.0.0-beta.13",
"resolved": "https://registry.npmjs.org/valibot/-/valibot-1.0.0-beta.13.tgz",
"integrity": "sha512-WCAqfG126/nadCrK36lOgVHrYWeWJfxb52PYE48gqg/8clLTy9sWjE6v/W43cVtgR+rSt30J1IAswk6ovT48pQ==",
"optional": true,
"version": "1.0.0-beta.14",
"resolved": "https://registry.npmjs.org/valibot/-/valibot-1.0.0-beta.14.tgz",
"integrity": "sha512-tLyV2rE5QL6U29MFy3xt4AqMrn+/HErcp2ZThASnQvPMwfSozjV1uBGKIGiegtZIGjinJqn0SlBdannf18wENA==",
"peer": true,
"requires": {}
},
"validate-npm-package-name": {
@@ -3512,12 +3542,20 @@
"string-width": "^4.2.0",
"y18n": "^5.0.5",
"yargs-parser": "^20.2.2"
},
"dependencies": {
"yargs-parser": {
"version": "20.2.9",
"resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.9.tgz",
"integrity": "sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==",
"dev": true
}
}
},
"yargs-parser": {
"version": "20.2.9",
"resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.9.tgz",
"integrity": "sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==",
"version": "21.1.1",
"resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz",
"integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==",
"dev": true
},
"yargs-unparser": {
@@ -3542,7 +3580,7 @@
"version": "3.24.1",
"resolved": "https://registry.npmjs.org/zod/-/zod-3.24.1.tgz",
"integrity": "sha512-muH7gBL9sI1nciMZV67X5fTKKBLtwpZ5VBp1vsOQzj1MhrBZ4wlVCm3gedKZWLp0Oyel8sIGfeiz54Su+OVT+A==",
"optional": true
"peer": true
}
}
}

View File

@@ -1,12 +1,12 @@
{
"name": "@sinclair/typebox-adapter",
"version": "0.9.1",
"description": "Integrate Valibot and Zod with TypeBox",
"name": "@sinclair/typemap",
"version": "0.8.0",
"description": "Unified Syntax Frontend and Type Remapping System for TypeBox, Valibot and Zod",
"author": "sinclairzx81",
"license": "MIT",
"repository": {
"type": "git",
"url": "https://github.com/sinclairzx81/typebox-adapter"
"url": "https://github.com/sinclairzx81/typemap"
},
"scripts": {
"benchmark": "hammer task benchmark",
@@ -18,15 +18,12 @@
"publish": "hammer task publish"
},
"peerDependencies": {
"@sinclair/typebox": "^0.34.14"
},
"optionalDependencies": {
"@sinclair/typebox": "^0.34.14",
"valibot": "^1.0.0-beta.13",
"zod": "^3.24.1"
},
"devDependencies": {
"@arethetypeswrong/cli": "^0.17.2",
"@effect/schema": "^0.75.5",
"@sinclair/hammer": "^0.18.0",
"@types/mocha": "^10.0.10",
"@types/node": "^22.10.2",

184
readme.md
View File

@@ -1,10 +1,10 @@
<div align='center'>
<h1>TypeBox Adapter</h1>
<h1>TypeMap</h1>
<p>Integrate Valibot and Zod with TypeBox</p>
<p>Unified Syntax Frontend and Type Remapping System for TypeBox, Valibot and Zod</p>
<img src="https://raw.githubusercontent.com/sinclairzx81/typebox-adapter/refs/heads/main/typebox-adapter.png" />
<img src="typemap.png" />
<br />
<br />
@@ -19,84 +19,186 @@
## Install
```bash
$ npm install @sinclair/typebox-adapter --save
$ npm install @sinclair/typemap --save
```
## Example
TypeBox Adapter converts Valibot and Zod Types into TypeBox compatible schematics
[TypeScript Example](https://www.typescriptlang.org/play/?moduleResolution=99&module=199#code/JYWwDg9gTgLgBAbzgIQgDzgXzgMyhEOAcgAEBnYAOwGMAbAQ2CgHoYBPMAUwCN0BaegBN6YGJyhEAUKEixEcAMox6MYNSy58hUhRoMmrDj3RSZ0eACo49MnABumgsTv1awXjFPhzcKzbgAXo7aARCCUpLMzHAAaq7uEPAwEHAAKkaoaJKS7FyxcAC8isqq1AA8uZwQOLEAfNnUEJRk8DGFKOgAFHYAdBDcAFac1DCdSHATk1PTMzNRcI3Nre0IkhNoAFz2PZQAriDc4p0AlAA0sxeXVxPzE5VbRP1DI0Sna3BsW717B0dn1wDAbc4FBOABHXZMTiCLYAbSIaFexDYSKIASIAF03hMAl8dvtDlAToCSVdgWB8FxYMBOGQtqtMMdjqSWay4MD1vS4PdiD9CUQsNi2cKSRyPlyeUQ+eIBZghSKFZcxbj5JLpRIsO9FdrpsDMFqdYb5vrItEAFphbkpdJcTLZSpwM3tJQqNQVIzVR31SSLFqO9qZToBPqDYajcaG9nRX3wM1bVIAeVDIzKqwm9C2wZaUCoAHMTudI0roun40oc5Rc0LuJmetm8wWi8XJjW0uW80LqLX65XiU2LsCu22YBXc5JGcz+8LjbUgA)
Use syntax to construct types for TypeBox, Valibot and Zod ...
```typescript
import { Box } from '@sinclair/typebox-adapter'
import { TypeBox, Zod, Valibot } from '@sinclair/typemap'
import * as v from 'valibot'
import * as z from 'zod'
// const T: TObject<{ ... }>
// Valibot to TypeBox (Runtime)
const T = TypeBox(`{
x: number,
y: number,
z: number
}`)
const V = Box(v.object({ // const V = {
x: v.number(), // type: 'object',
y: v.number(), // required: ['x', 'y', 'z'],
z: v.number() // properties: {
})) // x: { type: 'number' },
// y: { type: 'number' },
// z: { type: 'number' }
// }
// }
// const V: ObjectSchema<{ ... }>
// Zod to TypeBox (Static)
const V = Valibot(`{
x: number,
y: number,
z: number
}`)
const Z = Box(z.object({ // const Z: TObject<{
a: z.string(), // a: TString,
b: z.string(), // b: TString,
c: z.string() // c: TString
})) // }>
// const Z: ZodObject<{ ... }>
const Z = Zod(`{
x: number,
y: number,
z: number
}`)
```
... or structurally remap types from one library to another
```typescript
import { TypeBox, Valibot, Zod } from '@sinclair/typemap'
// Syntax > Zod > Valibot > TypeBox
const T = TypeBox(Valibot(Zod(`{
x: number,
y: number,
z: number
}`)))
```
... or compile types for high performance runtime type checking
```typescript
import { Compile } from '@sinclair/typemap'
import z from 'zod'
const T = z.object({ // const T: z.ZodObject<{
x: z.number(), // x: z.ZodNumber,
y: z.number(), // y: z.ZodNumber,
z: z.number(), // z: z.ZodNumber,
}) // }>
const C = Compile(T) // const C: Validator<TObject<{
// x: TNumber,
// y: TNumber,
// z: TNumber
// }>>
const R = C.Check({ // const R: boolean - High Performance Checking!
x: 1,
y: 2,
z: 3
})
```
## Overview
TypeBox Adapter converts Zod and Valibot types into TypeBox schematics (Json Schema). It performs a deep structural remapping of the types provided by these libraries into TypeScript-aligned Json Schema, enabling integration with industry-standard validators like Ajv and OpenAPI-related technologies, while also facilitating interoperability and acceleration via the TypeBox validation infrastructure.
TypeMap is an type mapping library developed for TypeBox, Valibot and Zod. It enables quick compatibility between each library by structurally remapping type representations from one library to another. In addition,TypeMap offers a uniform syntax for type construction as well as high-performance runtime type checking for Valibot and Zod via the TypeBox compiler infrastructure.
License MIT
TypeMap is designed to be a simple tool to enable Valibot and Zod to integrate with TypeBox and Json Schema validation infrastructure. It is also written to allow TypeBox to integrate with systems leveraging Valibot and Zod for validation. The frontend syntax provided by TypeMap seeks to explore a uniform API surface for runtime type libraries.
License: MIT
## Contents
- [Install](#Install)
- [Overview](#Overview)
- [Usage](#Usage)
- [Libraries](#Libraries)
- [TypeBox](#TypeBox)
- [Valibot](#Valibot)
- [Zod](#Zod)
- [Static](#Static)
- [Compile](#Compile)
- [Benchmark](#Benchmark)
- [Contribute](#Contribute)
## Usage
## Libraries
TypeBox Adapter provides a singular Box function to transform Valibot and Zod types into TypeBox schematics. The top-level export is capable of transforming both Valibot and Zod, but you should use the appropriate submodule depending on which library you are using.
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.
### TypeBox
Use the TypeBox function to map the parameter into a TypeBox type
```typescript
import { TypeBox } from '@sinclair/typemap'
const A = TypeBox(t.Number()) // const A: TNumber (TypeBox)
const B = TypeBox(v.string()) // const B: TString (Valibot)
const C = TypeBox(z.boolean()) // const C: TBoolean (Zod)
const D = TypeBox('string[]') // const D: TArray<TString> (Syntax)
```
### Valibot
Use the `/valibot` submodule if you only have Valibot installed. Refer to the Valibot [documentation](https://valibot.dev/) for more information on this type library.
Use the Valibot function to map the parameter into a Valibot type
```typescript
import { Box } from '@sinclair/typebox-adapter/valibot' // Transform Valibot Only
import { Valibot } from '@sinclair/typemap'
import * as v from 'valibot'
const T = Box(v.string()) // const T = { type: 'string' }
const A = Valibot(t.Number()) // const A: v.NumberSchema (TypeBox)
const B = Valibot(v.string()) // const B: v.StringSchema (Valibot)
const C = Valibot(z.boolean()) // const C: v.BooleanSchema (Zod)
const D = Valibot('string[]') // const D: v.ArraySchema<...> (Syntax)
```
### Zod
Use the `/zod` submodule if you only have Zod installed. Refer to the Zod [documentation](https://zod.dev/) for more information on this type library.
Use the Zod function to map the parameter into a Zod type
```typescript
import { Box } from '@sinclair/typebox-adapter/zod' // Transform Zod Only
import { Zod } from '@sinclair/typemap'
import * as z from 'zod'
const A = Zod(t.Number()) // const A: z.ZodNumber (TypeBox)
const B = Zod(v.string()) // const B: z.ZodString (Valibot)
const C = Zod(z.boolean()) // const C: z.ZodBoolean (Zod)
const D = Zod('string[]') // const D: z.ZodArray<...> (Syntax)
```
const T = Box(z.string()) // const T = { type: 'string' }
## Static
TypeMap can statically infer for TypeBox, Valibot, Zod and Syntax with the `Static` type.
```typescript
import { type Static } from '@sinclair/typemap'
const T = t.Number() // TypeBox
const V = v.string() // Valibot
const Z = z.boolean() // Zod
const S = 'string[]' // Syntax
type T = Static<typeof T> // number
type V = Static<typeof V> // string
type Z = Static<typeof Z> // boolean
type S = Static<typeof S> // 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.
```typescript
import { Compile } from '@sinclair/typemap'
// Pass TypeBox, Valibot, Zod or Syntax to JIT Compile the type.
const V = Compile(`{
x: number
y: number,
z: number
}`)
// TypeMap Interface
const R1 = V.Check({ x: 1, y: 2, z: 3 })
// Standard Schema Interface
const R2 = V['~standard'].validate({ x: 1, y: 2, z: 3 })
```
## Benchmark
@@ -136,5 +238,5 @@ For community benchmarks, refer to the [runtime-type-benchmarks](https://github.
## Contribute
This project is open to community contributions. Please ensure you submit an open issue before creating a pull request. TypeBox and its associated projects encourage 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. TypeMap encourages open community discussion before accepting new features.

120
src/compile/compile.ts Normal file
View File

@@ -0,0 +1,120 @@
/*--------------------------------------------------------------------------
@sinclair/typemap
The MIT License (MIT)
Copyright (c) 2024 Haydn Paterson (sinclair) <haydn.developer@gmail.com>
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
---------------------------------------------------------------------------*/
import { 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 * as t from '@sinclair/typebox'
// ------------------------------------------------------------------
// StandardSchemaProps
// ------------------------------------------------------------------
export class StandardSchemaProps<Type extends t.TSchema> implements StandardSchemaV1.Props<Type, t.Static<Type>> {
readonly #check: TypeCheck<Type>
constructor(check: TypeCheck<Type>) {
this.#check = check
}
// ----------------------------------------------------------------
// StandardSchemaV1.Props<Type, t.Static<Type>>
// ----------------------------------------------------------------
public get vendor(): '@sinclair/typemap' {
return '@sinclair/typemap'
}
public get version(): 1 {
return 1
}
public get types(): { input: Type; output: t.Static<Type> } {
return { input: this.#check.Schema(), output: null }
}
public validate(value: unknown): StandardSchemaV1.Result<t.Static<Type>> {
return this.#check.Check(value) ? this.#createValue(value) : this.#createIssues(value)
}
// ----------------------------------------------------------------
// Internal
// ----------------------------------------------------------------
#createIssues(value: unknown) {
const errors = [...Value.Errors(this.#check.Schema(), value)]
const issues: StandardSchemaV1.Issue[] = errors.map((error) => ({ ...error, path: [error.path] }))
return { issues }
}
#createValue(value: unknown) {
return { value }
}
}
// ------------------------------------------------------------------
// Validator<TSchema>
// ------------------------------------------------------------------
export class Validator<Type extends t.TSchema> implements StandardSchemaV1<Type, t.Static<Type>> {
readonly #standard: StandardSchemaProps<Type>
readonly #check: TypeCheck<Type>
constructor(check: TypeCheck<Type>) {
this.#standard = new StandardSchemaProps<Type>(check)
this.#check = check
}
/** Standard Schema Interface */
public get ['~standard'](): StandardSchemaProps<Type> {
return this.#standard
}
/** Parses this value. Do not use this function for high throughput validation */
public Parse(value: unknown): t.StaticDecode<Type> {
return Value.Parse(this.#check.Schema(), value)
}
/** Checks if this value matches the type */
public Check(value: unknown): value is t.Static<Type> {
return this.#check.Check(value)
}
/** Returns errors for this value */
public Errors(value: unknown): ValueErrorIterator {
return this.#check.Errors(value)
}
}
// ------------------------------------------------------------------
// CompileDynamic
// ------------------------------------------------------------------
// prettier-ignore
function CompileDynamic<Type extends t.TSchema>(type: Type, references: t.TSchema[] = []): TypeCheck<Type> {
return new TypeCheck(type, references, value => Value.Check(type, references, value), TypeCompiler.Code(type, references))
}
// ------------------------------------------------------------------
// Compile
// ------------------------------------------------------------------
/** Compiles a type for high performance validation */
// prettier-ignore
type TCompile<Type extends object | string,
Schema extends t.TSchema = TTypeBox<Type>,
Result extends Validator<Schema> = Validator<Schema>
> = Result
/** Compiles a type for high performance validation */
// prettier-ignore
export function Compile<Type extends object | string>(type: Type): TCompile<Type> {
const schema = TypeBox(type)
const check = IsEvalSupported() ? TypeCompiler.Compile(schema) : CompileDynamic(schema)
return new Validator(check)
}

View File

@@ -1,6 +1,6 @@
/*--------------------------------------------------------------------------
@sinclair/typebox-adapter
@sinclair/typemap
The MIT License (MIT)
@@ -26,4 +26,18 @@ THE SOFTWARE.
---------------------------------------------------------------------------*/
export * from './box'
/** Cached: flag to indicate if the environment supports runtime evaluation */
let isEvalSupported: boolean | undefined = undefined
// prettier-ignore
function TryEval(): boolean {
try { new Function('null')(); return true } catch { return false }
}
/** Tests if the environment supports eval */
// prettier-ignore
export function IsEvalSupported(): boolean {
if(isEvalSupported === undefined) {
isEvalSupported = TryEval()
}
return isEvalSupported
}

82
src/compile/standard.ts Normal file
View File

@@ -0,0 +1,82 @@
/*--------------------------------------------------------------------------
MIT License
Copyright (c) 2024 Colin McDonnell
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.
---------------------------------------------------------------------------*/
/** The Standard Schema interface. */
export interface StandardSchemaV1<Input = unknown, Output = Input> {
/** The Standard Schema properties. */
readonly '~standard': StandardSchemaV1.Props<Input, Output>
}
export declare namespace StandardSchemaV1 {
/** The Standard Schema properties interface. */
export interface Props<Input = unknown, Output = Input> {
/** The version number of the standard. */
readonly version: 1
/** The vendor name of the schema library. */
readonly vendor: string
/** Validates unknown input values. */
readonly validate: (value: unknown) => Result<Output> | Promise<Result<Output>>
/** Inferred types associated with the schema. */
readonly types?: Types<Input, Output> | undefined
}
/** The result interface of the validate function. */
export type Result<Output> = SuccessResult<Output> | FailureResult
/** The result interface if validation succeeds. */
export interface SuccessResult<Output> {
/** The typed output value. */
readonly value: Output
/** The non-existent issues. */
readonly issues?: undefined
}
/** The result interface if validation fails. */
export interface FailureResult {
/** The issues of failed validation. */
readonly issues: ReadonlyArray<Issue>
}
/** The issue interface of the failure output. */
export interface Issue {
/** The error message of the issue. */
readonly message: string
/** The path of the issue, if any. */
readonly path?: ReadonlyArray<PropertyKey | PathSegment> | undefined
}
/** The path segment interface of the issue. */
export interface PathSegment {
/** The key representing a path segment. */
readonly key: PropertyKey
}
/** The Standard Schema types interface. */
export interface Types<Input = unknown, Output = Input> {
/** The input type of the schema. */
readonly input: Input
/** The output type of the schema. */
readonly output: Output
}
/** Infers the input type of a Standard Schema. */
export type InferInput<Schema extends StandardSchemaV1> = NonNullable<Schema['~standard']['types']>['input']
/** Infers the output type of a Standard Schema. */
export type InferOutput<Schema extends StandardSchemaV1> = NonNullable<Schema['~standard']['types']>['output']
}

85
src/guard.ts Normal file
View File

@@ -0,0 +1,85 @@
/*--------------------------------------------------------------------------
@sinclair/typemap
The MIT License (MIT)
Copyright (c) 2024 Haydn Paterson (sinclair) <haydn.developer@gmail.com>
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
---------------------------------------------------------------------------*/
import * as 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 unknown> = 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 unknown> = 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)
}
// ------------------------------------------------------------------
// Valibot
// ------------------------------------------------------------------
/** Returns true if the given value is a Valibot type */
// prettier-ignore
export type TIsValibot<Type extends unknown> = (
Type extends v.BaseSchema<unknown, unknown, v.BaseIssue<unknown>>
? Type extends { '~standard': { vendor: 'valibot' } }
? true
: false
: false
)
/** Returns true if the given value is a Valibot type */
// prettier-ignore
export function IsValibot(type: unknown): type is v.AnySchema {
return (
t.ValueGuard.IsObject(type) &&
t.ValueGuard.HasPropertyKey(type, '~standard') &&
t.ValueGuard.IsObject(type['~standard']) &&
t.ValueGuard.HasPropertyKey(type['~standard'], 'vendor') &&
type['~standard'].vendor === 'valibot'
)
}
// ------------------------------------------------------------------
// Zod
// ------------------------------------------------------------------
// prettier-ignore
/** Returns true if the given value is a Zod type */
export type TIsZod<Type extends unknown> = (
Type extends z.ZodTypeAny ? true : false
)
/** Returns true if the given value is a Zod type */
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'
}

View File

@@ -1,6 +1,6 @@
/*--------------------------------------------------------------------------
@sinclair/typebox-adapter
@sinclair/typemap
The MIT License (MIT)
@@ -26,4 +26,8 @@ THE SOFTWARE.
---------------------------------------------------------------------------*/
export * from './box'
export { type Static } from './static'
export * from './compile/compile'
export * from './typebox/typebox'
export * from './valibot/valibot'
export * from './zod/zod'

44
src/static.ts Normal file
View File

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

View File

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

View File

@@ -1,6 +1,6 @@
/*--------------------------------------------------------------------------
@sinclair/typebox-adapter
@sinclair/typemap
The MIT License (MIT)
@@ -26,4 +26,13 @@ THE SOFTWARE.
---------------------------------------------------------------------------*/
export * from './box'
import * as t from '@sinclair/typebox'
// prettier-ignore
export type TTypeBoxFromTypeBox<Type extends unknown> = (
Type extends t.TSchema ? Type : t.TNever
)
// prettier-ignore
export function TypeBoxFromTypeBox<Type extends unknown, Result extends TTypeBoxFromTypeBox<Type> = TTypeBoxFromTypeBox<Type>>(type: Type): Result {
return (t.KindGuard.IsSchema(type) ? type : t.Never()) as never
}

View File

@@ -1,6 +1,6 @@
/*--------------------------------------------------------------------------
@sinclair/typebox-adapter
@sinclair/typemap
The MIT License (MIT)
@@ -26,14 +26,15 @@ THE SOFTWARE.
---------------------------------------------------------------------------*/
import * as tb from '@sinclair/typebox'
import * as t from '@sinclair/typebox'
import * as v from 'valibot'
import * as Guard from '../guard'
// ------------------------------------------------------------------
// Options
// ------------------------------------------------------------------
function IsSchemaWithPipe(type: BaseSchema): type is v.SchemaWithPipe<[BaseSchema, ...BaseValidation[]]> {
return tb.ValueGuard.IsObject(type) && tb.ValueGuard.HasPropertyKey(type, 'pipe') && tb.ValueGuard.IsArray(type.pipe)
return t.ValueGuard.IsObject(type) && t.ValueGuard.HasPropertyKey(type, 'pipe') && t.ValueGuard.IsArray(type.pipe)
}
// prettier-ignore
function Options(type: BaseSchema) {
@@ -42,19 +43,19 @@ function Options(type: BaseSchema) {
return {
...options, ...(
action.type === 'args' ? {} :
action.type === 'base64' ? { format: 'valibot:base64' } :
action.type === 'bic' ? { format: 'valibot:bic' } :
action.type === 'base64' ? { format: 'base64' } :
action.type === 'bic' ? { format: 'bic' } :
action.type === 'brand' ? {} :
action.type === 'bytes' ? {} :
action.type === 'check' ? {} :
action.type === 'check_items' ? {} :
action.type === 'credit_card' ? { format: 'valibot:credit_card' } :
action.type === 'cuid2' ? { format: 'valibot:cuid2' } :
action.type === 'decimal' ? { format: 'valibot:decimal' } :
action.type === 'credit_card' ? { format: 'credit_card' } :
action.type === 'cuid2' ? { format: 'cuid2' } :
action.type === 'decimal' ? { format: 'decimal' } :
action.type === 'description' ? { description: action.description } :
action.type === 'digits' ? { format: 'valibot:digits' } :
action.type === 'email' ? { format: 'valibot:email' } :
action.type === 'emoji' ? { format: 'valibot:emoji' } :
action.type === 'digits' ? { format: 'digits' } :
action.type === 'email' ? { format: 'email' } :
action.type === 'emoji' ? { format: 'emoji' } :
action.type === 'empty' ? (
type.type === 'array' ? { maxItems: 0 } :
type.type === 'string' ? { maxLength: 0 } :
@@ -71,26 +72,26 @@ function Options(type: BaseSchema) {
action.type === 'hex_color' ? {} :
action.type === 'imei' ? {} :
action.type === 'includes' ? (
type.type === 'array' ? { contains: tb.Literal(action.requirement) } :
type.type === 'array' ? { contains: t.Literal(action.requirement) } :
type.type === 'string' ? { pattern: action.requirement } :
{}) :
action.type === 'integer' ? { multipleOf: 1 } :
action.type === 'ip' ? { format: 'valibot:ip' } :
action.type === 'ipv4' ? { format: 'valibot:ipv4' } :
action.type === 'ipv6' ? { format: 'valibot:ipv6' } :
action.type === 'iso_date' ? { format: 'valibot:iso_date' } :
action.type === 'iso_date_time' ? { format: 'valibot:iso_date_time' } :
action.type === 'iso_time' ? { format: 'valibot:iso_time' } :
action.type === 'iso_time_second' ? { format: 'valibot:iso_time_second' } :
action.type === 'iso_timestamp' ? { format: 'valibot:iso_timestamp' } :
action.type === 'iso_week' ? { format: 'valibot:iso_week' } :
action.type === 'ip' ? { format: 'ip' } :
action.type === 'ipv4' ? { format: 'ipv4' } :
action.type === 'ipv6' ? { format: 'ipv6' } :
action.type === 'iso_date' ? { format: 'iso_date' } :
action.type === 'iso_date_time' ? { format: 'iso_date_time' } :
action.type === 'iso_time' ? { format: 'iso_time' } :
action.type === 'iso_time_second' ? { format: 'iso_time_second' } :
action.type === 'iso_timestamp' ? { format: 'iso_timestamp' } :
action.type === 'iso_week' ? { format: 'iso_week' } :
action.type === 'length' ? (
type.type === 'string' ? { minLength: action.requirement, maxLength: action.requirement } :
type.type === 'array' ? { minItems: action.requirement, maxItems: action.requirement } :
{}) :
action.type === 'mac' ? { format: 'valibot:mac' } :
action.type === 'mac48' ? { format: 'valibot:mac48' } :
action.type === 'mac64' ? { format: 'valibot:mac64' } :
action.type === 'mac' ? { format: 'mac' } :
action.type === 'mac48' ? { format: 'mac48' } :
action.type === 'mac64' ? { format: 'mac64' } :
action.type === 'map_items' ? {} :
action.type === 'max_bytes' ? {} :
action.type === 'max_graphemes' ? {} :
@@ -101,7 +102,7 @@ function Options(type: BaseSchema) {
action.type === 'max_size' ? {} :
action.type === 'max_value' ? { maximum: action.requirement } :
action.type === 'max_words' ? {} :
action.type === 'metadata' ? { ...action.metadata } :
action.type === 'metadata' ? { metadata: action.metadata } :
action.type === 'mime_type' ? {} :
action.type === 'min_bytes' ? {} :
action.type === 'min_graphemes' ? {} :
@@ -113,7 +114,7 @@ function Options(type: BaseSchema) {
action.type === 'min_value' ? { minimum: action.requirement } :
action.type === 'min_words' ? {} :
action.type === 'multiple_of' ? { multipleOf: action.requirement } :
action.type === 'nanoid' ? { format: 'valibot:nanoid' } :
action.type === 'nanoid' ? { format: 'nanoid' } :
action.type === 'non_empty' ? {} :
action.type === 'normalize' ? {} :
action.type === 'not_bytes' ? {} :
@@ -122,7 +123,7 @@ function Options(type: BaseSchema) {
action.type === 'not_size' ? {} :
action.type === 'not_value' ? {} :
action.type === 'not_words' ? {} :
action.type === 'octal' ? { format: 'valibot:octal' } :
action.type === 'octal' ? { format: 'octal' } :
action.type === 'partial_check' ? {} :
action.type === 'raw_check' ? {} :
action.type === 'raw_transform' ? {} :
@@ -144,9 +145,9 @@ function Options(type: BaseSchema) {
action.type === 'trim' ? {} :
action.type === 'trim_end' ? {} :
action.type === 'trim_start' ? {} :
action.type === 'ulid' ? { format: 'valibot:ulid' } :
action.type === 'url' ? { format: 'valibot:url' } :
action.type === 'uuid' ? { format: 'valibot:uuid' } :
action.type === 'ulid' ? { format: 'ulid' } :
action.type === 'url' ? { format: 'url' } :
action.type === 'uuid' ? { format: 'uuid' } :
action.type === 'value' ? {} :
action.type === 'words' ? {} :
{})
@@ -156,31 +157,31 @@ function Options(type: BaseSchema) {
// ------------------------------------------------------------------
// Formats
// ------------------------------------------------------------------
tb.FormatRegistry.Set('valibot:base64', (value) => v.safeParse(v.pipe(v.string(), v.base64()), value).success)
tb.FormatRegistry.Set('valibot:bic', (value) => v.safeParse(v.pipe(v.string(), v.bic()), value).success)
tb.FormatRegistry.Set('valibot:credit_card', (value) => v.safeParse(v.pipe(v.string(), v.creditCard()), value).success)
tb.FormatRegistry.Set('valibot:cuid2', (value) => v.safeParse(v.pipe(v.string(), v.cuid2()), value).success)
tb.FormatRegistry.Set('valibot:decimal', (value) => v.safeParse(v.pipe(v.string(), v.decimal()), value).success)
tb.FormatRegistry.Set('valibot:digits', (value) => v.safeParse(v.pipe(v.string(), v.digits()), value).success)
tb.FormatRegistry.Set('valibot:email', (value) => v.safeParse(v.pipe(v.string(), v.email()), value).success)
tb.FormatRegistry.Set('valibot:emoji', (value) => v.safeParse(v.pipe(v.string(), v.emoji()), value).success)
tb.FormatRegistry.Set('valibot:ip', (value) => v.safeParse(v.pipe(v.string(), v.ip()), value).success)
tb.FormatRegistry.Set('valibot:ipv4', (value) => v.safeParse(v.pipe(v.string(), v.ipv4()), value).success)
tb.FormatRegistry.Set('valibot:ipv6', (value) => v.safeParse(v.pipe(v.string(), v.ipv6()), value).success)
tb.FormatRegistry.Set('valibot:iso_date', (value) => v.safeParse(v.pipe(v.string(), v.isoDate()), value).success)
tb.FormatRegistry.Set('valibot:iso_date_time', (value) => v.safeParse(v.pipe(v.string(), v.isoDateTime()), value).success)
tb.FormatRegistry.Set('valibot:iso_time', (value) => v.safeParse(v.pipe(v.string(), v.isoTime()), value).success)
tb.FormatRegistry.Set('valibot:iso_time_second', (value) => v.safeParse(v.pipe(v.string(), v.isoTimeSecond()), value).success)
tb.FormatRegistry.Set('valibot:iso_timestamp', (value) => v.safeParse(v.pipe(v.string(), v.isoTimestamp()), value).success)
tb.FormatRegistry.Set('valibot:iso_week', (value) => v.safeParse(v.pipe(v.string(), v.isoWeek()), value).success)
tb.FormatRegistry.Set('valibot:mac', (value) => v.safeParse(v.pipe(v.string(), v.mac()), value).success)
tb.FormatRegistry.Set('valibot:mac48', (value) => v.safeParse(v.pipe(v.string(), v.mac48()), value).success)
tb.FormatRegistry.Set('valibot:mac64', (value) => v.safeParse(v.pipe(v.string(), v.mac64()), value).success)
tb.FormatRegistry.Set('valibot:nanoid', (value) => v.safeParse(v.pipe(v.string(), v.nanoid()), value).success)
tb.FormatRegistry.Set('valibot:octal', (value) => v.safeParse(v.pipe(v.string(), v.octal()), value).success)
tb.FormatRegistry.Set('valibot:ulid', (value) => v.safeParse(v.pipe(v.string(), v.ulid()), value).success)
tb.FormatRegistry.Set('valibot:url', (value) => v.safeParse(v.pipe(v.string(), v.url()), value).success)
tb.FormatRegistry.Set('valibot:uuid', (value) => v.safeParse(v.pipe(v.string(), v.uuid()), value).success)
t.FormatRegistry.Set('base64', (value) => v.safeParse(v.pipe(v.string(), v.base64()), value).success)
t.FormatRegistry.Set('bic', (value) => v.safeParse(v.pipe(v.string(), v.bic()), value).success)
t.FormatRegistry.Set('credit_card', (value) => v.safeParse(v.pipe(v.string(), v.creditCard()), value).success)
t.FormatRegistry.Set('cuid2', (value) => v.safeParse(v.pipe(v.string(), v.cuid2()), value).success)
t.FormatRegistry.Set('decimal', (value) => v.safeParse(v.pipe(v.string(), v.decimal()), value).success)
t.FormatRegistry.Set('digits', (value) => v.safeParse(v.pipe(v.string(), v.digits()), value).success)
t.FormatRegistry.Set('email', (value) => v.safeParse(v.pipe(v.string(), v.email()), value).success)
t.FormatRegistry.Set('emoji', (value) => v.safeParse(v.pipe(v.string(), v.emoji()), value).success)
t.FormatRegistry.Set('ip', (value) => v.safeParse(v.pipe(v.string(), v.ip()), value).success)
t.FormatRegistry.Set('ipv4', (value) => v.safeParse(v.pipe(v.string(), v.ipv4()), value).success)
t.FormatRegistry.Set('ipv6', (value) => v.safeParse(v.pipe(v.string(), v.ipv6()), value).success)
t.FormatRegistry.Set('iso_date', (value) => v.safeParse(v.pipe(v.string(), v.isoDate()), value).success)
t.FormatRegistry.Set('iso_date_time', (value) => v.safeParse(v.pipe(v.string(), v.isoDateTime()), value).success)
t.FormatRegistry.Set('iso_time', (value) => v.safeParse(v.pipe(v.string(), v.isoTime()), value).success)
t.FormatRegistry.Set('iso_time_second', (value) => v.safeParse(v.pipe(v.string(), v.isoTimeSecond()), value).success)
t.FormatRegistry.Set('iso_timestamp', (value) => v.safeParse(v.pipe(v.string(), v.isoTimestamp()), value).success)
t.FormatRegistry.Set('iso_week', (value) => v.safeParse(v.pipe(v.string(), v.isoWeek()), value).success)
t.FormatRegistry.Set('mac', (value) => v.safeParse(v.pipe(v.string(), v.mac()), value).success)
t.FormatRegistry.Set('mac48', (value) => v.safeParse(v.pipe(v.string(), v.mac48()), value).success)
t.FormatRegistry.Set('mac64', (value) => v.safeParse(v.pipe(v.string(), v.mac64()), value).success)
t.FormatRegistry.Set('nanoid', (value) => v.safeParse(v.pipe(v.string(), v.nanoid()), value).success)
t.FormatRegistry.Set('octal', (value) => v.safeParse(v.pipe(v.string(), v.octal()), value).success)
t.FormatRegistry.Set('ulid', (value) => v.safeParse(v.pipe(v.string(), v.ulid()), value).success)
t.FormatRegistry.Set('url', (value) => v.safeParse(v.pipe(v.string(), v.url()), value).success)
t.FormatRegistry.Set('uuid', (value) => v.safeParse(v.pipe(v.string(), v.uuid()), value).success)
// ------------------------------------------------------------------
// Schema
@@ -191,156 +192,156 @@ type BaseRecordKey = v.BaseSchema<string, string | number | symbol, v.BaseIssue<
// ------------------------------------------------------------------
// Any
// ------------------------------------------------------------------
type TFromAny<_Type extends v.AnySchema> = tb.Ensure<tb.TAny>
function FromAny(type: BaseSchema): tb.TSchema {
return tb.Any(Options(type))
type TFromAny<_Type extends v.AnySchema> = t.Ensure<t.TAny>
function FromAny(type: BaseSchema): t.TSchema {
return t.Any(Options(type))
}
// ------------------------------------------------------------------
// Array
// ------------------------------------------------------------------
type TFromArray<Type extends BaseSchema> = tb.Ensure<tb.TArray<TFromType<Type>>>
function FromArray(type: BaseSchema): tb.TSchema {
return tb.Array(FromType((type as v.ArraySchema<any, any>).item), Options(type))
type TFromArray<Type extends BaseSchema> = t.Ensure<t.TArray<TFromType<Type>>>
function FromArray(type: BaseSchema): t.TSchema {
return t.Array(FromType((type as v.ArraySchema<any, any>).item), Options(type))
}
// ------------------------------------------------------------------
// BigInt
// ------------------------------------------------------------------
type TFromBigInt<_Type extends v.BigintSchema<any>> = tb.Ensure<tb.TBigInt>
function FromBigInt(type: BaseSchema): tb.TSchema {
return tb.BigInt(Options(type))
type TFromBigInt<_Type extends v.BigintSchema<any>> = t.Ensure<t.TBigInt>
function FromBigInt(type: BaseSchema): t.TSchema {
return t.BigInt(Options(type))
}
// ------------------------------------------------------------------
// Blob
// ------------------------------------------------------------------
tb.TypeRegistry.Set<TBlob>('ValibotBlob', (schema, value) => {
t.TypeRegistry.Set<TBlob>('ValibotBlob', (schema, value) => {
return v.safeParse(schema.schema, value).success
})
interface TBlob<Type extends v.BlobSchema<any> = v.BlobSchema<any>> extends tb.TSchema {
[tb.Kind]: 'ValibotBlob'
interface TBlob<Type extends v.BlobSchema<any> = v.BlobSchema<any>> extends t.TSchema {
[t.Kind]: 'ValibotBlob'
static: v.InferOutput<this['type']>
type: Type
}
function _Blob(type: v.BlobSchema<any>, options?: tb.SchemaOptions): TBlob {
return tb.CreateType({ [tb.Kind]: 'ValibotBlob', type }, options) as never
function _Blob(type: v.BlobSchema<any>, options?: t.SchemaOptions): TBlob {
return t.CreateType({ [t.Kind]: 'ValibotBlob', type }, options) as never
}
type TFromBlob<Type extends v.BlobSchema<any>> = tb.Ensure<TBlob<Type>>
function FromBlob(type: BaseSchema): tb.TSchema {
type TFromBlob<Type extends v.BlobSchema<any>> = t.Ensure<TBlob<Type>>
function FromBlob(type: BaseSchema): t.TSchema {
return _Blob(type as v.BlobSchema<any>, Options(type))
}
// ------------------------------------------------------------------
// Boolean
// ------------------------------------------------------------------
type TFromBoolean<_Type extends v.BooleanSchema<any>> = tb.TBoolean
function FromBoolean(type: BaseSchema): tb.TSchema {
return tb.Boolean(Options(type))
type TFromBoolean<_Type extends v.BooleanSchema<any>> = t.TBoolean
function FromBoolean(type: BaseSchema): t.TSchema {
return t.Boolean(Options(type))
}
// ------------------------------------------------------------------
// Custom
// ------------------------------------------------------------------
tb.TypeRegistry.Set<TCustom>('ValibotCustom', (schema, value) => v.safeParse(schema.schema, value).success)
export interface TCustom<Type extends v.CustomSchema<any, any> = v.CustomSchema<any, any>> extends tb.TSchema {
[tb.Kind]: 'ValibotCustom'
t.TypeRegistry.Set<TCustom>('ValibotCustom', (schema, value) => v.safeParse(schema.schema, value).success)
export interface TCustom<Type extends v.CustomSchema<any, any> = v.CustomSchema<any, any>> extends t.TSchema {
[t.Kind]: 'ValibotCustom'
static: v.InferOutput<this['type']>
type: Type
}
function Custom<Type extends v.CustomSchema<any, any>>(type: Type, options?: tb.SchemaOptions): TCustom<Type> {
return tb.CreateType({ [tb.Kind]: 'ValibotCustom', type }, options) as never
function Custom<Type extends v.CustomSchema<any, any>>(type: Type, options?: t.SchemaOptions): TCustom<Type> {
return t.CreateType({ [t.Kind]: 'ValibotCustom', type }, options) as never
}
type TFromCustom<Type extends v.CustomSchema<any, any>> = tb.Ensure<TCustom<Type>>
function FromCustom(type: BaseSchema): tb.TSchema {
type TFromCustom<Type extends v.CustomSchema<any, any>> = t.Ensure<TCustom<Type>>
function FromCustom(type: BaseSchema): t.TSchema {
return Custom(type as v.CustomSchema<any, any>, Options(type))
}
// ------------------------------------------------------------------
// Date
// ------------------------------------------------------------------
type TFromDate<_Type extends v.DateSchema<any>> = tb.TDate
function FromDate(type: BaseSchema): tb.TSchema {
return tb.Date(Options(type))
type TFromDate<_Type extends v.DateSchema<any>> = t.TDate
function FromDate(type: BaseSchema): t.TSchema {
return t.Date(Options(type))
}
// ------------------------------------------------------------------
// Enum
// ------------------------------------------------------------------
tb.TypeRegistry.Set<TValibotEnum>('ValibotEnum', (schema, value) => {
t.TypeRegistry.Set<TValibotEnum>('ValibotEnum', (schema, value) => {
return v.safeParse(schema.schema, value).success
})
export interface TValibotEnum<Type extends v.EnumSchema<v.Enum, any> = v.EnumSchema<v.Enum, any>> extends tb.TSchema {
[tb.Kind]: 'ValibotEnum'
export interface TValibotEnum<Type extends v.EnumSchema<v.Enum, any> = v.EnumSchema<v.Enum, any>> extends t.TSchema {
[t.Kind]: 'ValibotEnum'
static: v.InferOutput<this['type']>
type: Type
}
function ValibotEnum<Type extends v.EnumSchema<v.Enum, any>>(type: Type, options?: tb.SchemaOptions): TValibotEnum<Type> {
return tb.CreateType({ [tb.Kind]: 'ValibotEnum', type }, options) as never
function ValibotEnum<Type extends v.EnumSchema<v.Enum, any>>(type: Type, options?: t.SchemaOptions): TValibotEnum<Type> {
return t.CreateType({ [t.Kind]: 'ValibotEnum', type }, options) as never
}
type TFromEnum<Enum extends v.EnumSchema<v.Enum, any>> = TValibotEnum<Enum>
function FromEnum<Type extends BaseSchema>(type: Type): tb.TSchema {
function FromEnum<Type extends BaseSchema>(type: Type): t.TSchema {
return ValibotEnum(type as never as v.EnumSchema<v.Enum, any>, Options(type))
}
// ------------------------------------------------------------------
// File
// ------------------------------------------------------------------
tb.TypeRegistry.Set<TFile>('ValibotFile', (schema, value) => {
t.TypeRegistry.Set<TFile>('ValibotFile', (schema, value) => {
return v.safeParse(schema.schema, value).success
})
export interface TFile<Type extends v.FileSchema<any> = v.FileSchema<any>> extends tb.TSchema {
[tb.Kind]: 'ValibotFile'
export interface TFile<Type extends v.FileSchema<any> = v.FileSchema<any>> extends t.TSchema {
[t.Kind]: 'ValibotFile'
static: v.InferOutput<this['type']>
type: Type
}
function _File(type: v.FileSchema<any>, options?: tb.SchemaOptions): TFile {
return tb.CreateType({ [tb.Kind]: 'ValibotFile', type }, options) as never
function _File(type: v.FileSchema<any>, options?: t.SchemaOptions): TFile {
return t.CreateType({ [t.Kind]: 'ValibotFile', type }, options) as never
}
type TFromFile<Type extends v.FileSchema<any>> = tb.Ensure<TFile<Type>>
function FromFile(type: BaseSchema): tb.TSchema {
type TFromFile<Type extends v.FileSchema<any>> = t.Ensure<TFile<Type>>
function FromFile(type: BaseSchema): t.TSchema {
return _File(type as v.FileSchema<any>, Options(type))
}
// ------------------------------------------------------------------
// Function
// ------------------------------------------------------------------
tb.TypeRegistry.Set<TFunction>('ValibotFunction', (schema, value) => {
t.TypeRegistry.Set<TFunction>('ValibotFunction', (schema, value) => {
return v.safeParse(schema.schema, value).success
})
export interface TFunction<Type extends v.FunctionSchema<any> = v.FunctionSchema<any>> extends tb.TSchema {
[tb.Kind]: 'ValibotFunction'
export interface TFunction<Type extends v.FunctionSchema<any> = v.FunctionSchema<any>> extends t.TSchema {
[t.Kind]: 'ValibotFunction'
static: v.InferOutput<this['type']>
type: Type
}
function _Function<Type extends v.FunctionSchema<any>>(type: Type, options?: tb.SchemaOptions): TFunction<Type> {
return tb.CreateType({ [tb.Kind]: 'ValibotFunction', type }, options) as never
function _Function<Type extends v.FunctionSchema<any>>(type: Type, options?: t.SchemaOptions): TFunction<Type> {
return t.CreateType({ [t.Kind]: 'ValibotFunction', type }, options) as never
}
type TFromFunction<Type extends v.FunctionSchema<any>> = tb.Ensure<TFunction<Type>>
function FromFunction(type: BaseSchema): tb.TSchema {
type TFromFunction<Type extends v.FunctionSchema<any>> = t.Ensure<TFunction<Type>>
function FromFunction(type: BaseSchema): t.TSchema {
return _Function(type as v.FunctionSchema<any>, Options(type))
}
// ------------------------------------------------------------------
// Instance
// ------------------------------------------------------------------
tb.TypeRegistry.Set<TInstance>('ValibotInstance', (schema, value) => {
t.TypeRegistry.Set<TInstance>('ValibotInstance', (schema, value) => {
return v.safeParse(schema.schema, value).success
})
export interface TInstance<Type extends v.InstanceSchema<v.Class, any> = v.InstanceSchema<v.Class, any>> extends tb.TSchema {
[tb.Kind]: 'ValibotInstance'
export interface TInstance<Type extends v.InstanceSchema<v.Class, any> = v.InstanceSchema<v.Class, any>> extends t.TSchema {
[t.Kind]: 'ValibotInstance'
static: v.InferOutput<this['type']>
type: Type
}
function Instance<Type extends v.InstanceSchema<v.Class, any>>(type: Type, options?: tb.SchemaOptions): TInstance<Type> {
return tb.CreateType({ [tb.Kind]: 'ValibotInstance', type }, options) as never
function Instance<Type extends v.InstanceSchema<v.Class, any>>(type: Type, options?: t.SchemaOptions): TInstance<Type> {
return t.CreateType({ [t.Kind]: 'ValibotInstance', type }, options) as never
}
type TFromInstance<Type extends v.InstanceSchema<v.Class, any>> = tb.Ensure<TInstance<Type>>
function FromInstance(type: BaseSchema): tb.TSchema {
type TFromInstance<Type extends v.InstanceSchema<v.Class, any>> = t.Ensure<TInstance<Type>>
function FromInstance(type: BaseSchema): t.TSchema {
return Instance(type as v.InstanceSchema<v.Class, any>, Options(type))
}
// ------------------------------------------------------------------
// Intersect
// ------------------------------------------------------------------
// prettier-ignore
type TFromIntersect<Type extends BaseSchema[], Result extends tb.TSchema[] = []> = (
type TFromIntersect<Type extends BaseSchema[], Result extends t.TSchema[] = []> = (
Type extends [infer Left extends BaseSchema, ...infer Right extends BaseSchema[]]
? TFromIntersect<Right, [...Result, TFromType<Left>]>
: tb.TIntersect<Result>
: t.TIntersect<Result>
)
function FromIntersect(type: BaseSchema): tb.TSchema {
function FromIntersect(type: BaseSchema): t.TSchema {
const intersect = type as v.IntersectSchema<BaseSchema[], any>
return tb.Intersect(
return t.Intersect(
intersect.options.map((option) => FromType(option)),
Options(type),
)
@@ -348,268 +349,268 @@ function FromIntersect(type: BaseSchema): tb.TSchema {
// ------------------------------------------------------------------
// Literal
// ------------------------------------------------------------------
type TFromLiteral<Value extends tb.TLiteralValue> = tb.Ensure<tb.TLiteral<Value>>
function FromLiteral(type: BaseSchema): tb.TSchema {
const literal = type as v.LiteralSchema<tb.TLiteralValue, any>
return tb.Literal(literal.literal, Options(type))
type TFromLiteral<Value extends t.TLiteralValue> = t.Ensure<t.TLiteral<Value>>
function FromLiteral(type: BaseSchema): t.TSchema {
const literal = type as v.LiteralSchema<t.TLiteralValue, any>
return t.Literal(literal.literal, Options(type))
}
// ------------------------------------------------------------------
// LooseObject
// ------------------------------------------------------------------
type TFromLooseObject<Properties extends v.ObjectEntries> = tb.Ensure<
tb.TObject<{
type TFromLooseObject<Properties extends v.ObjectEntries> = t.Ensure<
t.TObject<{
-readonly [Key in keyof Properties]: TFromType<Properties[Key]>
}>
>
function FromLooseObject(type: BaseSchema): tb.TSchema {
function FromLooseObject(type: BaseSchema): t.TSchema {
const object = type as v.LooseObjectSchema<v.ObjectEntries, any>
const keys = globalThis.Object.getOwnPropertyNames(object.entries)
return tb.Object(
return t.Object(
keys.reduce((properties, key) => {
return { ...properties, [key]: FromType(object.entries[key]) }
}, {} as tb.TProperties),
}, {} as t.TProperties),
Options(type),
)
}
// ------------------------------------------------------------------
// LooseTuple
// ------------------------------------------------------------------
tb.TypeRegistry.Set<TLooseTuple>('ValibotLooseTuple', (schema, value) => {
t.TypeRegistry.Set<TLooseTuple>('ValibotLooseTuple', (schema, value) => {
return v.safeParse(schema.schema, value).success
})
export interface TLooseTuple<Type extends v.LooseTupleSchema<BaseSchema[], any> = v.LooseTupleSchema<BaseSchema[], any>> extends tb.TSchema {
[tb.Kind]: 'ValibotLooseTuple'
export interface TLooseTuple<Type extends v.LooseTupleSchema<BaseSchema[], any> = v.LooseTupleSchema<BaseSchema[], any>> extends t.TSchema {
[t.Kind]: 'ValibotLooseTuple'
static: v.InferOutput<this['type']>
type: Type
}
function LooseTuple<Type extends v.LooseTupleSchema<BaseSchema[], any>>(type: Type, schema?: tb.SchemaOptions): TLooseTuple<Type> {
return tb.CreateType({ [tb.Kind]: 'ValibotLooseTuple', type }) as never
function LooseTuple<Type extends v.LooseTupleSchema<BaseSchema[], any>>(type: Type, schema?: t.SchemaOptions): TLooseTuple<Type> {
return t.CreateType({ [t.Kind]: 'ValibotLooseTuple', type }) as never
}
type TFromLooseTuple<Type extends v.LooseTupleSchema<BaseSchema[], any>> = tb.Ensure<TLooseTuple<Type>>
function FromLooseTuple(type: BaseSchema): tb.TSchema {
type TFromLooseTuple<Type extends v.LooseTupleSchema<BaseSchema[], any>> = t.Ensure<TLooseTuple<Type>>
function FromLooseTuple(type: BaseSchema): t.TSchema {
return LooseTuple(type as v.LooseTupleSchema<BaseSchema[], any>, Options(type))
}
// ------------------------------------------------------------------
// Map
// ------------------------------------------------------------------
tb.TypeRegistry.Set<TMap>('ValibotMap', (schema, value) => {
t.TypeRegistry.Set<TMap>('ValibotMap', (schema, value) => {
return v.safeParse(schema.schema, value).success
})
export interface TMap<Type extends v.MapSchema<BaseSchema, BaseSchema, any> = v.MapSchema<BaseSchema, BaseSchema, any>> extends tb.TSchema {
[tb.Kind]: 'ValibotMap'
export interface TMap<Type extends v.MapSchema<BaseSchema, BaseSchema, any> = v.MapSchema<BaseSchema, BaseSchema, any>> extends t.TSchema {
[t.Kind]: 'ValibotMap'
static: v.InferOutput<this['type']>
type: Type
}
function _Map<Type extends v.MapSchema<BaseSchema, BaseSchema, any>>(type: Type, options?: tb.SchemaOptions): TMap<Type> {
return tb.CreateType({ [tb.Kind]: 'ValibotMap', type }) as never
function _Map<Type extends v.MapSchema<BaseSchema, BaseSchema, any>>(type: Type, options?: t.SchemaOptions): TMap<Type> {
return t.CreateType({ [t.Kind]: 'ValibotMap', type }) as never
}
type TFromMap<Type extends v.MapSchema<BaseSchema, BaseSchema, any>> = tb.Ensure<TMap<Type>>
function FromMap(type: BaseSchema): tb.TSchema {
type TFromMap<Type extends v.MapSchema<BaseSchema, BaseSchema, any>> = t.Ensure<TMap<Type>>
function FromMap(type: BaseSchema): t.TSchema {
return _Map(type as v.MapSchema<BaseSchema, BaseSchema, any>, Options(type))
}
// ------------------------------------------------------------------
// NaN
// ------------------------------------------------------------------
tb.TypeRegistry.Set<TNaN>('ValibotNaN', (schema, value) => {
t.TypeRegistry.Set<TNaN>('ValibotNaN', (schema, value) => {
return v.safeParse(schema.schema, value).success
})
export interface TNaN<Type extends v.NanSchema<any> = v.NanSchema<any>> extends tb.TSchema {
[tb.Kind]: 'ValibotNaN'
export interface TNaN<Type extends v.NanSchema<any> = v.NanSchema<any>> extends t.TSchema {
[t.Kind]: 'ValibotNaN'
static: v.InferOutput<this['type']>
type: Type
}
function _NaN<Type extends v.NanSchema<any>>(type: Type, options?: tb.SchemaOptions): TNaN<Type> {
return tb.CreateType({ [tb.Kind]: 'ValibotNaN', type }, options) as never
function _NaN<Type extends v.NanSchema<any>>(type: Type, options?: t.SchemaOptions): TNaN<Type> {
return t.CreateType({ [t.Kind]: 'ValibotNaN', type }, options) as never
}
type TFromNaN<Type extends v.NanSchema<any>> = tb.Ensure<TNaN<Type>>
function FromNaN(type: BaseSchema): tb.TSchema {
type TFromNaN<Type extends v.NanSchema<any>> = t.Ensure<TNaN<Type>>
function FromNaN(type: BaseSchema): t.TSchema {
return _NaN(type as v.NanSchema<any>, Options(type))
}
// ------------------------------------------------------------------
// Never
// ------------------------------------------------------------------
type TFromNever<_Type extends v.NeverSchema<any>> = tb.TNever
function FromNever(type: BaseSchema): tb.TSchema {
return tb.Never(Options(type))
type TFromNever<_Type extends v.NeverSchema<any>> = t.TNever
function FromNever(type: BaseSchema): t.TSchema {
return t.Never(Options(type))
}
// ------------------------------------------------------------------
// NonNullable
// ------------------------------------------------------------------
type TFromNonNullable<Type extends BaseSchema> = tb.TExclude<TFromType<Type>, tb.TNull>
function FromNonNullable(type: BaseSchema): tb.TSchema {
type TFromNonNullable<Type extends BaseSchema> = t.TExclude<TFromType<Type>, t.TNull>
function FromNonNullable(type: BaseSchema): t.TSchema {
const non_nullable = type as v.NonNullableSchema<BaseSchema, any>
return tb.Exclude(FromType(non_nullable.wrapped), tb.Null(), Options(type))
return t.Exclude(FromType(non_nullable.wrapped), t.Null(), Options(type))
}
// ------------------------------------------------------------------
// NonNullish
// ------------------------------------------------------------------
type TFromNonNullish<Type extends BaseSchema> = tb.TExclude<TFromType<Type>, tb.TUnion<[tb.TNull, tb.TUndefined]>>
function FromNonNullish(type: BaseSchema): tb.TSchema {
type TFromNonNullish<Type extends BaseSchema> = t.TExclude<TFromType<Type>, t.TUnion<[t.TNull, t.TUndefined]>>
function FromNonNullish(type: BaseSchema): t.TSchema {
const non_nullish = type as v.NonNullishSchema<BaseSchema, any>
return tb.Exclude(FromType(non_nullish.wrapped), tb.Union([tb.Null(), tb.Undefined()]), Options(type))
return t.Exclude(FromType(non_nullish.wrapped), t.Union([t.Null(), t.Undefined()]), Options(type))
}
// ------------------------------------------------------------------
// NonOptional
// ------------------------------------------------------------------
type TFromNonOptional<Type extends BaseSchema, Result extends TFromType<Type> = TFromType<Type>> = tb.TOptionalWithFlag<Result, false>
function FromNonOptional(type: BaseSchema): tb.TSchema {
type TFromNonOptional<Type extends BaseSchema, Result extends TFromType<Type> = TFromType<Type>> = t.TOptionalWithFlag<Result, false>
function FromNonOptional(type: BaseSchema): t.TSchema {
const non_optional = type as v.NonOptionalSchema<BaseSchema, any>
return tb.Optional(FromType(non_optional.wrapped), false)
return t.Optional(FromType(non_optional.wrapped), false)
}
// ------------------------------------------------------------------
// Null
// ------------------------------------------------------------------
type TFromNull<_Type extends v.NullSchema<any>> = tb.TNull
type TFromNull<_Type extends v.NullSchema<any>> = t.TNull
function FromNull(type: BaseSchema) {
return tb.Null(Options(type))
return t.Null(Options(type))
}
// ------------------------------------------------------------------
// Nullable
// ------------------------------------------------------------------
type TFromNullable<Type extends BaseSchema> = tb.TUnion<[TFromType<Type>, tb.TNull]>
type TFromNullable<Type extends BaseSchema> = t.TUnion<[TFromType<Type>, t.TNull]>
function FromNullable(type: BaseSchema) {
const nullable = type as v.NullableSchema<BaseSchema, any>
return tb.Union([tb.Null(), FromType(nullable.wrapped)], Options(type))
return t.Union([t.Null(), FromType(nullable.wrapped)], Options(type))
}
// ------------------------------------------------------------------
// Nullish
// ------------------------------------------------------------------
type TFromNullish<Type extends BaseSchema> = tb.TUnion<[TFromType<Type>, tb.TNull, tb.TUndefined]>
type TFromNullish<Type extends BaseSchema> = t.TUnion<[TFromType<Type>, t.TNull, t.TUndefined]>
function FromNullish(type: BaseSchema) {
const nullish = type as v.NullishSchema<BaseSchema, any>
return tb.Union([FromType(nullish.wrapped), tb.Null(), tb.Undefined()], Options(type))
return t.Union([FromType(nullish.wrapped), t.Null(), t.Undefined()], Options(type))
}
// ------------------------------------------------------------------
// Number
// ------------------------------------------------------------------
type TFromNumber<_Type extends v.NumberSchema<any>> = tb.TNumber
function FromNumber(type: BaseSchema): tb.TSchema {
return tb.Number(Options(type))
type TFromNumber<_Type extends v.NumberSchema<any>> = t.TNumber
function FromNumber(type: BaseSchema): t.TSchema {
return t.Number(Options(type))
}
// ------------------------------------------------------------------
// Object
// ------------------------------------------------------------------
type TFromObject<Properties extends v.ObjectEntries> = tb.Ensure<
tb.TObject<{
type TFromObject<Properties extends v.ObjectEntries> = t.Ensure<
t.TObject<{
-readonly [Key in keyof Properties]: TFromType<Properties[Key]>
}>
>
function FromObject(type: BaseSchema): tb.TSchema {
function FromObject(type: BaseSchema): t.TSchema {
const object = type as v.ObjectSchema<v.ObjectEntries, any>
const keys = globalThis.Object.getOwnPropertyNames(object.entries)
return tb.Object(
return t.Object(
keys.reduce((properties, key) => {
return { ...properties, [key]: FromType(object.entries[key]) }
}, {} as tb.TProperties),
}, {} as t.TProperties),
Options(type),
)
}
// ------------------------------------------------------------------
// ObjectWithRest
// ------------------------------------------------------------------
type TFromObjectWithRest<Properties extends v.ObjectEntries, _Rest extends BaseSchema> = tb.Ensure<
tb.TObject<{
type TFromObjectWithRest<Properties extends v.ObjectEntries, _Rest extends BaseSchema> = t.Ensure<
t.TObject<{
-readonly [Key in keyof Properties]: TFromType<Properties[Key]>
}>
>
function FromObjectWithRest(type: BaseSchema): tb.TSchema {
function FromObjectWithRest(type: BaseSchema): t.TSchema {
const object = type as v.ObjectWithRestSchema<v.ObjectEntries, BaseSchema, any>
const keys = globalThis.Object.getOwnPropertyNames(object.entries)
return tb.Object(
return t.Object(
keys.reduce((properties, key) => {
return { ...properties, [key]: FromType(object.entries[key]) }
}, {} as tb.TProperties),
}, {} as t.TProperties),
{ ...Options(type), additionalProperties: FromType(object.rest) },
)
}
// ------------------------------------------------------------------
// Optional
// ------------------------------------------------------------------
type TFromOptional<Type extends BaseSchema, Result extends TFromType<Type> = TFromType<Type>> = tb.TOptionalWithFlag<Result, true>
function FromOptional(type: BaseSchema): tb.TSchema {
type TFromOptional<Type extends BaseSchema, Result extends TFromType<Type> = TFromType<Type>> = t.TOptionalWithFlag<Result, true>
function FromOptional(type: BaseSchema): t.TSchema {
const optional = type as v.OptionalSchema<BaseSchema, any>
return tb.Optional(FromType(optional.wrapped))
return t.Optional(FromType(optional.wrapped))
}
// ------------------------------------------------------------------
// PickList
// ------------------------------------------------------------------
type PickListOption = string | number | bigint
// prettier-ignore
type TFromPickList<Options extends PickListOption[], Result extends tb.TSchema[] = []> = (
type TFromPickList<Options extends PickListOption[], Result extends t.TSchema[] = []> = (
Options extends [infer Left extends PickListOption, ...infer Right extends PickListOption[]]
? (
Left extends tb.TLiteralValue
? TFromPickList<Right, [...Result, tb.TLiteral<Left>]>
Left extends t.TLiteralValue
? TFromPickList<Right, [...Result, t.TLiteral<Left>]>
: TFromPickList<Right, [...Result]>
)
: tb.TUnion<Result>
: t.TUnion<Result>
)
function FromPickList(type: BaseSchema): tb.TSchema {
function FromPickList(type: BaseSchema): t.TSchema {
const picklist = type as v.PicklistSchema<v.PicklistOptions, any>
return tb.Union(
picklist.options.map((option) => tb.Literal(option as tb.TLiteralValue)),
return t.Union(
picklist.options.map((option) => t.Literal(option as t.TLiteralValue)),
Options(type),
)
}
// ------------------------------------------------------------------
// Promise
// ------------------------------------------------------------------
tb.TypeRegistry.Set<TPromise>('ValibotPromise', (schema, value) => {
t.TypeRegistry.Set<TPromise>('ValibotPromise', (schema, value) => {
return v.safeParse(schema.schema, value).success
})
export interface TPromise<Type extends v.PromiseSchema<any> = v.PromiseSchema<any>> extends tb.TSchema {
[tb.Kind]: 'ValibotPromise'
export interface TPromise<Type extends v.PromiseSchema<any> = v.PromiseSchema<any>> extends t.TSchema {
[t.Kind]: 'ValibotPromise'
static: v.InferOutput<this['type']>
type: Type
}
function _Promise<Type extends v.PromiseSchema<any>>(type: Type, options?: tb.SchemaOptions): TPromise<Type> {
return tb.CreateType({ [tb.Kind]: 'ValibotPromise', type }, options) as never
function _Promise<Type extends v.PromiseSchema<any>>(type: Type, options?: t.SchemaOptions): TPromise<Type> {
return t.CreateType({ [t.Kind]: 'ValibotPromise', type }, options) as never
}
type TFromPromise<Type extends v.PromiseSchema<any>> = tb.Ensure<TPromise<Type>>
function FromPromise(type: BaseSchema): tb.TSchema {
type TFromPromise<Type extends v.PromiseSchema<any>> = t.Ensure<TPromise<Type>>
function FromPromise(type: BaseSchema): t.TSchema {
return _Promise(type as v.PromiseSchema<any>, Options(type))
}
// ------------------------------------------------------------------
// Record
// ------------------------------------------------------------------
type TFromRecord<Key extends BaseRecordKey, Value extends BaseSchema> = tb.Ensure<tb.TRecordOrObject<TFromType<Key>, TFromType<Value>>>
type TFromRecord<Key extends BaseRecordKey, Value extends BaseSchema> = t.Ensure<t.TRecordOrObject<TFromType<Key>, TFromType<Value>>>
function FromRecord(type: BaseSchema) {
const record = type as v.RecordSchema<BaseRecordKey, BaseSchema, any>
return tb.Record(FromType(record.key), FromType(record.value), Options(type))
return t.Record(FromType(record.key), FromType(record.value), Options(type))
}
// ------------------------------------------------------------------
// Set
// ------------------------------------------------------------------
tb.TypeRegistry.Set<TInstance>('ValibotSet', (schema, value) => {
t.TypeRegistry.Set<TInstance>('ValibotSet', (schema, value) => {
return v.safeParse(schema.schema, value).success
})
export interface TSet<Type extends v.SetSchema<BaseSchema, any> = v.SetSchema<BaseSchema, any>> extends tb.TSchema {
[tb.Kind]: 'ValibotSet'
export interface TSet<Type extends v.SetSchema<BaseSchema, any> = v.SetSchema<BaseSchema, any>> extends t.TSchema {
[t.Kind]: 'ValibotSet'
static: v.InferOutput<this['type']> extends infer Result ? Result : never
type: Type
}
function Set<Type extends v.SetSchema<BaseSchema, any>>(type: Type, options?: tb.SchemaOptions): TSet<Type> {
return tb.CreateType({ [tb.Kind]: 'ValibotSet', type }, options) as never
function Set<Type extends v.SetSchema<BaseSchema, any>>(type: Type, options?: t.SchemaOptions): TSet<Type> {
return t.CreateType({ [t.Kind]: 'ValibotSet', type }, options) as never
}
type TFromSet<Type extends v.SetSchema<BaseSchema, any>> = tb.Ensure<TSet<Type>>
function FromSet(type: BaseSchema): tb.TSchema {
type TFromSet<Type extends v.SetSchema<BaseSchema, any>> = t.Ensure<TSet<Type>>
function FromSet(type: BaseSchema): t.TSchema {
return Set(type as v.SetSchema<BaseSchema, any>)
}
// ------------------------------------------------------------------
// StrictObject
// ------------------------------------------------------------------
type TFromStrictObject<Properties extends v.ObjectEntries> = tb.Ensure<
tb.TObject<{
type TFromStrictObject<Properties extends v.ObjectEntries> = t.Ensure<
t.TObject<{
-readonly [Key in keyof Properties]: TFromType<Properties[Key]>
}>
>
function FromStrictObject(type: BaseSchema): tb.TSchema {
function FromStrictObject(type: BaseSchema): t.TSchema {
const object = type as v.StrictObjectSchema<v.ObjectEntries, any>
const keys = globalThis.Object.getOwnPropertyNames(object.entries)
return tb.Object(
return t.Object(
keys.reduce((properties, key) => {
return { ...properties, [key]: FromType(object.entries[key]) }
}, {} as tb.TProperties),
}, {} as t.TProperties),
{ ...Options(type), additionalProperties: false },
)
}
@@ -617,121 +618,121 @@ function FromStrictObject(type: BaseSchema): tb.TSchema {
// StrictTuple
// ------------------------------------------------------------------
// prettier-ignore
type TFromStrictTuple<Type extends BaseSchema[], Result extends tb.TSchema[] = []> = (
type TFromStrictTuple<Type extends BaseSchema[], Result extends t.TSchema[] = []> = (
Type extends [infer Left extends BaseSchema, ...infer Right extends BaseSchema[]]
? TFromTuple<Right, [...Result, TFromType<Left>]>
: tb.TTuple<Result>
: t.TTuple<Result>
)
function FromStrictTuple(type: BaseSchema): tb.TSchema {
function FromStrictTuple(type: BaseSchema): t.TSchema {
const tuple = type as v.StrictTupleSchema<any, any>
const items = globalThis.Array.isArray(tuple.items) ? tuple.items.map((item) => FromType(item)) : []
return tb.Tuple(items, Options(type))
return t.Tuple(items, Options(type))
}
// ------------------------------------------------------------------
// String
// ------------------------------------------------------------------
type TFromString<_Type extends v.StringSchema<any>> = tb.TString
function FromString(type: BaseSchema): tb.TSchema {
return tb.String(Options(type))
type TFromString<_Type extends v.StringSchema<any>> = t.TString
function FromString(type: BaseSchema): t.TSchema {
return t.String(Options(type))
}
// ------------------------------------------------------------------
// Symbol
// ------------------------------------------------------------------
type TFromSymbol<_Type extends v.SymbolSchema<any>> = tb.TSymbol
function FromSymbol(type: BaseSchema): tb.TSchema {
return tb.Symbol(Options(type))
type TFromSymbol<_Type extends v.SymbolSchema<any>> = t.TSymbol
function FromSymbol(type: BaseSchema): t.TSchema {
return t.Symbol(Options(type))
}
// ------------------------------------------------------------------
// Tuple
// ------------------------------------------------------------------
// prettier-ignore
type TFromTuple<Type extends BaseSchema[], Result extends tb.TSchema[] = []> = (
type TFromTuple<Type extends BaseSchema[], Result extends t.TSchema[] = []> = (
Type extends [infer Left extends BaseSchema, ...infer Right extends BaseSchema[]]
? TFromTuple<Right, [...Result, TFromType<Left>]>
: tb.TTuple<Result>
: t.TTuple<Result>
)
function FromTuple(type: BaseSchema): tb.TSchema {
function FromTuple(type: BaseSchema): t.TSchema {
const tuple = type as v.TupleSchema<any, any>
const items = globalThis.Array.isArray(tuple.items) ? tuple.items.map((item) => FromType(item)) : []
return tb.Tuple(items, Options(type))
return t.Tuple(items, Options(type))
}
// ------------------------------------------------------------------
// TupleWithRest
// ------------------------------------------------------------------
tb.TypeRegistry.Set<TTupleWithRest>('ValibotTupleWithRest', (schema, value) => {
t.TypeRegistry.Set<TTupleWithRest>('ValibotTupleWithRest', (schema, value) => {
return v.safeParse(schema.schema, value).success
})
interface TTupleWithRest<Type extends v.TupleWithRestSchema<BaseSchema[], BaseSchema, any> = v.TupleWithRestSchema<BaseSchema[], BaseSchema, any>> extends tb.TSchema {
[tb.Kind]: 'ValibotTupleWithRest'
interface TTupleWithRest<Type extends v.TupleWithRestSchema<BaseSchema[], BaseSchema, any> = v.TupleWithRestSchema<BaseSchema[], BaseSchema, any>> extends t.TSchema {
[t.Kind]: 'ValibotTupleWithRest'
static: v.InferOutput<this['type']>
type: Type
}
function TupleWithRest<Type extends v.TupleWithRestSchema<BaseSchema[], BaseSchema, any>>(type: Type, options?: tb.SchemaOptions): TTupleWithRest<Type> {
return tb.CreateType({ [tb.Kind]: 'ValibotTupleWithRest', type }, Options(type)) as never
function TupleWithRest<Type extends v.TupleWithRestSchema<BaseSchema[], BaseSchema, any>>(type: Type, options?: t.SchemaOptions): TTupleWithRest<Type> {
return t.CreateType({ [t.Kind]: 'ValibotTupleWithRest', type }, Options(type)) as never
}
type TFromTupleWithRest<Type extends v.TupleWithRestSchema<BaseSchema[], BaseSchema, any>> = tb.Ensure<TTupleWithRest<Type>>
function FromTupleWithRest(type: BaseSchema): tb.TSchema {
type TFromTupleWithRest<Type extends v.TupleWithRestSchema<BaseSchema[], BaseSchema, any>> = t.Ensure<TTupleWithRest<Type>>
function FromTupleWithRest(type: BaseSchema): t.TSchema {
return TupleWithRest(type as v.TupleWithRestSchema<BaseSchema[], BaseSchema, any>, Options(type))
}
// ------------------------------------------------------------------
// Undefined
// ------------------------------------------------------------------
type TFromUndefined<_Type extends v.UndefinedSchema<any>> = tb.TUndefined
function FromUndefined(type: BaseSchema): tb.TSchema {
return tb.Undefined(Options(type))
type TFromUndefined<_Type extends v.UndefinedSchema<any>> = t.TUndefined
function FromUndefined(type: BaseSchema): t.TSchema {
return t.Undefined(Options(type))
}
// ------------------------------------------------------------------
// Undefinable
// ------------------------------------------------------------------
type TFromUndefinedable<Type extends BaseSchema> = tb.TUnion<[TFromType<Type>, tb.TUndefined]>
function FromUndefinedable(type: BaseSchema): tb.TSchema {
type TFromUndefinedable<Type extends BaseSchema> = t.TUnion<[TFromType<Type>, t.TUndefined]>
function FromUndefinedable(type: BaseSchema): t.TSchema {
const undefinedable = type as v.UndefinedableSchema<BaseSchema, any>
return tb.Union([FromType(undefinedable.wrapped), tb.Undefined()], Options(type))
return t.Union([FromType(undefinedable.wrapped), t.Undefined()], Options(type))
}
// ------------------------------------------------------------------
// Union
// ------------------------------------------------------------------
// prettier-ignore
type TFromUnion<Type extends BaseSchema[], Result extends tb.TSchema[] = []> = (
type TFromUnion<Type extends BaseSchema[], Result extends t.TSchema[] = []> = (
Type extends [infer Left extends BaseSchema, ...infer Right extends BaseSchema[]]
? TFromUnion<Right, [...Result, TFromType<Left>]>
: tb.TUnion<Result>
: t.TUnion<Result>
)
function FromUnion(type: BaseSchema): tb.TSchema {
function FromUnion(type: BaseSchema): t.TSchema {
const variants = (type as v.UnionSchema<BaseSchema[], any>).options.map((option) => FromType(option))
return tb.Union(variants, Options(type))
return t.Union(variants, Options(type))
}
// ------------------------------------------------------------------
// Unknown
// ------------------------------------------------------------------
type TFromUnknown<_Type extends v.UnknownSchema> = tb.TUnknown
function FromUnknown(type: BaseSchema): tb.TSchema {
return tb.Unknown(Options(type))
type TFromUnknown<_Type extends v.UnknownSchema> = t.TUnknown
function FromUnknown(type: BaseSchema): t.TSchema {
return t.Unknown(Options(type))
}
// ------------------------------------------------------------------
// Variant
// ------------------------------------------------------------------
tb.TypeRegistry.Set<TVariant>('ValibotVariant', (schema, value) => {
t.TypeRegistry.Set<TVariant>('ValibotVariant', (schema, value) => {
return v.safeParse(schema.schema, value).success
})
interface TVariant<Type extends v.VariantSchema<string, v.VariantOptions<string>, any> = v.VariantSchema<string, v.VariantOptions<string>, any>> extends tb.TSchema {
[tb.Kind]: 'ValibotVariant'
interface TVariant<Type extends v.VariantSchema<string, v.VariantOptions<string>, any> = v.VariantSchema<string, v.VariantOptions<string>, any>> extends t.TSchema {
[t.Kind]: 'ValibotVariant'
static: v.InferOutput<this['type']>
type: Type
}
function Variant<Type extends v.VariantSchema<string, v.VariantOptions<string>, any>>(type: Type): TVariant<Type> {
return tb.CreateType({ [tb.Kind]: 'ValibotVariant', type }, Options(type)) as never
return t.CreateType({ [t.Kind]: 'ValibotVariant', type }, Options(type)) as never
}
type TFromVariant<Type extends v.VariantSchema<string, v.VariantOptions<string>, any>> = tb.Ensure<TVariant<Type>>
function FromVariant(type: BaseSchema): tb.TSchema {
type TFromVariant<Type extends v.VariantSchema<string, v.VariantOptions<string>, any>> = t.Ensure<TVariant<Type>>
function FromVariant(type: BaseSchema): t.TSchema {
return Variant(type as v.VariantSchema<string, v.VariantOptions<string>, any>)
}
// ------------------------------------------------------------------
// Void
// ------------------------------------------------------------------
type TFromVoid<_Type extends v.VoidSchema<any>> = tb.TVoid
function FromVoid(type: BaseSchema): tb.TSchema {
return tb.Void(Options(type))
type TFromVoid<_Type extends v.VoidSchema<any>> = t.TVoid
function FromVoid(type: BaseSchema): t.TSchema {
return t.Void(Options(type))
}
// ------------------------------------------------------------------
// Type
@@ -753,7 +754,7 @@ export type TFromType<Type extends BaseSchema> = (
Type extends v.FunctionSchema<any> ? TFromFunction<Type> :
Type extends v.InstanceSchema<v.Class, any> ? TFromInstance<Type> :
Type extends v.IntersectSchema<infer Types extends BaseSchema[], any> ? TFromIntersect<Types> :
Type extends v.LiteralSchema<infer Value extends tb.TLiteralValue, any> ? TFromLiteral<Value> :
Type extends v.LiteralSchema<infer Value extends t.TLiteralValue, any> ? TFromLiteral<Value> :
Type extends v.LooseObjectSchema<infer Properties extends v.ObjectEntries, any> ? TFromLooseObject<Properties> :
Type extends v.LooseTupleSchema<BaseSchema[], any> ? TFromLooseTuple<Type> :
Type extends v.MapSchema<BaseSchema, BaseSchema, any> ? TFromMap<Type> :
@@ -785,7 +786,7 @@ export type TFromType<Type extends BaseSchema> = (
Type extends v.UnknownSchema ? TFromUnknown<Type> :
Type extends v.VariantSchema<string, v.VariantOptions<string>, any> ? TFromVariant<Type> :
Type extends v.VoidSchema<any> ? TFromVoid<Type> :
tb.TNever
t.TNever
)
// prettier-ignore
export function FromType<Type extends BaseSchema>(type: Type): TFromType<Type> {
@@ -834,35 +835,18 @@ export function FromType<Type extends BaseSchema>(type: Type): TFromType<Type> {
type.type === 'union' ? FromUnion(type) :
type.type === 'variant' ? FromVariant(type) :
type.type === 'void' ? FromVoid(type) :
tb.Never()
t.Never()
) as never
}
// ------------------------------------------------------------------
// IsValibot
// TypeBoxFromValibot
// ------------------------------------------------------------------
// prettier-ignore
export function IsValibot(type: unknown): type is BaseSchema {
return (
tb.ValueGuard.IsObject(type) &&
tb.ValueGuard.HasPropertyKey(type, '~standard') &&
tb.ValueGuard.IsObject(type['~standard']) &&
tb.ValueGuard.HasPropertyKey(type['~standard'], 'vendor') &&
type['~standard'].vendor === 'valibot'
)
}
// ------------------------------------------------------------------
// Box
// ------------------------------------------------------------------
/** Converts a Valibot Type to a TypeBox Type */
// prettier-ignore
export type TBox<Type extends unknown> = (
Type extends BaseSchema
? Type extends { '~standard': { vendor: 'valibot' } }
? TFromType<Type>
: undefined
: undefined
export type TTypeBoxFromValibot<Type extends unknown> = (
Type extends BaseSchema ? TFromType<Type> : t.TNever
)
/** Converts a Valibot Type to a TypeBox Type */
export function Box<Type extends unknown, Result extends TBox<Type> = TBox<Type>>(type: Type): Result {
return (IsValibot(type) ? FromType(type) : undefined) as never
// prettier-ignore
export function TypeBoxFromValibot<Type extends unknown, Result extends TTypeBoxFromValibot<Type> = TTypeBoxFromValibot<Type>>(type: Type): Result {
return (Guard.IsValibot(type) ? FromType(type) : t.Never()) as never
}

View File

@@ -1,6 +1,6 @@
/*--------------------------------------------------------------------------
@sinclair/typebox-adapter
@sinclair/typemap
The MIT License (MIT)
@@ -26,106 +26,106 @@ THE SOFTWARE.
---------------------------------------------------------------------------*/
import * as tb from '@sinclair/typebox'
import * as t from '@sinclair/typebox'
import * as z from 'zod'
import * as Guard from '../guard'
// ------------------------------------------------------------------
// Options
// ------------------------------------------------------------------
function Options(type: z.ZodTypeAny): tb.SchemaOptions {
const description = tb.ValueGuard.IsUndefined(type.description) ? {} : { description: type.description }
function Options(type: z.ZodTypeAny): t.SchemaOptions {
const description = t.ValueGuard.IsUndefined(type.description) ? {} : { description: type.description }
return { ...description }
}
// ------------------------------------------------------------------
// Formats
// ------------------------------------------------------------------
const check = (type: z.ZodTypeAny, value: unknown) => type.safeParse(value).success
tb.FormatRegistry.Set('zod:base64', (value) => check(z.string().base64(), value))
tb.FormatRegistry.Set('zod:base64url', (value) => check(z.string().base64url(), value))
tb.FormatRegistry.Set('zod:cidrv4', (value) => check(z.string().cidr({ version: 'v4' }), value))
tb.FormatRegistry.Set('zod:cidrv6', (value) => check(z.string().cidr({ version: 'v6' }), value))
tb.FormatRegistry.Set('zod:cidr', (value) => check(z.string().cidr(), value))
tb.FormatRegistry.Set('zod:cuid', (value) => check(z.string().cuid(), value))
tb.FormatRegistry.Set('zod:cuid2', (value) => check(z.string().cuid2(), value))
tb.FormatRegistry.Set('zod:ulid', (value) => check(z.string().ulid(), value))
tb.FormatRegistry.Set('zod:email', (value) => check(z.string().email(), value))
tb.FormatRegistry.Set('zod:emoji', (value) => check(z.string().emoji(), value))
tb.FormatRegistry.Set('zod:ipv4', (value) => check(z.string().ip({ version: 'v4' }), value))
tb.FormatRegistry.Set('zod:ipv6', (value) => check(z.string().ip({ version: 'v6' }), value))
tb.FormatRegistry.Set('zod:ip', (value) => check(z.string().ip(), value))
tb.FormatRegistry.Set('zod:ipv6Cidr', (value) => check(z.string().cidr({ version: 'v6' }), value))
tb.FormatRegistry.Set('zod:nanoid', (value) => check(z.string().nanoid(), value))
tb.FormatRegistry.Set('zod:jwt', (value) => check(z.string().jwt(), value))
tb.FormatRegistry.Set('zod:date', (value) => check(z.string().date(), value))
tb.FormatRegistry.Set('zod:datetime', (value) => check(z.string().datetime(), value))
tb.FormatRegistry.Set('zod:duration', (value) => check(z.string().duration(), value))
tb.FormatRegistry.Set('zod:time', (value) => check(z.string().time(), value))
tb.FormatRegistry.Set('zod:url', (value) => check(z.string().url(), value))
tb.FormatRegistry.Set('zod:uuid', (value) => check(z.string().uuid(), value))
t.FormatRegistry.Set('base64', (value) => check(z.string().base64(), value))
t.FormatRegistry.Set('base64url', (value) => check(z.string().base64url(), value))
t.FormatRegistry.Set('cidrv4', (value) => check(z.string().cidr({ version: 'v4' }), value))
t.FormatRegistry.Set('cidrv6', (value) => check(z.string().cidr({ version: 'v6' }), value))
t.FormatRegistry.Set('cidr', (value) => check(z.string().cidr(), value))
t.FormatRegistry.Set('cuid', (value) => check(z.string().cuid(), value))
t.FormatRegistry.Set('cuid2', (value) => check(z.string().cuid2(), value))
t.FormatRegistry.Set('date', (value) => check(z.string().date(), value))
t.FormatRegistry.Set('datetime', (value) => check(z.string().datetime(), value))
t.FormatRegistry.Set('duration', (value) => check(z.string().duration(), value))
t.FormatRegistry.Set('email', (value) => check(z.string().email(), value))
t.FormatRegistry.Set('emoji', (value) => check(z.string().emoji(), value))
t.FormatRegistry.Set('ipv4', (value) => check(z.string().ip({ version: 'v4' }), value))
t.FormatRegistry.Set('ipv6', (value) => check(z.string().ip({ version: 'v6' }), value))
t.FormatRegistry.Set('ip', (value) => check(z.string().ip(), value))
t.FormatRegistry.Set('jwt', (value) => check(z.string().jwt(), value))
t.FormatRegistry.Set('nanoid', (value) => check(z.string().nanoid(), value))
t.FormatRegistry.Set('time', (value) => check(z.string().time(), value))
t.FormatRegistry.Set('ulid', (value) => check(z.string().ulid(), value))
t.FormatRegistry.Set('url', (value) => check(z.string().url(), value))
t.FormatRegistry.Set('uuid', (value) => check(z.string().uuid(), value))
// ------------------------------------------------------------------
// Any
// ------------------------------------------------------------------
type TFromAny = tb.TAny
function FromAny<Def extends z.ZodAnyDef>(_def: Def) {
return tb.Any()
type TFromAny = t.TAny
function FromAny<Def extends z.ZodAnyDef>(_def: Def): t.TSchema {
return t.Any()
}
// ------------------------------------------------------------------
// Array
// ------------------------------------------------------------------
type TFromArray<Type extends z.ZodTypeAny> = tb.Ensure<tb.TArray<TFromType<Type>>>
function FromArray<Def extends z.ZodArrayDef>(def: Def): tb.TSchema {
type TFromArray<Type extends z.ZodTypeAny> = t.Ensure<t.TArray<TFromType<Type>>>
function FromArray<Def extends z.ZodArrayDef>(def: Def): t.TSchema {
const minItems = def.minLength === null ? {} : { minItems: def.minLength.value }
const maxItems = def.maxLength === null ? {} : { minItems: def.maxLength.value }
const options = { ...minItems, ...maxItems }
return tb.Array(FromType(def.type), options)
return t.Array(FromType(def.type), options)
}
// ------------------------------------------------------------------
// BigInt
// ------------------------------------------------------------------
type TFromBigInt = tb.TBigInt
function FromBigInt<Def extends z.ZodBigIntDef>(def: Def) {
return tb.BigInt()
type TFromBigInt = t.TBigInt
function FromBigInt<Def extends z.ZodBigIntDef>(def: Def): t.TSchema {
return t.BigInt()
}
// ------------------------------------------------------------------
// Boolean
// ------------------------------------------------------------------
type TFromBoolean = tb.TBoolean
function FromBoolean<Def extends z.ZodBooleanDef>(def: Def) {
return tb.Boolean()
type TFromBoolean = t.TBoolean
function FromBoolean<Def extends z.ZodBooleanDef>(def: Def): t.TSchema {
return t.Boolean()
}
// ------------------------------------------------------------------
// Date
// ------------------------------------------------------------------
type TFromDate = tb.TDate
function FromDate<Def extends z.ZodDateDef>(def: Def) {
return tb.Date()
type TFromDate = t.TDate
function FromDate<Def extends z.ZodDateDef>(def: Def): t.TSchema {
return t.Date()
}
// ------------------------------------------------------------------
// Default
// ------------------------------------------------------------------
type TFromDefault<Type extends z.ZodType> = TFromType<Type>
function FromDefault<Def extends z.ZodDefaultDef>(def: Def): tb.TSchema {
return tb.CloneType(FromType(def.innerType), { default: def.defaultValue() })
function FromDefault<Def extends z.ZodDefaultDef>(def: Def): t.TSchema {
return t.CloneType(FromType(def.innerType), { default: def.defaultValue() })
}
// ------------------------------------------------------------------
// DiscriminatedUnion
// ------------------------------------------------------------------
// prettier-ignore
type TFromDiscriminatedUnion<Discriminator extends string, Types extends readonly z.ZodObject<any>[], Result extends tb.TSchema[] = []> = (
type TFromDiscriminatedUnion<Discriminator extends string, Types extends readonly z.ZodObject<any>[], Result extends t.TSchema[] = []> = (
Types extends [infer Left extends z.ZodObject<any>, ...infer Right extends z.ZodObject<any>[]]
? TFromDiscriminatedUnion<Discriminator, Right, [...Result, TFromType<Left>]>
: tb.TUnion<Result>
: t.TUnion<Result>
)
function FromDiscriminatedUnion<Def extends z.ZodDiscriminatedUnionDef<string, z.ZodDiscriminatedUnionOption<string>[]>>(def: Def): tb.TSchema {
function FromDiscriminatedUnion<Def extends z.ZodDiscriminatedUnionDef<string, z.ZodDiscriminatedUnionOption<string>[]>>(def: Def): t.TSchema {
const types = def.options.map((type) => FromType(type))
return tb.Union(types, { discriminator: def.discriminator })
return t.Union(types, { discriminator: def.discriminator })
}
// ------------------------------------------------------------------
// Effects
// ------------------------------------------------------------------
type TFromEffects<Input extends z.ZodTypeAny, Output extends unknown> = tb.Ensure<tb.TTransform<TFromType<Input>, Output>>
function FromEffects<Type extends z.ZodEffects<z.ZodTypeAny, unknown>>(type: Type): tb.TSchema {
return tb
type TFromEffects<Input extends z.ZodTypeAny, Output extends unknown> = t.Ensure<t.TTransform<TFromType<Input>, Output>>
function FromEffects<Type extends z.ZodEffects<z.ZodTypeAny, unknown>>(type: Type): t.TSchema {
return t
.Transform(FromType(type._def.schema))
.Decode((value) => type.parse(value))
.Encode((_) => {
@@ -133,69 +133,77 @@ function FromEffects<Type extends z.ZodEffects<z.ZodTypeAny, unknown>>(type: Typ
})
}
// ------------------------------------------------------------------
// Enum
// ------------------------------------------------------------------
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))
return t.Union(variants)
}
// ------------------------------------------------------------------
// Literal
// ------------------------------------------------------------------
type TFromLiteral<Value extends unknown> = tb.Ensure<Value extends tb.TLiteralValue ? tb.TLiteral<Value> : tb.TNever>
function FromLiteral<Def extends z.ZodLiteralDef>(def: Def) {
return tb.Literal(def.value as tb.TLiteralValue)
type TFromLiteral<Value extends unknown> = t.Ensure<Value extends t.TLiteralValue ? t.TLiteral<Value> : t.TNever>
function FromLiteral<Def extends z.ZodLiteralDef>(def: Def): t.TSchema {
return t.Literal(def.value as t.TLiteralValue)
}
// ------------------------------------------------------------------
// Intersect
// ------------------------------------------------------------------
// prettier-ignore
type TFromIntersect<Types extends z.ZodTypeAny[], Result extends tb.TSchema[] = []> = (
type TFromIntersect<Types extends z.ZodTypeAny[], Result extends t.TSchema[] = []> = (
Types extends [infer Left extends z.ZodTypeAny, ...infer Right extends z.ZodTypeAny[]]
? TFromIntersect<Right, [...Result, TFromType<Left>]>
: tb.Ensure<tb.TIntersect<Result>>
: t.Ensure<t.TIntersect<Result>>
)
function FromIntersect<Type extends z.ZodIntersectionDef>(type: Type): tb.TSchema {
return tb.Intersect([FromType(type.left), FromType(type.right)])
function FromIntersect<Type extends z.ZodIntersectionDef>(type: Type): t.TSchema {
return t.Intersect([FromType(type.left), FromType(type.right)])
}
// ------------------------------------------------------------------
// Object
// ------------------------------------------------------------------
type TFromObject<Properties extends z.ZodRawShape> = tb.Ensure<
tb.TObject<{
type TFromObject<Properties extends z.ZodRawShape> = t.Ensure<
t.TObject<{
[Key in keyof Properties]: TFromType<Properties[Key]>
}>
>
function FromObject<Def extends z.ZodObjectDef<z.ZodRawShape>, Shape extends z.ZodRawShape>(def: Def, shape: Shape): tb.TSchema {
function FromObject<Def extends z.ZodObjectDef<z.ZodRawShape>, Shape extends z.ZodRawShape>(def: Def, shape: Shape): t.TSchema {
const additionalProperties = def.unknownKeys === 'strict' ? { additionalProperties: false } : {}
const options = { ...additionalProperties }
return tb.Object(
return t.Object(
globalThis.Object.keys(shape).reduce((properties: any, key: any) => {
return { ...properties, [key]: FromType(shape[key]) }
}, {} as tb.TProperties) as never,
}, {} as t.TProperties) as never,
options,
)
}
// ------------------------------------------------------------------
// Optional
// ------------------------------------------------------------------
type TFromOptional<Type extends z.ZodTypeAny, Result extends tb.TSchema = tb.TOptional<TFromType<Type>>> = Result
function FromOptional<Def extends z.ZodOptionalDef>(def: Def): tb.TSchema {
return tb.Optional(FromType(def.innerType))
type TFromOptional<Type extends z.ZodTypeAny, Result extends t.TSchema = t.TOptional<TFromType<Type>>> = Result
function FromOptional<Def extends z.ZodOptionalDef>(def: Def): t.TSchema {
return t.Optional(FromType(def.innerType))
}
// ------------------------------------------------------------------
// Promise
// ------------------------------------------------------------------
type TFromPromise<Type extends z.ZodTypeAny> = tb.Ensure<tb.TPromise<TFromType<Type>>>
function FromPromise<Def extends z.ZodPromiseDef>(def: Def): tb.TSchema {
return tb.Promise(FromType(def.type))
type TFromPromise<Type extends z.ZodTypeAny> = t.Ensure<t.TPromise<TFromType<Type>>>
function FromPromise<Def extends z.ZodPromiseDef>(def: Def): t.TSchema {
return t.Promise(FromType(def.type))
}
// ------------------------------------------------------------------
// Nullable
// ------------------------------------------------------------------
type TFromNullable<Type extends z.ZodTypeAny> = tb.Ensure<tb.TUnion<[tb.TNull, TFromType<Type>]>>
function FromNullable<Def extends z.ZodNullableDef>(def: Def): tb.TSchema {
return tb.Union([tb.Null(), FromType(def.innerType)])
type TFromNullable<Type extends z.ZodTypeAny> = t.Ensure<t.TUnion<[t.TNull, TFromType<Type>]>>
function FromNullable<Def extends z.ZodNullableDef>(def: Def): t.TSchema {
return t.Union([t.Null(), FromType(def.innerType)])
}
// ------------------------------------------------------------------
// Number
// ------------------------------------------------------------------
type TFromNumber = tb.TNumber
type TFromNumber = t.TNumber
// prettier-ignore
function FromNumber<Def extends z.ZodNumberDef>(def: Def) {
function FromNumber<Def extends z.ZodNumberDef>(def: Def): t.TSchema {
const options = def.checks.reduce((options, check) => {
return { ...options, ... (
check.kind === 'int' ? { multipleOf: 1 } :
@@ -205,124 +213,124 @@ function FromNumber<Def extends z.ZodNumberDef>(def: Def) {
{}
)}
}, {})
return tb.Number(options)
return t.Number(options)
}
// ------------------------------------------------------------------
// Never
// ------------------------------------------------------------------
type TFromNever = tb.TNever
function FromNever<Def extends z.ZodNeverDef>(def: Def) {
return tb.Never()
type TFromNever = t.TNever
function FromNever<Def extends z.ZodNeverDef>(def: Def): t.TSchema {
return t.Never()
}
// ------------------------------------------------------------------
// Null
// ------------------------------------------------------------------
type TFromNull = tb.TNull
function FromNull<Def extends z.ZodNullDef>(def: Def) {
return tb.Null()
type TFromNull = t.TNull
function FromNull<Def extends z.ZodNullDef>(def: Def): t.TSchema {
return t.Null()
}
// ------------------------------------------------------------------
// Readonly
// ------------------------------------------------------------------
type TFromReadonly<Type extends z.ZodTypeAny, Result extends tb.TSchema = tb.TReadonly<TFromType<Type>>> = Result
function FromReadonly<Def extends z.ZodReadonlyDef>(def: Def): tb.TSchema {
return tb.Readonly(FromType(def.innerType))
type TFromReadonly<Type extends z.ZodTypeAny, Result extends t.TSchema = t.TReadonly<TFromType<Type>>> = Result
function FromReadonly<Def extends z.ZodReadonlyDef>(def: Def): t.TSchema {
return t.Readonly(FromType(def.innerType))
}
// ------------------------------------------------------------------
// Record
// ------------------------------------------------------------------
type TFromRecord<Key extends z.ZodTypeAny, Value extends z.ZodTypeAny> = tb.Ensure<tb.TRecordOrObject<TFromType<Key>, TFromType<Value>>>
function FromRecord<Def extends z.ZodRecordDef>(def: Def): tb.TSchema {
return tb.Record(FromType(def.keyType), FromType(def.valueType))
type TFromRecord<Key extends z.ZodTypeAny, Value extends z.ZodTypeAny> = t.Ensure<t.TRecordOrObject<TFromType<Key>, TFromType<Value>>>
function FromRecord<Def extends z.ZodRecordDef>(def: Def): t.TSchema {
return t.Record(FromType(def.keyType), FromType(def.valueType))
}
// ------------------------------------------------------------------
// String
// ------------------------------------------------------------------
type TFromString = tb.TString
type TFromString = t.TString
// prettier-ignore
function FromString<Def extends z.ZodStringDef>(def: Def) {
function FromString<Def extends z.ZodStringDef>(def: Def): t.TSchema {
const options = def.checks.reduce((options, check) => {
return { ...options, ...(
check.kind === 'base64' ? { format: 'zod:base64' } :
check.kind === 'base64url' ? { format: 'zod:base64url' } :
check.kind === 'cidr' ? { format: check.version === 'v4' ? 'zod:cidrv4' : check.version === 'v6' ? 'zod:cidrv6' : 'zod:cidr' } :
check.kind === 'cuid' ? { format: 'zod:cuid' } :
check.kind === 'cuid2' ? { format: 'zod:cuid2' } :
check.kind === 'date' ? { format: 'zod:date' } :
check.kind === 'datetime' ? { format: 'zod:datetime' } :
check.kind === 'duration' ? { format: 'zod:duration' } :
check.kind === 'email' ? { format: 'zod:email' } :
check.kind === 'emoji' ? { format: 'zod:emoji' } :
check.kind === 'base64' ? { format: 'base64' } :
check.kind === 'base64url' ? { format: 'base64url' } :
check.kind === 'cidr' ? { format: check.version === 'v4' ? 'cidrv4' : check.version === 'v6' ? 'cidrv6' : 'cidr' } :
check.kind === 'cuid' ? { format: 'cuid' } :
check.kind === 'cuid2' ? { format: 'cuid2' } :
check.kind === 'date' ? { format: 'date' } :
check.kind === 'datetime' ? { format: 'datetime' } :
check.kind === 'duration' ? { format: 'duration' } :
check.kind === 'email' ? { format: 'email' } :
check.kind === 'emoji' ? { format: 'emoji' } :
check.kind === 'endsWith' ? { pattern: `${check.value}$` } :
check.kind === 'includes' ? { pattern: check.value } :
check.kind === 'ip' ? { format: check.version === 'v4' ? 'zod:ipv4' : check.version === 'v6' ? 'zod:ipv6' : 'zod:ip' } :
check.kind === 'jwt' ? { format: 'zod:jwt' } :
check.kind === 'ip' ? { format: check.version === 'v4' ? 'ipv4' : check.version === 'v6' ? 'ipv6' : 'ip' } :
check.kind === 'jwt' ? { format: 'jwt' } :
check.kind === 'length' ? { minLength: check.value, maxLength: check.value } :
check.kind === 'min' ? { minLength: check.value } :
check.kind === 'max' ? { maxLength: check.value } :
check.kind === 'nanoid' ? { format: 'zod:nanoid' } :
check.kind === 'nanoid' ? { format: 'nanoid' } :
check.kind === 'regex' ? { pattern: check.regex.source } :
check.kind === 'startsWith' ? { pattern: `^${check.value}` } :
check.kind === 'time' ? { format: 'zod:time' } :
check.kind === 'ulid' ? { format: 'zod:ulid' } :
check.kind === 'url' ? { format: 'zod:url' } :
check.kind === 'uuid' ? { format: 'zod:uuid' } :
check.kind === 'time' ? { format: 'time' } :
check.kind === 'ulid' ? { format: 'ulid' } :
check.kind === 'url' ? { format: 'url' } :
check.kind === 'uuid' ? { format: 'uuid' } :
{}
)}
}, {})
return tb.String(options)
return t.String(options)
}
// ------------------------------------------------------------------
// Symbol
// ------------------------------------------------------------------
type TFromSymbol = tb.TSymbol
function FromSymbol<Def extends z.ZodSymbolDef>(def: Def) {
return tb.Symbol()
type TFromSymbol = t.TSymbol
function FromSymbol<Def extends z.ZodSymbolDef>(def: Def): t.TSchema {
return t.Symbol()
}
// ------------------------------------------------------------------
// Tuple
// ------------------------------------------------------------------
// prettier-ignore
type TFromTuple<Types extends z.ZodTypeAny[], Result extends tb.TSchema[] = []> = (
type TFromTuple<Types extends z.ZodTypeAny[], Result extends t.TSchema[] = []> = (
Types extends [infer Left extends z.ZodTypeAny, ...infer Right extends z.ZodTypeAny[]]
? TFromTuple<Right, [...Result, TFromType<Left>]>
: tb.TTuple<Result>
: t.TTuple<Result>
)
function FromTuple<Def extends z.ZodTupleDef>(def: Def): tb.TSchema {
return tb.Tuple(def.items.map((item) => FromType(item)))
function FromTuple<Def extends z.ZodTupleDef>(def: Def): t.TSchema {
return t.Tuple(def.items.map((item) => FromType(item)))
}
// ------------------------------------------------------------------
// Undefined
// ------------------------------------------------------------------
type TFromUndefined = tb.TUndefined
function FromUndefined<Def extends z.ZodUndefinedDef>(def: Def) {
return tb.Undefined()
type TFromUndefined = t.TUndefined
function FromUndefined<Def extends z.ZodUndefinedDef>(def: Def): t.TSchema {
return t.Undefined()
}
// ------------------------------------------------------------------
// Union
// ------------------------------------------------------------------
// prettier-ignore
type TFromUnion<Types extends z.ZodTypeAny[], Result extends tb.TSchema[] = []> = (
type TFromUnion<Types extends z.ZodTypeAny[], Result extends t.TSchema[] = []> = (
Types extends [infer Left extends z.ZodTypeAny, ...infer Right extends z.ZodTypeAny[]]
? TFromUnion<Right, [...Result, TFromType<Left>]>
: tb.TUnion<Result>
: t.TUnion<Result>
)
function FromUnion<Def extends z.ZodUnionDef>(def: Def): tb.TSchema {
return tb.Union(def.options.map((item) => FromType(item)))
function FromUnion<Def extends z.ZodUnionDef>(def: Def): t.TSchema {
return t.Union(def.options.map((item) => FromType(item)))
}
// ------------------------------------------------------------------
// Unknown
// ------------------------------------------------------------------
type TFromUnknown = tb.TUnknown
function FromUnknown<Def extends z.ZodUnknownDef>(def: Def) {
return tb.Unknown()
type TFromUnknown = t.TUnknown
function FromUnknown<Def extends z.ZodUnknownDef>(def: Def): t.TSchema {
return t.Unknown()
}
// ------------------------------------------------------------------
// Void
// ------------------------------------------------------------------
type TFromVoid = tb.TVoid
function FromVoid<Def extends z.ZodVoidDef>(def: Def) {
return tb.Void()
type TFromVoid = t.TVoid
function FromVoid<Def extends z.ZodVoidDef>(def: Def): t.TSchema {
return t.Void()
}
// ------------------------------------------------------------------
// Type
@@ -337,6 +345,7 @@ type TFromType<Type extends z.ZodType> = (
Type extends z.ZodDefault<infer Type> ? TFromDefault<Type> :
Type extends z.ZodDiscriminatedUnion<infer Discriminator, infer Types> ? TFromDiscriminatedUnion<Discriminator, Types> :
Type extends z.ZodEffects<infer Input, infer Output> ? TFromEffects<Input, Output> :
Type extends z.ZodEnum<infer Variants> ? TFromEnum<Variants> :
Type extends z.ZodLiteral<infer Value> ? TFromLiteral<Value> :
Type extends z.ZodNullable<infer Type> ? TFromNullable<Type> :
Type extends z.ZodObject<infer Properties> ? TFromObject<Properties> :
@@ -349,17 +358,17 @@ type TFromType<Type extends z.ZodType> = (
Type extends z.ZodNull ? TFromNull :
Type extends z.ZodString ? TFromString :
Type extends z.ZodSymbol ? TFromSymbol :
Type extends z.ZodTuple<infer Types> ? TFromTuple<tb.Assert<Types, z.ZodTypeAny[]>> :
Type extends z.ZodTuple<infer Types> ? TFromTuple<t.Assert<Types, z.ZodTypeAny[]>> :
Type extends z.ZodUndefined ? TFromUndefined :
Type extends z.ZodUnion<infer Types> ? TFromUnion<tb.Assert<Types, z.ZodTypeAny[]>> :
Type extends z.ZodUnion<infer Types> ? TFromUnion<t.Assert<Types, z.ZodTypeAny[]>> :
Type extends z.ZodUnknown ? TFromUnknown :
Type extends z.ZodVoid ? TFromVoid :
// Intersection (Ensure Last Due to Zod Differentiation Issue)
Type extends z.ZodIntersection<infer Left, infer Right> ? TFromIntersect<[Left, Right]> :
tb.TNever
t.TNever
)
// prettier-ignore
function FromType<Type extends z.ZodType>(type: Type): tb.TSchema {
function FromType<Type extends z.ZodType>(type: Type): t.TSchema {
const schema = (
type instanceof z.ZodAny ? FromAny(type._def) :
type instanceof z.ZodArray ? FromArray(type._def) :
@@ -369,6 +378,7 @@ function FromType<Type extends z.ZodType>(type: Type): tb.TSchema {
type instanceof z.ZodDefault ? FromDefault(type._def) :
type instanceof z.ZodDiscriminatedUnion ? FromDiscriminatedUnion(type._def) :
type instanceof z.ZodEffects ? FromEffects(type) :
type instanceof z.ZodEnum ? FromEnum(type._def) :
type instanceof z.ZodLiteral ? FromLiteral(type._def) :
type instanceof z.ZodNullable ? FromNullable(type._def) :
type instanceof z.ZodObject ? FromObject(type._def, type.shape) :
@@ -388,16 +398,19 @@ function FromType<Type extends z.ZodType>(type: Type): tb.TSchema {
type instanceof z.ZodVoid ? FromVoid(type._def) :
// Intersection (Ensure Last Due to Zod Differentiation Issue)
type instanceof z.ZodIntersection ? FromIntersect(type._def) :
tb.Never()
) as tb.TSchema
return tb.CreateType(schema, Options(type)) as tb.TSchema
t.Never()
) as t.TSchema
return t.CreateType(schema, Options(type)) as t.TSchema
}
// ------------------------------------------------------------------
// Box
// TypeBoxFromZod
// ------------------------------------------------------------------
/** Converts a Zod Type to a TypeBox Type */
export type TBox<Type extends unknown> = Type extends z.ZodType ? TFromType<Type> : undefined
/** Converts a Zod Type to a TypeBox Type */
export function Box<Type extends unknown, Result extends TBox<Type> = TBox<Type>>(type: Type): Result {
return (type instanceof z.ZodType ? FromType(type) : undefined) as never
// prettier-ignore
export type TTypeBoxFromZod<Type extends unknown> = (
Type extends z.ZodType ? TFromType<Type> : t.TNever
)
// prettier-ignore
export function TypeBoxFromZod<Type extends unknown, Result extends TTypeBoxFromZod<Type> = TTypeBoxFromZod<Type>>(type: Type): Result {
return (type instanceof z.ZodType ? FromType(type) : t.Never()) as never
}

63
src/typebox/typebox.ts Normal file
View File

@@ -0,0 +1,63 @@
/*--------------------------------------------------------------------------
@sinclair/typemap
The MIT License (MIT)
Copyright (c) 2024 Haydn Paterson (sinclair) <haydn.developer@gmail.com>
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
---------------------------------------------------------------------------*/
import { 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 * as t from '@sinclair/typebox'
/** Creates a TypeBox type from Syntax or another Type */
// prettier-ignore
export type TTypeBox<Type extends object | string> = (
Guard.TIsSyntax<Type> extends true ? TTypeBoxFromSyntax<Type> :
Guard.TIsTypeBox<Type> extends true ? TTypeBoxFromTypeBox<Type> :
Guard.TIsValibot<Type> extends true ? TTypeBoxFromValibot<Type> :
Guard.TIsZod<Type> extends true ? TTypeBoxFromZod<Type> :
t.TNever
)
/** Creates a TypeBox type from Syntax or another Type */
// prettier-ignore
export function TypeBox<Type extends object | string>(type: Type): TTypeBox<Type> {
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
}
/**
* Creates a TypeBox type from Syntax or another Type
* @deprecated Use TypeBox() export instead
*/
export function Box<Type extends object | string>(type: Type): TTypeBox<Type> {
return TypeBox(type)
}

View File

@@ -1,6 +1,6 @@
/*--------------------------------------------------------------------------
@sinclair/typebox-adapter
@sinclair/typemap
The MIT License (MIT)
@@ -26,4 +26,10 @@ THE SOFTWARE.
---------------------------------------------------------------------------*/
export * from './box'
import * as v from 'valibot'
// Valibot really should consider providing default generic type parameters
export type BaseConstraint = v.BaseValidation<any, unknown, v.BaseIssue<unknown>> | v.BaseMetadata<any> | v.RegexAction<any, any>
export type BaseRecordKey = v.BaseSchema<string, string | number | symbol, v.BaseIssue<unknown>>
export type BaseSchema = v.BaseSchema<unknown, unknown, v.BaseIssue<unknown>>
export type BaseError = v.ErrorMessage<any>

View File

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

View File

@@ -0,0 +1,394 @@
/*--------------------------------------------------------------------------
@sinclair/typemap
The MIT License (MIT)
Copyright (c) 2024 Haydn Paterson (sinclair) <haydn.developer@gmail.com>
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
---------------------------------------------------------------------------*/
import * as t from '@sinclair/typebox'
import * as v from 'valibot'
import * as c from './common'
// ------------------------------------------------------------------
// Constraints
// ------------------------------------------------------------------
function CreateConstraints(type: t.TSchema, initial: c.BaseConstraint[] = []): c.BaseConstraint[] {
const constraints: c.BaseConstraint[] = []
if (t.ValueGuard.IsString(type.description)) constraints.push(v.description(type.description!))
if (t.ValueGuard.IsString(type.title)) constraints.push(v.title(type.title!))
if (t.ValueGuard.IsObject(type.metadata)) constraints.push(v.metadata(type.metadata!))
return [...initial, ...constraints]
}
function CreateType(type: c.BaseSchema, constraints: c.BaseConstraint[] = []) {
return constraints.length === 0 ? type : v.pipe(type, ...constraints)
}
// ------------------------------------------------------------------
// Any
// ------------------------------------------------------------------
type TFromAny<Result = v.AnySchema> = Result
function FromAny(type: t.TAny): c.BaseSchema {
return CreateType(v.any(), CreateConstraints(type))
}
// ------------------------------------------------------------------
// Array
// ------------------------------------------------------------------
type TFromArray<Type extends t.TSchema, Result = v.ArraySchema<TFromType<Type>, c.BaseError>> = Result
function FromArray(type: t.TArray): c.BaseSchema {
const { minItems, maxItems /* minContains, maxContains, contains */ } = type
const constraints = CreateConstraints(type)
if (t.ValueGuard.IsNumber(minItems)) constraints.push(v.minLength(minItems))
if (t.ValueGuard.IsNumber(maxItems)) constraints.push(v.maxLength(maxItems))
const mapped = v.array(FromType(type.items))
return CreateType(mapped, constraints)
}
// ------------------------------------------------------------------
// BigInt
// ------------------------------------------------------------------
type TFromBigInt<Result = v.BigintSchema<c.BaseError>> = Result
function FromBigInt(type: t.TBigInt): c.BaseSchema {
return CreateType(v.bigint(), CreateConstraints(type))
}
// ------------------------------------------------------------------
// Boolean
// ------------------------------------------------------------------
type TFromBoolean<Result = v.BooleanSchema<c.BaseError>> = Result
function FromBoolean(type: t.TBoolean): c.BaseSchema {
return CreateType(v.boolean(), CreateConstraints(type))
}
// ------------------------------------------------------------------
// Date
// ------------------------------------------------------------------
type TFromDate<Result = v.DateSchema<c.BaseError>> = Result
function FromDate(type: t.TDate): c.BaseSchema {
return CreateType(v.date(), CreateConstraints(type))
}
// ------------------------------------------------------------------
// Function
// ------------------------------------------------------------------
// prettier-ignore
type TFromFunction<Parameters extends t.TSchema[], ReturnType extends t.TSchema> = (
v.FunctionSchema<any>
)
function FromFunction(type: t.TFunction): c.BaseSchema {
return CreateType(v.function(), CreateConstraints(type))
}
// ------------------------------------------------------------------
// Integer
// ------------------------------------------------------------------
type TFromInteger = v.NumberSchema<c.BaseError>
function FromInteger(type: t.TInteger): c.BaseSchema {
const { exclusiveMaximum, exclusiveMinimum, minimum, maximum, multipleOf } = type
const constraints = CreateConstraints(type, [v.integer()])
if (t.ValueGuard.IsNumber(exclusiveMinimum)) constraints.push(v.minValue(exclusiveMinimum + 1))
if (t.ValueGuard.IsNumber(exclusiveMaximum)) constraints.push(v.minValue(exclusiveMaximum - 1))
if (t.ValueGuard.IsNumber(maximum)) constraints.push(v.maxValue(maximum))
if (t.ValueGuard.IsNumber(minimum)) constraints.push(v.minValue(minimum))
if (t.ValueGuard.IsNumber(multipleOf)) constraints.push(v.multipleOf(multipleOf))
return CreateType(v.number(), constraints)
}
// ------------------------------------------------------------------
// Intersect
// ------------------------------------------------------------------
type TFromIntersect<Types extends t.TSchema[], Result extends c.BaseSchema[] = []> = Types extends [infer Left extends t.TSchema, ...infer Right extends t.TSchema[]]
? TFromIntersect<Right, [...Result, TFromType<Left>]>
: v.IntersectSchema<Result, any>
function FromIntersect(type: t.TIntersect): c.BaseSchema {
const schemas = type.allOf.map((schema) => FromType(schema))
return CreateType(v.intersect(schemas), CreateConstraints(type))
}
// ------------------------------------------------------------------
// Literal
// ------------------------------------------------------------------
type TFromLiteral<Value extends t.TLiteralValue> = v.LiteralSchema<Value, any>
function FromLiteral(type: t.TLiteral): c.BaseSchema {
return CreateType(v.literal(type.const), CreateConstraints(type))
}
// ------------------------------------------------------------------
// Object
// ------------------------------------------------------------------
// prettier-ignore
type TFromObject<Properties extends t.TProperties,
Result = v.ObjectSchema<{
[Key in keyof Properties]: TFromType<Properties[Key]>
}, c.BaseError>
> = Result
function FromObject(type: t.TObject): c.BaseSchema {
const { additionalProperties } = type
const constraints = CreateConstraints(type)
const properties = globalThis.Object.getOwnPropertyNames(type.properties).reduce((result, key) => ({ ...result, [key]: FromType(type.properties[key]) }), {})
return additionalProperties === false
? CreateType(v.strictObject(properties), constraints) // facade
: CreateType(v.object(properties), constraints)
}
// ------------------------------------------------------------------
// Promise
// ------------------------------------------------------------------
type TFromPromise<_Type extends t.TSchema, Result = v.PromiseSchema<c.BaseError>> = Result
function FromPromise(type: t.TPromise): c.BaseSchema {
return CreateType(v.promise(), CreateConstraints(type))
}
// ------------------------------------------------------------------
// Record
// ------------------------------------------------------------------
type TFromRegExp<Result = v.StringSchema<c.BaseError>> = Result
function FromRegExp(type: t.TRegExp): c.BaseSchema {
const { minLength, maxLength } = type
const constraints = CreateConstraints(type, [v.regex(new RegExp(type.source, type.flags))])
if (t.ValueGuard.IsNumber(maxLength)) constraints.push(v.maxLength(maxLength))
if (t.ValueGuard.IsNumber(minLength)) constraints.push(v.minLength(minLength))
return CreateType(v.string(), constraints)
}
// ------------------------------------------------------------------
// Record
// ------------------------------------------------------------------
// prettier-ignore
type TFromRecord<Key extends t.TSchema, Value extends t.TSchema> = (
TFromType<Key> extends infer MappedKey extends c.BaseRecordKey
? v.RecordSchema<MappedKey, TFromType<Value>, c.BaseError>
: v.RecordSchema<v.StringSchema<c.BaseError>, TFromType<Value>, c.BaseError>
)
// prettier-ignore
function FromRecord(type: t.TRecord): c.BaseSchema {
const constraints = CreateConstraints(type)
const pattern = globalThis.Object.getOwnPropertyNames(type.patternProperties)[0]
const value = FromType(type.patternProperties[pattern])
return (
pattern === t.PatternStringExact
? CreateType(v.record(v.string(), value), constraints)
: CreateType(v.record(v.pipe(v.string(), v.regex(new RegExp(pattern))), value), constraints)
)
}
// ------------------------------------------------------------------
// Optional
// ------------------------------------------------------------------
type TFromOptional<Type extends t.TSchema, Result = v.OptionalSchema<TFromType<Type>, c.BaseError>> = Result
function FromOptional(type: t.TOptional<t.TSchema>): c.BaseSchema {
return v.optional(FromType(t.Optional(type, false)))
}
// ------------------------------------------------------------------
// Readonly
// ------------------------------------------------------------------
type TFromReadonly<Type extends t.TSchema, Result = TFromType<Type>> = Result
function FromReadonly(type: t.TReadonly<t.TSchema>): c.BaseSchema {
return FromType(t.Readonly(type, false))
}
// ------------------------------------------------------------------
// Never
// ------------------------------------------------------------------
type TFromNever<Result = v.NeverSchema<c.BaseError>> = Result
function FromNever(type: t.TNever): c.BaseSchema {
return CreateType(v.never(), CreateConstraints(type))
}
// ------------------------------------------------------------------
// Null
// ------------------------------------------------------------------
type TFromNull<Result = v.NullSchema<c.BaseError>> = Result
function FromNull(type: t.TNull): c.BaseSchema {
return CreateType(v.null(), CreateConstraints(type))
}
// ------------------------------------------------------------------
// Number
// ------------------------------------------------------------------
type TFromNumber<Result = v.NumberSchema<c.BaseError>> = Result
function FromNumber(type: t.TNumber): c.BaseSchema {
const { exclusiveMaximum, exclusiveMinimum, minimum, maximum, multipleOf } = type
const constraints = CreateConstraints(type)
if (t.ValueGuard.IsNumber(exclusiveMinimum)) constraints.push(v.minValue(exclusiveMinimum + 1))
if (t.ValueGuard.IsNumber(exclusiveMaximum)) constraints.push(v.minValue(exclusiveMaximum - 1))
if (t.ValueGuard.IsNumber(maximum)) constraints.push(v.maxValue(maximum))
if (t.ValueGuard.IsNumber(minimum)) constraints.push(v.minValue(minimum))
if (t.ValueGuard.IsNumber(multipleOf)) constraints.push(v.multipleOf(multipleOf))
return CreateType(v.number(), constraints)
}
// ------------------------------------------------------------------
// String
// ------------------------------------------------------------------
type TFromString<Result = v.StringSchema<c.BaseError>> = Result
// prettier-ignore
function FromString(type: t.TString): c.BaseSchema {
const { minLength, maxLength, pattern, format } = type
const constraints = CreateConstraints(type)
if (t.ValueGuard.IsNumber(maxLength)) constraints.push(v.maxLength(maxLength))
if (t.ValueGuard.IsNumber(minLength)) constraints.push(v.minLength(minLength))
if (t.ValueGuard.IsString(pattern)) constraints.push(v.regex(new RegExp(pattern)))
if (t.ValueGuard.IsString(format)) constraints.push(...(
format === 'base64' ? [v.base64()] :
format === 'bic' ? [v.bic()] :
format === 'credit_card' ? [v.creditCard()] :
format === 'cuid2' ? [v.cuid2()] :
format === 'decimal' ? [v.decimal()] :
format === 'digits' ? [v.digits()] :
format === 'email' ? [v.email()] :
format === 'emoji' ? [v.emoji()] :
format === 'ip' ? [v.ip()] :
format === 'ipv4' ? [v.ipv4()] :
format === 'ipv6' ? [v.ipv6()] :
format === 'iso_date' ? [v.isoDate()] :
format === 'iso_date_time' ? [v.isoDateTime()] :
format === 'iso_time' ? [v.isoTime()] :
format === 'iso_time_second' ? [v.isoTimeSecond()] :
format === 'iso_timestamp' ? [v.isoTimestamp()] :
format === 'iso_week' ? [v.isoWeek()] :
format === 'mac' ? [v.mac()] :
format === 'mac48' ? [v.mac48()] :
format === 'mac64' ? [v.mac64()] :
format === 'nanoid' ? [v.nanoid()] :
format === 'octal' ? [v.octal()] :
format === 'ulid' ? [v.ulid()] :
format === 'url' ? [v.url()] :
format === 'uuid' ? [v.uuid()] :
[]))
return CreateType(v.string(), constraints)
}
// ------------------------------------------------------------------
// Symbol
// ------------------------------------------------------------------
type TFromSymbol<Result = v.SymbolSchema<c.BaseError>> = Result
function FromSymbol(type: t.TSymbol): c.BaseSchema {
return CreateType(v.symbol(), CreateConstraints(type))
}
// ------------------------------------------------------------------
// Tuple
// ------------------------------------------------------------------
// prettier-ignore
type TFromTuple<Types extends t.TSchema[], Mapped extends c.BaseSchema[] = TFromTypes<Types>> = (
v.TupleSchema<Mapped, c.BaseError>
)
function FromTuple(type: t.TTuple): c.BaseSchema {
const mapped = FromTypes(type.items || []) as [] | [c.BaseSchema, ...c.BaseSchema[]]
return CreateType(v.tuple(mapped), CreateConstraints(type))
}
// ------------------------------------------------------------------
// Undefined
// ------------------------------------------------------------------
type TFromUndefined<Result = v.UndefinedSchema<c.BaseError>> = Result
function FromUndefined(type: t.TUndefined): c.BaseSchema {
return CreateType(v.undefined(), CreateConstraints(type))
}
// ------------------------------------------------------------------
// Union
// ------------------------------------------------------------------
// prettier-ignore
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))
}
// ------------------------------------------------------------------
// TUnknown
// ------------------------------------------------------------------
type TFromUnknown<Result = v.UnknownSchema> = Result
function FromUnknown(type: t.TUnknown): c.BaseSchema {
return CreateType(v.unknown(), CreateConstraints(type))
}
// ------------------------------------------------------------------
// Void
// ------------------------------------------------------------------
type TFromVoid<Result = v.VoidSchema<c.BaseError>> = Result
function FromVoid(type: t.TVoid): c.BaseSchema {
return CreateType(v.void(), CreateConstraints(type))
}
// ------------------------------------------------------------------
// Types
// ------------------------------------------------------------------
type TFromTypes<Types extends t.TSchema[], Result extends c.BaseSchema[] = []> = Types extends [infer Left extends t.TSchema, ...infer Right extends t.TSchema[]] ? TFromTypes<Right, [...Result, TFromType<Left>]> : Result
function FromTypes(types: t.TSchema[]): c.BaseSchema[] {
return types.map((type) => FromType(type))
}
// ------------------------------------------------------------------
// Type
// ------------------------------------------------------------------
// prettier-ignore
type TFromType<Type extends t.TSchema> = (
Type extends t.TReadonly<infer Type extends t.TSchema> ? TFromReadonly<Type> :
Type extends t.TOptional<infer Type extends t.TSchema> ? TFromOptional<Type> :
Type extends t.TAny ? TFromAny :
Type extends t.TArray<infer Type extends t.TSchema> ? TFromArray<Type> :
Type extends t.TBigInt ? TFromBigInt :
Type extends t.TBoolean ? TFromBoolean :
Type extends t.TDate ? TFromDate :
Type extends t.TFunction<infer Parameters extends t.TSchema[], infer ReturnType extends t.TSchema> ? TFromFunction<Parameters, ReturnType> :
Type extends t.TInteger ? TFromInteger :
Type extends t.TIntersect<infer Types extends t.TSchema[]> ? TFromIntersect<Types> :
Type extends t.TLiteral<infer Value extends t.TLiteralValue> ? TFromLiteral<Value> :
Type extends t.TNull ? TFromNull :
Type extends t.TNever ? TFromNever :
Type extends t.TNumber ? TFromNumber :
Type extends t.TObject<infer Properties extends t.TProperties> ? TFromObject<Properties> :
Type extends t.TPromise<infer Type extends t.TSchema> ? TFromPromise<Type> :
Type extends t.TRecord<infer Key extends t.TSchema, infer Value extends t.TSchema> ? TFromRecord<Key, Value> :
Type extends t.TRegExp ? TFromRegExp :
Type extends t.TString ? TFromString :
Type extends t.TSymbol ? TFromSymbol :
Type extends t.TTuple<infer Types extends t.TSchema[]> ? TFromTuple<Types> :
Type extends t.TUndefined ? TFromUndefined :
Type extends t.TUnion<infer Types extends t.TSchema[]> ? TFromUnion<Types> :
Type extends t.TUnknown ? TFromUnknown :
Type extends t.TVoid ? TFromVoid :
v.NeverSchema<c.BaseError>
)
// prettier-ignore
function FromType(type: t.TSchema): c.BaseSchema {
return (
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) :
t.KindGuard.IsBoolean(type) ? FromBoolean(type) :
t.KindGuard.IsDate(type) ? FromDate(type) :
t.KindGuard.IsFunction(type) ? FromFunction(type) :
t.KindGuard.IsInteger(type) ? FromInteger(type) :
t.KindGuard.IsIntersect(type) ? FromIntersect(type) :
t.KindGuard.IsLiteral(type) ? FromLiteral(type) :
t.KindGuard.IsNever(type) ? FromNever(type) :
t.KindGuard.IsNull(type) ? FromNull(type) :
t.KindGuard.IsNumber(type) ? FromNumber(type) :
t.KindGuard.IsObject(type) ? FromObject(type) :
t.KindGuard.IsPromise(type) ? FromPromise(type) :
t.KindGuard.IsRegExp(type) ? FromRegExp(type) :
t.KindGuard.IsRecord(type) ? FromRecord(type) :
t.KindGuard.IsString(type) ? FromString(type) :
t.KindGuard.IsSymbol(type) ? FromSymbol(type) :
t.KindGuard.IsTuple(type) ? FromTuple(type) :
t.KindGuard.IsUndefined(type) ? FromUndefined(type) :
t.KindGuard.IsUnion(type) ? FromUnion(type) :
t.KindGuard.IsUnknown(type) ? FromUnknown(type) :
t.KindGuard.IsVoid(type) ? FromVoid(type) :
v.never()
)
}
// ------------------------------------------------------------------
// ValibotFromTypeBox
// ------------------------------------------------------------------
// prettier-ignore
export type TValibotFromTypeBox<Type extends object | string> = (
Type extends t.TSchema ? TFromType<Type> : v.NeverSchema<c.BaseError>
)
// prettier-ignore
export function ValibotFromTypeBox<Type extends object | string>(type: Type): TValibotFromTypeBox<Type> {
return (t.KindGuard.IsSchema(type) ? FromType(type) : v.never()) as never
}

View File

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

View File

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

56
src/valibot/valibot.ts Normal file
View File

@@ -0,0 +1,56 @@
/*--------------------------------------------------------------------------
@sinclair/typemap
The MIT License (MIT)
Copyright (c) 2024 Haydn Paterson (sinclair) <haydn.developer@gmail.com>
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
---------------------------------------------------------------------------*/
import { type TValibotFromSyntax, ValibotFromSyntax } from './valibot-from-syntax'
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 * as v from 'valibot'
import * as c from './common'
/** Creates a Valibot type from Syntax or another Type */
// prettier-ignore
export type TValibot<Type extends object | string> = (
Guard.TIsSyntax<Type> extends true ? TValibotFromSyntax<Type> :
Guard.TIsTypeBox<Type> extends true ? TValibotFromTypeBox<Type> :
Guard.TIsValibot<Type> extends true ? TValibotFromValibot<Type> :
Guard.TIsZod<Type> extends true ? TValibotFromZod<Type> :
v.NeverSchema<c.BaseError>
)
/** Creates a Valibot type from Syntax or another Type */
// prettier-ignore
export function Valibot<Type extends object | string, Result = TValibot<Type>>(type: Type): Result {
return (
Guard.IsSyntax(type) ? ValibotFromSyntax(type) :
Guard.IsTypeBox(type) ? ValibotFromTypeBox(type) :
Guard.IsValibot(type) ? ValibotFromValibot(type) :
Guard.IsZod(type) ? ValibotFromZod(type as any) :
v.never()
) as never
}

View File

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

389
src/zod/zod-from-typebox.ts Normal file
View File

@@ -0,0 +1,389 @@
/*--------------------------------------------------------------------------
@sinclair/typemap
The MIT License (MIT)
Copyright (c) 2024 Haydn Paterson (sinclair) <haydn.developer@gmail.com>
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
---------------------------------------------------------------------------*/
import * as t from '@sinclair/typebox'
import * as z from 'zod'
// ------------------------------------------------------------------
// Constraint
// ------------------------------------------------------------------
type TConstraint<Input extends z.ZodTypeAny = z.ZodTypeAny, Output extends z.ZodTypeAny = Input> = (input: Input) => Output
// ------------------------------------------------------------------
// Any
// ------------------------------------------------------------------
type TFromAny<Result = z.ZodAny> = Result
function FromAny(_type: t.TAny): z.ZodTypeAny {
return z.any()
}
// ------------------------------------------------------------------
// Array
// ------------------------------------------------------------------
type TFromArray<Type extends t.TSchema, Result = z.ZodArray<TFromType<Type>>> = Result
function FromArray(type: t.TArray): z.ZodTypeAny {
const constraints: TConstraint<z.ZodArray<z.ZodTypeAny, any>>[] = []
const { minItems, maxItems /* minContains, maxContains, contains */ } = type
if (t.ValueGuard.IsNumber(minItems)) constraints.push((input) => input.min(minItems))
if (t.ValueGuard.IsNumber(maxItems)) constraints.push((input) => input.max(maxItems))
const mapped = z.array(FromType(type.items))
return constraints.reduce((type, constraint) => constraint(type), mapped)
}
// ------------------------------------------------------------------
// BigInt
// ------------------------------------------------------------------
type TFromBigInt<Result = z.ZodBigInt> = Result
function FromBigInt(_type: t.TBigInt): z.ZodTypeAny {
return z.bigint()
}
// ------------------------------------------------------------------
// Boolean
// ------------------------------------------------------------------
type TFromBoolean<Result = z.ZodBoolean> = Result
function FromBoolean(_type: t.TBoolean): z.ZodTypeAny {
return z.boolean()
}
// ------------------------------------------------------------------
// Date
// ------------------------------------------------------------------
type TFromDate<Result = z.ZodDate> = Result
function FromDate(_type: t.TDate): z.ZodTypeAny {
return z.date()
}
// ------------------------------------------------------------------
// Function
// ------------------------------------------------------------------
// prettier-ignore
type TFromFunction<Parameters extends t.TSchema[], ReturnType extends t.TSchema,
MappedParameters extends z.ZodTypeAny[] = TFromTypes<Parameters>
> = (
MappedParameters extends [z.ZodTypeAny, ...z.ZodTypeAny[]] | []
? z.ZodFunction<z.ZodTuple<MappedParameters>, TFromType<ReturnType>>
: z.ZodNever
)
function FromFunction(type: t.TFunction): z.ZodTypeAny {
const mappedParameters = FromTypes(type.parameters) as [] | [z.ZodTypeAny, ...z.ZodTypeAny[]]
return z.function(z.tuple(mappedParameters), FromType(type.returns))
}
// ------------------------------------------------------------------
// Integer
// ------------------------------------------------------------------
type TFromInteger<Result = z.ZodNumber> = Result
function FromInteger(type: t.TInteger): z.ZodTypeAny {
const { exclusiveMaximum, exclusiveMinimum, minimum, maximum, multipleOf } = type
const constraints: TConstraint<z.ZodNumber>[] = [(value) => value.int()]
if (t.ValueGuard.IsNumber(exclusiveMinimum)) constraints.push((input) => input.min(exclusiveMinimum + 1))
if (t.ValueGuard.IsNumber(exclusiveMaximum)) constraints.push((input) => input.min(exclusiveMaximum - 1))
if (t.ValueGuard.IsNumber(maximum)) constraints.push((input) => input.max(maximum))
if (t.ValueGuard.IsNumber(minimum)) constraints.push((input) => input.min(minimum))
if (t.ValueGuard.IsNumber(multipleOf)) constraints.push((input) => input.multipleOf(multipleOf))
return constraints.reduce((input, constraint) => constraint(input), z.number())
}
// ------------------------------------------------------------------
// 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
function FromIntersect(type: t.TIntersect): z.ZodTypeAny {
return type.allOf.reduce((result, left) => {
return z.intersection(FromType(left), result) as never
}, z.unknown()) as never
}
// ------------------------------------------------------------------
// Literal
// ------------------------------------------------------------------
type TFromLiteral<Value extends t.TLiteralValue, Result = z.ZodLiteral<Value>> = Result
function FromLiteral(type: t.TLiteral): z.ZodTypeAny {
return z.literal(type.const)
}
// ------------------------------------------------------------------
// Object
// ------------------------------------------------------------------
type TFromObject<
Properties extends t.TProperties,
Result = z.ZodObject<{
[Key in keyof Properties]: TFromType<Properties[Key]>
}>,
> = Result
// prettier-ignore
function FromObject(type: t.TObject): z.ZodTypeAny {
const constraints: TConstraint<z.ZodObject<any, any, any>>[] = []
const { additionalProperties } = type
if (additionalProperties === false) constraints.push((input) => input.strict())
if (t.KindGuard.IsSchema(additionalProperties)) constraints.push((input) => input.catchall(FromType(additionalProperties)))
const properties = globalThis.Object.getOwnPropertyNames(type.properties).reduce((result, key) => ({ ...result, [key]: FromType(type.properties[key]) }), {})
return constraints.reduce((type, constraint) => constraint(type), z.object(properties))
}
// ------------------------------------------------------------------
// Promise
// ------------------------------------------------------------------
type TFromPromise<Type extends t.TSchema, Result = z.ZodPromise<TFromType<Type>>> = Result
function FromPromise(type: t.TPromise): z.ZodTypeAny {
return z.promise(FromType(type.item))
}
// ------------------------------------------------------------------
// Record
// ------------------------------------------------------------------
type TFromRegExp<Result = z.ZodString> = Result
function FromRegExp(type: t.TRegExp): z.ZodTypeAny {
const constraints: TConstraint<z.ZodString>[] = [(input) => input.regex(new RegExp(type.source), type.flags)]
const { minLength, maxLength } = type
if (t.ValueGuard.IsNumber(maxLength)) constraints.push((input) => input.max(maxLength))
if (t.ValueGuard.IsNumber(minLength)) constraints.push((input) => input.min(minLength))
return constraints.reduce((type, constraint) => constraint(type), z.string())
}
// ------------------------------------------------------------------
// 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
function FromRecord(type: t.TRecord): z.ZodTypeAny {
const pattern = globalThis.Object.getOwnPropertyNames(type.patternProperties)[0]
const value = FromType(type.patternProperties[pattern])
return (
pattern === t.PatternBooleanExact ? z.record(z.boolean(), value) :
pattern === t.PatternNumberExact ? z.record(z.number(), value) :
pattern === t.PatternStringExact ? z.record(z.string(), value) :
z.record(z.string().regex(new RegExp(pattern)), value)
)
}
// ------------------------------------------------------------------
// Optional
// ------------------------------------------------------------------
type TFromOptional<Type extends t.TSchema, Result = z.ZodOptional<TFromType<Type>>> = Result
function FromOptional(type: t.TOptional<t.TSchema>): z.ZodTypeAny {
return z.optional(FromType(t.Optional(type, false)))
}
// ------------------------------------------------------------------
// Readonly
// ------------------------------------------------------------------
type TFromReadonly<Type extends t.TSchema, Result = z.ZodReadonly<TFromType<Type>>> = Result
function FromReadonly(type: t.TReadonly<t.TSchema>): z.ZodTypeAny {
return FromType(t.Readonly(type, false))
}
// ------------------------------------------------------------------
// Never
// ------------------------------------------------------------------
type TFromNever<Result = z.ZodNever> = Result
function FromNever(type: t.TNever): z.ZodTypeAny {
return z.never()
}
// ------------------------------------------------------------------
// Never
// ------------------------------------------------------------------
type TFromNull<Result = z.ZodNull> = Result
function FromNull(_type: t.TNull): z.ZodTypeAny {
return z.null()
}
// ------------------------------------------------------------------
// Number
// ------------------------------------------------------------------
type TFromNumber<Result = z.ZodNumber> = Result
function FromNumber(type: t.TNumber): z.ZodTypeAny {
const { exclusiveMaximum, exclusiveMinimum, minimum, maximum, multipleOf } = type
const constraints: TConstraint<z.ZodNumber>[] = []
if (t.ValueGuard.IsNumber(exclusiveMinimum)) constraints.push((input) => input.min(exclusiveMinimum + 1))
if (t.ValueGuard.IsNumber(exclusiveMaximum)) constraints.push((input) => input.min(exclusiveMaximum - 1))
if (t.ValueGuard.IsNumber(maximum)) constraints.push((input) => input.max(maximum))
if (t.ValueGuard.IsNumber(minimum)) constraints.push((input) => input.min(minimum))
if (t.ValueGuard.IsNumber(multipleOf)) constraints.push((input) => input.multipleOf(multipleOf))
return constraints.reduce((input, constraint) => constraint(input), z.number())
}
// ------------------------------------------------------------------
// String
// ------------------------------------------------------------------
type TFromString<Result = z.ZodString> = Result
// prettier-ignore
function FromString(type: t.TString): z.ZodTypeAny {
const constraints: TConstraint<z.ZodString>[] = []
const { minLength, maxLength, pattern, format } = type
if (t.ValueGuard.IsNumber(maxLength)) constraints.push((input) => input.max(maxLength))
if (t.ValueGuard.IsNumber(minLength)) constraints.push((input) => input.min(minLength))
if (t.ValueGuard.IsString(pattern)) constraints.push((input) => input.regex(new RegExp(pattern)))
if (t.ValueGuard.IsString(format))
constraints.push((input) =>
format === 'base64' ? input.base64() :
format === 'base64url' ? input.base64url() :
format === 'cidrv4' ? input.cidr({ version: 'v4' }) :
format === 'cidrv6' ? input.cidr({ version: 'v6' }) :
format === 'cidr' ? input.cidr() :
format === 'cuid' ? input.cuid() :
format === 'cuid2' ? input.cuid2() :
format === 'date' ? input.date() :
format === 'datetime' ? input.datetime() :
format === 'duration' ? input.duration() :
format === 'email' ? input.email() :
format === 'emoji' ? input.emoji() :
format === 'ipv4' ? input.ip({ version: 'v4' }) :
format === 'ipv6' ? input.ip({ version: 'v6' }) :
format === 'ip' ? input.ip() :
format === 'jwt' ? input.jwt() :
format === 'nanoid' ? input.nanoid() :
format === 'time' ? input.time() :
format === 'ulid' ? input.ulid() :
format === 'url' ? input.url() :
format === 'uuid' ? input.uuid() :
input,
)
return constraints.reduce((type, constraint) => constraint(type), z.string())
}
// ------------------------------------------------------------------
// Symbol
// ------------------------------------------------------------------
type TFromSymbol<Result = z.ZodSymbol> = Result
function FromSymbol(_type: t.TSymbol): z.ZodTypeAny {
return z.symbol()
}
// ------------------------------------------------------------------
// Tuple
// ------------------------------------------------------------------
// prettier-ignore
type TFromTuple<Types extends t.TSchema[], Mapped extends z.ZodTypeAny[] = TFromTypes<Types>> = (
Mapped extends [z.ZodTypeAny, ...z.ZodTypeAny[]] | []
? z.ZodTuple<Mapped>
: z.ZodNever
)
function FromTuple(type: t.TTuple): z.ZodTypeAny {
const mapped = FromTypes(type.items || []) as [] | [z.ZodTypeAny, ...z.ZodTypeAny[]]
return z.tuple(mapped)
}
// ------------------------------------------------------------------
// Undefined
// ------------------------------------------------------------------
type TFromUndefined<Result = z.ZodUndefined> = Result
function FromUndefined(_type: t.TUndefined): z.ZodTypeAny {
return z.undefined()
}
// ------------------------------------------------------------------
// Union
// ------------------------------------------------------------------
// prettier-ignore
type TFromUnion<Types extends t.TSchema[], Mapped extends z.ZodTypeAny[] = TFromTypes<Types>> = (
Mapped extends z.ZodUnionOptions ? z.ZodUnion<Mapped> : z.ZodNever
)
function FromUnion(_type: t.TUnion): z.ZodTypeAny {
const mapped = FromTypes(_type.anyOf) as [z.ZodTypeAny, z.ZodTypeAny, ...z.ZodTypeAny[]]
return mapped.length >= 1 ? z.union(mapped) : z.never()
}
// ------------------------------------------------------------------
// TUnknown
// ------------------------------------------------------------------
type TFromUnknown<Result = z.ZodUnknown> = Result
function FromUnknown(_type: t.TUnknown): z.ZodTypeAny {
return z.unknown()
}
// ------------------------------------------------------------------
// Void
// ------------------------------------------------------------------
type TFromVoid<Result = z.ZodVoid> = Result
function FromVoid(_type: t.TVoid): z.ZodTypeAny {
return z.void()
}
// ------------------------------------------------------------------
// 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
function FromTypes(types: t.TSchema[]): z.ZodTypeAny[] {
return types.map((type) => FromType(type))
}
// ------------------------------------------------------------------
// Type
// ------------------------------------------------------------------
// prettier-ignore
type TFromType<Type extends t.TSchema> = (
Type extends t.TReadonly<infer Type extends t.TSchema> ? TFromReadonly<Type> :
Type extends t.TOptional<infer Type extends t.TSchema> ? TFromOptional<Type> :
Type extends t.TAny ? TFromAny :
Type extends t.TArray<infer Type extends t.TSchema> ? TFromArray<Type> :
Type extends t.TBigInt ? TFromBigInt :
Type extends t.TBoolean ? TFromBoolean :
Type extends t.TDate ? TFromDate :
Type extends t.TFunction<infer Parameters extends t.TSchema[], infer ReturnType extends t.TSchema> ? TFromFunction<Parameters, ReturnType> :
Type extends t.TInteger ? TFromInteger :
Type extends t.TIntersect<infer Types extends t.TSchema[]> ? TFromIntersect<Types> :
Type extends t.TLiteral<infer Value extends t.TLiteralValue> ? TFromLiteral<Value> :
Type extends t.TNever ? TFromNever :
Type extends t.TNull ? TFromNull :
Type extends t.TNumber ? TFromNumber :
Type extends t.TObject<infer Properties extends t.TProperties> ? TFromObject<Properties> :
Type extends t.TPromise<infer Type extends t.TSchema> ? TFromPromise<Type> :
Type extends t.TRecord<infer Key extends t.TSchema, infer Value extends t.TSchema> ? TFromRecord<Key, Value> :
Type extends t.TRegExp ? TFromRegExp :
Type extends t.TString ? TFromString :
Type extends t.TSymbol ? TFromSymbol :
Type extends t.TTuple<infer Types extends t.TSchema[]> ? TFromTuple<Types> :
Type extends t.TUndefined ? TFromUndefined :
Type extends t.TUnion<infer Types extends t.TSchema[]> ? TFromUnion<Types> :
Type extends t.TUnknown ? TFromUnknown :
Type extends t.TVoid ? TFromVoid :
z.ZodNever
)
// prettier-ignore
function FromType(type: t.TSchema): z.ZodTypeAny {
const constraints: TConstraint<z.ZodTypeAny>[] = []
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))
return 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) :
t.KindGuard.IsBoolean(type) ? FromBoolean(type) :
t.KindGuard.IsDate(type) ? FromDate(type) :
t.KindGuard.IsFunction(type) ? FromFunction(type) :
t.KindGuard.IsInteger(type) ? FromInteger(type) :
t.KindGuard.IsIntersect(type) ? FromIntersect(type) :
t.KindGuard.IsLiteral(type) ? FromLiteral(type) :
t.KindGuard.IsNever(type) ? FromNever(type) :
t.KindGuard.IsNull(type) ? FromNull(type) :
t.KindGuard.IsNumber(type) ? FromNumber(type) :
t.KindGuard.IsObject(type) ? FromObject(type) :
t.KindGuard.IsPromise(type) ? FromPromise(type) :
t.KindGuard.IsRegExp(type) ? FromRegExp(type) :
t.KindGuard.IsRecord(type) ? FromRecord(type) :
t.KindGuard.IsString(type) ? FromString(type) :
t.KindGuard.IsSymbol(type) ? FromSymbol(type) :
t.KindGuard.IsTuple(type) ? FromTuple(type) :
t.KindGuard.IsUndefined(type) ? FromUndefined(type) :
t.KindGuard.IsUnion(type) ? FromUnion(type) :
t.KindGuard.IsUnknown(type) ? FromUnknown(type) :
t.KindGuard.IsVoid(type) ? FromVoid(type) :
z.never()
))
}
// ------------------------------------------------------------------
// ZodFromTypeBox
// ------------------------------------------------------------------
// prettier-ignore
export type TZodFromTypeBox<Type extends object | string> = (
Type extends t.TSchema ? TFromType<Type> : z.ZodNever
)
export function ZodFromTypeBox<Type extends object | string>(type: Type): TZodFromTypeBox<Type> {
return (t.KindGuard.IsSchema(type) ? FromType(type) : z.never()) as never
}

View File

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

View File

@@ -1,6 +1,6 @@
/*--------------------------------------------------------------------------
@sinclair/typebox-adapter
@sinclair/typemap
The MIT License (MIT)
@@ -26,11 +26,21 @@ THE SOFTWARE.
---------------------------------------------------------------------------*/
import { TSchema, KindGuard } from '@sinclair/typebox'
import * as Guard from '../guard'
import * as z from 'zod'
/** Converts a TypeBox Type to a TypeBox Type */
export type TBox<Type extends unknown> = Type extends TSchema ? Type : undefined
/** Converts a TypeBox Type to a TypeBox Type */
export function Box<Type extends unknown, Result extends TBox<Type> = TBox<Type>>(type: Type): Result {
return (KindGuard.IsSchema(type) ? type : undefined) as never
type BaseType = z.ZodTypeAny | z.ZodEffects<any>
// prettier-ignore
export type TZodFromZod<Type extends object | string,
Result extends BaseType = (
Type extends BaseType
? Type
: z.ZodNever
)
> = Result
// prettier-ignore
export function ZodFromZod<Type extends object | string>(type: Type): TZodFromZod<Type> {
return (Guard.IsZod(type) ? type : z.never()) as never
}

View File

@@ -1,6 +1,6 @@
/*--------------------------------------------------------------------------
@sinclair/typebox-adapter
@sinclair/typemap
The MIT License (MIT)
@@ -26,33 +26,31 @@ THE SOFTWARE.
---------------------------------------------------------------------------*/
import { TSchema, KindGuard, Unknown, type TUnknown } from '@sinclair/typebox'
import * as TypeBox from './typebox/index'
import * as Valibot from './valibot/index'
import * as Zod from './zod/index'
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 * as z from 'zod'
/** Converts a Zod, Valibot or TypeBox Type to a TypeBox Type */
/** Creates a Zod type from Syntax or another Type */
// prettier-ignore
export type TBox<Type extends unknown> = (
TypeBox.TBox<Type> extends infer Schema extends TSchema ? Schema :
Valibot.TBox<Type> extends infer Schema extends TSchema ? Schema :
Zod.TBox<Type> extends infer Schema extends TSchema ? Schema :
TUnknown
export type TZod<Type extends object | string> = (
Guard.TIsSyntax<Type> extends true ? TZodFromSyntax<Type> :
Guard.TIsTypeBox<Type> extends true ? TZodFromTypeBox<Type> :
Guard.TIsValibot<Type> extends true ? TZodFromValibot<Type> :
Guard.TIsZod<Type> extends true ? TZodFromZod<Type> :
z.ZodNever
)
/** Converts a Zod, Valibot or TypeBox Type to a TypeBox Type */
/** Creates a Zod type from Syntax or another Type */
// prettier-ignore
export function Box<Type extends unknown>(type: Type): TBox<Type> {
{
const result = TypeBox.Box(type)
if(KindGuard.IsSchema(result)) return result as never
}
{
const result = Valibot.Box(type)
if(KindGuard.IsSchema(result)) return result as never
}
{
const result = Zod.Box(type)
if(KindGuard.IsSchema(result)) return result as never
}
return Unknown() as never
export function Zod<Type extends object | string, Result = TZod<Type>>(type: Type): Result {
return (
Guard.IsSyntax(type) ? ZodFromSyntax(type) :
Guard.IsTypeBox(type) ? ZodFromTypeBox(type) :
Guard.IsValibot(type) ? ZodFromValibot(type) :
Guard.IsZod(type) ? ZodFromZod(type) :
z.never()
) as never
}

View File

@@ -1,6 +1,5 @@
import { TypeCompiler } from '@sinclair/typebox/compiler'
import { Value } from '@sinclair/typebox/value'
import { Box } from '@sinclair/typebox-adapter'
import { Compile, TypeBox } from '@sinclair/typemap'
import * as v from 'valibot'
import * as z from 'zod'
@@ -26,7 +25,7 @@ function zod() {
return benchmark('zod', 'zod', () => T.safeParse({ x: 'hello', y: 42, z: true }).success)
}
function zod_using_value() {
const T = Box(
const T = TypeBox(
z.object({
x: z.string(),
y: z.number(),
@@ -36,14 +35,12 @@ function zod_using_value() {
return benchmark('zod', 'typebox:value', () => Value.Check(T, { x: 'hello', y: 42, z: true }))
}
function zod_using_compiler() {
const T = TypeCompiler.Compile(
Box(
z.object({
x: z.string(),
y: z.number(),
z: z.boolean(),
}),
),
const T = Compile(
z.object({
x: z.string(),
y: z.number(),
z: z.boolean(),
}),
)
return benchmark('zod', 'typebox:compile', () => T.Check({ x: 'hello', y: 42, z: true }))
}
@@ -59,7 +56,7 @@ function valibot() {
return benchmark('valibot', 'valibot', () => v.safeParse(T, { x: 'hello', y: 42, z: true }).success)
}
function valibot_using_value() {
const T = Box(
const T = TypeBox(
v.object({
x: v.string(),
y: v.number(),
@@ -69,14 +66,12 @@ function valibot_using_value() {
return benchmark('valibot', 'typebox:value', () => Value.Check(T, { x: 'hello', y: 42, z: true }))
}
function valibot_using_compiler() {
const T = TypeCompiler.Compile(
Box(
v.object({
x: v.string(),
y: v.number(),
z: v.boolean(),
}),
),
const T = Compile(
v.object({
x: v.string(),
y: v.number(),
z: v.boolean(),
}),
)
return benchmark('valibot', 'typebox:compile', () => T.Check({ x: 'hello', y: 42, z: true }))
}

View File

@@ -1,6 +1,6 @@
/*--------------------------------------------------------------------------
@sinclair/typebox-adapter
@sinclair/typemap
The MIT License (MIT)

View File

@@ -1,6 +1,6 @@
/*--------------------------------------------------------------------------
@sinclair/typebox-adapter
@sinclair/typemap
The MIT License (MIT)

View File

@@ -1,6 +1,6 @@
/*--------------------------------------------------------------------------
@sinclair/typebox-adapter
@sinclair/typemap
The MIT License (MIT)

View File

@@ -1,6 +1,6 @@
/*--------------------------------------------------------------------------
@sinclair/typebox-adapter
@sinclair/typemap
The MIT License (MIT)

View File

@@ -1,6 +1,6 @@
/*--------------------------------------------------------------------------
@sinclair/typebox-adapter
@sinclair/typemap
The MIT License (MIT)

View File

@@ -1,6 +1,6 @@
/*--------------------------------------------------------------------------
@sinclair/typebox-adapter
@sinclair/typemap
The MIT License (MIT)

View File

@@ -1,6 +1,6 @@
/*--------------------------------------------------------------------------
@sinclair/typebox-adapter
@sinclair/typemap
The MIT License (MIT)

View File

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

View File

@@ -1,6 +1,6 @@
/*--------------------------------------------------------------------------
@sinclair/typebox-adapter
@sinclair/typemap
The MIT License (MIT)

View File

@@ -1,2 +1,4 @@
import './zod'
import './valibot'
import './typebox-from-zod'
import './typebox-from-valibot'
import './valibot-from-typebox'
import './zod-from-typebox'

View File

@@ -1,38 +1,38 @@
import { Box } from '@sinclair/typebox-adapter'
import * as Types from '@sinclair/typebox'
import { TypeBox } from '@sinclair/typemap'
import { TypeGuard } from '@sinclair/typebox'
import { Assert } from './assert'
import * as t from '@sinclair/typebox'
import * as v from 'valibot'
describe('Valibot', () => {
describe('TypeBox from Valibot', () => {
// ----------------------------------------------------------------
// Metadata
// ----------------------------------------------------------------
it('Should map Description', () => {
const T = Box(v.pipe(v.number(), v.description('a number')))
const T = TypeBox(v.pipe(v.number(), v.description('a number')))
Assert.IsEqual(T.description, 'a number')
})
it('Should map Title', () => {
const T = Box(v.pipe(v.number(), v.title('a number')))
const T = TypeBox(v.pipe(v.number(), v.title('a number')))
Assert.IsEqual(T.title, 'a number')
})
it('Should map Metadata', () => {
const T = Box(v.pipe(v.number(), v.metadata({ x: 1, y: 2 })))
Assert.IsEqual(T.x, 1)
Assert.IsEqual(T.y, 2)
const T = TypeBox(v.pipe(v.number(), v.metadata({ x: 1, y: 2 })))
Assert.IsEqual(T.metadata.x, 1)
Assert.IsEqual(T.metadata.y, 2)
})
// ----------------------------------------------------------------
// Any
// ----------------------------------------------------------------
it('Should map Any', () => {
const T = Box(v.any())
const T = TypeBox(v.any())
Assert.IsTrue(TypeGuard.IsAny(T))
})
// ----------------------------------------------------------------
// Array
// ----------------------------------------------------------------
it('Should map Array', () => {
const T = Box(v.array(v.number()))
const T = TypeBox(v.array(v.number()))
Assert.IsTrue(TypeGuard.IsArray(T))
Assert.IsTrue(TypeGuard.IsNumber(T.items))
})
@@ -40,26 +40,26 @@ describe('Valibot', () => {
// BigInt
// ----------------------------------------------------------------
it('Should map BigInt', () => {
const T = Box(v.bigint())
const T = TypeBox(v.bigint())
Assert.IsTrue(TypeGuard.IsBigInt(T))
})
// ----------------------------------------------------------------
// Date
// ----------------------------------------------------------------
it('Should map Date', () => {
const T = Box(v.date())
const T = TypeBox(v.date())
Assert.IsTrue(TypeGuard.IsDate(T))
})
// ----------------------------------------------------------------
// Effects
// ----------------------------------------------------------------
// it('Should map Effects (Transform)', () => {
// const T = Box(v.number().transform(x => x))
// const T = TypeBox(v.number().transform(x => x))
// Assert.IsTrue(TypeGuard.IsNumber(T))
// Assert.IsTrue(TypeGuard.IsTransform(T))
// })
// it('Should map Effects (Refine)', () => {
// const T = Box(v.number().refine(x => true))
// const T = TypeBox(v.number().refine(x => true))
// Assert.IsTrue(TypeGuard.IsNumber(T))
// Assert.IsTrue(TypeGuard.IsTransform(T))
// })
@@ -67,17 +67,17 @@ describe('Valibot', () => {
// Literal
// ----------------------------------------------------------------
it('Should map Literal (Number)', () => {
const T = Box(v.literal(42))
const T = TypeBox(v.literal(42))
Assert.IsTrue(TypeGuard.IsLiteral(T))
Assert.IsEqual(T.const, 42)
})
it('Should map Literal (String)', () => {
const T = Box(v.literal('hello'))
const T = TypeBox(v.literal('hello'))
Assert.IsTrue(TypeGuard.IsLiteral(T))
Assert.IsEqual(T.const, 'hello')
})
it('Should map Literal (Boolean)', () => {
const T = Box(v.literal(true))
const T = TypeBox(v.literal(true))
Assert.IsTrue(TypeGuard.IsLiteral(T))
Assert.IsEqual(T.const, true)
})
@@ -85,7 +85,7 @@ describe('Valibot', () => {
// Nullable
// ----------------------------------------------------------------
it('Should map Nullable', () => {
const T = Box(v.nullable(v.number()))
const T = TypeBox(v.nullable(v.number()))
Assert.IsTrue(TypeGuard.IsUnion(T))
Assert.IsTrue(TypeGuard.IsNull(T.anyOf[0]))
Assert.IsTrue(TypeGuard.IsNumber(T.anyOf[1]))
@@ -94,7 +94,7 @@ describe('Valibot', () => {
// Object
// ----------------------------------------------------------------
it('Should map Object', () => {
const T = Box(
const T = TypeBox(
v.object({
x: v.number(),
y: v.string(),
@@ -105,7 +105,7 @@ describe('Valibot', () => {
Assert.IsTrue(TypeGuard.IsString(T.properties.y))
})
it('Should map Object (Strict)', () => {
const T = Box(
const T = TypeBox(
v.strictObject({
x: v.number(),
y: v.string(),
@@ -120,7 +120,7 @@ describe('Valibot', () => {
// Optional
// ----------------------------------------------------------------
it('Should map Optional', () => {
const T = Box(
const T = TypeBox(
v.object({
x: v.optional(v.number()),
y: v.optional(v.number()),
@@ -133,7 +133,7 @@ describe('Valibot', () => {
Assert.IsTrue(TypeGuard.IsOptional(T.properties.y))
})
it('Should map Optional (Partial)', () => {
const T = Box(
const T = TypeBox(
v.partial(
v.object({
x: v.number(),
@@ -151,19 +151,19 @@ describe('Valibot', () => {
// Promise
// ----------------------------------------------------------------
it('Should map Promise', () => {
const T = Box(v.promise())
Assert.IsEqual(T[Types.Kind], 'ValibotPromise')
const T = TypeBox(v.promise())
Assert.IsEqual(T[t.Kind], 'ValibotPromise')
})
// ----------------------------------------------------------------
// Record
// ----------------------------------------------------------------
it('Should map Record (String Key)', () => {
const T = Box(v.record(v.string(), v.number()))
const T = TypeBox(v.record(v.string(), v.number()))
Assert.IsTrue(TypeGuard.IsRecord(T))
Assert.IsTrue(TypeGuard.IsNumber(T.patternProperties[Types.PatternStringExact]))
Assert.IsTrue(TypeGuard.IsNumber(T.patternProperties[t.PatternStringExact]))
})
it('Should map Record (Finite Union)', () => {
const T = Box(v.record(v.union([v.literal('x'), v.literal('y')]), v.number()))
const T = TypeBox(v.record(v.union([v.literal('x'), v.literal('y')]), v.number()))
Assert.IsTrue(TypeGuard.IsObject(T))
Assert.IsTrue(TypeGuard.IsNumber(T.properties.x))
Assert.IsTrue(TypeGuard.IsNumber(T.properties.y))
@@ -172,35 +172,35 @@ describe('Valibot', () => {
// Never
// ----------------------------------------------------------------
it('Should map Never', () => {
const T = Box(v.never())
const T = TypeBox(v.never())
Assert.IsTrue(TypeGuard.IsNever(T))
})
// ----------------------------------------------------------------
// Null
// ----------------------------------------------------------------
it('Should map Null', () => {
const T = Box(v.null())
const T = TypeBox(v.null())
Assert.IsTrue(TypeGuard.IsNull(T))
})
// ----------------------------------------------------------------
// Number
// ----------------------------------------------------------------
it('Should map Number', () => {
const T = Box(v.number())
const T = TypeBox(v.number())
Assert.IsTrue(TypeGuard.IsNumber(T))
})
it('Should map Number (Integer)', () => {
const T = Box(v.pipe(v.number(), v.integer()))
const T = TypeBox(v.pipe(v.number(), v.integer()))
Assert.IsTrue(TypeGuard.IsNumber(T))
Assert.IsEqual(T.multipleOf, 1)
})
it('Should map Number (Minimum)', () => {
const T = Box(v.pipe(v.number(), v.minValue(100)))
const T = TypeBox(v.pipe(v.number(), v.minValue(100)))
Assert.IsTrue(TypeGuard.IsNumber(T))
Assert.IsEqual(T.minimum, 100)
})
it('Should map Number (Maximum)', () => {
const T = Box(v.pipe(v.number(), v.maxValue(100)))
const T = TypeBox(v.pipe(v.number(), v.maxValue(100)))
Assert.IsTrue(TypeGuard.IsNumber(T))
Assert.IsEqual(T.maximum, 100)
})
@@ -208,194 +208,203 @@ describe('Valibot', () => {
// String
// ----------------------------------------------------------------
it('Should map String', () => {
const T = Box(v.string())
const T = TypeBox(v.string())
Assert.IsTrue(TypeGuard.IsString(T))
})
it('Should map String (Base64)', () => {
const T = Box(v.pipe(v.string(), v.base64()))
const T = TypeBox(v.pipe(v.string(), v.base64()))
Assert.IsTrue(TypeGuard.IsString(T))
Assert.IsEqual(T.format, 'valibot:base64')
Assert.IsEqual(T.format, 'base64')
})
it('Should map String (Bic)', () => {
const T = Box(v.pipe(v.string(), v.bic()))
const T = TypeBox(v.pipe(v.string(), v.bic()))
Assert.IsTrue(TypeGuard.IsString(T))
Assert.IsEqual(T.format, 'valibot:bic')
Assert.IsEqual(T.format, 'bic')
})
it('Should map String (CreditCard)', () => {
const T = Box(v.pipe(v.string(), v.creditCard()))
const T = TypeBox(v.pipe(v.string(), v.creditCard()))
Assert.IsTrue(TypeGuard.IsString(T))
Assert.IsEqual(T.format, 'valibot:credit_card')
Assert.IsEqual(T.format, 'credit_card')
})
it('Should map String (Cuid2)', () => {
const T = Box(v.pipe(v.string(), v.cuid2()))
const T = TypeBox(v.pipe(v.string(), v.cuid2()))
Assert.IsTrue(TypeGuard.IsString(T))
Assert.IsEqual(T.format, 'valibot:cuid2')
Assert.IsEqual(T.format, 'cuid2')
})
it('Should map String (Decimal)', () => {
const T = Box(v.pipe(v.string(), v.decimal()))
const T = TypeBox(v.pipe(v.string(), v.decimal()))
Assert.IsTrue(TypeGuard.IsString(T))
Assert.IsEqual(T.format, 'valibot:decimal')
Assert.IsEqual(T.format, 'decimal')
})
it('Should map String (Digits)', () => {
const T = Box(v.pipe(v.string(), v.digits()))
const T = TypeBox(v.pipe(v.string(), v.digits()))
Assert.IsTrue(TypeGuard.IsString(T))
Assert.IsEqual(T.format, 'valibot:digits')
Assert.IsEqual(T.format, 'digits')
})
it('Should map String (Email)', () => {
const T = Box(v.pipe(v.string(), v.email()))
const T = TypeBox(v.pipe(v.string(), v.email()))
Assert.IsTrue(TypeGuard.IsString(T))
Assert.IsEqual(T.format, 'valibot:email')
Assert.IsEqual(T.format, 'email')
})
it('Should map String (Emoji)', () => {
const T = Box(v.pipe(v.string(), v.emoji()))
const T = TypeBox(v.pipe(v.string(), v.emoji()))
Assert.IsTrue(TypeGuard.IsString(T))
Assert.IsEqual(T.format, 'valibot:emoji')
Assert.IsEqual(T.format, 'emoji')
})
it('Should map String (Empty)', () => {
const T = Box(v.pipe(v.string(), v.empty()))
const T = TypeBox(v.pipe(v.string(), v.empty()))
Assert.IsTrue(TypeGuard.IsString(T))
Assert.IsEqual(T.maxLength, 0)
})
it('Should map String (EndsWith)', () => {
const T = Box(v.pipe(v.string(), v.endsWith('hello')))
const T = TypeBox(v.pipe(v.string(), v.endsWith('hello')))
Assert.IsTrue(TypeGuard.IsString(T))
Assert.IsEqual(T.pattern, 'hello$')
})
it('Should map String (Includes)', () => {
const T = Box(v.pipe(v.string(), v.includes('hello')))
const T = TypeBox(v.pipe(v.string(), v.includes('hello')))
Assert.IsTrue(TypeGuard.IsString(T))
Assert.IsEqual(T.pattern, 'hello')
})
it('Should map String (Ipv4)', () => {
const T = Box(v.pipe(v.string(), v.ipv4()))
const T = TypeBox(v.pipe(v.string(), v.ipv4()))
Assert.IsTrue(TypeGuard.IsString(T))
Assert.IsEqual(T.format, 'valibot:ipv4')
Assert.IsEqual(T.format, 'ipv4')
})
it('Should map String (IpV6)', () => {
const T = Box(v.pipe(v.string(), v.ipv6()))
const T = TypeBox(v.pipe(v.string(), v.ipv6()))
Assert.IsTrue(TypeGuard.IsString(T))
Assert.IsEqual(T.format, 'valibot:ipv6')
Assert.IsEqual(T.format, 'ipv6')
})
it('Should map String (Ip)', () => {
const T = Box(v.pipe(v.string(), v.ip()))
const T = TypeBox(v.pipe(v.string(), v.ip()))
Assert.IsTrue(TypeGuard.IsString(T))
Assert.IsEqual(T.format, 'valibot:ip')
Assert.IsEqual(T.format, 'ip')
})
it('Should map String (IsoDate)', () => {
const T = Box(v.pipe(v.string(), v.isoDate()))
const T = TypeBox(v.pipe(v.string(), v.isoDate()))
Assert.IsTrue(TypeGuard.IsString(T))
Assert.IsEqual(T.format, 'valibot:iso_date')
Assert.IsEqual(T.format, 'iso_date')
})
it('Should map String (IsoDateTime)', () => {
const T = Box(v.pipe(v.string(), v.isoDateTime()))
const T = TypeBox(v.pipe(v.string(), v.isoDateTime()))
Assert.IsTrue(TypeGuard.IsString(T))
Assert.IsEqual(T.format, 'valibot:iso_date_time')
Assert.IsEqual(T.format, 'iso_date_time')
})
it('Should map String (IsoTime)', () => {
const T = Box(v.pipe(v.string(), v.isoTime()))
const T = TypeBox(v.pipe(v.string(), v.isoTime()))
Assert.IsTrue(TypeGuard.IsString(T))
Assert.IsEqual(T.format, 'valibot:iso_time')
Assert.IsEqual(T.format, 'iso_time')
})
it('Should map String (IsoTimeSecond)', () => {
const T = Box(v.pipe(v.string(), v.isoTimeSecond()))
const T = TypeBox(v.pipe(v.string(), v.isoTimeSecond()))
Assert.IsTrue(TypeGuard.IsString(T))
Assert.IsEqual(T.format, 'valibot:iso_time_second')
Assert.IsEqual(T.format, 'iso_time_second')
})
it('Should map String (IsoTimestamp)', () => {
const T = Box(v.pipe(v.string(), v.isoTimestamp()))
const T = TypeBox(v.pipe(v.string(), v.isoTimestamp()))
Assert.IsTrue(TypeGuard.IsString(T))
Assert.IsEqual(T.format, 'valibot:iso_timestamp')
Assert.IsEqual(T.format, 'iso_timestamp')
})
it('Should map String (IsoWeek)', () => {
const T = Box(v.pipe(v.string(), v.isoWeek()))
const T = TypeBox(v.pipe(v.string(), v.isoWeek()))
Assert.IsTrue(TypeGuard.IsString(T))
Assert.IsEqual(T.format, 'valibot:iso_week')
Assert.IsEqual(T.format, 'iso_week')
})
it('Should map String (Length)', () => {
const T = Box(v.pipe(v.string(), v.length(100)))
const T = TypeBox(v.pipe(v.string(), v.length(100)))
Assert.IsTrue(TypeGuard.IsString(T))
Assert.IsEqual(T.maxLength, 100)
Assert.IsEqual(T.minLength, 100)
})
it('Should map String (Mac48)', () => {
const T = Box(v.pipe(v.string(), v.mac48()))
const T = TypeBox(v.pipe(v.string(), v.mac48()))
Assert.IsTrue(TypeGuard.IsString(T))
Assert.IsEqual(T.format, 'valibot:mac48')
Assert.IsEqual(T.format, 'mac48')
})
it('Should map String (Mac64)', () => {
const T = Box(v.pipe(v.string(), v.mac64()))
const T = TypeBox(v.pipe(v.string(), v.mac64()))
Assert.IsTrue(TypeGuard.IsString(T))
Assert.IsEqual(T.format, 'valibot:mac64')
Assert.IsEqual(T.format, 'mac64')
})
it('Should map String (Mac)', () => {
const T = Box(v.pipe(v.string(), v.mac()))
const T = TypeBox(v.pipe(v.string(), v.mac()))
Assert.IsTrue(TypeGuard.IsString(T))
Assert.IsEqual(T.format, 'valibot:mac')
Assert.IsEqual(T.format, 'mac')
})
it('Should map String (MaxLength)', () => {
const T = Box(v.pipe(v.string(), v.maxLength(100)))
const T = TypeBox(v.pipe(v.string(), v.maxLength(100)))
Assert.IsTrue(TypeGuard.IsString(T))
Assert.IsEqual(T.maxLength, 100)
})
it('Should map String (MinLength)', () => {
const T = Box(v.pipe(v.string(), v.minLength(100)))
const T = TypeBox(v.pipe(v.string(), v.minLength(100)))
Assert.IsTrue(TypeGuard.IsString(T))
Assert.IsEqual(T.minLength, 100)
})
it('Should map String (Nanoid)', () => {
const T = Box(v.pipe(v.string(), v.nanoid()))
const T = TypeBox(v.pipe(v.string(), v.nanoid()))
Assert.IsTrue(TypeGuard.IsString(T))
Assert.IsEqual(T.format, 'valibot:nanoid')
Assert.IsEqual(T.format, 'nanoid')
})
it('Should map String (Octal)', () => {
const T = Box(v.pipe(v.string(), v.octal()))
const T = TypeBox(v.pipe(v.string(), v.octal()))
Assert.IsTrue(TypeGuard.IsString(T))
Assert.IsEqual(T.format, 'valibot:octal')
Assert.IsEqual(T.format, 'octal')
})
it('Should map String (RegExp)', () => {
const T = Box(v.pipe(v.string(), v.regex(/abc/)))
const T = TypeBox(v.pipe(v.string(), v.regex(/abc/)))
Assert.IsTrue(TypeGuard.IsString(T))
Assert.IsEqual(T.pattern, 'abc')
})
it('Should map String (StartsWith)', () => {
const T = Box(v.pipe(v.string(), v.startsWith('hello')))
const T = TypeBox(v.pipe(v.string(), v.startsWith('hello')))
Assert.IsTrue(TypeGuard.IsString(T))
Assert.IsEqual(T.pattern, '^hello')
})
it('Should map String (Ulid)', () => {
const T = Box(v.pipe(v.string(), v.ulid()))
const T = TypeBox(v.pipe(v.string(), v.ulid()))
Assert.IsTrue(TypeGuard.IsString(T))
Assert.IsEqual(T.format, 'valibot:ulid')
Assert.IsEqual(T.format, 'ulid')
})
it('Should map String (Url)', () => {
const T = Box(v.pipe(v.string(), v.url()))
const T = TypeBox(v.pipe(v.string(), v.url()))
Assert.IsTrue(TypeGuard.IsString(T))
Assert.IsEqual(T.format, 'valibot:url')
Assert.IsEqual(T.format, 'url')
})
it('Should map String (Uuid)', () => {
const T = Box(v.pipe(v.string(), v.uuid()))
const T = TypeBox(v.pipe(v.string(), v.uuid()))
Assert.IsTrue(TypeGuard.IsString(T))
Assert.IsEqual(T.format, 'valibot:uuid')
Assert.IsEqual(T.format, 'uuid')
})
// ----------------------------------------------------------------
// Symbol
// ----------------------------------------------------------------
it('Should map Symbol', () => {
const T = Box(v.symbol())
const T = TypeBox(v.symbol())
Assert.IsTrue(TypeGuard.IsSymbol(T))
})
// ----------------------------------------------------------------
// Tuple
// ----------------------------------------------------------------
it('Should map Tuple', () => {
const T = TypeBox(v.tuple([v.number(), v.string()]))
Assert.IsTrue(TypeGuard.IsTuple(T))
Assert.IsTrue(TypeGuard.IsNumber(T.items![0]))
Assert.IsTrue(TypeGuard.IsString(T.items![1]))
})
// ----------------------------------------------------------------
// Undefined
// ----------------------------------------------------------------
it('Should map Undefined', () => {
const T = Box(v.undefined())
const T = TypeBox(v.undefined())
Assert.IsTrue(TypeGuard.IsUndefined(T))
})
// ----------------------------------------------------------------
// Union
// ----------------------------------------------------------------
it('Should map Union', () => {
const T = Box(v.union([v.string(), v.boolean()]))
const T = TypeBox(v.union([v.string(), v.boolean()]))
Assert.IsTrue(TypeGuard.IsUnion(T))
Assert.IsTrue(TypeGuard.IsString(T.anyOf[0]))
Assert.IsTrue(TypeGuard.IsBoolean(T.anyOf[1]))
@@ -404,14 +413,14 @@ describe('Valibot', () => {
// Unknown
// ----------------------------------------------------------------
it('Should map Unknown', () => {
const T = Box(v.unknown())
const T = TypeBox(v.unknown())
Assert.IsTrue(TypeGuard.IsUnknown(T))
})
// ----------------------------------------------------------------
// Void
// ----------------------------------------------------------------
it('Should map Void', () => {
const T = Box(v.void())
const T = TypeBox(v.void())
Assert.IsTrue(TypeGuard.IsVoid(T))
})
})

View File

@@ -1,33 +1,33 @@
import { Box } from '@sinclair/typebox-adapter'
import * as Types from '@sinclair/typebox'
import { TypeBox } from '@sinclair/typemap'
import { TypeGuard } from '@sinclair/typebox'
import { Assert } from './assert'
import * as t from '@sinclair/typebox'
import * as z from 'zod'
describe('Zod', () => {
describe('TypeBox From Zod', () => {
// ----------------------------------------------------------------
// Metadata
// ----------------------------------------------------------------
it('Should map Description', () => {
const T = Box(z.number().describe('a number'))
const T = TypeBox(z.number().describe('a number'))
Assert.IsEqual(T.description, 'a number')
})
it('Should map Default', () => {
const T = Box(z.number().default(12345))
const T = TypeBox(z.number().default(12345))
Assert.IsEqual(T.default, 12345)
})
// ----------------------------------------------------------------
// Any
// ----------------------------------------------------------------
it('Should map Any', () => {
const T = Box(z.any())
const T = TypeBox(z.any())
Assert.IsTrue(TypeGuard.IsAny(T))
})
// ----------------------------------------------------------------
// Array
// ----------------------------------------------------------------
it('Should map Array', () => {
const T = Box(z.array(z.number()))
const T = TypeBox(z.array(z.number()))
Assert.IsTrue(TypeGuard.IsArray(T))
Assert.IsTrue(TypeGuard.IsNumber(T.items))
})
@@ -35,14 +35,14 @@ describe('Zod', () => {
// BigInt
// ----------------------------------------------------------------
it('Should map BigInt', () => {
const T = Box(z.bigint())
const T = TypeBox(z.bigint())
Assert.IsTrue(TypeGuard.IsBigInt(T))
})
// ----------------------------------------------------------------
// Date
// ----------------------------------------------------------------
it('Should map Date', () => {
const T = Box(z.date())
const T = TypeBox(z.date())
Assert.IsTrue(TypeGuard.IsDate(T))
})
// ----------------------------------------------------------------
@@ -52,7 +52,7 @@ describe('Zod', () => {
const A = z.object({ type: z.literal('A') })
const B = z.object({ type: z.literal('B') })
const C = z.object({ type: z.literal('C') })
const T = Box(z.discriminatedUnion('type', [A, B, C]))
const T = TypeBox(z.discriminatedUnion('type', [A, B, C]))
Assert.IsTrue(TypeGuard.IsUnion(T))
Assert.IsEqual(T.discriminator, 'type')
Assert.IsTrue(T.anyOf[0].properties.type.const === 'A')
@@ -63,30 +63,40 @@ describe('Zod', () => {
// Effects
// ----------------------------------------------------------------
it('Should map Effects (Transform)', () => {
const T = Box(z.number().transform((x) => x))
const T = TypeBox(z.number().transform((x) => x))
Assert.IsTrue(TypeGuard.IsNumber(T))
Assert.IsTrue(TypeGuard.IsTransform(T))
})
it('Should map Effects (Refine)', () => {
const T = Box(z.number().refine((x) => true))
const T = TypeBox(z.number().refine((x) => true))
Assert.IsTrue(TypeGuard.IsNumber(T))
Assert.IsTrue(TypeGuard.IsTransform(T))
})
// ----------------------------------------------------------------
// Enum
// ----------------------------------------------------------------
it('Should map Enum', () => {
const T = TypeBox(z.enum(['a', 'b', 'c']))
Assert.IsTrue(TypeGuard.IsUnion(T))
Assert.IsEqual(T.anyOf[0].const, 'a')
Assert.IsEqual(T.anyOf[1].const, 'b')
Assert.IsEqual(T.anyOf[2].const, 'c')
})
// ----------------------------------------------------------------
// Literal
// ----------------------------------------------------------------
it('Should map Literal (Number)', () => {
const T = Box(z.literal(42))
const T = TypeBox(z.literal(42))
Assert.IsTrue(TypeGuard.IsLiteral(T))
Assert.IsEqual(T.const, 42)
})
it('Should map Literal (String)', () => {
const T = Box(z.literal('hello'))
const T = TypeBox(z.literal('hello'))
Assert.IsTrue(TypeGuard.IsLiteral(T))
Assert.IsEqual(T.const, 'hello')
})
it('Should map Literal (Boolean)', () => {
const T = Box(z.literal(true))
const T = TypeBox(z.literal(true))
Assert.IsTrue(TypeGuard.IsLiteral(T))
Assert.IsEqual(T.const, true)
})
@@ -94,7 +104,7 @@ describe('Zod', () => {
// Nullable
// ----------------------------------------------------------------
it('Should map Nullable', () => {
const T = Box(z.number().nullable())
const T = TypeBox(z.number().nullable())
Assert.IsTrue(TypeGuard.IsUnion(T))
Assert.IsTrue(TypeGuard.IsNull(T.anyOf[0]))
Assert.IsTrue(TypeGuard.IsNumber(T.anyOf[1]))
@@ -103,7 +113,7 @@ describe('Zod', () => {
// Object
// ----------------------------------------------------------------
it('Should map Object', () => {
const T = Box(
const T = TypeBox(
z.object({
x: z.number(),
y: z.string(),
@@ -114,7 +124,7 @@ describe('Zod', () => {
Assert.IsTrue(TypeGuard.IsString(T.properties.y))
})
it('Should map Object (Strict)', () => {
const T = Box(
const T = TypeBox(
z
.object({
x: z.number(),
@@ -131,7 +141,7 @@ describe('Zod', () => {
// Optional
// ----------------------------------------------------------------
it('Should map Optional', () => {
const T = Box(
const T = TypeBox(
z.object({
x: z.number().optional(),
y: z.number().optional(),
@@ -144,7 +154,7 @@ describe('Zod', () => {
Assert.IsTrue(TypeGuard.IsOptional(T.properties.y))
})
it('Should map Optional (Readonly)', () => {
const T = Box(
const T = TypeBox(
z.object({
x: z.number().optional().readonly(),
y: z.number().optional().readonly(),
@@ -159,7 +169,7 @@ describe('Zod', () => {
Assert.IsTrue(TypeGuard.IsReadonly(T.properties.y))
})
it('Should map Optional (Partial)', () => {
const T = Box(
const T = TypeBox(
z
.object({
x: z.number(),
@@ -177,7 +187,7 @@ describe('Zod', () => {
// Promise
// ----------------------------------------------------------------
it('Should map Promise', () => {
const T = Box(z.promise(z.number()))
const T = TypeBox(z.promise(z.number()))
Assert.IsTrue(TypeGuard.IsPromise(T))
Assert.IsTrue(TypeGuard.IsNumber(T.item))
})
@@ -185,7 +195,7 @@ describe('Zod', () => {
// Readonly
// ----------------------------------------------------------------
it('Should map Readonly', () => {
const T = Box(
const T = TypeBox(
z.object({
x: z.number().readonly(),
y: z.number().readonly(),
@@ -198,7 +208,7 @@ describe('Zod', () => {
Assert.IsTrue(TypeGuard.IsReadonly(T.properties.y))
})
it('Should map Readonly (Optional)', () => {
const T = Box(
const T = TypeBox(
z.object({
x: z.number().readonly().optional(),
y: z.number().readonly().optional(),
@@ -216,22 +226,22 @@ describe('Zod', () => {
// Record
// ----------------------------------------------------------------
it('Should map Record (Key Implicit)', () => {
const T = Box(z.record(z.number()))
const T = TypeBox(z.record(z.number()))
Assert.IsTrue(TypeGuard.IsRecord(T))
Assert.IsTrue(TypeGuard.IsNumber(T.patternProperties[Types.PatternStringExact]))
Assert.IsTrue(TypeGuard.IsNumber(T.patternProperties[t.PatternStringExact]))
})
it('Should map Record (Number Key)', () => {
const T = Box(z.record(z.number(), z.number()))
const T = TypeBox(z.record(z.number(), z.number()))
Assert.IsTrue(TypeGuard.IsRecord(T))
Assert.IsTrue(TypeGuard.IsNumber(T.patternProperties[Types.PatternNumberExact]))
Assert.IsTrue(TypeGuard.IsNumber(T.patternProperties[t.PatternNumberExact]))
})
it('Should map Record (String Key)', () => {
const T = Box(z.record(z.string(), z.number()))
const T = TypeBox(z.record(z.string(), z.number()))
Assert.IsTrue(TypeGuard.IsRecord(T))
Assert.IsTrue(TypeGuard.IsNumber(T.patternProperties[Types.PatternStringExact]))
Assert.IsTrue(TypeGuard.IsNumber(T.patternProperties[t.PatternStringExact]))
})
it('Should map Record (Finite Union)', () => {
const T = Box(z.record(z.union([z.literal('x'), z.literal('y')]), z.number()))
const T = TypeBox(z.record(z.union([z.literal('x'), z.literal('y')]), z.number()))
Assert.IsTrue(TypeGuard.IsObject(T))
Assert.IsTrue(TypeGuard.IsNumber(T.properties.x))
Assert.IsTrue(TypeGuard.IsNumber(T.properties.y))
@@ -240,35 +250,35 @@ describe('Zod', () => {
// Never
// ----------------------------------------------------------------
it('Should map Never', () => {
const T = Box(z.never())
const T = TypeBox(z.never())
Assert.IsTrue(TypeGuard.IsNever(T))
})
// ----------------------------------------------------------------
// Null
// ----------------------------------------------------------------
it('Should map Null', () => {
const T = Box(z.null())
const T = TypeBox(z.null())
Assert.IsTrue(TypeGuard.IsNull(T))
})
// ----------------------------------------------------------------
// Number
// ----------------------------------------------------------------
it('Should map Number', () => {
const T = Box(z.number())
const T = TypeBox(z.number())
Assert.IsTrue(TypeGuard.IsNumber(T))
})
it('Should map Number (Integer)', () => {
const T = Box(z.number().int())
const T = TypeBox(z.number().int())
Assert.IsTrue(TypeGuard.IsNumber(T))
Assert.IsEqual(T.multipleOf, 1)
})
it('Should map Number (Minimum)', () => {
const T = Box(z.number().min(100))
const T = TypeBox(z.number().min(100))
Assert.IsTrue(TypeGuard.IsNumber(T))
Assert.IsEqual(T.minimum, 100)
})
it('Should map Number (Maximum)', () => {
const T = Box(z.number().max(100))
const T = TypeBox(z.number().max(100))
Assert.IsTrue(TypeGuard.IsNumber(T))
Assert.IsEqual(T.maximum, 100)
})
@@ -276,153 +286,153 @@ describe('Zod', () => {
// String
// ----------------------------------------------------------------
it('Should map String', () => {
const T = Box(z.string())
const T = TypeBox(z.string())
Assert.IsTrue(TypeGuard.IsString(T))
})
it('Should map String (Base64)', () => {
const T = Box(z.string().base64())
const T = TypeBox(z.string().base64())
Assert.IsTrue(TypeGuard.IsString(T))
Assert.IsEqual(T.format, 'zod:base64')
Assert.IsEqual(T.format, 'base64')
})
it('Should map String (Base64Url)', () => {
const T = Box(z.string().base64url())
const T = TypeBox(z.string().base64url())
Assert.IsTrue(TypeGuard.IsString(T))
Assert.IsEqual(T.format, 'zod:base64url')
Assert.IsEqual(T.format, 'base64url')
})
it('Should map String (Cidr V4)', () => {
const T = Box(z.string().cidr({ version: 'v4' }))
const T = TypeBox(z.string().cidr({ version: 'v4' }))
Assert.IsTrue(TypeGuard.IsString(T))
Assert.IsEqual(T.format, 'zod:cidrv4')
Assert.IsEqual(T.format, 'cidrv4')
})
it('Should map String (Cidr v6)', () => {
const T = Box(z.string().cidr({ version: 'v6' }))
const T = TypeBox(z.string().cidr({ version: 'v6' }))
Assert.IsTrue(TypeGuard.IsString(T))
Assert.IsEqual(T.format, 'zod:cidrv6')
Assert.IsEqual(T.format, 'cidrv6')
})
it('Should map String (Cidr)', () => {
const T = Box(z.string().cidr())
const T = TypeBox(z.string().cidr())
Assert.IsTrue(TypeGuard.IsString(T))
Assert.IsEqual(T.format, 'zod:cidr')
Assert.IsEqual(T.format, 'cidr')
})
it('Should map String (Cuid)', () => {
const T = Box(z.string().cuid())
const T = TypeBox(z.string().cuid())
Assert.IsTrue(TypeGuard.IsString(T))
Assert.IsEqual(T.format, 'zod:cuid')
Assert.IsEqual(T.format, 'cuid')
})
it('Should map String (Cuid2)', () => {
const T = Box(z.string().cuid2())
const T = TypeBox(z.string().cuid2())
Assert.IsTrue(TypeGuard.IsString(T))
Assert.IsEqual(T.format, 'zod:cuid2')
Assert.IsEqual(T.format, 'cuid2')
})
it('Should map String (Ulid)', () => {
const T = Box(z.string().ulid())
const T = TypeBox(z.string().ulid())
Assert.IsTrue(TypeGuard.IsString(T))
Assert.IsEqual(T.format, 'zod:ulid')
Assert.IsEqual(T.format, 'ulid')
})
it('Should map String (Email)', () => {
const T = Box(z.string().email())
const T = TypeBox(z.string().email())
Assert.IsTrue(TypeGuard.IsString(T))
Assert.IsEqual(T.format, 'zod:email')
Assert.IsEqual(T.format, 'email')
})
it('Should map String (Emoji)', () => {
const T = Box(z.string().emoji())
const T = TypeBox(z.string().emoji())
Assert.IsTrue(TypeGuard.IsString(T))
Assert.IsEqual(T.format, 'zod:emoji')
Assert.IsEqual(T.format, 'emoji')
})
it('Should map String (EndsWith)', () => {
const T = Box(z.string().endsWith('hello'))
const T = TypeBox(z.string().endsWith('hello'))
Assert.IsTrue(TypeGuard.IsString(T))
Assert.IsEqual(T.pattern, 'hello$')
})
it('Should map String (Includes)', () => {
const T = Box(z.string().includes('hello'))
const T = TypeBox(z.string().includes('hello'))
Assert.IsTrue(TypeGuard.IsString(T))
Assert.IsEqual(T.pattern, 'hello')
})
it('Should map String (IpV4)', () => {
const T = Box(z.string().ip({ version: 'v4' }))
const T = TypeBox(z.string().ip({ version: 'v4' }))
Assert.IsTrue(TypeGuard.IsString(T))
Assert.IsEqual(T.format, 'zod:ipv4')
Assert.IsEqual(T.format, 'ipv4')
})
it('Should map String (IpV6)', () => {
const T = Box(z.string().ip({ version: 'v6' }))
const T = TypeBox(z.string().ip({ version: 'v6' }))
Assert.IsTrue(TypeGuard.IsString(T))
Assert.IsEqual(T.format, 'zod:ipv6')
Assert.IsEqual(T.format, 'ipv6')
})
it('Should map String (Ip)', () => {
const T = Box(z.string().ip())
const T = TypeBox(z.string().ip())
Assert.IsTrue(TypeGuard.IsString(T))
Assert.IsEqual(T.format, 'zod:ip')
Assert.IsEqual(T.format, 'ip')
})
it('Should map String (Jwt)', () => {
const T = Box(z.string().jwt())
const T = TypeBox(z.string().jwt())
Assert.IsTrue(TypeGuard.IsString(T))
Assert.IsEqual(T.format, 'zod:jwt')
Assert.IsEqual(T.format, 'jwt')
})
it('Should map String (Length)', () => {
const T = Box(z.string().length(100))
const T = TypeBox(z.string().length(100))
Assert.IsTrue(TypeGuard.IsString(T))
Assert.IsEqual(T.minLength, 100)
Assert.IsEqual(T.maxLength, 100)
})
it('Should map String (Min)', () => {
const T = Box(z.string().min(100))
const T = TypeBox(z.string().min(100))
Assert.IsTrue(TypeGuard.IsString(T))
Assert.IsEqual(T.minLength, 100)
})
it('Should map String (Max)', () => {
const T = Box(z.string().max(100))
const T = TypeBox(z.string().max(100))
Assert.IsTrue(TypeGuard.IsString(T))
Assert.IsEqual(T.maxLength, 100)
})
it('Should map String (Nanoid)', () => {
const T = Box(z.string().nanoid())
const T = TypeBox(z.string().nanoid())
Assert.IsTrue(TypeGuard.IsString(T))
Assert.IsEqual(T.format, 'zod:nanoid')
Assert.IsEqual(T.format, 'nanoid')
})
it('Should map String (RegExp)', () => {
const T = Box(z.string().regex(/abc/))
const T = TypeBox(z.string().regex(/abc/))
Assert.IsTrue(TypeGuard.IsString(T))
Assert.IsEqual(T.pattern, 'abc')
})
it('Should map String (StartsWith)', () => {
const T = Box(z.string().startsWith('hello'))
const T = TypeBox(z.string().startsWith('hello'))
Assert.IsTrue(TypeGuard.IsString(T))
Assert.IsEqual(T.pattern, '^hello')
})
it('Should map String (Time)', () => {
const T = Box(z.string().time())
const T = TypeBox(z.string().time())
Assert.IsTrue(TypeGuard.IsString(T))
Assert.IsEqual(T.format, 'zod:time')
Assert.IsEqual(T.format, 'time')
})
it('Should map String (Ulid)', () => {
const T = Box(z.string().ulid())
const T = TypeBox(z.string().ulid())
Assert.IsTrue(TypeGuard.IsString(T))
Assert.IsEqual(T.format, 'zod:ulid')
Assert.IsEqual(T.format, 'ulid')
})
it('Should map String (Url)', () => {
const T = Box(z.string().url())
const T = TypeBox(z.string().url())
Assert.IsTrue(TypeGuard.IsString(T))
Assert.IsEqual(T.format, 'zod:url')
Assert.IsEqual(T.format, 'url')
})
it('Should map String (Uuid)', () => {
const T = Box(z.string().uuid())
const T = TypeBox(z.string().uuid())
Assert.IsTrue(TypeGuard.IsString(T))
Assert.IsEqual(T.format, 'zod:uuid')
Assert.IsEqual(T.format, 'uuid')
})
// ----------------------------------------------------------------
// Symbol
// ----------------------------------------------------------------
it('Should map Symbol', () => {
const T = Box(z.symbol())
const T = TypeBox(z.symbol())
Assert.IsTrue(TypeGuard.IsSymbol(T))
})
// ----------------------------------------------------------------
// Tuple
// ----------------------------------------------------------------
it('Should map Tuple', () => {
const T = Box(z.tuple([z.number(), z.string()]))
const T = TypeBox(z.tuple([z.number(), z.string()]))
Assert.IsTrue(TypeGuard.IsTuple(T))
Assert.IsTrue(TypeGuard.IsNumber(T.items![0]))
Assert.IsTrue(TypeGuard.IsString(T.items![1]))
@@ -431,14 +441,14 @@ describe('Zod', () => {
// Undefined
// ----------------------------------------------------------------
it('Should map Undefined', () => {
const T = Box(z.undefined())
const T = TypeBox(z.undefined())
Assert.IsTrue(TypeGuard.IsUndefined(T))
})
// ----------------------------------------------------------------
// Union
// ----------------------------------------------------------------
it('Should map Union', () => {
const T = Box(z.union([z.string(), z.boolean()]))
const T = TypeBox(z.union([z.string(), z.boolean()]))
Assert.IsTrue(TypeGuard.IsUnion(T))
Assert.IsTrue(TypeGuard.IsString(T.anyOf[0]))
Assert.IsTrue(TypeGuard.IsBoolean(T.anyOf[1]))
@@ -447,14 +457,14 @@ describe('Zod', () => {
// Unknown
// ----------------------------------------------------------------
it('Should map Unknown', () => {
const T = Box(z.unknown())
const T = TypeBox(z.unknown())
Assert.IsTrue(TypeGuard.IsUnknown(T))
})
// ----------------------------------------------------------------
// Void
// ----------------------------------------------------------------
it('Should map Void', () => {
const T = Box(z.void())
const T = TypeBox(z.void())
Assert.IsTrue(TypeGuard.IsVoid(T))
})
})

View File

@@ -0,0 +1,426 @@
import { TypeBox, Valibot } from '@sinclair/typemap'
import { TypeGuard } from '@sinclair/typebox'
import { Assert } from './assert'
import * as t from '@sinclair/typebox'
import * as v from 'valibot'
describe('Valibot from TypeBox', () => {
// ----------------------------------------------------------------
// Metadata
// ----------------------------------------------------------------
it('Should map Description', () => {
const T = TypeBox(Valibot(t.Number({ description: 'a number' })))
Assert.IsEqual(T.description, 'a number')
})
it('Should map Title', () => {
const T = TypeBox(Valibot(t.Number({ title: 'a number' })))
Assert.IsEqual(T.title, 'a number')
})
it('Should map Metadata', () => {
const T = TypeBox(Valibot(t.Number({ metadata: { x: 1, y: 2 } })))
Assert.IsEqual(T.metadata.x, 1)
Assert.IsEqual(T.metadata.y, 2)
})
// ----------------------------------------------------------------
// Any
// ----------------------------------------------------------------
it('Should map Any', () => {
const T = TypeBox(Valibot(t.Any()))
Assert.IsTrue(TypeGuard.IsAny(T))
})
// ----------------------------------------------------------------
// Array
// ----------------------------------------------------------------
it('Should map Array', () => {
const T = TypeBox(Valibot(t.Array(t.Number())))
Assert.IsTrue(TypeGuard.IsArray(T))
Assert.IsTrue(TypeGuard.IsNumber(T.items))
})
// ----------------------------------------------------------------
// BigInt
// ----------------------------------------------------------------
it('Should map BigInt', () => {
const T = TypeBox(Valibot(t.BigInt()))
Assert.IsTrue(TypeGuard.IsBigInt(T))
})
// ----------------------------------------------------------------
// Date
// ----------------------------------------------------------------
it('Should map Date', () => {
const T = TypeBox(Valibot(t.Date()))
Assert.IsTrue(TypeGuard.IsDate(T))
})
// ----------------------------------------------------------------
// Effects
// ----------------------------------------------------------------
// it('Should map Effects (Transform)', () => {
// const T = TypeBox(v.number().transform(x => x))
// Assert.IsTrue(TypeGuard.IsNumber(T))
// Assert.IsTrue(TypeGuard.IsTransform(T))
// })
// it('Should map Effects (Refine)', () => {
// const T = TypeBox(v.number().refine(x => true))
// Assert.IsTrue(TypeGuard.IsNumber(T))
// Assert.IsTrue(TypeGuard.IsTransform(T))
// })
// ----------------------------------------------------------------
// Literal
// ----------------------------------------------------------------
it('Should map Literal (Number)', () => {
const T = TypeBox(Valibot(t.Literal(42)))
Assert.IsTrue(TypeGuard.IsLiteral(T))
Assert.IsEqual(T.const, 42)
})
it('Should map Literal (String)', () => {
const T = TypeBox(Valibot(t.Literal('hello')))
Assert.IsTrue(TypeGuard.IsLiteral(T))
Assert.IsEqual(T.const, 'hello')
})
it('Should map Literal (Boolean)', () => {
const T = TypeBox(Valibot(t.Literal(true)))
Assert.IsTrue(TypeGuard.IsLiteral(T))
Assert.IsEqual(T.const, true)
})
// ----------------------------------------------------------------
// Nullable
// ----------------------------------------------------------------
it('Should map Nullable', () => {
const T = TypeBox(Valibot(t.Union([t.Null(), t.Number()])))
Assert.IsTrue(TypeGuard.IsUnion(T))
Assert.IsTrue(TypeGuard.IsNull(T.anyOf[0]))
Assert.IsTrue(TypeGuard.IsNumber(T.anyOf[1]))
})
// ----------------------------------------------------------------
// Object
// ----------------------------------------------------------------
it('Should map Object', () => {
const T = TypeBox(
Valibot(
t.Object({
x: t.Number(),
y: t.String(),
}),
),
)
Assert.IsTrue(TypeGuard.IsObject(T))
Assert.IsTrue(TypeGuard.IsNumber(T.properties.x))
Assert.IsTrue(TypeGuard.IsString(T.properties.y))
})
it('Should map Object (Strict)', () => {
const T = TypeBox(
Valibot(
t.Object(
{
x: t.Number(),
y: t.String(),
},
{ additionalProperties: false },
),
),
)
Assert.IsTrue(TypeGuard.IsObject(T))
Assert.IsTrue(TypeGuard.IsNumber(T.properties.x))
Assert.IsTrue(TypeGuard.IsString(T.properties.y))
Assert.IsEqual(T.additionalProperties, false)
})
// ----------------------------------------------------------------
// Optional
// ----------------------------------------------------------------
it('Should map Optional', () => {
const T = TypeBox(
Valibot(
t.Object({
x: t.Optional(t.Number()),
y: t.Optional(t.Number()),
}),
),
)
Assert.IsTrue(TypeGuard.IsObject(T))
Assert.IsTrue(TypeGuard.IsNumber(T.properties.x))
Assert.IsTrue(TypeGuard.IsOptional(T.properties.x))
Assert.IsTrue(TypeGuard.IsNumber(T.properties.y))
Assert.IsTrue(TypeGuard.IsOptional(T.properties.y))
})
it('Should map Optional (Partial)', () => {
const T = TypeBox(
Valibot(
t.Partial(
t.Object({
x: t.Optional(t.Number()),
y: t.Optional(t.Number()),
}),
),
),
)
Assert.IsTrue(TypeGuard.IsObject(T))
Assert.IsTrue(TypeGuard.IsNumber(T.properties.x))
Assert.IsTrue(TypeGuard.IsOptional(T.properties.x))
Assert.IsTrue(TypeGuard.IsNumber(T.properties.y))
Assert.IsTrue(TypeGuard.IsOptional(T.properties.y))
})
// ----------------------------------------------------------------
// Promise
// ----------------------------------------------------------------
it('Should map Promise', () => {
const T = TypeBox(Valibot(t.Promise(t.String())))
Assert.IsEqual(T[t.Kind], 'ValibotPromise')
})
// ----------------------------------------------------------------
// Record
// ----------------------------------------------------------------
it('Should map Record (String Key)', () => {
const T = TypeBox(Valibot(t.Record(t.String(), t.Number())))
Assert.IsTrue(TypeGuard.IsRecord(T))
Assert.IsTrue(TypeGuard.IsNumber(T.patternProperties[t.PatternStringExact]))
})
it('Should map Record (Finite Union)', () => {
const T = TypeBox(Valibot(t.Record(t.Union([t.Literal('x'), t.Literal('y')]), t.Number())))
Assert.IsTrue(TypeGuard.IsObject(T))
Assert.IsTrue(TypeGuard.IsNumber(T.properties.x))
Assert.IsTrue(TypeGuard.IsNumber(T.properties.y))
})
// ----------------------------------------------------------------
// Never
// ----------------------------------------------------------------
it('Should map Never', () => {
const T = TypeBox(Valibot(t.Never()))
Assert.IsTrue(TypeGuard.IsNever(T))
})
// ----------------------------------------------------------------
// Null
// ----------------------------------------------------------------
it('Should map Null', () => {
const T = TypeBox(Valibot(t.Null()))
Assert.IsTrue(TypeGuard.IsNull(T))
})
// ----------------------------------------------------------------
// Number
// ----------------------------------------------------------------
it('Should map Number', () => {
const T = TypeBox(Valibot(t.Number()))
Assert.IsTrue(TypeGuard.IsNumber(T))
})
it('Should map Number (Integer)', () => {
const T = TypeBox(Valibot(t.Integer())) // remap as Number + Modulo
Assert.IsTrue(TypeGuard.IsNumber(T))
Assert.IsEqual(T.multipleOf, 1)
})
it('Should map Number (Minimum)', () => {
const T = TypeBox(Valibot(t.Number({ minimum: 100 })))
Assert.IsTrue(TypeGuard.IsNumber(T))
Assert.IsEqual(T.minimum, 100)
})
it('Should map Number (Maximum)', () => {
const T = TypeBox(Valibot(t.Number({ maximum: 100 })))
Assert.IsTrue(TypeGuard.IsNumber(T))
Assert.IsEqual(T.maximum, 100)
})
// ----------------------------------------------------------------
// String
// ----------------------------------------------------------------
it('Should map String', () => {
const T = TypeBox(Valibot(t.String()))
Assert.IsTrue(TypeGuard.IsString(T))
})
it('Should map String (Base64)', () => {
const T = TypeBox(Valibot(t.String({ format: 'base64' })))
Assert.IsTrue(TypeGuard.IsString(T))
Assert.IsEqual(T.format, 'base64')
})
it('Should map String (Bic)', () => {
const T = TypeBox(Valibot(t.String({ format: 'bic' })))
Assert.IsTrue(TypeGuard.IsString(T))
Assert.IsEqual(T.format, 'bic')
})
it('Should map String (CreditCard)', () => {
const T = TypeBox(Valibot(t.String({ format: 'credit_card' })))
Assert.IsTrue(TypeGuard.IsString(T))
Assert.IsEqual(T.format, 'credit_card')
})
it('Should map String (Cuid2)', () => {
const T = TypeBox(Valibot(t.String({ format: 'cuid2' })))
Assert.IsTrue(TypeGuard.IsString(T))
Assert.IsEqual(T.format, 'cuid2')
})
it('Should map String (Decimal)', () => {
const T = TypeBox(Valibot(t.String({ format: 'decimal' })))
Assert.IsTrue(TypeGuard.IsString(T))
Assert.IsEqual(T.format, 'decimal')
})
it('Should map String (Digits)', () => {
const T = TypeBox(Valibot(t.String({ format: 'digits' })))
Assert.IsTrue(TypeGuard.IsString(T))
Assert.IsEqual(T.format, 'digits')
})
it('Should map String (Email)', () => {
const T = TypeBox(Valibot(t.String({ format: 'email' })))
Assert.IsTrue(TypeGuard.IsString(T))
Assert.IsEqual(T.format, 'email')
})
it('Should map String (Emoji)', () => {
const T = TypeBox(Valibot(t.String({ format: 'emoji' })))
Assert.IsTrue(TypeGuard.IsString(T))
Assert.IsEqual(T.format, 'emoji')
})
it('Should map String (EndsWith)', () => {
const T = TypeBox(Valibot(t.String({ pattern: 'hello$' })))
Assert.IsTrue(TypeGuard.IsString(T))
Assert.IsEqual(T.pattern, 'hello$')
})
it('Should map String (Includes)', () => {
const T = TypeBox(Valibot(t.String({ pattern: 'hello' })))
Assert.IsTrue(TypeGuard.IsString(T))
Assert.IsEqual(T.pattern, 'hello')
})
it('Should map String (Ipv4)', () => {
const T = TypeBox(Valibot(t.String({ format: 'ipv4' })))
Assert.IsTrue(TypeGuard.IsString(T))
Assert.IsEqual(T.format, 'ipv4')
})
it('Should map String (IpV6)', () => {
const T = TypeBox(Valibot(t.String({ format: 'ipv6' })))
Assert.IsTrue(TypeGuard.IsString(T))
Assert.IsEqual(T.format, 'ipv6')
})
it('Should map String (Ip)', () => {
const T = TypeBox(Valibot(t.String({ format: 'ip' })))
Assert.IsTrue(TypeGuard.IsString(T))
Assert.IsEqual(T.format, 'ip')
})
it('Should map String (IsoDate)', () => {
const T = TypeBox(Valibot(t.String({ format: 'iso_date' })))
Assert.IsTrue(TypeGuard.IsString(T))
Assert.IsEqual(T.format, 'iso_date')
})
it('Should map String (IsoDateTime)', () => {
const T = TypeBox(Valibot(t.String({ format: 'iso_date_time' })))
Assert.IsTrue(TypeGuard.IsString(T))
Assert.IsEqual(T.format, 'iso_date_time')
})
it('Should map String (IsoTime)', () => {
const T = TypeBox(Valibot(t.String({ format: 'iso_time' })))
Assert.IsTrue(TypeGuard.IsString(T))
Assert.IsEqual(T.format, 'iso_time')
})
it('Should map String (IsoTimeSecond)', () => {
const T = TypeBox(Valibot(t.String({ format: 'iso_time_second' })))
Assert.IsTrue(TypeGuard.IsString(T))
Assert.IsEqual(T.format, 'iso_time_second')
})
it('Should map String (IsoTimestamp)', () => {
const T = TypeBox(Valibot(t.String({ format: 'iso_timestamp' })))
Assert.IsTrue(TypeGuard.IsString(T))
Assert.IsEqual(T.format, 'iso_timestamp')
})
it('Should map String (IsoWeek)', () => {
const T = TypeBox(Valibot(t.String({ format: 'iso_week' })))
Assert.IsTrue(TypeGuard.IsString(T))
Assert.IsEqual(T.format, 'iso_week')
})
it('Should map String (Mac48)', () => {
const T = TypeBox(Valibot(t.String({ format: 'mac48' })))
Assert.IsTrue(TypeGuard.IsString(T))
Assert.IsEqual(T.format, 'mac48')
})
it('Should map String (Mac64)', () => {
const T = TypeBox(Valibot(t.String({ format: 'mac64' })))
Assert.IsTrue(TypeGuard.IsString(T))
Assert.IsEqual(T.format, 'mac64')
})
it('Should map String (Mac)', () => {
const T = TypeBox(Valibot(t.String({ format: 'mac' })))
Assert.IsTrue(TypeGuard.IsString(T))
Assert.IsEqual(T.format, 'mac')
})
it('Should map String (MaxLength)', () => {
const T = TypeBox(Valibot(t.String({ maxLength: 100 })))
Assert.IsTrue(TypeGuard.IsString(T))
Assert.IsEqual(T.maxLength, 100)
})
it('Should map String (MinLength)', () => {
const T = TypeBox(Valibot(t.String({ minLength: 100 })))
Assert.IsTrue(TypeGuard.IsString(T))
Assert.IsEqual(T.minLength, 100)
})
it('Should map String (Nanoid)', () => {
const T = TypeBox(Valibot(t.String({ format: 'nanoid' })))
Assert.IsTrue(TypeGuard.IsString(T))
Assert.IsEqual(T.format, 'nanoid')
})
it('Should map String (Octal)', () => {
const T = TypeBox(Valibot(t.String({ format: 'octal' })))
Assert.IsTrue(TypeGuard.IsString(T))
Assert.IsEqual(T.format, 'octal')
})
it('Should map String (RegExp)', () => {
const T = TypeBox(Valibot(t.RegExp(/abc/)))
Assert.IsTrue(TypeGuard.IsString(T))
Assert.IsEqual(T.pattern, 'abc')
})
it('Should map String (StartsWith)', () => {
const T = TypeBox(Valibot(t.String({ pattern: '^hello' })))
Assert.IsTrue(TypeGuard.IsString(T))
Assert.IsEqual(T.pattern, '^hello')
})
it('Should map String (Ulid)', () => {
const T = TypeBox(Valibot(t.String({ format: 'ulid' })))
Assert.IsTrue(TypeGuard.IsString(T))
Assert.IsEqual(T.format, 'ulid')
})
it('Should map String (Url)', () => {
const T = TypeBox(Valibot(t.String({ format: 'url' })))
Assert.IsTrue(TypeGuard.IsString(T))
Assert.IsEqual(T.format, 'url')
})
it('Should map String (Uuid)', () => {
const T = TypeBox(Valibot(t.String({ format: 'uuid' })))
Assert.IsTrue(TypeGuard.IsString(T))
Assert.IsEqual(T.format, 'uuid')
})
// ----------------------------------------------------------------
// Symbol
// ----------------------------------------------------------------
it('Should map Symbol', () => {
const T = TypeBox(Valibot(t.Symbol()))
Assert.IsTrue(TypeGuard.IsSymbol(T))
})
// ----------------------------------------------------------------
// Tuple
// ----------------------------------------------------------------
it('Should map Tuple', () => {
const T = TypeBox(Valibot(t.Tuple([t.Number(), t.String()])))
Assert.IsTrue(TypeGuard.IsTuple(T))
Assert.IsTrue(TypeGuard.IsNumber(T.items![0]))
Assert.IsTrue(TypeGuard.IsString(T.items![1]))
})
// ----------------------------------------------------------------
// Undefined
// ----------------------------------------------------------------
it('Should map Undefined', () => {
const T = TypeBox(Valibot(t.Undefined()))
Assert.IsTrue(TypeGuard.IsUndefined(T))
})
// ----------------------------------------------------------------
// Union
// ----------------------------------------------------------------
it('Should map Union', () => {
const T = TypeBox(Valibot(t.Union([t.String(), t.Boolean()])))
Assert.IsTrue(TypeGuard.IsUnion(T))
Assert.IsTrue(TypeGuard.IsString(T.anyOf[0]))
Assert.IsTrue(TypeGuard.IsBoolean(T.anyOf[1]))
})
// ----------------------------------------------------------------
// Unknown
// ----------------------------------------------------------------
it('Should map Unknown', () => {
const T = TypeBox(Valibot(t.Unknown()))
Assert.IsTrue(TypeGuard.IsUnknown(T))
})
// ----------------------------------------------------------------
// Void
// ----------------------------------------------------------------
it('Should map Void', () => {
const T = TypeBox(Valibot(t.Void()))
Assert.IsTrue(TypeGuard.IsVoid(T))
})
})

429
test/zod-from-typebox.ts Normal file
View File

@@ -0,0 +1,429 @@
import { TypeBox, Zod } from '@sinclair/typemap'
import { TypeGuard } from '@sinclair/typebox'
import { Assert } from './assert'
import * as t from '@sinclair/typebox'
import * as z from 'zod'
describe('Zod From TypeBox', () => {
// ----------------------------------------------------------------
// Metadata
// ----------------------------------------------------------------
it('Should map Description', () => {
const T = TypeBox(Zod(t.Number({ description: 'a number' })))
Assert.IsEqual(T.description, 'a number')
})
it('Should map Default', () => {
const T = TypeBox(Zod(t.Number({ default: 12345 })))
Assert.IsEqual(T.default, 12345)
})
// ----------------------------------------------------------------
// Any
// ----------------------------------------------------------------
it('Should map Any', () => {
const T = TypeBox(Zod(t.Any()))
Assert.IsTrue(TypeGuard.IsAny(T))
})
// ----------------------------------------------------------------
// Array
// ----------------------------------------------------------------
it('Should map Array', () => {
const T = TypeBox(Zod(t.Array(t.Number())))
Assert.IsTrue(TypeGuard.IsArray(T))
Assert.IsTrue(TypeGuard.IsNumber(T.items))
})
// ----------------------------------------------------------------
// BigInt
// ----------------------------------------------------------------
it('Should map BigInt', () => {
const T = TypeBox(Zod(t.BigInt()))
Assert.IsTrue(TypeGuard.IsBigInt(T))
})
// ----------------------------------------------------------------
// Date
// ----------------------------------------------------------------
it('Should map Date', () => {
const T = TypeBox(Zod(t.Date()))
Assert.IsTrue(TypeGuard.IsDate(T))
})
// ----------------------------------------------------------------
// Effects
// ----------------------------------------------------------------
// it('Should map Effects (Transform)', () => {
// const T = TypeBox(z.number().transform((x) => x))
// Assert.IsTrue(TypeGuard.IsNumber(T))
// Assert.IsTrue(TypeGuard.IsTransform(T))
// })
// it('Should map Effects (Refine)', () => {
// const T = TypeBox(z.number().refine((x) => true))
// Assert.IsTrue(TypeGuard.IsNumber(T))
// Assert.IsTrue(TypeGuard.IsTransform(T))
// })
// ----------------------------------------------------------------
// Literal
// ----------------------------------------------------------------
it('Should map Literal (Number)', () => {
const T = TypeBox(Zod(t.Literal(42)))
Assert.IsTrue(TypeGuard.IsLiteral(T))
Assert.IsEqual(T.const, 42)
})
it('Should map Literal (String)', () => {
const T = TypeBox(Zod(t.Literal('hello')))
Assert.IsTrue(TypeGuard.IsLiteral(T))
Assert.IsEqual(T.const, 'hello')
})
it('Should map Literal (Boolean)', () => {
const T = TypeBox(Zod(t.Literal(true)))
Assert.IsTrue(TypeGuard.IsLiteral(T))
Assert.IsEqual(T.const, true)
})
// ----------------------------------------------------------------
// Object
// ----------------------------------------------------------------
it('Should map Object', () => {
const T = TypeBox(
Zod(
t.Object({
x: t.Number(),
y: t.String(),
}),
),
)
Assert.IsTrue(TypeGuard.IsObject(T))
Assert.IsTrue(TypeGuard.IsNumber(T.properties.x))
Assert.IsTrue(TypeGuard.IsString(T.properties.y))
})
it('Should map Object (Strict)', () => {
const T = TypeBox(
Zod(
t.Object(
{
x: t.Number(),
y: t.String(),
},
{ additionalProperties: false },
),
),
)
Assert.IsTrue(TypeGuard.IsObject(T))
Assert.IsTrue(TypeGuard.IsNumber(T.properties.x))
Assert.IsTrue(TypeGuard.IsString(T.properties.y))
Assert.IsEqual(T.additionalProperties, false)
})
// ----------------------------------------------------------------
// Optional
// ----------------------------------------------------------------
it('Should map Optional', () => {
const T = TypeBox(
Zod(
t.Object({
x: t.Optional(t.Number()),
y: t.Optional(t.Number()),
}),
),
)
Assert.IsTrue(TypeGuard.IsObject(T))
Assert.IsTrue(TypeGuard.IsNumber(T.properties.x))
Assert.IsTrue(TypeGuard.IsOptional(T.properties.x))
Assert.IsTrue(TypeGuard.IsNumber(T.properties.y))
Assert.IsTrue(TypeGuard.IsOptional(T.properties.y))
})
it('Should map Optional (Readonly)', () => {
const T = TypeBox(
Zod(
t.Object({
x: t.ReadonlyOptional(t.Number()),
y: t.ReadonlyOptional(t.Number()),
}),
),
)
Assert.IsTrue(TypeGuard.IsObject(T))
Assert.IsTrue(TypeGuard.IsNumber(T.properties.x))
Assert.IsTrue(TypeGuard.IsOptional(T.properties.x))
Assert.IsFalse(TypeGuard.IsReadonly(T.properties.x)) // Cannot Map for Readonly in Zod
Assert.IsTrue(TypeGuard.IsNumber(T.properties.y))
Assert.IsTrue(TypeGuard.IsOptional(T.properties.y))
Assert.IsFalse(TypeGuard.IsReadonly(T.properties.y)) // Cannot Map for Readonly in Zod
})
it('Should map Optional (Partial)', () => {
const T = TypeBox(
Zod(
t.Partial(
t.Object({
x: t.Number(),
y: t.Number(),
}),
),
),
)
Assert.IsTrue(TypeGuard.IsObject(T))
Assert.IsTrue(TypeGuard.IsNumber(T.properties.x))
Assert.IsTrue(TypeGuard.IsOptional(T.properties.x))
Assert.IsTrue(TypeGuard.IsNumber(T.properties.y))
Assert.IsTrue(TypeGuard.IsOptional(T.properties.y))
})
// ----------------------------------------------------------------
// Promise
// ----------------------------------------------------------------
it('Should map Promise', () => {
const T = TypeBox(Zod(t.Promise(t.Number())))
Assert.IsTrue(TypeGuard.IsPromise(T))
Assert.IsTrue(TypeGuard.IsNumber(T.item))
})
// ----------------------------------------------------------------
// Readonly
// ----------------------------------------------------------------
it('Should map Readonly', () => {
const T = TypeBox(
Zod(
t.Object({
x: t.Readonly(t.Number()),
y: t.Readonly(t.Number()),
}),
),
)
Assert.IsTrue(TypeGuard.IsObject(T))
Assert.IsTrue(TypeGuard.IsNumber(T.properties.x))
Assert.IsFalse(TypeGuard.IsReadonly(T.properties.x))
Assert.IsTrue(TypeGuard.IsNumber(T.properties.y))
Assert.IsFalse(TypeGuard.IsReadonly(T.properties.y))
})
// ----------------------------------------------------------------
// Record
// ----------------------------------------------------------------
it('Should map Record (Number Key)', () => {
const T = TypeBox(Zod(t.Record(t.Number(), t.Number())))
Assert.IsTrue(TypeGuard.IsRecord(T))
Assert.IsTrue(TypeGuard.IsNumber(T.patternProperties[t.PatternNumberExact]))
})
it('Should map Record (String Key)', () => {
const T = TypeBox(Zod(t.Record(t.String(), t.Number())))
Assert.IsTrue(TypeGuard.IsRecord(T))
Assert.IsTrue(TypeGuard.IsNumber(T.patternProperties[t.PatternStringExact]))
})
it('Should map Record (Finite Union)', () => {
const T = TypeBox(Zod(t.Record(t.Union([t.Literal('x'), t.Literal('y')]), t.Number())))
Assert.IsTrue(TypeGuard.IsObject(T))
Assert.IsTrue(TypeGuard.IsNumber(T.properties.x))
Assert.IsTrue(TypeGuard.IsNumber(T.properties.y))
})
// ----------------------------------------------------------------
// Never
// ----------------------------------------------------------------
it('Should map Never', () => {
const T = TypeBox(Zod(t.Never()))
Assert.IsTrue(TypeGuard.IsNever(T))
})
// ----------------------------------------------------------------
// Null
// ----------------------------------------------------------------
it('Should map Null', () => {
const T = TypeBox(Zod(t.Null()))
Assert.IsTrue(TypeGuard.IsNull(T))
})
// ----------------------------------------------------------------
// Number
// ----------------------------------------------------------------
it('Should map Number', () => {
const T = TypeBox(Zod(t.Number()))
Assert.IsTrue(TypeGuard.IsNumber(T))
})
it('Should map Number (Integer)', () => {
const T = TypeBox(Zod(t.Integer()))
Assert.IsTrue(TypeGuard.IsNumber(T))
Assert.IsEqual(T.multipleOf, 1)
})
it('Should map Number (Minimum)', () => {
const T = TypeBox(Zod(t.Number({ minimum: 100 })))
Assert.IsTrue(TypeGuard.IsNumber(T))
Assert.IsEqual(T.minimum, 100)
})
it('Should map Number (Maximum)', () => {
const T = TypeBox(Zod(t.Number({ maximum: 100 })))
Assert.IsTrue(TypeGuard.IsNumber(T))
Assert.IsEqual(T.maximum, 100)
})
// ----------------------------------------------------------------
// String
// ----------------------------------------------------------------
it('Should map String', () => {
const T = TypeBox(Zod(t.String()))
Assert.IsTrue(TypeGuard.IsString(T))
})
it('Should map String (Base64)', () => {
const T = TypeBox(Zod(t.String({ format: 'base64' })))
Assert.IsTrue(TypeGuard.IsString(T))
Assert.IsEqual(T.format, 'base64')
})
it('Should map String (Base64Url)', () => {
const T = TypeBox(Zod(t.String({ format: 'base64url' })))
Assert.IsTrue(TypeGuard.IsString(T))
Assert.IsEqual(T.format, 'base64url')
})
it('Should map String (Cidr V4)', () => {
const T = TypeBox(Zod(t.String({ format: 'cidrv4' })))
Assert.IsTrue(TypeGuard.IsString(T))
Assert.IsEqual(T.format, 'cidrv4')
})
it('Should map String (Cidr v6)', () => {
const T = TypeBox(Zod(t.String({ format: 'cidrv6' })))
Assert.IsTrue(TypeGuard.IsString(T))
Assert.IsEqual(T.format, 'cidrv6')
})
it('Should map String (Cidr)', () => {
const T = TypeBox(Zod(t.String({ format: 'cidr' })))
Assert.IsTrue(TypeGuard.IsString(T))
Assert.IsEqual(T.format, 'cidr')
})
it('Should map String (Cuid)', () => {
const T = TypeBox(Zod(t.String({ format: 'cuid' })))
Assert.IsTrue(TypeGuard.IsString(T))
Assert.IsEqual(T.format, 'cuid')
})
it('Should map String (Cuid2)', () => {
const T = TypeBox(Zod(t.String({ format: 'cuid2' })))
Assert.IsTrue(TypeGuard.IsString(T))
Assert.IsEqual(T.format, 'cuid2')
})
it('Should map String (Ulid)', () => {
const T = TypeBox(Zod(t.String({ format: 'ulid' })))
Assert.IsTrue(TypeGuard.IsString(T))
Assert.IsEqual(T.format, 'ulid')
})
it('Should map String (Email)', () => {
const T = TypeBox(Zod(t.String({ format: 'email' })))
Assert.IsTrue(TypeGuard.IsString(T))
Assert.IsEqual(T.format, 'email')
})
it('Should map String (Emoji)', () => {
const T = TypeBox(Zod(t.String({ format: 'emoji' })))
Assert.IsTrue(TypeGuard.IsString(T))
Assert.IsEqual(T.format, 'emoji')
})
it('Should map String (EndsWith)', () => {
const T = TypeBox(Zod(t.String({ pattern: 'hello$' })))
Assert.IsTrue(TypeGuard.IsString(T))
Assert.IsEqual(T.pattern, 'hello$')
})
it('Should map String (Includes)', () => {
const T = TypeBox(Zod(t.String({ pattern: 'hello' })))
Assert.IsTrue(TypeGuard.IsString(T))
Assert.IsEqual(T.pattern, 'hello')
})
it('Should map String (IpV4)', () => {
const T = TypeBox(Zod(t.String({ format: 'ipv4' })))
Assert.IsTrue(TypeGuard.IsString(T))
Assert.IsEqual(T.format, 'ipv4')
})
it('Should map String (IpV6)', () => {
const T = TypeBox(Zod(t.String({ format: 'ipv6' })))
Assert.IsTrue(TypeGuard.IsString(T))
Assert.IsEqual(T.format, 'ipv6')
})
it('Should map String (Ip)', () => {
const T = TypeBox(Zod(t.String({ format: 'ip' })))
Assert.IsTrue(TypeGuard.IsString(T))
Assert.IsEqual(T.format, 'ip')
})
it('Should map String (Jwt)', () => {
const T = TypeBox(Zod(t.String({ format: 'jwt' })))
Assert.IsTrue(TypeGuard.IsString(T))
Assert.IsEqual(T.format, 'jwt')
})
it('Should map String (Length)', () => {
const T = TypeBox(Zod(t.String({ minLength: 100, maxLength: 100 })))
Assert.IsTrue(TypeGuard.IsString(T))
Assert.IsEqual(T.minLength, 100)
Assert.IsEqual(T.maxLength, 100)
})
it('Should map String (Min)', () => {
const T = TypeBox(Zod(t.String({ minLength: 100 })))
Assert.IsTrue(TypeGuard.IsString(T))
Assert.IsEqual(T.minLength, 100)
})
it('Should map String (Max)', () => {
const T = TypeBox(Zod(t.String({ maxLength: 100 })))
Assert.IsTrue(TypeGuard.IsString(T))
Assert.IsEqual(T.maxLength, 100)
})
it('Should map String (Nanoid)', () => {
const T = TypeBox(Zod(t.String({ format: 'nanoid' })))
Assert.IsTrue(TypeGuard.IsString(T))
Assert.IsEqual(T.format, 'nanoid')
})
it('Should map String (RegExp)', () => {
const T = TypeBox(Zod(t.RegExp(/abc/)))
Assert.IsTrue(TypeGuard.IsString(T))
Assert.IsEqual(T.pattern, 'abc')
})
it('Should map String (StartsWith)', () => {
const T = TypeBox(Zod(t.String({ pattern: '^hello' })))
Assert.IsTrue(TypeGuard.IsString(T))
Assert.IsEqual(T.pattern, '^hello')
})
it('Should map String (Time)', () => {
const T = TypeBox(Zod(t.String({ format: 'time' })))
Assert.IsTrue(TypeGuard.IsString(T))
Assert.IsEqual(T.format, 'time')
})
it('Should map String (Ulid)', () => {
const T = TypeBox(Zod(t.String({ format: 'ulid' })))
Assert.IsTrue(TypeGuard.IsString(T))
Assert.IsEqual(T.format, 'ulid')
})
it('Should map String (Url)', () => {
const T = TypeBox(Zod(t.String({ format: 'url' })))
Assert.IsTrue(TypeGuard.IsString(T))
Assert.IsEqual(T.format, 'url')
})
it('Should map String (Uuid)', () => {
const T = TypeBox(Zod(t.String({ format: 'uuid' })))
Assert.IsTrue(TypeGuard.IsString(T))
Assert.IsEqual(T.format, 'uuid')
})
// ----------------------------------------------------------------
// Symbol
// ----------------------------------------------------------------
it('Should map Symbol', () => {
const T = TypeBox(Zod(t.Symbol()))
Assert.IsTrue(TypeGuard.IsSymbol(T))
})
// ----------------------------------------------------------------
// Tuple
// ----------------------------------------------------------------
it('Should map Tuple', () => {
const T = TypeBox(Zod(t.Tuple([t.Number(), t.String()])))
Assert.IsTrue(TypeGuard.IsTuple(T))
Assert.IsTrue(TypeGuard.IsNumber(T.items![0]))
Assert.IsTrue(TypeGuard.IsString(T.items![1]))
})
// ----------------------------------------------------------------
// Undefined
// ----------------------------------------------------------------
it('Should map Undefined', () => {
const T = TypeBox(Zod(t.Undefined()))
Assert.IsTrue(TypeGuard.IsUndefined(T))
})
// ----------------------------------------------------------------
// Union
// ----------------------------------------------------------------
it('Should map Union', () => {
const T = TypeBox(Zod(t.Union([t.String(), t.Boolean()])))
Assert.IsTrue(TypeGuard.IsUnion(T))
Assert.IsTrue(TypeGuard.IsString(T.anyOf[0]))
Assert.IsTrue(TypeGuard.IsBoolean(T.anyOf[1]))
})
// ----------------------------------------------------------------
// Unknown
// ----------------------------------------------------------------
it('Should map Unknown', () => {
const T = TypeBox(Zod(t.Unknown()))
Assert.IsTrue(TypeGuard.IsUnknown(T))
})
// ----------------------------------------------------------------
// Void
// ----------------------------------------------------------------
it('Should map Void', () => {
const T = TypeBox(Zod(t.Void()))
Assert.IsTrue(TypeGuard.IsVoid(T))
})
})

View File

@@ -5,10 +5,7 @@
"moduleResolution": "Node",
"baseUrl": ".",
"paths": {
"@sinclair/typebox-adapter/typebox": ["src/typebox/index.ts"],
"@sinclair/typebox-adapter/valibot": ["src/valibot/index.ts"],
"@sinclair/typebox-adapter/zod": ["src/zod/index.ts"],
"@sinclair/typebox-adapter": ["src/index.ts"]
"@sinclair/typemap": ["src/index.ts"]
}
}
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 816 KiB

BIN
typemap.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 872 KiB