@idea1/filekit
v1.0.0
Published
Messy-file reader/writer toolkit (CSV + XLSX) for the close kit and similar agent-driven data pipelines. Pure Node, no dependencies.
Downloads
177
Keywords
Readme
@datafabriq/filekit
A reader and writer for the spreadsheets agent-driven data pipelines depend on — CSV and
XLSX files a client uploads that a downstream process has to parse correctly every time.
Pure Node (fs + zlib), no dependencies, no build step.
const fk = require('@datafabriq/filekit');
fk.parseCsv(text, { headerRow }) // quoted fields, comma-thousands; headerRow skips a preamble
fk.readXlsx(pathOrBuffer) // reads .xlsx directly — the unzip is built in
fk.writeXlsx(path, sheets) // one tab per dataset; row 0 is the header
fk.num(v) // '$1,234.50' → 1234.5; '(312,571.01)' → -312571.01
fk.excelSerialToYM(n) // 46143 → '2026-05'
fk.findMonthColumns(header) // discover a MON YYYY matrix by header, never by index
fk.findColumnBySerialMonth(sheet, headerRow, '2026-05')
fk.findRow(sheet, (row, n) => …) // locate a block by its labelreadXlsx returns real sheet names in workbook order; address a sheet by name
(wb.sheet('GL 24500 Accrued Bonus')) rather than by index. Cells are 1-based and
Excel-shaped: sheet.at(12, 3) is cell C12.
Reading messy source files
Two properties of these files break naive parsers, and both are covered by the tests:
- Month columns move. A commission ledger's
MON YYYYmatrix grows a column each period, and a bonus workbook's month headers are Excel serial dates. Locate the close month by matching the header; a fixed column index silently reads the wrong month. - A cell's value is not always its text. Totals are formula cells whose value lives in
<v>; empty cells are self-closing and carry no value at all; text may be a shared string or an inline string.filekitresolves all four.
Locate a block by the labels around it (Beginning, New Accruals, Payments, Ending,
the GL numbers, etc.) rather than by row number, so an inserted row does not shift the read.
Writing a reference workbook
writeXlsx produces workbooks a Custom Files connector can ingest — one tab per dataset,
snake_case headers on row 1, and conventions bronze expects:
- Dates as literal
YYYY-MM-DDtext, never Excel serials, soTRY_CAST(… AS DATE)holds. - An omitted cell for a null; an empty cell ingests as
NULL,0does not. - Values written as numbers, text as inline strings, XML-escaped.
- Every column ingests as
STRING; the reading spec does theTRY_CAST.
Tests
npm testSelf-contained — every fixture is built in-process, so the suite carries no customer data and runs anywhere. It asserts the cell shapes above: formula cells, self-closing cells, shared strings with entities, serial dates, a header below a nine-row preamble, and a write→read round-trip preserving nulls, negatives, and escaping.
Origin
Extracted from Concept3D's month-end close kit (datafabriq-ops → context/revenue-reporting/close-tools/),
where the same reader already served two teams' file shapes (Concept3D's QuotaPath/bonus
files, Intake's Amazon/Ed's-workbook files) before this package existed.
Publishing
Published as @idea1/filekit (public), same npm org as @idea1/cli. Pushing a
filekit-v*.*.* tag runs .github/workflows/publish-filekit.yml, which runs npm run build
(the test suite) then npm run deploy (npm publish --access public), authenticated via
the NPM_TOKEN repo secret — an npm Automation token for a member of the idea1 npm org.
Bump the version in package.json first, since npm rejects re-publishing an existing version.
