phonograph/svelte/src/editor-state.svelte.ts
2025-08-24 23:24:14 -07:00

76 lines
2 KiB
TypeScript

import * as uuid from "uuid";
import { type Encodable, type FieldType } from "./field.svelte.ts";
type Assert<_T extends true> = void;
// This should be a discriminated union type, but TypeScript isn't
// sophisticated enough to discriminate based on the nested field_type's tag,
// causing a huge pain in the ass.
export type EditorState = {
date_value: string;
text_value: string;
time_value: string;
is_null: boolean;
};
export const DEFAULT_EDITOR_STATE: EditorState = {
date_value: "",
text_value: "",
time_value: "",
is_null: false,
};
export function editor_state_from_encodable(value: Encodable): EditorState {
if (value.t === "Text") {
return {
...DEFAULT_EDITOR_STATE,
text_value: value.c ?? "",
is_null: value.c === undefined,
};
} else if (value.t === "Timestamp") {
return {
...DEFAULT_EDITOR_STATE,
date_value: value.c
? `${value.c.getFullYear()}-${
value.c.getMonth() + 1
}-${value.c.getDate()}`
: "",
is_null: value.c === undefined,
time_value: value.c
? `${value.c.getHours()}:${value.c.getMinutes()}`
: "",
};
} else if (value.t === "Uuid") {
return {
...DEFAULT_EDITOR_STATE,
text_value: value.c ?? "",
is_null: value.c === undefined,
};
}
type _ = Assert<typeof value extends never ? true : false>;
throw new Error("this should be unreachable");
}
export function encodable_from_editor_state(
value: EditorState,
field_type: FieldType,
): Encodable | undefined {
if (field_type.t === "Text") {
return { t: "Text", c: value.text_value };
}
if (field_type.t === "Timestamp") {
// FIXME
throw new Error("not yet implemented");
}
if (field_type.t === "Uuid") {
try {
return { t: "Uuid", c: uuid.stringify(uuid.parse(value.text_value)) };
} catch {
// uuid.parse() throws a TypeError if unsuccessful.
return undefined;
}
}
type _ = Assert<typeof field_type extends never ? true : false>;
throw new Error("this should be unreachable");
}