107 lines
3.7 KiB
TypeScript
107 lines
3.7 KiB
TypeScript
import { type DocumentData, type DocumentType } from "./types";
|
|
|
|
export type FieldType = "identifier" | "shortText" | "longText" | "toggle";
|
|
|
|
export type ValueForFieldType<F extends FieldType> = {
|
|
identifier: string;
|
|
shortText: string;
|
|
longText: string;
|
|
toggle: boolean;
|
|
}[F];
|
|
|
|
function defaultValue<F extends FieldType>(fieldType: F): ValueForFieldType<F> {
|
|
switch (fieldType) {
|
|
case "identifier":
|
|
case "shortText":
|
|
case "longText":
|
|
return "" as ValueForFieldType<F>;
|
|
case "toggle":
|
|
return false as ValueForFieldType<F>;
|
|
}
|
|
}
|
|
|
|
export type DocumentField<D extends DocumentType, F extends FieldType> = {
|
|
name: string;
|
|
fieldType: F;
|
|
getter: (doc: DocumentData<D>) => ValueForFieldType<F>;
|
|
setter: (
|
|
value: ValueForFieldType<F>,
|
|
doc: DocumentData<D>,
|
|
) => DocumentData<D>;
|
|
setDefault: (doc: DocumentData<D>) => DocumentData<D>;
|
|
};
|
|
|
|
const simpleField = <D extends DocumentType, F extends FieldType>(
|
|
name: string,
|
|
key: keyof DocumentData<D>,
|
|
fieldType: F,
|
|
): DocumentField<D, F> => ({
|
|
name,
|
|
fieldType,
|
|
getter: (doc) => doc[key] as unknown as ValueForFieldType<F>,
|
|
setter: (value, doc) => ({ ...doc, [key]: value }),
|
|
setDefault: (doc) => ({ ...doc, [key]: defaultValue(fieldType) }),
|
|
});
|
|
|
|
const simpleFields = <D extends DocumentType>(
|
|
fields: Record<string, [keyof DocumentData<D>, FieldType]>,
|
|
): DocumentField<D, FieldType>[] =>
|
|
Object.entries(fields).map(([name, [key, fieldType]]) =>
|
|
simpleField(name, key, fieldType),
|
|
);
|
|
|
|
export function getFieldsForType<D extends DocumentType>(
|
|
docType: D,
|
|
): DocumentField<D, FieldType>[] {
|
|
// Explicit casts are required because the getter function puts the type D in the parameters position and thus the specialized getter is not valid in the case of the more general document type.
|
|
// While the switch correctly sees that D is now "front", the _type_ could be a union and thus the getter needs to be able to accept any of them.
|
|
// I know this will only ever be called in the context of one value, but this is clearly abusing the type system.
|
|
// TODO: Fix the types
|
|
switch (docType) {
|
|
case "front":
|
|
return simpleFields<"front">({
|
|
Name: ["name", "shortText"],
|
|
Description: ["description", "longText"],
|
|
Resolved: ["resolved", "toggle"],
|
|
}) as unknown as DocumentField<D, FieldType>[];
|
|
case "location":
|
|
return simpleFields<"location">({
|
|
Name: ["name", "shortText"],
|
|
Description: ["description", "longText"],
|
|
}) as unknown as DocumentField<D, FieldType>[];
|
|
case "monster":
|
|
return simpleFields<"monster">({
|
|
Name: ["name", "shortText"],
|
|
}) as unknown as DocumentField<D, FieldType>[];
|
|
case "npc":
|
|
return simpleFields<"npc">({
|
|
Name: ["name", "shortText"],
|
|
Description: ["description", "longText"],
|
|
}) as unknown as DocumentField<D, FieldType>[];
|
|
case "scene":
|
|
return simpleFields<"scene">({
|
|
Text: ["text", "longText"],
|
|
}) as unknown as DocumentField<D, FieldType>[];
|
|
case "secret":
|
|
return simpleFields<"secret">({
|
|
Discovered: ["discovered", "toggle"],
|
|
Text: ["text", "shortText"],
|
|
}) as unknown as DocumentField<D, FieldType>[];
|
|
case "session":
|
|
return simpleFields<"session">({
|
|
Name: ["name", "shortText"],
|
|
"Strong Start": ["strongStart", "longText"],
|
|
}) as unknown as DocumentField<D, FieldType>[];
|
|
case "thread":
|
|
return simpleFields<"thread">({
|
|
Resolved: ["resolved", "toggle"],
|
|
Text: ["text", "shortText"],
|
|
}) as unknown as DocumentField<D, FieldType>[];
|
|
case "treasure":
|
|
return simpleFields<"treasure">({
|
|
Discovered: ["discovered", "toggle"],
|
|
Text: ["text", "shortText"],
|
|
}) as unknown as DocumentField<D, FieldType>[];
|
|
}
|
|
}
|