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.
@@ -1,97 +1,220 @@
1
1
  'use strict';
2
2
 
3
3
  const fs = require('fs');
4
- const { FileOperationError } = require('./errors');
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
- * Read a file synchronously with specified encoding
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 fs.readFileSync(fileInputName, encoding).toString();
96
+ return this._readFileSync(fileInputName, encoding);
23
97
  } catch (error) {
24
- throw new FileOperationError('read', fileInputName, error);
98
+ throw this._wrapReadError(fileInputName, error);
25
99
  }
26
100
  }
27
101
 
28
102
  /**
29
- * Read a file asynchronously with specified encoding
30
- * Uses fs.promises when available, falls back to callback-based API
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 fs.promises.readFile(fileInputName, encoding)
40
- .then(buf => buf.toString())
129
+ return this._readFileAsyncWithPromises(fileInputName, encoding)
41
130
  .catch(error => {
42
- throw new FileOperationError('read', fileInputName, error);
131
+ throw this._wrapReadError(fileInputName, error);
43
132
  });
44
133
  }
134
+
45
135
  return new Promise((resolve, reject) => {
46
- fs.readFile(fileInputName, encoding, (err, data) => {
47
- if (err) {
48
- reject(new FileOperationError('read', fileInputName, err));
136
+ const callback = (error, data) => {
137
+ if (error) {
138
+ reject(this._wrapReadError(fileInputName, error));
49
139
  return;
50
140
  }
51
- resolve(data.toString());
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
- * Logs confirmation message to console on success
59
- * @param {string} json - Content to write to file
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(json, fileOutputName) {
64
- fs.writeFile(fileOutputName, json, function (err) {
65
- if (err) {
66
- throw new FileOperationError('write', fileOutputName, err);
67
- } else {
68
- console.log('File saved: ' + fileOutputName);
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} json - Content to write to file
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(json, fileOutputName) {
200
+ writeFileAsync(content, fileOutputName) {
82
201
  if (fs.promises && typeof fs.promises.writeFile === 'function') {
83
- return fs.promises.writeFile(fileOutputName, json)
202
+ return this._writeFileAsyncWithPromises(fileOutputName, content)
84
203
  .catch(error => {
85
- throw new FileOperationError('write', fileOutputName, error);
204
+ throw this._wrapWriteError(fileOutputName, error);
86
205
  });
87
206
  }
207
+
88
208
  return new Promise((resolve, reject) => {
89
- fs.writeFile(fileOutputName, json, (err) => {
90
- if (err) return reject(new FileOperationError('write', fileOutputName, err));
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();
@@ -1,6 +1,6 @@
1
1
  'use strict';
2
2
 
3
- const { JsonValidationError } = require('./errors');
3
+ const { JsonValidationError } = require('../core/errors');
4
4
 
5
5
  /**
6
6
  * JSON validation utilities