Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

jsonexport

Package Overview
Dependencies
Maintainers
1
Versions
43
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

jsonexport - npm Package Compare versions

Comparing version 1.4.2 to 1.5.0

lib/escape-delimiters.js

297

lib/index.js

@@ -0,1 +1,2 @@

/* jshint node:true */
'use strict';

@@ -8,2 +9,6 @@ /**

var joinRows = require('./join-rows');
var generateHeaders;
var escapeDelimiters;
var options;

@@ -28,2 +33,11 @@

options = parseOptions(userOptions);
escapeDelimiters = require('./escape-delimiters')(
options.textDelimiter,
options.rowDelimiter,
options.endOfLine
);
generateHeaders = require('./generate-headers')(escapeDelimiters);
generateCsv(json, callback);

@@ -46,3 +60,3 @@ };

undefinedString: '', // String
endOfLine: null, // String
endOfLine: os.EOL || '\n', // String
mainPathItem: null, // String

@@ -55,6 +69,6 @@ booleanTrueString: null, // String

//Handlers
handleString: null, // Function
handleNumber: null, // Function
handleBoolean: null, // Function
handleDate: null, // Function
handleString: handleString, // Function
handleNumber: handleNumber, // Function
handleBoolean: handleBoolean, // Function
handleDate: handleDate, // Function
//handleArray: null, // Function

@@ -75,135 +89,108 @@ //handleObject: null // Function

function generateCsv(json, callback) {
//Check if the passed json is an Array
if(_.isArray(json)){
var parseResult = [];
json.forEach(function (item) {
//Call checkType to list all items inside this object
//Items are returned as a object {item: 'Prop Value, Item Name',
// value: 'Prop Data Value'}
var itemResult = checkType(item, options.mainPathItem);
parseResult.push(itemResult);
});
return callback(null, generateFromArray(json));
}
else if(_.isObject(json)){
return callback(null, generateFromObject(json));
}
//Generate the csv headers based on prop usage over the elements
var headers = generateHeaders(parseResult);
//Generate the csv output
var fileRows = [];
if(options.includeHeaders){
//Add the headers to the first line
fileRows.push(headers.join(options.rowDelimiter));
}
return callback(new Error('Unable to parse the JSON object, its not an Array or Object.'));
}
parseResult.forEach(function (result) {
//Initialize the array with empty strings to handle 'unpopular' headers
var resultRows = [Array(headers.length).join(".").split(".")];
function generateFromArray(json) {
var fileRows = [];
var parseResult = [];
var outputFile;
var fillRows;
json.forEach(function (item) {
//Call checkType to list all items inside this object
//Items are returned as a object {item: 'Prop Value, Item Name',
// value: 'Prop Data Value'}
var itemResult = checkType(item, options.mainPathItem);
parseResult.push(itemResult);
});
result.forEach(function(element){
var placed = false;
resultRows.forEach(function (row) {
if(!placed && row[headers.indexOf(element.item)] == ''){
row[headers.indexOf(element.item)] = element.value;
placed = true;
}
});
//Generate the csv headers based on prop usage over the elements
var headers = generateHeaders(parseResult, options.orderHeaders);
//Generate the csv output
if(!placed){
var newRow = Array(headers.length).join(".").split(".");
newRow[headers.indexOf(element.item)] = element.value;
resultRows.push(newRow);
}
});
resultRows.forEach(function (row) {
fileRows.push(row.join(options.rowDelimiter));
});
});
//Merge all rows in a single output with the correct End of Line string
var outputFile = fileRows.join(options.endOfLine || os.EOL || '\n');
return callback(null, outputFile);
}
//Check if the passed json is an Object
else if(_.isObject(json)){
var fileRows = [];
var horizontalRows = [[],[]];
var textDelimiterRegex = new RegExp("\\" + options.textDelimiter, 'g');
var endOfLine = options.endOfLine || os.EOL || '\n';
for(var prop in json){
var prefix = "";
if(options.mainPathItem)
prefix = options.mainPathItem + options.headerPathString;
var parseResult = checkType(json[prop], prefix + prop);
parseResult.forEach(function (result) {
if(options.includeHeaders){
//Add the headers to the first line
fileRows.push(headers.join(options.rowDelimiter));
}
var value = result.value ? result.value.toString() : options.undefinedString;
// Escape the textDelimiters contained in the field
/*(https://tools.ietf.org/html/rfc4180)
7. If double-quotes are used to enclose fields, then a double-quote
appearing inside a field must be escaped by preceding it with
another double quote.
For example: "aaa","b""bb","ccc"
*/
value = value.replace(textDelimiterRegex, options.textDelimiter+options.textDelimiter);
// Escape the whole field if it contains a rowDelimiter or a linebreak
if (value.indexOf(options.rowDelimiter) >= 0 || value.indexOf(endOfLine) >= 0) {
value = options.textDelimiter + value + options.textDelimiter;
}
//Type header;value
if(options.verticalOutput){
var row = [result.item, value];
fileRows.push(row.join(options.rowDelimiter));
}else{
horizontalRows[0].push(result.item);
horizontalRows[1].push(value);
}
});
}
if(!options.verticalOutput){
fileRows.push(horizontalRows[0].join(options.rowDelimiter));
fileRows.push(horizontalRows[1].join(options.rowDelimiter));
}
//Merge all rows in a single output with the correct End of Line string
var outputFile = fileRows.join(options.endOfLine || os.EOL || '\n');
return callback(null, outputFile);
}
fillRows = function (result) {
//Initialize the array with empty strings to handle 'unpopular' headers
var resultRows = [Array(headers.length).join(".").split(".")];
return callback(new Error('Unable to parse the JSON object, its not an Array or Object.'));
result.forEach(function(element){
var placed = false;
resultRows.forEach(function (row) {
if(!placed && row[headers.indexOf(element.item)] === ''){
row[headers.indexOf(element.item)] = escapeDelimiters(element.value);
placed = true;
}
});
if(!placed){
var newRow = Array(headers.length).join(".").split(".");
newRow[headers.indexOf(element.item)] = escapeDelimiters(element.value);
resultRows.push(newRow);
}
});
resultRows.forEach(function (row) {
fileRows.push(row.join(options.rowDelimiter));
});
};
parseResult.forEach(fillRows);
return joinRows(fileRows, options.endOfLine);
}
/**
* Generate the file headers with optional sorting by header usage
*
* @param {Array} parseResult
* @returns {Array} headers
*/
function generateHeaders(parseResult){
var headers = [];
var headerCount = [];
//Check all the parsed json results
parseResult.forEach(function (result) {
result.forEach(function (element) {
if(headerCount[element.item])
headerCount[element.item] += 1;
else
headerCount[element.item] = 1;
})
});
var headerSort = [];
//Create a sortable collection of headers
for(var header in headerCount){
if(headerCount.hasOwnProperty(header)){
headerSort.push({
name: header,
count: headerCount[header]
});
}
}
if(options.orderHeaders){
//Sort the headers based on the count.
headerSort = _.sortBy(headerSort,'count').reverse();
}
//Create the headers list
headerSort.forEach(function (header) {
headers.push(header.name);
});
return headers;
function generateFromObject(json) {
var fileRows = [];
var parseResult = [];
var outputFile;
var fillRows;
var horizontalRows = [[],[]];
fillRows = function (result) {
var value = result.value ? result.value.toString() : options.undefinedString;
value = escapeDelimiters(value);
//Type header;value
if(options.verticalOutput){
var row = [result.item, value];
fileRows.push(row.join(options.rowDelimiter));
}else{
horizontalRows[0].push(result.item);
horizontalRows[1].push(value);
}
};
for(var prop in json){
var prefix = "";
if(options.mainPathItem)
prefix = options.mainPathItem + options.headerPathString;
parseResult = checkType(json[prop], prefix + prop);
parseResult.forEach(fillRows);
}
if(!options.verticalOutput){
fileRows.push(horizontalRows[0].join(options.rowDelimiter));
fileRows.push(horizontalRows[1].join(options.rowDelimiter));
}
return joinRows(fileRows, options.endOfLine);
}
function headers(result, item) {
if (!item) return result;
return result.map(function (element) {
element.item = element.item ? item + options.headerPathString + element.item : item;
return element;
});
}
/**

@@ -216,34 +203,30 @@ * Check the element type of the element call the correct handle function

function checkType(element, item){
var result = [];
var result;
//Check if element is a String
if(_.isString(element)){
var resultString = options.handleString ? options.handleString(element, item) : handleString(element, item);
result.push({
result = [{
item: item,
value: resultString
});
value: options.handleString(element, item),
}];
}
//Check if element is a Number
else if(_.isNumber(element)){
var resultNumber = options.handleNumber ? options.handleNumber(element, item) : handleNumber(element, item);
result.push({
result = [{
item: item,
value: resultNumber
});
value: options.handleNumber(element, item),
}];
}
//Check if element is a Boolean
else if(_.isBoolean(element)){
var resultBoolean = options.handleBoolean ? options.handleBoolean(element, item) : handleBoolean(element, item);
result.push({
result = [{
item: item,
value: resultBoolean
});
value: options.handleBoolean(element, item),
}];
}
//Check if element is a Date
else if(_.isDate(element)){
var resultDate = options.handleDate ? options.handleDate(element, item) : handleDate(element, item);
result.push({
result = [{
item: item,
value: resultDate
});
value: options.handleDate(element, item),
}];
}

@@ -253,11 +236,3 @@ //Check if element is an Array

var resultArray = handleArray(element, item);
resultArray.forEach(function (resultArrayElement) {
if(resultArrayElement.item != null && item){
resultArrayElement.item = item + options.headerPathString + resultArrayElement.item;
}
if(!resultArrayElement.item && item){
resultArrayElement.item = item;
}
result.push(resultArrayElement);
});
result = headers(resultArray, item);
}

@@ -267,11 +242,3 @@ //Check if element is a Object

var resultObject = handleObject(element, item);
resultObject.forEach(function (resultObjectElement) {
if(resultObjectElement.item != null && item) {
resultObjectElement.item = item + options.headerPathString + resultObjectElement.item;
}
if(!resultObjectElement.item && item){
resultObjectElement.item = item;
}
result.push(resultObjectElement);
});
result = headers(resultObject, item);
}

@@ -317,3 +284,3 @@ return result;

//Check if there is a firstElement and if the current element dont have a item
if(resultElement.item == null && firstElementWithoutItem != null){
if(!resultElement.item && firstElementWithoutItem !== undefined){
//Append the value to the firstElementWithoutItem.

@@ -325,3 +292,3 @@ result[firstElementWithoutItem].value += options.arrayPathString + resultElement.value;

//Set the firstElement if its not set
if(firstElementWithoutItem == null && resultElement.item == null)
if(!firstElementWithoutItem && !resultElement.item)
firstElementWithoutItem = resultIndex;

@@ -328,0 +295,0 @@ //Keep the item in the array

{
"name": "jsonexport",
"version": "1.4.2",
"version": "1.5.0",
"description": "Makes easy to convert JSON to CSV",
"main": "./lib",
"scripts": {
"test": "mocha tests/*.js tests/**/*.js"
"test": "mocha tests/*.js tests/**/*.js",
"lint": "./node_modules/.bin/jshint ./lib/index.js"
},

