UNPKG

4.34 kBJavaScriptView Raw
1"use strict";
2Object.defineProperty(exports, "__esModule", { value: true });
3const ts_lodash_1 = require("ts-lodash");
4const deps_1 = require("./deps");
5/**
6 * Generates a Unicode table and feeds it into configured printer.
7 *
8 * Top-level arguments:
9 *
10 * @arg {Object[]} data - the records to format as a table.
11 * @arg {Object} options - configuration for the table.
12 *
13 * @arg {Object[]} [options.columns] - Options for formatting and finding values for table columns.
14 * @arg {function(string)} [options.headerAnsi] - Zero-width formattter for entire header.
15 * @arg {string} [options.colSep] - Separator between columns.
16 * @arg {function(row, options)} [options.after] - Function called after each row is printed.
17 * @arg {function(string)} [options.printLine] - Function responsible for printing to terminal.
18 * @arg {function(cells)} [options.printHeader] - Function to print header cells as a row.
19 * @arg {function(cells)} [options.printRow] - Function to print cells as a row.
20 *
21 * @arg {function(row)|string} [options.columns[].key] - Path to the value in the row or function to retrieve the pre-formatted value for the cell.
22 * @arg {function(string)} [options.columns[].label] - Header name for column.
23 * @arg {function(string, row)} [options.columns[].format] - Formatter function for column value.
24 * @arg {function(row)} [options.columns[].get] - Function to return a value to be presented in cell without formatting.
25 *
26 */
27function table(stream, data, inputOptions = {}) {
28 const options = Object.assign({}, inputOptions, { columns: (inputOptions.columns || []).map(c => (Object.assign({ format: (value) => (value ? value.toString() : ''), width: 0, label: function () {
29 return this.key.toString();
30 }, get: function (row) {
31 let value;
32 let path = ts_lodash_1.default.result(this, 'key');
33 if (!path) {
34 value = row;
35 }
36 else {
37 value = ts_lodash_1.default.get(row, path);
38 }
39 return this.format(value, row);
40 } }, c))), colSep: ' ', after: () => { }, headerAnsi: ts_lodash_1.default.identity, printLine: (s) => stream.log(s), printRow: function (cells) {
41 this.printLine(cells.join(this.colSep).trimRight());
42 }, printHeader: function (cells) {
43 this.printRow(cells.map(ts_lodash_1.default.ary(this.headerAnsi, 1)));
44 this.printRow(cells.map(hdr => hdr.replace(/./g, '─')));
45 } });
46 function calcWidth(cell) {
47 let lines = deps_1.default.stripAnsi(cell).split(/[\r\n]+/);
48 let lineLengths = lines.map(ts_lodash_1.default.property('length'));
49 return Math.max.apply(Math, lineLengths);
50 }
51 function pad(string, length) {
52 let visibleLength = deps_1.default.stripAnsi(string).length;
53 let diff = length - visibleLength;
54 return string + ' '.repeat(Math.max(0, diff));
55 }
56 function render() {
57 let columns = options.columns;
58 if (typeof columns[0] === 'string') {
59 columns = columns.map((key) => ({ key }));
60 }
61 for (let row of data) {
62 row.height = 1;
63 for (let col of columns) {
64 let cell = col.get(row);
65 col.width = Math.max(ts_lodash_1.default.result(col, 'label').length, col.width || 0, calcWidth(cell));
66 row.height = Math.max(row.height || 0, cell.split(/[\r\n]+/).length);
67 }
68 }
69 if (options.printHeader) {
70 options.printHeader(columns.map(function (col) {
71 let label = ts_lodash_1.default.result(col, 'label');
72 return pad(label, col.width || label.length);
73 }));
74 }
75 function getNthLineOfCell(n, row, col) {
76 // TODO memoize this
77 let lines = col.get(row).split(/[\r\n]+/);
78 return pad(lines[n] || '', col.width);
79 }
80 for (let row of data) {
81 for (let i = 0; i < (row.height || 0); i++) {
82 let cells = columns.map(ts_lodash_1.default.partial(getNthLineOfCell, i, row));
83 options.printRow(cells);
84 }
85 options.after(row, options);
86 }
87 }
88 render();
89}
90exports.table = table;
91module.exports = table;