Something went wrong. Try again.
Starship Simulator Controls thoriumsim.com
Something went wrong. Try again.
7.9 kB · 287 lines
TypeScript
at develop
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288import type { ActionOverrides } from "@thorium/.server/data";import { components } from "@thorium/ecs-components";import type z from "zod";type ZodObjectOrWrapped = z.ZodObject<any, any> | z.ZodEffects<z.ZodObject<any, any>>;
export function getObjectFormSchema(schema: ZodObjectOrWrapped): z.ZodObject<any, any> { if (schema._def.typeName === "ZodEffects") { const typedSchema = schema as z.ZodEffects<z.ZodObject<any, any>>; return getObjectFormSchema(typedSchema._def.schema); } return schema as z.ZodObject<any, any>;}
/** * Get all default values from a Zod schema. */export function getDefaultValues<Schema extends z.ZodObject<any, any>>(schema: Schema) { const { shape } = schema; type DefaultValuesType = any; // DefaultValues<Partial<z.infer<Schema>>>; const defaultValues = {} as DefaultValuesType;
for (const key of Object.keys(shape)) { const item = shape[key] as z.ZodAny;
if (getBaseType(item) === "ZodObject") { const defaultItems = getDefaultValues(item as unknown as z.ZodObject<any, any>); for (const defaultItemKey of Object.keys(defaultItems)) { const pathKey = `${key}.${defaultItemKey}` as keyof DefaultValuesType; defaultValues[pathKey] = defaultItems[defaultItemKey]; } } else { const defaultValue = getDefaultValueInZodStack(item); if (defaultValue !== undefined) { defaultValues[key as keyof DefaultValuesType] = defaultValue; } } }
return defaultValues;}
/** * Get the type name of the lowest level Zod type. * This will unpack optionals, refinements, etc. */export function getBaseType(schema: z.ZodAny): string { return getBaseSchema(schema)._def.typeName;}
/** * Get the lowest level Zod type. * This will unpack optionals, refinements, etc. */function getBaseSchema(schema: z.ZodAny): z.ZodAny { if ("innerType" in schema._def) { return getBaseSchema(schema._def.innerType as z.ZodAny); } if ("schema" in schema._def) { return getBaseSchema(schema._def.schema as z.ZodAny); } return schema;}
/** * Search for a "ZodDefult" in the Zod stack and return its value. */function getDefaultValueInZodStack(schema: z.ZodAny): any { const typedSchema = schema as unknown as z.ZodDefault<z.ZodNumber | z.ZodString>;
if (typedSchema._def.typeName === "ZodDefault") { return typedSchema._def.defaultValue(); }
if ("innerType" in typedSchema._def) { return getDefaultValueInZodStack(typedSchema._def.innerType as unknown as z.ZodAny); } if ("schema" in typedSchema._def) { return getDefaultValueInZodStack((typedSchema._def as any).schema as z.ZodAny); } return undefined;}
/** * Beautify a camelCase string. * e.g. "myString" -> "My String" */export function beautifyObjectName(string: string) { let output = string.replace(/([A-Z])/g, " $1"); output = output.charAt(0).toUpperCase() + output.slice(1); return output;}
/** * Convert a Zod schema to HTML input props to give direct feedback to the user. * Once submitted, the schema will be validated completely. */export function zodToHtmlInputProps(schema: any): React.InputHTMLAttributes<HTMLInputElement> { if (["ZodOptional", "ZodNullable"].includes(schema._def.typeName)) { const typedSchema = schema as z.ZodOptional<z.ZodNumber | z.ZodString>; return { ...zodToHtmlInputProps(typedSchema._def.innerType), required: false, }; }
const typedSchema = schema as z.ZodNumber | z.ZodString;
if (!("checks" in typedSchema._def)) return {};
const { checks } = typedSchema._def; const inputProps: React.InputHTMLAttributes<HTMLInputElement> = { required: true, }; const type = getBaseType(schema);
for (const check of checks) { if (check.kind === "min") { if (type === "ZodString") { inputProps.minLength = check.value; } else { inputProps.min = check.value; } } if (check.kind === "max") { if (type === "ZodString") { inputProps.maxLength = check.value; } else { inputProps.max = check.value; } } }
return inputProps;}
/** * Define handlers for specific Zod types. * You can expand this object to support more types. */const DEFAULT_ZOD_HANDLERS = { ZodBoolean: "checkbox", ZodDate: "date", ZodEnum: "select", ZodNumber: "number",} as const;
export const ZOD_COMPARISONS = { ZodNumber: ["=", "!=", ">", "<", "<=", ">="], ZodBoolean: ["true", "false"], ZodString: ["=", "!=", "contains", "is empty", "is not empty"], ZodArray: ["contains", "length", "is empty", "is not empty"], ZodLiteral: ["=", "!="], ZodEnum: ["=", "!="], ZodUnion: ["=", "!="], // "ZodObject", // "ZodRecord",};
export type InputTypes = | "object" | "text" | "textarea" | "number" | "select" | "checkbox" | "date" | "tags" | "room" | "starmapCoordinates" | "shipTemplate" | "components" | "sound";
export function getInputType<T extends keyof typeof ZOD_COMPARISONS>( item: { key: string; name: string; type: any; values: any; }, comparison: (typeof ZOD_COMPARISONS)[T][number] | null,): InputTypes { if (item.key === "tags") return "tags"; if (!item.type) return "text"; if (item.type === "ZodArray") { if (comparison === "contains") return "text"; return "number"; } if (item.type === "ZodEnum" || item.type === "select") { return "select"; } if (item.type === "ZodObject" || item.type === "object") { return "object"; } if (item.type in DEFAULT_ZOD_HANDLERS) { return DEFAULT_ZOD_HANDLERS[item.type as keyof typeof DEFAULT_ZOD_HANDLERS]; }
return item.type as any;}
function getItemFromShape(shape: any, name: string) { const item = shape[name] as z.ZodAny;
if ("unwrap" in item && item.unwrap && typeof item.unwrap === "function") { return item.unwrap(); }
return item;}
type ParsedSchema = { type: string; name: string; key: string; isRequired: boolean; inputProps: React.InputHTMLAttributes<HTMLInputElement>; values: any; helper?: string; isNested: boolean; path: string;}[];const fieldConfig = {} as any;export function parseSchema( schema: any, overrides: Record<string, ActionOverrides> = {}, nestedName?: string,): ParsedSchema { if (!schema) return []; const { shape } = schema; if (!shape) { if (schema._def.typeName === "ZodIntersection") { const left = parseSchema(schema._def.left, overrides, nestedName); const right = parseSchema(schema._def.right, overrides, nestedName);
return [...left, ...right]; }
if (schema._def.typeName === "ZodUnion") { return schema._def.options.flatMap((option: any) => parseSchema(option, overrides, nestedName), ); } return []; } return Object.keys(shape).flatMap((name) => { let output: ParsedSchema = []; const item = getItemFromShape(shape, name); const type = overrides[name]?.type || getBaseType(item); if (type === "ZodObject") { const objectSchema = getObjectFormSchema(item as unknown as ZodObjectOrWrapped); output = output.concat(parseSchema(objectSchema, overrides, name)); } const itemName = overrides[name]?.name ?? item._def.description ?? beautifyObjectName(name);
const key = `${nestedName ? `${nestedName}.` : ""}${name}`;
const values = overrides[name]?.values || (getBaseSchema(item) as unknown as z.ZodEnum<any>)._def.values;
const fieldConfigItem = fieldConfig?.[name] ?? {}; const inputProps = { ...zodToHtmlInputProps(item), ...overrides[name]?.inputProps, }; const isRequired = inputProps.required ?? fieldConfigItem.inputProps?.required ?? false;
output.unshift({ type: type, name: itemName, key, isRequired, inputProps, values, helper: overrides[name]?.helper, isNested: !!nestedName, path: nestedName || "", }); return output; });}
export function schemaWithoutDefault(component: keyof typeof components) { const schema = components[component]; if (schema && "removeDefault" in schema) return schema.removeDefault(); return schema;}