/*-------------------------------------------------------------------------- @sinclair/typemap The MIT License (MIT) Copyright (c) 2024-2025 Haydn Paterson (sinclair) Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ---------------------------------------------------------------------------*/ import * as t from '@sinclair/typebox' import * as v from 'valibot' import * as Guard from '../guard' // ------------------------------------------------------------------ // Options // ------------------------------------------------------------------ function IsSchemaWithPipe(type: BaseSchema): type is v.SchemaWithPipe<[BaseSchema, ...BaseValidation[]]> { return t.ValueGuard.IsObject(type) && t.ValueGuard.HasPropertyKey(type, 'pipe') && t.ValueGuard.IsArray(type.pipe) } // prettier-ignore function Options(type: BaseSchema) { if (!IsSchemaWithPipe(type)) return {} return type.pipe.slice(1).reduce((options, action: { type: string } & { [key: string]: any }) => { return { ...options, ...( action.type === 'args' ? {} : 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: 'credit_card' } : action.type === 'cuid2' ? { format: 'cuid2' } : action.type === 'decimal' ? { format: 'decimal' } : action.type === 'description' ? { description: action.description } : 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 } : {}) : action.type === 'ends_with' ? { pattern: `${action.requirement}$` } : action.type === 'every_item' ? {} : action.type === 'excludes' ? {} : action.type === 'filter_items' ? {} : action.type === 'find_items' ? {} : action.type === 'finite' ? {} : action.type === 'graphemes' ? {} : action.type === 'hash' ? {} : action.type === 'hexadecimal' ? {} : action.type === 'hex_color' ? {} : action.type === 'imei' ? {} : action.type === 'includes' ? ( type.type === 'array' ? { contains: t.Literal(action.requirement) } : type.type === 'string' ? { pattern: action.requirement } : {}) : action.type === 'integer' ? { multipleOf: 1 } : 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: 'mac' } : action.type === 'mac48' ? { format: 'mac48' } : action.type === 'mac64' ? { format: 'mac64' } : action.type === 'map_items' ? {} : action.type === 'max_bytes' ? {} : action.type === 'max_graphemes' ? {} : action.type === 'max_length' ? ( type.type === 'string' ? { maxLength: action.requirement } : type.type === 'array' ? { maxItems: action.requirement } : {}) : action.type === 'max_size' ? {} : action.type === 'max_value' ? { maximum: action.requirement } : action.type === 'max_words' ? {} : action.type === 'metadata' ? { metadata: action.metadata } : action.type === 'mime_type' ? {} : action.type === 'min_bytes' ? {} : action.type === 'min_graphemes' ? {} : action.type === 'min_length' ? ( type.type === 'string' ? { minLength: action.requirement } : type.type === 'array' ? { minItems: action.requirement } : {}) : action.type === 'min_size' ? {} : action.type === 'min_value' ? { minimum: action.requirement } : action.type === 'min_words' ? {} : action.type === 'multiple_of' ? { multipleOf: action.requirement } : action.type === 'nanoid' ? { format: 'nanoid' } : action.type === 'non_empty' ? {} : action.type === 'normalize' ? {} : action.type === 'not_bytes' ? {} : action.type === 'not_graphemes' ? {} : action.type === 'not_length' ? {} : // needs TNot action.type === 'not_size' ? {} : action.type === 'not_value' ? {} : action.type === 'not_words' ? {} : action.type === 'octal' ? { format: 'octal' } : action.type === 'partial_check' ? {} : action.type === 'raw_check' ? {} : action.type === 'raw_transform' ? {} : action.type === 'readonly' ? {} : action.type === 'reduce_items' ? {} : action.type === 'regex' ? { pattern: action.requirement.source } : action.type === 'returns' ? {} : action.type === 'safe_integer' ? { multipleOf: 1 } : action.type === 'size' ? {} : action.type === 'some_item' ? {} : action.type === 'sort_items' ? {} : action.type === 'starts_with' ? { pattern: `^${action.requirement}` } : action.type === 'title' ? { title: action.title } : action.type === 'to_lower_case' ? {} : action.type === 'to_max_value' ? {} : action.type === 'to_min_value' ? {} : action.type === 'to_upper_case' ? {} : action.type === 'transform' ? {} : action.type === 'trim' ? {} : action.type === 'trim_end' ? {} : action.type === 'trim_start' ? {} : action.type === 'ulid' ? { format: 'ulid' } : action.type === 'url' ? { format: 'url' } : action.type === 'uuid' ? { format: 'uuid' } : action.type === 'value' ? {} : action.type === 'words' ? {} : {}) } }, {}) } // ------------------------------------------------------------------ // Formats // ------------------------------------------------------------------ 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 // ------------------------------------------------------------------ type BaseValidation = v.BaseValidation> type BaseSchema = v.BaseSchema> type BaseRecordKey = v.BaseSchema> // ------------------------------------------------------------------ // Any // ------------------------------------------------------------------ type TFromAny<_Type extends v.AnySchema> = t.Ensure function FromAny(type: BaseSchema): t.TSchema { return t.Any(Options(type)) } // ------------------------------------------------------------------ // Array // ------------------------------------------------------------------ type TFromArray = t.Ensure>> function FromArray(type: BaseSchema): t.TSchema { return t.Array(FromType((type as v.ArraySchema).item), Options(type)) } // ------------------------------------------------------------------ // BigInt // ------------------------------------------------------------------ type TFromBigInt<_Type extends v.BigintSchema> = t.Ensure function FromBigInt(type: BaseSchema): t.TSchema { return t.BigInt(Options(type)) } // ------------------------------------------------------------------ // Blob // ------------------------------------------------------------------ t.TypeRegistry.Set('ValibotBlob', (schema, value) => { return v.safeParse(schema.schema, value).success }) interface TBlob = v.BlobSchema> extends t.TSchema { [t.Kind]: 'ValibotBlob' static: v.InferOutput type: Type } function _Blob(type: v.BlobSchema, options?: t.SchemaOptions): TBlob { return t.CreateType({ [t.Kind]: 'ValibotBlob', type }, options) as never } type TFromBlob> = t.Ensure> function FromBlob(type: BaseSchema): t.TSchema { return _Blob(type as v.BlobSchema, Options(type)) } // ------------------------------------------------------------------ // Boolean // ------------------------------------------------------------------ type TFromBoolean<_Type extends v.BooleanSchema> = t.TBoolean function FromBoolean(type: BaseSchema): t.TSchema { return t.Boolean(Options(type)) } // ------------------------------------------------------------------ // Custom // ------------------------------------------------------------------ t.TypeRegistry.Set('ValibotCustom', (schema, value) => v.safeParse(schema.schema, value).success) interface TCustom = v.CustomSchema> extends t.TSchema { [t.Kind]: 'ValibotCustom' static: v.InferOutput type: Type } function Custom>(type: Type, options?: t.SchemaOptions): TCustom { return t.CreateType({ [t.Kind]: 'ValibotCustom', type }, options) as never } type TFromCustom> = t.Ensure> function FromCustom(type: BaseSchema): t.TSchema { return Custom(type as v.CustomSchema, Options(type)) } // ------------------------------------------------------------------ // Date // ------------------------------------------------------------------ type TFromDate<_Type extends v.DateSchema> = t.TDate function FromDate(type: BaseSchema): t.TSchema { return t.Date(Options(type)) } // ------------------------------------------------------------------ // Enum // ------------------------------------------------------------------ t.TypeRegistry.Set('ValibotEnum', (schema, value) => { return v.safeParse(schema.schema, value).success }) export interface TValibotEnum = v.EnumSchema> extends t.TSchema { [t.Kind]: 'ValibotEnum' static: v.InferOutput type: Type } function ValibotEnum>(type: Type, options?: t.SchemaOptions): TValibotEnum { return t.CreateType({ [t.Kind]: 'ValibotEnum', type }, options) as never } type TFromEnum> = TValibotEnum function FromEnum(type: Type): t.TSchema { return ValibotEnum(type as never as v.EnumSchema, Options(type)) } // ------------------------------------------------------------------ // File // ------------------------------------------------------------------ t.TypeRegistry.Set('ValibotFile', (schema, value) => { return v.safeParse(schema.schema, value).success }) export interface TValibotFile = v.FileSchema> extends t.TSchema { [t.Kind]: 'ValibotFile' static: v.InferOutput type: Type } function _File(type: v.FileSchema, options?: t.SchemaOptions): TValibotFile { return t.CreateType({ [t.Kind]: 'ValibotFile', type }, options) as never } type TFromFile> = t.Ensure> function FromFile(type: BaseSchema): t.TSchema { return _File(type as v.FileSchema, Options(type)) } // ------------------------------------------------------------------ // Function // ------------------------------------------------------------------ t.TypeRegistry.Set('ValibotFunction', (schema, value) => { return v.safeParse(schema.schema, value).success }) export interface TValibotFunction = v.FunctionSchema> extends t.TSchema { [t.Kind]: 'ValibotFunction' static: v.InferOutput type: Type } function _Function>(type: Type, options?: t.SchemaOptions): TValibotFunction { return t.CreateType({ [t.Kind]: 'ValibotFunction', type }, options) as never } type TFromFunction> = t.Ensure> function FromFunction(type: BaseSchema): t.TSchema { return _Function(type as v.FunctionSchema, Options(type)) } // ------------------------------------------------------------------ // Instance // ------------------------------------------------------------------ t.TypeRegistry.Set('ValibotInstance', (schema, value) => { return v.safeParse(schema.schema, value).success }) export interface TValibotInstance = v.InstanceSchema> extends t.TSchema { [t.Kind]: 'ValibotInstance' static: v.InferOutput type: Type } function Instance>(type: Type, options?: t.SchemaOptions): TValibotInstance { return t.CreateType({ [t.Kind]: 'ValibotInstance', type }, options) as never } type TFromInstance> = t.Ensure> function FromInstance(type: BaseSchema): t.TSchema { return Instance(type as v.InstanceSchema, Options(type)) } // ------------------------------------------------------------------ // Intersect // ------------------------------------------------------------------ // prettier-ignore type TFromIntersect = ( Type extends [infer Left extends BaseSchema, ...infer Right extends BaseSchema[]] ? TFromIntersect]> : t.TIntersect ) function FromIntersect(type: BaseSchema): t.TSchema { const intersect = type as v.IntersectSchema return t.Intersect( intersect.options.map((option) => FromType(option)), Options(type), ) } // ------------------------------------------------------------------ // Literal // ------------------------------------------------------------------ type TFromLiteral = t.Ensure> function FromLiteral(type: BaseSchema): t.TSchema { const literal = type as v.LiteralSchema return t.Literal(literal.literal, Options(type)) } // ------------------------------------------------------------------ // LooseObject // ------------------------------------------------------------------ type TFromLooseObject = t.Ensure< t.TObject<{ -readonly [Key in keyof Properties]: TFromType }> > function FromLooseObject(type: BaseSchema): t.TSchema { const object = type as v.LooseObjectSchema const keys = globalThis.Object.getOwnPropertyNames(object.entries) return t.Object( keys.reduce((properties, key) => { return { ...properties, [key]: FromType(object.entries[key]) } }, {} as t.TProperties), Options(type), ) } // ------------------------------------------------------------------ // LooseTuple // ------------------------------------------------------------------ t.TypeRegistry.Set('ValibotLooseTuple', (schema, value) => { return v.safeParse(schema.schema, value).success }) export interface TValibotLooseTuple = v.LooseTupleSchema> extends t.TSchema { [t.Kind]: 'ValibotLooseTuple' static: v.InferOutput type: Type } function LooseTuple>(type: Type, schema?: t.SchemaOptions): TValibotLooseTuple { return t.CreateType({ [t.Kind]: 'ValibotLooseTuple', type }) as never } type TFromLooseTuple> = t.Ensure> function FromLooseTuple(type: BaseSchema): t.TSchema { return LooseTuple(type as v.LooseTupleSchema, Options(type)) } // ------------------------------------------------------------------ // Map // ------------------------------------------------------------------ t.TypeRegistry.Set('ValibotMap', (schema, value) => { return v.safeParse(schema.schema, value).success }) export interface TValibotMap = v.MapSchema> extends t.TSchema { [t.Kind]: 'ValibotMap' static: v.InferOutput type: Type } function _Map>(type: Type, options?: t.SchemaOptions): TValibotMap { return t.CreateType({ [t.Kind]: 'ValibotMap', type }) as never } type TFromMap> = t.Ensure> function FromMap(type: BaseSchema): t.TSchema { return _Map(type as v.MapSchema, Options(type)) } // ------------------------------------------------------------------ // NaN // ------------------------------------------------------------------ t.TypeRegistry.Set('ValibotNaN', (schema, value) => { return v.safeParse(schema.schema, value).success }) export interface TValibotNaN = v.NanSchema> extends t.TSchema { [t.Kind]: 'ValibotNaN' static: v.InferOutput type: Type } function _NaN>(type: Type, options?: t.SchemaOptions): TValibotNaN { return t.CreateType({ [t.Kind]: 'ValibotNaN', type }, options) as never } type TFromNaN> = t.Ensure> function FromNaN(type: BaseSchema): t.TSchema { return _NaN(type as v.NanSchema, Options(type)) } // ------------------------------------------------------------------ // Never // ------------------------------------------------------------------ type TFromNever<_Type extends v.NeverSchema> = t.TNever function FromNever(type: BaseSchema): t.TSchema { return t.Never(Options(type)) } // ------------------------------------------------------------------ // NonNullable // ------------------------------------------------------------------ type TFromNonNullable = t.TExclude, t.TNull> function FromNonNullable(type: BaseSchema): t.TSchema { const non_nullable = type as v.NonNullableSchema return t.Exclude(FromType(non_nullable.wrapped), t.Null(), Options(type)) } // ------------------------------------------------------------------ // NonNullish // ------------------------------------------------------------------ type TFromNonNullish = t.TExclude, t.TUnion<[t.TNull, t.TUndefined]>> function FromNonNullish(type: BaseSchema): t.TSchema { const non_nullish = type as v.NonNullishSchema return t.Exclude(FromType(non_nullish.wrapped), t.Union([t.Null(), t.Undefined()]), Options(type)) } // ------------------------------------------------------------------ // NonOptional // ------------------------------------------------------------------ type TFromNonOptional = TFromType> = t.TOptionalWithFlag function FromNonOptional(type: BaseSchema): t.TSchema { const non_optional = type as v.NonOptionalSchema return t.Optional(FromType(non_optional.wrapped), false) } // ------------------------------------------------------------------ // Null // ------------------------------------------------------------------ type TFromNull<_Type extends v.NullSchema> = t.TNull function FromNull(type: BaseSchema) { return t.Null(Options(type)) } // ------------------------------------------------------------------ // Nullable // ------------------------------------------------------------------ type TFromNullable = t.TUnion<[TFromType, t.TNull]> function FromNullable(type: BaseSchema) { const nullable = type as v.NullableSchema return t.Union([t.Null(), FromType(nullable.wrapped)], Options(type)) } // ------------------------------------------------------------------ // Nullish // ------------------------------------------------------------------ type TFromNullish = t.TUnion<[TFromType, t.TNull, t.TUndefined]> function FromNullish(type: BaseSchema) { const nullish = type as v.NullishSchema return t.Union([FromType(nullish.wrapped), t.Null(), t.Undefined()], Options(type)) } // ------------------------------------------------------------------ // Number // ------------------------------------------------------------------ type TFromNumber<_Type extends v.NumberSchema> = t.TNumber function FromNumber(type: BaseSchema): t.TSchema { return t.Number(Options(type)) } // ------------------------------------------------------------------ // Object // ------------------------------------------------------------------ type TFromObject = t.Ensure< t.TObject<{ -readonly [Key in keyof Properties]: TFromType }> > function FromObject(type: BaseSchema): t.TSchema { const object = type as v.ObjectSchema const keys = globalThis.Object.getOwnPropertyNames(object.entries) return t.Object( keys.reduce((properties, key) => { return { ...properties, [key]: FromType(object.entries[key]) } }, {} as t.TProperties), Options(type), ) } // ------------------------------------------------------------------ // ObjectWithRest // ------------------------------------------------------------------ type TFromObjectWithRest = t.Ensure< t.TObject<{ -readonly [Key in keyof Properties]: TFromType }> > function FromObjectWithRest(type: BaseSchema): t.TSchema { const object = type as v.ObjectWithRestSchema const keys = globalThis.Object.getOwnPropertyNames(object.entries) return t.Object( keys.reduce((properties, key) => { return { ...properties, [key]: FromType(object.entries[key]) } }, {} as t.TProperties), { ...Options(type), additionalProperties: FromType(object.rest) }, ) } // ------------------------------------------------------------------ // Optional // ------------------------------------------------------------------ type TFromOptional = TFromType> = t.TOptionalWithFlag function FromOptional(type: BaseSchema): t.TSchema { const optional = type as v.OptionalSchema return t.Optional(FromType(optional.wrapped)) } // ------------------------------------------------------------------ // PickList // ------------------------------------------------------------------ type PickListOption = string | number | bigint // prettier-ignore type TFromPickList = ( Options extends [infer Left extends PickListOption, ...infer Right extends PickListOption[]] ? ( Left extends t.TLiteralValue ? TFromPickList]> : TFromPickList ) : t.TUnion ) function FromPickList(type: BaseSchema): t.TSchema { const picklist = type as v.PicklistSchema return t.Union( picklist.options.map((option) => t.Literal(option as t.TLiteralValue)), Options(type), ) } // ------------------------------------------------------------------ // Promise // ------------------------------------------------------------------ t.TypeRegistry.Set('ValibotPromise', (schema, value) => { return v.safeParse(schema.schema, value).success }) export interface TValibotPromise = v.PromiseSchema> extends t.TSchema { [t.Kind]: 'ValibotPromise' static: v.InferOutput type: Type } function _Promise>(type: Type, options?: t.SchemaOptions): TValibotPromise { return t.CreateType({ [t.Kind]: 'ValibotPromise', type }, options) as never } type TFromPromise> = t.Ensure> function FromPromise(type: BaseSchema): t.TSchema { return _Promise(type as v.PromiseSchema, Options(type)) } // ------------------------------------------------------------------ // Record // ------------------------------------------------------------------ type TFromRecord = t.Ensure, TFromType>> function FromRecord(type: BaseSchema) { const record = type as v.RecordSchema return t.Record(FromType(record.key), FromType(record.value), Options(type)) } // ------------------------------------------------------------------ // Set // ------------------------------------------------------------------ t.TypeRegistry.Set('ValibotSet', (schema, value) => { return v.safeParse(schema.schema, value).success }) export interface TValibotSet = v.SetSchema> extends t.TSchema { [t.Kind]: 'ValibotSet' static: v.InferOutput extends infer Result ? Result : never type: Type } function Set>(type: Type, options?: t.SchemaOptions): TValibotSet { return t.CreateType({ [t.Kind]: 'ValibotSet', type }, options) as never } type TFromSet> = t.Ensure> function FromSet(type: BaseSchema): t.TSchema { return Set(type as v.SetSchema) } // ------------------------------------------------------------------ // StrictObject // ------------------------------------------------------------------ type TFromStrictObject = t.Ensure< t.TObject<{ -readonly [Key in keyof Properties]: TFromType }> > function FromStrictObject(type: BaseSchema): t.TSchema { const object = type as v.StrictObjectSchema const keys = globalThis.Object.getOwnPropertyNames(object.entries) return t.Object( keys.reduce((properties, key) => { return { ...properties, [key]: FromType(object.entries[key]) } }, {} as t.TProperties), { ...Options(type), additionalProperties: false }, ) } // ------------------------------------------------------------------ // StrictTuple // ------------------------------------------------------------------ // prettier-ignore type TFromStrictTuple = ( Type extends [infer Left extends BaseSchema, ...infer Right extends BaseSchema[]] ? TFromTuple]> : t.TTuple ) function FromStrictTuple(type: BaseSchema): t.TSchema { const tuple = type as v.StrictTupleSchema const items = globalThis.Array.isArray(tuple.items) ? tuple.items.map((item) => FromType(item)) : [] return t.Tuple(items, Options(type)) } // ------------------------------------------------------------------ // String // ------------------------------------------------------------------ type TFromString<_Type extends v.StringSchema> = t.TString function FromString(type: BaseSchema): t.TSchema { return t.String(Options(type)) } // ------------------------------------------------------------------ // Symbol // ------------------------------------------------------------------ type TFromSymbol<_Type extends v.SymbolSchema> = t.TSymbol function FromSymbol(type: BaseSchema): t.TSchema { return t.Symbol(Options(type)) } // ------------------------------------------------------------------ // Tuple // ------------------------------------------------------------------ // prettier-ignore type TFromTuple = ( Type extends [infer Left extends BaseSchema, ...infer Right extends BaseSchema[]] ? TFromTuple]> : t.TTuple ) function FromTuple(type: BaseSchema): t.TSchema { const tuple = type as v.TupleSchema const items = globalThis.Array.isArray(tuple.items) ? tuple.items.map((item) => FromType(item)) : [] return t.Tuple(items, Options(type)) } // ------------------------------------------------------------------ // TupleWithRest // ------------------------------------------------------------------ t.TypeRegistry.Set('ValibotTupleWithRest', (schema, value) => { return v.safeParse(schema.schema, value).success }) interface TTupleWithRest = v.TupleWithRestSchema> extends t.TSchema { [t.Kind]: 'ValibotTupleWithRest' static: v.InferOutput type: Type } function TupleWithRest>(type: Type, options?: t.SchemaOptions): TTupleWithRest { return t.CreateType({ [t.Kind]: 'ValibotTupleWithRest', type }, Options(type)) as never } type TFromTupleWithRest> = t.Ensure> function FromTupleWithRest(type: BaseSchema): t.TSchema { return TupleWithRest(type as v.TupleWithRestSchema, Options(type)) } // ------------------------------------------------------------------ // Undefined // ------------------------------------------------------------------ type TFromUndefined<_Type extends v.UndefinedSchema> = t.TUndefined function FromUndefined(type: BaseSchema): t.TSchema { return t.Undefined(Options(type)) } // ------------------------------------------------------------------ // Undefinable // ------------------------------------------------------------------ type TFromUndefinedable = t.TUnion<[TFromType, t.TUndefined]> function FromUndefinedable(type: BaseSchema): t.TSchema { const undefinedable = type as v.UndefinedableSchema return t.Union([FromType(undefinedable.wrapped), t.Undefined()], Options(type)) } // ------------------------------------------------------------------ // Union // ------------------------------------------------------------------ // prettier-ignore type TFromUnion = ( Type extends [infer Left extends BaseSchema, ...infer Right extends BaseSchema[]] ? TFromUnion]> : t.TUnion ) function FromUnion(type: BaseSchema): t.TSchema { const variants = (type as v.UnionSchema).options.map((option) => FromType(option)) return t.Union(variants, Options(type)) } // ------------------------------------------------------------------ // Unknown // ------------------------------------------------------------------ type TFromUnknown<_Type extends v.UnknownSchema> = t.TUnknown function FromUnknown(type: BaseSchema): t.TSchema { return t.Unknown(Options(type)) } // ------------------------------------------------------------------ // Variant // ------------------------------------------------------------------ t.TypeRegistry.Set('ValibotVariant', (schema, value) => { return v.safeParse(schema.schema, value).success }) interface TVariant, any> = v.VariantSchema, any>> extends t.TSchema { [t.Kind]: 'ValibotVariant' static: v.InferOutput type: Type } function Variant, any>>(type: Type): TVariant { return t.CreateType({ [t.Kind]: 'ValibotVariant', type }, Options(type)) as never } type TFromVariant, any>> = t.Ensure> function FromVariant(type: BaseSchema): t.TSchema { return Variant(type as v.VariantSchema, any>) } // ------------------------------------------------------------------ // Void // ------------------------------------------------------------------ type TFromVoid<_Type extends v.VoidSchema> = t.TVoid function FromVoid(type: BaseSchema): t.TSchema { return t.Void(Options(type)) } // ------------------------------------------------------------------ // Type // ------------------------------------------------------------------ // prettier-ignore type TFromType = ( // Pipes - Extract First Type And Remap Type extends { pipe: [infer Type extends BaseSchema, ...any[]] } ? TFromType : // Types Type extends v.AnySchema ? TFromAny : Type extends v.ArraySchema ? TFromArray : Type extends v.BigintSchema ? TFromBigInt : Type extends v.BlobSchema ? TFromBlob : Type extends v.BooleanSchema ? TFromBoolean : Type extends v.CustomSchema ? TFromCustom : Type extends v.DateSchema ? TFromDate : Type extends v.EnumSchema ? TFromEnum : Type extends v.FileSchema ? TFromFile : Type extends v.FunctionSchema ? TFromFunction : Type extends v.InstanceSchema ? TFromInstance : Type extends v.IntersectSchema ? TFromIntersect : Type extends v.LiteralSchema ? TFromLiteral : Type extends v.LooseObjectSchema ? TFromLooseObject : Type extends v.LooseTupleSchema ? TFromLooseTuple : Type extends v.MapSchema ? TFromMap : Type extends v.NanSchema ? TFromNaN : Type extends v.NeverSchema ? TFromNever : Type extends v.NonNullableSchema ? TFromNonNullable : Type extends v.NonNullishSchema ? TFromNonNullish : Type extends v.NonOptionalSchema ? TFromNonOptional : Type extends v.NullSchema ? TFromNull : Type extends v.NullableSchema ? TFromNullable : Type extends v.NullishSchema ? TFromNullish : Type extends v.NumberSchema ? TFromNumber : Type extends v.ObjectSchema ? TFromObject : Type extends v.ObjectWithRestSchema ? TFromObjectWithRest : Type extends v.OptionalSchema ? TFromOptional : Type extends v.PicklistSchema ? TFromPickList : Type extends v.PromiseSchema ? TFromPromise : Type extends v.RecordSchema ? TFromRecord : Type extends v.SetSchema ? TFromSet : Type extends v.StrictObjectSchema ? TFromStrictObject : Type extends v.StrictTupleSchema ? TFromStrictTuple : Type extends v.StringSchema ? TFromString : Type extends v.SymbolSchema ? TFromSymbol : Type extends v.TupleSchema ? TFromTuple : Type extends v.TupleWithRestSchema ? TFromTupleWithRest : Type extends v.UndefinedSchema ? TFromUndefined : Type extends v.UndefinedableSchema ? TFromUndefinedable : Type extends v.UnionSchema ? TFromUnion : Type extends v.UnknownSchema ? TFromUnknown : Type extends v.VariantSchema, any> ? TFromVariant : Type extends v.VoidSchema ? TFromVoid : t.TNever ) // prettier-ignore function FromType(type: Type): TFromType { return ( type.type === 'any' ? FromAny(type) : type.type === 'array' ? FromArray(type) : type.type === 'bigint' ? FromBigInt(type) : type.type === 'blob' ? FromBlob(type) : type.type === 'boolean' ? FromBoolean(type) : type.type === 'custom' ? FromCustom(type) : type.type === 'date' ? FromDate(type) : type.type === 'enum' ? FromEnum(type) : type.type === 'file' ? FromFile(type) : type.type === 'function' ? FromFunction(type) : type.type === 'intersect' ? FromIntersect(type) : type.type === 'instance' ? FromInstance(type) : type.type === 'literal' ? FromLiteral(type) : type.type === 'loose_object' ? FromLooseObject(type) : type.type === 'loose_tuple' ? FromLooseTuple(type) : type.type === 'map' ? FromMap(type) : type.type === 'nan' ? FromNaN(type) : type.type === 'never' ? FromNever(type) : type.type === 'non_nullable' ? FromNonNullable(type) : type.type === 'non_nullish' ? FromNonNullish(type) : type.type === 'non_optional' ? FromNonOptional(type) : type.type === 'null' ? FromNull(type) : type.type === 'nullable' ? FromNullable(type) : type.type === 'nullish' ? FromNullish(type) : type.type === 'number' ? FromNumber(type) : type.type === 'object' ? FromObject(type) : type.type === 'object_with_rest' ? FromObjectWithRest(type) : type.type === 'optional' ? FromOptional(type) : type.type === 'picklist' ? FromPickList(type) : type.type === 'promise' ? FromPromise(type) : type.type === 'record' ? FromRecord(type) : type.type === 'string' ? FromString(type) : type.type === 'set' ? FromSet(type) : type.type === 'strict_object' ? FromStrictObject(type) : type.type === 'strict_tuple' ? FromStrictTuple(type) : type.type === 'symbol' ? FromSymbol(type) : type.type === 'tuple_with_rest' ? FromTupleWithRest(type) : type.type === 'tuple' ? FromTuple(type) : type.type === 'undefined' ? FromUndefined(type) : type.type === 'undefinedable' ? FromUndefinedable(type) : type.type === 'unknown' ? FromUnknown(type) : type.type === 'union' ? FromUnion(type) : type.type === 'variant' ? FromVariant(type) : type.type === 'void' ? FromVoid(type) : t.Never() ) as never } // ------------------------------------------------------------------ // TypeBoxFromValibot // ------------------------------------------------------------------ // prettier-ignore export type TTypeBoxFromValibot, Result extends t.TSchema = TFromType > = Result /** Converts a Valibot Type to a TypeBox Type */ // prettier-ignore export function TypeBoxFromValibot, Result extends TTypeBoxFromValibot = TTypeBoxFromValibot>(type: Type): Result { return (Guard.IsValibot(type) ? FromType(type) : t.Never()) as never }