node/lib/internal/cli_table.js
Michaël Zasso 0646eda4fc
lib: flatten access to primordials
Store all primordials as properties of the primordials object.
Static functions are prefixed by the constructor's name and prototype
methods are prefixed by the constructor's name followed by "Prototype".
For example: primordials.Object.keys becomes primordials.ObjectKeys.

PR-URL: https://github.com/nodejs/node/pull/30610
Refs: https://github.com/nodejs/node/issues/29766
Reviewed-By: Anna Henningsen <anna@addaleax.net>
Reviewed-By: Matteo Collina <matteo.collina@gmail.com>
Reviewed-By: Colin Ihrig <cjihrig@gmail.com>
Reviewed-By: Trivikram Kamat <trivikr.dev@gmail.com>
2019-11-25 10:28:15 +01:00

87 lines
2.7 KiB
JavaScript

'use strict';
const {
MathCeil,
MathMax,
ObjectPrototypeHasOwnProperty,
} = primordials;
const { getStringWidth } = require('internal/readline/utils');
// The use of Unicode characters below is the only non-comment use of non-ASCII
// Unicode characters in Node.js built-in modules. If they are ever removed or
// rewritten with \u escapes, then a test will need to be (re-)added to Node.js
// core to verify that Unicode characters work in built-ins. Otherwise,
// consumers using Unicode in _third_party_main.js will run into problems.
// Refs: https://github.com/nodejs/node/issues/10673
const tableChars = {
/* eslint-disable node-core/non-ascii-character */
middleMiddle: '─',
rowMiddle: '┼',
topRight: '┐',
topLeft: '┌',
leftMiddle: '├',
topMiddle: '┬',
bottomRight: '┘',
bottomLeft: '└',
bottomMiddle: '┴',
rightMiddle: '┤',
left: '│ ',
right: ' │',
middle: ' │ ',
/* eslint-enable node-core/non-ascii-character */
};
const renderRow = (row, columnWidths) => {
let out = tableChars.left;
for (let i = 0; i < row.length; i++) {
const cell = row[i];
const len = getStringWidth(cell);
const needed = (columnWidths[i] - len) / 2;
// round(needed) + ceil(needed) will always add up to the amount
// of spaces we need while also left justifying the output.
out += `${' '.repeat(needed)}${cell}${' '.repeat(MathCeil(needed))}`;
if (i !== row.length - 1)
out += tableChars.middle;
}
out += tableChars.right;
return out;
};
const table = (head, columns) => {
const rows = [];
const columnWidths = head.map((h) => getStringWidth(h));
const longestColumn = columns.reduce((n, a) => MathMax(n, a.length), 0);
for (let i = 0; i < head.length; i++) {
const column = columns[i];
for (let j = 0; j < longestColumn; j++) {
if (rows[j] === undefined)
rows[j] = [];
const value = rows[j][i] =
ObjectPrototypeHasOwnProperty(column, j) ? column[j] : '';
const width = columnWidths[i] || 0;
const counted = getStringWidth(value);
columnWidths[i] = MathMax(width, counted);
}
}
const divider = columnWidths.map((i) =>
tableChars.middleMiddle.repeat(i + 2));
let result = `${tableChars.topLeft}${divider.join(tableChars.topMiddle)}` +
`${tableChars.topRight}\n${renderRow(head, columnWidths)}\n` +
`${tableChars.leftMiddle}${divider.join(tableChars.rowMiddle)}` +
`${tableChars.rightMiddle}\n`;
for (const row of rows)
result += `${renderRow(row, columnWidths)}\n`;
result += `${tableChars.bottomLeft}${divider.join(tableChars.bottomMiddle)}` +
tableChars.bottomRight;
return result;
};
module.exports = table;