@fusedashlabs/ui9000-workspace
Version:
UI9000 workspace MCP. One tool, show_workspace, draws a chart from your table. Set TYPESAFE_API_KEY to let Jev choose the chart.
110 lines (109 loc) • 3.06 kB
JavaScript
/**
* Column-oriented view of one dataset — the profiler's only input.
*
* A Table is the parsed shape of a CSV: header names plus raw cell text in row
* order. The profiler never sees typed rows, so a fixture CSV and a live
* dataset go through exactly the same classification.
*/
/** Rows in the table — the longest column wins if a CSV row was short. */
export function tableRowCount(table) {
let rows = 0;
for (const column of table.columns) {
if (column.values.length > rows)
rows = column.values.length;
}
return rows;
}
/** Row-oriented copy of a Table. Used to persist / profile, not as MCP tool output. */
export function tableToRows(table) {
const rowCount = tableRowCount(table);
const rows = [];
for (let i = 0; i < rowCount; i += 1) {
const row = {};
for (const column of table.columns) {
row[column.name] = column.values[i] ?? '';
}
rows.push(row);
}
return rows;
}
/** Header text reduced to letters and digits: `Created At` and `created_at` match. */
export function normalizeName(name) {
return name.toLowerCase().replace(/[^a-z0-9]/g, '');
}
/**
* Minimal RFC 4180 reader: quoted fields, `""` escapes, CR/LF or LF, blank
* lines skipped. Enough for fixtures; the profiler owns no other parsing.
*/
export function parseCsvTable(text) {
const rows = parseRows(text);
const header = rows.shift();
if (!header)
return { columns: [] };
const columns = header.map((name) => ({ name: name.trim(), values: [] }));
for (const row of rows) {
for (const [index, column] of columns.entries()) {
column.values.push(row[index] ?? '');
}
}
return { columns };
}
function parseRows(text) {
const rows = [];
let row = [];
let field = '';
let quoted = false;
let i = 0;
const endField = () => {
row.push(field);
field = '';
};
const endRow = () => {
endField();
if (row.length > 1 || row[0] !== '')
rows.push(row);
row = [];
};
while (i < text.length) {
const char = text[i];
if (quoted) {
if (char === '"') {
if (text[i + 1] === '"') {
field += '"';
i += 2;
continue;
}
quoted = false;
i += 1;
continue;
}
field += char;
i += 1;
continue;
}
if (char === '"') {
quoted = true;
i += 1;
continue;
}
if (char === ',') {
endField();
i += 1;
continue;
}
if (char === '\r') {
i += 1;
continue;
}
if (char === '\n') {
endRow();
i += 1;
continue;
}
field += char;
i += 1;
}
if (field !== '' || row.length > 0)
endRow();
return rows;
}