Files
gridline/desktop/src/lib/csvParser.ts
T
adrianbonpin 6854d889c5 refactor: convert to bun-workspaces monorepo (desktop/ + www/)
- Move the Tauri app (React frontend + Rust backend) into desktop/ via
  git mv — configs unchanged (relative paths: tauri.conf.json, vite.config.ts)
- Root package.json becomes a private bun workspace container with
  orchestration scripts; desktop package renamed gridline-desktop
- Scaffold www/ with Astro 7 + Tailwind v4 (hand-wired vite plugin,
  static output, ready for Dokploy)
- Update release.yml for the new layout: projectPath: desktop,
  desktop/src-tauri resource paths, rust-cache workspace path
- Update README + AGENTS.md structure trees and dev commands
- Verified: vitest (1074), cargo test (354), desktop build, tauri dev
  (window launches), tauri build (dmg + app bundles), Astro build
2026-08-16 19:31:53 +08:00

43 lines
1.2 KiB
TypeScript

export interface ParsedCsv {
headers: string[];
rows: string[][];
}
export function parseCsv(input: string): ParsedCsv {
const text = input.replace(/^\uFEFF/, "");
if (text.trim() === "") throw new Error("CSV input is empty");
const rows: string[][] = [];
let field = "";
let row: string[] = [];
let inQuotes = false;
for (let i = 0; i < text.length; i++) {
const ch = text[i];
if (inQuotes) {
if (ch === '"') {
if (text[i + 1] === '"') { field += '"'; i++; }
else inQuotes = false;
} else field += ch;
} else if (ch === '"') {
inQuotes = true;
} else if (ch === ',') {
row.push(field); field = "";
} else if (ch === '\n' || ch === '\r') {
if (ch === '\r' && text[i + 1] === '\n') i++;
row.push(field); field = "";
rows.push(row); row = [];
} else field += ch;
}
if (field !== "" || row.length > 0) { row.push(field); rows.push(row); }
if (rows.length === 0) throw new Error("CSV input is empty");
const [headers, ...data] = rows;
const width = headers.length;
const padded = data.map((r) => {
const out = r.slice(0, width);
while (out.length < width) out.push("");
return out;
});
return { headers, rows: padded };
}