jtcsv 2.2.8 → 3.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/README.md +204 -115
- package/bin/jtcsv.ts +2612 -0
- package/browser.d.ts +142 -0
- package/dist/benchmark.js +446 -0
- package/dist/benchmark.js.map +1 -0
- package/dist/bin/jtcsv.js +1940 -0
- package/dist/bin/jtcsv.js.map +1 -0
- package/dist/csv-to-json.js +1262 -0
- package/dist/csv-to-json.js.map +1 -0
- package/dist/errors.js +291 -0
- package/dist/errors.js.map +1 -0
- package/dist/eslint.config.js +147 -0
- package/dist/eslint.config.js.map +1 -0
- package/dist/index-core.js +95 -0
- package/dist/index-core.js.map +1 -0
- package/dist/index.js +93 -0
- package/dist/index.js.map +1 -0
- package/dist/json-save.js +229 -0
- package/dist/json-save.js.map +1 -0
- package/dist/json-to-csv.js +576 -0
- package/dist/json-to-csv.js.map +1 -0
- package/dist/jtcsv-core.cjs.js +1736 -0
- package/dist/jtcsv-core.cjs.js.map +1 -0
- package/dist/jtcsv-core.esm.js +1708 -0
- package/dist/jtcsv-core.esm.js.map +1 -0
- package/dist/jtcsv-core.umd.js +1742 -0
- package/dist/jtcsv-core.umd.js.map +1 -0
- package/dist/jtcsv-full.cjs.js +2241 -0
- package/dist/jtcsv-full.cjs.js.map +1 -0
- package/dist/jtcsv-full.esm.js +2209 -0
- package/dist/jtcsv-full.esm.js.map +1 -0
- package/dist/jtcsv-full.umd.js +2247 -0
- package/dist/jtcsv-full.umd.js.map +1 -0
- package/dist/jtcsv-workers.esm.js +768 -0
- package/dist/jtcsv-workers.esm.js.map +1 -0
- package/dist/jtcsv-workers.umd.js +782 -0
- package/dist/jtcsv-workers.umd.js.map +1 -0
- package/dist/jtcsv.cjs.js +1996 -2048
- package/dist/jtcsv.cjs.js.map +1 -1
- package/dist/jtcsv.esm.js +1992 -2048
- package/dist/jtcsv.esm.js.map +1 -1
- package/dist/jtcsv.umd.js +2157 -2209
- package/dist/jtcsv.umd.js.map +1 -1
- package/dist/plugins/express-middleware/index.js +350 -0
- package/dist/plugins/express-middleware/index.js.map +1 -0
- package/dist/plugins/fastify-plugin/index.js +315 -0
- package/dist/plugins/fastify-plugin/index.js.map +1 -0
- package/dist/plugins/hono/index.js +111 -0
- package/dist/plugins/hono/index.js.map +1 -0
- package/dist/plugins/nestjs/index.js +112 -0
- package/dist/plugins/nestjs/index.js.map +1 -0
- package/dist/plugins/nuxt/index.js +53 -0
- package/dist/plugins/nuxt/index.js.map +1 -0
- package/dist/plugins/remix/index.js +133 -0
- package/dist/plugins/remix/index.js.map +1 -0
- package/dist/plugins/sveltekit/index.js +155 -0
- package/dist/plugins/sveltekit/index.js.map +1 -0
- package/dist/plugins/trpc/index.js +136 -0
- package/dist/plugins/trpc/index.js.map +1 -0
- package/dist/run-demo.js +49 -0
- package/dist/run-demo.js.map +1 -0
- package/dist/src/browser/browser-functions.js +193 -0
- package/dist/src/browser/browser-functions.js.map +1 -0
- package/dist/src/browser/core.js +123 -0
- package/dist/src/browser/core.js.map +1 -0
- package/dist/src/browser/csv-to-json-browser.js +353 -0
- package/dist/src/browser/csv-to-json-browser.js.map +1 -0
- package/dist/src/browser/errors-browser.js +219 -0
- package/dist/src/browser/errors-browser.js.map +1 -0
- package/dist/src/browser/extensions/plugins.js +106 -0
- package/dist/src/browser/extensions/plugins.js.map +1 -0
- package/dist/src/browser/extensions/workers.js +66 -0
- package/dist/src/browser/extensions/workers.js.map +1 -0
- package/dist/src/browser/index.js +140 -0
- package/dist/src/browser/index.js.map +1 -0
- package/dist/src/browser/json-to-csv-browser.js +225 -0
- package/dist/src/browser/json-to-csv-browser.js.map +1 -0
- package/dist/src/browser/streams.js +340 -0
- package/dist/src/browser/streams.js.map +1 -0
- package/dist/src/browser/workers/csv-parser.worker.js +264 -0
- package/dist/src/browser/workers/csv-parser.worker.js.map +1 -0
- package/dist/src/browser/workers/worker-pool.js +338 -0
- package/dist/src/browser/workers/worker-pool.js.map +1 -0
- package/dist/src/core/delimiter-cache.js +196 -0
- package/dist/src/core/delimiter-cache.js.map +1 -0
- package/dist/src/core/node-optimizations.js +279 -0
- package/dist/src/core/node-optimizations.js.map +1 -0
- package/dist/src/core/plugin-system.js +399 -0
- package/dist/src/core/plugin-system.js.map +1 -0
- package/dist/src/core/transform-hooks.js +348 -0
- package/dist/src/core/transform-hooks.js.map +1 -0
- package/dist/src/engines/fast-path-engine-new.js +262 -0
- package/dist/src/engines/fast-path-engine-new.js.map +1 -0
- package/dist/src/engines/fast-path-engine.js +671 -0
- package/dist/src/engines/fast-path-engine.js.map +1 -0
- package/dist/src/errors.js +18 -0
- package/dist/src/errors.js.map +1 -0
- package/dist/src/formats/ndjson-parser.js +332 -0
- package/dist/src/formats/ndjson-parser.js.map +1 -0
- package/dist/src/formats/tsv-parser.js +230 -0
- package/dist/src/formats/tsv-parser.js.map +1 -0
- package/dist/src/index-with-plugins.js +259 -0
- package/dist/src/index-with-plugins.js.map +1 -0
- package/dist/src/types/index.js +3 -0
- package/dist/src/types/index.js.map +1 -0
- package/dist/src/utils/bom-utils.js +267 -0
- package/dist/src/utils/bom-utils.js.map +1 -0
- package/dist/src/utils/encoding-support.js +77 -0
- package/dist/src/utils/encoding-support.js.map +1 -0
- package/dist/src/utils/schema-validator.js +609 -0
- package/dist/src/utils/schema-validator.js.map +1 -0
- package/dist/src/utils/transform-loader.js +281 -0
- package/dist/src/utils/transform-loader.js.map +1 -0
- package/dist/src/utils/validators.js +40 -0
- package/dist/src/utils/validators.js.map +1 -0
- package/dist/src/utils/zod-adapter.js +144 -0
- package/dist/src/utils/zod-adapter.js.map +1 -0
- package/dist/src/web-server/index.js +648 -0
- package/dist/src/web-server/index.js.map +1 -0
- package/dist/src/workers/csv-multithreaded.js +211 -0
- package/dist/src/workers/csv-multithreaded.js.map +1 -0
- package/dist/src/workers/csv-parser.worker.js +179 -0
- package/dist/src/workers/csv-parser.worker.js.map +1 -0
- package/dist/src/workers/worker-pool.js +228 -0
- package/dist/src/workers/worker-pool.js.map +1 -0
- package/dist/stream-csv-to-json.js +665 -0
- package/dist/stream-csv-to-json.js.map +1 -0
- package/dist/stream-json-to-csv.js +389 -0
- package/dist/stream-json-to-csv.js.map +1 -0
- package/examples/advanced/conditional-transformations.ts +446 -0
- package/examples/advanced/csv-parser.worker.ts +89 -0
- package/examples/advanced/nested-objects-example.ts +306 -0
- package/examples/advanced/performance-optimization.ts +504 -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 +290 -0
- package/examples/{cli-batch-processing.js → cli-batch-processing.ts} +38 -38
- package/examples/{cli-tool.js → cli-tool.ts} +5 -8
- package/examples/{error-handling.js → error-handling.ts} +356 -324
- package/examples/{express-api.js → express-api.ts} +161 -164
- package/examples/{large-dataset-example.js → large-dataset-example.ts} +201 -182
- package/examples/{ndjson-processing.js → ndjson-processing.ts} +456 -434
- package/examples/{plugin-excel-exporter.js → plugin-excel-exporter.ts} +6 -7
- package/examples/react-integration.tsx +637 -0
- package/examples/{schema-validation.js → schema-validation.ts} +2 -2
- package/examples/simple-usage.ts +194 -0
- package/examples/{streaming-example.js → streaming-example.ts} +12 -12
- package/index.d.ts +187 -18
- package/package.json +75 -81
- package/plugins.d.ts +37 -0
- package/schema.d.ts +103 -0
- package/src/browser/browser-functions.ts +402 -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.ts +494 -0
- package/src/browser/{errors-browser.js → errors-browser.ts} +305 -197
- package/src/browser/extensions/plugins.ts +93 -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.ts +338 -0
- package/src/browser/streams.ts +403 -0
- package/src/browser/workers/{csv-parser.worker.js → csv-parser.worker.ts} +3 -3
- package/src/browser/workers/{worker-pool.js → worker-pool.ts} +51 -30
- package/src/core/delimiter-cache.ts +320 -0
- package/src/core/{node-optimizations.js → node-optimizations.ts} +448 -407
- package/src/core/plugin-system.ts +588 -0
- package/src/core/transform-hooks.ts +566 -0
- package/src/engines/{fast-path-engine-new.js → fast-path-engine-new.ts} +11 -2
- package/src/engines/{fast-path-engine.js → fast-path-engine.ts} +79 -53
- package/src/errors.ts +1 -0
- package/src/formats/{ndjson-parser.js → ndjson-parser.ts} +24 -16
- package/src/formats/{tsv-parser.js → tsv-parser.ts} +18 -17
- package/src/{index-with-plugins.js → index-with-plugins.ts} +381 -357
- package/src/types/index.ts +275 -0
- package/src/utils/bom-utils.ts +373 -0
- package/src/utils/encoding-support.ts +155 -0
- package/src/utils/{schema-validator.js → schema-validator.ts} +814 -589
- package/src/utils/transform-loader.ts +389 -0
- package/src/utils/validators.ts +35 -0
- package/src/utils/zod-adapter.ts +280 -0
- package/src/web-server/{index.js → index.ts} +19 -19
- 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/bin/jtcsv.js +0 -2462
- package/csv-to-json.js +0 -688
- package/errors.js +0 -208
- package/examples/simple-usage.js +0 -282
- package/index.js +0 -68
- package/json-save.js +0 -254
- package/json-to-csv.js +0 -526
- package/plugins/README.md +0 -91
- package/plugins/express-middleware/README.md +0 -64
- package/plugins/express-middleware/example.js +0 -136
- package/plugins/express-middleware/index.d.ts +0 -114
- package/plugins/express-middleware/index.js +0 -360
- package/plugins/express-middleware/package.json +0 -52
- package/plugins/fastify-plugin/index.js +0 -406
- package/plugins/fastify-plugin/package.json +0 -55
- package/plugins/hono/README.md +0 -28
- package/plugins/hono/index.d.ts +0 -12
- package/plugins/hono/index.js +0 -36
- package/plugins/hono/package.json +0 -35
- package/plugins/nestjs/README.md +0 -35
- package/plugins/nestjs/index.d.ts +0 -25
- package/plugins/nestjs/index.js +0 -77
- package/plugins/nestjs/package.json +0 -37
- package/plugins/nextjs-api/README.md +0 -57
- package/plugins/nextjs-api/examples/ConverterComponent.jsx +0 -386
- package/plugins/nextjs-api/examples/api-convert.js +0 -69
- package/plugins/nextjs-api/index.js +0 -387
- package/plugins/nextjs-api/package.json +0 -63
- package/plugins/nextjs-api/route.js +0 -371
- package/plugins/nuxt/README.md +0 -24
- package/plugins/nuxt/index.js +0 -21
- package/plugins/nuxt/package.json +0 -35
- package/plugins/nuxt/runtime/composables/useJtcsv.js +0 -6
- package/plugins/nuxt/runtime/plugin.js +0 -6
- package/plugins/remix/README.md +0 -26
- package/plugins/remix/index.d.ts +0 -16
- package/plugins/remix/index.js +0 -62
- package/plugins/remix/package.json +0 -35
- package/plugins/sveltekit/README.md +0 -28
- package/plugins/sveltekit/index.d.ts +0 -17
- package/plugins/sveltekit/index.js +0 -54
- package/plugins/sveltekit/package.json +0 -33
- package/plugins/trpc/README.md +0 -25
- package/plugins/trpc/index.d.ts +0 -7
- package/plugins/trpc/index.js +0 -32
- package/plugins/trpc/package.json +0 -34
- package/src/browser/browser-functions.js +0 -219
- package/src/browser/csv-to-json-browser.js +0 -700
- package/src/browser/index.js +0 -113
- package/src/browser/json-to-csv-browser.js +0 -309
- package/src/browser/streams.js +0 -393
- package/src/core/delimiter-cache.js +0 -186
- package/src/core/plugin-system.js +0 -476
- package/src/core/transform-hooks.js +0 -350
- package/src/errors.js +0 -26
- package/src/utils/transform-loader.js +0 -205
- package/stream-csv-to-json.js +0 -542
- package/stream-json-to-csv.js +0 -464
- /package/examples/{web-workers-advanced.js → web-workers-advanced.ts} +0 -0
|
@@ -6,8 +6,18 @@
|
|
|
6
6
|
* @date 2026-01-22
|
|
7
7
|
*/
|
|
8
8
|
|
|
9
|
-
class FastPathEngine {
|
|
10
|
-
|
|
9
|
+
class FastPathEngine {
|
|
10
|
+
compilers: Map<any, any>;
|
|
11
|
+
rowCompilers: Map<any, any>;
|
|
12
|
+
stats: {
|
|
13
|
+
simpleParserCount: number;
|
|
14
|
+
quoteAwareParserCount: number;
|
|
15
|
+
standardParserCount: number;
|
|
16
|
+
cacheHits: number;
|
|
17
|
+
cacheMisses: number;
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
constructor() {
|
|
11
21
|
this.compilers = new Map();
|
|
12
22
|
this.rowCompilers = new Map();
|
|
13
23
|
this.stats = {
|
|
@@ -31,7 +41,7 @@ class FastPathEngine {
|
|
|
31
41
|
return csv.indexOf('\\') !== -1;
|
|
32
42
|
}
|
|
33
43
|
|
|
34
|
-
_getStructureForParse(csv, options) {
|
|
44
|
+
_getStructureForParse(csv: any, options: any) {
|
|
35
45
|
const sampleSize = Math.min(1000, csv.length);
|
|
36
46
|
const sample = csv.substring(0, sampleSize);
|
|
37
47
|
const structure = this.analyzeStructure(sample, options);
|
|
@@ -69,7 +79,7 @@ class FastPathEngine {
|
|
|
69
79
|
/**
|
|
70
80
|
* Анализирует структуру CSV и определяет оптимальный парсер
|
|
71
81
|
*/
|
|
72
|
-
analyzeStructure(sample, options = {}) {
|
|
82
|
+
analyzeStructure(sample: any, options: any = {}) {
|
|
73
83
|
const delimiter = options.delimiter || this._detectDelimiter(sample);
|
|
74
84
|
const lines = sample.split('\n').slice(0, 10);
|
|
75
85
|
|
|
@@ -151,7 +161,7 @@ class FastPathEngine {
|
|
|
151
161
|
/**
|
|
152
162
|
* Выбирает оптимальный движок парсинга
|
|
153
163
|
*/
|
|
154
|
-
_selectEngine(hasQuotes, hasNewlinesInFields, _fieldConsistency) {
|
|
164
|
+
_selectEngine(hasQuotes: any, hasNewlinesInFields: any, _fieldConsistency: any) {
|
|
155
165
|
if (!hasQuotes && !hasNewlinesInFields) {
|
|
156
166
|
return 'SIMPLE';
|
|
157
167
|
}
|
|
@@ -181,7 +191,7 @@ class FastPathEngine {
|
|
|
181
191
|
};
|
|
182
192
|
}
|
|
183
193
|
|
|
184
|
-
_emitSimpleRows(csv, delimiter, onRow) {
|
|
194
|
+
_emitSimpleRows(csv: any, delimiter: any, onRow: any) {
|
|
185
195
|
let currentRow = [];
|
|
186
196
|
let rowHasData = false;
|
|
187
197
|
let fieldStart = 0;
|
|
@@ -190,9 +200,9 @@ class FastPathEngine {
|
|
|
190
200
|
while (i <= csv.length) {
|
|
191
201
|
const char = i < csv.length ? csv[i] : '\n';
|
|
192
202
|
|
|
193
|
-
if (char !== '\r' && char !== '\n' && char !== ' ' && char !== '\t') {
|
|
194
|
-
rowHasData = true;
|
|
195
|
-
}
|
|
203
|
+
if (!rowHasData && char !== '\r' && char !== '\n' && char !== ' ' && char !== '\t') {
|
|
204
|
+
rowHasData = true;
|
|
205
|
+
}
|
|
196
206
|
|
|
197
207
|
if (char === delimiter || char === '\n' || char === '\r' || i === csv.length) {
|
|
198
208
|
const field = csv.slice(fieldStart, i);
|
|
@@ -217,7 +227,7 @@ class FastPathEngine {
|
|
|
217
227
|
}
|
|
218
228
|
}
|
|
219
229
|
|
|
220
|
-
_emitSimpleRowsEscaped(csv, delimiter, onRow) {
|
|
230
|
+
_emitSimpleRowsEscaped(csv: any, delimiter: any, onRow: any) {
|
|
221
231
|
let currentRow = [];
|
|
222
232
|
let currentField = '';
|
|
223
233
|
let rowHasData = false;
|
|
@@ -228,9 +238,9 @@ class FastPathEngine {
|
|
|
228
238
|
const char = i < csv.length ? csv[i] : '\n';
|
|
229
239
|
const nextChar = i + 1 < csv.length ? csv[i + 1] : '';
|
|
230
240
|
|
|
231
|
-
if (char !== '\r' && char !== '\n' && char !== ' ' && char !== '\t') {
|
|
232
|
-
rowHasData = true;
|
|
233
|
-
}
|
|
241
|
+
if (!rowHasData && char !== '\r' && char !== '\n' && char !== ' ' && char !== '\t') {
|
|
242
|
+
rowHasData = true;
|
|
243
|
+
}
|
|
234
244
|
|
|
235
245
|
if (escapeNext) {
|
|
236
246
|
currentField += char;
|
|
@@ -288,7 +298,7 @@ class FastPathEngine {
|
|
|
288
298
|
}
|
|
289
299
|
}
|
|
290
300
|
|
|
291
|
-
*_simpleRowsGenerator(csv, delimiter) {
|
|
301
|
+
*_simpleRowsGenerator(csv: any, delimiter: any) {
|
|
292
302
|
let currentRow = [];
|
|
293
303
|
let rowHasData = false;
|
|
294
304
|
let fieldStart = 0;
|
|
@@ -324,7 +334,7 @@ class FastPathEngine {
|
|
|
324
334
|
}
|
|
325
335
|
}
|
|
326
336
|
|
|
327
|
-
*_simpleEscapedRowsGenerator(csv, delimiter) {
|
|
337
|
+
*_simpleEscapedRowsGenerator(csv: any, delimiter: any) {
|
|
328
338
|
let currentRow = [];
|
|
329
339
|
let currentField = '';
|
|
330
340
|
let rowHasData = false;
|
|
@@ -401,7 +411,7 @@ class FastPathEngine {
|
|
|
401
411
|
_createSimpleRowEmitter(structure) {
|
|
402
412
|
const { delimiter, hasBackslashes } = structure;
|
|
403
413
|
|
|
404
|
-
return (csv, onRow) => {
|
|
414
|
+
return (csv: any, onRow: any) => {
|
|
405
415
|
if (hasBackslashes) {
|
|
406
416
|
this._emitSimpleRowsEscaped(csv, delimiter, onRow);
|
|
407
417
|
} else {
|
|
@@ -437,7 +447,7 @@ class FastPathEngine {
|
|
|
437
447
|
_createQuoteAwareRowEmitter(structure) {
|
|
438
448
|
const { delimiter, hasEscapedQuotes, hasBackslashes } = structure;
|
|
439
449
|
|
|
440
|
-
return (csv, onRow) => {
|
|
450
|
+
return (csv: any, onRow: any) => {
|
|
441
451
|
const iterator = hasBackslashes
|
|
442
452
|
? this._quoteAwareEscapedRowsGenerator(csv, delimiter, hasEscapedQuotes)
|
|
443
453
|
: this._quoteAwareRowsGenerator(csv, delimiter, hasEscapedQuotes);
|
|
@@ -448,7 +458,7 @@ class FastPathEngine {
|
|
|
448
458
|
};
|
|
449
459
|
}
|
|
450
460
|
|
|
451
|
-
*_quoteAwareRowsGenerator(csv, delimiter, hasEscapedQuotes) {
|
|
461
|
+
*_quoteAwareRowsGenerator(csv: any, delimiter: any, hasEscapedQuotes: any) {
|
|
452
462
|
let currentRow = [];
|
|
453
463
|
let currentField = '';
|
|
454
464
|
let rowHasData = false;
|
|
@@ -489,19 +499,27 @@ class FastPathEngine {
|
|
|
489
499
|
continue;
|
|
490
500
|
}
|
|
491
501
|
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
502
|
+
if (nextChar === delimiter || nextChar === '\n' || nextChar === '\r' || i + 1 >= csv.length) {
|
|
503
|
+
insideQuotes = false;
|
|
504
|
+
i++;
|
|
505
|
+
continue;
|
|
506
|
+
}
|
|
507
|
+
|
|
508
|
+
if (nextChar === ' ' || nextChar === '\t') {
|
|
509
|
+
let j = i + 1;
|
|
510
|
+
while (j < csv.length && (csv[j] === ' ' || csv[j] === '\t')) {
|
|
511
|
+
j++;
|
|
512
|
+
}
|
|
513
|
+
if (j >= csv.length || csv[j] === delimiter || csv[j] === '\n' || csv[j] === '\r') {
|
|
514
|
+
insideQuotes = false;
|
|
515
|
+
i++;
|
|
516
|
+
continue;
|
|
517
|
+
}
|
|
518
|
+
}
|
|
519
|
+
|
|
520
|
+
currentField += '"';
|
|
521
|
+
i++;
|
|
522
|
+
continue;
|
|
505
523
|
}
|
|
506
524
|
|
|
507
525
|
insideQuotes = true;
|
|
@@ -537,8 +555,8 @@ class FastPathEngine {
|
|
|
537
555
|
|
|
538
556
|
if (insideQuotes) {
|
|
539
557
|
const error = new Error('Unclosed quotes in CSV');
|
|
540
|
-
error.code = 'FAST_PATH_UNCLOSED_QUOTES';
|
|
541
|
-
error.lineNumber = lineNumber;
|
|
558
|
+
(error as any).code = 'FAST_PATH_UNCLOSED_QUOTES';
|
|
559
|
+
(error as any).lineNumber = lineNumber;
|
|
542
560
|
throw error;
|
|
543
561
|
}
|
|
544
562
|
|
|
@@ -551,7 +569,7 @@ class FastPathEngine {
|
|
|
551
569
|
}
|
|
552
570
|
}
|
|
553
571
|
|
|
554
|
-
*_quoteAwareEscapedRowsGenerator(csv, delimiter, hasEscapedQuotes) {
|
|
572
|
+
*_quoteAwareEscapedRowsGenerator(csv: any, delimiter: any, hasEscapedQuotes: any) {
|
|
555
573
|
let currentRow = [];
|
|
556
574
|
let currentField = '';
|
|
557
575
|
let rowHasData = false;
|
|
@@ -624,19 +642,27 @@ class FastPathEngine {
|
|
|
624
642
|
continue;
|
|
625
643
|
}
|
|
626
644
|
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
645
|
+
if (nextChar === delimiter || nextChar === '\n' || nextChar === '\r' || i + 1 >= csv.length) {
|
|
646
|
+
insideQuotes = false;
|
|
647
|
+
i++;
|
|
648
|
+
continue;
|
|
649
|
+
}
|
|
650
|
+
|
|
651
|
+
if (nextChar === ' ' || nextChar === '\t') {
|
|
652
|
+
let j = i + 1;
|
|
653
|
+
while (j < csv.length && (csv[j] === ' ' || csv[j] === '\t')) {
|
|
654
|
+
j++;
|
|
655
|
+
}
|
|
656
|
+
if (j >= csv.length || csv[j] === delimiter || csv[j] === '\n' || csv[j] === '\r') {
|
|
657
|
+
insideQuotes = false;
|
|
658
|
+
i++;
|
|
659
|
+
continue;
|
|
660
|
+
}
|
|
661
|
+
}
|
|
662
|
+
|
|
663
|
+
currentField += '"';
|
|
664
|
+
i++;
|
|
665
|
+
continue;
|
|
640
666
|
}
|
|
641
667
|
|
|
642
668
|
insideQuotes = true;
|
|
@@ -677,8 +703,8 @@ class FastPathEngine {
|
|
|
677
703
|
|
|
678
704
|
if (insideQuotes) {
|
|
679
705
|
const error = new Error('Unclosed quotes in CSV');
|
|
680
|
-
error.code = 'FAST_PATH_UNCLOSED_QUOTES';
|
|
681
|
-
error.lineNumber = lineNumber;
|
|
706
|
+
(error as any).code = 'FAST_PATH_UNCLOSED_QUOTES';
|
|
707
|
+
(error as any).lineNumber = lineNumber;
|
|
682
708
|
throw error;
|
|
683
709
|
}
|
|
684
710
|
|
|
@@ -759,7 +785,7 @@ class FastPathEngine {
|
|
|
759
785
|
/**
|
|
760
786
|
* Iterates rows without allocating the full result set.
|
|
761
787
|
*/
|
|
762
|
-
*iterateRows(csv, options = {}) {
|
|
788
|
+
*iterateRows(csv: any, options = {}) {
|
|
763
789
|
const structure = this._getStructureForParse(csv, options);
|
|
764
790
|
const useEscapes = structure.hasBackslashes;
|
|
765
791
|
|
|
@@ -797,7 +823,7 @@ class FastPathEngine {
|
|
|
797
823
|
/**
|
|
798
824
|
* Парсит CSV с использованием оптимального парсера
|
|
799
825
|
*/
|
|
800
|
-
parse(csv, options = {}) {
|
|
826
|
+
parse(csv: any, options = {}) {
|
|
801
827
|
const structure = this._getStructureForParse(csv, options);
|
|
802
828
|
const parser = this.compileParser(structure);
|
|
803
829
|
|
|
@@ -808,7 +834,7 @@ class FastPathEngine {
|
|
|
808
834
|
* Parses CSV and emits rows via a callback to reduce memory usage.
|
|
809
835
|
*/
|
|
810
836
|
/* istanbul ignore next */
|
|
811
|
-
parseRows(csv, options = {}, onRow) {
|
|
837
|
+
parseRows(csv: any, options = {}, onRow: any) {
|
|
812
838
|
for (const row of this.iterateRows(csv, options)) {
|
|
813
839
|
onRow(row);
|
|
814
840
|
}
|
|
@@ -841,4 +867,4 @@ class FastPathEngine {
|
|
|
841
867
|
}
|
|
842
868
|
}
|
|
843
869
|
|
|
844
|
-
|
|
870
|
+
export default FastPathEngine;
|
package/src/errors.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from '../errors';
|
|
@@ -11,7 +11,7 @@ function createTextDecoder() {
|
|
|
11
11
|
return new TextDecoder('utf-8');
|
|
12
12
|
}
|
|
13
13
|
try {
|
|
14
|
-
const { TextDecoder: UtilTextDecoder } = require(
|
|
14
|
+
const { TextDecoder: UtilTextDecoder } = require("util");
|
|
15
15
|
return new UtilTextDecoder('utf-8');
|
|
16
16
|
} catch (_error) {
|
|
17
17
|
return null;
|
|
@@ -23,7 +23,8 @@ function getTransformStream() {
|
|
|
23
23
|
return TransformStream;
|
|
24
24
|
}
|
|
25
25
|
try {
|
|
26
|
-
|
|
26
|
+
const streamModule = require("stream/web");
|
|
27
|
+
return streamModule.TransformStream;
|
|
27
28
|
} catch (_error) {
|
|
28
29
|
return null;
|
|
29
30
|
}
|
|
@@ -50,7 +51,7 @@ class NdjsonParser {
|
|
|
50
51
|
* console.log(obj);
|
|
51
52
|
* }
|
|
52
53
|
*/
|
|
53
|
-
static async *parseStream(input, options = {}) {
|
|
54
|
+
static async *parseStream(input: any, options: any = {}) {
|
|
54
55
|
const {
|
|
55
56
|
bufferSize: _bufferSize = 64 * 1024, // 64KB буфер
|
|
56
57
|
maxLineLength = 10 * 1024 * 1024, // 10MB максимальная длина строки
|
|
@@ -167,7 +168,7 @@ class NdjsonParser {
|
|
|
167
168
|
* const ndjson = NdjsonParser.toNdjson(data);
|
|
168
169
|
* // Результат: '{"name":"John"}\n{"name":"Jane"}'
|
|
169
170
|
*/
|
|
170
|
-
static toNdjson(data, options = {}) {
|
|
171
|
+
static toNdjson(data: any, options: any = {}) {
|
|
171
172
|
if (!Array.isArray(data)) {
|
|
172
173
|
throw new Error('Input must be an array');
|
|
173
174
|
}
|
|
@@ -193,7 +194,7 @@ class NdjsonParser {
|
|
|
193
194
|
* const data = NdjsonParser.fromNdjson(ndjson);
|
|
194
195
|
* // Результат: [{ name: 'John' }, { name: 'Jane' }]
|
|
195
196
|
*/
|
|
196
|
-
static fromNdjson(ndjsonString, options = {}) {
|
|
197
|
+
static fromNdjson(ndjsonString: any, options: any = {}) {
|
|
197
198
|
const {
|
|
198
199
|
filter = null,
|
|
199
200
|
transform = null,
|
|
@@ -202,7 +203,7 @@ class NdjsonParser {
|
|
|
202
203
|
|
|
203
204
|
return ndjsonString
|
|
204
205
|
.split('\n')
|
|
205
|
-
.map((line, index) => {
|
|
206
|
+
.map((line: any, index: any) => {
|
|
206
207
|
if (!line.trim()) {
|
|
207
208
|
return null;
|
|
208
209
|
}
|
|
@@ -232,7 +233,7 @@ class NdjsonParser {
|
|
|
232
233
|
* @param {Object} options - Опции конвертации
|
|
233
234
|
* @returns {TransformStream} Transform stream
|
|
234
235
|
*/
|
|
235
|
-
static createNdjsonToCsvStream(options = {}) {
|
|
236
|
+
static createNdjsonToCsvStream(options: any = {}) {
|
|
236
237
|
const {
|
|
237
238
|
delimiter = ',',
|
|
238
239
|
includeHeaders = true,
|
|
@@ -248,7 +249,7 @@ class NdjsonParser {
|
|
|
248
249
|
}
|
|
249
250
|
|
|
250
251
|
return new TransformStreamCtor({
|
|
251
|
-
async transform(chunk, controller) {
|
|
252
|
+
async transform(chunk: any, controller: any) {
|
|
252
253
|
try {
|
|
253
254
|
const obj = JSON.parse(chunk);
|
|
254
255
|
|
|
@@ -270,7 +271,7 @@ class NdjsonParser {
|
|
|
270
271
|
}
|
|
271
272
|
},
|
|
272
273
|
|
|
273
|
-
_escapeCsvField(value, delimiter) {
|
|
274
|
+
_escapeCsvField(value: any, delimiter: any) {
|
|
274
275
|
if (value === null || value === undefined) {
|
|
275
276
|
return '';
|
|
276
277
|
}
|
|
@@ -292,7 +293,7 @@ class NdjsonParser {
|
|
|
292
293
|
* @param {Object} options - Опции конвертации
|
|
293
294
|
* @returns {TransformStream} Transform stream
|
|
294
295
|
*/
|
|
295
|
-
static createCsvToNdjsonStream(options = {}) {
|
|
296
|
+
static createCsvToNdjsonStream(options: any = {}) {
|
|
296
297
|
const {
|
|
297
298
|
delimiter = ',',
|
|
298
299
|
hasHeaders = true,
|
|
@@ -308,7 +309,7 @@ class NdjsonParser {
|
|
|
308
309
|
}
|
|
309
310
|
|
|
310
311
|
return new TransformStreamCtor({
|
|
311
|
-
transform(chunk, controller) {
|
|
312
|
+
transform(chunk: any, controller: any) {
|
|
312
313
|
const lines = chunk.toString().split('\n');
|
|
313
314
|
|
|
314
315
|
for (const line of lines) {
|
|
@@ -323,11 +324,11 @@ class NdjsonParser {
|
|
|
323
324
|
firstLine = false;
|
|
324
325
|
} else {
|
|
325
326
|
const obj = headers
|
|
326
|
-
? headers.reduce((acc, header, index) => {
|
|
327
|
+
? headers.reduce((acc: any, header: any, index: any) => {
|
|
327
328
|
acc[header] = fields[index] || '';
|
|
328
329
|
return acc;
|
|
329
330
|
}, {})
|
|
330
|
-
: fields.reduce((acc, field, index) => {
|
|
331
|
+
: fields.reduce((acc: any, field: any, index: any) => {
|
|
331
332
|
acc[`field_${index}`] = field;
|
|
332
333
|
return acc;
|
|
333
334
|
}, {});
|
|
@@ -337,7 +338,7 @@ class NdjsonParser {
|
|
|
337
338
|
}
|
|
338
339
|
},
|
|
339
340
|
|
|
340
|
-
_parseCsvLine(line, delimiter) {
|
|
341
|
+
_parseCsvLine(line: any, delimiter: any) {
|
|
341
342
|
const fields = [];
|
|
342
343
|
let currentField = '';
|
|
343
344
|
let insideQuotes = false;
|
|
@@ -378,7 +379,8 @@ class NdjsonParser {
|
|
|
378
379
|
validLines: 0,
|
|
379
380
|
errorLines: 0,
|
|
380
381
|
totalBytes: 0,
|
|
381
|
-
errors: []
|
|
382
|
+
errors: [],
|
|
383
|
+
successRate: 0
|
|
382
384
|
};
|
|
383
385
|
|
|
384
386
|
if (typeof input === 'string') {
|
|
@@ -464,4 +466,10 @@ class NdjsonParser {
|
|
|
464
466
|
}
|
|
465
467
|
}
|
|
466
468
|
|
|
467
|
-
|
|
469
|
+
export default NdjsonParser;
|
|
470
|
+
|
|
471
|
+
// CommonJS compatibility
|
|
472
|
+
if (typeof module !== 'undefined' && module.exports) {
|
|
473
|
+
module.exports = NdjsonParser;
|
|
474
|
+
module.exports.default = NdjsonParser;
|
|
475
|
+
}
|
|
@@ -6,10 +6,13 @@
|
|
|
6
6
|
* @date 2026-01-23
|
|
7
7
|
*/
|
|
8
8
|
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
9
|
+
import fs from "fs";
|
|
10
|
+
import path from "path";
|
|
11
|
+
import { csvToJson } from "../../csv-to-json";
|
|
12
|
+
import { jsonToCsv } from "../../json-to-csv";
|
|
13
|
+
import { ValidationError, SecurityError, FileSystemError } from "../../errors";
|
|
14
|
+
import { createJsonToCsvStream } from "../../stream-json-to-csv";
|
|
15
|
+
import { createCsvToJsonStream } from "../../stream-csv-to-json";
|
|
13
16
|
|
|
14
17
|
function validateTsvFilePath(filePath) {
|
|
15
18
|
if (typeof filePath !== 'string' || filePath.trim() === '') {
|
|
@@ -111,8 +114,6 @@ class TsvParser {
|
|
|
111
114
|
* @returns {TransformStream} Transform stream
|
|
112
115
|
*/
|
|
113
116
|
static createJsonToTsvStream(options = {}) {
|
|
114
|
-
const { createJsonToCsvStream } = require('../../stream-json-to-csv');
|
|
115
|
-
|
|
116
117
|
return createJsonToCsvStream({
|
|
117
118
|
delimiter: '\t',
|
|
118
119
|
...options
|
|
@@ -125,8 +126,6 @@ class TsvParser {
|
|
|
125
126
|
* @returns {TransformStream} Transform stream
|
|
126
127
|
*/
|
|
127
128
|
static createTsvToJsonStream(options = {}) {
|
|
128
|
-
const { createCsvToJsonStream } = require('../../stream-csv-to-json');
|
|
129
|
-
|
|
130
129
|
return createCsvToJsonStream({
|
|
131
130
|
delimiter: '\t',
|
|
132
131
|
autoDetect: false,
|
|
@@ -141,11 +140,10 @@ class TsvParser {
|
|
|
141
140
|
* @returns {Promise<Array>} Promise с массивом объектов
|
|
142
141
|
*/
|
|
143
142
|
static async readTsvAsJson(filePath, options = {}) {
|
|
144
|
-
const fs = require('fs').promises;
|
|
145
143
|
const safePath = validateTsvFilePath(filePath);
|
|
146
144
|
|
|
147
145
|
try {
|
|
148
|
-
const tsvContent = await fs.readFile(safePath, 'utf8');
|
|
146
|
+
const tsvContent = await fs.promises.readFile(safePath, 'utf8');
|
|
149
147
|
return csvToJson(tsvContent, {
|
|
150
148
|
delimiter: '\t',
|
|
151
149
|
autoDetect: false,
|
|
@@ -175,7 +173,6 @@ class TsvParser {
|
|
|
175
173
|
* @returns {Array} Массив объектов
|
|
176
174
|
*/
|
|
177
175
|
static readTsvAsJsonSync(filePath, options = {}) {
|
|
178
|
-
const fs = require('fs');
|
|
179
176
|
const safePath = validateTsvFilePath(filePath);
|
|
180
177
|
|
|
181
178
|
try {
|
|
@@ -210,14 +207,13 @@ class TsvParser {
|
|
|
210
207
|
* @returns {Promise<void>}
|
|
211
208
|
*/
|
|
212
209
|
static async saveAsTsv(data, filePath, options = {}) {
|
|
213
|
-
const fs = require('fs').promises;
|
|
214
210
|
const safePath = validateTsvFilePath(filePath);
|
|
215
211
|
const tsvContent = this.jsonToTsv(data, options);
|
|
216
212
|
const dir = path.dirname(safePath);
|
|
217
213
|
|
|
218
214
|
try {
|
|
219
|
-
await fs.mkdir(dir, { recursive: true });
|
|
220
|
-
await fs.writeFile(safePath, tsvContent, 'utf8');
|
|
215
|
+
await fs.promises.mkdir(dir, { recursive: true });
|
|
216
|
+
await fs.promises.writeFile(safePath, tsvContent, 'utf8');
|
|
221
217
|
return safePath;
|
|
222
218
|
} catch (error) {
|
|
223
219
|
if (error.code === 'ENOENT') {
|
|
@@ -240,7 +236,6 @@ class TsvParser {
|
|
|
240
236
|
* @param {Object} options - Опции сохранения
|
|
241
237
|
*/
|
|
242
238
|
static saveAsTsvSync(data, filePath, options = {}) {
|
|
243
|
-
const fs = require('fs');
|
|
244
239
|
const safePath = validateTsvFilePath(filePath);
|
|
245
240
|
const tsvContent = this.jsonToTsv(data, options);
|
|
246
241
|
|
|
@@ -254,7 +249,7 @@ class TsvParser {
|
|
|
254
249
|
* @param {Object} options - Опции валидации
|
|
255
250
|
* @returns {Object} Результат валидации
|
|
256
251
|
*/
|
|
257
|
-
static validateTsv(tsvString, options = {}) {
|
|
252
|
+
static validateTsv(tsvString, options: any = {}) {
|
|
258
253
|
const { requireConsistentColumns = true } = options;
|
|
259
254
|
|
|
260
255
|
if (!tsvString || typeof tsvString !== 'string') {
|
|
@@ -336,4 +331,10 @@ class TsvParser {
|
|
|
336
331
|
}
|
|
337
332
|
}
|
|
338
333
|
|
|
339
|
-
|
|
334
|
+
export default TsvParser;
|
|
335
|
+
|
|
336
|
+
// CommonJS compatibility
|
|
337
|
+
if (typeof module !== 'undefined' && module.exports) {
|
|
338
|
+
module.exports = TsvParser;
|
|
339
|
+
module.exports.default = TsvParser;
|
|
340
|
+
}
|