Skip to content

Commit cbdd464

Browse files
committed
Initial JSON CSV package
0 parents  commit cbdd464

15 files changed

Lines changed: 2366 additions & 0 deletions

.github/workflows/ci.yml

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
name: CI
2+
3+
on:
4+
push:
5+
branches:
6+
- main
7+
pull_request:
8+
branches:
9+
- main
10+
11+
permissions:
12+
contents: read
13+
14+
jobs:
15+
test:
16+
name: Test on Node ${{ matrix.node-version }}
17+
runs-on: ubuntu-latest
18+
19+
strategy:
20+
fail-fast: false
21+
matrix:
22+
node-version:
23+
- 20
24+
- 22
25+
26+
steps:
27+
- name: Check out repository
28+
uses: actions/checkout@v4
29+
30+
- name: Set up Node
31+
uses: actions/setup-node@v4
32+
with:
33+
node-version: ${{ matrix.node-version }}
34+
cache: npm
35+
36+
- name: Install dependencies
37+
run: npm ci
38+
39+
- name: Typecheck
40+
run: npm run typecheck
41+
42+
- name: Build
43+
run: npm run build
44+
45+
- name: Test
46+
run: npm test

.gitignore

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
node_modules/
2+
dist/
3+
.DS_Store
4+
.deploy_key*

CHANGELOG.md

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
# Changelog
2+
3+
All notable changes to this package are documented here.
4+
5+
## 0.1.0 - 2026-05-12
6+
7+
- Initial release with JSON records to CSV conversion.
8+
- Added automatic column inference, nested object flattening and explicit columns.
9+
- Added robust CSV escaping, formula escaping, circular reference handling and browser/Node-friendly ESM output.

LICENSE

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
MIT License
2+
3+
Copyright (c) 2026 Recoveredd
4+
5+
Permission is hereby granted, free of charge, to any person obtaining a copy
6+
of this software and associated documentation files (the "Software"), to deal
7+
in the Software without restriction, including without limitation the rights
8+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9+
copies of the Software, and to permit persons to whom the Software is
10+
furnished to do so, subject to the following conditions:
11+
12+
The above copyright notice and this permission notice shall be included in all
13+
copies or substantial portions of the Software.
14+
15+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21+
SOFTWARE.

README.md

