jsonexport
Advanced tools
Comparing version 2.5.2 to 3.0.0
## Change log | ||
---------------------- | ||
- v3.0.0 - Promise API & fillTopRow | ||
- v2.5.2 - fix stream memory limit (issue #64) | ||
- v2.5.1 - security fixes (npm audit) | ||
- v2.5.0 - Fixed nester array issue | ||
- v2.5.0 - fix nested array issue | ||
- v2.3.0 - added mapHeaders option | ||
@@ -7,0 +8,0 @@ - ran npm audit fix |
@@ -8,5 +8,8 @@ /* jshint node:true */ | ||
var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; | ||
var Parser = require('./parser/csv'); | ||
var Stream = require('./core/stream'); | ||
var helper = require('./core/helper'); | ||
var EOL = require('./core/eol'); | ||
@@ -22,11 +25,78 @@ /** | ||
*/ | ||
module.exports = function (json, userOptions, callback) { | ||
if (helper.isFunction(userOptions)) { | ||
callback = userOptions; | ||
userOptions = {}; | ||
module.exports = function () { | ||
var DEFAULT_OPTIONS = { | ||
headers: [], // Array | ||
rename: [], // Array | ||
headerPathString: '.', // String | ||
rowDelimiter: ',', // String | ||
textDelimiter: '"', // String | ||
arrayPathString: ';', // String | ||
undefinedString: '', // String | ||
endOfLine: EOL || '\n', // String | ||
mainPathItem: null, // String | ||
booleanTrueString: null, // String | ||
booleanFalseString: null, // String | ||
includeHeaders: true, // Boolean | ||
fillGaps: false, // Boolean | ||
verticalOutput: true, // Boolean | ||
forceTextDelimiter: false //Boolean | ||
}; | ||
// argument parsing | ||
var json = void 0, | ||
userOptions = void 0, | ||
callback = void 0; | ||
if (arguments.length === 3) { | ||
var _arguments = Array.prototype.slice.call(arguments); | ||
json = _arguments[0]; | ||
userOptions = _arguments[1]; | ||
callback = _arguments[2]; | ||
} else if (arguments.length === 2) { | ||
var any = void 0; | ||
var _arguments2 = Array.prototype.slice.call(arguments); | ||
json = _arguments2[0]; | ||
any = _arguments2[1]; | ||
if (typeof any === 'function') { | ||
callback = any; | ||
} else if ((typeof any === 'undefined' ? 'undefined' : _typeof(any)) === 'object') { | ||
userOptions = any; | ||
} | ||
} else if (arguments.length === 1) { | ||
var _arguments3 = Array.prototype.slice.call(arguments), | ||
_any = _arguments3[0]; | ||
if ((typeof _any === 'undefined' ? 'undefined' : _typeof(_any)) === 'object') { | ||
var defaultKeys = Object.keys(DEFAULT_OPTIONS); | ||
var objectKeys = Object.keys(_any); | ||
var isOptions = objectKeys.every(function (key) { | ||
return defaultKeys.includes(key); | ||
}); | ||
if (objectKeys.length > 0 && isOptions) { | ||
userOptions = _any; | ||
} else { | ||
json = _any; | ||
} | ||
} else { | ||
json = _any; | ||
} | ||
} else { | ||
return new Stream(new Parser(DEFAULT_OPTIONS)); | ||
} | ||
userOptions = !callback ? json : userOptions; | ||
var parser = new Parser(userOptions); | ||
if (!callback || !helper.isFunction(callback)) return new Stream(parser); | ||
parser.parse(json, callback); | ||
var options = Object.assign({}, DEFAULT_OPTIONS, userOptions); | ||
var parser = new Parser(options); | ||
// if no json is provided Stream API will be used | ||
if (!json) { | ||
return new Stream(parser); | ||
} | ||
// always return an promise | ||
return new Promise(function (resolve, reject) { | ||
parser.parse(json, function (err, result) { | ||
if (callback) return callback(err, result); | ||
if (err) return reject(err); | ||
if (reject) return resolve(result); | ||
}); | ||
}); | ||
}; |
@@ -12,3 +12,2 @@ /* jshint node:true */ | ||
var EOL = require('../core/eol'); | ||
var joinRows = require('../core/join-rows'); | ||
@@ -22,3 +21,3 @@ var Handler = require('./handler'); | ||
this._options = this._parseOptions(options) || {}; | ||
this._options = options || {}; | ||
this._handler = new Handler(this._options); | ||
@@ -132,3 +131,3 @@ this._headers = this._options.headers || []; | ||
// make sure there isnt a empty row for this header | ||
if (emptyRowIndexByHeader[elementHeaderIndex] < rows.length) { | ||
if (self._options.fillTopRow && emptyRowIndexByHeader[elementHeaderIndex] < rows.length) { | ||
rows[emptyRowIndexByHeader[elementHeaderIndex]][elementHeaderIndex] = self._escape(element.value); | ||
@@ -233,37 +232,3 @@ emptyRowIndexByHeader[elementHeaderIndex] += 1; | ||
} | ||
/** | ||
* Replaces the default options with the custom user options | ||
* | ||
* @param {Options} userOptions | ||
*/ | ||
}, { | ||
key: '_parseOptions', | ||
value: function _parseOptions(userOptions) { | ||
var defaultOptions = { | ||
headers: [], // Array | ||
rename: [], // Array | ||
headerPathString: '.', // String | ||
rowDelimiter: ',', // String | ||
textDelimiter: '"', // String | ||
arrayPathString: ';', // String | ||
undefinedString: '', // String | ||
endOfLine: EOL || '\n', // String | ||
mainPathItem: null, // String | ||
booleanTrueString: null, // String | ||
booleanFalseString: null, // String | ||
includeHeaders: true, // Boolean | ||
fillGaps: false, // Boolean | ||
verticalOutput: true, // Boolean | ||
forceTextDelimiter: false, //Boolean | ||
//Handlers | ||
handleString: undefined, // Function | ||
handleNumber: undefined, // Function | ||
handleBoolean: undefined, // Function | ||
handleDate: undefined // Function | ||
}; | ||
return Object.assign({}, defaultOptions, userOptions); | ||
} | ||
}, { | ||
key: 'headers', | ||
@@ -270,0 +235,0 @@ get: function get() { |
@@ -18,10 +18,4 @@ /* jshint node:true */ | ||
//an object of {typeName:(value,index,parent)=>any} | ||
// an object of {typeName:(value,index,parent)=>any} | ||
this._options.typeHandlers = this._options.typeHandlers || {}; | ||
//deprecated options | ||
this._options.handleString = this._options.handleString ? warnDepOp('handleString', this._options.handleString) : this._handleString; | ||
this._options.handleNumber = this._options.handleNumber ? warnDepOp('handleNumber', this._options.handleNumber) : this._handleNumber; | ||
this._options.handleBoolean = this._options.handleBoolean ? warnDepOp('handleBoolean', this._options.handleBoolean) : this._handleBoolean; | ||
this._options.handleDate = this._options.handleDate ? warnDepOp('handleDate', this._options.handleDate) : this._handleDate; | ||
} | ||
@@ -99,4 +93,3 @@ | ||
element = this.castValue(element, item, index, parent); | ||
//try simple value by highier performance switch | ||
// try simple value by highier performance switch | ||
switch (typeof element === 'undefined' ? 'undefined' : _typeof(element)) { | ||
@@ -106,3 +99,3 @@ case 'string': | ||
item: item, | ||
value: this._options.handleString(element, item) | ||
value: this._handleString(element, item) | ||
}]; | ||
@@ -113,3 +106,3 @@ | ||
item: item, | ||
value: this._options.handleNumber(element, item) | ||
value: this._handleNumber(element, item) | ||
}]; | ||
@@ -120,3 +113,3 @@ | ||
item: item, | ||
value: this._options.handleBoolean.bind(this)(element, item) | ||
value: this._handleBoolean.bind(this)(element, item) | ||
}]; | ||
@@ -243,7 +236,2 @@ } | ||
function warnDepOp(optionName, backOut) { | ||
console.warn("[jsonexport]: option " + optionName + " has been deprecated. Use option.typeHandlers"); | ||
return backOut; | ||
} | ||
var globalScope = typeof window === "undefined" ? global : window; | ||
@@ -250,0 +238,0 @@ function isInstanceOfTypeName(element, typeName) { |
@@ -10,2 +10,3 @@ /* jshint node:true */ | ||
const helper = require('./core/helper'); | ||
const EOL = require('./core/eol'); | ||
@@ -21,11 +22,63 @@ /** | ||
*/ | ||
module.exports = function(json, userOptions, callback) { | ||
if (helper.isFunction(userOptions)) { | ||
callback = userOptions; | ||
userOptions = {}; | ||
module.exports = function() { | ||
const DEFAULT_OPTIONS = { | ||
headers: [], // Array | ||
rename: [], // Array | ||
headerPathString: '.', // String | ||
rowDelimiter: ',', // String | ||
textDelimiter: '"', // String | ||
arrayPathString: ';', // String | ||
undefinedString: '', // String | ||
endOfLine: EOL || '\n', // String | ||
mainPathItem: null, // String | ||
booleanTrueString: null, // String | ||
booleanFalseString: null, // String | ||
includeHeaders: true, // Boolean | ||
fillGaps: false, // Boolean | ||
verticalOutput: true, // Boolean | ||
forceTextDelimiter: false, //Boolean | ||
}; | ||
// argument parsing | ||
let json, userOptions, callback; | ||
if (arguments.length === 3) { | ||
[json, userOptions, callback] = arguments; | ||
} else if (arguments.length === 2) { | ||
let any; | ||
[json, any] = arguments; | ||
if (typeof any === 'function') { | ||
callback = any; | ||
} else if (typeof any === 'object') { | ||
userOptions = any; | ||
} | ||
} else if (arguments.length === 1) { | ||
const [any] = arguments; | ||
if (typeof any === 'object') { | ||
const defaultKeys = Object.keys(DEFAULT_OPTIONS); | ||
const objectKeys = Object.keys(any); | ||
const isOptions = objectKeys.every((key) => defaultKeys.includes(key)); | ||
if (objectKeys.length > 0 && isOptions) { | ||
userOptions = any; | ||
} else { | ||
json = any; | ||
} | ||
} else { | ||
json = any; | ||
} | ||
} else { | ||
return new Stream(new Parser(DEFAULT_OPTIONS)); | ||
} | ||
userOptions = !callback ? json : userOptions; | ||
let parser = new Parser(userOptions); | ||
if (!callback || !helper.isFunction(callback)) return new Stream(parser); | ||
parser.parse(json, callback); | ||
const options = Object.assign({}, DEFAULT_OPTIONS, userOptions); | ||
const parser = new Parser(options); | ||
// if no json is provided Stream API will be used | ||
if (!json) { | ||
return new Stream(parser); | ||
} | ||
// always return an promise | ||
return new Promise((resolve, reject) => { | ||
parser.parse(json, (err, result) => { | ||
if (callback) return callback(err, result); | ||
if (err) return reject(err); | ||
if (reject) return resolve(result); | ||
}); | ||
}); | ||
}; |
@@ -7,3 +7,2 @@ /* jshint node:true */ | ||
*/ | ||
const EOL = require('../core/eol') | ||
const joinRows = require('../core/join-rows'); | ||
@@ -15,3 +14,3 @@ const Handler = require('./handler'); | ||
constructor(options) { | ||
this._options = this._parseOptions(options) || {}; | ||
this._options = options || {}; | ||
this._handler = new Handler(this._options); | ||
@@ -105,3 +104,3 @@ this._headers = this._options.headers || []; | ||
// make sure there isnt a empty row for this header | ||
if (emptyRowIndexByHeader[elementHeaderIndex] < rows.length) { | ||
if (self._options.fillTopRow && emptyRowIndexByHeader[elementHeaderIndex] < rows.length) { | ||
rows[emptyRowIndexByHeader[elementHeaderIndex]][elementHeaderIndex] = self._escape(element.value); | ||
@@ -173,35 +172,4 @@ emptyRowIndexByHeader[elementHeaderIndex] += 1; | ||
} | ||
/** | ||
* Replaces the default options with the custom user options | ||
* | ||
* @param {Options} userOptions | ||
*/ | ||
_parseOptions(userOptions) { | ||
let defaultOptions = { | ||
headers: [], // Array | ||
rename: [], // Array | ||
headerPathString: '.', // String | ||
rowDelimiter: ',', // String | ||
textDelimiter: '"', // String | ||
arrayPathString: ';', // String | ||
undefinedString: '', // String | ||
endOfLine: EOL || '\n', // String | ||
mainPathItem: null, // String | ||
booleanTrueString: null, // String | ||
booleanFalseString: null, // String | ||
includeHeaders: true, // Boolean | ||
fillGaps: false, // Boolean | ||
verticalOutput: true, // Boolean | ||
forceTextDelimiter: false, //Boolean | ||
//Handlers | ||
handleString: undefined, // Function | ||
handleNumber: undefined, // Function | ||
handleBoolean: undefined, // Function | ||
handleDate: undefined, // Function | ||
}; | ||
return Object.assign({}, defaultOptions, userOptions); | ||
} | ||
} | ||
module.exports = Parser; | ||
module.exports = Parser; |
@@ -10,10 +10,4 @@ /* jshint node:true */ | ||
//an object of {typeName:(value,index,parent)=>any} | ||
// an object of {typeName:(value,index,parent)=>any} | ||
this._options.typeHandlers = this._options.typeHandlers || {}; | ||
//deprecated options | ||
this._options.handleString = this._options.handleString ? warnDepOp('handleString', this._options.handleString) : this._handleString; | ||
this._options.handleNumber = this._options.handleNumber ? warnDepOp('handleNumber', this._options.handleNumber) : this._handleNumber; | ||
this._options.handleBoolean = this._options.handleBoolean ? warnDepOp('handleBoolean', this._options.handleBoolean) : this._handleBoolean; | ||
this._options.handleDate = this._options.handleDate ? warnDepOp('handleDate', this._options.handleDate) : this._handleDate; | ||
} | ||
@@ -82,4 +76,3 @@ | ||
element = this.castValue(element, item, index, parent); | ||
//try simple value by highier performance switch | ||
// try simple value by highier performance switch | ||
switch(typeof element){ | ||
@@ -89,3 +82,3 @@ case 'string': | ||
item: item, | ||
value: this._options.handleString(element, item), | ||
value: this._handleString(element, item), | ||
}]; | ||
@@ -96,3 +89,3 @@ | ||
item: item, | ||
value: this._options.handleNumber(element, item), | ||
value: this._handleNumber(element, item), | ||
}]; | ||
@@ -103,3 +96,3 @@ | ||
item: item, | ||
value: this._options.handleBoolean.bind(this)(element, item), | ||
value: this._handleBoolean.bind(this)(element, item), | ||
}]; | ||
@@ -207,7 +200,2 @@ } | ||
function warnDepOp(optionName, backOut){ | ||
console.warn("[jsonexport]: option "+optionName+" has been deprecated. Use option.typeHandlers"); | ||
return backOut; | ||
} | ||
const globalScope = typeof(window)==="undefined" ? global : window; | ||
@@ -227,2 +215,2 @@ function isInstanceOfTypeName(element, typeName){ | ||
return false; | ||
} | ||
} |
{ | ||
"name": "jsonexport", | ||
"version": "2.5.2", | ||
"version": "3.0.0", | ||
"description": "Makes easy to convert JSON to CSV", | ||
@@ -5,0 +5,0 @@ "main": "./lib", |
@@ -11,2 +11,3 @@ # jsonexport {} → 📄 | ||
[![Try jsonexport on RunKit](https://badge.runkitcdn.com/jsonexport.svg)](https://npm.runkit.com/jsonexport) | ||
![npm bundle size](https://img.shields.io/bundlephobia/minzip/jsonexport) | ||
@@ -17,3 +18,3 @@ ✔ **easy to use** 👌 (should work as expected without much customization)️ | ||
✔️ **tiny** 🐜 (0 dependencies) | ||
✔️ **tiny** 🐜 (0 dependencies) | ||
@@ -24,5 +25,5 @@ ✔ **scalable** 💪 (works with big files using Streams) | ||
[Project Page](http://kauegimenes.github.io/jsonexport/) | ||
[Project Page](https://kauegimenes.github.io/jsonexport/) | ||
[Online Demo Page](http://kauegimenes.github.io/jsonexport/demo/) | ||
[Online Demo Page](https://kauegimenes.github.io/jsonexport/demo/) | ||
@@ -37,2 +38,3 @@ <details> | ||
- [Stream](#stream) | ||
- [Promise](#promise) | ||
- [JSON Array Example](#json-array-example) | ||
@@ -98,2 +100,13 @@ - [Simple Array](#simple-array) | ||
## Promise | ||
```javascript | ||
const jsonexport = require('jsonexport') | ||
try { | ||
const csv = await jsonexport({lang: 'Node.js', module: 'jsonexport'}, {rowDelimiter: '|'}); | ||
} catch (err) { | ||
console.error(err); | ||
} | ||
``` | ||
## JSON Array Example | ||
@@ -258,2 +271,3 @@ | ||
- `fillGaps` - `Boolean` Set this option if don't want to have empty cells in case of an object with multiple nested items (array prop), defaults to `false` [Issue #22](https://github.com/kauegimenes/jsonexport/issues/22) | ||
- `fillTopRow` - `Boolean` try filling top rows first for unpopular colums, defaults to `false` | ||
- `headers` - `Array` Used to set a custom header order, defaults to `[]` example `['lastname', 'name']` | ||
@@ -278,9 +292,2 @@ - `rename` - `Array` Used to set a custom header text, defaults to `[]` example `['Last Name', 'Name']` | ||
**Deprecated Options** (Use typeHandlers) | ||
- `handleString` - `Function` Use this to customize all `Strings` in the CSV file. | ||
- `handleNumber` - `Function` Use this to customize all `Numbers` in the CSV file. | ||
- `handleBoolean` - `Function` Use this to customize all `Booleans` in the CSV file. | ||
- `handleDate` - `Function` Use this to customize all `Dates` in the CSV file. (default to date.toLocaleString) | ||
#### typeHandlers | ||
@@ -338,3 +345,22 @@ Define types by constructors and what function to run when that type is matched | ||
Date typeHandler? | ||
```javascript | ||
var date = new Date(); | ||
jsonexport({ | ||
a: date, | ||
b: true | ||
}, { | ||
typeHandlers: { | ||
Object: (value, name) => { | ||
if (value instanceof Date) return date.toLocaleString(); | ||
return value; | ||
} | ||
} | ||
}, (err, csv) => { | ||
if (err) return console.error(err); | ||
console.log(csv); | ||
}); | ||
``` | ||
When using **typeHandlers**, Do NOT do this | ||
@@ -341,0 +367,0 @@ |
@@ -70,3 +70,3 @@ /* jshint node:true */ | ||
}], {}, (err, csv) => { | ||
expect(csv).to.equal(`a.b,a.c.d,a.e.f${os.EOL}true,1,1${os.EOL},2,2${os.EOL},3,${os.EOL},4,`); | ||
expect(csv).to.equal(`a.b,a.c.d,a.e.f${os.EOL}true,1,${os.EOL},2,${os.EOL},3,${os.EOL},4,1${os.EOL},,2`); | ||
}); | ||
@@ -73,0 +73,0 @@ }); |
@@ -43,2 +43,33 @@ var chai = require('chai'); | ||
}); | ||
it('fillTopRow', () => { | ||
jsonexport([{ | ||
a: { | ||
b: true, | ||
c: [{ | ||
d: 1 | ||
}, | ||
{ | ||
d: 2 | ||
}, | ||
{ | ||
d: 3 | ||
}, | ||
{ | ||
d: 4 | ||
} | ||
], | ||
e: [{ | ||
f: 1 | ||
}, | ||
{ | ||
f: 2 | ||
} | ||
] | ||
} | ||
}], { | ||
fillTopRow: true, | ||
}, (err, csv) => { | ||
expect(csv).to.equal(`a.b,a.c.d,a.e.f${os.EOL}true,1,1${os.EOL},2,2${os.EOL},3,${os.EOL},4,`); | ||
}); | ||
}); | ||
it('mapHeaders', () => { | ||
@@ -186,4 +217,4 @@ jsonexport([{ | ||
}); | ||
describe.skip('Handlers', () => { | ||
it('handleString', () => { | ||
describe('Type Handlers', () => { | ||
it('String', () => { | ||
jsonexport({ | ||
@@ -193,3 +224,5 @@ a: 'test', | ||
}, { | ||
handleString: (value, name) => value + "|||" | ||
typeHandlers: { | ||
String: (value) => value + "|||" | ||
} | ||
}, (err, csv) => { | ||
@@ -199,3 +232,3 @@ expect(csv).to.have.string('a,test|||'); | ||
}); | ||
it('handleNumber', () => { | ||
it('Number', () => { | ||
jsonexport({ | ||
@@ -205,3 +238,5 @@ a: 1, | ||
}, { | ||
handleNumber: (value, name) => value + "|||" | ||
typeHandlers: { | ||
Number: (value) => value + "|||" | ||
} | ||
}, (err, csv) => { | ||
@@ -211,3 +246,3 @@ expect(csv).to.have.string('a,1|||'); | ||
}); | ||
it('handleBoolean', () => { | ||
it('Boolean', () => { | ||
jsonexport({ | ||
@@ -217,3 +252,5 @@ a: true, | ||
}, { | ||
handleBoolean: (value, name) => value + "|||" | ||
typeHandlers: { | ||
Boolean: (value, name) => value + "|||" | ||
} | ||
}, (err, csv) => { | ||
@@ -223,3 +260,3 @@ expect(csv).to.have.string('a,true|||'); | ||
}); | ||
it('handleDate', () => { | ||
it('Date', (done) => { | ||
var date = new Date(); | ||
@@ -230,5 +267,11 @@ jsonexport({ | ||
}, { | ||
handleDate: (value, name) => value + "|||" | ||
typeHandlers: { | ||
Object: (value, name) => { | ||
if (value instanceof Date) return date + '|||'; | ||
return value; | ||
} | ||
} | ||
}, (err, csv) => { | ||
expect(csv).to.have.string('a,' + date + '|||'); | ||
done(); | ||
}); | ||
@@ -235,0 +278,0 @@ }); |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
92026
37
1871
378