// DOM-free helpers for the viewer, so Node can test them (test/test.mjs). /** Child path of `name` in the group at `parent`. */ export function joinPath(parent, name) { return parent === "/" ? `/${name}` : `${parent}/${name}`; } /** One value as display text. */ export function formatValue(v) { if (v === null || v === undefined) return ""; if (typeof v === "bigint") return v.toString(); if (typeof v === "number") { if (Number.isInteger(v)) return String(v); return String(Number(v.toPrecision(7))); } if (typeof v === "string") return JSON.stringify(v); if (ArrayBuffer.isView(v) || Array.isArray(v)) { const items = Array.from(v.slice(0, 16), formatValue); if (v.length > 16) items.push(`… (${v.length} values)`); return `[${items.join(", ")}]`; } return String(v); } /** * The window of a dataset to show: a hyperslab over its `shape` with the * last dimension as columns, the one before as rows, and any leading * dimensions held at `fixed` indices. `row`/`col` are the window's top-left * corner. Returns null for a scalar (read it whole). */ export function viewWindow(shape, { row = 0, col = 0, rows = 50, cols = 12, fixed = [] } = {}) { const rank = shape.length; if (rank === 0) return null; const clamp = (x, n) => Math.max(0, Math.min(x, Math.max(0, n - 1))); if (rank === 1) { const r0 = clamp(row, shape[0]); const n = Math.max(0, Math.min(rows, shape[0] - r0)); return { start: [r0], count: [n], rows: n, cols: 1, row: r0, col: 0 }; } const lead = shape.slice(0, rank - 2).map((n, i) => clamp(fixed[i] ?? 0, n)); const nr = shape[rank - 2]; const nc = shape[rank - 1]; const r0 = clamp(row, nr); const c0 = clamp(col, nc); const r = Math.max(0, Math.min(rows, nr - r0)); const c = Math.max(0, Math.min(cols, nc - c0)); return { start: [...lead, r0, c0], count: [...lead.map(() => 1), r, c], rows: r, cols: c, row: r0, col: c0, }; } /** * Split row-major `data` into `rows` x `cols` cells of display text; each * cell holds `per` consecutive values (the elements of an array datatype). */ export function toRows(data, rows, cols, per = 1) { const out = []; for (let r = 0; r < rows; r++) { const row = []; for (let c = 0; c < cols; c++) { const i = (r * cols + c) * per; row.push(per === 1 ? formatValue(data[i]) : formatValue(data.slice(i, i + per))); } out.push(row); } return out; } /** Number of values an array datatype packs into each element. */ export function perElement(elementShape) { return elementShape.reduce((a, b) => a * b, 1); }