import type { PhyFile, Node, KeyNode } from "./phy"; export type PhyReference = { source: string; checksum: string; [key: string]: unknown }; export type IdxFile = { version: string; phyReference: PhyReference; order: string[]; [key: string]: unknown; }; /** Collects keys in document order, including ghost keys and excluding decals. T-18. */ export function eligibleKeyIds(phy: PhyFile): string[] { const ids: string[] = []; const visit = (nodes: Node[]) => nodes.forEach((n) => { if (n.type === "key") { if (!n.decal) ids.push(n.id); } else if (n.type === "cluster") visit(n.children); else if (n.type === "variantGroup") n.children.forEach((v) => visit(v.children)); }); visit(phy.root); return ids; } /** Makes initial index order from KLE occurrence order. T-18. */ export function createIdx(phy: PhyFile, keyOrder: string[], phyReference: PhyReference): IdxFile { const valid = new Set(eligibleKeyIds(phy)); return { version: "0.1.0", phyReference: structuredClone(phyReference), order: keyOrder.filter((id) => valid.has(id)), }; } /** Lists eligible PHY keys omitted from the saved order. T-18. */ export function unregisteredKeys(phy: PhyFile, idx: IdxFile): string[] { const registered = new Set(idx.order); return eligibleKeyIds(phy).filter((id) => !registered.has(id)); } /** Registers new keys at the end without rebuilding existing order. T-18. */ export function appendKeys(idx: IdxFile, ids: string[]): IdxFile { const out = structuredClone(idx); for (const id of ids) if (!out.order.includes(id)) out.order.push(id); return out; } /** Removes one key from index order. */ export function excludeKey(idx: IdxFile, keyId: string): IdxFile { const o = structuredClone(idx); o.order = o.order.filter((x) => x !== keyId); return o; } /** Reorders the saved key list. */ export function reorderKeys(idx: IdxFile, order: string[]): IdxFile { if ( order.length !== idx.order.length || new Set(order).size !== order.length || order.some((x) => !idx.order.includes(x)) ) throw new Error("Order must contain every registered key exactly once"); return { ...structuredClone(idx), order: [...order] }; }