The TypeScript engine for the CSVX specification. Like every engine in this
project, it is specification-first: it implements CSVX behavior, but its internal architecture
does not define the format. See AGENTS.md and ../csvx-spec/AGENTS.md for the binding rules.
The initial pass provides the Phase 1 foundation, same shape as csvx-go:
-
CSVX ZIP package loading and writing (
loadWorkbookFromZip/writeWorkbookToZip, buffer-based — no filesystem access, so these work in a browser as well as Node) -
Filesystem convenience wrappers (
openPackage,writePackage,openDirectory,packageDirectory,extractPackage) — the only place this engine touchesnode:fs -
UTF-8 CSV sheet loading/writing, RFC 4180–compatible
-
Optional
.meta.jsonsheet metadata: formulas, cached values, per-cell styles, validation -
A data model generated from
../csvx-spec/schemas/*.json(src/schema/generated.ts, viacsvx-cli codegen --lang ts), not hand-typed — seeAGENTS.mdfor why that matters -
Zip-slip-safe extraction (absolute/
../NUL-containing entry paths are rejected) -
Structural, load-time validation (
validate()for paths,validateBuffer()for in-memory ZIP data — the latter is browser-safe and exported from./browsertoo) -
A formula engine: parsing, evaluation, workbook-wide recalculation (ranges, cross-sheet references, cycles), and workbook names
-
The edit operations of spec chapter 15 (
insertRows,deleteColumns,setCell,paste,applyStyle,renameSheet, ...), which rewrite formula references, names, validation formulas and print settings as the spec requires -
CSV import (spec 11.1), CSV export (spec 11.2:
exportCSV) and text case conversion -
Node-only helpers that call the
csvxcommand-line tool for XLSX (see "XLSX" below)
Not implemented here: XLSX parsing/writing (see "XLSX" for how to get it), print pagination, and
full JSON-Schema conformance validation (that lives in ../csvx-spec/validator; this engine does
not carry its own copy, per ../csvx-spec/AGENTS.md rule 3.3). Exact-duplicate-ZIP-entry rejection
is a known gap — see the comment on assertSafeEntryNames in src/package.ts.
Each capability follows this sequence:
Specify → create conformance fixtures → implement → run tests
The specification repository is the authority: https://github.com/DevShedLabs/csvx-spec.
npm install @devshedlabs/csvx-ts # once published to npm
npm install github:DevShedLabs/csvx-ts#v0.1.11 --allow-git=all # from a tag; builds on installThe package ships both ESM and CommonJS builds, so import and require() (and
require.resolve) both work, including from an Electron main process. The version in
package.json follows the shared csvx-* tag; scripts/check-version.mjs (run by npm run check)
fails if it falls behind.
In Node:
import { openPackage } from "@devshedlabs/csvx-ts";
const workbook = await openPackage("report.csvx");
console.log(workbook.sheets[0].records);In a browser (e.g. csvx-web), import the /browser subpath instead — the main entry
transitively pulls in node:fs/promises via node.ts, which a bundler can't resolve client-side:
import { loadWorkbookFromZip } from "@devshedlabs/csvx-ts/browser";
const workbook = await loadWorkbookFromZip(await file.arrayBuffer());CSV is the canonical sheet data layer. Metadata that CSV cannot represent is stored in the
matching .meta.json sidecar.
To exercise this library from the command line, use
csvx-cli — this package is a library only; see
AGENTS.md for why CLI-shaped code does not belong here.
This engine does not read or write XLSX. The project keeps exactly one XLSX implementation (in
csvx-go, driven by csvx-cli) so the formats cannot drift apart, and CSVX-to-XLSX export of an
edited workbook is done by csvx-go (via csvx export), not here. There are several ways to get XLSX data into a
TypeScript program; pick by where your code runs:
-
csvxon the machine (recommended for Node). Installcsvx-cliand call it through this package:import { importXLSX, exportXLSX, isCSVXCLIAvailable } from "@devshedlabs/csvx-ts"; if (await isCSVXCLIAvailable()) { const workbook = await importXLSX("report.xlsx"); // runs `csvx import`, then loads the package await exportXLSX("report.csvx", "report.xlsx"); // runs `csvx export` }
The tool is found as
csvxonPATH, or via theCSVX_CLIenvironment variable, or{ cli: "/path/to/csvx" }. If it is missing you get aCSVXCLINotFoundErrorthat says so. These helpers are Node-only and are not part of the/browserentry. -
Convert ahead of time, then load
.csvx. Runcsvx import report.xlsx report.csvxin a build step, a script, or a CI job, and give your program the.csvx. Nothing XLSX-specific remains at runtime, and this works in the browser too (loadWorkbookFromZip). -
A small Go program or service. If you cannot install the CLI, write a few lines of Go that import
csvx-goat the same tag and callcsvx.Convert("report.xlsx", "report.csvx"), run it as a sidecar process or behind an HTTP endpoint, and load its output here. Prefer route 1 unless you need to embed the conversion in your own Go service, since the CLI is that program already. -
A browser app cannot run a CLI. Use route 2 (convert before upload) or route 3 (a server endpoint that converts and returns the
.csvx), and keep XLSX parsing out of the client.
If your workload is mostly XLSX in and out, consider using csvx-go directly: it has the same
edit and formula operations as this package and also imports XLSX.
npm install # install dependencies
npm run codegen # regenerate src/schema/generated.ts from ../csvx-spec/schemas
npx tsc --noEmit # type-check
npx vitest run # run tests (includes real csvx-spec/examples fixtures + schema validation)
npm run build # compile to dist/scripts/check.sh runs the same checks CI would (type-check, test, build). Run it any time:
./scripts/check.shA git hook runs it automatically before every push, blocking the push if it fails. Enable it once per clone (this is local git config, not something that comes from cloning the repo):
git config core.hooksPath .githooksSkip in a genuine emergency with git push --no-verify — prefer fixing the failure instead. See
../csvx-spec/AGENTS.md section 6 for why this exists: it's the interim stand-in for real CI.