UNPKG

le-table

Version:

Another NodeJS module for creating ASCII tables.

232 lines (203 loc) 6.81 kB
"use strict"; const Overlap = require("overlap"); const Box = require("cli-box"); const Ul = require("ul"); const ansiParser = require("ansi-parser"); class LeTable { /** * LeTable * Creates a new instance of `LeTable`. * * @name LeTable * @function * @param {Object} options An object containing the table configuration: * * - `cell`: object containing * - `hAlign` (default: `"center"`): One of the following values: `"left"`, `"center"` and `"right"` * - `vAlign` (default: `"middle"`): One of the following values: `"top"`, `"middle"` and `"bottom"` * - `autoEOL` (default: `true`): if true, the lines are wrapped inside of the cell * - `stretch` (default: `true`): if true, the size of the box will not be fixed * - `marks`: object containing the mark characters (see example) * - `noAnsi` (Boolean): If you want to disable ANSI characters in the output. * * @return {LeTable} The `LeTable` instance. */ constructor (options) { this.data = []; options = Ul.deepMerge(options, { marks: LeTable.defaults.marks, cell: LeTable.defaults.cell }); this.options = options; this.cell_ops = options.cell; this.cell_ops.padding = this.cell_ops.padding || { left: 1, right: 1 }; this.marks = options.marks; } /** * addRow * Adds a new row in table. * * @name addRow * @function * @param {Array} columns Row data (as array) * @param {Object} ops Options for cell content * @return {LeTable} The `LeTable` instance. */ addRow (columns, ops) { let computedColumns = []; let cColumn = null; let comCol = null; let cellOps = this.cell_ops; columns.forEach(cColumn => { comCol = { text: (cColumn.text || cColumn).toString(), data: { stretch: cellOps.stretch, autoEOL: cellOps.autoEOL, vAlign: cellOps.vAlign, hAlign: cellOps.hAlign, padding: cellOps.padding } }; // Override with ops comCol.data = Ul.deepMerge(cColumn.data, ops, comCol.data); computedColumns.push(comCol); }); this.data.push(computedColumns); return this; } /** * stringify * Stringifies the table. * * @name stringify * @function * @return {String} The stringified table */ stringify () { let output = ""; let offset = { x: 0, y: 0 }; let cellSizes = []; let cRow = null; let cColumn = null; let cell = null; let cCell = null; let splits = null; let wMax = null; let hMax = null; let mrks = null; let marks = this.marks; let createCell = (cColumn, wMax, hMax, marks) => { // Applying left/right padding to text let pad = cColumn.data.padding || { left: 0, right: 0 }; let lines = cColumn.text.split('\n').map(line => " ".repeat(pad.left) + line + " ".repeat(pad.right) ); let paddedText = lines.join('\n'); const totalWidth = wMax + pad.left + pad.right; return Box({ w: cColumn.data.w || cColumn.data.width || totalWidth, h: cColumn.data.h || cColumn.data.height || hMax, marks: marks }, { text: paddedText, stretch: cColumn.data.stretch, autoEOL: cColumn.data.autoEOL, vAlign: cColumn.data.vAlign, hAlign: cColumn.data.hAlign }).toString(); } // Compute cell sizes internally this.data.forEach((cRow, i) => { cellSizes.push([]); cRow.forEach(cColumn => { cell = createCell(cColumn, 1, 1, {}); splits = cell.split("\n"); let pad = cColumn.data.padding || { left: 0, right: 0 }; cCell = { w: splits[0].trim().length - pad.left - pad.right + pad.left + pad.right, h: splits.length - 2 }; cellSizes[i].push(cCell); }); }); // Each row this.data.forEach((cRow, i) => { // Compute row wMax = -1; hMax = -1; cellSizes[i].forEach(cCell => { if (cCell.h > hMax) { hMax = cCell.h; } }); // Each column from current row cRow.forEach((cColumn, ii) => { // Compute current column cellSizes.forEach((cCell, iii) => { cCell = cellSizes[iii][ii]; if (cCell.w > wMax) { wMax = cCell.w; } }); mrks = { nw: ((!i && !ii) ? marks.nw : (!i && ii < cRow.length) ? marks.mt : (!ii && i < this.data.length) ? marks.ml : marks.mm), n: marks.n, ne: (!i && ii === cRow.length - 1) ? marks.ne : marks.mr, e: marks.e, se: marks.se, s: marks.s, sw: (i === this.data.length - 1 && !ii) ? marks.sw : marks.mb, w: marks.w, b: " " }; // Add stringified cell to output output = Overlap({ who: output, with: createCell(cColumn, wMax, hMax, mrks), where: offset }); let pad = cColumn.data.padding || { left: 0, right: 0 }; offset.x += wMax + pad.left + pad.right + mrks.w.length - 2; }); offset.x = 0; offset.y += hMax + 1; }); let str = output.trim(); if (this.options.noAnsi) { str = ansiParser.removeAnsi(str); } return str; } } // Defaults LeTable.defaults = { marks: { nw: "┌", n: "─", ne: "┐", e: "│", se: "┘", s: "─", sw: "└", w: "│", b: " " , mt: "┬", ml: "├", mr: "┤", mb: "┴", mm: "┼" }, cell: { vAlign: "top", hAlign: "left", autoEOL: true, stretch: true, padding: { left: 0, right: 0 } } }; module.exports = LeTable;