diff options
author | Gus Caplan <me@gus.host> | 2018-01-13 13:55:19 -0600 |
---|---|---|
committer | Gus Caplan <me@gus.host> | 2018-03-30 19:41:41 -0500 |
commit | 97ace0449292eab3f044158ba3787e6af5dd6f3a (patch) | |
tree | cd6150997307934e3f1998252d3465709469916b /lib/internal/cli_table.js | |
parent | 83d44bee0134e3b8b6b98bf89e1f02981d72adee (diff) | |
download | android-node-v8-97ace0449292eab3f044158ba3787e6af5dd6f3a.tar.gz android-node-v8-97ace0449292eab3f044158ba3787e6af5dd6f3a.tar.bz2 android-node-v8-97ace0449292eab3f044158ba3787e6af5dd6f3a.zip |
console: add table method
PR-URL: https://github.com/nodejs/node/pull/18137
Reviewed-By: Tiancheng "Timothy" Gu <timothygu99@gmail.com>
Reviewed-By: Ruben Bridgewater <ruben@bridgewater.de>
Diffstat (limited to 'lib/internal/cli_table.js')
-rw-r--r-- | lib/internal/cli_table.js | 83 |
1 files changed, 83 insertions, 0 deletions
diff --git a/lib/internal/cli_table.js b/lib/internal/cli_table.js new file mode 100644 index 0000000000..4c07d92eeb --- /dev/null +++ b/lib/internal/cli_table.js @@ -0,0 +1,83 @@ +'use strict'; + +const { Buffer } = require('buffer'); +const { removeColors } = require('internal/util'); +const HasOwnProperty = Function.call.bind(Object.prototype.hasOwnProperty); + +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 countSymbols = (string) => { + const normalized = removeColors(string).normalize('NFC'); + return Buffer.from(normalized, 'UCS-2').byteLength / 2; +}; + +const renderRow = (row, columnWidths) => { + let out = tableChars.left; + for (var i = 0; i < row.length; i++) { + const cell = row[i]; + const len = countSymbols(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(Math.ceil(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) => countSymbols(h)); + const longestColumn = columns.reduce((n, a) => Math.max(n, a.length), 0); + + for (var i = 0; i < head.length; i++) { + const column = columns[i]; + for (var j = 0; j < longestColumn; j++) { + if (!rows[j]) + rows[j] = []; + const v = rows[j][i] = HasOwnProperty(column, j) ? column[j] : ''; + const width = columnWidths[i] || 0; + const counted = countSymbols(v); + columnWidths[i] = Math.max(width, counted); + } + } + + const divider = columnWidths.map((i) => + tableChars.middleMiddle.repeat(i + 2)); + + const tl = tableChars.topLeft; + const tr = tableChars.topRight; + const lm = tableChars.leftMiddle; + let result = `${tl}${divider.join(tableChars.topMiddle)}${tr} +${renderRow(head, columnWidths)} +${lm}${divider.join(tableChars.rowMiddle)}${tableChars.rightMiddle} +`; + + for (const row of rows) + result += `${renderRow(row, columnWidths)}\n`; + + result += `${tableChars.bottomLeft}${ + divider.join(tableChars.bottomMiddle)}${tableChars.bottomRight}`; + + return result; +}; + +module.exports = table; |