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.esm.js
CHANGED
|
@@ -384,8 +384,18 @@ function jsonToCsv(data, options = {}) {
|
|
|
384
384
|
|
|
385
385
|
// Защита от CSV инъекций
|
|
386
386
|
let escapedValue = stringValue;
|
|
387
|
-
if (preventCsvInjection
|
|
388
|
-
|
|
387
|
+
if (preventCsvInjection) {
|
|
388
|
+
// Dangerous prefixes: =, +, -, @, tab (\t), carriage return (\r)
|
|
389
|
+
if (/^[=+\-@\t\r]/.test(stringValue)) {
|
|
390
|
+
escapedValue = "'" + stringValue;
|
|
391
|
+
}
|
|
392
|
+
// Unicode Bidi override characters
|
|
393
|
+
const bidiChars = ['\u202A', '\u202B', '\u202C', '\u202D', '\u202E'];
|
|
394
|
+
for (const bidi of bidiChars) {
|
|
395
|
+
if (stringValue.includes(bidi)) {
|
|
396
|
+
escapedValue = escapedValue.replace(new RegExp(bidi, 'g'), '');
|
|
397
|
+
}
|
|
398
|
+
}
|
|
389
399
|
}
|
|
390
400
|
|
|
391
401
|
// Соответствие RFC 4180
|
|
@@ -698,10 +708,18 @@ function parseCsvValue(value, options) {
|
|
|
698
708
|
}
|
|
699
709
|
|
|
700
710
|
// Парсинг чисел
|
|
701
|
-
if (parseNumbers
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
711
|
+
if (parseNumbers) {
|
|
712
|
+
// Быстрая проверка числа: первый символ цифра, минус или точка
|
|
713
|
+
const trimmed = result.trim();
|
|
714
|
+
const firstChar = trimmed.charAt(0);
|
|
715
|
+
if (firstChar >= '0' && firstChar <= '9' || firstChar === '-' || firstChar === '.') {
|
|
716
|
+
const num = parseFloat(trimmed);
|
|
717
|
+
if (!isNaN(num) && isFinite(num)) {
|
|
718
|
+
// Убедимся, что строка полностью соответствует числу (без лишних символов)
|
|
719
|
+
if (String(num) === trimmed || trimmed.includes('.') && !isNaN(Number(trimmed))) {
|
|
720
|
+
return num;
|
|
721
|
+
}
|
|
722
|
+
}
|
|
705
723
|
}
|
|
706
724
|
}
|
|
707
725
|
|
|
@@ -813,28 +831,42 @@ function autoDetectDelimiter(csv, candidates = [';', ',', '\t', '|']) {
|
|
|
813
831
|
|
|
814
832
|
// Использование первой непустой строки для определения
|
|
815
833
|
const firstLine = lines[0];
|
|
834
|
+
|
|
835
|
+
// Быстрый подсчёт вхождений кандидатов за один проход
|
|
816
836
|
const counts = {};
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
const
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
|
|
837
|
+
const candidateSet = new Set(candidates);
|
|
838
|
+
for (let i = 0; i < firstLine.length; i++) {
|
|
839
|
+
const char = firstLine[i];
|
|
840
|
+
if (candidateSet.has(char)) {
|
|
841
|
+
counts[char] = (counts[char] || 0) + 1;
|
|
842
|
+
}
|
|
843
|
+
}
|
|
844
|
+
// Убедимся, что все кандидаты присутствуют в counts (даже с нулём)
|
|
845
|
+
for (const delim of candidates) {
|
|
846
|
+
if (!(delim in counts)) {
|
|
847
|
+
counts[delim] = 0;
|
|
848
|
+
}
|
|
849
|
+
}
|
|
823
850
|
|
|
824
851
|
// Поиск разделителя с максимальным количеством
|
|
825
852
|
let maxCount = -1;
|
|
826
853
|
let detectedDelimiter = ';'; // значение по умолчанию
|
|
827
|
-
|
|
854
|
+
const maxDelimiters = [];
|
|
828
855
|
for (const [delim, count] of Object.entries(counts)) {
|
|
829
856
|
if (count > maxCount) {
|
|
830
857
|
maxCount = count;
|
|
831
|
-
|
|
858
|
+
maxDelimiters.length = 0;
|
|
859
|
+
maxDelimiters.push(delim);
|
|
860
|
+
} else if (count === maxCount) {
|
|
861
|
+
maxDelimiters.push(delim);
|
|
832
862
|
}
|
|
833
863
|
}
|
|
834
864
|
|
|
835
|
-
// Если разделитель не найден или
|
|
836
|
-
if (maxCount === 0) {
|
|
837
|
-
|
|
865
|
+
// Если разделитель не найден или есть ничья, возвращаем стандартный
|
|
866
|
+
if (maxCount === 0 || maxDelimiters.length > 1) {
|
|
867
|
+
detectedDelimiter = ';';
|
|
868
|
+
} else {
|
|
869
|
+
detectedDelimiter = maxDelimiters[0];
|
|
838
870
|
}
|
|
839
871
|
return detectedDelimiter;
|
|
840
872
|
}
|
|
@@ -1333,8 +1365,18 @@ function escapeCsvValue(value, options) {
|
|
|
1333
1365
|
}
|
|
1334
1366
|
const stringValue = String(value);
|
|
1335
1367
|
let escapedValue = stringValue;
|
|
1336
|
-
if (preventCsvInjection
|
|
1337
|
-
|
|
1368
|
+
if (preventCsvInjection) {
|
|
1369
|
+
// Dangerous prefixes: =, +, -, @, tab (\t), carriage return (\r)
|
|
1370
|
+
if (/^[=+\-@\t\r]/.test(stringValue)) {
|
|
1371
|
+
escapedValue = "'" + stringValue;
|
|
1372
|
+
}
|
|
1373
|
+
// Unicode Bidi override characters
|
|
1374
|
+
const bidiChars = ['\u202A', '\u202B', '\u202C', '\u202D', '\u202E'];
|
|
1375
|
+
for (const bidi of bidiChars) {
|
|
1376
|
+
if (stringValue.includes(bidi)) {
|
|
1377
|
+
escapedValue = escapedValue.replace(new RegExp(bidi, 'g'), '');
|
|
1378
|
+
}
|
|
1379
|
+
}
|
|
1338
1380
|
}
|
|
1339
1381
|
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');
|
|
1340
1382
|
if (needsQuoting) {
|