convert-csv-to-json 4.46.0 → 4.47.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 +9 -0
- package/csvToJson-mockup.html +309 -0
- package/index.d.ts +53 -6
- package/index.js +81 -60
- package/package.json +3 -1
- package/src/browserApi.js +39 -105
- package/src/core/configurable.js +126 -0
- package/src/{util → core}/errors.js +21 -20
- package/src/core/parserConfig.js +37 -0
- package/src/{streamProcessor.js → core/streamProcessor.js} +121 -9
- package/src/csvToJson.js +96 -181
- package/src/csvToJsonAsync.js +15 -102
- package/src/util/fileUtils.js +161 -38
- package/src/util/jsonUtils.js +1 -1
package/src/util/fileUtils.js
CHANGED
|
@@ -1,97 +1,220 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
3
|
const fs = require('fs');
|
|
4
|
-
const { FileOperationError } = require('
|
|
4
|
+
const { FileOperationError } = require('../core/errors');
|
|
5
|
+
|
|
6
|
+
const ENCODED_FILE_ENCODINGS = new Set(['base64', 'hex']);
|
|
5
7
|
|
|
6
8
|
/**
|
|
7
|
-
* File I/O utilities for reading and writing CSV/JSON files
|
|
8
|
-
* Provides both synchronous and asynchronous file operations
|
|
9
|
+
* File I/O utilities for reading and writing CSV/JSON files.
|
|
10
|
+
* Provides both synchronous and asynchronous file operations.
|
|
9
11
|
* @category Utilities
|
|
10
12
|
*/
|
|
11
13
|
class FileUtils {
|
|
14
|
+
/**
|
|
15
|
+
* Determine whether the encoding represents a binary-encoded file.
|
|
16
|
+
* @param {string} encoding - File encoding label
|
|
17
|
+
* @returns {boolean} True when encoding is base64 or hex
|
|
18
|
+
* @private
|
|
19
|
+
*/
|
|
20
|
+
_isEncodedFile(encoding) {
|
|
21
|
+
return ENCODED_FILE_ENCODINGS.has(encoding);
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Decode raw file content that was stored as base64 or hex.
|
|
26
|
+
* @param {string} rawContent - Raw file content read from disk
|
|
27
|
+
* @param {string} encoding - Encoding used for the file
|
|
28
|
+
* @returns {string} UTF-8 decoded string content
|
|
29
|
+
* @private
|
|
30
|
+
*/
|
|
31
|
+
_decodeContent(rawContent, encoding) {
|
|
32
|
+
if (this._isEncodedFile(encoding)) {
|
|
33
|
+
return Buffer.from(rawContent, encoding).toString('utf8');
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
return rawContent;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Convert raw file data into a string.
|
|
41
|
+
* @param {string|Buffer} data - Data read from fs
|
|
42
|
+
* @returns {string} String representation of the data
|
|
43
|
+
* @private
|
|
44
|
+
*/
|
|
45
|
+
_toString(data) {
|
|
46
|
+
return typeof data === 'string' ? data : data.toString();
|
|
47
|
+
}
|
|
12
48
|
|
|
13
49
|
/**
|
|
14
|
-
*
|
|
50
|
+
* Wrap a read error in a FileOperationError instance.
|
|
51
|
+
* @param {string} fileInputName - Path to file being read
|
|
52
|
+
* @param {Error} error - Original error from fs
|
|
53
|
+
* @returns {FileOperationError} Wrapped read error
|
|
54
|
+
* @private
|
|
55
|
+
*/
|
|
56
|
+
_wrapReadError(fileInputName, error) {
|
|
57
|
+
return new FileOperationError('read', fileInputName, error);
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* Wrap a write error in a FileOperationError instance.
|
|
62
|
+
* @param {string} fileOutputName - Path to file being written
|
|
63
|
+
* @param {Error} error - Original error from fs
|
|
64
|
+
* @returns {FileOperationError} Wrapped write error
|
|
65
|
+
* @private
|
|
66
|
+
*/
|
|
67
|
+
_wrapWriteError(fileOutputName, error) {
|
|
68
|
+
return new FileOperationError('write', fileOutputName, error);
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
/**
|
|
72
|
+
* Perform a synchronous file read using the provided encoding.
|
|
73
|
+
* @param {string} fileInputName - Path to file to read
|
|
74
|
+
* @param {string} encoding - File encoding to use when reading
|
|
75
|
+
* @returns {string} Decoded file content
|
|
76
|
+
* @private
|
|
77
|
+
*/
|
|
78
|
+
_readFileSync(fileInputName, encoding) {
|
|
79
|
+
if (this._isEncodedFile(encoding)) {
|
|
80
|
+
const rawContent = fs.readFileSync(fileInputName, 'utf8');
|
|
81
|
+
return this._decodeContent(rawContent, encoding);
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
return this._toString(fs.readFileSync(fileInputName, encoding));
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
/**
|
|
88
|
+
* Read a file synchronously with specified encoding.
|
|
15
89
|
* @param {string} fileInputName - Path to file to read
|
|
16
90
|
* @param {string} encoding - File encoding (e.g., 'utf8', 'latin1')
|
|
17
91
|
* @returns {string} File contents as string
|
|
18
92
|
* @throws {FileOperationError} If file read fails
|
|
19
93
|
*/
|
|
20
|
-
readFile(fileInputName, encoding) {
|
|
94
|
+
readFile(fileInputName, encoding = 'utf8') {
|
|
21
95
|
try {
|
|
22
|
-
return
|
|
96
|
+
return this._readFileSync(fileInputName, encoding);
|
|
23
97
|
} catch (error) {
|
|
24
|
-
throw
|
|
98
|
+
throw this._wrapReadError(fileInputName, error);
|
|
25
99
|
}
|
|
26
100
|
}
|
|
27
101
|
|
|
28
102
|
/**
|
|
29
|
-
* Read a file
|
|
30
|
-
*
|
|
103
|
+
* Read a file using fs.promises and return decoded content.
|
|
104
|
+
* @param {string} fileInputName - Path to file to read
|
|
105
|
+
* @param {string} encoding - File encoding to use
|
|
106
|
+
* @returns {Promise<string>} Promise resolving to decoded file content
|
|
107
|
+
* @private
|
|
108
|
+
*/
|
|
109
|
+
_readFileAsyncWithPromises(fileInputName, encoding) {
|
|
110
|
+
if (this._isEncodedFile(encoding)) {
|
|
111
|
+
return fs.promises.readFile(fileInputName, 'utf8')
|
|
112
|
+
.then(rawContent => this._decodeContent(rawContent, encoding));
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
return fs.promises.readFile(fileInputName, encoding)
|
|
116
|
+
.then(data => this._toString(data));
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
/**
|
|
120
|
+
* Read a file asynchronously with specified encoding.
|
|
121
|
+
* Uses fs.promises when available, falls back to callback-based API.
|
|
31
122
|
* @param {string} fileInputName - Path to file to read
|
|
32
123
|
* @param {string} encoding - File encoding (default: 'utf8')
|
|
33
124
|
* @returns {Promise<string>} Promise resolving to file contents
|
|
34
125
|
* @throws {FileOperationError} If file read fails
|
|
35
126
|
*/
|
|
36
127
|
readFileAsync(fileInputName, encoding = 'utf8') {
|
|
37
|
-
// Use fs.promises when available for a Promise-based API
|
|
38
128
|
if (fs.promises && typeof fs.promises.readFile === 'function') {
|
|
39
|
-
return
|
|
40
|
-
.then(buf => buf.toString())
|
|
129
|
+
return this._readFileAsyncWithPromises(fileInputName, encoding)
|
|
41
130
|
.catch(error => {
|
|
42
|
-
throw
|
|
131
|
+
throw this._wrapReadError(fileInputName, error);
|
|
43
132
|
});
|
|
44
133
|
}
|
|
134
|
+
|
|
45
135
|
return new Promise((resolve, reject) => {
|
|
46
|
-
|
|
47
|
-
if (
|
|
48
|
-
reject(
|
|
136
|
+
const callback = (error, data) => {
|
|
137
|
+
if (error) {
|
|
138
|
+
reject(this._wrapReadError(fileInputName, error));
|
|
49
139
|
return;
|
|
50
140
|
}
|
|
51
|
-
|
|
52
|
-
|
|
141
|
+
|
|
142
|
+
try {
|
|
143
|
+
const content = this._isEncodedFile(encoding)
|
|
144
|
+
? this._decodeContent(this._toString(data), encoding)
|
|
145
|
+
: this._toString(data);
|
|
146
|
+
resolve(content);
|
|
147
|
+
} catch (decodeError) {
|
|
148
|
+
reject(this._wrapReadError(fileInputName, decodeError));
|
|
149
|
+
}
|
|
150
|
+
};
|
|
151
|
+
|
|
152
|
+
const readEncoding = this._isEncodedFile(encoding) ? 'utf8' : encoding;
|
|
153
|
+
fs.readFile(fileInputName, readEncoding, callback);
|
|
53
154
|
});
|
|
54
155
|
}
|
|
55
156
|
|
|
56
157
|
/**
|
|
57
|
-
* Write content to a file synchronously
|
|
58
|
-
*
|
|
59
|
-
* @param {string}
|
|
158
|
+
* Write content to a file synchronously.
|
|
159
|
+
* @param {string} fileOutputName - Path to output file
|
|
160
|
+
* @param {string} content - File content to write
|
|
161
|
+
* @private
|
|
162
|
+
*/
|
|
163
|
+
_writeFileSync(fileOutputName, content) {
|
|
164
|
+
fs.writeFileSync(fileOutputName, content, 'utf8');
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
/**
|
|
168
|
+
* Write content to a file using fs.promises.
|
|
169
|
+
* @param {string} fileOutputName - Path to output file
|
|
170
|
+
* @param {string} content - File content to write
|
|
171
|
+
* @returns {Promise<void>} Promise that resolves when write completes
|
|
172
|
+
* @private
|
|
173
|
+
*/
|
|
174
|
+
_writeFileAsyncWithPromises(fileOutputName, content) {
|
|
175
|
+
return fs.promises.writeFile(fileOutputName, content, 'utf8');
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
/**
|
|
179
|
+
* Write content to a file synchronously.
|
|
180
|
+
* @param {string} content - Content to write to file
|
|
60
181
|
* @param {string} fileOutputName - Path to output file
|
|
61
182
|
* @throws {FileOperationError} If file write fails
|
|
62
183
|
*/
|
|
63
|
-
writeFile(
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
}
|
|
70
|
-
});
|
|
184
|
+
writeFile(content, fileOutputName) {
|
|
185
|
+
try {
|
|
186
|
+
this._writeFileSync(fileOutputName, content);
|
|
187
|
+
} catch (error) {
|
|
188
|
+
throw this._wrapWriteError(fileOutputName, error);
|
|
189
|
+
}
|
|
71
190
|
}
|
|
72
191
|
|
|
73
192
|
/**
|
|
74
|
-
* Write content to a file asynchronously
|
|
75
|
-
* Uses fs.promises when available, falls back to callback-based API
|
|
76
|
-
* @param {string}
|
|
193
|
+
* Write content to a file asynchronously.
|
|
194
|
+
* Uses fs.promises when available, falls back to callback-based API.
|
|
195
|
+
* @param {string} content - Content to write to file
|
|
77
196
|
* @param {string} fileOutputName - Path to output file
|
|
78
197
|
* @returns {Promise<void>} Promise that resolves when write completes
|
|
79
198
|
* @throws {FileOperationError} If file write fails
|
|
80
199
|
*/
|
|
81
|
-
writeFileAsync(
|
|
200
|
+
writeFileAsync(content, fileOutputName) {
|
|
82
201
|
if (fs.promises && typeof fs.promises.writeFile === 'function') {
|
|
83
|
-
return
|
|
202
|
+
return this._writeFileAsyncWithPromises(fileOutputName, content)
|
|
84
203
|
.catch(error => {
|
|
85
|
-
throw
|
|
204
|
+
throw this._wrapWriteError(fileOutputName, error);
|
|
86
205
|
});
|
|
87
206
|
}
|
|
207
|
+
|
|
88
208
|
return new Promise((resolve, reject) => {
|
|
89
|
-
fs.writeFile(fileOutputName,
|
|
90
|
-
if (
|
|
209
|
+
fs.writeFile(fileOutputName, content, 'utf8', (error) => {
|
|
210
|
+
if (error) {
|
|
211
|
+
reject(this._wrapWriteError(fileOutputName, error));
|
|
212
|
+
return;
|
|
213
|
+
}
|
|
91
214
|
resolve();
|
|
92
215
|
});
|
|
93
216
|
});
|
|
94
217
|
}
|
|
95
|
-
|
|
96
218
|
}
|
|
219
|
+
|
|
97
220
|
module.exports = new FileUtils();
|