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/csv-to-json.js
DELETED
|
@@ -1,688 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* CSV to JSON Converter - Node.js Module
|
|
3
|
-
*
|
|
4
|
-
* A lightweight, efficient module for converting CSV data to JSON format
|
|
5
|
-
* with proper parsing and error handling.
|
|
6
|
-
*
|
|
7
|
-
* @module csv-to-json
|
|
8
|
-
*/
|
|
9
|
-
|
|
10
|
-
const {
|
|
11
|
-
ValidationError,
|
|
12
|
-
SecurityError,
|
|
13
|
-
FileSystemError,
|
|
14
|
-
ParsingError,
|
|
15
|
-
LimitError,
|
|
16
|
-
ConfigurationError,
|
|
17
|
-
safeExecute
|
|
18
|
-
} = require('./errors');
|
|
19
|
-
|
|
20
|
-
const { TransformHooks, predefinedHooks } = require('./src/core/transform-hooks');
|
|
21
|
-
const DelimiterCache = require('./src/core/delimiter-cache');
|
|
22
|
-
const FastPathEngine = require('./src/engines/fast-path-engine');
|
|
23
|
-
|
|
24
|
-
// Глобальный экземпляр кэша для авто-детектирования разделителя
|
|
25
|
-
const globalDelimiterCache = new DelimiterCache(100);
|
|
26
|
-
const globalFastPathEngine = new FastPathEngine();
|
|
27
|
-
|
|
28
|
-
/**
|
|
29
|
-
* Validates CSV input and options
|
|
30
|
-
* @private
|
|
31
|
-
*/
|
|
32
|
-
function validateCsvInput(csv, options) {
|
|
33
|
-
// Validate CSV input
|
|
34
|
-
if (typeof csv !== 'string') {
|
|
35
|
-
throw new ValidationError('Input must be a CSV string');
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
// Validate options
|
|
39
|
-
if (options && typeof options !== 'object') {
|
|
40
|
-
throw new ConfigurationError('Options must be an object');
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
// Validate delimiter
|
|
44
|
-
if (options?.delimiter && typeof options.delimiter !== 'string') {
|
|
45
|
-
throw new ConfigurationError('Delimiter must be a string');
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
if (options?.delimiter && options.delimiter.length !== 1) {
|
|
49
|
-
throw new ConfigurationError('Delimiter must be a single character');
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
// Validate autoDetect
|
|
53
|
-
if (options?.autoDetect !== undefined && typeof options.autoDetect !== 'boolean') {
|
|
54
|
-
throw new ConfigurationError('autoDetect must be a boolean');
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
// Validate candidates
|
|
58
|
-
if (options?.candidates && !Array.isArray(options.candidates)) {
|
|
59
|
-
throw new ConfigurationError('candidates must be an array');
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
// Validate maxRows
|
|
63
|
-
if (options?.maxRows !== undefined && (typeof options.maxRows !== 'number' || options.maxRows <= 0)) {
|
|
64
|
-
throw new ConfigurationError('maxRows must be a positive number');
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
// Validate cache options
|
|
68
|
-
if (options?.useCache !== undefined && typeof options.useCache !== 'boolean') {
|
|
69
|
-
throw new ConfigurationError('useCache must be a boolean');
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
if (options?.cache && !(options.cache instanceof DelimiterCache)) {
|
|
73
|
-
throw new ConfigurationError('cache must be an instance of DelimiterCache');
|
|
74
|
-
}
|
|
75
|
-
|
|
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) {
|
|
89
|
-
if (typeof options.hooks !== 'object') {
|
|
90
|
-
throw new ConfigurationError('hooks must be an object');
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
if (options.hooks.beforeConvert && typeof options.hooks.beforeConvert !== 'function') {
|
|
94
|
-
throw new ConfigurationError('hooks.beforeConvert must be a function');
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
if (options.hooks.afterConvert && typeof options.hooks.afterConvert !== 'function') {
|
|
98
|
-
throw new ConfigurationError('hooks.afterConvert must be a function');
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
if (options.hooks.perRow && typeof options.hooks.perRow !== 'function') {
|
|
102
|
-
throw new ConfigurationError('hooks.perRow must be a function');
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
if (options.hooks.transformHooks && !(options.hooks.transformHooks instanceof TransformHooks)) {
|
|
106
|
-
throw new ConfigurationError('hooks.transformHooks must be an instance of TransformHooks');
|
|
107
|
-
}
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
return true;
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
/**
|
|
114
|
-
* Parses a value based on options
|
|
115
|
-
* @private
|
|
116
|
-
*/
|
|
117
|
-
function parseCsvValue(value, options) {
|
|
118
|
-
/* istanbul ignore next */
|
|
119
|
-
const { trim = true, parseNumbers = false, parseBooleans = false } = options;
|
|
120
|
-
|
|
121
|
-
let result = value;
|
|
122
|
-
|
|
123
|
-
if (trim) {
|
|
124
|
-
result = result.trim();
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
// Remove Excel formula protection
|
|
128
|
-
if (result.startsWith("'")) {
|
|
129
|
-
result = result.substring(1);
|
|
130
|
-
}
|
|
131
|
-
|
|
132
|
-
// Parse numbers
|
|
133
|
-
if (parseNumbers && /^-?\d+(\.\d+)?$/.test(result)) {
|
|
134
|
-
const num = parseFloat(result);
|
|
135
|
-
/* istanbul ignore next */
|
|
136
|
-
if (!isNaN(num)) {
|
|
137
|
-
return num;
|
|
138
|
-
}
|
|
139
|
-
}
|
|
140
|
-
|
|
141
|
-
// Parse booleans
|
|
142
|
-
if (parseBooleans) {
|
|
143
|
-
const lowerValue = result.toLowerCase();
|
|
144
|
-
if (lowerValue === 'true') {
|
|
145
|
-
return true;
|
|
146
|
-
}
|
|
147
|
-
if (lowerValue === 'false') {
|
|
148
|
-
return false;
|
|
149
|
-
}
|
|
150
|
-
}
|
|
151
|
-
|
|
152
|
-
// 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
|
-
*/
|
|
164
|
-
function autoDetectDelimiter(csv, candidates = [';', ',', '\t', '|'], cache = null) {
|
|
165
|
-
// Используем статический метод DelimiterCache с поддержкой кэширования
|
|
166
|
-
return DelimiterCache.autoDetectDelimiter(csv, candidates, cache);
|
|
167
|
-
}
|
|
168
|
-
|
|
169
|
-
/**
|
|
170
|
-
* Converts CSV string to JSON array with hooks and caching support
|
|
171
|
-
*
|
|
172
|
-
* @param {string} csv - CSV string to convert
|
|
173
|
-
* @param {Object} [options] - Configuration options
|
|
174
|
-
* @param {string} [options.delimiter] - CSV delimiter character (default: auto-detected)
|
|
175
|
-
* @param {boolean} [options.autoDetect=true] - Auto-detect delimiter if not specified
|
|
176
|
-
* @param {Array} [options.candidates=[';', ',', '\t', '|']] - Candidate delimiters for auto-detection
|
|
177
|
-
* @param {boolean} [options.hasHeaders=true] - Whether CSV has headers row
|
|
178
|
-
* @param {Object} [options.renameMap={}] - Map for renaming column headers (newKey: oldKey)
|
|
179
|
-
* @param {boolean} [options.trim=true] - Trim whitespace from values
|
|
180
|
-
* @param {boolean} [options.parseNumbers=false] - Parse numeric values
|
|
181
|
-
* @param {boolean} [options.parseBooleans=false] - Parse boolean values
|
|
182
|
-
* @param {number} [options.maxRows] - Maximum number of rows to process (optional, no limit by default)
|
|
183
|
-
* @param {boolean} [options.useCache=true] - Use caching for delimiter detection
|
|
184
|
-
* @param {DelimiterCache} [options.cache] - Custom cache instance (optional)
|
|
185
|
-
* @param {Object} [options.hooks] - Transform hooks
|
|
186
|
-
* @param {Function} [options.hooks.beforeConvert] - Hook called before conversion
|
|
187
|
-
* @param {Function} [options.hooks.afterConvert] - Hook called after conversion
|
|
188
|
-
* @param {Function} [options.hooks.perRow] - Hook called for each row
|
|
189
|
-
* @param {TransformHooks} [options.hooks.transformHooks] - TransformHooks instance
|
|
190
|
-
* @returns {Array<Object>} JSON array
|
|
191
|
-
*
|
|
192
|
-
* @example
|
|
193
|
-
* const { csvToJson } = require('./csv-to-json');
|
|
194
|
-
*
|
|
195
|
-
* const csv = `id;name;email\n1;John;john@example.com\n2;Jane;jane@example.com`;
|
|
196
|
-
* const json = csvToJson(csv, {
|
|
197
|
-
* delimiter: ';',
|
|
198
|
-
* parseNumbers: true,
|
|
199
|
-
* useCache: true, // Включить кэширование
|
|
200
|
-
* hooks: {
|
|
201
|
-
* beforeConvert: (data) => {
|
|
202
|
-
* console.log('Starting conversion...');
|
|
203
|
-
* return data;
|
|
204
|
-
* },
|
|
205
|
-
* perRow: (row, index) => {
|
|
206
|
-
* return { ...row, processed: true, index };
|
|
207
|
-
* },
|
|
208
|
-
* afterConvert: (data) => {
|
|
209
|
-
* return data.filter(item => item.id > 0);
|
|
210
|
-
* }
|
|
211
|
-
* }
|
|
212
|
-
* });
|
|
213
|
-
*/
|
|
214
|
-
function csvToJson(csv, options = {}) {
|
|
215
|
-
return safeExecute(() => {
|
|
216
|
-
// Validate input
|
|
217
|
-
validateCsvInput(csv, options);
|
|
218
|
-
|
|
219
|
-
const opts = options && typeof options === 'object' ? options : {};
|
|
220
|
-
|
|
221
|
-
const {
|
|
222
|
-
delimiter,
|
|
223
|
-
autoDetect = true,
|
|
224
|
-
candidates = [';', ',', '\t', '|'],
|
|
225
|
-
hasHeaders = true,
|
|
226
|
-
renameMap = {},
|
|
227
|
-
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
|
-
} = opts;
|
|
237
|
-
|
|
238
|
-
if (fastPathMode === 'stream') {
|
|
239
|
-
return csvToJsonIterator(csv, { ...opts, useFastPath, fastPathMode: 'objects' });
|
|
240
|
-
}
|
|
241
|
-
|
|
242
|
-
// Выбираем кэш для использования
|
|
243
|
-
const cacheToUse = useCache ? (customCache || globalDelimiterCache) : null;
|
|
244
|
-
|
|
245
|
-
// Create transform hooks system
|
|
246
|
-
const transformHooks = new TransformHooks();
|
|
247
|
-
|
|
248
|
-
// Add individual hooks if provided
|
|
249
|
-
if (hooks.beforeConvert) {
|
|
250
|
-
transformHooks.beforeConvert(hooks.beforeConvert);
|
|
251
|
-
}
|
|
252
|
-
|
|
253
|
-
if (hooks.afterConvert) {
|
|
254
|
-
transformHooks.afterConvert(hooks.afterConvert);
|
|
255
|
-
}
|
|
256
|
-
|
|
257
|
-
if (hooks.perRow) {
|
|
258
|
-
transformHooks.perRow(hooks.perRow);
|
|
259
|
-
}
|
|
260
|
-
|
|
261
|
-
// Use provided TransformHooks instance if available
|
|
262
|
-
const finalHooks = hooks.transformHooks || transformHooks;
|
|
263
|
-
|
|
264
|
-
// Apply beforeConvert hooks to CSV string
|
|
265
|
-
const processedCsv = finalHooks.applyBeforeConvert(csv, {
|
|
266
|
-
operation: 'csvToJson',
|
|
267
|
-
options: opts
|
|
268
|
-
});
|
|
269
|
-
|
|
270
|
-
// Determine delimiter with caching support
|
|
271
|
-
let finalDelimiter = delimiter;
|
|
272
|
-
if (!finalDelimiter && autoDetect) {
|
|
273
|
-
finalDelimiter = autoDetectDelimiter(processedCsv, candidates, cacheToUse);
|
|
274
|
-
}
|
|
275
|
-
finalDelimiter = finalDelimiter || ';'; // fallback
|
|
276
|
-
|
|
277
|
-
// Handle empty CSV
|
|
278
|
-
if (processedCsv.trim() === '') {
|
|
279
|
-
return [];
|
|
280
|
-
}
|
|
281
|
-
|
|
282
|
-
let headers = null;
|
|
283
|
-
let totalRows = 0;
|
|
284
|
-
let dataRowIndex = 0;
|
|
285
|
-
const result = [];
|
|
286
|
-
|
|
287
|
-
try {
|
|
288
|
-
const parseOptions = { delimiter: finalDelimiter };
|
|
289
|
-
if (useFastPath === false) {
|
|
290
|
-
parseOptions.forceEngine = 'STANDARD';
|
|
291
|
-
}
|
|
292
|
-
|
|
293
|
-
globalFastPathEngine.parseRows(processedCsv, parseOptions, (fields) => {
|
|
294
|
-
totalRows++;
|
|
295
|
-
|
|
296
|
-
if (!headers) {
|
|
297
|
-
if (hasHeaders) {
|
|
298
|
-
headers = fields.map(header => {
|
|
299
|
-
const trimmed = trim ? header.trim() : header;
|
|
300
|
-
return renameMap[trimmed] || trimmed;
|
|
301
|
-
});
|
|
302
|
-
return;
|
|
303
|
-
}
|
|
304
|
-
headers = fields.map((_, index) => `column${index + 1}`);
|
|
305
|
-
}
|
|
306
|
-
|
|
307
|
-
if (!fields || fields.length === 0) {
|
|
308
|
-
return;
|
|
309
|
-
}
|
|
310
|
-
|
|
311
|
-
if (maxRows && totalRows > maxRows) {
|
|
312
|
-
throw new LimitError(
|
|
313
|
-
`CSV size exceeds maximum limit of ${maxRows} rows`,
|
|
314
|
-
maxRows,
|
|
315
|
-
totalRows
|
|
316
|
-
);
|
|
317
|
-
}
|
|
318
|
-
|
|
319
|
-
const fieldCount = Math.min(fields.length, headers.length);
|
|
320
|
-
let row;
|
|
321
|
-
|
|
322
|
-
if (fastPathMode === 'compact') {
|
|
323
|
-
row = new Array(fieldCount);
|
|
324
|
-
for (let j = 0; j < fieldCount; j++) {
|
|
325
|
-
row[j] = parseCsvValue(fields[j], { trim, parseNumbers, parseBooleans });
|
|
326
|
-
}
|
|
327
|
-
} else {
|
|
328
|
-
row = {};
|
|
329
|
-
for (let j = 0; j < fieldCount; j++) {
|
|
330
|
-
row[headers[j]] = parseCsvValue(fields[j], { trim, parseNumbers, parseBooleans });
|
|
331
|
-
}
|
|
332
|
-
}
|
|
333
|
-
|
|
334
|
-
const processedRow = finalHooks.applyPerRow(row, dataRowIndex, {
|
|
335
|
-
lineNumber: totalRows,
|
|
336
|
-
headers,
|
|
337
|
-
options: opts
|
|
338
|
-
});
|
|
339
|
-
|
|
340
|
-
dataRowIndex++;
|
|
341
|
-
result.push(processedRow);
|
|
342
|
-
|
|
343
|
-
if (fields.length > headers.length && process.env.NODE_ENV === 'development') {
|
|
344
|
-
console.warn(`[jtcsv] Line ${totalRows}: ${fields.length - headers.length} extra fields ignored`);
|
|
345
|
-
}
|
|
346
|
-
});
|
|
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
|
-
}
|
|
354
|
-
|
|
355
|
-
if (!headers) {
|
|
356
|
-
return [];
|
|
357
|
-
}
|
|
358
|
-
|
|
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
|
-
}
|
|
367
|
-
|
|
368
|
-
return finalHooks.applyAfterConvert(result, {
|
|
369
|
-
operation: 'csvToJson',
|
|
370
|
-
totalRows: result.length,
|
|
371
|
-
options: opts
|
|
372
|
-
});
|
|
373
|
-
|
|
374
|
-
}, 'PARSE_FAILED', { function: 'csvToJson' });
|
|
375
|
-
}
|
|
376
|
-
|
|
377
|
-
/* istanbul ignore next */
|
|
378
|
-
async function* csvToJsonIterator(csv, options = {}) {
|
|
379
|
-
validateCsvInput(csv, options);
|
|
380
|
-
|
|
381
|
-
const opts = options && typeof options === 'object' ? options : {};
|
|
382
|
-
|
|
383
|
-
const {
|
|
384
|
-
delimiter,
|
|
385
|
-
autoDetect = true,
|
|
386
|
-
candidates = [';', ',', '\t', '|'],
|
|
387
|
-
hasHeaders = true,
|
|
388
|
-
renameMap = {},
|
|
389
|
-
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;
|
|
399
|
-
|
|
400
|
-
const cacheToUse = useCache ? (customCache || globalDelimiterCache) : null;
|
|
401
|
-
|
|
402
|
-
const transformHooks = new TransformHooks();
|
|
403
|
-
|
|
404
|
-
if (hooks.beforeConvert) {
|
|
405
|
-
transformHooks.beforeConvert(hooks.beforeConvert);
|
|
406
|
-
}
|
|
407
|
-
|
|
408
|
-
if (hooks.afterConvert) {
|
|
409
|
-
transformHooks.afterConvert(hooks.afterConvert);
|
|
410
|
-
}
|
|
411
|
-
|
|
412
|
-
if (hooks.perRow) {
|
|
413
|
-
transformHooks.perRow(hooks.perRow);
|
|
414
|
-
}
|
|
415
|
-
|
|
416
|
-
const finalHooks = hooks.transformHooks || transformHooks;
|
|
417
|
-
|
|
418
|
-
const processedCsv = finalHooks.applyBeforeConvert(csv, {
|
|
419
|
-
operation: 'csvToJson',
|
|
420
|
-
options: opts
|
|
421
|
-
});
|
|
422
|
-
|
|
423
|
-
let finalDelimiter = delimiter;
|
|
424
|
-
if (!finalDelimiter && autoDetect) {
|
|
425
|
-
finalDelimiter = autoDetectDelimiter(processedCsv, candidates, cacheToUse);
|
|
426
|
-
}
|
|
427
|
-
finalDelimiter = finalDelimiter || ';';
|
|
428
|
-
|
|
429
|
-
if (processedCsv.trim() === '') {
|
|
430
|
-
return;
|
|
431
|
-
}
|
|
432
|
-
|
|
433
|
-
let headers = null;
|
|
434
|
-
let totalRows = 0;
|
|
435
|
-
let dataRowIndex = 0;
|
|
436
|
-
|
|
437
|
-
const handleFields = (fields, lineNumber) => {
|
|
438
|
-
if (!headers) {
|
|
439
|
-
if (hasHeaders) {
|
|
440
|
-
headers = fields.map(header => {
|
|
441
|
-
const trimmed = trim ? header.trim() : header;
|
|
442
|
-
return renameMap[trimmed] || trimmed;
|
|
443
|
-
});
|
|
444
|
-
return null;
|
|
445
|
-
}
|
|
446
|
-
headers = fields.map((_, index) => `column${index + 1}`);
|
|
447
|
-
}
|
|
448
|
-
|
|
449
|
-
if (!fields || fields.length === 0) {
|
|
450
|
-
return null;
|
|
451
|
-
}
|
|
452
|
-
|
|
453
|
-
const fieldCount = Math.min(fields.length, headers.length);
|
|
454
|
-
let row;
|
|
455
|
-
|
|
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
|
-
}
|
|
463
|
-
} else {
|
|
464
|
-
row = {};
|
|
465
|
-
for (let j = 0; j < fieldCount; j++) {
|
|
466
|
-
row[headers[j]] = parseCsvValue(fields[j], { trim, parseNumbers, parseBooleans });
|
|
467
|
-
}
|
|
468
|
-
}
|
|
469
|
-
|
|
470
|
-
const processedRow = finalHooks.applyPerRow(row, dataRowIndex, {
|
|
471
|
-
lineNumber,
|
|
472
|
-
headers,
|
|
473
|
-
options: opts
|
|
474
|
-
});
|
|
475
|
-
|
|
476
|
-
dataRowIndex++;
|
|
477
|
-
return processedRow;
|
|
478
|
-
};
|
|
479
|
-
|
|
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
|
-
}
|
|
511
|
-
|
|
512
|
-
/**
|
|
513
|
-
* Validates file path for CSV reading
|
|
514
|
-
* @private
|
|
515
|
-
*/
|
|
516
|
-
function validateCsvFilePath(filePath) {
|
|
517
|
-
const path = require('path');
|
|
518
|
-
|
|
519
|
-
// Basic validation
|
|
520
|
-
if (typeof filePath !== 'string' || filePath.trim() === '') {
|
|
521
|
-
throw new ValidationError('File path must be a non-empty string');
|
|
522
|
-
}
|
|
523
|
-
|
|
524
|
-
// Ensure file has .csv extension
|
|
525
|
-
if (!filePath.toLowerCase().endsWith('.csv')) {
|
|
526
|
-
throw new ValidationError('File must have .csv extension');
|
|
527
|
-
}
|
|
528
|
-
|
|
529
|
-
// Prevent directory traversal attacks
|
|
530
|
-
const normalizedPath = path.normalize(filePath);
|
|
531
|
-
if (normalizedPath.includes('..') ||
|
|
532
|
-
/\\\\.\\.\\|\/\\.\\.\//.test(filePath) ||
|
|
533
|
-
filePath.startsWith('..') ||
|
|
534
|
-
filePath.includes('/..')) {
|
|
535
|
-
throw new SecurityError('Directory traversal detected in file path');
|
|
536
|
-
}
|
|
537
|
-
|
|
538
|
-
return path.resolve(filePath);
|
|
539
|
-
}
|
|
540
|
-
|
|
541
|
-
/**
|
|
542
|
-
* Reads CSV file and converts it to JSON array with hooks and caching support
|
|
543
|
-
*
|
|
544
|
-
* @param {string} filePath - Path to CSV file
|
|
545
|
-
* @param {Object} [options] - Configuration options (same as csvToJson)
|
|
546
|
-
* @returns {Promise<Array<Object>>} Promise that resolves to JSON array
|
|
547
|
-
*
|
|
548
|
-
* @example
|
|
549
|
-
* const { readCsvAsJson } = require('./csv-to-json');
|
|
550
|
-
*
|
|
551
|
-
* const json = await readCsvAsJson('./data.csv', {
|
|
552
|
-
* delimiter: ',',
|
|
553
|
-
* parseNumbers: true,
|
|
554
|
-
* useCache: true,
|
|
555
|
-
* hooks: {
|
|
556
|
-
* perRow: (row) => ({ ...row, processed: true })
|
|
557
|
-
* }
|
|
558
|
-
* });
|
|
559
|
-
*/
|
|
560
|
-
async function readCsvAsJson(filePath, options = {}) {
|
|
561
|
-
const fs = require('fs').promises;
|
|
562
|
-
|
|
563
|
-
// Validate file path
|
|
564
|
-
const safePath = validateCsvFilePath(filePath);
|
|
565
|
-
|
|
566
|
-
try {
|
|
567
|
-
// Read file
|
|
568
|
-
const csvContent = await fs.readFile(safePath, 'utf8');
|
|
569
|
-
|
|
570
|
-
// Parse CSV with hooks and caching
|
|
571
|
-
return csvToJson(csvContent, options);
|
|
572
|
-
} catch (error) {
|
|
573
|
-
// Re-throw parsing errors as-is
|
|
574
|
-
if (error instanceof ParsingError || error instanceof ValidationError || error instanceof LimitError) {
|
|
575
|
-
throw error;
|
|
576
|
-
}
|
|
577
|
-
|
|
578
|
-
// Wrap file system errors
|
|
579
|
-
if (error.code === 'ENOENT') {
|
|
580
|
-
throw new FileSystemError(`File not found: ${safePath}`, error);
|
|
581
|
-
}
|
|
582
|
-
if (error.code === 'EACCES') {
|
|
583
|
-
throw new FileSystemError(`Permission denied: ${safePath}`, error);
|
|
584
|
-
}
|
|
585
|
-
if (error.code === 'EISDIR') {
|
|
586
|
-
throw new FileSystemError(`Path is a directory: ${safePath}`, error);
|
|
587
|
-
}
|
|
588
|
-
|
|
589
|
-
throw new FileSystemError(`Failed to read CSV file: ${error.message}`, error);
|
|
590
|
-
}
|
|
591
|
-
}
|
|
592
|
-
|
|
593
|
-
/**
|
|
594
|
-
* Synchronously reads CSV file and converts it to JSON array with hooks and caching support
|
|
595
|
-
*
|
|
596
|
-
* @param {string} filePath - Path to CSV file
|
|
597
|
-
* @param {Object} [options] - Configuration options (same as csvToJson)
|
|
598
|
-
* @returns {Array<Object>} JSON array
|
|
599
|
-
*/
|
|
600
|
-
function readCsvAsJsonSync(filePath, options = {}) {
|
|
601
|
-
const fs = require('fs');
|
|
602
|
-
|
|
603
|
-
// Validate file path
|
|
604
|
-
const safePath = validateCsvFilePath(filePath);
|
|
605
|
-
|
|
606
|
-
try {
|
|
607
|
-
// Read file
|
|
608
|
-
const csvContent = fs.readFileSync(safePath, 'utf8');
|
|
609
|
-
|
|
610
|
-
// Parse CSV with hooks and caching
|
|
611
|
-
return csvToJson(csvContent, options);
|
|
612
|
-
} catch (error) {
|
|
613
|
-
// Re-throw parsing errors as-is
|
|
614
|
-
if (error instanceof ParsingError || error instanceof ValidationError || error instanceof LimitError) {
|
|
615
|
-
throw error;
|
|
616
|
-
}
|
|
617
|
-
|
|
618
|
-
// Wrap file system errors
|
|
619
|
-
if (error.code === 'ENOENT') {
|
|
620
|
-
throw new FileSystemError(`File not found: ${safePath}`, error);
|
|
621
|
-
}
|
|
622
|
-
if (error.code === 'EACCES') {
|
|
623
|
-
throw new FileSystemError(`Permission denied: ${safePath}`, error);
|
|
624
|
-
}
|
|
625
|
-
if (error.code === 'EISDIR') {
|
|
626
|
-
throw new FileSystemError(`Path is a directory: ${safePath}`, error);
|
|
627
|
-
}
|
|
628
|
-
|
|
629
|
-
throw new FileSystemError(`Failed to read CSV file: ${error.message}`, error);
|
|
630
|
-
}
|
|
631
|
-
}
|
|
632
|
-
|
|
633
|
-
/**
|
|
634
|
-
* Creates a new TransformHooks instance
|
|
635
|
-
* @returns {TransformHooks} New TransformHooks instance
|
|
636
|
-
*/
|
|
637
|
-
function createTransformHooks() {
|
|
638
|
-
return new TransformHooks();
|
|
639
|
-
}
|
|
640
|
-
|
|
641
|
-
/**
|
|
642
|
-
* Creates a new DelimiterCache instance
|
|
643
|
-
* @param {number} maxSize - Maximum cache size (default: 100)
|
|
644
|
-
* @returns {DelimiterCache} New DelimiterCache instance
|
|
645
|
-
*/
|
|
646
|
-
/* istanbul ignore next */
|
|
647
|
-
function createDelimiterCache(maxSize = 100) {
|
|
648
|
-
return new DelimiterCache(maxSize);
|
|
649
|
-
}
|
|
650
|
-
|
|
651
|
-
/**
|
|
652
|
-
* Gets statistics from the global delimiter cache
|
|
653
|
-
* @returns {Object} Cache statistics
|
|
654
|
-
*/
|
|
655
|
-
/* istanbul ignore next */
|
|
656
|
-
function getDelimiterCacheStats() {
|
|
657
|
-
return globalDelimiterCache.getStats();
|
|
658
|
-
}
|
|
659
|
-
|
|
660
|
-
/**
|
|
661
|
-
* Clears the global delimiter cache
|
|
662
|
-
*/
|
|
663
|
-
/* istanbul ignore next */
|
|
664
|
-
function clearDelimiterCache() {
|
|
665
|
-
globalDelimiterCache.clear();
|
|
666
|
-
}
|
|
667
|
-
|
|
668
|
-
// Export the functions
|
|
669
|
-
module.exports = {
|
|
670
|
-
csvToJson,
|
|
671
|
-
csvToJsonIterator,
|
|
672
|
-
readCsvAsJson,
|
|
673
|
-
readCsvAsJsonSync,
|
|
674
|
-
autoDetectDelimiter,
|
|
675
|
-
createTransformHooks,
|
|
676
|
-
createDelimiterCache,
|
|
677
|
-
getDelimiterCacheStats,
|
|
678
|
-
clearDelimiterCache,
|
|
679
|
-
TransformHooks,
|
|
680
|
-
DelimiterCache,
|
|
681
|
-
predefinedHooks
|
|
682
|
-
};
|
|
683
|
-
|
|
684
|
-
// For ES6 module compatibility
|
|
685
|
-
/* istanbul ignore next */
|
|
686
|
-
if (typeof module !== 'undefined' && module.exports) {
|
|
687
|
-
module.exports.default = csvToJson;
|
|
688
|
-
}
|