@@ -41,4 +42,5 @@ "bin": {

"chai": "^3.5.0",
"jshint": "^2.9.4",
"mocha": "^3.1.0"
}
}

@@ -19,2 +19,4 @@ # jsonexport

----------------------
- v1.5.0 - escaping content in headers / arrays (papswell)
- v1.4.2 - default date handler return date.toLocaleString (jclay)
- v1.3.2 - fix userOptions optional

@@ -76,7 +78,7 @@ - v1.3.1 - object & array test

```
name;lastname
Bob;Smith
James;David
Robert;Miller
David;Martin
name,lastname
Bob,Smith
James,David
Robert,Miller
David,Martin
```

@@ -125,7 +127,7 @@

```
lastname;name;family.type;family.name;nickname;location
Smith;Bob;Father;Peter;;
David;James;Mother;Julie;;
Miller;Robert;;;;1231,3214,4214
Martin;David;;;dmartin;
lastname,name,family.type,family.name,nickname,location
Smith,Bob,Father,Peter,,
David,James,Mother,Julie,,
Miller,Robert,,,,1231,3214,4214
Martin,David,,,dmartin,
```

@@ -157,5 +159,5 @@

```
cars;12
roads;5
traffic;slow
cars,12
roads,5
traffic,slow
```

@@ -191,9 +193,9 @@

