convert-csv-to-json 3.12.0 → 3.13.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/CHANGELOG.md +15 -0
- package/README.md +71 -26
- package/index.d.ts +8 -0
- package/index.js +12 -0
- package/package.json +1 -1
- package/src/csvToJson.js +7 -0
- package/src/util/stringUtils.js +90 -21
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to this project will be documented in this file.
|
|
4
|
+
|
|
5
|
+
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
|
6
|
+
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
|
+
|
|
8
|
+
## [Unreleased]
|
|
9
|
+
|
|
10
|
+
### Added
|
|
11
|
+
- New `csvStringToJsonStringified()` method that converts CSV content directly to a validated JSON string without requiring file I/O
|
|
12
|
+
- Improved test coverage for string-based CSV parsing
|
|
13
|
+
|
|
14
|
+
### Changed
|
|
15
|
+
- No breaking changes - all existing APIs remain unchanged
|
package/README.md
CHANGED
|
@@ -41,6 +41,7 @@ show your :heart: and support.
|
|
|
41
41
|
- [Number](#number)
|
|
42
42
|
- [Boolean](#boolean)
|
|
43
43
|
+ [Encoding](#encoding)
|
|
44
|
+
+ [Working with CSV strings directly](#working-with-csv-strings-directly)
|
|
44
45
|
* [Chaining Pattern](#chaining-pattern)
|
|
45
46
|
- [Development](#development)
|
|
46
47
|
- [CI CD github action](#ci-cd-github-action)
|
|
@@ -220,13 +221,49 @@ If the header is not on the first line you can define the header index like:
|
|
|
220
221
|
Empty rows are ignored and not parsed.
|
|
221
222
|
|
|
222
223
|
#### Format property value by type
|
|
223
|
-
|
|
224
|
+
The `formatValueByType()` function intelligently converts string values to their appropriate types while preserving data integrity. To enable automatic type conversion:
|
|
225
|
+
|
|
224
226
|
```js
|
|
225
|
-
|
|
226
|
-
|
|
227
|
+
csvToJson.formatValueByType()
|
|
228
|
+
.getJsonFromCsv(fileInputName);
|
|
227
229
|
```
|
|
228
|
-
For example:
|
|
229
230
|
|
|
231
|
+
This conversion follows these rules:
|
|
232
|
+
|
|
233
|
+
##### Numbers
|
|
234
|
+
- Regular integers and decimals are converted to Number type
|
|
235
|
+
- Numbers with leading zeros are preserved as strings (e.g., "0012" stays "0012")
|
|
236
|
+
- Large integers outside JavaScript's safe range are preserved as strings
|
|
237
|
+
- Valid decimal numbers are converted to Number type
|
|
238
|
+
|
|
239
|
+
For example:
|
|
240
|
+
```json
|
|
241
|
+
{
|
|
242
|
+
"normalInteger": 42, // Converted to number
|
|
243
|
+
"decimal": 3.14, // Converted to number
|
|
244
|
+
"leadingZeros": "0012345", // Kept as string to preserve leading zeros
|
|
245
|
+
"largeNumber": "9007199254740992" // Kept as string to preserve precision
|
|
246
|
+
}
|
|
247
|
+
```
|
|
248
|
+
|
|
249
|
+
##### Boolean
|
|
250
|
+
Case-insensitive "true" or "false" strings are converted to boolean values:
|
|
251
|
+
```json
|
|
252
|
+
{
|
|
253
|
+
"registered": true, // From "true" or "TRUE" or "True"
|
|
254
|
+
"active": false // From "false" or "FALSE" or "False"
|
|
255
|
+
}
|
|
256
|
+
```
|
|
257
|
+
|
|
258
|
+
##### Complete Example
|
|
259
|
+
Input CSV:
|
|
260
|
+
```csv
|
|
261
|
+
first_name;last_name;email;gender;age;id;zip;registered
|
|
262
|
+
Constantin;Langsdon;clangsdon0@hc360.com;Male;96;00123;123;true
|
|
263
|
+
Norah;Raison;nraison1@wired.com;Female;32;987;00456;FALSE
|
|
264
|
+
```
|
|
265
|
+
|
|
266
|
+
Output JSON:
|
|
230
267
|
```json
|
|
231
268
|
[
|
|
232
269
|
{
|
|
@@ -235,8 +272,9 @@ For example:
|
|
|
235
272
|
"email": "clangsdon0@hc360.com",
|
|
236
273
|
"gender": "Male",
|
|
237
274
|
"age": 96,
|
|
238
|
-
"
|
|
239
|
-
"
|
|
275
|
+
"id": "00123", // Preserved leading zeros
|
|
276
|
+
"zip": 123, // Converted to number
|
|
277
|
+
"registered": true // Converted to boolean
|
|
240
278
|
},
|
|
241
279
|
{
|
|
242
280
|
"first_name": "Norah",
|
|
@@ -244,29 +282,12 @@ For example:
|
|
|
244
282
|
"email": "nraison1@wired.com",
|
|
245
283
|
"gender": "Female",
|
|
246
284
|
"age": 32,
|
|
247
|
-
"
|
|
248
|
-
"
|
|
285
|
+
"id": "987",
|
|
286
|
+
"zip": "00456", // Preserved leading zeros
|
|
287
|
+
"registered": false // Case-insensitive boolean conversion
|
|
249
288
|
}
|
|
250
289
|
]
|
|
251
290
|
```
|
|
252
|
-
##### Number
|
|
253
|
-
The property **age** is printed as
|
|
254
|
-
```json
|
|
255
|
-
"age": 32
|
|
256
|
-
```
|
|
257
|
-
instead of
|
|
258
|
-
```json
|
|
259
|
-
"age": "32"
|
|
260
|
-
```
|
|
261
|
-
##### Boolean
|
|
262
|
-
The property **registered** is printed as
|
|
263
|
-
```json
|
|
264
|
-
"registered": true
|
|
265
|
-
```
|
|
266
|
-
instead of
|
|
267
|
-
```json
|
|
268
|
-
"registered": "true"
|
|
269
|
-
```
|
|
270
291
|
|
|
271
292
|
#### Encoding
|
|
272
293
|
You can read and decode files with the following encoding:
|
|
@@ -306,6 +327,30 @@ You can read and decode files with the following encoding:
|
|
|
306
327
|
.getJsonFromCsv(fileInputName);
|
|
307
328
|
```
|
|
308
329
|
|
|
330
|
+
#### Working with CSV strings directly
|
|
331
|
+
If you have CSV content as a string (for example, from an API response or test data), you can parse it directly without writing to a file:
|
|
332
|
+
|
|
333
|
+
```js
|
|
334
|
+
|
|
335
|
+
// Parse CSV string to array of objects
|
|
336
|
+
let csvString = 'firstName;lastName\nJohn;Doe\nJane;Smith';
|
|
337
|
+
let jsonArray = csvToJson.csvStringToJson(csvString);
|
|
338
|
+
// Output: [{"firstName":"John","lastName":"Doe"},{"firstName":"Jane","lastName":"Smith"}]
|
|
339
|
+
|
|
340
|
+
// Parse CSV string to JSON string (validated)
|
|
341
|
+
let jsonString = csvToJson.csvStringToJsonStringified(csvString);
|
|
342
|
+
// Output: "[\n {\n \"firstName\": \"John\",\n \"lastName\": \"Doe\"\n },\n {\n \"firstName\": \"Jane\",\n \"lastName\": \"Smith\"\n }\n]"
|
|
343
|
+
```
|
|
344
|
+
|
|
345
|
+
Both methods support all configuration options through the chaining pattern:
|
|
346
|
+
|
|
347
|
+
```js
|
|
348
|
+
let jsonArray = csvToJson
|
|
349
|
+
.fieldDelimiter(',')
|
|
350
|
+
.formatValueByType()
|
|
351
|
+
.csvStringToJson(csvString);
|
|
352
|
+
```
|
|
353
|
+
|
|
309
354
|
### Chaining Pattern
|
|
310
355
|
|
|
311
356
|
The exposed API is implemented with the [Method Chaining Pattern](https://en.wikipedia.org/wiki/Method_chaining), which means that multiple methods can be chained, e.g.:
|
package/index.d.ts
CHANGED
|
@@ -92,6 +92,14 @@ declare module 'convert-csv-to-json' {
|
|
|
92
92
|
getJsonFromCsv(inputFileName: string): any[];
|
|
93
93
|
|
|
94
94
|
csvStringToJson(csvString: string): any[];
|
|
95
|
+
|
|
96
|
+
/**
|
|
97
|
+
* Parses a csv string and returns a JSON string (validated)
|
|
98
|
+
* @param {csvString} csvString CSV content as string
|
|
99
|
+
* @return {string} JSON stringified result
|
|
100
|
+
*/
|
|
101
|
+
csvStringToJsonStringified(csvString: string): string;
|
|
102
|
+
|
|
95
103
|
/**
|
|
96
104
|
* Parses .csv file and put its content into a file in json format.
|
|
97
105
|
* @param {inputFileName} path/filename
|
package/index.js
CHANGED
|
@@ -156,6 +156,18 @@ exports.csvStringToJson = function(csvString) {
|
|
|
156
156
|
return csvToJson.csvStringToJson(csvString);
|
|
157
157
|
};
|
|
158
158
|
|
|
159
|
+
/**
|
|
160
|
+
* Parses a csv string and returns a JSON string (validated)
|
|
161
|
+
* @param {csvString} csvString CSV content as string
|
|
162
|
+
* @return {string} JSON stringified result
|
|
163
|
+
*/
|
|
164
|
+
exports.csvStringToJsonStringified = function(csvString) {
|
|
165
|
+
if (csvString === undefined || csvString === null) {
|
|
166
|
+
throw new Error("csvString is not defined!!!");
|
|
167
|
+
}
|
|
168
|
+
return csvToJson.csvStringToJsonStringified(csvString);
|
|
169
|
+
};
|
|
170
|
+
|
|
159
171
|
/**
|
|
160
172
|
* Parses .csv file and put its content into a file in json format.
|
|
161
173
|
* @param {inputFileName} path/filename
|
package/package.json
CHANGED
package/src/csvToJson.js
CHANGED
|
@@ -69,6 +69,13 @@ class CsvToJson {
|
|
|
69
69
|
return this.csvToJson(csvString);
|
|
70
70
|
}
|
|
71
71
|
|
|
72
|
+
csvStringToJsonStringified(csvString) {
|
|
73
|
+
let json = this.csvStringToJson(csvString);
|
|
74
|
+
let jsonStringified = JSON.stringify(json, undefined, 1);
|
|
75
|
+
jsonUtils.validateJson(jsonStringified);
|
|
76
|
+
return jsonStringified;
|
|
77
|
+
}
|
|
78
|
+
|
|
72
79
|
csvToJson(parsedCsv) {
|
|
73
80
|
this.validateInputConfig();
|
|
74
81
|
let lines = parsedCsv.split(newLine);
|
package/src/util/stringUtils.js
CHANGED
|
@@ -1,40 +1,109 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
3
|
class StringUtils {
|
|
4
|
+
// Regular expressions as constants for better maintainability
|
|
5
|
+
static PATTERNS = {
|
|
6
|
+
INTEGER: /^-?\d+$/,
|
|
7
|
+
FLOAT: /^-?\d*\.\d+$/,
|
|
8
|
+
WHITESPACE: /\s/g
|
|
9
|
+
};
|
|
4
10
|
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
11
|
+
static BOOLEAN_VALUES = {
|
|
12
|
+
TRUE: 'true',
|
|
13
|
+
FALSE: 'false'
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Removes whitespace from property names based on configuration
|
|
18
|
+
* @param {boolean} shouldTrimAll - If true, removes all whitespace, otherwise only trims edges
|
|
19
|
+
* @param {string} propertyName - The property name to process
|
|
20
|
+
* @returns {string} The processed property name
|
|
21
|
+
*/
|
|
22
|
+
trimPropertyName(shouldTrimAll, propertyName) {
|
|
23
|
+
if (!propertyName) {
|
|
24
|
+
return '';
|
|
8
25
|
}
|
|
9
|
-
return
|
|
10
|
-
|
|
26
|
+
return shouldTrimAll ?
|
|
27
|
+
propertyName.replace(StringUtils.PATTERNS.WHITESPACE, '') :
|
|
28
|
+
propertyName.trim();
|
|
11
29
|
}
|
|
12
30
|
|
|
31
|
+
/**
|
|
32
|
+
* Converts a string value to its appropriate type while preserving data integrity
|
|
33
|
+
* @param {string} value - The input value to convert
|
|
34
|
+
* @returns {string|number|boolean} The converted value
|
|
35
|
+
*/
|
|
13
36
|
getValueFormatByType(value) {
|
|
14
|
-
if(value
|
|
37
|
+
if (this.isEmpty(value)) {
|
|
15
38
|
return String();
|
|
16
39
|
}
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
40
|
+
|
|
41
|
+
if (this.isBoolean(value)) {
|
|
42
|
+
return this.convertToBoolean(value);
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
if (this.isInteger(value)) {
|
|
46
|
+
return this.convertInteger(value);
|
|
21
47
|
}
|
|
22
|
-
|
|
23
|
-
if(value
|
|
24
|
-
return
|
|
48
|
+
|
|
49
|
+
if (this.isFloat(value)) {
|
|
50
|
+
return this.convertFloat(value);
|
|
25
51
|
}
|
|
52
|
+
|
|
26
53
|
return String(value);
|
|
27
54
|
}
|
|
28
55
|
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
56
|
+
/**
|
|
57
|
+
* Checks if a value array contains any non-empty values
|
|
58
|
+
* @param {Array} values - Array to check for content
|
|
59
|
+
* @returns {boolean} True if array has any non-empty values
|
|
60
|
+
*/
|
|
61
|
+
hasContent(values = []) {
|
|
62
|
+
return Array.isArray(values) &&
|
|
63
|
+
values.some(value => Boolean(value));
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
// Private helper methods for type checking and conversion
|
|
67
|
+
isEmpty(value) {
|
|
68
|
+
return value === undefined || value === '';
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
isBoolean(value) {
|
|
72
|
+
const normalizedValue = value.toLowerCase();
|
|
73
|
+
return normalizedValue === StringUtils.BOOLEAN_VALUES.TRUE ||
|
|
74
|
+
normalizedValue === StringUtils.BOOLEAN_VALUES.FALSE;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
isInteger(value) {
|
|
78
|
+
return StringUtils.PATTERNS.INTEGER.test(value);
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
isFloat(value) {
|
|
82
|
+
return StringUtils.PATTERNS.FLOAT.test(value);
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
hasLeadingZero(value) {
|
|
86
|
+
const isPositiveWithLeadingZero = value.length > 1 && value[0] === '0';
|
|
87
|
+
const isNegativeWithLeadingZero = value.length > 2 && value[0] === '-' && value[1] === '0';
|
|
88
|
+
return isPositiveWithLeadingZero || isNegativeWithLeadingZero;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
convertToBoolean(value) {
|
|
92
|
+
return JSON.parse(value.toLowerCase());
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
convertInteger(value) {
|
|
96
|
+
if (this.hasLeadingZero(value)) {
|
|
97
|
+
return String(value);
|
|
36
98
|
}
|
|
37
|
-
|
|
99
|
+
|
|
100
|
+
const num = Number(value);
|
|
101
|
+
return Number.isSafeInteger(num) ? num : String(value);
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
convertFloat(value) {
|
|
105
|
+
const num = Number(value);
|
|
106
|
+
return Number.isFinite(num) ? num : String(value);
|
|
38
107
|
}
|
|
39
108
|
}
|
|
40
109
|
|