import { type DocumentData, type DocumentType } from "./types"; export type FieldType = "identifier" | "shortText" | "longText" | "toggle"; export type ValueForFieldType = { identifier: string; shortText: string; longText: string; toggle: boolean; }[F]; function defaultValue(fieldType: F): ValueForFieldType { switch (fieldType) { case "identifier": case "shortText": case "longText": return "" as ValueForFieldType; case "toggle": return false as ValueForFieldType; } } export type DocumentField = { name: string; fieldType: F; getter: (doc: DocumentData) => ValueForFieldType; setter: ( value: ValueForFieldType, doc: DocumentData, ) => DocumentData; setDefault: (doc: DocumentData) => DocumentData; }; const simpleField = ( name: string, key: keyof DocumentData, fieldType: F, ): DocumentField => ({ name, fieldType, getter: (doc) => doc[key] as unknown as ValueForFieldType, setter: (value, doc) => ({ ...doc, [key]: value }), setDefault: (doc) => ({ ...doc, [key]: defaultValue(fieldType) }), }); const simpleFields = ( fields: Record, FieldType]>, ): DocumentField[] => Object.entries(fields).map(([name, [key, fieldType]]) => simpleField(name, key, fieldType), ); export function getFieldsForType( docType: D, ): DocumentField[] { // 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[]; case "location": return simpleFields<"location">({ Name: ["name", "shortText"], Description: ["description", "longText"], }) as unknown as DocumentField[]; case "monster": return simpleFields<"monster">({ Name: ["name", "shortText"], }) as unknown as DocumentField[]; case "npc": return simpleFields<"npc">({ Name: ["name", "shortText"], Description: ["description", "longText"], }) as unknown as DocumentField[]; case "scene": return simpleFields<"scene">({ Text: ["text", "longText"], }) as unknown as DocumentField[]; case "secret": return simpleFields<"secret">({ Discovered: ["discovered", "toggle"], Text: ["text", "shortText"], }) as unknown as DocumentField[]; case "session": return simpleFields<"session">({ Name: ["name", "shortText"], "Strong Start": ["strongStart", "longText"], }) as unknown as DocumentField[]; case "thread": return simpleFields<"thread">({ Resolved: ["resolved", "toggle"], Text: ["text", "shortText"], }) as unknown as DocumentField[]; case "treasure": return simpleFields<"treasure">({ Discovered: ["discovered", "toggle"], Text: ["text", "shortText"], }) as unknown as DocumentField[]; } }