```
cars;12
roads;5
traffic;slow
speed.max;123
speed.avg;20
speed.min;5
size;10,20
cars,12
roads,5
traffic,slow
speed.max,123
speed.avg,20
speed.min,5
size,10;20
```

@@ -249,4 +251,4 @@

```
lang;Hey - Node.js
module;Hey - jsonexport
lang,Hey - Node.js
module,Hey - jsonexport
```

@@ -0,1 +1,5 @@

/* jshint node:true */
/* jshint esversion: 6 */
/* jshint -W030 */
var chai = require('chai');

@@ -12,5 +16,6 @@ var expect = chai.expect;

name: 'James',
lastname: 'David'
lastname: 'David',
escaped: 'I am a "quoted" field'
}], {}, (err, csv) => {
expect(csv).to.equal('name,lastname\nBob,Smith\nJames,David');
expect(csv).to.equal('name,lastname,escaped\nBob,Smith,\nJames,David,I am a ""quoted"" field');
});

@@ -17,0 +22,0 @@ });

@@ -0,1 +1,5 @@

/* jshint node:true */
/* jshint esversion: 6 */
/* jshint -W030 */
var chai = require('chai');

@@ -24,7 +28,8 @@ var expect = chai.expect;

},
size: [10,20]
size: [10,20],
escaped: 'I am a "quoted" field'
}, {}, (err, csv) => {
expect(csv).to.equal('cars,12\nroads,5\ntraffic,slow\nspeed.max,123\nspeed.avg,20\nspeed.min,5\nsize,10;20');
expect(csv).to.equal('cars,12\nroads,5\ntraffic,slow\nspeed.max,123\nspeed.avg,20\nspeed.min,5\nsize,10;20\nescaped,I am a ""quoted"" field');
});
});
});
SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc