diff --git a/README.md b/README.md index cfbac77..1004b28 100644 --- a/README.md +++ b/README.md @@ -167,6 +167,23 @@ console.log(table.toString()); //frobnicate bar quuz ``` +## Debugging + +Later versions of cli-table3 supporting debugging your table data. + +Enable and use debugging: + +``` +var table = new Table({ debug: 1 }); +table.push([{}, {},}); // etc. + +console.log(table.toString()); +table.messages.forEach((message) => console.log(message)); +``` + +If you are rendering multiple tables with debugging on run `Table.reset()` after +rendering each table. + ## Build Targets Clone the repository and run `yarn install` to install all its submodules, then run one of the following commands: diff --git a/src/cell.js b/src/cell.js index 2f39119..29abf09 100644 --- a/src/cell.js +++ b/src/cell.js @@ -1,3 +1,4 @@ +const { info, debug } = require('./debug'); const utils = require('./utils'); class Cell { @@ -111,6 +112,12 @@ class Cell { draw(lineNum, spanningCell) { if (lineNum == 'top') return this.drawTop(this.drawRight); if (lineNum == 'bottom') return this.drawBottom(this.drawRight); + let content = utils.truncate(this.content, 10, this.truncate); + if (!lineNum) { + info(`${this.y}-${this.x}: ${this.rowSpan - lineNum}x${this.colSpan} Cell ${content}`); + } else { + // debug(`${lineNum}-${this.x}: 1x${this.colSpan} RowSpanCell ${content}`); + } let padLen = Math.max(this.height - this.lines.length, 0); let padTop; switch (this.vAlign) { @@ -286,7 +293,10 @@ class ColSpanCell { */ constructor() {} - draw() { + draw(lineNum) { + if (typeof lineNum === 'number') { + debug(`${this.y}-${this.x}: 1x1 ColSpanCell`); + } return ''; } @@ -320,6 +330,7 @@ class RowSpanCell { if (lineNum == 'bottom') { return this.originalCell.draw('bottom'); } + debug(`${this.y}-${this.x}: 1x${this.colSpan} RowSpanCell for ${this.originalCell.content}`); return this.originalCell.draw(this.offset + 1 + lineNum); } diff --git a/src/debug.js b/src/debug.js new file mode 100644 index 0000000..6acfb03 --- /dev/null +++ b/src/debug.js @@ -0,0 +1,28 @@ +let messages = []; +let level = 0; + +const debug = (msg, min) => { + if (level >= min) { + messages.push(msg); + } +}; + +debug.WARN = 1; +debug.INFO = 2; +debug.DEBUG = 3; + +debug.reset = () => { + messages = []; +}; + +debug.setDebugLevel = (v) => { + level = v; +}; + +debug.warn = (msg) => debug(msg, debug.WARN); +debug.info = (msg) => debug(msg, debug.INFO); +debug.debug = (msg) => debug(msg, debug.DEBUG); + +debug.debugMessages = () => messages; + +module.exports = debug; diff --git a/src/layout-manager.js b/src/layout-manager.js index cb84d9e..2dc4960 100644 --- a/src/layout-manager.js +++ b/src/layout-manager.js @@ -1,3 +1,4 @@ +const { warn, debug } = require('./debug'); const Cell = require('./cell'); const { ColSpanCell, RowSpanCell } = Cell; @@ -126,6 +127,7 @@ const { ColSpanCell, RowSpanCell } = Cell; function fillInTable(table) { let h_max = maxHeight(table); let w_max = maxWidth(table); + debug(`Max rows: ${h_max}; Max cols: ${w_max}`); for (let y = 0; y < h_max; y++) { for (let x = 0; x < w_max; x++) { if (!conflictExists(table, x, y)) { @@ -140,10 +142,10 @@ const { ColSpanCell, RowSpanCell } = Cell; opts.rowSpan++; y2++; } - let cell = new Cell(opts); cell.x = opts.x; cell.y = opts.y; + warn(`Missing cell at ${cell.y}-${cell.x}.`); insertCell(cell, table[y]); } } diff --git a/src/table.js b/src/table.js index 4fb33ec..eb4a9bd 100644 --- a/src/table.js +++ b/src/table.js @@ -1,11 +1,38 @@ +const debug = require('./debug'); const utils = require('./utils'); const tableLayout = require('./layout-manager'); class Table extends Array { - constructor(options) { + constructor(opts) { super(); - this.options = utils.mergeOptions(options); + const options = utils.mergeOptions(opts); + Object.defineProperty(this, 'options', { + value: options, + enumerable: options.debug, + }); + + if (options.debug) { + switch (typeof options.debug) { + case 'boolean': + debug.setDebugLevel(debug.WARN); + break; + case 'number': + debug.setDebugLevel(options.debug); + break; + case 'string': + debug.setDebugLevel(parseInt(options.debug, 10)); + break; + default: + debug.setDebugLevel(debug.WARN); + debug.warn(`Debug option is expected to be boolean, number, or string. Received a ${typeof options.debug}`); + } + Object.defineProperty(this, 'messages', { + get() { + return debug.debugMessages(); + }, + }); + } } toString() { @@ -65,6 +92,8 @@ class Table extends Array { } } +Table.reset = () => debug.reset(); + function doDraw(row, lineNum, result) { let line = []; row.forEach(function (cell) { diff --git a/test/table-test.js b/test/table-test.js index 2cfa0ff..5ed490e 100644 --- a/test/table-test.js +++ b/test/table-test.js @@ -129,6 +129,41 @@ describe('@api Table ', function () { ]; expect(table.toString()).toEqual(expected.join('\n')); }); + describe('debugging', () => { + afterEach(() => Table.reset()); + it('is not accessible when disabled', () => { + let table = new Table(); + expect(table.messages).toBeUndefined(); + }); + it('warns of missing cells', () => { + let table = new Table({ debug: true }); + table.push([{ rowSpan: 2 }], [{}]); + table.toString(); + expect(table.messages).toEqual(['Missing cell at 0-1.']); + }); + it('provides cell info', () => { + let table = new Table({ debug: 2 }); + table.push(['a', 'b', { content: 'c', rowSpan: 2 }], [{ content: 'd', colSpan: 2 }]); + table.toString(); + expect(table.messages).toContain('0-0: 1x1 Cell a'); + expect(table.messages).toContain('0-1: 1x1 Cell b'); + expect(table.messages).toContain('0-2: 2x1 Cell c'); + expect(table.messages).toContain('1-0: 1x2 Cell d'); + }); + it('provides rowSpan and colSpan cell debug info', () => { + let table = new Table({ debug: 3 }); + table.push(['a', 'b', { content: 'c', rowSpan: 2 }], [{ content: 'd', colSpan: 2 }]); + table.toString(); + expect(table.messages).toContain('1-1: 1x1 ColSpanCell'); + expect(table.messages).toContain('1-2: 1x1 RowSpanCell for c'); + }); + it('provides debug info', () => { + let table = new Table({ debug: 3 }); + table.push([{}, {}], [{}, {}]); + table.toString(); + expect(table.messages).toContain('Max rows: 2; Max cols: 2'); + }); + }); }); /*