diff options
author | Nathan-SR <144961007+Nathan-SR@users.noreply.github.com> | 2025-05-30 03:30:12 -0400 |
---|---|---|
committer | Nathan-SR <144961007+Nathan-SR@users.noreply.github.com> | 2025-05-30 03:30:12 -0400 |
commit | 29e5bbe68e02fe1d86e960a634d0580c37612254 (patch) | |
tree | e88585946a58feb988e3a3bb45dd2a9a09fea4c3 /src/fields/Types.ts | |
parent | f92a02ec5d676359cb268a35d30e5bf9886199c1 (diff) | |
parent | 49fb76f1c54fb8fc4e76bdcf675719d41bfc36aa (diff) |
Merge branch 'master' into Template-Changes
Diffstat (limited to 'src/fields/Types.ts')
-rw-r--r-- | src/fields/Types.ts | 104 |
1 files changed, 37 insertions, 67 deletions
diff --git a/src/fields/Types.ts b/src/fields/Types.ts index 474882959..ba2e9bb6f 100644 --- a/src/fields/Types.ts +++ b/src/fields/Types.ts @@ -1,5 +1,6 @@ import { DateField } from './DateField'; import { Doc, FieldType, FieldResult, Opt } from './Doc'; +import { InkField } from './InkField'; import { List } from './List'; import { ProxyField } from './Proxy'; import { RefField } from './RefField'; @@ -8,7 +9,7 @@ import { ScriptField } from './ScriptField'; import { AudioField, CsvField, ImageField, PdfField, VideoField, WebField } from './URLField'; // eslint-disable-next-line no-use-before-define -export type ToConstructor<T extends FieldType> = T extends string ? 'string' : T extends number ? 'number' : T extends boolean ? 'boolean' : T extends List<infer U> ? ListSpec<U> : new (...args: any[]) => T; +export type ToConstructor<T extends FieldType> = T extends string ? 'string' : T extends number ? 'number' : T extends boolean ? 'boolean' : T extends List<infer U> ? ListSpec<U> : new (...args: never[]) => T; export type DefaultFieldConstructor<T extends FieldType> = { type: ToConstructor<T>; @@ -17,7 +18,7 @@ export type DefaultFieldConstructor<T extends FieldType> = { // type ListSpec<T extends Field[]> = { List: ToContructor<Head<T>> | ListSpec<Tail<T>> }; export type ListSpec<T extends FieldType> = { List: ToConstructor<T> }; -export type InterfaceValue = ToConstructor<FieldType> | ListSpec<FieldType> | DefaultFieldConstructor<FieldType> | ((doc?: Doc) => any); +export type InterfaceValue = ToConstructor<FieldType> | ListSpec<FieldType> | DefaultFieldConstructor<FieldType> | ((doc?: Doc) => never); export type ToType<T extends InterfaceValue> = T extends 'string' ? string @@ -31,9 +32,9 @@ export type ToType<T extends InterfaceValue> = T extends 'string' // eslint-disable-next-line @typescript-eslint/no-unused-vars T extends DefaultFieldConstructor<infer _U> ? never - : T extends { new (...args: any[]): List<FieldType> } + : T extends { new (...args: never[]): List<FieldType> } ? never - : T extends { new (...args: any[]): infer R } + : T extends { new (...args: never[]): infer R } ? R : T extends (doc?: Doc) => infer R ? R @@ -41,44 +42,40 @@ export type ToType<T extends InterfaceValue> = T extends 'string' export interface Interface { [key: string]: InterfaceValue; - // [key: string]: ToConstructor<Field> | ListSpec<Field[]>; } export type ToInterface<T extends Interface> = { [P in Exclude<keyof T, 'proto'>]: T[P] extends DefaultFieldConstructor<infer F> ? Exclude<FieldResult<F>, undefined> : FieldResult<ToType<T[P]>>; }; -// type ListType<U extends Field[]> = { 0: List<ListType<Tail<U>>>, 1: ToType<Head<U>> }[HasTail<U> extends true ? 0 : 1]; - -export type Head<T extends any[]> = T extends [any, ...any[]] ? T[0] : never; -export type Tail<T extends any[]> = ((...t: T) => any) extends (_: any, ...tail: infer TT) => any ? TT : []; -export type HasTail<T extends any[]> = T extends [] | [any] ? false : true; +export type Head<T extends unknown[]> = T extends [unknown, ...unknown[]] ? T[0] : Interface; +export type Tail<T extends unknown[]> = ((...t: T) => unknown) extends (_: unknown, ...tail: infer TT) => unknown ? TT : []; +export type HasTail<T extends unknown[]> = T extends [] | [unknown] ? false : true; // TODO Allow you to optionally specify default values for schemas, which should then make that field not be partial -export type WithoutRefField<T extends FieldType> = T extends RefField ? never : T; +export type WithoutRefField<T extends FieldType> = T extends RefField ? unknown : T; export type CastCtor = ToConstructor<FieldType> | ListSpec<FieldType>; type WithoutList<T extends FieldType> = T extends List<infer R> ? (R extends RefField ? (R | Promise<R>)[] : R[]) : T; -export function Cast<T extends CastCtor>(field: FieldResult, ctor: T): FieldResult<ToType<T>>; -// eslint-disable-next-line no-redeclare -export function Cast<T extends CastCtor>(field: FieldResult, ctor: T, defaultVal: WithoutList<WithoutRefField<ToType<T>>> | null): WithoutList<ToType<T>>; -// eslint-disable-next-line no-redeclare +export function Cast<T extends CastCtor>(field: FieldResult, ctor: T): FieldResult<ToType<T>> | undefined; +export function Cast<T extends CastCtor>(field: FieldResult, ctor: T, defaultVal: WithoutList<ToType<T>> | null): WithoutList<ToType<T>> | undefined; export function Cast<T extends CastCtor>(field: FieldResult, ctor: T, defaultVal?: ToType<T> | null): FieldResult<ToType<T>> | undefined { if (field instanceof Promise) { - return defaultVal === undefined ? (field.then(f => Cast(f, ctor) as any) as any) : defaultVal === null ? undefined : defaultVal; + return defaultVal === undefined ? (field.then(f => Cast(f, ctor) as ToType<T>) as ToType<T>) : defaultVal === null ? undefined : defaultVal; } if (field !== undefined && !(field instanceof Promise)) { if (typeof ctor === 'string') { - // eslint-disable-next-line valid-typeof if (typeof field === ctor) { return field as ToType<T>; } } else if (typeof ctor === 'object') { if (field instanceof List) { - return field as any; + return field as ToType<T>; } + // eslint-disable-next-line @typescript-eslint/no-explicit-any } else if (field instanceof (ctor as any)) { return field as ToType<T>; + // eslint-disable-next-line @typescript-eslint/no-explicit-any } else if (field instanceof ProxyField && field.value instanceof (ctor as any)) { return field.value as ToType<T>; } @@ -86,63 +83,36 @@ export function Cast<T extends CastCtor>(field: FieldResult, ctor: T, defaultVal return defaultVal === null ? undefined : defaultVal; } -export function toList(doc: Doc | Doc[]) { - return doc instanceof Doc ? [doc] : doc; -} +export function toList(doc: Doc | Doc[]) { return doc instanceof Doc ? [doc] : doc; } // prettier-ignore export function DocCast(field: FieldResult, defaultVal?: Doc) { - const doc = Cast(field, Doc, null); - return doc && !(doc instanceof Promise) ? doc : (defaultVal as Doc); -} - -export function NumCast(field: FieldResult, defaultVal: number | null = 0) { - return Cast(field, 'number', defaultVal); -} - -export function StrCast(field: FieldResult, defaultVal: string | null = '') { - return Cast(field, 'string', defaultVal); -} - -export function BoolCast(field: FieldResult, defaultVal: boolean | null = false) { - return Cast(field, 'boolean', defaultVal); -} -export function DateCast(field: FieldResult) { - return Cast(field, DateField, null); -} -export function RTFCast(field: FieldResult) { - return Cast(field, RichTextField, null); -} - -export function ScriptCast(field: FieldResult, defaultVal: ScriptField | null = null) { - return Cast(field, ScriptField, defaultVal); -} -export function CsvCast(field: FieldResult, defaultVal: CsvField | null = null) { - return Cast(field, CsvField, defaultVal); -} -export function WebCast(field: FieldResult, defaultVal: WebField | null = null) { - return Cast(field, WebField, defaultVal); -} -export function VideoCast(field: FieldResult, defaultVal: VideoField | null = null) { - return Cast(field, VideoField, defaultVal); -} -export function AudioCast(field: FieldResult, defaultVal: AudioField | null = null) { - return Cast(field, AudioField, defaultVal); -} -export function PDFCast(field: FieldResult, defaultVal: PdfField | null = null) { - return Cast(field, PdfField, defaultVal); -} -export function ImageCast(field: FieldResult, defaultVal: ImageField | null = null) { - return Cast(field, ImageField, defaultVal); + return ((doc: Doc | undefined) => (doc && !(doc instanceof Promise) ? doc : defaultVal))(Cast(field, Doc, null)); +} +export function NumCast (field: FieldResult, defaultVal: number | null = 0) { return Cast(field, 'number', defaultVal)!; } // prettier-ignore +export function StrCast (field: FieldResult, defaultVal: string | null = '') { return Cast(field, 'string', defaultVal)!; } // prettier-ignore +export function BoolCast (field: FieldResult, defaultVal: boolean | null = false) { return Cast(field, 'boolean', defaultVal)!; } // prettier-ignore +export function DateCast (field: FieldResult, defaultVal: DateField | null = null) { return Cast(field, DateField, defaultVal); } // prettier-ignore +export function RTFCast (field: FieldResult, defaultVal: RichTextField | null = null){ return Cast(field, RichTextField, defaultVal); } // prettier-ignore +export function ScriptCast(field: FieldResult, defaultVal: ScriptField | null = null) { return Cast(field, ScriptField, defaultVal); } // prettier-ignore +export function CsvCast (field: FieldResult, defaultVal: CsvField | null = null) { return Cast(field, CsvField, defaultVal); } // prettier-ignore +export function WebCast (field: FieldResult, defaultVal: WebField | null = null) { return Cast(field, WebField, defaultVal); } // prettier-ignore +export function VideoCast (field: FieldResult, defaultVal: VideoField | null = null) { return Cast(field, VideoField, defaultVal); } // prettier-ignore +export function AudioCast (field: FieldResult, defaultVal: AudioField | null = null) { return Cast(field, AudioField, defaultVal); } // prettier-ignore +export function PDFCast (field: FieldResult, defaultVal: PdfField | null = null) { return Cast(field, PdfField, defaultVal); } // prettier-ignore +export function ImageCast (field: FieldResult, defaultVal: ImageField | null = null) { return Cast(field, ImageField, defaultVal); } // prettier-ignore +export function InkCast (field: FieldResult, defaultVal: InkField | null = null) { return Cast(field, InkField, defaultVal); } // prettier-ignore + +export function ImageCastToNameType(field: FieldResult, defaultVal: ImageField | null = null) { + const href = ImageCast(field, defaultVal)?.url.href; + return href ? [href.replace(/.[^.]*$/, ''), href.split('.').lastElement()] : ['', '']; } export function ImageCastWithSuffix(field: FieldResult, suffix: string, defaultVal: ImageField | null = null) { - const href = ImageCast(field, defaultVal)?.url.href; - return href ? `${href.split('.')[0]}${suffix}.${href.split('.')[1]}` : null; + const [name, type] = ImageCastToNameType(field, defaultVal); + return name ? `${name}${suffix}.${type}` : null; } export function FieldValue<T extends FieldType, U extends WithoutList<T>>(field: FieldResult<T>, defaultValue: U): WithoutList<T>; -// eslint-disable-next-line no-redeclare export function FieldValue<T extends FieldType>(field: FieldResult<T>): Opt<T>; -// eslint-disable-next-line no-redeclare export function FieldValue<T extends FieldType>(field: FieldResult<T>, defaultValue?: T): Opt<T> { return field instanceof Promise || field === undefined ? defaultValue : field; } |