Comparing version 2.1.0 to 2.2.1
@@ -0,1 +1,13 @@ | ||
2.2.1 / 2013-11-10 | ||
================== | ||
* mainly for development e.g. adding code format, update readme.. | ||
2.2.0 / 2013-11-08 | ||
================== | ||
* not create CSV column title by passing hasCSVColumnTitle: false, into params. | ||
* if field is not exist in object then the field value in CSV will be empty. | ||
* fix data in object format - {...} | ||
2.1.0 / 2013-06-11 | ||
@@ -29,2 +41,2 @@ ================== | ||
* add optional custom delimiter | ||
* add optional custom delimiter |
@@ -1,2 +0,1 @@ | ||
/** | ||
@@ -11,8 +10,10 @@ * Module dependencies. | ||
* | ||
* @param {Object} params Function parameters containing data, fields and delimiter | ||
* @param {Function} callback Callback function returning csv output | ||
* @param {Object} params Function parameters containing data, fields, | ||
* delimiter (default is ',') and hasCSVColumnTitle (default is true) | ||
* @param {Function} callback(err, csv) - Callback function | ||
* if error, returning error in call back. | ||
* if csv is created successfully, returning csv output to callback. | ||
*/ | ||
module.exports = function(params, callback) { | ||
params.data = JSON.parse(JSON.stringify(params.data)); | ||
checkFields(params, function(err) { | ||
checkParams(params, function(err) { | ||
if (err) return callback(err); | ||
@@ -29,23 +30,46 @@ createColumnTitles(params, function(err, title) { | ||
/** | ||
* Check if all the fields are present in the json data. | ||
* get type of the passing variable | ||
* for more detail see http://javascriptweblog.wordpress.com/2011/08/08/fixing-the-javascript-typeof-operator/ | ||
* | ||
* @param {Object} params Function parameters containing data, fields and delimiter | ||
* @param {Object} any variable to get type | ||
*/ | ||
var typeOf = function(obj) { | ||
return ({}).toString.call(obj).match(/\s([a-zA-Z]+)/)[1].toLowerCase(); | ||
} | ||
/** | ||
* Check passing params | ||
* | ||
* @param {Object} params Function parameters containing data, fields, | ||
* delimiter and hasCSVColumnTitle | ||
* @param {Function} callback Callback function returning error when invalid field is found | ||
*/ | ||
var checkFields = function(params, callback) { | ||
// private iteration function | ||
var myIterator = function(item, callback) { | ||
if (Object.keys(params.data[0]).indexOf(item) === -1) { | ||
callback(new Error('Cannot find ' + item + ' as a json key')); | ||
} else { | ||
callback(null); | ||
} | ||
}; | ||
// check every field if it exists in the json file | ||
async.each(params.fields, myIterator, function(err) { | ||
if (err) return callback(err); | ||
callback(null); | ||
}); | ||
var checkParams = function(params, callback) { | ||
//#check params.data | ||
params.data = JSON.parse(JSON.stringify(params.data)); | ||
// if data is an Object, not in array [{}], then just create 1 item array. | ||
// So from now all data in array of object format. | ||
if (typeOf(params.data) != 'array') { | ||
var ar = new Array(); | ||
ar[0] = params.data; | ||
params.data = ar; | ||
} | ||
//#check fieldNames | ||
if (params.fieldNames && params.fieldNames.length !== params.fields.length) { | ||
callback(new Error('fieldNames and fields should be of the same length, if fieldNames is provided.')); | ||
} | ||
params.fieldNames = params.fieldNames || params.fields; | ||
//#check delimiter | ||
params.del = params.del || ','; | ||
//#check hasCSVColumnTitle, if it is not explicitly set to false then true. | ||
if (params.hasCSVColumnTitle !== false) { | ||
params.hasCSVColumnTitle = true; | ||
} | ||
callback(null); | ||
}; | ||
@@ -60,17 +84,13 @@ | ||
var createColumnTitles = function(params, callback) { | ||
var del = params.del || ','; | ||
var str = ''; | ||
if (params.fieldNames && params.fieldNames.length !== params.fields.length) { | ||
callback(new Error('fieldNames and fields should be of the same length, if fieldNames is provided.')); | ||
//if CSV has column title, then create it | ||
if (params.hasCSVColumnTitle) { | ||
params.fieldNames.forEach(function(element) { | ||
if (str !== '') { | ||
str += params.del; | ||
} | ||
str += JSON.stringify(element); | ||
}); | ||
} | ||
var fieldNames = params.fieldNames || params.fields; | ||
fieldNames.forEach(function(element) { | ||
if (str !== '') { | ||
str += del; | ||
} | ||
str += JSON.stringify(element); | ||
}); | ||
callback(null, str); | ||
@@ -87,15 +107,20 @@ }; | ||
var createColumnContent = function(params, str, callback) { | ||
var del = params.del || ','; | ||
params.data.forEach(function(data_element) { | ||
var line = ''; | ||
params.fields.forEach(function(field_element) { | ||
if (line !== '') { | ||
line += del; | ||
} | ||
line += JSON.stringify(data_element[field_element]); | ||
}); | ||
line = line.replace(/\\"/g, '""'); | ||
str += os.EOL + line; | ||
//if null or empty object do nothing | ||
if (data_element && Object.getOwnPropertyNames(data_element).length > 0) { | ||
var line = ''; | ||
var eol = os.EOL || '\n'; | ||
params.fields.forEach(function(field_element) { | ||
if (data_element.hasOwnProperty(field_element)) { | ||
line += JSON.stringify(data_element[field_element]); | ||
} | ||
line += params.del; | ||
}); | ||
//remove last delimeter | ||
line = line.substring(0, line.length - 1); | ||
line = line.replace(/\\"/g, '""'); | ||
str += eol + line; | ||
} | ||
}); | ||
callback(str); | ||
}; | ||
}; |
{ | ||
"name": "json2csv", | ||
"preferGlobal": "true", | ||
"version": "2.1.0", | ||
"version": "2.2.1", | ||
"description": "Convert json to csv with column titles", | ||
@@ -28,3 +28,4 @@ "keywords": [ | ||
"scripts": { | ||
"test": "make test" | ||
"test": "./node_modules/.bin/mocha --reporter spec", | ||
"format": "node ./node_modules/js-beautify/js/bin/js-beautify.js lib/json2csv.js test/test.js package.json -r --config js-beautify.json" | ||
}, | ||
@@ -34,9 +35,11 @@ "dependencies": { | ||
"cli-table": "~0.2.0", | ||
"async": "~0.2.6" | ||
"async": "~0.2.9" | ||
}, | ||
"devDependencies": { | ||
"mocha": "~1.8.1", | ||
"should": "~1.2.1", | ||
"async": "~0.2.6" | ||
"mocha": "~1.14.0", | ||
"should": "~2.0.2", | ||
"async": "~0.2.9", | ||
"js-beautify": "~1.4.2" | ||
} | ||
} |
@@ -34,2 +34,4 @@ # Convert json to csv | ||
- Supports optional custom delimiters | ||
- Not create CSV column title by passing hasCSVColumnTitle: false, into params. | ||
- If field is not exist in object then the field value in CSV will be empty. | ||
@@ -260,2 +262,32 @@ ## Use as a module | ||
``` | ||
## Formatting json2csv | ||
Requires js-beautify. | ||
Run | ||
```bash | ||
$ make format | ||
``` | ||
or | ||
```bash | ||
$ npm run-script format | ||
``` | ||
## Contributors | ||
Install require packages for development run following command under json2csv dir. | ||
Run | ||
```bash | ||
$ npm install | ||
``` | ||
Could you please make sure code is formatted and test passed before submit Pull Requests? | ||
See Testing and Formatting json2csv above. | ||
@@ -275,2 +307,2 @@ ## But I want streams! | ||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. | ||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. |
147
test/test.js
var should = require('should'), | ||
json2csv = require('.././lib/json2csv'), | ||
fs = require('fs'), | ||
async = require('async'); | ||
json2csv = require('.././lib/json2csv'), | ||
fs = require('fs'), | ||
async = require('async'); | ||
var _in = require('./fixtures/in'), | ||
_in_quotes = require('./fixtures/in-quotes'), | ||
_out = '', | ||
_out_quotes = '', | ||
_out_selected = '', | ||
_out_reversed = '', | ||
_out_tsv = '', | ||
_out_fieldNames = ''; | ||
_in_quotes = require('./fixtures/in-quotes'), | ||
_out = '', | ||
_out_withoutTitle = '', | ||
_out_withNotExistField = '', | ||
_out_quotes = '', | ||
_out_selected = '', | ||
_out_reversed = '', | ||
_out_tsv = '', | ||
_out_fieldNames = ''; | ||
describe('json2csv', function() { | ||
before(function(done) { | ||
async.parallel([ | ||
function(callback){ | ||
function(callback) { | ||
fs.readFile('test/fixtures/out.csv', function(err, data) { | ||
@@ -26,3 +29,17 @@ if (err) callback(err); | ||
}, | ||
function(callback){ | ||
function(callback) { | ||
fs.readFile('test/fixtures/out-withoutTitle.csv', function(err, data) { | ||
if (err) callback(err); | ||
_out_withoutTitle = data.toString(); | ||
callback(null); | ||
}); | ||
}, | ||
function(callback) { | ||
fs.readFile('test/fixtures/out-withNotExistField.csv', function(err, data) { | ||
if (err) callback(err); | ||
_out_withNotExistField = data.toString(); | ||
callback(null); | ||
}); | ||
}, | ||
function(callback) { | ||
fs.readFile('test/fixtures/out-quotes.csv', function(err, data) { | ||
@@ -34,3 +51,3 @@ if (err) callback(err); | ||
}, | ||
function(callback){ | ||
function(callback) { | ||
fs.readFile('test/fixtures/out-selected.csv', function(err, data) { | ||
@@ -42,3 +59,3 @@ if (err) callback(err); | ||
}, | ||
function(callback){ | ||
function(callback) { | ||
fs.readFile('test/fixtures/out-reversed.csv', function(err, data) { | ||
@@ -50,3 +67,3 @@ if (err) callback(err); | ||
}, | ||
function(callback){ | ||
function(callback) { | ||
fs.readFile('test/fixtures/out.tsv', function(err, data) { | ||
@@ -58,4 +75,4 @@ if (err) callback(err); | ||
}, | ||
function(callback){ | ||
fs.readFile('test/fixtures/out-fieldNames.csv', function(err, data){ | ||
function(callback) { | ||
fs.readFile('test/fixtures/out-fieldNames.csv', function(err, data) { | ||
if (err) callback(err); | ||
@@ -73,5 +90,8 @@ _out_fieldNames = data.toString(); | ||
}); | ||
it('should parse json to csv', function(done) { | ||
json2csv({data: _in, fields: ['carModel', 'price', 'color']}, function(err, csv) { | ||
json2csv({ | ||
data: _in, | ||
fields: ['carModel', 'price', 'color'] | ||
}, function(err, csv) { | ||
csv.should.equal(_out); | ||
@@ -81,12 +101,38 @@ done(); | ||
}); | ||
it('should callback an error if field is not a key in the json data', function(done) { | ||
json2csv({data: _in, fields: ['carModel', 'location', 'color']}, function(err, csv) { | ||
err.message.should.equal('Cannot find location as a json key'); | ||
it('should parse json to csv without column title', function(done) { | ||
json2csv({ | ||
data: _in, | ||
fields: ['carModel', 'price', 'color'], | ||
hasCSVColumnTitle: false | ||
}, function(err, csv) { | ||
csv.should.equal(_out_withoutTitle); | ||
done(); | ||
}) | ||
}); | ||
it('should parse data:{} to csv with only column title', function(done) { | ||
json2csv({ | ||
data: {}, | ||
fields: ['carModel', 'price', 'color'] | ||
}, function(err, csv) { | ||
csv.should.equal('"carModel","price","color"'); | ||
done(); | ||
}) | ||
}); | ||
it('should parse data:[null] to csv with only column title', function(done) { | ||
json2csv({ | ||
data: [null], | ||
fields: ['carModel', 'price', 'color'] | ||
}, function(err, csv) { | ||
csv.should.equal('"carModel","price","color"'); | ||
done(); | ||
}) | ||
}); | ||
it('should output only selected fields', function(done) { | ||
json2csv({data: _in, fields: ['carModel', 'price']}, function(err, csv) { | ||
json2csv({ | ||
data: _in, | ||
fields: ['carModel', 'price'] | ||
}, function(err, csv) { | ||
csv.should.equal(_out_selected); | ||
@@ -96,5 +142,18 @@ done(); | ||
}); | ||
it('should output not exist field with empty value', function(done) { | ||
json2csv({ | ||
data: _in, | ||
fields: ['first not exist field', 'carModel', 'price', 'not exist field', 'color'] | ||
}, function(err, csv) { | ||
csv.should.equal(_out_withNotExistField); | ||
done(); | ||
}) | ||
}); | ||
it('should output reversed order', function(done) { | ||
json2csv({data: _in, fields: ['price', 'carModel']}, function(err, csv) { | ||
json2csv({ | ||
data: _in, | ||
fields: ['price', 'carModel'] | ||
}, function(err, csv) { | ||
csv.should.equal(_out_reversed); | ||
@@ -104,12 +163,18 @@ done(); | ||
}); | ||
it('should output a string', function(done) { | ||
json2csv({data: _in, fields: ['carModel', 'price', 'color']}, function(err, csv) { | ||
csv.should.be.a('string'); | ||
json2csv({ | ||
data: _in, | ||
fields: ['carModel', 'price', 'color'] | ||
}, function(err, csv) { | ||
csv.should.be.type('string'); | ||
done(); | ||
}) | ||
}); | ||
it('should escape quotes with double quotes', function(done) { | ||
json2csv({data: _in_quotes, fields: ['a string']}, function(err, csv) { | ||
json2csv({ | ||
data: _in_quotes, | ||
fields: ['a string'] | ||
}, function(err, csv) { | ||
csv.should.equal(_out_quotes); | ||
@@ -121,3 +186,7 @@ done(); | ||
it('should use a custom delimiter when \'del\' property is present', function(done) { | ||
json2csv({data: _in, fields: ['carModel', 'price', 'color'], del:'\t'}, function(err, csv) { | ||
json2csv({ | ||
data: _in, | ||
fields: ['carModel', 'price', 'color'], | ||
del: '\t' | ||
}, function(err, csv) { | ||
csv.should.equal(_out_tsv); | ||
@@ -127,5 +196,9 @@ done(); | ||
}) | ||
it('should name columns as specified in \'fieldNames\' property', function(done) { | ||
json2csv({data: _in, fields: ['carModel', 'price'], fieldNames: ['Car Model', 'Price USD']}, function(err, csv) { | ||
json2csv({ | ||
data: _in, | ||
fields: ['carModel', 'price'], | ||
fieldNames: ['Car Model', 'Price USD'] | ||
}, function(err, csv) { | ||
csv.should.equal(_out_fieldNames); | ||
@@ -135,3 +208,3 @@ done(); | ||
}) | ||
}); |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Deprecated
MaintenanceThe maintainer of the package marked it as deprecated. This could indicate that a single version should not be used, or that the package is no longer maintained and any new vulnerabilities will not be fixed.
Found 1 instance in 1 package
New author
Supply chain riskA new npm collaborator published a version of the package for the first time. New collaborators are usually benign additions to a project, but do indicate a change to the security surface area of a package.
Found 1 instance in 1 package
Deprecated
MaintenanceThe maintainer of the package marked it as deprecated. This could indicate that a single version should not be used, or that the package is no longer maintained and any new vulnerabilities will not be fixed.
Found 1 instance in 1 package
406
306
31106
4
24
1
Updatedasync@~0.2.9