svm0n_datadeck/test-csv-parser.mjs
SVM0N 3b213d0650 SWITCH TO CSV AS MAIN: retire XLSX, drop SheetJS, simplify save path
Plugin is CSV-only. registerExtensions(["csv"]); SheetJS gone; the
_csv_helpers/ mirror collapses to a single canonical CSV. Bundle drops
720 KB → 297 KB (-59%); parse+eval 0.9 ms → 0.5 ms.

Migration plan was empirically validated before any data was touched:
xlsx-to-csv-roundtrip.mjs reads each xlsx, Papa.unparse → Papa.parse,
cell-by-cell compares the result to the source. All 10 checks passed
across books / movies / quotes / dictionary / habit_tracker — proves
the round-trip is lossless including multiline notes, stars, embedded
punctuation, and unicode.

migrate-xlsx-to-csv.mjs is the cutover: writes canonical csv, moves
xlsx → Archive/<name>_pre-csv-migration.xlsx (recoverable), removes
the _csv_helpers/ folder, rewrites data.json fileConfigs keys from
*.xlsx → *.csv so per-file overrides survive.

Code surface:
- main.ts: onLoadFile / doSave / generateMobileFiles / renderAddEntryForm
  all collapsed to the csv-only path; loadXLSX + isXlsx removed.
- mobile dashboards: csv-add and dataviewjs now point at the same
  canonical csv (used to be split because Dataview couldn't read xlsx).
- regenerate-mobile-dashboards.mjs: drops the helper-folder path.
- package.json: xlsx dependency removed (9 transitive packages gone).

Also included in this commit (carried over from the same session):
- mobile toolbar: ⚙ Columns / 📱 Mobile / 💾 Backup collapse into a
  ⋯ overflow menu on screens ≤ 600 px so the toolbar fits on one row.
- mobile compact density: pure-CSS media-query switch for Library
  (2-col compact grid + mobile-md card style), tighter Kanban cards,
  smaller Table cells.

Tests: 88 plugin + 21 mobile-dashboard, all green. Typecheck clean.

Verified manually: open books.csv, edit a note (saves debounce), open
on iPhone (compact library grid, ⋯ menu, csv-add form pre-fills).

Class name XLSXCardView left in place to keep this commit focused on
behavior; rename to CardView is a noted follow-up in handoff.md.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-24 07:23:02 +00:00

118 lines
2.7 KiB
JavaScript

/**
* Simple test for CSV parsing logic
* Run with: node test-csv-parser.mjs
*/
// Mirror of src/utils.ts → parseCSV (Papa-backed). Kept in sync by hand.
import Papa from "papaparse";
function parseCSV(raw) {
if (!raw) return { headers: [], rows: [] };
const result = Papa.parse(raw, { header: true, skipEmptyLines: true });
const headers = (result.meta.fields ?? []).map(String);
const rows = (result.data ?? []).map(r => {
const row = {};
headers.forEach(h => { row[h] = r[h] != null ? String(r[h]) : ""; });
return row;
});
return { headers, rows };
}
// Test cases
const tests = [
{
name: "Simple CSV",
input: `Name,Age,City
John,25,NYC
Jane,30,LA`,
expected: {
headers: ["Name", "Age", "City"],
rows: [
{ Name: "John", Age: "25", City: "NYC" },
{ Name: "Jane", Age: "30", City: "LA" }
]
}
},
{
name: "Quoted fields with commas",
input: `Title,Description
"Hello, World","A simple greeting"
Test,"No quotes needed"`,
expected: {
headers: ["Title", "Description"],
rows: [
{ Title: "Hello, World", Description: "A simple greeting" },
{ Title: "Test", Description: "No quotes needed" }
]
}
},
{
name: "Escaped quotes",
input: `Name,Quote
John,"He said ""Hello"""
Jane,"She replied ""Hi""!"`,
expected: {
headers: ["Name", "Quote"],
rows: [
{ Name: "John", Quote: 'He said "Hello"' },
{ Name: "Jane", Quote: 'She replied "Hi"!' }
]
}
},
{
name: "Empty fields",
input: `A,B,C
1,,3
,2,
,,`,
expected: {
headers: ["A", "B", "C"],
rows: [
{ A: "1", B: "", C: "3" },
{ A: "", B: "2", C: "" },
{ A: "", B: "", C: "" }
]
}
},
{
name: "Unicode content",
input: `Name,Emoji,Japanese
Test,🎉,こんにちは
Book,📚,日本語`,
expected: {
headers: ["Name", "Emoji", "Japanese"],
rows: [
{ Name: "Test", Emoji: "🎉", Japanese: "こんにちは" },
{ Name: "Book", Emoji: "📚", Japanese: "日本語" }
]
}
},
{
name: "Empty CSV",
input: "",
expected: { headers: [], rows: [] }
}
];
let passed = 0;
let failed = 0;
console.log("Running CSV parser tests...\n");
for (const test of tests) {
const result = parseCSV(test.input);
const resultStr = JSON.stringify(result);
const expectedStr = JSON.stringify(test.expected);
if (resultStr === expectedStr) {
console.log(`${test.name}`);
passed++;
} else {
console.log(`${test.name}`);
console.log(` Expected: ${expectedStr}`);
console.log(` Got: ${resultStr}`);
failed++;
}
}
console.log(`\n${passed} passed, ${failed} failed`);
process.exit(failed > 0 ? 1 : 0);