convert-csv-to-json 3.28.0 → 4.1.0
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/CHANGELOG.md +41 -1
- package/README.md +173 -833
- package/docs/ASYNC.md +485 -0
- package/docs/BROWSER.md +425 -0
- package/docs/ERROR_HANDLING.md +367 -0
- package/docs/MAPROWS.md +196 -0
- package/docs/SYNC.md +239 -0
- package/index.d.ts +10 -8
- package/index.js +13 -10
- package/migration/RFC4180_MIGRATION_GUIDE.md +737 -0
- package/package.json +1 -1
- package/release-notes/RELEASE_NOTES_v4.0.0.md +320 -0
- package/src/browserApi.js +29 -6
- package/src/csvToJson.js +233 -82
- package/src/csvToJsonAsync.js +15 -1
- package/src/util/errors.js +227 -0
- package/src/util/fileUtils.js +18 -7
- package/src/util/jsonUtils.js +3 -1
- /package/{MIGRATION.md → migration/MIGRATION_TO_ASYNC.md} +0 -0
|
@@ -0,0 +1,737 @@
|
|
|
1
|
+
# RFC 4180 Migration Guide
|
|
2
|
+
|
|
3
|
+
## Overview
|
|
4
|
+
|
|
5
|
+
This guide helps developers migrate to csvToJson v3.21.0, which introduces **full RFC 4180 compliance**. RFC 4180 is the standard specification for CSV (Comma-Separated Values) files.
|
|
6
|
+
|
|
7
|
+
**⏱️ Estimated reading time: 15-20 minutes**
|
|
8
|
+
|
|
9
|
+
---
|
|
10
|
+
|
|
11
|
+
## Table of Contents
|
|
12
|
+
|
|
13
|
+
1. [What is RFC 4180?](#what-is-rfc-4180)
|
|
14
|
+
2. [Breaking Changes](#breaking-changes)
|
|
15
|
+
3. [Migration Checklist](#migration-checklist)
|
|
16
|
+
4. [Quick Migration Examples](#quick-migration-examples)
|
|
17
|
+
5. [Detailed Migration Scenarios](#detailed-migration-scenarios)
|
|
18
|
+
6. [Testing Your Migration](#testing-your-migration)
|
|
19
|
+
7. [Troubleshooting](#troubleshooting)
|
|
20
|
+
8. [FAQ](#faq)
|
|
21
|
+
|
|
22
|
+
---
|
|
23
|
+
|
|
24
|
+
## What is RFC 4180?
|
|
25
|
+
|
|
26
|
+
RFC 4180 is the Internet Engineering Task Force (IETF) standard specification for CSV files. It defines:
|
|
27
|
+
|
|
28
|
+
### Key Specifications
|
|
29
|
+
|
|
30
|
+
| Aspect | RFC 4180 Standard |
|
|
31
|
+
|--------|-------------------|
|
|
32
|
+
| **Field Delimiter** | Comma (`,`) |
|
|
33
|
+
| **Record Delimiter** | CRLF (`\r\n`) or LF (`\n`) |
|
|
34
|
+
| **Quote Character** | Double-quote (`"`) |
|
|
35
|
+
| **Quoted Fields** | Allowed for any field |
|
|
36
|
+
| **Quote Escaping** | Use double quotes (`""`) |
|
|
37
|
+
| **MIME Type** | `text/csv` |
|
|
38
|
+
| **Charset** | UTF-8 (recommended) |
|
|
39
|
+
|
|
40
|
+
### RFC 4180 CSV Example
|
|
41
|
+
|
|
42
|
+
```csv
|
|
43
|
+
firstName,lastName,email,status
|
|
44
|
+
"Smith, John",Smith,john@example.com,"Active, Verified"
|
|
45
|
+
Jane,Doe,jane@example.com,"Inactive"
|
|
46
|
+
"Cooper, Andy",Cooper,"andy@company.com, andy.cooper@home.com","Active"
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
**Key Features Demonstrated:**
|
|
50
|
+
- Comma delimiters
|
|
51
|
+
- Quoted fields containing commas
|
|
52
|
+
- Escaped quotes using `""`
|
|
53
|
+
- Field names (header row)
|
|
54
|
+
|
|
55
|
+
---
|
|
56
|
+
|
|
57
|
+
## Breaking Changes
|
|
58
|
+
|
|
59
|
+
### 1. Default Delimiter: Semicolon → Comma
|
|
60
|
+
|
|
61
|
+
**The most significant breaking change**
|
|
62
|
+
|
|
63
|
+
#### Context
|
|
64
|
+
- **Before**: Default delimiter was semicolon (`;`)
|
|
65
|
+
- **After**: Default delimiter is comma (`,`) - per RFC 4180 standard
|
|
66
|
+
- **Reason**: RFC 4180 specifies comma as the standard delimiter
|
|
67
|
+
|
|
68
|
+
#### Impact Analysis
|
|
69
|
+
|
|
70
|
+
| Scenario | Impact | Action Required |
|
|
71
|
+
|----------|--------|-----------------|
|
|
72
|
+
| Using explicit `.fieldDelimiter()` | ✅ None | No changes needed |
|
|
73
|
+
| Parsing comma-delimited CSV | ✅ Improved | May see better results |
|
|
74
|
+
| Parsing semicolon-delimited CSV | ❌ Breaking | Add `.fieldDelimiter(';')` |
|
|
75
|
+
| No delimiter configuration | ❌ Breaking | Verify CSV format |
|
|
76
|
+
|
|
77
|
+
#### Before Code (Old Behavior)
|
|
78
|
+
```javascript
|
|
79
|
+
const csvToJson = require('convert-csv-to-json');
|
|
80
|
+
|
|
81
|
+
// Assuming file uses semicolons as delimiter
|
|
82
|
+
// data.csv:
|
|
83
|
+
// name;email;age
|
|
84
|
+
// John;john@example.com;30
|
|
85
|
+
|
|
86
|
+
let result = csvToJson.getJsonFromCsv('data.csv');
|
|
87
|
+
// Works - automatically used semicolon
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
#### After Code (New RFC 4180 Behavior)
|
|
91
|
+
```javascript
|
|
92
|
+
const csvToJson = require('convert-csv-to-json');
|
|
93
|
+
|
|
94
|
+
// data.csv (with semicolons):
|
|
95
|
+
// name;email;age
|
|
96
|
+
// John;john@example.com;30
|
|
97
|
+
|
|
98
|
+
let result = csvToJson.getJsonFromCsv('data.csv');
|
|
99
|
+
// ❌ BREAKS - expects comma delimiter now
|
|
100
|
+
// Result: { 'name;email;age': 'John;john@example.com;30' }
|
|
101
|
+
|
|
102
|
+
// ✅ FIX: Explicitly set semicolon delimiter
|
|
103
|
+
let result = csvToJson.fieldDelimiter(';').getJsonFromCsv('data.csv');
|
|
104
|
+
// Works correctly
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
### 2. Removed Deprecated Function `jsonToCsv()`
|
|
108
|
+
|
|
109
|
+
**This function has been completely removed**
|
|
110
|
+
|
|
111
|
+
#### Before
|
|
112
|
+
```javascript
|
|
113
|
+
csvToJson.jsonToCsv('input.csv', 'output.json');
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
#### After
|
|
117
|
+
```javascript
|
|
118
|
+
csvToJson.generateJsonFileFromCsv('input.csv', 'output.json');
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
### 3. Stricter Quoted Field Parsing
|
|
122
|
+
|
|
123
|
+
RFC 4180 compliance means stricter adherence to the standard.
|
|
124
|
+
|
|
125
|
+
#### Quote Escaping Changes
|
|
126
|
+
|
|
127
|
+
**Before (Non-compliant):**
|
|
128
|
+
```javascript
|
|
129
|
+
// Input CSV: name,description
|
|
130
|
+
// "John","He said ""Hello"""
|
|
131
|
+
|
|
132
|
+
let result = csvToJson.supportQuotedField(true).csvStringToJson(csv);
|
|
133
|
+
// Result might have inconsistent quote handling
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
**After (RFC 4180 Compliant):**
|
|
137
|
+
```javascript
|
|
138
|
+
// Input CSV: name,description
|
|
139
|
+
// "John","He said ""Hello"""
|
|
140
|
+
|
|
141
|
+
let result = csvToJson.supportQuotedField(true).csvStringToJson(csv);
|
|
142
|
+
// Result correctly unescapes to: He said "Hello"
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
#### Multi-line Field Handling
|
|
146
|
+
|
|
147
|
+
**Before:**
|
|
148
|
+
- Multi-line fields in quoted regions might not parse correctly
|
|
149
|
+
|
|
150
|
+
**After:**
|
|
151
|
+
- Full support for multi-line fields within quoted regions
|
|
152
|
+
- Newlines preserved inside quoted fields
|
|
153
|
+
- Line ending detection: CRLF, LF, CR all supported
|
|
154
|
+
|
|
155
|
+
```javascript
|
|
156
|
+
let csv = 'id,description\n' +
|
|
157
|
+
'1,"Multi-line\ndescription\nhere"\n' +
|
|
158
|
+
'2,"Single line"\n';
|
|
159
|
+
|
|
160
|
+
let result = csvToJson.supportQuotedField(true).csvStringToJson(csv);
|
|
161
|
+
// Correctly handles newlines inside quoted fields
|
|
162
|
+
```
|
|
163
|
+
|
|
164
|
+
---
|
|
165
|
+
|
|
166
|
+
## Migration Checklist
|
|
167
|
+
|
|
168
|
+
Use this checklist to identify and fix breaking changes:
|
|
169
|
+
|
|
170
|
+
- [ ] **Audit CSV files** - Identify delimiter used (`,`, `;`, `|`, `\t`, etc.)
|
|
171
|
+
- [ ] **Search codebase** - Find all `csvToJson` calls
|
|
172
|
+
- [ ] **Check default usage** - Look for calls without `.fieldDelimiter()`
|
|
173
|
+
- [ ] **Update non-comma delimiters** - Add `.fieldDelimiter()` calls
|
|
174
|
+
- [ ] **Replace deprecated functions** - Change `jsonToCsv()` to `generateJsonFileFromCsv()`
|
|
175
|
+
- [ ] **Test quoted fields** - Verify fields with quotes parse correctly
|
|
176
|
+
- [ ] **Test multi-line fields** - Verify newlines in fields work
|
|
177
|
+
- [ ] **Run test suite** - Execute existing tests to find issues
|
|
178
|
+
- [ ] **Update documentation** - Document any changes to your API
|
|
179
|
+
|
|
180
|
+
---
|
|
181
|
+
|
|
182
|
+
## Quick Migration Examples
|
|
183
|
+
|
|
184
|
+
### Scenario 1: Semicolon-Delimited Files
|
|
185
|
+
|
|
186
|
+
**Affected Code:**
|
|
187
|
+
```javascript
|
|
188
|
+
// Before (v3.20 and earlier)
|
|
189
|
+
const csvToJson = require('convert-csv-to-json');
|
|
190
|
+
let data = csvToJson.getJsonFromCsv('data.csv'); // Worked with semicolons
|
|
191
|
+
```
|
|
192
|
+
|
|
193
|
+
**Migration:**
|
|
194
|
+
```javascript
|
|
195
|
+
// After (v3.21)
|
|
196
|
+
const csvToJson = require('convert-csv-to-json');
|
|
197
|
+
let data = csvToJson.fieldDelimiter(';').getJsonFromCsv('data.csv');
|
|
198
|
+
```
|
|
199
|
+
|
|
200
|
+
### Scenario 2: Tab-Delimited Files
|
|
201
|
+
|
|
202
|
+
**Affected Code:**
|
|
203
|
+
```javascript
|
|
204
|
+
// Before
|
|
205
|
+
let data = csvToJson.getJsonFromCsv('data.tsv');
|
|
206
|
+
```
|
|
207
|
+
|
|
208
|
+
**Migration:**
|
|
209
|
+
```javascript
|
|
210
|
+
// After
|
|
211
|
+
let data = csvToJson.fieldDelimiter('\t').getJsonFromCsv('data.tsv');
|
|
212
|
+
```
|
|
213
|
+
|
|
214
|
+
### Scenario 3: Pipe-Delimited Files
|
|
215
|
+
|
|
216
|
+
**Affected Code:**
|
|
217
|
+
```javascript
|
|
218
|
+
// Before
|
|
219
|
+
let data = csvToJson.getJsonFromCsv('data.psv');
|
|
220
|
+
```
|
|
221
|
+
|
|
222
|
+
**Migration:**
|
|
223
|
+
```javascript
|
|
224
|
+
// After
|
|
225
|
+
let data = csvToJson.fieldDelimiter('|').getJsonFromCsv('data.psv');
|
|
226
|
+
```
|
|
227
|
+
|
|
228
|
+
### Scenario 4: Standard Comma-Delimited CSV
|
|
229
|
+
|
|
230
|
+
**No Changes Needed:**
|
|
231
|
+
```javascript
|
|
232
|
+
// Before (already works the same)
|
|
233
|
+
let data = csvToJson.getJsonFromCsv('data.csv');
|
|
234
|
+
|
|
235
|
+
// After (still works the same)
|
|
236
|
+
let data = csvToJson.getJsonFromCsv('data.csv');
|
|
237
|
+
// Now works out-of-the-box without explicit delimiter!
|
|
238
|
+
```
|
|
239
|
+
|
|
240
|
+
### Scenario 5: Remove Deprecated Function
|
|
241
|
+
|
|
242
|
+
**Before:**
|
|
243
|
+
```javascript
|
|
244
|
+
csvToJson.jsonToCsv('input.csv', 'output.json');
|
|
245
|
+
```
|
|
246
|
+
|
|
247
|
+
**After:**
|
|
248
|
+
```javascript
|
|
249
|
+
csvToJson.generateJsonFileFromCsv('input.csv', 'output.json');
|
|
250
|
+
```
|
|
251
|
+
|
|
252
|
+
---
|
|
253
|
+
|
|
254
|
+
## Detailed Migration Scenarios
|
|
255
|
+
|
|
256
|
+
### Scenario A: Express.js CSV Upload Handler
|
|
257
|
+
|
|
258
|
+
**Original Code (Pre-RFC 4180):**
|
|
259
|
+
```javascript
|
|
260
|
+
const express = require('express');
|
|
261
|
+
const csvToJson = require('convert-csv-to-json');
|
|
262
|
+
const app = express();
|
|
263
|
+
|
|
264
|
+
app.post('/upload', (req, res) => {
|
|
265
|
+
try {
|
|
266
|
+
// Assumes semicolon delimiter (old default)
|
|
267
|
+
let result = csvToJson.getJsonFromCsv(req.file.path);
|
|
268
|
+
res.json(result);
|
|
269
|
+
} catch (error) {
|
|
270
|
+
res.status(400).json({ error: error.message });
|
|
271
|
+
}
|
|
272
|
+
});
|
|
273
|
+
```
|
|
274
|
+
|
|
275
|
+
**Migrated Code (RFC 4180 Compliant):**
|
|
276
|
+
```javascript
|
|
277
|
+
const express = require('express');
|
|
278
|
+
const csvToJson = require('convert-csv-to-json');
|
|
279
|
+
const app = express();
|
|
280
|
+
|
|
281
|
+
app.post('/upload', (req, res) => {
|
|
282
|
+
try {
|
|
283
|
+
// Detect delimiter or use user-provided delimiter
|
|
284
|
+
const delimiter = req.body.delimiter || ','; // Default to comma (RFC 4180)
|
|
285
|
+
|
|
286
|
+
let result = csvToJson
|
|
287
|
+
.fieldDelimiter(delimiter)
|
|
288
|
+
.supportQuotedField(true)
|
|
289
|
+
.getJsonFromCsv(req.file.path);
|
|
290
|
+
|
|
291
|
+
res.json(result);
|
|
292
|
+
} catch (error) {
|
|
293
|
+
res.status(400).json({ error: error.message });
|
|
294
|
+
}
|
|
295
|
+
});
|
|
296
|
+
```
|
|
297
|
+
|
|
298
|
+
### Scenario B: Batch CSV Processing Script
|
|
299
|
+
|
|
300
|
+
**Original Code:**
|
|
301
|
+
```javascript
|
|
302
|
+
const csvToJson = require('convert-csv-to-json');
|
|
303
|
+
const fs = require('fs');
|
|
304
|
+
const path = require('path');
|
|
305
|
+
|
|
306
|
+
// Process all CSV files in a directory
|
|
307
|
+
const csvDir = './data/csv';
|
|
308
|
+
fs.readdirSync(csvDir).forEach(file => {
|
|
309
|
+
if (file.endsWith('.csv')) {
|
|
310
|
+
const csvPath = path.join(csvDir, file);
|
|
311
|
+
const result = csvToJson.getJsonFromCsv(csvPath);
|
|
312
|
+
console.log(`Processed ${file}: ${result.length} records`);
|
|
313
|
+
}
|
|
314
|
+
});
|
|
315
|
+
```
|
|
316
|
+
|
|
317
|
+
**Migrated Code:**
|
|
318
|
+
```javascript
|
|
319
|
+
const csvToJson = require('convert-csv-to-json');
|
|
320
|
+
const fs = require('fs');
|
|
321
|
+
const path = require('path');
|
|
322
|
+
|
|
323
|
+
// Configuration by file extension or name pattern
|
|
324
|
+
const delimiterConfig = {
|
|
325
|
+
'semicolon': ';',
|
|
326
|
+
'tab': '\t',
|
|
327
|
+
'pipe': '|',
|
|
328
|
+
'default': ','
|
|
329
|
+
};
|
|
330
|
+
|
|
331
|
+
function detectDelimiter(filename) {
|
|
332
|
+
// Example: detect based on filename pattern
|
|
333
|
+
if (filename.includes('semi')) return delimiterConfig.semicolon;
|
|
334
|
+
if (filename.includes('tsv')) return delimiterConfig.tab;
|
|
335
|
+
if (filename.includes('pipe')) return delimiterConfig.pipe;
|
|
336
|
+
return delimiterConfig.default; // RFC 4180 default
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
// Process all CSV files in a directory
|
|
340
|
+
const csvDir = './data/csv';
|
|
341
|
+
fs.readdirSync(csvDir).forEach(file => {
|
|
342
|
+
if (file.endsWith('.csv') || file.endsWith('.tsv')) {
|
|
343
|
+
const csvPath = path.join(csvDir, file);
|
|
344
|
+
const delimiter = detectDelimiter(file);
|
|
345
|
+
|
|
346
|
+
try {
|
|
347
|
+
const result = csvToJson
|
|
348
|
+
.fieldDelimiter(delimiter)
|
|
349
|
+
.supportQuotedField(true)
|
|
350
|
+
.getJsonFromCsv(csvPath);
|
|
351
|
+
console.log(`✓ Processed ${file}: ${result.length} records`);
|
|
352
|
+
} catch (error) {
|
|
353
|
+
console.error(`✗ Error processing ${file}: ${error.message}`);
|
|
354
|
+
}
|
|
355
|
+
}
|
|
356
|
+
});
|
|
357
|
+
```
|
|
358
|
+
|
|
359
|
+
### Scenario C: Data Import with Validation
|
|
360
|
+
|
|
361
|
+
**Original Code:**
|
|
362
|
+
```javascript
|
|
363
|
+
const csvToJson = require('convert-csv-to-json');
|
|
364
|
+
|
|
365
|
+
function importUserData(csvFile) {
|
|
366
|
+
let data = csvToJson.getJsonFromCsv(csvFile);
|
|
367
|
+
|
|
368
|
+
// Validate and import
|
|
369
|
+
data.forEach(user => {
|
|
370
|
+
if (user.email && user.name) {
|
|
371
|
+
saveUser(user);
|
|
372
|
+
}
|
|
373
|
+
});
|
|
374
|
+
}
|
|
375
|
+
```
|
|
376
|
+
|
|
377
|
+
**Migrated Code:**
|
|
378
|
+
```javascript
|
|
379
|
+
const csvToJson = require('convert-csv-to-json');
|
|
380
|
+
|
|
381
|
+
function importUserData(csvFile, options = {}) {
|
|
382
|
+
const delimiter = options.delimiter || ','; // RFC 4180 default
|
|
383
|
+
const hasQuotedFields = options.hasQuotedFields !== false; // Default true
|
|
384
|
+
|
|
385
|
+
try {
|
|
386
|
+
let data = csvToJson
|
|
387
|
+
.fieldDelimiter(delimiter)
|
|
388
|
+
.supportQuotedField(hasQuotedFields)
|
|
389
|
+
.formatValueByType(true) // Format values by type
|
|
390
|
+
.getJsonFromCsv(csvFile);
|
|
391
|
+
|
|
392
|
+
// Validate and import
|
|
393
|
+
const imported = [];
|
|
394
|
+
const errors = [];
|
|
395
|
+
|
|
396
|
+
data.forEach((user, index) => {
|
|
397
|
+
if (user.email && user.name) {
|
|
398
|
+
try {
|
|
399
|
+
saveUser(user);
|
|
400
|
+
imported.push(user.email);
|
|
401
|
+
} catch (error) {
|
|
402
|
+
errors.push(`Row ${index + 2}: ${error.message}`);
|
|
403
|
+
}
|
|
404
|
+
} else {
|
|
405
|
+
errors.push(`Row ${index + 2}: Missing email or name`);
|
|
406
|
+
}
|
|
407
|
+
});
|
|
408
|
+
|
|
409
|
+
return { imported, errors };
|
|
410
|
+
} catch (error) {
|
|
411
|
+
throw new Error(`CSV processing failed: ${error.message}`);
|
|
412
|
+
}
|
|
413
|
+
}
|
|
414
|
+
```
|
|
415
|
+
|
|
416
|
+
### Scenario D: Backward Compatibility Wrapper
|
|
417
|
+
|
|
418
|
+
**If you need to maintain backward compatibility:**
|
|
419
|
+
|
|
420
|
+
```javascript
|
|
421
|
+
const csvToJsonLib = require('convert-csv-to-json');
|
|
422
|
+
|
|
423
|
+
// Wrapper with backward-compatible defaults
|
|
424
|
+
class CSVConverter {
|
|
425
|
+
constructor(options = {}) {
|
|
426
|
+
// Use RFC 4180 standard by default, but allow override
|
|
427
|
+
this.defaultDelimiter = options.defaultDelimiter || ',';
|
|
428
|
+
this.legacyMode = options.legacyMode || false;
|
|
429
|
+
}
|
|
430
|
+
|
|
431
|
+
getJsonFromCsv(filepath, options = {}) {
|
|
432
|
+
const delimiter = options.delimiter || this.defaultDelimiter;
|
|
433
|
+
|
|
434
|
+
// In legacy mode, default to semicolon
|
|
435
|
+
if (this.legacyMode && !options.delimiter) {
|
|
436
|
+
return csvToJsonLib
|
|
437
|
+
.fieldDelimiter(';')
|
|
438
|
+
.getJsonFromCsv(filepath);
|
|
439
|
+
}
|
|
440
|
+
|
|
441
|
+
return csvToJsonLib
|
|
442
|
+
.fieldDelimiter(delimiter)
|
|
443
|
+
.supportQuotedField(options.supportQuotedField !== false)
|
|
444
|
+
.getJsonFromCsv(filepath);
|
|
445
|
+
}
|
|
446
|
+
}
|
|
447
|
+
|
|
448
|
+
// Usage - RFC 4180 mode (default)
|
|
449
|
+
const converter = new CSVConverter();
|
|
450
|
+
let data = converter.getJsonFromCsv('data.csv');
|
|
451
|
+
|
|
452
|
+
// Usage - Legacy mode (backward compatible)
|
|
453
|
+
const legacyConverter = new CSVConverter({ legacyMode: true });
|
|
454
|
+
let legacyData = legacyConverter.getJsonFromCsv('legacy_data.csv');
|
|
455
|
+
|
|
456
|
+
// Usage - Custom delimiter
|
|
457
|
+
let tabData = converter.getJsonFromCsv('data.tsv', { delimiter: '\t' });
|
|
458
|
+
```
|
|
459
|
+
|
|
460
|
+
---
|
|
461
|
+
|
|
462
|
+
## Testing Your Migration
|
|
463
|
+
|
|
464
|
+
### Step 1: Unit Tests
|
|
465
|
+
|
|
466
|
+
Create tests to verify both old and new behavior:
|
|
467
|
+
|
|
468
|
+
```javascript
|
|
469
|
+
const csvToJson = require('convert-csv-to-json');
|
|
470
|
+
|
|
471
|
+
describe('RFC 4180 Migration Tests', () => {
|
|
472
|
+
test('should parse comma-delimited CSV (RFC 4180 default)', () => {
|
|
473
|
+
const csv = 'name,age\nJohn,30\nJane,25\n';
|
|
474
|
+
const result = csvToJson.csvStringToJson(csv);
|
|
475
|
+
|
|
476
|
+
expect(result.length).toBe(2);
|
|
477
|
+
expect(result[0].name).toBe('John');
|
|
478
|
+
});
|
|
479
|
+
|
|
480
|
+
test('should parse semicolon-delimited CSV with explicit delimiter', () => {
|
|
481
|
+
const csv = 'name;age\nJohn;30\nJane;25\n';
|
|
482
|
+
const result = csvToJson
|
|
483
|
+
.fieldDelimiter(';')
|
|
484
|
+
.csvStringToJson(csv);
|
|
485
|
+
|
|
486
|
+
expect(result.length).toBe(2);
|
|
487
|
+
expect(result[0].name).toBe('John');
|
|
488
|
+
});
|
|
489
|
+
|
|
490
|
+
test('should handle quoted fields per RFC 4180', () => {
|
|
491
|
+
const csv = 'name,description\n"Smith, John","He said ""Hello"""\n';
|
|
492
|
+
const result = csvToJson
|
|
493
|
+
.supportQuotedField(true)
|
|
494
|
+
.csvStringToJson(csv);
|
|
495
|
+
|
|
496
|
+
expect(result[0].name).toBe('Smith, John');
|
|
497
|
+
expect(result[0].description).toBe('He said "Hello"');
|
|
498
|
+
});
|
|
499
|
+
});
|
|
500
|
+
```
|
|
501
|
+
|
|
502
|
+
### Step 2: Integration Tests
|
|
503
|
+
|
|
504
|
+
Test with real CSV files:
|
|
505
|
+
|
|
506
|
+
```javascript
|
|
507
|
+
describe('Real CSV File Integration', () => {
|
|
508
|
+
test('should process standard RFC 4180 CSV', () => {
|
|
509
|
+
const result = csvToJson.getJsonFromCsv('./test/data/standard.csv');
|
|
510
|
+
expect(result.length).toBeGreaterThan(0);
|
|
511
|
+
});
|
|
512
|
+
|
|
513
|
+
test('should process legacy semicolon-delimited CSV', () => {
|
|
514
|
+
const result = csvToJson
|
|
515
|
+
.fieldDelimiter(';')
|
|
516
|
+
.getJsonFromCsv('./test/data/legacy.csv');
|
|
517
|
+
expect(result.length).toBeGreaterThan(0);
|
|
518
|
+
});
|
|
519
|
+
});
|
|
520
|
+
```
|
|
521
|
+
|
|
522
|
+
### Step 3: Validation Checklist
|
|
523
|
+
|
|
524
|
+
```javascript
|
|
525
|
+
// Test for correct parsing
|
|
526
|
+
✓ Basic parsing works
|
|
527
|
+
✓ Field count matches headers
|
|
528
|
+
✓ Empty fields handled correctly
|
|
529
|
+
✓ Quoted fields with commas work
|
|
530
|
+
✓ Escaped quotes unescaped correctly
|
|
531
|
+
✓ Multi-line fields preserved
|
|
532
|
+
✓ Line endings detected correctly (CRLF, LF, CR)
|
|
533
|
+
✓ Special characters preserved
|
|
534
|
+
✓ Type formatting works
|
|
535
|
+
✓ Boolean/number conversion works
|
|
536
|
+
✓ Error handling for malformed CSV
|
|
537
|
+
```
|
|
538
|
+
|
|
539
|
+
---
|
|
540
|
+
|
|
541
|
+
## Troubleshooting
|
|
542
|
+
|
|
543
|
+
### Problem 1: "Headers Not Found" Error
|
|
544
|
+
|
|
545
|
+
**Symptom:**
|
|
546
|
+
```javascript
|
|
547
|
+
// Works in v3.20, breaks in v3.21
|
|
548
|
+
csvToJson.getJsonFromCsv('mydata.csv');
|
|
549
|
+
// Error: No header row found in CSV
|
|
550
|
+
```
|
|
551
|
+
|
|
552
|
+
**Cause:** File likely uses semicolon delimiter (old default changed to comma)
|
|
553
|
+
|
|
554
|
+
**Solution:**
|
|
555
|
+
```javascript
|
|
556
|
+
// Add explicit delimiter
|
|
557
|
+
csvToJson.fieldDelimiter(';').getJsonFromCsv('mydata.csv');
|
|
558
|
+
|
|
559
|
+
// Or inspect the file first
|
|
560
|
+
const fs = require('fs');
|
|
561
|
+
const firstLine = fs.readFileSync('mydata.csv', 'utf8').split('\n')[0];
|
|
562
|
+
console.log('First line:', firstLine);
|
|
563
|
+
// Count delimiters to detect type
|
|
564
|
+
```
|
|
565
|
+
|
|
566
|
+
### Problem 2: Fields Not Splitting Correctly
|
|
567
|
+
|
|
568
|
+
**Symptom:**
|
|
569
|
+
```javascript
|
|
570
|
+
// One field shows entire row content
|
|
571
|
+
[{ 'field1;field2;field3': '...value...value...value' }]
|
|
572
|
+
```
|
|
573
|
+
|
|
574
|
+
**Cause:** Wrong delimiter configured or auto-detection failed
|
|
575
|
+
|
|
576
|
+
**Solution:**
|
|
577
|
+
```javascript
|
|
578
|
+
// Explicitly set the delimiter
|
|
579
|
+
csvToJson.fieldDelimiter(';').getJsonFromCsv('file.csv');
|
|
580
|
+
|
|
581
|
+
// Or auto-detect:
|
|
582
|
+
function detectDelimiter(filePath) {
|
|
583
|
+
const fs = require('fs');
|
|
584
|
+
const line = fs.readFileSync(filePath, 'utf8').split('\n')[0];
|
|
585
|
+
|
|
586
|
+
const delimiters = [',', ';', '|', '\t'];
|
|
587
|
+
for (let delim of delimiters) {
|
|
588
|
+
if (line.includes(delim)) {
|
|
589
|
+
return delim;
|
|
590
|
+
}
|
|
591
|
+
}
|
|
592
|
+
return ','; // Default to RFC 4180
|
|
593
|
+
}
|
|
594
|
+
|
|
595
|
+
const delimiter = detectDelimiter('file.csv');
|
|
596
|
+
csvToJson.fieldDelimiter(delimiter).getJsonFromCsv('file.csv');
|
|
597
|
+
```
|
|
598
|
+
|
|
599
|
+
### Problem 3: Quoted Fields Not Working
|
|
600
|
+
|
|
601
|
+
**Symptom:**
|
|
602
|
+
```javascript
|
|
603
|
+
// With input: name,value
|
|
604
|
+
// "John","He said ""Hi"""
|
|
605
|
+
let result = csvToJson.getJsonFromCsv('file.csv');
|
|
606
|
+
// Result shows: { name: '"John"', value: '"He said ""Hi"""' }
|
|
607
|
+
```
|
|
608
|
+
|
|
609
|
+
**Cause:** `.supportQuotedField()` not enabled
|
|
610
|
+
|
|
611
|
+
**Solution:**
|
|
612
|
+
```javascript
|
|
613
|
+
let result = csvToJson
|
|
614
|
+
.supportQuotedField(true)
|
|
615
|
+
.getJsonFromCsv('file.csv');
|
|
616
|
+
// Now works correctly
|
|
617
|
+
```
|
|
618
|
+
|
|
619
|
+
### Problem 4: `jsonToCsv` Function Not Found
|
|
620
|
+
|
|
621
|
+
**Symptom:**
|
|
622
|
+
```javascript
|
|
623
|
+
csvToJson.jsonToCsv('input.csv', 'output.json');
|
|
624
|
+
// TypeError: csvToJson.jsonToCsv is not a function
|
|
625
|
+
```
|
|
626
|
+
|
|
627
|
+
**Cause:** Function was removed (it was deprecated)
|
|
628
|
+
|
|
629
|
+
**Solution:**
|
|
630
|
+
```javascript
|
|
631
|
+
// Replace with the non-deprecated function
|
|
632
|
+
csvToJson.generateJsonFileFromCsv('input.csv', 'output.json');
|
|
633
|
+
```
|
|
634
|
+
|
|
635
|
+
### Problem 5: Multi-line Fields Not Preserved
|
|
636
|
+
|
|
637
|
+
**Symptom:**
|
|
638
|
+
```javascript
|
|
639
|
+
// Input has field with newlines inside quotes
|
|
640
|
+
// But newlines are stripped or cause parsing errors
|
|
641
|
+
```
|
|
642
|
+
|
|
643
|
+
**Cause:** Parsing multi-line data requires `supportQuotedField(true)`
|
|
644
|
+
|
|
645
|
+
**Solution:**
|
|
646
|
+
```javascript
|
|
647
|
+
let result = csvToJson
|
|
648
|
+
.supportQuotedField(true)
|
|
649
|
+
.getJsonFromCsv('file.csv');
|
|
650
|
+
// Newlines inside quoted fields now preserved
|
|
651
|
+
```
|
|
652
|
+
|
|
653
|
+
---
|
|
654
|
+
|
|
655
|
+
## FAQ
|
|
656
|
+
|
|
657
|
+
### Q: Do I need to update my code?
|
|
658
|
+
|
|
659
|
+
**A:** Only if you:
|
|
660
|
+
- Don't explicitly set `.fieldDelimiter()` and use non-comma delimiters
|
|
661
|
+
- Use the removed `jsonToCsv()` function
|
|
662
|
+
- Parse quoted CSV files without `.supportQuotedField(true)`
|
|
663
|
+
|
|
664
|
+
### Q: Is this a breaking change?
|
|
665
|
+
|
|
666
|
+
**A:** Yes, the default delimiter changed from semicolon to comma. However, most code using explicit `.fieldDelimiter()` is unaffected.
|
|
667
|
+
|
|
668
|
+
### Q: Why change the default delimiter?
|
|
669
|
+
|
|
670
|
+
**A:** RFC 4180 (the standard specification) defines comma as the standard delimiter. This makes the library RFC 4180 compliant out-of-the-box.
|
|
671
|
+
|
|
672
|
+
### Q: Can I still use semicolons?
|
|
673
|
+
|
|
674
|
+
**A:** Yes, just use: `.fieldDelimiter(';').getJsonFromCsv('file.csv')`
|
|
675
|
+
|
|
676
|
+
### Q: What about backward compatibility?
|
|
677
|
+
|
|
678
|
+
**A:** Existing code with explicit delimiters works without changes. Only code relying on the old default delimiter needs updates.
|
|
679
|
+
|
|
680
|
+
### Q: Can I detect the delimiter automatically?
|
|
681
|
+
|
|
682
|
+
**A:** Yes, see the troubleshooting section for delimiter detection code.
|
|
683
|
+
|
|
684
|
+
### Q: Are all my CSV files now broken?
|
|
685
|
+
|
|
686
|
+
**A:** Only if they use non-comma delimiters AND you were relying on the old default. Explicitly set the delimiter to fix.
|
|
687
|
+
|
|
688
|
+
### Q: What's RFC 4180?
|
|
689
|
+
|
|
690
|
+
**A:** It's the official IETF standard for CSV file format. Read more: https://tools.ietf.org/html/rfc4180
|
|
691
|
+
|
|
692
|
+
### Q: Do I need to update my tests?
|
|
693
|
+
|
|
694
|
+
**A:** Yes, update tests that assume the old semicolon default or test the removed `jsonToCsv()` function.
|
|
695
|
+
|
|
696
|
+
### Q: How do I test my migration?
|
|
697
|
+
|
|
698
|
+
**A:** Run existing tests first to identify failures, then update code and delimiters as needed. See "Testing Your Migration" section above.
|
|
699
|
+
|
|
700
|
+
### Q: What if I have legacy code I can't change?
|
|
701
|
+
|
|
702
|
+
**A:** You can create a wrapper class (see Scenario D) that uses the old default delimiter and maintains backward compatibility.
|
|
703
|
+
|
|
704
|
+
### Q: Where can I get help?
|
|
705
|
+
|
|
706
|
+
**A:** Check GitHub Issues: https://github.com/iuccio/csvToJson/issues
|
|
707
|
+
|
|
708
|
+
---
|
|
709
|
+
|
|
710
|
+
## Summary
|
|
711
|
+
|
|
712
|
+
**Key Points to Remember:**
|
|
713
|
+
|
|
714
|
+
1. **Default delimiter is now comma (`,`)** - per RFC 4180 standard
|
|
715
|
+
2. **Explicitly set delimiters** for non-comma files: `.fieldDelimiter(';')`
|
|
716
|
+
3. **Remove `jsonToCsv()` calls** - use `generateJsonFileFromCsv()` instead
|
|
717
|
+
4. **Enable quoted field support** for complex CSV: `.supportQuotedField(true)`
|
|
718
|
+
5. **Test thoroughly** - especially if not using explicit delimiters
|
|
719
|
+
6. **Refer to RFC 4180** - for standard CSV format specification
|
|
720
|
+
|
|
721
|
+
---
|
|
722
|
+
|
|
723
|
+
## Next Steps
|
|
724
|
+
|
|
725
|
+
1. ✅ Review breaking changes above
|
|
726
|
+
2. ✅ Audit your codebase for affected code
|
|
727
|
+
3. ✅ Update code with explicit delimiters as needed
|
|
728
|
+
4. ✅ Run tests to identify issues
|
|
729
|
+
5. ✅ Update affected tests
|
|
730
|
+
6. ✅ Deploy with confidence!
|
|
731
|
+
|
|
732
|
+
---
|
|
733
|
+
|
|
734
|
+
**For more information, see:**
|
|
735
|
+
- [Release Notes](./RELEASE_NOTES.md)
|
|
736
|
+
- [README](./README.md)
|
|
737
|
+
- [RFC 4180 Specification](https://tools.ietf.org/html/rfc4180)
|