A single-file client-side React application that parses, auto-cleans and displays data tables from raw Fidelity CSV exports. Built with Bun, Parcel, TypeScript and TailwindCSS v4
Brokerage firms and financial reports typically contain messy headers, account preambles, and legal footers that break standard SQL or naive CSV parsers. This application uses a custom heuristic processor:
- Token Isolation: Parses fields respecting double quotes, escaped quotes (
"") and newlines inside quotes - Density Metrics: Picks the most common column count across all rows, filtering out metadata lines
- Contiguous Block Extraction: Keeps the block of rows that fit that width (Fidelity data rows carry one extra trailing comma), discarding preambles, postambles and legal disclaimers
- Natural Sort Order: Loaded files and tabs are sorted via
Intl.Collatorwith numeric ordering (file2.csvcomes beforefile10.csv) - Import: Click the empty-state placeholder or the Import CSV Files button to open the file picker
- Column Types: Each column is detected as text, number, percent, currency or market cap; the badge in the header shows the type and cycles it on click. Sorting and numeric filters follow the type
- Sticky Layout: Sticky table headers, plus pinned columns: the anchor button in a column header keeps that column at the left edge on horizontal scroll. Pins are per file in tabs and shared in merge view
- Merge View and Export: Show all files as stacked blocks, export the active tab, one merged CSV or every file separately, with sort and filters applied
- Features Synchronous Lazy State Initialization from
localStorageto avoid multi-effect race conditions and theme flickering often triggered by double-rendering inReact.StrictModeenvironments during development - Dark mode via the TailwindCSS v4
darkclass kept in sync on the document root - Export/Import app configuration as a JSON file
- Runtime: Bun
- Build Tool: Parcel
- Frontend Library: React (TypeScript)
- Styling Framework: TailwindCSS v4, icons are inline SVGs
Ensure you have Bun installed locally on your development machine.
-
Clone the repository and navigate to the root directory:
git clone https://github.com/daggerok/csv.git && cd $_
-
Install the necessary development dependencies:
bun install -E
-
Launch the local Parcel development server with Hot Module Replacement (HMR):
bun run serve
-
Upgrade all ecosystem packages to their latest absolute versions:
bunx npm-check-updates -u
Since the entire system compiles into a self-contained Single Page Application (SPA) without requiring any heavy node backend or cloud infrastructure, you can generate a static deployment bundle:
bun run build && bunx serve ./distThe resulting optimized assets will be located inside the ./dist folder, ready to be served from any static hosting
architecture or local offline workspace.
This application executes entirely client-side inside your web browser. No financial data, statements, ledger indices,
or CSV filenames are transmitted to external cloud systems, tracking networks, or third-party servers. With
Remember Data on (the default), imported files are kept in this browser's localStorage until you turn it off or
click Clear Data
Open problems, planned to be fixed later
Files are read whole, parsed on the main thread, kept in React state and rendered without virtualization in both tab and merge views. Big exports or many files at once freeze the tab. Fix: parse in a Web Worker and virtualize rows
parseCSVText calls field.trim() on every field, quoted ones included, so " keep spaces " loses its spaces.
Fix: trim only unquoted fields and add parser fixtures (embedded quotes, whitespace, multiline values, extra and
missing columns, Fidelity preambles and footers)
rememberData defaults to true, so imported datasets stay in localStorage on shared or managed machines. Fix:
default to false, word the toggle as "Store imported data in this browser"
Custom names, type overrides, filters and sort are keyed by column index only, so renaming or filtering column 0 in one file applies to column 0 of every file. Fix: key them by file (or schema) plus column index, as pinned columns already are
clsx, lucide-react, recharts, tailwind-merge, papaparse and @types/papaparse are declared but never
imported. bun audit reports 33 vulnerabilities, all in dev tooling (pm2, Parcel, Jest), the production graph is
clean. Fix: drop unused packages, drop or upgrade pm2
bun run test only runs the build and CI only builds. Fix: unit tests for the parser, filter grammar, type
detection and export, fixture tests on real Fidelity CSVs, run them in CI
The empty-state upload area is a clickable <div> (not reachable by keyboard), per-file import errors only go to
console.error, and invalid JSON or oversized data is reported with alert(). Fix: a real <button> or labeled
control, inline non-blocking notifications with per-file import warnings