Skip to content
Open
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
25 changes: 25 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,31 @@ You will see output about your tests that looks like this:
1 error found
```

## require

You can use csv-test from a node application using classic require function.

```js
require('csv-test')(config, stream, validator, callback);
```

- **config(str):** Configuration in yaml format.
- **stream(ReadStream):** Data to validate.
- **customValidator:** Custom validator object.
- **callback(function):** Function called when job is finished.

An example usage might look like this:

```js
var config = fs.readFileSync('path/to/config.yml', 'utf8'),
stream = fs.createReadStream('path/to/data.csv', 'utf8');

require('csv-test')(config, stream, undefined, function(errors) {
// handle list of errors.
console.error(errors)
});
```

## configuration

`csv-test` runs by testing your CSV against a configuration file. The configuration file support [yaml](https://en.wikipedia.org/wiki/YAML), which is a human-readable data format. Here is an example configuration file:
Expand Down
155 changes: 81 additions & 74 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,81 +5,88 @@ var _ = require('lodash'),
validator = require('validator'),
transform = require('stream-transform');

module.exports = function(yml, stream, validators) {

var index = 0,
errorCount = 0,
config = yaml.safeLoad(yml),
settings = _.extend({ columns: true }, config.settings),
parser = parse(settings),
transformer = transform(testRow);

if (validators && _.isObject(validators)) addValidators(validators);

stream.pipe(parser).pipe(transformer);
stream.on('end', finish);

function testRow(row) {
index++;
_.each(row, function(value, field) {
var error = testField(value, field, row);
if (error) console.error(chalk.red(error));
});
}

function testField(value, field, row) {
var fieldIndex = '✗ [row ' + index + ', field ' + field + '] ',
rules = config.fields[field],
output = [];

rules = _.isString(rules) ? [rules] : rules;

_.each(rules, function(options, rule) {
if (_.isArray(rules)) {
rule = options;
options = undefined;
}

if (_.isObject(rule)) {
options = _.values(rule)[0];
rule = _.keys(rule)[0];
}

var args = _.isArray(options) ?
[value].concat(options) : [value, options],
test = validator[rule];

if (!test) throw new Error('`' + rule + '` is not a valid rule.');

this.row = row;
this.field = field;
this.value = value;

if (!test.apply(this, args)) {
errorCount = errorCount + 1;
output.push(fieldIndex + '`' + rule + '` failed.');
}
});

return output.join('\n');
}

function finish() {
console.log(index + ' rows tested');
if (errorCount) {
var label = errorCount === 1 ? ' error' : ' errors';
console.log(chalk.red(errorCount + label + ' found'));
process.exit(1);
} else {
console.log(chalk.green('no errors found'));
process.exit(0);
module.exports = function(yml, stream, validators, doneCallback) {

var index = 0,
errorCount = 0,
errorList = [],
config = yaml.safeLoad(yml),
settings = _.extend({ columns: true }, config.settings),
parser = parse(settings),
transformer = transform(testRow);

if (validators && _.isObject(validators)) addValidators(validators);

stream.pipe(parser).pipe(transformer);
stream.on('end', finish);

function testRow(row) {
index++;
_.each(row, function(value, field) {
var error = testField(value, field, row);
if (error) console.error(chalk.red(error));
});
}
}

function addValidators(validators) {
_.each(validators, function(func, key) {
validator.extend(key, func);
});
}
function testField(value, field, row) {
var fieldIndex = '✗ [row ' + index + ', field ' + field + '] ',
rules = config.fields[field],
output = [];

rules = _.isString(rules) ? [rules] : rules;

_.each(rules, function(options, rule) {
if (_.isArray(rules)) {
rule = options;
options = undefined;
}

if (_.isObject(rule)) {
options = _.values(rule)[0];
rule = _.keys(rule)[0];
}

var args = _.isArray(options) ?
[value].concat(options) : [value, options],
test = validator[rule];

if (!test) throw new Error('`' + rule + '` is not a valid rule.');

this.row = row;
this.field = field;
this.value = value;

if (!test.apply(this, args)) {
errorCount = errorCount + 1;
output.push(fieldIndex + '`' + rule + '` failed.');
if(doneCallback)
errorList.push(output);
}
});

return output.join('\n');
}

function finish() {
if(doneCallback) doneCallback(errorList);
else finishCli()
}
function finishCli() {
console.log(index + ' rows tested');
if (errorCount) {
var label = errorCount === 1 ? ' error' : ' errors';
console.log(chalk.red(errorCount + label + ' found'));
process.exit(1);
} else {
console.log(chalk.green('no errors found'));
process.exit(0);
}
}

function addValidators(validators) {
_.each(validators, function(func, key) {
validator.extend(key, func);
});
}

};
37 changes: 37 additions & 0 deletions test/require.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
var tape = require('tape');
var fs = require('fs');


tape('require csv-test module', function(t) {
var config = fs.readFileSync('test/fixtures/test.yml', 'utf8'),
file = 'test/fixtures/test.csv',
stream = fs.createReadStream(file, 'utf8');

require('..')(config, stream, undefined, function(error){
t.plan(1);
t.deepEqual(error, [], 'should runs without error');
});
});

tape('allow fields without rules', function(t) {
var config = fs.readFileSync('test/fixtures/undefinedFields.yml', 'utf8'),
file = 'test/fixtures/test.csv',
stream = fs.createReadStream(file, 'utf8');

require('..')(config, stream, undefined, function(error){
t.plan(1);
t.deepEqual(error, [], 'should runs without error');
});
});

tape('support custom rules', function(t) {
var config = fs.readFileSync('test/fixtures/customValidators.yml', 'utf8'),
file = 'test/fixtures/customValidators.csv',
validator = require('./fixtures/customValidators.js'),
stream = fs.createReadStream(file, 'utf8');

require('..')(config, stream, validator, function(error){
t.plan(1);
t.deepEqual(error, [], 'should runs without error');
});
});