jtcsv 2.2.7 → 3.0.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/README.md +31 -1
- package/bin/jtcsv.js +891 -821
- package/bin/jtcsv.ts +2534 -0
- package/csv-to-json.js +168 -145
- package/dist/jtcsv-core.cjs.js +1407 -0
- package/dist/jtcsv-core.cjs.js.map +1 -0
- package/dist/jtcsv-core.esm.js +1379 -0
- package/dist/jtcsv-core.esm.js.map +1 -0
- package/dist/jtcsv-core.umd.js +1413 -0
- package/dist/jtcsv-core.umd.js.map +1 -0
- package/dist/jtcsv-full.cjs.js +1912 -0
- package/dist/jtcsv-full.cjs.js.map +1 -0
- package/dist/jtcsv-full.esm.js +1880 -0
- package/dist/jtcsv-full.esm.js.map +1 -0
- package/dist/jtcsv-full.umd.js +1918 -0
- package/dist/jtcsv-full.umd.js.map +1 -0
- package/dist/jtcsv-workers.esm.js +759 -0
- package/dist/jtcsv-workers.esm.js.map +1 -0
- package/dist/jtcsv-workers.umd.js +773 -0
- package/dist/jtcsv-workers.umd.js.map +1 -0
- package/dist/jtcsv.cjs.js +61 -19
- package/dist/jtcsv.cjs.js.map +1 -1
- package/dist/jtcsv.esm.js +61 -19
- package/dist/jtcsv.esm.js.map +1 -1
- package/dist/jtcsv.umd.js +61 -19
- package/dist/jtcsv.umd.js.map +1 -1
- package/errors.js +188 -2
- package/examples/advanced/conditional-transformations.js +446 -0
- package/examples/advanced/conditional-transformations.ts +446 -0
- package/examples/advanced/csv-parser.worker.js +89 -0
- package/examples/advanced/csv-parser.worker.ts +89 -0
- package/examples/advanced/nested-objects-example.js +306 -0
- package/examples/advanced/nested-objects-example.ts +306 -0
- package/examples/advanced/performance-optimization.js +504 -0
- package/examples/advanced/performance-optimization.ts +504 -0
- package/examples/advanced/run-demo-server.js +116 -0
- package/examples/advanced/run-demo-server.ts +116 -0
- package/examples/advanced/web-worker-usage.html +874 -0
- package/examples/async-multithreaded-example.ts +335 -0
- package/examples/cli-advanced-usage.md +288 -0
- package/examples/cli-batch-processing.ts +38 -0
- package/examples/cli-tool.js +0 -3
- package/examples/cli-tool.ts +183 -0
- package/examples/error-handling.js +21 -7
- package/examples/error-handling.ts +356 -0
- package/examples/express-api.js +0 -3
- package/examples/express-api.ts +164 -0
- package/examples/large-dataset-example.js +0 -3
- package/examples/large-dataset-example.ts +204 -0
- package/examples/ndjson-processing.js +1 -1
- package/examples/ndjson-processing.ts +456 -0
- package/examples/plugin-excel-exporter.js +3 -4
- package/examples/plugin-excel-exporter.ts +406 -0
- package/examples/react-integration.tsx +637 -0
- package/examples/schema-validation.ts +640 -0
- package/examples/simple-usage.js +254 -254
- package/examples/simple-usage.ts +194 -0
- package/examples/streaming-example.js +4 -5
- package/examples/streaming-example.ts +419 -0
- package/examples/web-workers-advanced.ts +28 -0
- package/index.d.ts +1 -3
- package/index.js +15 -1
- package/json-save.js +9 -3
- package/json-to-csv.js +168 -21
- package/package.json +69 -10
- package/plugins/express-middleware/README.md +21 -2
- package/plugins/express-middleware/example.js +3 -4
- package/plugins/express-middleware/example.ts +135 -0
- package/plugins/express-middleware/index.d.ts +1 -1
- package/plugins/express-middleware/index.js +270 -118
- package/plugins/express-middleware/index.ts +557 -0
- package/plugins/fastify-plugin/index.js +2 -4
- package/plugins/fastify-plugin/index.ts +443 -0
- package/plugins/hono/index.ts +226 -0
- package/plugins/nestjs/index.ts +201 -0
- package/plugins/nextjs-api/examples/ConverterComponent.tsx +386 -0
- package/plugins/nextjs-api/examples/api-convert.js +0 -2
- package/plugins/nextjs-api/examples/api-convert.ts +67 -0
- package/plugins/nextjs-api/index.tsx +339 -0
- package/plugins/nextjs-api/route.js +2 -3
- package/plugins/nextjs-api/route.ts +370 -0
- package/plugins/nuxt/index.ts +94 -0
- package/plugins/nuxt/runtime/composables/useJtcsv.ts +100 -0
- package/plugins/nuxt/runtime/plugin.ts +71 -0
- package/plugins/remix/index.js +1 -1
- package/plugins/remix/index.ts +260 -0
- package/plugins/sveltekit/index.js +1 -1
- package/plugins/sveltekit/index.ts +301 -0
- package/plugins/trpc/index.ts +267 -0
- package/src/browser/browser-functions.ts +402 -0
- package/src/browser/core.js +92 -0
- package/src/browser/core.ts +152 -0
- package/src/browser/csv-to-json-browser.d.ts +3 -0
- package/src/browser/csv-to-json-browser.js +36 -14
- package/src/browser/csv-to-json-browser.ts +264 -0
- package/src/browser/errors-browser.ts +303 -0
- package/src/browser/extensions/plugins.js +92 -0
- package/src/browser/extensions/plugins.ts +93 -0
- package/src/browser/extensions/workers.js +39 -0
- package/src/browser/extensions/workers.ts +39 -0
- package/src/browser/globals.d.ts +5 -0
- package/src/browser/index.ts +192 -0
- package/src/browser/json-to-csv-browser.d.ts +3 -0
- package/src/browser/json-to-csv-browser.js +13 -3
- package/src/browser/json-to-csv-browser.ts +262 -0
- package/src/browser/streams.js +12 -2
- package/src/browser/streams.ts +336 -0
- package/src/browser/workers/csv-parser.worker.ts +377 -0
- package/src/browser/workers/worker-pool.ts +548 -0
- package/src/core/delimiter-cache.js +22 -8
- package/src/core/delimiter-cache.ts +310 -0
- package/src/core/node-optimizations.ts +449 -0
- package/src/core/plugin-system.js +29 -11
- package/src/core/plugin-system.ts +400 -0
- package/src/core/transform-hooks.ts +558 -0
- package/src/engines/fast-path-engine-new.ts +347 -0
- package/src/engines/fast-path-engine.ts +854 -0
- package/src/errors.ts +72 -0
- package/src/formats/ndjson-parser.ts +469 -0
- package/src/formats/tsv-parser.ts +334 -0
- package/src/index-with-plugins.js +16 -9
- package/src/index-with-plugins.ts +395 -0
- package/src/types/index.ts +255 -0
- package/src/utils/bom-utils.js +259 -0
- package/src/utils/bom-utils.ts +373 -0
- package/src/utils/encoding-support.js +124 -0
- package/src/utils/encoding-support.ts +155 -0
- package/src/utils/schema-validator.js +19 -19
- package/src/utils/schema-validator.ts +819 -0
- package/src/utils/transform-loader.js +1 -1
- package/src/utils/transform-loader.ts +389 -0
- package/src/utils/zod-adapter.js +170 -0
- package/src/utils/zod-adapter.ts +280 -0
- package/src/web-server/index.js +10 -10
- package/src/web-server/index.ts +683 -0
- package/src/workers/csv-multithreaded.ts +310 -0
- package/src/workers/csv-parser.worker.ts +227 -0
- package/src/workers/worker-pool.ts +409 -0
- package/stream-csv-to-json.js +26 -8
- package/stream-json-to-csv.js +1 -0
package/csv-to-json.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
// @ts-nocheck
|
|
1
2
|
/**
|
|
2
3
|
* CSV to JSON Converter - Node.js Module
|
|
3
4
|
*
|
|
@@ -20,6 +21,7 @@ const {
|
|
|
20
21
|
const { TransformHooks, predefinedHooks } = require('./src/core/transform-hooks');
|
|
21
22
|
const DelimiterCache = require('./src/core/delimiter-cache');
|
|
22
23
|
const FastPathEngine = require('./src/engines/fast-path-engine');
|
|
24
|
+
const { stripBomFromString, normalizeCsvInput } = require('./src/utils/bom-utils');
|
|
23
25
|
|
|
24
26
|
// Глобальный экземпляр кэша для авто-детектирования разделителя
|
|
25
27
|
const globalDelimiterCache = new DelimiterCache(100);
|
|
@@ -73,19 +75,19 @@ function validateCsvInput(csv, options) {
|
|
|
73
75
|
throw new ConfigurationError('cache must be an instance of DelimiterCache');
|
|
74
76
|
}
|
|
75
77
|
|
|
76
|
-
if (options?.useFastPath !== undefined && typeof options.useFastPath !== 'boolean') {
|
|
77
|
-
throw new ConfigurationError('useFastPath must be a boolean');
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
if (options?.fastPathMode !== undefined
|
|
81
|
-
&& options.fastPathMode !== 'objects'
|
|
82
|
-
&& options.fastPathMode !== 'compact'
|
|
83
|
-
&& options.fastPathMode !== 'stream') {
|
|
84
|
-
throw new ConfigurationError('fastPathMode must be "objects", "compact", or "stream"');
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
// Validate hooks
|
|
88
|
-
if (options?.hooks) {
|
|
78
|
+
if (options?.useFastPath !== undefined && typeof options.useFastPath !== 'boolean') {
|
|
79
|
+
throw new ConfigurationError('useFastPath must be a boolean');
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
if (options?.fastPathMode !== undefined
|
|
83
|
+
&& options.fastPathMode !== 'objects'
|
|
84
|
+
&& options.fastPathMode !== 'compact'
|
|
85
|
+
&& options.fastPathMode !== 'stream') {
|
|
86
|
+
throw new ConfigurationError('fastPathMode must be "objects", "compact", or "stream"');
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
// Validate hooks
|
|
90
|
+
if (options?.hooks) {
|
|
89
91
|
if (typeof options.hooks !== 'object') {
|
|
90
92
|
throw new ConfigurationError('hooks must be an object');
|
|
91
93
|
}
|
|
@@ -114,9 +116,9 @@ function validateCsvInput(csv, options) {
|
|
|
114
116
|
* Parses a value based on options
|
|
115
117
|
* @private
|
|
116
118
|
*/
|
|
117
|
-
function parseCsvValue(value, options) {
|
|
118
|
-
/* istanbul ignore next */
|
|
119
|
-
const { trim = true, parseNumbers = false, parseBooleans = false } = options;
|
|
119
|
+
function parseCsvValue(value, options) {
|
|
120
|
+
/* istanbul ignore next */
|
|
121
|
+
const { trim = true, parseNumbers = false, parseBooleans = false } = options;
|
|
120
122
|
|
|
121
123
|
let result = value;
|
|
122
124
|
|
|
@@ -130,13 +132,23 @@ function parseCsvValue(value, options) {
|
|
|
130
132
|
}
|
|
131
133
|
|
|
132
134
|
// Parse numbers
|
|
133
|
-
if (parseNumbers
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
135
|
+
if (parseNumbers) {
|
|
136
|
+
// Fast numeric detection: check first character and use parseFloat
|
|
137
|
+
const trimmed = result.trim();
|
|
138
|
+
const firstChar = trimmed.charAt(0);
|
|
139
|
+
// Quick reject: if first character is not digit, minus, or dot, skip
|
|
140
|
+
if ((firstChar >= '0' && firstChar <= '9') || firstChar === '-' || firstChar === '.') {
|
|
141
|
+
const num = parseFloat(trimmed);
|
|
142
|
+
if (!isNaN(num) && isFinite(num)) {
|
|
143
|
+
// Ensure the whole string represents the same number (no extra characters)
|
|
144
|
+
// parseFloat ignores trailing non-numeric characters, so we need to verify
|
|
145
|
+
// that the string matches the parsed number when converted back
|
|
146
|
+
if (String(num) === trimmed || (trimmed.includes('.') && !isNaN(Number(trimmed)))) {
|
|
147
|
+
return num;
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
}
|
|
140
152
|
|
|
141
153
|
// Parse booleans
|
|
142
154
|
if (parseBooleans) {
|
|
@@ -150,17 +162,17 @@ function parseCsvValue(value, options) {
|
|
|
150
162
|
}
|
|
151
163
|
|
|
152
164
|
// Parse empty strings as null
|
|
153
|
-
if (result === '') {
|
|
154
|
-
return null;
|
|
155
|
-
}
|
|
156
|
-
|
|
157
|
-
return result;
|
|
158
|
-
}
|
|
159
|
-
|
|
160
|
-
/**
|
|
161
|
-
* Auto-detect CSV delimiter from content with caching support
|
|
162
|
-
* @private
|
|
163
|
-
*/
|
|
165
|
+
if (result === '') {
|
|
166
|
+
return null;
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
return result;
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
/**
|
|
173
|
+
* Auto-detect CSV delimiter from content with caching support
|
|
174
|
+
* @private
|
|
175
|
+
*/
|
|
164
176
|
function autoDetectDelimiter(csv, candidates = [';', ',', '\t', '|'], cache = null) {
|
|
165
177
|
// Используем статический метод DelimiterCache с поддержкой кэширования
|
|
166
178
|
return DelimiterCache.autoDetectDelimiter(csv, candidates, cache);
|
|
@@ -225,19 +237,21 @@ function csvToJson(csv, options = {}) {
|
|
|
225
237
|
hasHeaders = true,
|
|
226
238
|
renameMap = {},
|
|
227
239
|
trim = true,
|
|
228
|
-
parseNumbers = false,
|
|
229
|
-
parseBooleans = false,
|
|
230
|
-
maxRows,
|
|
231
|
-
useCache = true,
|
|
232
|
-
cache: customCache,
|
|
233
|
-
useFastPath = true,
|
|
234
|
-
fastPathMode = 'objects',
|
|
235
|
-
hooks = {}
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
240
|
+
parseNumbers = false,
|
|
241
|
+
parseBooleans = false,
|
|
242
|
+
maxRows,
|
|
243
|
+
useCache = true,
|
|
244
|
+
cache: customCache,
|
|
245
|
+
useFastPath = true,
|
|
246
|
+
fastPathMode = 'objects',
|
|
247
|
+
hooks = {},
|
|
248
|
+
stripBom = true, // New option: strip BOM by default
|
|
249
|
+
normalizeEncoding = true // New option: normalize encoding
|
|
250
|
+
} = opts;
|
|
251
|
+
|
|
252
|
+
if (fastPathMode === 'stream') {
|
|
253
|
+
return csvToJsonIterator(csv, { ...opts, useFastPath, fastPathMode: 'objects' });
|
|
254
|
+
}
|
|
241
255
|
|
|
242
256
|
// Выбираем кэш для использования
|
|
243
257
|
const cacheToUse = useCache ? (customCache || globalDelimiterCache) : null;
|
|
@@ -261,10 +275,19 @@ function csvToJson(csv, options = {}) {
|
|
|
261
275
|
// Use provided TransformHooks instance if available
|
|
262
276
|
const finalHooks = hooks.transformHooks || transformHooks;
|
|
263
277
|
|
|
278
|
+
// Handle BOM and encoding normalization
|
|
279
|
+
let normalizedCsv = csv;
|
|
280
|
+
if (stripBom) {
|
|
281
|
+
normalizedCsv = stripBomFromString(normalizedCsv);
|
|
282
|
+
}
|
|
283
|
+
if (normalizeEncoding) {
|
|
284
|
+
normalizedCsv = normalizeCsvInput(normalizedCsv, { normalizeLineEndings: true });
|
|
285
|
+
}
|
|
286
|
+
|
|
264
287
|
// Apply beforeConvert hooks to CSV string
|
|
265
|
-
const processedCsv = finalHooks.applyBeforeConvert(
|
|
288
|
+
const processedCsv = finalHooks.applyBeforeConvert(normalizedCsv, {
|
|
266
289
|
operation: 'csvToJson',
|
|
267
|
-
options: opts
|
|
290
|
+
options: opts
|
|
268
291
|
});
|
|
269
292
|
|
|
270
293
|
// Determine delimiter with caching support
|
|
@@ -285,13 +308,13 @@ function csvToJson(csv, options = {}) {
|
|
|
285
308
|
const result = [];
|
|
286
309
|
|
|
287
310
|
try {
|
|
288
|
-
const parseOptions = { delimiter: finalDelimiter };
|
|
289
|
-
if (useFastPath === false) {
|
|
290
|
-
parseOptions.forceEngine = 'STANDARD';
|
|
291
|
-
}
|
|
292
|
-
|
|
293
|
-
globalFastPathEngine.parseRows(processedCsv, parseOptions, (fields) => {
|
|
294
|
-
totalRows++;
|
|
311
|
+
const parseOptions = { delimiter: finalDelimiter };
|
|
312
|
+
if (useFastPath === false) {
|
|
313
|
+
parseOptions.forceEngine = 'STANDARD';
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
globalFastPathEngine.parseRows(processedCsv, parseOptions, (fields) => {
|
|
317
|
+
totalRows++;
|
|
295
318
|
|
|
296
319
|
if (!headers) {
|
|
297
320
|
if (hasHeaders) {
|
|
@@ -308,10 +331,10 @@ function csvToJson(csv, options = {}) {
|
|
|
308
331
|
return;
|
|
309
332
|
}
|
|
310
333
|
|
|
311
|
-
if (maxRows && totalRows > maxRows) {
|
|
312
|
-
throw new LimitError(
|
|
313
|
-
`CSV size exceeds maximum limit of ${maxRows} rows`,
|
|
314
|
-
maxRows,
|
|
334
|
+
if (maxRows && totalRows > maxRows) {
|
|
335
|
+
throw new LimitError(
|
|
336
|
+
`CSV size exceeds maximum limit of ${maxRows} rows`,
|
|
337
|
+
maxRows,
|
|
315
338
|
totalRows
|
|
316
339
|
);
|
|
317
340
|
}
|
|
@@ -344,26 +367,26 @@ function csvToJson(csv, options = {}) {
|
|
|
344
367
|
console.warn(`[jtcsv] Line ${totalRows}: ${fields.length - headers.length} extra fields ignored`);
|
|
345
368
|
}
|
|
346
369
|
});
|
|
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
|
-
}
|
|
370
|
+
} catch (error) {
|
|
371
|
+
if (error && error.code === 'FAST_PATH_UNCLOSED_QUOTES') {
|
|
372
|
+
const lineInfo = error.lineNumber ? ` at line ${error.lineNumber}` : '';
|
|
373
|
+
throw new ParsingError(`Unclosed quotes in CSV${lineInfo}`, error.lineNumber);
|
|
374
|
+
}
|
|
375
|
+
throw error;
|
|
376
|
+
}
|
|
354
377
|
|
|
355
378
|
if (!headers) {
|
|
356
379
|
return [];
|
|
357
380
|
}
|
|
358
381
|
|
|
359
|
-
if (totalRows > 1000000 && !maxRows && process.env.NODE_ENV !== 'test') {
|
|
360
|
-
console.warn(
|
|
361
|
-
'Warning: Processing >1M records in memory may be slow.\n' +
|
|
362
|
-
'Consider using createCsvToJsonStream() for better performance with large files.\n' +
|
|
363
|
-
'Current size: ' + totalRows.toLocaleString() + ' rows\n' +
|
|
364
|
-
'Tip: Use { maxRows: N } option to set a custom limit if needed.'
|
|
365
|
-
);
|
|
366
|
-
}
|
|
382
|
+
if (totalRows > 1000000 && !maxRows && process.env.NODE_ENV !== 'test') {
|
|
383
|
+
console.warn(
|
|
384
|
+
'Warning: Processing >1M records in memory may be slow.\n' +
|
|
385
|
+
'Consider using createCsvToJsonStream() for better performance with large files.\n' +
|
|
386
|
+
'Current size: ' + totalRows.toLocaleString() + ' rows\n' +
|
|
387
|
+
'Tip: Use { maxRows: N } option to set a custom limit if needed.'
|
|
388
|
+
);
|
|
389
|
+
}
|
|
367
390
|
|
|
368
391
|
return finalHooks.applyAfterConvert(result, {
|
|
369
392
|
operation: 'csvToJson',
|
|
@@ -374,8 +397,8 @@ function csvToJson(csv, options = {}) {
|
|
|
374
397
|
}, 'PARSE_FAILED', { function: 'csvToJson' });
|
|
375
398
|
}
|
|
376
399
|
|
|
377
|
-
/* istanbul ignore next */
|
|
378
|
-
async function* csvToJsonIterator(csv, options = {}) {
|
|
400
|
+
/* istanbul ignore next */
|
|
401
|
+
async function* csvToJsonIterator(csv, options = {}) {
|
|
379
402
|
validateCsvInput(csv, options);
|
|
380
403
|
|
|
381
404
|
const opts = options && typeof options === 'object' ? options : {};
|
|
@@ -387,15 +410,15 @@ async function* csvToJsonIterator(csv, options = {}) {
|
|
|
387
410
|
hasHeaders = true,
|
|
388
411
|
renameMap = {},
|
|
389
412
|
trim = true,
|
|
390
|
-
parseNumbers = false,
|
|
391
|
-
parseBooleans = false,
|
|
392
|
-
maxRows,
|
|
393
|
-
useCache = true,
|
|
394
|
-
cache: customCache,
|
|
395
|
-
useFastPath = true,
|
|
396
|
-
fastPathMode = 'objects',
|
|
397
|
-
hooks = {}
|
|
398
|
-
} = opts;
|
|
413
|
+
parseNumbers = false,
|
|
414
|
+
parseBooleans = false,
|
|
415
|
+
maxRows,
|
|
416
|
+
useCache = true,
|
|
417
|
+
cache: customCache,
|
|
418
|
+
useFastPath = true,
|
|
419
|
+
fastPathMode = 'objects',
|
|
420
|
+
hooks = {}
|
|
421
|
+
} = opts;
|
|
399
422
|
|
|
400
423
|
const cacheToUse = useCache ? (customCache || globalDelimiterCache) : null;
|
|
401
424
|
|
|
@@ -446,20 +469,20 @@ async function* csvToJsonIterator(csv, options = {}) {
|
|
|
446
469
|
headers = fields.map((_, index) => `column${index + 1}`);
|
|
447
470
|
}
|
|
448
471
|
|
|
449
|
-
if (!fields || fields.length === 0) {
|
|
450
|
-
return null;
|
|
451
|
-
}
|
|
452
|
-
|
|
453
|
-
const fieldCount = Math.min(fields.length, headers.length);
|
|
472
|
+
if (!fields || fields.length === 0) {
|
|
473
|
+
return null;
|
|
474
|
+
}
|
|
475
|
+
|
|
476
|
+
const fieldCount = Math.min(fields.length, headers.length);
|
|
454
477
|
let row;
|
|
455
478
|
|
|
456
|
-
const resolvedFastPathMode = fastPathMode === 'stream' ? 'objects' : fastPathMode;
|
|
457
|
-
|
|
458
|
-
if (resolvedFastPathMode === 'compact') {
|
|
459
|
-
row = new Array(fieldCount);
|
|
460
|
-
for (let j = 0; j < fieldCount; j++) {
|
|
461
|
-
row[j] = parseCsvValue(fields[j], { trim, parseNumbers, parseBooleans });
|
|
462
|
-
}
|
|
479
|
+
const resolvedFastPathMode = fastPathMode === 'stream' ? 'objects' : fastPathMode;
|
|
480
|
+
|
|
481
|
+
if (resolvedFastPathMode === 'compact') {
|
|
482
|
+
row = new Array(fieldCount);
|
|
483
|
+
for (let j = 0; j < fieldCount; j++) {
|
|
484
|
+
row[j] = parseCsvValue(fields[j], { trim, parseNumbers, parseBooleans });
|
|
485
|
+
}
|
|
463
486
|
} else {
|
|
464
487
|
row = {};
|
|
465
488
|
for (let j = 0; j < fieldCount; j++) {
|
|
@@ -477,37 +500,37 @@ async function* csvToJsonIterator(csv, options = {}) {
|
|
|
477
500
|
return processedRow;
|
|
478
501
|
};
|
|
479
502
|
|
|
480
|
-
try {
|
|
481
|
-
const parseOptions = { delimiter: finalDelimiter };
|
|
482
|
-
if (useFastPath === false) {
|
|
483
|
-
parseOptions.forceEngine = 'STANDARD';
|
|
484
|
-
}
|
|
485
|
-
|
|
486
|
-
for (const fields of globalFastPathEngine.iterateRows(processedCsv, parseOptions)) {
|
|
487
|
-
totalRows++;
|
|
488
|
-
if (maxRows && totalRows > maxRows) {
|
|
489
|
-
throw new LimitError(
|
|
490
|
-
`CSV size exceeds maximum limit of ${maxRows} rows`,
|
|
491
|
-
maxRows,
|
|
492
|
-
totalRows
|
|
493
|
-
);
|
|
494
|
-
}
|
|
495
|
-
const processedRow = handleFields(fields, totalRows);
|
|
496
|
-
if (processedRow !== undefined && processedRow !== null) {
|
|
497
|
-
if (fields.length > headers.length && process.env.NODE_ENV === 'development') {
|
|
498
|
-
console.warn(`[jtcsv] Line ${totalRows}: ${fields.length - headers.length} extra fields ignored`);
|
|
499
|
-
}
|
|
500
|
-
yield processedRow;
|
|
501
|
-
}
|
|
502
|
-
}
|
|
503
|
-
} catch (error) {
|
|
504
|
-
if (error && error.code === 'FAST_PATH_UNCLOSED_QUOTES') {
|
|
505
|
-
const lineInfo = error.lineNumber ? ` at line ${error.lineNumber}` : '';
|
|
506
|
-
throw new ParsingError(`Unclosed quotes in CSV${lineInfo}`, error.lineNumber);
|
|
507
|
-
}
|
|
508
|
-
throw error;
|
|
509
|
-
}
|
|
510
|
-
}
|
|
503
|
+
try {
|
|
504
|
+
const parseOptions = { delimiter: finalDelimiter };
|
|
505
|
+
if (useFastPath === false) {
|
|
506
|
+
parseOptions.forceEngine = 'STANDARD';
|
|
507
|
+
}
|
|
508
|
+
|
|
509
|
+
for (const fields of globalFastPathEngine.iterateRows(processedCsv, parseOptions)) {
|
|
510
|
+
totalRows++;
|
|
511
|
+
if (maxRows && totalRows > maxRows) {
|
|
512
|
+
throw new LimitError(
|
|
513
|
+
`CSV size exceeds maximum limit of ${maxRows} rows`,
|
|
514
|
+
maxRows,
|
|
515
|
+
totalRows
|
|
516
|
+
);
|
|
517
|
+
}
|
|
518
|
+
const processedRow = handleFields(fields, totalRows);
|
|
519
|
+
if (processedRow !== undefined && processedRow !== null) {
|
|
520
|
+
if (fields.length > headers.length && process.env.NODE_ENV === 'development') {
|
|
521
|
+
console.warn(`[jtcsv] Line ${totalRows}: ${fields.length - headers.length} extra fields ignored`);
|
|
522
|
+
}
|
|
523
|
+
yield processedRow;
|
|
524
|
+
}
|
|
525
|
+
}
|
|
526
|
+
} catch (error) {
|
|
527
|
+
if (error && error.code === 'FAST_PATH_UNCLOSED_QUOTES') {
|
|
528
|
+
const lineInfo = error.lineNumber ? ` at line ${error.lineNumber}` : '';
|
|
529
|
+
throw new ParsingError(`Unclosed quotes in CSV${lineInfo}`, error.lineNumber);
|
|
530
|
+
}
|
|
531
|
+
throw error;
|
|
532
|
+
}
|
|
533
|
+
}
|
|
511
534
|
|
|
512
535
|
/**
|
|
513
536
|
* Validates file path for CSV reading
|
|
@@ -643,27 +666,27 @@ function createTransformHooks() {
|
|
|
643
666
|
* @param {number} maxSize - Maximum cache size (default: 100)
|
|
644
667
|
* @returns {DelimiterCache} New DelimiterCache instance
|
|
645
668
|
*/
|
|
646
|
-
/* istanbul ignore next */
|
|
647
|
-
function createDelimiterCache(maxSize = 100) {
|
|
648
|
-
return new DelimiterCache(maxSize);
|
|
649
|
-
}
|
|
669
|
+
/* istanbul ignore next */
|
|
670
|
+
function createDelimiterCache(maxSize = 100) {
|
|
671
|
+
return new DelimiterCache(maxSize);
|
|
672
|
+
}
|
|
650
673
|
|
|
651
674
|
/**
|
|
652
675
|
* Gets statistics from the global delimiter cache
|
|
653
676
|
* @returns {Object} Cache statistics
|
|
654
677
|
*/
|
|
655
|
-
/* istanbul ignore next */
|
|
656
|
-
function getDelimiterCacheStats() {
|
|
657
|
-
return globalDelimiterCache.getStats();
|
|
658
|
-
}
|
|
678
|
+
/* istanbul ignore next */
|
|
679
|
+
function getDelimiterCacheStats() {
|
|
680
|
+
return globalDelimiterCache.getStats();
|
|
681
|
+
}
|
|
659
682
|
|
|
660
683
|
/**
|
|
661
684
|
* Clears the global delimiter cache
|
|
662
685
|
*/
|
|
663
|
-
/* istanbul ignore next */
|
|
664
|
-
function clearDelimiterCache() {
|
|
665
|
-
globalDelimiterCache.clear();
|
|
666
|
-
}
|
|
686
|
+
/* istanbul ignore next */
|
|
687
|
+
function clearDelimiterCache() {
|
|
688
|
+
globalDelimiterCache.clear();
|
|
689
|
+
}
|
|
667
690
|
|
|
668
691
|
// Export the functions
|
|
669
692
|
module.exports = {
|
|
@@ -682,7 +705,7 @@ module.exports = {
|
|
|
682
705
|
};
|
|
683
706
|
|
|
684
707
|
// For ES6 module compatibility
|
|
685
|
-
/* istanbul ignore next */
|
|
686
|
-
if (typeof module !== 'undefined' && module.exports) {
|
|
687
|
-
module.exports.default = csvToJson;
|
|
688
|
-
}
|
|
708
|
+
/* istanbul ignore next */
|
|
709
|
+
if (typeof module !== 'undefined' && module.exports) {
|
|
710
|
+
module.exports.default = csvToJson;
|
|
711
|
+
}
|