Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
72 changes: 46 additions & 26 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -221,13 +221,49 @@ If the header is not on the first line you can define the header index like:
Empty rows are ignored and not parsed.

#### Format property value by type
If you want that a number will be printed as a Number type, and values *true* or *false* is printed as a boolean Type, use:
The `formatValueByType()` function intelligently converts string values to their appropriate types while preserving data integrity. To enable automatic type conversion:

```js
csvToJson.formatValueByType()
.getJsonFromCsv(fileInputName);
csvToJson.formatValueByType()
.getJsonFromCsv(fileInputName);
```

This conversion follows these rules:

##### Numbers
- Regular integers and decimals are converted to Number type
- Numbers with leading zeros are preserved as strings (e.g., "0012" stays "0012")
- Large integers outside JavaScript's safe range are preserved as strings
- Valid decimal numbers are converted to Number type

For example:
```json
{
"normalInteger": 42, // Converted to number
"decimal": 3.14, // Converted to number
"leadingZeros": "0012345", // Kept as string to preserve leading zeros
"largeNumber": "9007199254740992" // Kept as string to preserve precision
}
```

##### Boolean
Case-insensitive "true" or "false" strings are converted to boolean values:
```json
{
"registered": true, // From "true" or "TRUE" or "True"
"active": false // From "false" or "FALSE" or "False"
}
```

##### Complete Example
Input CSV:
```csv
first_name;last_name;email;gender;age;id;zip;registered
Constantin;Langsdon;[email protected];Male;96;00123;123;true
Norah;Raison;[email protected];Female;32;987;00456;FALSE
```
For example:

Output JSON:
```json
[
{
Expand All @@ -236,38 +272,22 @@ For example:
"email": "[email protected]",
"gender": "Male",
"age": 96,
"zip": 123,
"registered": true
"id": "00123", // Preserved leading zeros
"zip": 123, // Converted to number
"registered": true // Converted to boolean
},
{
"first_name": "Norah",
"last_name": "Raison",
"email": "[email protected]",
"gender": "Female",
"age": 32,
"zip": "",
"registered": false
"id": "987",
"zip": "00456", // Preserved leading zeros
"registered": false // Case-insensitive boolean conversion
}
]
```
##### Number
The property **age** is printed as
```json
"age": 32
```
instead of
```json
"age": "32"
```
##### Boolean
The property **registered** is printed as
```json
"registered": true
```
instead of
```json
"registered": "true"
```

#### Encoding
You can read and decode files with the following encoding:
Expand Down
111 changes: 90 additions & 21 deletions src/util/stringUtils.js
Original file line number Diff line number Diff line change
@@ -1,40 +1,109 @@
'use strict';

class StringUtils {
// Regular expressions as constants for better maintainability
static PATTERNS = {
INTEGER: /^-?\d+$/,
FLOAT: /^-?\d*\.\d+$/,
WHITESPACE: /\s/g
};

trimPropertyName(isTrimHeaderFieldWhiteSpace,value) {
if(isTrimHeaderFieldWhiteSpace) {
return value.replace(/\s/g, '');
static BOOLEAN_VALUES = {
TRUE: 'true',
FALSE: 'false'
};

/**
* Removes whitespace from property names based on configuration
* @param {boolean} shouldTrimAll - If true, removes all whitespace, otherwise only trims edges
* @param {string} propertyName - The property name to process
* @returns {string} The processed property name
*/
trimPropertyName(shouldTrimAll, propertyName) {
if (!propertyName) {
return '';
}
return value.trim();

return shouldTrimAll ?
propertyName.replace(StringUtils.PATTERNS.WHITESPACE, '') :
propertyName.trim();
}

/**
* Converts a string value to its appropriate type while preserving data integrity
* @param {string} value - The input value to convert
* @returns {string|number|boolean} The converted value
*/
getValueFormatByType(value) {
if(value === undefined || value === ''){
if (this.isEmpty(value)) {
return String();
}
//is Number
let isNumber = !isNaN(value);
if (isNumber) {
return Number(value);

if (this.isBoolean(value)) {
return this.convertToBoolean(value);
}

if (this.isInteger(value)) {
return this.convertInteger(value);
}
// is Boolean
if(value === "true" || value === "false"){
return JSON.parse(value.toLowerCase());

if (this.isFloat(value)) {
return this.convertFloat(value);
}

return String(value);
}

hasContent(values) {
if (values.length > 0) {
for (let i = 0; i < values.length; i++) {
if (values[i]) {
return true;
}
}
/**
* Checks if a value array contains any non-empty values
* @param {Array} values - Array to check for content
* @returns {boolean} True if array has any non-empty values
*/
hasContent(values = []) {
return Array.isArray(values) &&
values.some(value => Boolean(value));
}

// Private helper methods for type checking and conversion
isEmpty(value) {
return value === undefined || value === '';
}

isBoolean(value) {
const normalizedValue = value.toLowerCase();
return normalizedValue === StringUtils.BOOLEAN_VALUES.TRUE ||
normalizedValue === StringUtils.BOOLEAN_VALUES.FALSE;
}

isInteger(value) {
return StringUtils.PATTERNS.INTEGER.test(value);
}

isFloat(value) {
return StringUtils.PATTERNS.FLOAT.test(value);
}

hasLeadingZero(value) {
const isPositiveWithLeadingZero = value.length > 1 && value[0] === '0';
const isNegativeWithLeadingZero = value.length > 2 && value[0] === '-' && value[1] === '0';
return isPositiveWithLeadingZero || isNegativeWithLeadingZero;
}

convertToBoolean(value) {
return JSON.parse(value.toLowerCase());
}

convertInteger(value) {
if (this.hasLeadingZero(value)) {
return String(value);
}
return false;

const num = Number(value);
return Number.isSafeInteger(num) ? num : String(value);
}

convertFloat(value) {
const num = Number(value);
return Number.isFinite(num) ? num : String(value);
}
}

Expand Down
Loading