import { SchemaOptions, Static, StringOptions, TLiteral, TObject, TPropertyKey, TSchema, TUnion, Type } from '@sinclair/typebox/type'; import { AllKeys, Obj, TPartialSome } from './types.js'; export const capitalize = (str: S): Capitalize => { return (str.charAt(0).toUpperCase() + str.slice(1)) as Capitalize; }; export const isObj = (obj: unknown): obj is Obj => obj !== null && typeof obj === 'object'; export type TUnionOfString = T extends [infer L extends string, ...infer R extends string[]] ? TUnionOfString]> : Acc; export const LiteralUnion = (values: [...T], options?: SchemaOptions): TUnion> => { return Type.Union( values.map(value => Type.Literal(value)), options ) as never; }; export const PartialSome = >[]>( schema: T, keys: readonly [...K], options?: SchemaOptions ): TPartialSome => { return Type.Composite([Type.Omit(schema, keys), Type.Partial(Type.Pick(schema, keys))], options); }; // NOTE: Latest version of typebox makes Omit/Pick distributive by default, but loses strongly typed keys export const DistOmit = >[]>(schema: T, keys: readonly [...K], options?: SchemaOptions) => { return Type.Omit(schema, keys, options); }; export const DistPick = >[]>(schema: T, keys: readonly [...K], options?: SchemaOptions) => { return Type.Pick(schema, keys, options); }; export const MaybeArray = (schema: T, options?: SchemaOptions) => Type.Union([schema, Type.Array(schema)], options); export const Nullable = (schema: T, options?: SchemaOptions) => Type.Optional(Type.Union([schema, Type.Null()], options)); /* Current issue with Type.KeyOf() + Generics export const SchemaOverride = (schema: S, overrides: T, options?: ObjectOptions) => { return Type.Composite([Type.Omit(schema, Type.KeyOf(overrides)), overrides], options); }; */ // TODO: figure out a way of building UnionPartialSome without having to explicitly overload // for every tuple length. export function UnionPartialSome>[]>( union: TUnion<[U1]>, keys: readonly [...K] ): TUnion<[TPartialSome]>; export function UnionPartialSome>[]>( union: TUnion<[U1, U2]>, keys: readonly [...K] ): TUnion<[TPartialSome, TPartialSome]>; export function UnionPartialSome>[]>( union: TUnion<[U1, U2, U3]>, keys: readonly [...K] ): TUnion<[TPartialSome, TPartialSome, TPartialSome]>; export function UnionPartialSome< U1 extends TObject, U2 extends TObject, U3 extends TObject, U4 extends TObject, K extends AllKeys>[], >( union: TUnion<[U1, U2, U3, U4]>, keys: readonly [...K] ): TUnion<[TPartialSome, TPartialSome, TPartialSome, TPartialSome]>; export function UnionPartialSome< U1 extends TObject, U2 extends TObject, U3 extends TObject, U4 extends TObject, K extends AllKeys>[], >( union: TUnion<[U1, U2, U3, U4]>, keys: readonly [...K] ): TUnion<[TPartialSome, TPartialSome, TPartialSome, TPartialSome]>; export function UnionPartialSome< U1 extends TObject, U2 extends TObject, U3 extends TObject, U4 extends TObject, U5 extends TObject, K extends AllKeys>[], >( union: TUnion<[U1, U2, U3, U4, U5]>, keys: readonly [...K] ): TUnion<[TPartialSome, TPartialSome, TPartialSome, TPartialSome, TPartialSome]>; export function UnionPartialSome< U1 extends TObject, U2 extends TObject, U3 extends TObject, U4 extends TObject, U5 extends TObject, U6 extends TObject, K extends AllKeys>[], >( union: TUnion<[U1, U2, U3, U4, U5, U6]>, keys: readonly [...K] ): TUnion<[TPartialSome, TPartialSome, TPartialSome, TPartialSome, TPartialSome, TPartialSome]>; export function UnionPartialSome< U1 extends TObject, U2 extends TObject, U3 extends TObject, U4 extends TObject, U5 extends TObject, U6 extends TObject, U7 extends TObject, K extends AllKeys>[], >( union: TUnion<[U1, U2, U3, U4, U5, U6, U7]>, keys: readonly [...K] ): TUnion< [ TPartialSome, TPartialSome, TPartialSome, TPartialSome, TPartialSome, TPartialSome, TPartialSome, ] >; export function UnionPartialSome< U1 extends TObject, U2 extends TObject, U3 extends TObject, U4 extends TObject, U5 extends TObject, U6 extends TObject, U7 extends TObject, U8 extends TObject, K extends AllKeys>[], >( union: TUnion<[U1, U2, U3, U4, U5, U6, U7, U8]>, keys: readonly [...K] ): TUnion< [ TPartialSome, TPartialSome, TPartialSome, TPartialSome, TPartialSome, TPartialSome, TPartialSome, TPartialSome, ] >; export function UnionPartialSome(union: TUnion, keys: readonly [...TPropertyKey[]]): TUnion { return Type.Union(union.anyOf.map(schema => PartialSome(schema, keys))); } export const IsoDate = (options?: StringOptions) => Type.Transform(Type.String({ format: 'date-time', ...options })) .Decode(value => new Date(value)) .Encode(value => value.toISOString());