jtcsv 2.1.3 → 2.1.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +60 -341
- package/csv-to-json.js +35 -26
- package/dist/jtcsv.cjs.js +807 -133
- package/dist/jtcsv.cjs.js.map +1 -1
- package/dist/jtcsv.esm.js +800 -134
- package/dist/jtcsv.esm.js.map +1 -1
- package/dist/jtcsv.umd.js +807 -133
- package/dist/jtcsv.umd.js.map +1 -1
- package/errors.js +20 -0
- package/examples/browser-vanilla.html +37 -0
- package/examples/cli-batch-processing.js +38 -0
- package/examples/simple-usage.js +10 -7
- package/examples/web-workers-advanced.js +28 -0
- package/json-save.js +2 -1
- package/package.json +8 -4
- package/plugins/README.md +41 -467
- package/plugins/express-middleware/README.md +32 -274
- package/plugins/hono/README.md +16 -13
- package/plugins/nestjs/README.md +13 -11
- package/plugins/nextjs-api/README.md +28 -423
- package/plugins/nextjs-api/index.js +1 -2
- package/plugins/nextjs-api/route.js +1 -2
- package/plugins/nuxt/README.md +6 -7
- package/plugins/remix/README.md +9 -9
- package/plugins/sveltekit/README.md +8 -8
- package/plugins/trpc/README.md +8 -5
- package/src/browser/browser-functions.js +33 -3
- package/src/browser/csv-to-json-browser.js +269 -11
- package/src/browser/errors-browser.js +19 -1
- package/src/browser/index.js +39 -5
- package/src/browser/streams.js +393 -0
- package/src/browser/workers/csv-parser.worker.js +20 -2
- package/src/browser/workers/worker-pool.js +507 -447
- package/src/core/plugin-system.js +4 -0
- package/src/engines/fast-path-engine.js +31 -23
- package/src/formats/ndjson-parser.js +54 -5
- package/src/formats/tsv-parser.js +4 -1
- package/stream-csv-to-json.js +11 -2
- package/stream-json-to-csv.js +13 -1
package/README.md
CHANGED
|
@@ -1,172 +1,48 @@
|
|
|
1
|
-
# jtcsv -
|
|
1
|
+
# jtcsv - JSON <-> CSV toolkit for Node.js and browser
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
[jtcsv
|
|
3
|
+
[](https://www.npmjs.com/package/jtcsv)
|
|
6
4
|
[](https://opensource.org/licenses/MIT)
|
|
7
|
-
[](https://www.npmjs.com/package/jtcsv
|
|
8
|
-
|
|
9
|
-
A lightweight, efficient, and secure library for converting between JSON and CSV formats with full browser support, Web Workers for large files, and streaming capabilities.
|
|
10
|
-
Zero-deps core with optional add-ons (TUI, Excel) for advanced workflows.
|
|
11
|
-
|
|
12
|
-
## ✨ Features
|
|
13
|
-
|
|
14
|
-
### 🚀 Core Features
|
|
15
|
-
- **Bidirectional Conversion**: JSON ↔ CSV with full type preservation
|
|
16
|
-
- **Zero-Deps Core**: Pure JavaScript/TypeScript core with optional add-ons
|
|
17
|
-
- **TypeScript Support**: Full type definitions included
|
|
18
|
-
- **Security First**: Built-in CSV injection protection
|
|
19
|
-
- **RFC 4180 Compliant**: Proper CSV formatting and escaping
|
|
20
|
-
|
|
21
|
-
### 🌐 Browser Support
|
|
22
|
-
- **Full Browser Compatibility**: Chrome, Firefox, Safari, Edge, Mobile
|
|
23
|
-
- **Web Workers**: Process large files without blocking UI
|
|
24
|
-
- **File API Integration**: Direct file upload/download support
|
|
25
|
-
- **Streaming Processing**: Handle files of any size
|
|
26
|
-
- **Progress Tracking**: Real-time progress updates
|
|
5
|
+
[](https://www.npmjs.com/package/jtcsv)
|
|
27
6
|
|
|
28
|
-
|
|
29
|
-
- **High Speed**: Optimized parsing algorithms
|
|
30
|
-
- **Memory Efficient**: Streaming and chunked processing
|
|
31
|
-
- **Worker Pool**: Reusable Web Workers for parallel processing
|
|
32
|
-
- **Caching**: Intelligent caching for repeated operations
|
|
7
|
+
Fast JSON <-> CSV conversion with streaming helpers, NDJSON/TSV support, and optional integrations.
|
|
33
8
|
|
|
34
|
-
|
|
35
|
-
-
|
|
36
|
-
-
|
|
37
|
-
-
|
|
38
|
-
-
|
|
39
|
-
-
|
|
9
|
+
## Features
|
|
10
|
+
- JSON <-> CSV conversion with security defaults
|
|
11
|
+
- Streaming helpers and async iterator API
|
|
12
|
+
- NDJSON and TSV helpers
|
|
13
|
+
- Browser bundle with Web Worker helpers
|
|
14
|
+
- Optional plugin system and framework adapters
|
|
15
|
+
- CLI and optional TUI
|
|
40
16
|
|
|
41
|
-
|
|
42
|
-
- **NestJS**: `@jtcsv/nestjs`
|
|
43
|
-
- **Remix**: `@jtcsv/remix`
|
|
44
|
-
- **Nuxt**: `@jtcsv/nuxt`
|
|
45
|
-
- **SvelteKit**: `@jtcsv/sveltekit`
|
|
46
|
-
- **Hono**: `@jtcsv/hono`
|
|
47
|
-
- **tRPC**: `@jtcsv/trpc`
|
|
48
|
-
|
|
49
|
-
## 📦 Installation
|
|
50
|
-
|
|
51
|
-
### Node.js
|
|
17
|
+
## Installation
|
|
52
18
|
```bash
|
|
53
19
|
npm install jtcsv
|
|
54
20
|
```
|
|
55
21
|
|
|
56
22
|
### Optional add-ons
|
|
57
23
|
```bash
|
|
58
|
-
# Terminal UI
|
|
59
24
|
npm install @jtcsv/tui
|
|
60
|
-
|
|
61
|
-
# Excel plugin
|
|
62
25
|
npm install @jtcsv/excel exceljs
|
|
26
|
+
npm install @jtcsv/validator
|
|
63
27
|
```
|
|
64
28
|
|
|
65
|
-
|
|
66
|
-
```html
|
|
67
|
-
<!-- UMD version (global jtcsv variable) -->
|
|
68
|
-
<script src="https://cdn.jsdelivr.net/npm/jtcsvst/jtcsv.umd.js"></script>
|
|
69
|
-
|
|
70
|
-
<!-- ESM version -->
|
|
71
|
-
<script type="module">
|
|
72
|
-
import { jsonToCsv } from 'https://cdn.jsdelivr.net/npm/jtcsvst/jtcsv.esm.js';
|
|
73
|
-
</script>
|
|
74
|
-
```
|
|
75
|
-
|
|
76
|
-
## 🚀 Quick Start
|
|
77
|
-
|
|
78
|
-
### Node.js Usage
|
|
29
|
+
## Quick start (Node.js)
|
|
79
30
|
```javascript
|
|
80
|
-
const { jsonToCsv, csvToJson } = require('jtcsv
|
|
31
|
+
const { jsonToCsv, csvToJson } = require('jtcsv');
|
|
81
32
|
|
|
82
|
-
// JSON to CSV
|
|
83
33
|
const data = [
|
|
84
34
|
{ id: 1, name: 'John', email: 'john@example.com' },
|
|
85
35
|
{ id: 2, name: 'Jane', email: 'jane@example.com' }
|
|
86
36
|
];
|
|
87
37
|
|
|
88
|
-
const csv = jsonToCsv(data, {
|
|
89
|
-
|
|
90
|
-
includeHeaders: true,
|
|
91
|
-
preventCsvInjection: true
|
|
92
|
-
});
|
|
38
|
+
const csv = jsonToCsv(data, { delimiter: ',', includeHeaders: true });
|
|
39
|
+
const json = csvToJson(csv, { delimiter: ',', parseNumbers: true });
|
|
93
40
|
|
|
94
41
|
console.log(csv);
|
|
95
|
-
// id,name,email
|
|
96
|
-
// 1,John,john@example.com
|
|
97
|
-
// 2,Jane,jane@example.com
|
|
98
|
-
|
|
99
|
-
// CSV to JSON
|
|
100
|
-
const csvString = 'id,name,email\n1,John,john@example.com\n2,Jane,jane@example.com';
|
|
101
|
-
const json = csvToJson(csvString, {
|
|
102
|
-
delimiter: ',',
|
|
103
|
-
parseNumbers: true
|
|
104
|
-
});
|
|
105
|
-
|
|
106
42
|
console.log(json);
|
|
107
|
-
// [
|
|
108
|
-
// { id: 1, name: 'John', email: 'john@example.com' },
|
|
109
|
-
// { id: 2, name: 'Jane', email: 'jane@example.com' }
|
|
110
|
-
// ]
|
|
111
|
-
```
|
|
112
|
-
|
|
113
|
-
### Browser Usage
|
|
114
|
-
```javascript
|
|
115
|
-
// Using global variable (UMD)
|
|
116
|
-
const csv = window.jtcsv.jsonToCsv(data, { delimiter: ',' });
|
|
117
|
-
|
|
118
|
-
// Download as file
|
|
119
|
-
window.jtcsv.downloadAsCsv(data, 'export.csv', { delimiter: ',' });
|
|
120
|
-
|
|
121
|
-
// Parse uploaded file
|
|
122
|
-
const fileInput = document.querySelector('input[type="file"]');
|
|
123
|
-
const json = await window.jtcsv.parseCsvFile(fileInput.files[0], {
|
|
124
|
-
delimiter: ',',
|
|
125
|
-
parseNumbers: true
|
|
126
|
-
});
|
|
127
|
-
|
|
128
|
-
// Use Web Workers for large files
|
|
129
|
-
const largeFile = document.querySelector('input[type="file"]').files[0];
|
|
130
|
-
const result = await window.jtcsv.parseCSVWithWorker(largeFile, {}, (progress) => {
|
|
131
|
-
console.log(`Progress: ${progress.percentage.toFixed(1)}%`);
|
|
132
|
-
});
|
|
133
43
|
```
|
|
134
44
|
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
### Core Functions
|
|
138
|
-
|
|
139
|
-
#### `jsonToCsv(data, options)`
|
|
140
|
-
Converts an array of objects to CSV string.
|
|
141
|
-
|
|
142
|
-
**Options:**
|
|
143
|
-
- `delimiter` (string, default: ';'): CSV delimiter character
|
|
144
|
-
- `includeHeaders` (boolean, default: true): Include header row
|
|
145
|
-
- `renameMap` (object): Map for renaming column headers
|
|
146
|
-
- `preventCsvInjection` (boolean, default: true): Escape formulas for security
|
|
147
|
-
- `rfc4180Compliant` (boolean, default: true): RFC 4180 compliance
|
|
148
|
-
- `maxRecords` (number): Maximum records to process
|
|
149
|
-
|
|
150
|
-
#### `csvToJson(csv, options)`
|
|
151
|
-
Converts CSV string to array of objects.
|
|
152
|
-
|
|
153
|
-
**Options:**
|
|
154
|
-
Fast path parsing is the default pipeline; use `fastPathMode` to control row shape.
|
|
155
|
-
- `delimiter` (string): Delimiter (auto-detected if not specified)
|
|
156
|
-
- `autoDetect` (boolean, default: true): Auto-detect delimiter
|
|
157
|
-
- `hasHeaders` (boolean, default: true): CSV has header row
|
|
158
|
-
- `parseNumbers` (boolean, default: false): Parse numeric values
|
|
159
|
-
- `parseBooleans` (boolean, default: false): Parse boolean values
|
|
160
|
-
- `trim` (boolean, default: true): Trim whitespace
|
|
161
|
-
- `maxRows` (number): Maximum rows to process
|
|
162
|
-
- `useFastPath` (boolean, default: true): Enable fast-path parser (set `false` to force quote-aware path)
|
|
163
|
-
- `fastPathMode` (string, default: 'objects'): `'objects'` for object rows, `'compact'` for arrays (lower memory), `'stream'` to return an async iterator
|
|
164
|
-
|
|
165
|
-
#### `csvToJsonIterator(csv, options)`
|
|
166
|
-
Convert CSV to JSON rows as an async iterator for large inputs.
|
|
167
|
-
You can also call `csvToJson(csv, { fastPathMode: 'stream' })` to get the same async iterator.
|
|
168
|
-
|
|
169
|
-
**Example:**
|
|
45
|
+
### Async iterator
|
|
170
46
|
```javascript
|
|
171
47
|
const { csvToJsonIterator } = require('jtcsv');
|
|
172
48
|
|
|
@@ -176,222 +52,65 @@ for await (const row of csvToJsonIterator(csv, { fastPathMode: 'compact' })) {
|
|
|
176
52
|
}
|
|
177
53
|
```
|
|
178
54
|
|
|
179
|
-
|
|
55
|
+
## Browser usage
|
|
56
|
+
- Bundler: `import { csvToJson, jsonToCsv } from 'jtcsv/browser';`
|
|
57
|
+
- CDN UMD: `https://cdn.jsdelivr.net/npm/jtcsv/dist/jtcsv.umd.js`
|
|
58
|
+
- CDN ESM: `https://cdn.jsdelivr.net/npm/jtcsv/dist/jtcsv.esm.js`
|
|
180
59
|
|
|
181
|
-
|
|
182
|
-
Converts and downloads JSON as CSV file.
|
|
60
|
+
See `README-browser.md` for full browser API and worker helpers.
|
|
183
61
|
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
#### `parseCsvBlob(blob, options)`
|
|
191
|
-
Parses CSV Blob to JSON.
|
|
192
|
-
|
|
193
|
-
### Web Workers Functions
|
|
194
|
-
|
|
195
|
-
#### `createWorkerPool(options)`
|
|
196
|
-
Creates a pool of Web Workers for parallel processing.
|
|
62
|
+
## CLI
|
|
63
|
+
```bash
|
|
64
|
+
npx jtcsv csv-to-json input.csv output.json
|
|
65
|
+
npx jtcsv json-to-csv input.json output.csv
|
|
66
|
+
npx jtcsv stream csv-to-json big.csv output.json
|
|
67
|
+
npx jtcsv batch json-to-csv "data/*.json" output/
|
|
197
68
|
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
- `autoScale` (boolean, default: true): Auto-scale workers
|
|
202
|
-
- `idleTimeout` (number, default: 60000): Idle timeout in ms
|
|
69
|
+
# optional TUI
|
|
70
|
+
npx jtcsv tui
|
|
71
|
+
```
|
|
203
72
|
|
|
204
|
-
|
|
205
|
-
Parses CSV using Web Workers with progress tracking.
|
|
73
|
+
See `CLI.md` for full command list and options.
|
|
206
74
|
|
|
207
|
-
##
|
|
75
|
+
## Demos
|
|
76
|
+
Run these from the repo root:
|
|
77
|
+
```bash
|
|
78
|
+
# Express API demo
|
|
79
|
+
npm run demo
|
|
208
80
|
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
import React, { useState } from 'react';
|
|
212
|
-
import { parseCsvFile, downloadAsCsv } from 'jtcsv
|
|
81
|
+
# Web demo (Vite dev server on http://localhost:3000)
|
|
82
|
+
npm run demo:web
|
|
213
83
|
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
const [loading, setLoading] = useState(false);
|
|
217
|
-
|
|
218
|
-
const handleFileUpload = async (event) => {
|
|
219
|
-
const file = event.target.files[0];
|
|
220
|
-
if (!file) return;
|
|
221
|
-
|
|
222
|
-
setLoading(true);
|
|
223
|
-
try {
|
|
224
|
-
const jsonData = await parseCsvFile(file, {
|
|
225
|
-
delimiter: ',',
|
|
226
|
-
parseNumbers: true
|
|
227
|
-
});
|
|
228
|
-
setData(jsonData);
|
|
229
|
-
} catch (error) {
|
|
230
|
-
console.error('Error:', error);
|
|
231
|
-
} finally {
|
|
232
|
-
setLoading(false);
|
|
233
|
-
}
|
|
234
|
-
};
|
|
235
|
-
|
|
236
|
-
const handleExport = () => {
|
|
237
|
-
downloadAsCsv(data, 'export.csv', { delimiter: ',' });
|
|
238
|
-
};
|
|
239
|
-
|
|
240
|
-
return (
|
|
241
|
-
<div>
|
|
242
|
-
<input type="file" accept=".csv" onChange={handleFileUpload} />
|
|
243
|
-
<button onClick={handleExport} disabled={!data.length}>
|
|
244
|
-
Export to CSV
|
|
245
|
-
</button>
|
|
246
|
-
{loading && <div>Processing...</div>}
|
|
247
|
-
<pre>{JSON.stringify(data.slice(0, 5), null, 2)}</pre>
|
|
248
|
-
</div>
|
|
249
|
-
);
|
|
250
|
-
}
|
|
84
|
+
# Preview built demo
|
|
85
|
+
npm run demo:serve
|
|
251
86
|
```
|
|
252
87
|
|
|
253
|
-
|
|
254
|
-
```
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
const progressBar = document.getElementById('progress-bar');
|
|
259
|
-
const status = document.getElementById('status');
|
|
260
|
-
|
|
261
|
-
try {
|
|
262
|
-
const result = await parseCSVWithWorker(file, {}, (progress) => {
|
|
263
|
-
const percent = Math.round(progress.percentage);
|
|
264
|
-
progressBar.style.width = percent + '%';
|
|
265
|
-
progressBar.textContent = percent + '%';
|
|
266
|
-
|
|
267
|
-
status.textContent =
|
|
268
|
-
`Processing: ${progress.processed.toLocaleString()} of ${progress.total.toLocaleString()} rows ` +
|
|
269
|
-
`(${Math.round(progress.speed)} rows/sec)`;
|
|
270
|
-
});
|
|
271
|
-
|
|
272
|
-
status.textContent = `Processed ${result.length.toLocaleString()} rows successfully`;
|
|
273
|
-
return result;
|
|
274
|
-
} catch (error) {
|
|
275
|
-
status.textContent = `Error: ${error.message}`;
|
|
276
|
-
throw error;
|
|
277
|
-
}
|
|
278
|
-
}
|
|
88
|
+
From inside `demo/` use:
|
|
89
|
+
```bash
|
|
90
|
+
npm run dev
|
|
91
|
+
npm run preview
|
|
92
|
+
npm run serve
|
|
279
93
|
```
|
|
280
94
|
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
const dangerousData = [
|
|
284
|
-
{ formula: '=SUM(1,2)', command: '=cmd|"/c calc"!A1' }
|
|
285
|
-
];
|
|
95
|
+
## Plugin system
|
|
96
|
+
The plugin-enabled API is exported from `jtcsv/plugins`.
|
|
286
97
|
|
|
287
|
-
|
|
288
|
-
const
|
|
289
|
-
// formula,command
|
|
290
|
-
// "'=SUM(1,2)","'=cmd|"/c calc"!A1"
|
|
291
|
-
// Formulas are prefixed with single quote to prevent execution
|
|
98
|
+
```javascript
|
|
99
|
+
const { create } = require('jtcsv/plugins');
|
|
292
100
|
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
// formula,command
|
|
296
|
-
// =SUM(1,2),=cmd|"/c calc"!A1
|
|
297
|
-
// WARNING: This could execute commands in Excel!
|
|
101
|
+
const jtcsv = create();
|
|
102
|
+
jtcsv.use('my-plugin', { name: 'My Plugin', version: '1.0.0' });
|
|
298
103
|
```
|
|
299
104
|
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
### Benchmark Results (Node.js 22, 10K rows/records)
|
|
303
|
-
|
|
304
|
-
**CSV → JSON (10K rows)**
|
|
105
|
+
See `README-PLUGINS.md` and `plugins/README.md` for integrations.
|
|
305
106
|
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
| **JTCSV (FastPath Compact)** | 16.79 ms | 4.47 MB | 🥇 1st |
|
|
309
|
-
| **JTCSV (FastPath Stream)** | 18.27 ms | 6.03 MB | 🥈 2nd |
|
|
310
|
-
| **JTCSV** | 19.76 ms | 8.96 MB | 🥉 3rd |
|
|
311
|
-
| PapaParse | 21.57 ms | 6.97 MB | 4th |
|
|
312
|
-
| csv-parser | 30.52 ms | 6.53 MB | 5th |
|
|
313
|
-
|
|
314
|
-
**JSON → CSV (10K records)**
|
|
315
|
-
|
|
316
|
-
| Library | Time | Memory | Rank |
|
|
317
|
-
|---------|------|--------|------|
|
|
318
|
-
| **JTCSV** | 11.21 ms | 4.77 MB | 🥇 1st |
|
|
319
|
-
| json2csv | 12.27 ms | 12.11 MB | 🥈 2nd |
|
|
320
|
-
|
|
321
|
-
### Scaling (JTCSV only)
|
|
322
|
-
|
|
323
|
-
| Rows/Records | CSV→JSON Time (FastPath Compact) | JSON→CSV Time (JTCSV) | CSV→JSON Memory | JSON→CSV Memory |
|
|
324
|
-
|--------------|----------------------------------|-----------------------|-----------------|-----------------|
|
|
325
|
-
| 1,000 | 2.06 ms | 1.04 ms | 2.15 MB | 0.52 MB |
|
|
326
|
-
| 10,000 | 14.68 ms | 8.23 ms | 2.11 MB | 4.14 MB |
|
|
327
|
-
| 100,000 | 164.18 ms | 90.93 ms | 44.93 MB | 34.79 MB |
|
|
328
|
-
|
|
329
|
-
See `BENCHMARK-RESULTS.md` and `docs/PERFORMANCE.md` for environment details and methodology.
|
|
330
|
-
|
|
331
|
-
## 🛠️ Development
|
|
332
|
-
|
|
333
|
-
### Building from Source
|
|
107
|
+
## Development
|
|
108
|
+
Run from the repo root:
|
|
334
109
|
```bash
|
|
335
|
-
# Clone repository
|
|
336
|
-
git clone https://github.com/Linol-Hamelton/jtcsv.git
|
|
337
|
-
cd jtcsv
|
|
338
|
-
|
|
339
|
-
# Install dependencies
|
|
340
|
-
npm install
|
|
341
|
-
|
|
342
|
-
# Build browser version
|
|
343
|
-
npm run build
|
|
344
|
-
|
|
345
|
-
# Run tests
|
|
346
110
|
npm test
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
npm run demo
|
|
350
|
-
```
|
|
351
|
-
|
|
352
|
-
### Project Structure
|
|
353
|
-
```
|
|
354
|
-
jtcsv/
|
|
355
|
-
├── src/browser/ # Browser-specific code
|
|
356
|
-
│ ├── index.js # Browser entry point
|
|
357
|
-
│ ├── *.js # Browser modules
|
|
358
|
-
│ └── workers/ # Web Workers implementation
|
|
359
|
-
├── dist/ # Built distributions
|
|
360
|
-
│ ├── jtcsv.umd.js # UMD bundle
|
|
361
|
-
│ ├── jtcsv.esm.js # ESM bundle
|
|
362
|
-
│ └── jtcsv.cjs.js # CJS bundle
|
|
363
|
-
├── demo/ # Demo application
|
|
364
|
-
├── __tests__/ # Test files
|
|
365
|
-
├── rollup.config.mjs # Build configuration
|
|
366
|
-
└── package.json # Project configuration
|
|
111
|
+
npm run test:coverage
|
|
112
|
+
npm run build
|
|
367
113
|
```
|
|
368
114
|
|
|
369
|
-
##
|
|
370
|
-
|
|
371
|
-
Contributions are welcome! Please feel free to submit a Pull Request.
|
|
372
|
-
|
|
373
|
-
1. Fork the repository
|
|
374
|
-
2. Create your feature branch (`git checkout -b feature/amazing-feature`)
|
|
375
|
-
3. Commit your changes (`git commit -m 'Add some amazing feature'`)
|
|
376
|
-
4. Push to the branch (`git push origin feature/amazing-feature`)
|
|
377
|
-
5. Open a Pull Request
|
|
378
|
-
|
|
379
|
-
## 📄 License
|
|
380
|
-
|
|
381
|
-
This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.
|
|
382
|
-
|
|
383
|
-
## 🙏 Acknowledgments
|
|
384
|
-
|
|
385
|
-
- Inspired by the need for secure, efficient CSV processing in browsers
|
|
386
|
-
- Thanks to all contributors who have helped improve this library
|
|
387
|
-
- Special thanks to the open source community for invaluable tools and libraries
|
|
388
|
-
|
|
389
|
-
## 📞 Support
|
|
390
|
-
|
|
391
|
-
- **GitHub Issues**: [Report bugs or request features](https://github.com/Linol-Hamelton/jtcsv/issues)
|
|
392
|
-
- **Documentation**: [Full API documentation](https://github.com/Linol-Hamelton/jtcsv#readme)
|
|
393
|
-
- **Examples**: [Example code and demos](https://github.com/Linol-Hamelton/jtcsv/tree/main/demo)
|
|
394
|
-
|
|
395
|
-
---
|
|
396
|
-
|
|
397
|
-
**Happy coding!** If you find this library useful, please consider giving it a star on GitHub ⭐
|
|
115
|
+
## License
|
|
116
|
+
MIT. See `LICENSE`.
|
package/csv-to-json.js
CHANGED
|
@@ -114,8 +114,9 @@ function validateCsvInput(csv, options) {
|
|
|
114
114
|
* Parses a value based on options
|
|
115
115
|
* @private
|
|
116
116
|
*/
|
|
117
|
-
function parseCsvValue(value, options) {
|
|
118
|
-
|
|
117
|
+
function parseCsvValue(value, options) {
|
|
118
|
+
/* istanbul ignore next */
|
|
119
|
+
const { trim = true, parseNumbers = false, parseBooleans = false } = options;
|
|
119
120
|
|
|
120
121
|
let result = value;
|
|
121
122
|
|
|
@@ -131,10 +132,11 @@ function parseCsvValue(value, options) {
|
|
|
131
132
|
// Parse numbers
|
|
132
133
|
if (parseNumbers && /^-?\d+(\.\d+)?$/.test(result)) {
|
|
133
134
|
const num = parseFloat(result);
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
135
|
+
/* istanbul ignore next */
|
|
136
|
+
if (!isNaN(num)) {
|
|
137
|
+
return num;
|
|
138
|
+
}
|
|
139
|
+
}
|
|
138
140
|
|
|
139
141
|
// Parse booleans
|
|
140
142
|
if (parseBooleans) {
|
|
@@ -342,12 +344,13 @@ function csvToJson(csv, options = {}) {
|
|
|
342
344
|
console.warn(`[jtcsv] Line ${totalRows}: ${fields.length - headers.length} extra fields ignored`);
|
|
343
345
|
}
|
|
344
346
|
});
|
|
345
|
-
} catch (error) {
|
|
346
|
-
if (error && error.code === 'FAST_PATH_UNCLOSED_QUOTES') {
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
347
|
+
} catch (error) {
|
|
348
|
+
if (error && error.code === 'FAST_PATH_UNCLOSED_QUOTES') {
|
|
349
|
+
const lineInfo = error.lineNumber ? ` at line ${error.lineNumber}` : '';
|
|
350
|
+
throw new ParsingError(`Unclosed quotes in CSV${lineInfo}`, error.lineNumber);
|
|
351
|
+
}
|
|
352
|
+
throw error;
|
|
353
|
+
}
|
|
351
354
|
|
|
352
355
|
if (!headers) {
|
|
353
356
|
return [];
|
|
@@ -371,7 +374,8 @@ function csvToJson(csv, options = {}) {
|
|
|
371
374
|
}, 'PARSE_FAILED', { function: 'csvToJson' });
|
|
372
375
|
}
|
|
373
376
|
|
|
374
|
-
|
|
377
|
+
/* istanbul ignore next */
|
|
378
|
+
async function* csvToJsonIterator(csv, options = {}) {
|
|
375
379
|
validateCsvInput(csv, options);
|
|
376
380
|
|
|
377
381
|
const opts = options && typeof options === 'object' ? options : {};
|
|
@@ -498,7 +502,8 @@ async function* csvToJsonIterator(csv, options = {}) {
|
|
|
498
502
|
}
|
|
499
503
|
} catch (error) {
|
|
500
504
|
if (error && error.code === 'FAST_PATH_UNCLOSED_QUOTES') {
|
|
501
|
-
|
|
505
|
+
const lineInfo = error.lineNumber ? ` at line ${error.lineNumber}` : '';
|
|
506
|
+
throw new ParsingError(`Unclosed quotes in CSV${lineInfo}`, error.lineNumber);
|
|
502
507
|
}
|
|
503
508
|
throw error;
|
|
504
509
|
}
|
|
@@ -638,24 +643,27 @@ function createTransformHooks() {
|
|
|
638
643
|
* @param {number} maxSize - Maximum cache size (default: 100)
|
|
639
644
|
* @returns {DelimiterCache} New DelimiterCache instance
|
|
640
645
|
*/
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
646
|
+
/* istanbul ignore next */
|
|
647
|
+
function createDelimiterCache(maxSize = 100) {
|
|
648
|
+
return new DelimiterCache(maxSize);
|
|
649
|
+
}
|
|
644
650
|
|
|
645
651
|
/**
|
|
646
652
|
* Gets statistics from the global delimiter cache
|
|
647
653
|
* @returns {Object} Cache statistics
|
|
648
654
|
*/
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
655
|
+
/* istanbul ignore next */
|
|
656
|
+
function getDelimiterCacheStats() {
|
|
657
|
+
return globalDelimiterCache.getStats();
|
|
658
|
+
}
|
|
652
659
|
|
|
653
660
|
/**
|
|
654
661
|
* Clears the global delimiter cache
|
|
655
662
|
*/
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
663
|
+
/* istanbul ignore next */
|
|
664
|
+
function clearDelimiterCache() {
|
|
665
|
+
globalDelimiterCache.clear();
|
|
666
|
+
}
|
|
659
667
|
|
|
660
668
|
// Export the functions
|
|
661
669
|
module.exports = {
|
|
@@ -674,6 +682,7 @@ module.exports = {
|
|
|
674
682
|
};
|
|
675
683
|
|
|
676
684
|
// For ES6 module compatibility
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
685
|
+
/* istanbul ignore next */
|
|
686
|
+
if (typeof module !== 'undefined' && module.exports) {
|
|
687
|
+
module.exports.default = csvToJson;
|
|
688
|
+
}
|