be1f86044e
Phase 3 of RFC #308: Stateful Sense refactor. - Examples (cpu-usage, nerve-health) use initialState + compute(state) - CLI create/init templates generate stateful sense (no SQLite/Drizzle) - Removed: sense query, sense schema commands (no more per-sense SQLite) - Removed: sense-sqlite.ts, schema templates, migration templates - Updated all CLI tests for new sense structure Refs #308, closes #311
49 lines
1.6 KiB
TypeScript
49 lines
1.6 KiB
TypeScript
function stringifyCell(value: unknown): string {
|
|
if (value === null || value === undefined) return "";
|
|
if (typeof value === "bigint") return value.toString();
|
|
if (typeof value === "number" || typeof value === "boolean") return String(value);
|
|
if (typeof value === "string") return value;
|
|
if (Buffer.isBuffer(value)) return value.toString("hex");
|
|
try {
|
|
return JSON.stringify(value);
|
|
} catch {
|
|
return String(value);
|
|
}
|
|
}
|
|
|
|
/** Collect column keys in stable order (first row keys, then any extras). */
|
|
export function collectColumnKeys(rows: Record<string, unknown>[]): string[] {
|
|
const keys: string[] = [];
|
|
const seen = new Set<string>();
|
|
for (const row of rows) {
|
|
for (const k of Object.keys(row)) {
|
|
if (!seen.has(k)) {
|
|
seen.add(k);
|
|
keys.push(k);
|
|
}
|
|
}
|
|
}
|
|
return keys;
|
|
}
|
|
|
|
const MAX_CELL = 64;
|
|
|
|
function truncate(s: string): string {
|
|
if (s.length <= MAX_CELL) return s;
|
|
return `${s.slice(0, MAX_CELL - 1)}…`;
|
|
}
|
|
|
|
/** Plain aligned table for terminal output. */
|
|
export function formatRowsAsAlignedTable(rows: Record<string, unknown>[]): string {
|
|
if (rows.length === 0) {
|
|
return "(0 rows)\n";
|
|
}
|
|
const cols = collectColumnKeys(rows);
|
|
const cells = rows.map((row) => cols.map((c) => truncate(stringifyCell(row[c]))));
|
|
const widths = cols.map((c, j) => Math.max(c.length, ...cells.map((r) => r[j].length)));
|
|
const sep = widths.map((w) => "-".repeat(w)).join("-+-");
|
|
const header = cols.map((c, j) => c.padEnd(widths[j])).join(" | ");
|
|
const body = cells.map((r) => r.map((cell, j) => cell.padEnd(widths[j])).join(" | ")).join("\n");
|
|
return `${header}\n${sep}\n${body}\n`;
|
|
}
|