metaforecast/node_modules/json2csv/bin/utils/TablePrinter.js

118 lines
3.0 KiB
JavaScript
Raw Normal View History

2021-01-12 12:43:41 +00:00
'use strict';
const { Writable } = require('stream');
const MIN_CELL_WIDTH = 15;
class TablePrinter {
constructor(opts) {
this.opts = opts;
this._hasWritten = false;
}
push(csv) {
const lines = csv.split(this.opts.eol);
if (!lines.length) return;
if (!this._hasWritten) this.setColumnWidths(lines[0]);
const top = this._hasWritten ? this.middleLine : this.topLine;
this.print(top, lines);
this._hasWritten = true;
}
end(csv) {
let lines = csv.split(this.opts.eol);
if (!this._hasWritten) this.setColumnWidths(lines[0]);
const top = this._hasWritten ? this.middleLine : this.topLine;
this.print(top, lines, this.bottomLine);
}
printCSV(csv) {
this.end(csv);
}
setColumnWidths(line) {
this.colWidths = line
.split(this.opts.delimiter)
.map(elem => Math.max(elem.length * 2, MIN_CELL_WIDTH));
this.topLine = `${this.colWidths.map(i => '─'.repeat(i)).join('┬')}`;
this.middleLine = `${this.colWidths.map(i => '─'.repeat(i)).join('┼')}`;
this.bottomLine = `${this.colWidths.map(i => '─'.repeat(i)).join('┴')}`;
}
print(top, lines, bottom) {
const table = `${top}\n`
+ lines
.map(row => this.formatRow(row))
.join(`\n${this.middleLine}\n`)
+ (bottom ? `\n${bottom}` : '');
// eslint-disable-next-line no-console
console.log(table);
}
formatRow(row) {
const wrappedRow = row
.split(this.opts.delimiter)
.map((cell, i) => cell.match(new RegExp(`(.{1,${this.colWidths[i] - 2}})`, 'g')) || []);
const height = wrappedRow.reduce((acc, cell) => Math.max(acc, cell.length), 0);
const processedCells = wrappedRow
.map((cell, i) => this.formatCell(cell, height, this.colWidths[i]));
return Array(height).fill('')
.map((_, i) => `${processedCells.map(cell => cell[i]).join('│')}`)
.join('\n');
}
formatCell(content, heigth, width) {
const paddedContent = this.padCellHorizontally(content, width);
return this.padCellVertically(paddedContent, heigth, width);
}
padCellVertically(content, heigth, width) {
const vertPad = heigth - content.length;
const vertPadTop = Math.ceil(vertPad / 2);
const vertPadBottom = vertPad - vertPadTop;
const emptyLine = ' '.repeat(width);
return [
...Array(vertPadTop).fill(emptyLine),
...content,
...Array(vertPadBottom).fill(emptyLine)
];
}
padCellHorizontally(content, width) {
return content.map((line) => {
const horPad = width - line.length - 2;
return ` ${line}${' '.repeat(horPad)} `;
});
}
writeStream() {
let csv = '';
const table = this;
return new Writable({
write(chunk, encoding, callback) {
csv += chunk.toString();
const index = csv.lastIndexOf(table.opts.eol);
let lines = csv.substring(0, index);
csv = csv.substring(index + 1);
if (lines) table.push(lines);
callback();
},
final() {
table.end(csv);
}
});
}
}
module.exports = TablePrinter;