aboutsummaryrefslogtreecommitdiff
path: root/src/fields/Types.ts
diff options
context:
space:
mode:
authorbobzel <zzzman@gmail.com>2025-05-05 12:37:09 -0400
committerbobzel <zzzman@gmail.com>2025-05-05 12:37:09 -0400
commit3a733aa0fd24517e83649824dec0fc8bcc0bde43 (patch)
treeac01848cdab3b83582c0b7ab6f3d2b1c8187a24f /src/fields/Types.ts
parente058d227ccbce47c86b0fa558adb01dfccaf4d60 (diff)
parentd4659e2bd3ddb947683948083232c26fb1227f39 (diff)
Merge branch 'master' into joanne-tutorialagent
Diffstat (limited to 'src/fields/Types.ts')
-rw-r--r--src/fields/Types.ts104
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;
}