diff options
Diffstat (limited to 'src/features/surface-host/logic/table.ts')
| -rw-r--r-- | src/features/surface-host/logic/table.ts | 54 |
1 files changed, 54 insertions, 0 deletions
diff --git a/src/features/surface-host/logic/table.ts b/src/features/surface-host/logic/table.ts new file mode 100644 index 0000000..027553c --- /dev/null +++ b/src/features/surface-host/logic/table.ts @@ -0,0 +1,54 @@ +/** + * Pure parser for the `rendererId: "table"` custom-field payload. + * + * This is the FRONTEND-side renderer contract for tabular custom fields: a + * backend that wants a table emits a `custom` field with `rendererId: "table"` + * and a payload of `{ columns: string[]; rows: (string|number)[][] }`. Cells are + * coerced to strings. Anything that does not match the shape returns `null`, so + * the renderer gracefully skips it (never throws on hostile/partial data). + */ + +export interface TableData { + readonly columns: readonly string[]; + readonly rows: readonly (readonly string[])[]; +} + +function isStringArray(v: unknown): v is unknown[] { + return Array.isArray(v); +} + +function coerceCell(v: unknown): string | null { + if (typeof v === "string") return v; + if (typeof v === "number" && Number.isFinite(v)) return String(v); + if (typeof v === "boolean") return String(v); + return null; +} + +export function parseTablePayload(payload: unknown): TableData | null { + if (typeof payload !== "object" || payload === null) return null; + const obj = payload as Record<string, unknown>; + + const rawColumns = obj.columns; + const rawRows = obj.rows; + if (!isStringArray(rawColumns) || !isStringArray(rawRows)) return null; + + const columns: string[] = []; + for (const col of rawColumns) { + if (typeof col !== "string") return null; + columns.push(col); + } + + const rows: string[][] = []; + for (const row of rawRows) { + if (!Array.isArray(row)) return null; + const cells: string[] = []; + for (const cell of row) { + const c = coerceCell(cell); + if (c === null) return null; + cells.push(c); + } + rows.push(cells); + } + + return { columns, rows }; +} |
