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/dist/jtcsv.umd.js
CHANGED
|
@@ -391,8 +391,18 @@
|
|
|
391
391
|
|
|
392
392
|
// Защита от CSV инъекций
|
|
393
393
|
let escapedValue = stringValue;
|
|
394
|
-
if (preventCsvInjection
|
|
395
|
-
|
|
394
|
+
if (preventCsvInjection) {
|
|
395
|
+
// Dangerous prefixes: =, +, -, @, tab (\t), carriage return (\r)
|
|
396
|
+
if (/^[=+\-@\t\r]/.test(stringValue)) {
|
|
397
|
+
escapedValue = "'" + stringValue;
|
|
398
|
+
}
|
|
399
|
+
// Unicode Bidi override characters
|
|
400
|
+
const bidiChars = ['\u202A', '\u202B', '\u202C', '\u202D', '\u202E'];
|
|
401
|
+
for (const bidi of bidiChars) {
|
|
402
|
+
if (stringValue.includes(bidi)) {
|
|
403
|
+
escapedValue = escapedValue.replace(new RegExp(bidi, 'g'), '');
|
|
404
|
+
}
|
|
405
|
+
}
|
|
396
406
|
}
|
|
397
407
|
|
|
398
408
|
// Соответствие RFC 4180
|
|
@@ -705,10 +715,18 @@
|
|
|
705
715
|
}
|
|
706
716
|
|
|
707
717
|
// Парсинг чисел
|
|
708
|
-
if (parseNumbers
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
718
|
+
if (parseNumbers) {
|
|
719
|
+
// Быстрая проверка числа: первый символ цифра, минус или точка
|
|
720
|
+
const trimmed = result.trim();
|
|
721
|
+
const firstChar = trimmed.charAt(0);
|
|
722
|
+
if (firstChar >= '0' && firstChar <= '9' || firstChar === '-' || firstChar === '.') {
|
|
723
|
+
const num = parseFloat(trimmed);
|
|
724
|
+
if (!isNaN(num) && isFinite(num)) {
|
|
725
|
+
// Убедимся, что строка полностью соответствует числу (без лишних символов)
|
|
726
|
+
if (String(num) === trimmed || trimmed.includes('.') && !isNaN(Number(trimmed))) {
|
|
727
|
+
return num;
|
|
728
|
+
}
|
|
729
|
+
}
|
|
712
730
|
}
|
|
713
731
|
}
|
|
714
732
|
|
|
@@ -820,28 +838,42 @@
|
|
|
820
838
|
|
|
821
839
|
// Использование первой непустой строки для определения
|
|
822
840
|
const firstLine = lines[0];
|
|
841
|
+
|
|
842
|
+
// Быстрый подсчёт вхождений кандидатов за один проход
|
|
823
843
|
const counts = {};
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
const
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
844
|
+
const candidateSet = new Set(candidates);
|
|
845
|
+
for (let i = 0; i < firstLine.length; i++) {
|
|
846
|
+
const char = firstLine[i];
|
|
847
|
+
if (candidateSet.has(char)) {
|
|
848
|
+
counts[char] = (counts[char] || 0) + 1;
|
|
849
|
+
}
|
|
850
|
+
}
|
|
851
|
+
// Убедимся, что все кандидаты присутствуют в counts (даже с нулём)
|
|
852
|
+
for (const delim of candidates) {
|
|
853
|
+
if (!(delim in counts)) {
|
|
854
|
+
counts[delim] = 0;
|
|
855
|
+
}
|
|
856
|
+
}
|
|
830
857
|
|
|
831
858
|
// Поиск разделителя с максимальным количеством
|
|
832
859
|
let maxCount = -1;
|
|
833
860
|
let detectedDelimiter = ';'; // значение по умолчанию
|
|
834
|
-
|
|
861
|
+
const maxDelimiters = [];
|
|
835
862
|
for (const [delim, count] of Object.entries(counts)) {
|
|
836
863
|
if (count > maxCount) {
|
|
837
864
|
maxCount = count;
|
|
838
|
-
|
|
865
|
+
maxDelimiters.length = 0;
|
|
866
|
+
maxDelimiters.push(delim);
|
|
867
|
+
} else if (count === maxCount) {
|
|
868
|
+
maxDelimiters.push(delim);
|
|
839
869
|
}
|
|
840
870
|
}
|
|
841
871
|
|
|
842
|
-
// Если разделитель не найден или
|
|
843
|
-
if (maxCount === 0) {
|
|
844
|
-
|
|
872
|
+
// Если разделитель не найден или есть ничья, возвращаем стандартный
|
|
873
|
+
if (maxCount === 0 || maxDelimiters.length > 1) {
|
|
874
|
+
detectedDelimiter = ';';
|
|
875
|
+
} else {
|
|
876
|
+
detectedDelimiter = maxDelimiters[0];
|
|
845
877
|
}
|
|
846
878
|
return detectedDelimiter;
|
|
847
879
|
}
|
|
@@ -1340,8 +1372,18 @@
|
|
|
1340
1372
|
}
|
|
1341
1373
|
const stringValue = String(value);
|
|
1342
1374
|
let escapedValue = stringValue;
|
|
1343
|
-
if (preventCsvInjection
|
|
1344
|
-
|
|
1375
|
+
if (preventCsvInjection) {
|
|
1376
|
+
// Dangerous prefixes: =, +, -, @, tab (\t), carriage return (\r)
|
|
1377
|
+
if (/^[=+\-@\t\r]/.test(stringValue)) {
|
|
1378
|
+
escapedValue = "'" + stringValue;
|
|
1379
|
+
}
|
|
1380
|
+
// Unicode Bidi override characters
|
|
1381
|
+
const bidiChars = ['\u202A', '\u202B', '\u202C', '\u202D', '\u202E'];
|
|
1382
|
+
for (const bidi of bidiChars) {
|
|
1383
|
+
if (stringValue.includes(bidi)) {
|
|
1384
|
+
escapedValue = escapedValue.replace(new RegExp(bidi, 'g'), '');
|
|
1385
|
+
}
|
|
1386
|
+
}
|
|
1345
1387
|
}
|
|
1346
1388
|
const needsQuoting = rfc4180Compliant ? escapedValue.includes(delimiter) || escapedValue.includes('"') || escapedValue.includes('\n') || escapedValue.includes('\r') : escapedValue.includes(delimiter) || escapedValue.includes('"') || escapedValue.includes('\n') || escapedValue.includes('\r');
|
|
1347
1389
|
if (needsQuoting) {
|