Revision 0.8.4 (#13)

* Parameterized Types

* Syntax Options

* Documentation
This commit is contained in:
sinclairzx81
2025-01-28 02:39:50 +09:00
committed by GitHub
parent c2991c1972
commit 78dc497ef8
21 changed files with 451 additions and 159 deletions

View File

@@ -29,8 +29,8 @@ THE SOFTWARE.
import { TypeCompiler, TypeCheck, ValueErrorIterator } from '@sinclair/typebox/compiler'
import { Value } from '@sinclair/typebox/value'
import { TypeBox, TTypeBox } from '../typebox/typebox'
import { StandardSchemaV1 } from './standard'
import { IsEvalSupported } from './environment'
import { StandardSchemaV1 } from './standard'
import * as t from '@sinclair/typebox'
// ------------------------------------------------------------------
@@ -112,9 +112,8 @@ function CompileDynamic<Type extends t.TSchema>(type: Type, references: t.TSchem
/** 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
Schema extends t.TSchema = TTypeBox<{}, Type>,
> = Validator<Schema>
/** Compiles a type for high performance validation */
// prettier-ignore
export function Compile<Type extends object | string>(type: Type): TCompile<Type> {

View File

@@ -30,20 +30,14 @@ import * as t from '@sinclair/typebox'
import * as v from 'valibot'
import * as z from 'zod'
// ------------------------------------------------------------------
// Syntax
// ------------------------------------------------------------------
/** Returns true if the given value is a Syntax type */
export type TIsSyntax<Type extends 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
// prettier-ignore
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)
@@ -74,12 +68,44 @@ export function IsValibot(type: unknown): type is v.AnySchema {
// ------------------------------------------------------------------
// Zod
// ------------------------------------------------------------------
// prettier-ignore
/** Returns true if the given value is a Zod type */
// prettier-ignore
export type TIsZod<Type extends unknown> = (
Type extends z.ZodTypeAny ? true : false
)
/** Returns true if the given value is a Zod type */
// prettier-ignore
export function IsZod(type: unknown): type is z.ZodTypeAny {
return t.ValueGuard.IsObject(type) && t.ValueGuard.HasPropertyKey(type, '~standard') && t.ValueGuard.IsObject(type['~standard']) && t.ValueGuard.HasPropertyKey(type['~standard'], 'vendor') && type['~standard'].vendor === 'zod'
return (
t.ValueGuard.IsObject(type) &&
t.ValueGuard.HasPropertyKey(type, '~standard') &&
t.ValueGuard.IsObject(type['~standard']) &&
t.ValueGuard.HasPropertyKey(type['~standard'], 'vendor') &&
type['~standard'].vendor === 'zod'
)
}
// ------------------------------------------------------------------
// Signature
// ------------------------------------------------------------------
function Signature1(args: any[]) {
return args.length === 3 && t.ValueGuard.IsObject(args[0]) && t.ValueGuard.IsString(args[1]) && t.ValueGuard.IsObject(args[2])
}
function Signature2(args: any[]) {
return args.length === 2 && t.ValueGuard.IsString(args[0]) && t.ValueGuard.IsObject(args[1])
}
function Signature3(args: any[]) {
return args.length === 2 && t.ValueGuard.IsObject(args[0]) && t.ValueGuard.IsString(args[1])
}
function Signature4(args: any[]) {
return args.length === 1 && (t.ValueGuard.IsString(args[0]) || t.ValueGuard.IsObject(args[0]))
}
export function Signature(args: any[]): [parameter: Record<PropertyKey, object>, type: string | object, options: object] {
// prettier-ignore
return (
Signature1(args) ? [args[0], args[1], args[2]] :
Signature2(args) ? [{}, args[0], args[1]] :
Signature3(args) ? [args[0], args[1], {}] :
Signature4(args) ? [{}, args[0], {}] :
[{}, 'never', {}]
)
}

View File

@@ -27,6 +27,7 @@ THE SOFTWARE.
---------------------------------------------------------------------------*/
export { type Static } from './static'
export { type TSyntaxOptions } from './options'
export * from './compile/compile'
export * from './typebox/typebox'
export * from './valibot/valibot'

40
src/options.ts Normal file
View File

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

View File

@@ -29,16 +29,18 @@ THE SOFTWARE.
import { StaticParseAsSchema, Parse } from '@sinclair/typebox/syntax'
import * as t from '@sinclair/typebox'
// ------------------------------------------------------------------
// TypeBoxFromSyntax
// ------------------------------------------------------------------
// prettier-ignore
export type TTypeBoxFromSyntax<
Type extends string | object,
Parsed = Type extends string ? StaticParseAsSchema<{}, Type> : t.TNever,
Result extends t.TSchema = Parsed extends t.TSchema ? Parsed : t.TNever
export type TTypeBoxFromSyntax<Context extends t.TProperties, Type extends string | object,
Mapped = Type extends string ? StaticParseAsSchema<Context, Type> : t.TNever,
Result extends t.TSchema = Mapped extends t.TSchema ? Mapped : 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()
/** Creates a TypeBox Type From Syntax */
export function TypeBoxFromSyntax<Context extends t.TProperties, Type extends string>(context: Context, type: Type, options?: t.SchemaOptions): TTypeBoxFromSyntax<Context, Type> {
const parsed = t.ValueGuard.IsString(type) ? Parse(context, type, options) : t.Never()
const result = t.KindGuard.IsSchema(parsed) ? parsed : t.Never()
return result as never
}

View File

@@ -26,39 +26,77 @@ THE SOFTWARE.
---------------------------------------------------------------------------*/
import { TTypeBoxFromSyntax, TypeBoxFromSyntax } from './typebox-from-syntax'
import { TTypeBoxFromTypeBox, TypeBoxFromTypeBox } from './typebox-from-typebox'
import { TTypeBoxFromValibot, TypeBoxFromValibot } from './typebox-from-valibot'
import { TTypeBoxFromZod, TypeBoxFromZod } from './typebox-from-zod'
import * as Guard from '../guard'
import { type TTypeBoxFromSyntax, TypeBoxFromSyntax } from './typebox-from-syntax'
import { type TTypeBoxFromTypeBox, TypeBoxFromTypeBox } from './typebox-from-typebox'
import { type TTypeBoxFromValibot, TypeBoxFromValibot } from './typebox-from-valibot'
import { type TTypeBoxFromZod, TypeBoxFromZod } from './typebox-from-zod'
import { type TSyntaxOptions } from '../options'
import * as g from '../guard'
import * as t from '@sinclair/typebox'
// ------------------------------------------------------------------------------
//
// TParameter: Shared
//
// TypeBox supports Type injection via a Context parameter. Because the Context
// only accepts types of TSchema, we need to an intermediate structure to hold
// remote types such that they can be mapped prior to syntax parsing.
//
// -------------------------------------------------------------------------------
export type TParameter = Record<PropertyKey, object>
// ------------------------------------------------------------------
// ContextFromParameter
// ------------------------------------------------------------------
// prettier-ignore
export type TContextFromParameter<Parameter extends TParameter,
Result extends t.TProperties = {
[Key in keyof Parameter]: TTypeBox<{}, Parameter[Key]>
}
> = Result
// prettier-ignore
export function ContextFromParameter<Parameter extends TParameter>(parameter: Parameter): TContextFromParameter<Parameter> {
return globalThis.Object.getOwnPropertyNames(parameter).reduce((result, key) => {
return { ...result, [key]: TypeBox(parameter[key] as never) }
}, {} as t.TProperties) as never
}
// ------------------------------------------------------------------
// TypeBox
// ------------------------------------------------------------------
/** Creates a TypeBox type from Syntax or another Type */
// prettier-ignore
export type TTypeBox<Type extends object | string, Result = (
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> :
export type TTypeBox<Parameter extends TParameter, Type extends object | string, Result = (
Type extends string ? TTypeBoxFromSyntax<TContextFromParameter<Parameter>, Type> :
g.TIsTypeBox<Type> extends true ? TTypeBoxFromTypeBox<Type> :
g.TIsValibot<Type> extends true ? TTypeBoxFromValibot<Type> :
g.TIsZod<Type> extends true ? TTypeBoxFromZod<Type> :
t.TNever
)> = Result
/** Creates a TypeBox type from Syntax or another Type */
export function TypeBox<Parameter extends TParameter, Type extends string>(parameter: Parameter, type: Type, options?: TSyntaxOptions): TTypeBox<Parameter, Type>
/** Creates a TypeBox type from Syntax or another Type */
export function TypeBox<Type extends object | string>(type: Type, options?: TSyntaxOptions): TTypeBox<{}, Type>
/** 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
export function TypeBox(...args: any[]): never {
const [parameter, type, options] = g.Signature(args)
return t.CloneType(
t.ValueGuard.IsString(type) ? TypeBoxFromSyntax(ContextFromParameter(parameter), type, options) :
g.IsTypeBox(type) ? TypeBoxFromTypeBox(type) :
g.IsValibot(type) ? TypeBoxFromValibot(type) :
g.IsZod(type) ? TypeBoxFromZod(type) :
t.Never(),
options) as never
}
/**
* Creates a TypeBox type from Syntax or another Type
* @deprecated Use TypeBox() export instead
*/
export function Box<Type extends object | string, Mapped = TTypeBox<Type>, Result extends Mapped = Mapped>(type: Type): Result {
return TypeBox(type) as never
}
/** Creates a TypeBox type from Syntax or another Type */
export function Type<Parameter extends TParameter, Type extends string>(parameter: Parameter, type: Type, options?: TSyntaxOptions): TTypeBox<Parameter, Type>
/** Creates a TypeBox type from Syntax or another Type */
export function Type<Type extends object | string>(type: Type, options?: TSyntaxOptions): TTypeBox<{}, Type>
/** Creates a TypeBox type from Syntax or another Type */
// prettier-ignore
export function Type(...args: any[]): never {
return TypeBox.apply(null, args as never) as never
}

View File

@@ -32,15 +32,18 @@ import { ValibotFromTypeBox, TValibotFromTypeBox } from './valibot-from-typebox'
import * as t from '@sinclair/typebox'
import * as c from './common'
// ------------------------------------------------------------------
// ValibotFromSyntax
// ------------------------------------------------------------------
// prettier-ignore
export type TValibotFromSyntax<Type extends object | string,
Schema extends t.TSchema = TTypeBoxFromSyntax<Type>,
export type TValibotFromSyntax<Context extends t.TProperties, Type extends string,
Schema extends t.TSchema = TTypeBoxFromSyntax<Context, 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)
export function ValibotFromSyntax<Context extends t.TProperties, Type extends string>(context: Context, type: Type, options?: t.SchemaOptions): TValibotFromSyntax<Context, Type> {
const schema = TypeBoxFromSyntax(context, type, options)
const result = ValibotFromTypeBox(schema)
return result
return result as never
}

View File

@@ -30,27 +30,42 @@ import { type TValibotFromSyntax, ValibotFromSyntax } from './valibot-from-synta
import { type TValibotFromTypeBox, ValibotFromTypeBox } from './valibot-from-typebox'
import { type TValibotFromValibot, ValibotFromValibot } from './valibot-from-valibot'
import { type TValibotFromZod, ValibotFromZod } from './valibot-from-zod'
import * as Guard from '../guard'
import { type TSyntaxOptions } from '../options'
import * as g from '../guard'
import * as t from '@sinclair/typebox'
import * as v from 'valibot'
import * as c from './common'
import { TParameter, TContextFromParameter, ContextFromParameter } from '../typebox/typebox'
// ------------------------------------------------------------------
// Valibot
// ------------------------------------------------------------------
/** Creates a Valibot type from Syntax or another Type */
// prettier-ignore
export type TValibot<Type extends object | string, Result = (
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> :
export type TValibot<Parameter extends TParameter, Type extends object | string, Result = (
Type extends string ? TValibotFromSyntax<TContextFromParameter<Parameter>, Type> :
g.TIsTypeBox<Type> extends true ? TValibotFromTypeBox<Type> :
g.TIsValibot<Type> extends true ? TValibotFromValibot<Type> :
g.TIsZod<Type> extends true ? TValibotFromZod<Type> :
v.NeverSchema<c.BaseError>
)> = Result
/** Creates a Valibot type from Syntax or another Type */
export function Valibot<Parameter extends TParameter, Type extends string>(parameter: Parameter, type: Type, options?: TSyntaxOptions): TValibot<Parameter, Type>
/** Creates a Valibot type from Syntax or another Type */
export function Valibot<Type extends string>(type: Type, options?: TSyntaxOptions): TValibot<{}, Type>
/** Creates a Valibot type from Syntax or another Type */
export function Valibot<Type extends object>(type: Type, options?: TSyntaxOptions): TValibot<{}, Type>
/** Creates a Valibot type from Syntax or another Type */
// prettier-ignore
export function Valibot<Type extends object | string, Mapped = TValibot<Type>, Result extends Mapped = Mapped>(type: Type): Result {
export function Valibot(...args: any[]): never {
const [parameter, type, options] = g.Signature(args)
return (
Guard.IsSyntax(type) ? ValibotFromSyntax(type) :
Guard.IsTypeBox(type) ? ValibotFromTypeBox(type) :
Guard.IsValibot(type) ? ValibotFromValibot(type) :
Guard.IsZod(type) ? ValibotFromZod(type as any) :
t.ValueGuard.IsString(type) ? ValibotFromSyntax(ContextFromParameter(parameter), type, options) :
g.IsTypeBox(type) ? ValibotFromTypeBox(type) :
g.IsValibot(type) ? ValibotFromValibot(type) :
g.IsZod(type) ? ValibotFromZod(type as any) :
v.never()
) as never
}

View File

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

View File

@@ -30,27 +30,42 @@ import { type TZodFromSyntax, ZodFromSyntax } from './zod-from-syntax'
import { type TZodFromTypeBox, ZodFromTypeBox } from './zod-from-typebox'
import { type TZodFromValibot, ZodFromValibot } from './zod-from-valibot'
import { type TZodFromZod, ZodFromZod } from './zod-from-zod'
import * as Guard from '../guard'
import { type TSyntaxOptions } from '../options'
import * as g from '../guard'
import * as t from '@sinclair/typebox'
import * as z from 'zod'
import { TParameter, TContextFromParameter, ContextFromParameter } from '../typebox/typebox'
// ------------------------------------------------------------------
// Zod
// ------------------------------------------------------------------
/** Creates a Zod type from Syntax or another Type */
// prettier-ignore
export type TZod<Type extends object | string, Result = (
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> :
export type TZod<Parameter extends TParameter, Type extends object | string, Result = (
Type extends string ? TZodFromSyntax<TContextFromParameter<Parameter>, Type> :
g.TIsTypeBox<Type> extends true ? TZodFromTypeBox<Type> :
g.TIsValibot<Type> extends true ? TZodFromValibot<Type> :
g.TIsZod<Type> extends true ? TZodFromZod<Type> :
z.ZodNever
)> = Result
/** Creates a Zod type from Syntax or another Type */
export function Zod<Parameter extends TParameter, Type extends string>(parameter: Parameter, type: Type, options?: TSyntaxOptions): TZod<Parameter, Type>
/** Creates a Zod type from Syntax or another Type */
export function Zod<Type extends string>(type: Type, options?: TSyntaxOptions): TZod<{}, Type>
/** Creates a Zod type from Syntax or another Type */
export function Zod<Type extends object>(type: Type, options?: TSyntaxOptions): TZod<{}, Type>
/** Creates a Zod type from Syntax or another Type */
// prettier-ignore
export function Zod<Type extends object | string, Mapped = TZod<Type>, Result extends Mapped = Mapped>(type: Type): Result {
export function Zod(...args: any[]): never {
const [parameter, type, options] = g.Signature(args)
return (
Guard.IsSyntax(type) ? ZodFromSyntax(type) :
Guard.IsTypeBox(type) ? ZodFromTypeBox(type) :
Guard.IsValibot(type) ? ZodFromValibot(type) :
Guard.IsZod(type) ? ZodFromZod(type) :
t.ValueGuard.IsString(type) ? ZodFromSyntax(ContextFromParameter(parameter), type, options) :
g.IsTypeBox(type) ? ZodFromTypeBox(type) :
g.IsValibot(type) ? ZodFromValibot(type) :
g.IsZod(type) ? ZodFromZod(type) :
z.never()
) as never
}