-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathindex.js
More file actions
executable file
·79 lines (72 loc) · 2.41 KB
/
index.js
File metadata and controls
executable file
·79 lines (72 loc) · 2.41 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
#!/usr/bin/env node
/**
* Parses a CSV file and ensures that not only is it valid CSV,
* but the data in each column fits a defined schema.
*/
'use strict';
const fs = require('fs');
const csv = require('csv');
const yargs = require('yargs');
const checkCell = require('./checks').checkCell;
const argv = yargs
.alias({
csv: 'c',
errors: 'e',
schema: 's',
})
.demand(['schema'])
.describe({
csv: 'CSV file to examine (else stdin)',
errors: 'File to log problems (else stdout)',
schema: 'Schema definition file',
})
.epilogue('Parses a CSV file and ensures that not only is it valid CSV, but the data in each column fits a defined schema.')
.help()
.string(['csv', 'errors', 'schema'])
.version()
.wrap(yargs.terminalWidth() - 5)
.argv;
const instream = argv.csv ? fs.createReadStream(argv.csv) : process.stdin;
const outstream = argv.errors ? fs.createWriteStream(argv.errors) : process.stdout;
const schema = JSON.parse(fs.readFileSync(argv.schema, { encoding: 'utf8' }));
const namedColumnMode = !Array.isArray(schema.columnDefs);
let row = namedColumnMode ? 1 : 0;
const parser = csv.parse({ columns: namedColumnMode })
.on('error', err => {
outstream.write(`${err.message}\n`);
})
.on('end', () => {
// Need to close output file if using one, but can't close stdout
if (argv.errors) { outstream.end(); }
})
.on('readable', () => {
// For each row...
let rec;
while (rec = parser.read()) {
row++;
if (row <= schema.skipRows) continue;
// Explicit column count
const colCnt = namedColumnMode ? Object.keys(rec).length : rec.length;
if (schema.columns && schema.columns !== colCnt) {
const msg = `(Row ${row}): Schema specifies ${schema.columns} columns, found ${colCnt}\n`;
outstream.write(msg);
}
// For each cell in this row...
if (namedColumnMode) {
Object.keys(schema.columnDefs).forEach(key => {
checkCell(rec[key], schema.columnDefs[key]).forEach(msgmid => {
const msg = `(Row ${row}, Col '${key}'): ${msgmid}\n`;
outstream.write(msg);
});
});
} else {
schema.columnDefs.forEach((colDef, idx) => {
checkCell(rec[idx], colDef).forEach(msgmid => {
const msg = `(Row ${row}, Col ${idx + 1}): ${msgmid}\n`;
outstream.write(msg);
});
});
}
}
});
instream.pipe(parser);