Skip to content

Commit

Permalink
fix: Streamify pretty print (#248)
Browse files Browse the repository at this point in the history
  • Loading branch information
juanjoDiaz authored and knownasilya committed Feb 5, 2018
1 parent bb8126f commit fb7ad53
Show file tree
Hide file tree
Showing 9 changed files with 172 additions and 55 deletions.
50 changes: 26 additions & 24 deletions bin/json2csv.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,10 @@
const fs = require('fs');
const os = require('os');
const path = require('path');
const Table = require('cli-table');
const program = require('commander');
const json2csv = require('../lib/json2csv');
const parseNdJson = require('../lib/parse-ndjson');
const parseNdJson = require('./utils/parseNdjson');
const TablePrinter = require('./utils/TablePrinter');
const pkg = require('../package');

const JSON2CSVParser = json2csv.Parser;
Expand Down Expand Up @@ -46,6 +46,9 @@ const inputPath = makePathAbsolute(program.input);
const outputPath = makePathAbsolute(program.output);
const fieldsConfigPath = makePathAbsolute(program.fieldsConfig);

program.delimiter = program.delimiter || ',';
program.eol = program.eol || os.EOL;

// don't fail if piped to e.g. head
/* istanbul ignore next */
process.stdout.on('error', (error) => {
Expand Down Expand Up @@ -116,25 +119,10 @@ function getInputFromStdin() {
});
}

function logPretty(csv) {
let lines = csv.split(os.EOL);
const header = program.header ? lines.shift().split(',') : undefined;

const table = new Table(header ? {
head: header,
colWidths: header.map(elem => elem.length * 2)
} : undefined);

lines.forEach(line => table.push(line.split(',')));

// eslint-disable-next-line no-console
console.log(table.toString());
}

function processOutput(csv) {
if (!outputPath) {
// eslint-disable-next-line no-console
program.pretty ? logPretty(csv) : console.log(csv);
program.pretty ? (new TablePrinter(program)).printCSV(csv) : console.log(csv);
return;
}

Expand Down Expand Up @@ -203,18 +191,32 @@ Promise.resolve()
input.on('error', reject);
stream.on('error', reject);
let csv = '';
const table = new TablePrinter(program);
stream
.on('data', chunk => (csv += chunk.toString()))
.on('end', () => resolve(csv))
.on('data', chunk => {
csv += chunk.toString();
const index = csv.lastIndexOf(program.eol);
let lines = csv.substring(0, index);
csv = csv.substring(index + 1);

if (lines) {
table.push(lines);
}

})
.on('end', () => {
table.end(csv);
resolve();
})
.on('error', reject);
}).then(logPretty);
});
})
.catch((err) => {
if (err.message.indexOf(inputPath) !== -1) {
if (inputPath && err.message.indexOf(inputPath) !== -1) {
err = new Error('Invalid input file. (' + err.message + ')');
} else if (err.message.indexOf(outputPath) !== -1) {
} else if (outputPath && err.message.indexOf(outputPath) !== -1) {
err = new Error('Invalid output file. (' + err.message + ')');
} else if (err.message.indexOf(fieldsConfigPath) !== -1) {
} else if (fieldsConfigPath && err.message.indexOf(fieldsConfigPath) !== -1) {
err = new Error('Invalid fields config file. (' + err.message + ')');
}
// eslint-disable-next-line no-console
Expand Down
79 changes: 79 additions & 0 deletions bin/utils/TablePrinter.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
'use strict';

const Table = require('cli-table2');

const MIN_CELL_WIDTH = 15;

class TablePrinter {
constructor(params) {
this.params = params;
this._hasWritten = false;
this.colWidths;
}

push(csv) {
const lines = csv.split(this.params.eol);

const chars = {
'bottom': '',
'bottom-mid': '',
'bottom-left': '',
'bottom-right': ''
};
if (!this._hasWritten) {
this.colWidths = this.getColumnWidths(lines[0]);
if (this.params.header) {
const head = lines.shift().split(this.params.delimiter);
const table = new Table({ head, colWidths: this.colWidths, chars });
this.print(table, []);
this._hasWritten = true;
}
} else {
chars['top-left'] = '├';
chars['top-mid'] = '┼';
chars['top-right'] = '┤';
}

if (!lines.length) return;

const table = new Table({ colWidths: this.colWidths, chars });
this.print(table, lines);
this._hasWritten = true;
}

end(csv) {
const lines = csv.split(this.params.eol);
const chars = { 'top-left': '├' , 'top-mid': '┼', 'top-right': '┤' };
const table = new Table({ colWidths: this.colWidths, chars });
this.print(table, lines);
}

printCSV(csv) {
let lines = csv.split(this.params.eol);

this.colWidths = this.getColumnWidths(lines[0]);
const head = this.params.header
? lines.shift().split(this.params.delimiter)
: undefined;

const table = new Table(head
? { head, colWidths: this.colWidths }
: { colWidths: this.colWidths });

this.print(table, lines);
}

getColumnWidths(line) {
return line
.split(this.params.delimiter)
.map(elem => Math.max(elem.length * 2, MIN_CELL_WIDTH));
}

print(table, lines) {
lines.forEach(line => table.push(line.split(this.params.delimiter)));
// eslint-disable-next-line no-console
console.log(table.toString());
}
}

module.exports = TablePrinter;
File renamed without changes.
38 changes: 21 additions & 17 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@
"release": "standard-version"
},
"dependencies": {
"cli-table": "^0.3.1",
"cli-table2": "^0.2.0",
"commander": "^2.8.1",
"flat": "^4.0.0",
"jsonparse": "^1.3.1",
Expand Down
25 changes: 24 additions & 1 deletion test/CLI.js
Original file line number Diff line number Diff line change
Expand Up @@ -705,9 +705,20 @@ module.exports = (testRunner, jsonFixtures, csvFixtures) => {
});
});