Lines changed: 232 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,232 @@
1+
# json-csv-kit
2+
3+
[![CI](https://github.com/Recoveredd/json-csv-kit/actions/workflows/ci.yml/badge.svg)](https://github.com/Recoveredd/json-csv-kit/actions/workflows/ci.yml)
4+
5+
Convert JSON records to clean CSV with TypeScript-first options.
6+
7+
`json-csv-kit` is a small utility for exports, admin tools, reports, support dashboards, docs generators and browser-based data tools. It keeps the common JSON-to-CSV path simple while leaving room for explicit columns, nested data and safe CSV escaping.
8+
9+
## Package quality
10+
11+
- TypeScript types are generated from the source.
12+
- ESM-only package with no runtime dependencies.
13+
- Marked as side-effect free for bundlers.
14+
- Tested on Node.js 20 and 22 with GitHub Actions.
15+
- Works in Node.js, browsers, Vite apps and static docs tooling.
16+
17+
## Install
18+
19+
```bash
20+
npm install json-csv-kit
21+
```
22+
23+
## Quick Start
24+
25+
```ts
26+
import { jsonToCsv } from 'json-csv-kit';
27+
28+
const csv = jsonToCsv([
29+
{ name: 'Ada', role: 'Engineer' },
30+
{ name: 'Grace', role: 'Admiral' }
31+
]);
32+
33+
console.log(csv);
34+
```
35+
36+
```csv
37+
name,role
38+
Ada,Engineer
39+
Grace,Admiral
40+
```
41+
42+
Nested plain objects are flattened by default:
43+
44+
```ts
45+
jsonToCsv([
46+
{
47+
customer: {
48+
name: 'Northwind',
49+
region: 'EU'
50+
},
51+
total: 120
52+
}
53+
]);
54+
```
55+
56+
```csv
57+
customer.name,customer.region,total
58+
Northwind,EU,120
59+
```
60+
61+
## Which API should I use?
62+
63+
| Function | Use it when you need |
64+
| --- | --- |
65+
| `jsonToCsv` | convert an array of records to a CSV string |
66+
| `toCsv` | short alias for `jsonToCsv` |
67+
| `inferCsvColumns` | inspect the columns that would be generated |
68+
| `flattenRecord` | flatten one nested object into dot-path keys |
69+
| `escapeCsvCell` | escape a single cell before composing CSV yourself |
70+
71+
## Explicit columns
72+
73+
Use explicit columns when you need stable order, custom headers or a subset of fields.
74+
75+
```ts
76+
jsonToCsv(rows, {
77+
columns: [
78+
{ key: 'customer', header: 'Customer', path: 'customer.name' },
79+
{ key: 'region', header: 'Region', path: 'customer.region' },
80+
{ key: 'total', header: 'Total' }
81+
]
82+
});
83+
```
84+
85+
Use an accessor for custom logic or when paths need bracket notation:
86+
87+
```ts
88+
jsonToCsv(rows, {
89+
columns: [
90+
{
91+
key: 'city',
92+
header: 'City',
93+
accessor: (row) => row.customer?.['billing.address']?.city
94+
}
95+
]
96+
});
97+
```
98+
99+
Format a column before CSV escaping:
100+
101+
```ts
102+
jsonToCsv(rows, {
103+
columns: [
104+
{
105+
key: 'total',
106+
accessor: (row) => row.totalCents,
107+
formatter: (value) => `$${Number(value) / 100}`
108+
}
109+
]
110+
});
111+
```
112+
113+
## CSV safety
114+
115+
Values are escaped according to normal CSV rules:
116+
117+
- fields containing the delimiter are quoted
118+
- fields containing newlines are quoted
119+
- quotes inside quoted fields are doubled
120+
121+
```ts
122+
jsonToCsv([{ name: 'Ada, Lovelace', note: 'Line 1\n"Line 2"' }]);
123+
```
124+
125+
```csv
126+
name,note
127+
"Ada, Lovelace","Line 1
128+
""Line 2"""
129+
```
130+
131+
When exporting to spreadsheets, use `escapeFormulae` to reduce formula-injection risk:
132+
133+
```ts
134+
jsonToCsv([{ value: '=SUM(A1:A2)' }], {
135+
escapeFormulae: true
136+
});
137+
```
138+
139+
```csv
140+
value
141+
'=SUM(A1:A2)
142+
```
143+
144+
## Options
145+
146+
```ts
147+
interface JsonToCsvOptions<TRecord> {
148+
columns?: Array<string | CsvColumn<TRecord>>;
149+
includeHeaders?: boolean;
150+
flatten?: boolean;
151+
sortColumns?: boolean;
152+
delimiter?: string;
153+
newline?: string;
154+
quote?: string;
155+
nullValue?: string;
156+
arrayMode?: 'json' | 'join' | 'empty';
157+
arraySeparator?: string;
158+
escapeFormulae?: boolean | string;
159+
dateFormatter?: (date: Date) => string;
160+
}
161+
```
162+
163+
| Option | Default | Meaning |
164+
| --- | --- | --- |
165+
| `columns` | inferred | explicit column list |
166+
| `includeHeaders` | `true` | include the first header row |
167+
| `flatten` | `true` | flatten nested plain objects into dot paths |
168+
| `sortColumns` | `false` | sort inferred columns alphabetically |
169+
| `delimiter` | `','` | field delimiter |
170+
| `newline` | `'\n'` | line separator |
171+
| `quote` | `'"'` | quote character |
172+
| `nullValue` | `''` | output for `null` and `undefined` |
173+
| `arrayMode` | `'json'` | format arrays as JSON, joined text or empty |
174+
| `arraySeparator` | `', '` | separator used by `arrayMode: 'join'` |
175+
| `escapeFormulae` | `false` | prefix spreadsheet-like formulas |
176+
| `dateFormatter` | ISO string | format `Date` values |
177+
178+
## Ecosystem recipes
179+
180+
Use with `object-key-paths` to inspect columns before exporting:
181+
182+
```ts
183+
import { getLeafPaths } from 'object-key-paths';
184+
import { jsonToCsv } from 'json-csv-kit';
185+
186+
const columns = getLeafPaths(report).map((path) => ({
187+
key: path,
188+
header: path
189+
}));
190+
191+
const csv = jsonToCsv([report], { columns });
192+
```
193+
194+
Use with `object-path-kit` when source paths need bracket notation:
195+
196+
```ts
197+
import { getPath } from 'object-path-kit';
198+
import { jsonToCsv } from 'json-csv-kit';
199+
200+
const csv = jsonToCsv(rows, {
201+
columns: [
202+
{
203+
key: 'city',
204+
header: 'City',
205+
accessor: (row) => getPath(row, 'customer["billing.address"].city')
206+
}
207+
]
208+
});
209+
```
210+
211+
Use with `array-table-kit` when you need both Markdown and CSV exports from the same records:
212+
213+
```ts
214+
import { arrayToMarkdownTable } from 'array-table-kit';
215+
import { jsonToCsv } from 'json-csv-kit';
216+
217+
const markdown = arrayToMarkdownTable(rows);
218+
const csv = jsonToCsv(rows);
219+
```
220+
221+
## Notes
222+
223+
- Input must be an array of plain objects.
224+
- Dot paths are intentionally simple. Use `accessor` or `object-path-kit` for bracket notation and keys containing dots.
225+
- Arrays are serialized as JSON by default so no information is lost.
226+
- `BigInt` values inside arrays or objects are converted to strings during JSON serialization.
227+
- Circular references are represented as `[Circular]` instead of crashing the export.
228+
- Class instances, `Map`, `Set` and other non-plain objects are serialized as JSON when possible.
229+
230+
## License
231+
232+
MIT

0 commit comments

Comments
 (0)