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
package/src/browser/index.js
DELETED
|
@@ -1,113 +0,0 @@
|
|
|
1
|
-
// Браузерный entry point для jtcsv
|
|
2
|
-
// Экспортирует все функции с поддержкой браузера
|
|
3
|
-
|
|
4
|
-
import { jsonToCsv, preprocessData, deepUnwrap } from './json-to-csv-browser.js';
|
|
5
|
-
import { csvToJson, csvToJsonIterator, autoDetectDelimiter } from './csv-to-json-browser.js';
|
|
6
|
-
import {
|
|
7
|
-
downloadAsCsv,
|
|
8
|
-
parseCsvFile,
|
|
9
|
-
parseCsvFileStream,
|
|
10
|
-
jsonToCsvStream,
|
|
11
|
-
jsonToNdjsonStream,
|
|
12
|
-
csvToJsonStream
|
|
13
|
-
} from './browser-functions.js';
|
|
14
|
-
import { createWorkerPool, parseCSVWithWorker } from './workers/worker-pool.js';
|
|
15
|
-
import {
|
|
16
|
-
ValidationError,
|
|
17
|
-
SecurityError,
|
|
18
|
-
FileSystemError,
|
|
19
|
-
ParsingError,
|
|
20
|
-
LimitError,
|
|
21
|
-
ConfigurationError,
|
|
22
|
-
ERROR_CODES
|
|
23
|
-
} from './errors-browser.js';
|
|
24
|
-
|
|
25
|
-
async function createWorkerPoolLazy(options = {}) {
|
|
26
|
-
const mod = await import('./workers/worker-pool.js');
|
|
27
|
-
return mod.createWorkerPool(options);
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
async function parseCSVWithWorkerLazy(csvInput, options = {}, onProgress = null) {
|
|
31
|
-
const mod = await import('./workers/worker-pool.js');
|
|
32
|
-
return mod.parseCSVWithWorker(csvInput, options, onProgress);
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
// Основной экспорт
|
|
36
|
-
const jtcsv = {
|
|
37
|
-
// JSON to CSV функции
|
|
38
|
-
jsonToCsv,
|
|
39
|
-
preprocessData,
|
|
40
|
-
downloadAsCsv,
|
|
41
|
-
deepUnwrap,
|
|
42
|
-
|
|
43
|
-
// CSV to JSON функции
|
|
44
|
-
csvToJson,
|
|
45
|
-
csvToJsonIterator,
|
|
46
|
-
parseCsvFile,
|
|
47
|
-
parseCsvFileStream,
|
|
48
|
-
jsonToCsvStream,
|
|
49
|
-
jsonToNdjsonStream,
|
|
50
|
-
csvToJsonStream,
|
|
51
|
-
autoDetectDelimiter,
|
|
52
|
-
|
|
53
|
-
// Web Workers функции
|
|
54
|
-
createWorkerPool,
|
|
55
|
-
parseCSVWithWorker,
|
|
56
|
-
createWorkerPoolLazy,
|
|
57
|
-
parseCSVWithWorkerLazy,
|
|
58
|
-
|
|
59
|
-
// Error classes
|
|
60
|
-
ValidationError,
|
|
61
|
-
SecurityError,
|
|
62
|
-
FileSystemError,
|
|
63
|
-
ParsingError,
|
|
64
|
-
LimitError,
|
|
65
|
-
ConfigurationError,
|
|
66
|
-
ERROR_CODES,
|
|
67
|
-
|
|
68
|
-
// Удобные алиасы
|
|
69
|
-
parse: csvToJson,
|
|
70
|
-
unparse: jsonToCsv,
|
|
71
|
-
|
|
72
|
-
// Версия
|
|
73
|
-
version: '2.0.0-browser'
|
|
74
|
-
};
|
|
75
|
-
|
|
76
|
-
// Экспорт для разных сред
|
|
77
|
-
if (typeof module !== 'undefined' && module.exports) {
|
|
78
|
-
// Node.js CommonJS
|
|
79
|
-
module.exports = jtcsv;
|
|
80
|
-
} else if (typeof define === 'function' && define.amd) {
|
|
81
|
-
// AMD
|
|
82
|
-
define([], () => jtcsv);
|
|
83
|
-
} else if (typeof window !== 'undefined') {
|
|
84
|
-
// Браузер (глобальная переменная)
|
|
85
|
-
window.jtcsv = jtcsv;
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
export default jtcsv;
|
|
89
|
-
export {
|
|
90
|
-
jsonToCsv,
|
|
91
|
-
preprocessData,
|
|
92
|
-
downloadAsCsv,
|
|
93
|
-
deepUnwrap,
|
|
94
|
-
csvToJson,
|
|
95
|
-
csvToJsonIterator,
|
|
96
|
-
parseCsvFile,
|
|
97
|
-
parseCsvFileStream,
|
|
98
|
-
jsonToCsvStream,
|
|
99
|
-
jsonToNdjsonStream,
|
|
100
|
-
csvToJsonStream,
|
|
101
|
-
autoDetectDelimiter,
|
|
102
|
-
createWorkerPool,
|
|
103
|
-
parseCSVWithWorker,
|
|
104
|
-
createWorkerPoolLazy,
|
|
105
|
-
parseCSVWithWorkerLazy,
|
|
106
|
-
ValidationError,
|
|
107
|
-
SecurityError,
|
|
108
|
-
FileSystemError,
|
|
109
|
-
ParsingError,
|
|
110
|
-
LimitError,
|
|
111
|
-
ConfigurationError,
|
|
112
|
-
ERROR_CODES
|
|
113
|
-
};
|
|
@@ -1,309 +0,0 @@
|
|
|
1
|
-
// Браузерная версия JSON to CSV конвертера
|
|
2
|
-
// Адаптирована для работы в браузере без Node.js API
|
|
3
|
-
|
|
4
|
-
import {
|
|
5
|
-
ValidationError,
|
|
6
|
-
ConfigurationError,
|
|
7
|
-
LimitError,
|
|
8
|
-
safeExecute
|
|
9
|
-
} from './errors-browser.js';
|
|
10
|
-
|
|
11
|
-
/**
|
|
12
|
-
* Валидация входных данных и опций
|
|
13
|
-
* @private
|
|
14
|
-
*/
|
|
15
|
-
function validateInput(data, options) {
|
|
16
|
-
// Validate data
|
|
17
|
-
if (!Array.isArray(data)) {
|
|
18
|
-
throw new ValidationError('Input data must be an array');
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
// Validate options
|
|
22
|
-
if (options && typeof options !== 'object') {
|
|
23
|
-
throw new ConfigurationError('Options must be an object');
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
// Validate delimiter
|
|
27
|
-
if (options?.delimiter && typeof options.delimiter !== 'string') {
|
|
28
|
-
throw new ConfigurationError('Delimiter must be a string');
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
if (options?.delimiter && options.delimiter.length !== 1) {
|
|
32
|
-
throw new ConfigurationError('Delimiter must be a single character');
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
// Validate renameMap
|
|
36
|
-
if (options?.renameMap && typeof options.renameMap !== 'object') {
|
|
37
|
-
throw new ConfigurationError('renameMap must be an object');
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
// Validate maxRecords
|
|
41
|
-
if (options && options.maxRecords !== undefined) {
|
|
42
|
-
if (typeof options.maxRecords !== 'number' || options.maxRecords <= 0) {
|
|
43
|
-
throw new ConfigurationError('maxRecords must be a positive number');
|
|
44
|
-
}
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
// Validate preventCsvInjection
|
|
48
|
-
if (options?.preventCsvInjection !== undefined && typeof options.preventCsvInjection !== 'boolean') {
|
|
49
|
-
throw new ConfigurationError('preventCsvInjection must be a boolean');
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
// Validate rfc4180Compliant
|
|
53
|
-
if (options?.rfc4180Compliant !== undefined && typeof options.rfc4180Compliant !== 'boolean') {
|
|
54
|
-
throw new ConfigurationError('rfc4180Compliant must be a boolean');
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
return true;
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
/**
|
|
61
|
-
* Конвертирует JSON данные в CSV формат
|
|
62
|
-
*
|
|
63
|
-
* @param {Array<Object>} data - Массив объектов для конвертации в CSV
|
|
64
|
-
* @param {Object} [options] - Опции конфигурации
|
|
65
|
-
* @param {string} [options.delimiter=';'] - CSV разделитель
|
|
66
|
-
* @param {boolean} [options.includeHeaders=true] - Включать ли заголовки
|
|
67
|
-
* @param {Object} [options.renameMap={}] - Маппинг переименования заголовков
|
|
68
|
-
* @param {Object} [options.template={}] - Шаблон для порядка колонок
|
|
69
|
-
* @param {number} [options.maxRecords] - Максимальное количество записей
|
|
70
|
-
* @param {boolean} [options.preventCsvInjection=true] - Защита от CSV инъекций
|
|
71
|
-
* @param {boolean} [options.rfc4180Compliant=true] - Соответствие RFC 4180
|
|
72
|
-
* @returns {string} CSV строка
|
|
73
|
-
*/
|
|
74
|
-
export function jsonToCsv(data, options = {}) {
|
|
75
|
-
return safeExecute(() => {
|
|
76
|
-
// Валидация входных данных
|
|
77
|
-
validateInput(data, options);
|
|
78
|
-
|
|
79
|
-
const opts = options && typeof options === 'object' ? options : {};
|
|
80
|
-
|
|
81
|
-
const {
|
|
82
|
-
delimiter = ';',
|
|
83
|
-
includeHeaders = true,
|
|
84
|
-
renameMap = {},
|
|
85
|
-
template = {},
|
|
86
|
-
maxRecords,
|
|
87
|
-
preventCsvInjection = true,
|
|
88
|
-
rfc4180Compliant = true
|
|
89
|
-
} = opts;
|
|
90
|
-
|
|
91
|
-
// Обработка пустых данных
|
|
92
|
-
if (data.length === 0) {
|
|
93
|
-
return '';
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
// Предупреждение для больших наборов данных
|
|
97
|
-
if (data.length > 1000000 && !maxRecords && process.env.NODE_ENV !== 'production') {
|
|
98
|
-
console.warn(
|
|
99
|
-
'⚠️ Warning: Processing >1M records in memory may be slow.\n' +
|
|
100
|
-
'💡 Consider processing data in batches or using Web Workers for large files.\n' +
|
|
101
|
-
'📊 Current size: ' + data.length.toLocaleString() + ' records'
|
|
102
|
-
);
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
// Применение ограничения по количеству записей
|
|
106
|
-
if (maxRecords && data.length > maxRecords) {
|
|
107
|
-
throw new LimitError(
|
|
108
|
-
`Data size exceeds maximum limit of ${maxRecords} records`,
|
|
109
|
-
maxRecords,
|
|
110
|
-
data.length
|
|
111
|
-
);
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
// Получение всех уникальных ключей
|
|
115
|
-
const allKeys = new Set();
|
|
116
|
-
data.forEach((item) => {
|
|
117
|
-
if (!item || typeof item !== 'object') {
|
|
118
|
-
return;
|
|
119
|
-
}
|
|
120
|
-
Object.keys(item).forEach(key => allKeys.add(key));
|
|
121
|
-
});
|
|
122
|
-
|
|
123
|
-
const originalKeys = Array.from(allKeys);
|
|
124
|
-
|
|
125
|
-
// Применение rename map для создания заголовков
|
|
126
|
-
const headers = originalKeys.map(key => renameMap[key] || key);
|
|
127
|
-
|
|
128
|
-
// Создание обратного маппинга
|
|
129
|
-
const reverseRenameMap = {};
|
|
130
|
-
originalKeys.forEach((key, index) => {
|
|
131
|
-
reverseRenameMap[headers[index]] = key;
|
|
132
|
-
});
|
|
133
|
-
|
|
134
|
-
// Применение порядка из шаблона
|
|
135
|
-
let finalHeaders = headers;
|
|
136
|
-
if (Object.keys(template).length > 0) {
|
|
137
|
-
const templateHeaders = Object.keys(template).map(key => renameMap[key] || key);
|
|
138
|
-
const extraHeaders = headers.filter(h => !templateHeaders.includes(h));
|
|
139
|
-
finalHeaders = [...templateHeaders, ...extraHeaders];
|
|
140
|
-
}
|
|
141
|
-
|
|
142
|
-
/**
|
|
143
|
-
* Экранирование значения для CSV с защитой от инъекций
|
|
144
|
-
* @private
|
|
145
|
-
*/
|
|
146
|
-
const escapeValue = (value) => {
|
|
147
|
-
if (value === null || value === undefined || value === '') {
|
|
148
|
-
return '';
|
|
149
|
-
}
|
|
150
|
-
|
|
151
|
-
const stringValue = String(value);
|
|
152
|
-
|
|
153
|
-
// Защита от CSV инъекций
|
|
154
|
-
let escapedValue = stringValue;
|
|
155
|
-
if (preventCsvInjection && /^[=+\-@]/.test(stringValue)) {
|
|
156
|
-
escapedValue = "'" + stringValue;
|
|
157
|
-
}
|
|
158
|
-
|
|
159
|
-
// Соответствие RFC 4180
|
|
160
|
-
const needsQuoting = rfc4180Compliant
|
|
161
|
-
? (escapedValue.includes(delimiter) ||
|
|
162
|
-
escapedValue.includes('"') ||
|
|
163
|
-
escapedValue.includes('\n') ||
|
|
164
|
-
escapedValue.includes('\r'))
|
|
165
|
-
: (escapedValue.includes(delimiter) ||
|
|
166
|
-
escapedValue.includes('"') ||
|
|
167
|
-
escapedValue.includes('\n') ||
|
|
168
|
-
escapedValue.includes('\r'));
|
|
169
|
-
|
|
170
|
-
if (needsQuoting) {
|
|
171
|
-
return `"${escapedValue.replace(/"/g, '""')}"`;
|
|
172
|
-
}
|
|
173
|
-
|
|
174
|
-
return escapedValue;
|
|
175
|
-
};
|
|
176
|
-
|
|
177
|
-
// Построение CSV строк
|
|
178
|
-
const rows = [];
|
|
179
|
-
|
|
180
|
-
// Добавление заголовков
|
|
181
|
-
if (includeHeaders && finalHeaders.length > 0) {
|
|
182
|
-
rows.push(finalHeaders.join(delimiter));
|
|
183
|
-
}
|
|
184
|
-
|
|
185
|
-
// Добавление данных
|
|
186
|
-
for (const item of data) {
|
|
187
|
-
if (!item || typeof item !== 'object') {
|
|
188
|
-
continue;
|
|
189
|
-
}
|
|
190
|
-
|
|
191
|
-
const row = finalHeaders.map(header => {
|
|
192
|
-
const originalKey = reverseRenameMap[header] || header;
|
|
193
|
-
const value = item[originalKey];
|
|
194
|
-
return escapeValue(value);
|
|
195
|
-
}).join(delimiter);
|
|
196
|
-
|
|
197
|
-
rows.push(row);
|
|
198
|
-
}
|
|
199
|
-
|
|
200
|
-
// Разделители строк согласно RFC 4180
|
|
201
|
-
const lineEnding = rfc4180Compliant ? '\r\n' : '\n';
|
|
202
|
-
return rows.join(lineEnding);
|
|
203
|
-
}, 'PARSE_FAILED', { function: 'jsonToCsv' });
|
|
204
|
-
}
|
|
205
|
-
|
|
206
|
-
/**
|
|
207
|
-
* Глубокое разворачивание вложенных объектов и массивов
|
|
208
|
-
*
|
|
209
|
-
* @param {*} value - Значение для разворачивания
|
|
210
|
-
* @param {number} [depth=0] - Текущая глубина рекурсии
|
|
211
|
-
* @param {number} [maxDepth=5] - Максимальная глубина рекурсии
|
|
212
|
-
* @param {Set} [visited=new Set()] - Посещенные объекты для обнаружения циклических ссылок
|
|
213
|
-
* @returns {string} Развернутое строковое значение
|
|
214
|
-
*/
|
|
215
|
-
export function deepUnwrap(value, depth = 0, maxDepth = 5, visited = new Set()) {
|
|
216
|
-
// Проверка глубины
|
|
217
|
-
if (depth >= maxDepth) {
|
|
218
|
-
return '[Too Deep]';
|
|
219
|
-
}
|
|
220
|
-
if (value === null || value === undefined) {
|
|
221
|
-
return '';
|
|
222
|
-
}
|
|
223
|
-
|
|
224
|
-
// Обработка циклических ссылок
|
|
225
|
-
if (typeof value === 'object') {
|
|
226
|
-
if (visited.has(value)) {
|
|
227
|
-
return '[Circular Reference]';
|
|
228
|
-
}
|
|
229
|
-
visited.add(value);
|
|
230
|
-
}
|
|
231
|
-
|
|
232
|
-
// Обработка массивов
|
|
233
|
-
if (Array.isArray(value)) {
|
|
234
|
-
if (value.length === 0) {
|
|
235
|
-
return '';
|
|
236
|
-
}
|
|
237
|
-
const unwrappedItems = value.map(item =>
|
|
238
|
-
deepUnwrap(item, depth + 1, maxDepth, visited)
|
|
239
|
-
).filter(item => item !== '');
|
|
240
|
-
return unwrappedItems.join(', ');
|
|
241
|
-
}
|
|
242
|
-
|
|
243
|
-
// Обработка объектов
|
|
244
|
-
if (typeof value === 'object') {
|
|
245
|
-
const keys = Object.keys(value);
|
|
246
|
-
if (keys.length === 0) {
|
|
247
|
-
return '';
|
|
248
|
-
}
|
|
249
|
-
|
|
250
|
-
if (depth + 1 >= maxDepth) {
|
|
251
|
-
return '[Too Deep]';
|
|
252
|
-
}
|
|
253
|
-
|
|
254
|
-
// Сериализация сложных объектов
|
|
255
|
-
try {
|
|
256
|
-
return JSON.stringify(value);
|
|
257
|
-
} catch (error) {
|
|
258
|
-
if (error.message.includes('circular') || error.message.includes('Converting circular')) {
|
|
259
|
-
return '[Circular Reference]';
|
|
260
|
-
}
|
|
261
|
-
return '[Unstringifiable Object]';
|
|
262
|
-
}
|
|
263
|
-
}
|
|
264
|
-
|
|
265
|
-
// Примитивные значения
|
|
266
|
-
return String(value);
|
|
267
|
-
}
|
|
268
|
-
|
|
269
|
-
/**
|
|
270
|
-
* Предобработка JSON данных путем глубокого разворачивания вложенных структур
|
|
271
|
-
*
|
|
272
|
-
* @param {Array<Object>} data - Массив объектов для предобработки
|
|
273
|
-
* @returns {Array<Object>} Предобработанные данные с развернутыми значениями
|
|
274
|
-
*/
|
|
275
|
-
export function preprocessData(data) {
|
|
276
|
-
if (!Array.isArray(data)) {
|
|
277
|
-
return [];
|
|
278
|
-
}
|
|
279
|
-
|
|
280
|
-
return data.map(item => {
|
|
281
|
-
if (!item || typeof item !== 'object') {
|
|
282
|
-
return {};
|
|
283
|
-
}
|
|
284
|
-
|
|
285
|
-
const processed = {};
|
|
286
|
-
|
|
287
|
-
for (const key in item) {
|
|
288
|
-
if (Object.prototype.hasOwnProperty.call(item, key)) {
|
|
289
|
-
const value = item[key];
|
|
290
|
-
if (value && typeof value === 'object') {
|
|
291
|
-
processed[key] = deepUnwrap(value);
|
|
292
|
-
} else {
|
|
293
|
-
processed[key] = value;
|
|
294
|
-
}
|
|
295
|
-
}
|
|
296
|
-
}
|
|
297
|
-
|
|
298
|
-
return processed;
|
|
299
|
-
});
|
|
300
|
-
}
|
|
301
|
-
|
|
302
|
-
// Экспорт для Node.js совместимости
|
|
303
|
-
if (typeof module !== 'undefined' && module.exports) {
|
|
304
|
-
module.exports = {
|
|
305
|
-
jsonToCsv,
|
|
306
|
-
preprocessData,
|
|
307
|
-
deepUnwrap
|
|
308
|
-
};
|
|
309
|
-
}
|