testRunner.add('should print pretty table without header', (t) => {
const opts = ' --no-header --pretty';

child_process.exec(cli + '-i ' + getFixturePath('/json/default.json') + opts, (err, stdout, stderr) => {
t.notOk(stderr);
const csv = stdout;
t.equal(csv, csvFixtures.prettyprintWithoutHeader);
t.end();
});
});

testRunner.add('should print pretty table without streaming', (t) => {
const opts = ' --fields carModel,price,color'
+ ' --pretty --no-streaming';
+ ' --no-streaming --pretty ';

child_process.exec(cli + '-i ' + getFixturePath('/json/default.json') + opts, (err, stdout, stderr) => {
t.notOk(stderr);
Expand All @@ -716,5 +727,17 @@ module.exports = (testRunner, jsonFixtures, csvFixtures) => {
t.end();
});
});

testRunner.add('should print pretty table without streaming and without header', (t) => {
const opts = ' --fields carModel,price,color'
+ ' --no-streaming --no-header --pretty ';

child_process.exec(cli + '-i ' + getFixturePath('/json/default.json') + opts, (err, stdout, stderr) => {
t.notOk(stderr);
const csv = stdout;
t.equal(csv, csvFixtures.prettyprintWithoutHeader);
t.end();
});
});
};

22 changes: 11 additions & 11 deletions test/fixtures/csv/prettyprint.txt
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
┌────────────────────┬────────────────────────────┐
│ "carModel" │ "price" │ "color" │
├────────────────────┼────────────────────────────┤
│ "Audi" │ 0 │ "blue" │
├────────────────────┼────────────────────────────┤
│ "BMW" │ 15000 │ "red" │
├────────────────────┼────────────────────────────┤
│ "Mercedes" │ 20000 │ "yellow" │
├────────────────────┼────────────────────────────┤
│ "Porsche" │ 30000 │ "green" │
└────────────────────┴────────────────────────────┘
┌────────────────────┬───────────────┬───────────────┐
│ "carModel" │ "price" │ "color"
├────────────────────┼───────────────┼───────────────┤
│ "Audi" │ 0 │ "blue"
├────────────────────┼───────────────┼───────────────┤
│ "BMW" │ 15000 │ "red"
├────────────────────┼───────────────┼───────────────┤
│ "Mercedes" │ 20000 │ "yellow"
├────────────────────┼───────────────┼───────────────┤
│ "Porsche" │ 30000 │ "green"
└────────────────────┴───────────────┴───────────────┘
9 changes: 9 additions & 0 deletions test/fixtures/csv/prettyprintWithoutHeader.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
┌───────────────┬───────────────┬───────────────┐
│ "Audi" │ 0 │ "blue" │
├───────────────┼───────────────┼───────────────┤
│ "BMW" │ 15000 │ "red" │
├───────────────┼───────────────┼───────────────┤
│ "Mercedes" │ 20000 │ "yellow" │
├───────────────┼───────────────┼───────────────┤
│ "Porsche" │ 30000 │ "green" │
└───────────────┴───────────────┴───────────────┘
2 changes: 1 addition & 1 deletion test/parseNdjson.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
'use strict';

const parsendjson = require('../lib/parse-ndjson');
const parsendjson = require('../bin/utils/parseNdjson');

module.exports = (testRunner, jsonFixtures) => {
testRunner.add('should parse line-delimited JSON', (t) => {
Expand Down

0 comments on commit fb7ad53

Please sign in to comment.