pax_global_header00006660000000000000000000000064126544524040014520gustar00rootroot0000000000000052 comment=57111fff6349df8e47a3776ff9ea994ea8917e40 cli-table2-0.2.0/000077500000000000000000000000001265445240400134355ustar00rootroot00000000000000cli-table2-0.2.0/.gitignore000066400000000000000000000001071265445240400154230ustar00rootroot00000000000000node_modules/ .idea/ coverage/ JasmineAdapter-1.1.2.js jasmine-1.1.0.jscli-table2-0.2.0/.travis.yml000066400000000000000000000002071265445240400155450ustar00rootroot00000000000000language: node_js node_js: - "0.10" - "0.11" after_script: - cat ./coverage/lcov.info | ./node_modules/coveralls/bin/coveralls.jscli-table2-0.2.0/README.md000066400000000000000000000171471265445240400147260ustar00rootroot00000000000000CLI Table 2 [![npm version](https://badge.fury.io/js/cli-table2.svg)](http://badge.fury.io/js/cli-table2) [![Build Status](https://travis-ci.org/jamestalmage/cli-table2.svg?branch=master)](https://travis-ci.org/jamestalmage/cli-table2) [![Coverage Status](https://coveralls.io/repos/jamestalmage/cli-table2/badge.png?branch=master)](https://coveralls.io/r/jamestalmage/cli-table2?branch=master) =========== This utility allows you to render unicode-aided tables on the command line from your node.js scripts. Based on (and api compatible with) the original [cli-table](https://github.com/Automattic/cli-table), `cli-table2` is nearly a complete rewrite to accommodate column and row spanning. It passes the entire original cli-table test suite, and should be a drop in replacement for nearly all users. ![Screenshot](http://i.imgur.com/sYq4T.png) ## Features not in the original cli-table - Ability to make cells span columns and/or rows. - Ability to set custom styles per cell (border characters/colors, padding, etc). - Vertical alignment (top, bottom, center). - Automatic word wrapping. - More robust truncation of cell text that contains ansi color characters. - Better handling of text color that spans multiple lines. - API compatible with the original cli-table. - Exhaustive test suite including the entire original cli-table test suite. - Lots of examples auto-generated from the tests ([basic](https://github.com/jamestalmage/cli-table2/blob/master/basic-usage.md), [advanced](https://github.com/jamestalmage/cli-table2/blob/master/advanced-usage.md)). ## Features - Customizable characters that constitute the table. - Color/background styling in the header through [colors.js](http://github.com/marak/colors.js) - Column width customization - Text truncation based on predefined widths - Text alignment (left, right, center) - Padding (left, right) - Easy-to-use API ## Installation ```bash npm install cli-table2 ``` ## How to use A portion of the unit test suite is used to generate examples: - [basic-usage](https://github.com/jamestalmage/cli-table2/blob/master/basic-usage.md) - covers basic uses. - [advanced](https://github.com/jamestalmage/cli-table2/blob/master/advanced-usage.md) - covers using the new column and row span features. This package is api compatible with the original [cli-table](https://github.com/Automattic/cli-table). So all the original documentation still applies (copied below). ### Horizontal Tables ```javascript var Table = require('cli-table2'); // instantiate var table = new Table({ head: ['TH 1 label', 'TH 2 label'] , colWidths: [100, 200] }); // table is an Array, so you can `push`, `unshift`, `splice` and friends table.push( ['First value', 'Second value'] , ['First value', 'Second value'] ); console.log(table.toString()); ``` ### Vertical Tables ```javascript var Table = require('cli-table2'); var table = new Table(); table.push( { 'Some key': 'Some value' } , { 'Another key': 'Another value' } ); console.log(table.toString()); ``` ### Cross Tables Cross tables are very similar to vertical tables, with two key differences: 1. They require a `head` setting when instantiated that has an empty string as the first header 2. The individual rows take the general form of { "Header": ["Row", "Values"] } ```javascript var Table = require('cli-table2'); var table = new Table({ head: ["", "Top Header 1", "Top Header 2"] }); table.push( { 'Left Header 1': ['Value Row 1 Col 1', 'Value Row 1 Col 2'] } , { 'Left Header 2': ['Value Row 2 Col 1', 'Value Row 2 Col 2'] } ); console.log(table.toString()); ``` ### Custom styles The ```chars``` property controls how the table is drawn: ```javascript var table = new Table({ chars: { 'top': '═' , 'top-mid': '╤' , 'top-left': '╔' , 'top-right': '╗' , 'bottom': '═' , 'bottom-mid': '╧' , 'bottom-left': '╚' , 'bottom-right': '╝' , 'left': '║' , 'left-mid': '╟' , 'mid': '─' , 'mid-mid': '┼' , 'right': '║' , 'right-mid': '╢' , 'middle': '│' } }); table.push( ['foo', 'bar', 'baz'] , ['frob', 'bar', 'quuz'] ); console.log(table.toString()); // Outputs: // //╔══════╤═════╤══════╗ //║ foo │ bar │ baz ║ //╟──────┼─────┼──────╢ //║ frob │ bar │ quuz ║ //╚══════╧═════╧══════╝ ``` Empty decoration lines will be skipped, to avoid vertical separator rows just set the 'mid', 'left-mid', 'mid-mid', 'right-mid' to the empty string: ```javascript var table = new Table({ chars: {'mid': '', 'left-mid': '', 'mid-mid': '', 'right-mid': ''} }); table.push( ['foo', 'bar', 'baz'] , ['frobnicate', 'bar', 'quuz'] ); console.log(table.toString()); // Outputs: (note the lack of the horizontal line between rows) //┌────────────┬─────┬──────┐ //│ foo │ bar │ baz │ //│ frobnicate │ bar │ quuz │ //└────────────┴─────┴──────┘ ``` By setting all chars to empty with the exception of 'middle' being set to a single space and by setting padding to zero, it's possible to get the most compact layout with no decorations: ```javascript var table = new Table({ chars: { 'top': '' , 'top-mid': '' , 'top-left': '' , 'top-right': '' , 'bottom': '' , 'bottom-mid': '' , 'bottom-left': '' , 'bottom-right': '' , 'left': '' , 'left-mid': '' , 'mid': '' , 'mid-mid': '' , 'right': '' , 'right-mid': '' , 'middle': ' ' }, style: { 'padding-left': 0, 'padding-right': 0 } }); table.push( ['foo', 'bar', 'baz'] , ['frobnicate', 'bar', 'quuz'] ); console.log(table.toString()); // Outputs: //foo bar baz //frobnicate bar quuz ``` ## Build Targets Clone the repository and run `npm install` to install all its submodules, then run one of the following commands: ###### Run the tests with coverage reports. ```bash $ gulp coverage ``` ###### Run the tests every time a file changes. ```bash $ gulp watch-test ``` ###### Run the examples and print the output to the command line. ```bash $ gulp example ``` Other build targets are available, check `gulpfile.js` for a comprehensive list. ## Credits - James Talmage - author <james.talmage@jrtechnical.com> ([jamestalmage](http://github.com/jamestalmage)) - Guillermo Rauch - author of the original cli-table <guillermo@learnboost.com> ([Guille](http://github.com/guille)) ## License (The MIT License) Copyright (c) 2014 James Talmage <james.talmage@jrtechnical.com> Original cli-table code/documentation: Copyright (c) 2010 LearnBoost <dev@learnboost.com> Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the 'Software'), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. cli-table2-0.2.0/advanced-usage.md000066400000000000000000000171711265445240400166350ustar00rootroot00000000000000##### use colSpan to span columns - (colSpan above normal cell) ┌───────────────┐ │ greetings │ ├───────────────┤ │ greetings │ ├───────┬───────┤ │ hello │ howdy │ └───────┴───────┘ ```javascript var table = new Table({style:{head:[],border:[]}}); table.push( [{colSpan:2,content:'greetings'}], [{colSpan:2,content:'greetings'}], ['hello','howdy'] ); ``` ##### use colSpan to span columns - (colSpan below normal cell) ┌───────┬───────┐ │ hello │ howdy │ ├───────┴───────┤ │ greetings │ ├───────────────┤ │ greetings │ └───────────────┘ ```javascript var table = new Table({style:{head:[],border:[]}}); table.push( ['hello','howdy'], [{colSpan:2,content:'greetings'}], [{colSpan:2,content:'greetings'}] ); ``` ##### use rowSpan to span rows - (rowSpan on the left side) ┌───────────┬───────────┬───────┐ │ greetings │ │ hello │ │ │ greetings ├───────┤ │ │ │ howdy │ └───────────┴───────────┴───────┘ ```javascript var table = new Table({style:{head:[],border:[]}}); table.push( [{rowSpan:2,content:'greetings'},{rowSpan:2,content:'greetings',vAlign:'center'},'hello'], ['howdy'] ); ``` ##### use rowSpan to span rows - (rowSpan on the right side) ┌───────┬───────────┬───────────┐ │ hello │ greetings │ │ ├───────┤ │ │ │ howdy │ │ greetings │ └───────┴───────────┴───────────┘ ```javascript var table = new Table({style:{head:[],border:[]}}); table.push( ['hello',{rowSpan:2,content:'greetings'},{rowSpan:2,content:'greetings',vAlign:'bottom'}], ['howdy'] ); ``` ##### mix rowSpan and colSpan together for complex table layouts ┌───────┬─────┬────┐ │ hello │ sup │ hi │ ├───────┤ │ │ │ howdy │ │ │ ├───┬───┼──┬──┤ │ │ o │ k │ │ │ │ └───┴───┴──┴──┴────┘ ```javascript var table = new Table({style:{head:[],border:[]}}); table.push( [{content:'hello',colSpan:2},{rowSpan:2, colSpan:2,content:'sup'},{rowSpan:3,content:'hi'}], [{content:'howdy',colSpan:2}], ['o','k','',''] ); ``` ##### multi-line content will flow across rows in rowSpan cells ┌───────┬───────────┬───────────┐ │ hello │ greetings │ greetings │ ├───────┤ friends │ friends │ │ howdy │ │ │ └───────┴───────────┴───────────┘ ```javascript var table = new Table({style:{head:[],border:[]}}); table.push( ['hello',{rowSpan:2,content:'greetings\nfriends'},{rowSpan:2,content:'greetings\nfriends'}], ['howdy'] ); ``` ##### multi-line content will flow across rows in rowSpan cells - (complex layout) ┌───────┬─────┬────┐ │ hello │ sup │ hi │ ├───────┤ man │ yo │ │ howdy │ hey │ │ ├───┬───┼──┬──┤ │ │ o │ k │ │ │ │ └───┴───┴──┴──┴────┘ ```javascript var table = new Table({style:{head:[],border:[]}}); table.push( [{content:'hello',colSpan:2},{rowSpan:2, colSpan:2,content:'sup\nman\nhey'},{rowSpan:3,content:'hi\nyo'}], [{content:'howdy',colSpan:2}], ['o','k','',''] ); ``` ##### rowSpan cells can have a staggered layout ┌───┬───┐ │ a │ b │ │ ├───┤ │ │ c │ ├───┤ │ │ d │ │ └───┴───┘ ```javascript var table = new Table({style:{head:[],border:[]}}); table.push( [{content:'a',rowSpan:2},'b'], [{content:'c',rowSpan:2}], ['d'] ); ``` ##### the layout manager automatically create empty cells to fill in the table ┌───┬───┬──┐ │ a │ b │ │ │ ├───┤ │ │ │ │ │ │ ├───┴──┤ │ │ c │ ├───┤ │ │ │ │ └───┴──────┘ ```javascript var table = new Table({style:{head:[],border:[]}}); //notice we only create 3 cells here, but the table ends up having 6. table.push( [{content:'a',rowSpan:3,colSpan:2},'b'], [], [{content:'c',rowSpan:2,colSpan:2}], [] ); ``` ##### use table `rowHeights` option to fix row height. The truncation symbol will be shown on the last line. ┌───────┐ │ hello │ │ hi… │ └───────┘ ```javascript var table = new Table({rowHeights:[2],style:{head:[],border:[]}}); table.push(['hello\nhi\nsup']); ``` ##### if `colWidths` is not specified, the layout manager will automatically widen rows to fit the content ┌─────────────┐ │ hello there │ ├──────┬──────┤ │ hi │ hi │ └──────┴──────┘ ```javascript var table = new Table({style:{head:[],border:[]}}); table.push( [{colSpan:2,content:'hello there'}], ['hi', 'hi'] ); ``` ##### you can specify a column width for only the first row, other rows will be automatically widened to fit content ┌─────────────┐ │ hello there │ ├────┬────────┤ │ hi │ hi │ └────┴────────┘ ```javascript var table = new Table({colWidths:[4],style:{head:[],border:[]}}); table.push( [{colSpan:2,content:'hello there'}], ['hi',{hAlign:'center',content:'hi'}] ); ``` ##### a column with a null column width will be automatically widened to fit content ┌─────────────┐ │ hello there │ ├────────┬────┤ │ hi │ hi │ └────────┴────┘ ```javascript var table = new Table({colWidths:[null, 4],style:{head:[],border:[]}}); table.push( [{colSpan:2,content:'hello there'}], [{hAlign:'right',content:'hi'}, 'hi'] ); ``` ##### feel free to use colors in your content strings, column widths will be calculated correctly ![table image](https://cdn.rawgit.com/jamestalmage/cli-table2/c806c2636df97f73c732b41aa913cf78d4ac0d39/examples/screenshots/truncation-with-colors.png) ```javascript var table = new Table({colWidths:[5],style:{head:[],border:[]}}); table.push([colors.red('hello')]); ``` cli-table2-0.2.0/basic-usage.md000066400000000000000000000137121265445240400161460ustar00rootroot00000000000000##### Basic Usage ![table image](https://cdn.rawgit.com/jamestalmage/cli-table2/c806c2636df97f73c732b41aa913cf78d4ac0d39/examples/screenshots/basic-usage-with-colors.png) ```javascript // By default, headers will be red, and borders will be grey var table = new Table({head:['a','b']}); table.push(['c','d']); ``` ##### Basic Usage - disable colors - (used often in the examples and tests) ┌──────┬─────────────────────┬─────────────────────────┬─────────────────┐ │ Rel │ Change │ By │ When │ ├──────┼─────────────────────┼─────────────────────────┼─────────────────┤ │ v0.1 │ Testing something … │ rauchg@gmail.com │ 7 minutes ago │ ├──────┼─────────────────────┼─────────────────────────┼─────────────────┤ │ v0.1 │ Testing something … │ rauchg@gmail.com │ 8 minutes ago │ └──────┴─────────────────────┴─────────────────────────┴─────────────────┘ ```javascript // For most of these examples, and most of the unit tests we disable colors. // It makes unit tests easier to write/understand, and allows these pages to // display the examples as text instead of screen shots. var table = new Table({ head: ['Rel', 'Change', 'By', 'When'] , style: { head: [] //disable colors in header cells , border: [] //disable colors for the border } , colWidths: [6, 21, 25, 17] //set the widths of each column (optional) }); table.push( ['v0.1', 'Testing something cool', 'rauchg@gmail.com', '7 minutes ago'] , ['v0.1', 'Testing something cool', 'rauchg@gmail.com', '8 minutes ago'] ); ``` ##### Create vertical tables by adding objects a that specify key-value pairs ┌────┬──────────────────────┐ │v0.1│Testing something cool│ ├────┼──────────────────────┤ │v0.1│Testing something cool│ └────┴──────────────────────┘ ```javascript var table = new Table({ style: {'padding-left':0, 'padding-right':0, head:[], border:[]} }); table.push( {'v0.1': 'Testing something cool'} , {'v0.1': 'Testing something cool'} ); ``` ##### Cross tables are similar to vertical tables, but include an empty string for the first header ┌────────┬────────┬──────────────────────┐ │ │Header 1│Header 2 │ ├────────┼────────┼──────────────────────┤ │Header 3│v0.1 │Testing something cool│ ├────────┼────────┼──────────────────────┤ │Header 4│v0.1 │Testing something cool│ └────────┴────────┴──────────────────────┘ ```javascript var table = new Table({ head: ["", "Header 1", "Header 2"], style: {'padding-left':0, 'padding-right':0, head:[], border:[]} }); // clear styles to prevent color output table.push( {"Header 3": ['v0.1', 'Testing something cool'] } , {"Header 4": ['v0.1', 'Testing something cool'] } ); ``` ##### Stylize the table with custom border characters ╔══════╤═════╤══════╗ ║ foo │ bar │ baz ║ ╟──────┼─────┼──────╢ ║ frob │ bar │ quuz ║ ╚══════╧═════╧══════╝ ```javascript var table = new Table({ chars: { 'top': '═' , 'top-mid': '╤' , 'top-left': '╔' , 'top-right': '╗' , 'bottom': '═' , 'bottom-mid': '╧' , 'bottom-left': '╚' , 'bottom-right': '╝' , 'left': '║' , 'left-mid': '╟' , 'right': '║' , 'right-mid': '╢' }, style: { head: [] , border: [] } }); table.push( ['foo', 'bar', 'baz'] , ['frob', 'bar', 'quuz'] ); ``` ##### Use ansi colors (i.e. colors.js) to style text within the cells at will, even across multiple lines ![table image](https://cdn.rawgit.com/jamestalmage/cli-table2/c806c2636df97f73c732b41aa913cf78d4ac0d39/examples/screenshots/multi-line-colors.png) ```javascript var table = new Table({style:{border:[],header:[]}}); table.push([ colors.red('Hello\nhow\nare\nyou?'), colors.blue('I\nam\nfine\nthanks!') ]); ``` ##### Set `wordWrap` to true to make lines of text wrap instead of being truncated ┌───────┬─────────┐ │ Hello │ I am │ │ how │ fine │ │ are │ thanks! │ │ you? │ │ └───────┴─────────┘ ```javascript var table = new Table({ style:{border:[],header:[]}, colWidths:[7,9], wordWrap:true }); table.push([ 'Hello how are you?', 'I am fine thanks!' ]); ``` cli-table2-0.2.0/examples/000077500000000000000000000000001265445240400152535ustar00rootroot00000000000000cli-table2-0.2.0/examples/.DS_Store000066400000000000000000000140041265445240400167350ustar00rootroot00000000000000Bud1 enshot screenshotsbwspblobbplist00  ]ShowStatusBar[ShowPathbar[ShowToolbar[ShowTabView_ContainerShowSidebar\WindowBounds\SidebarWidth[ShowSidebar  _{{878, 408}, {770, 460}} '3?Kbo| screenshotsvSrnlong  @ @ @ @ E DSDB ` @ @ @cli-table2-0.2.0/examples/basic-usage-examples.js000066400000000000000000000204651265445240400216170ustar00rootroot00000000000000var Table = require('../src/table'); var colors = require('colors/safe'); module.exports = function(runTest) { function it(name, fn) { var result = fn(); runTest(name, result[0], result[1], result[2]); } it('Basic Usage',function(){ function makeTable(){ // By default, headers will be red, and borders will be grey var table = new Table({head:['a','b']}); table.push(['c','d']); return table; } var expected = [ colors.gray('┌───') + colors.gray('┬───┐') , colors.gray('│') + colors.red(' a ') + colors.gray('│') + colors.red(' b ') + colors.gray('│') , colors.gray('├───') + colors.gray('┼───┤') , colors.gray('│') + (' c ') + colors.gray('│') + (' d ') + colors.gray('│') , colors.gray('└───') + colors.gray('┴───┘') ]; return [makeTable,expected,'basic-usage-with-colors']; }); it('Basic Usage - disable colors - (used often in the examples and tests)', function (){ function makeTable(){ // For most of these examples, and most of the unit tests we disable colors. // It makes unit tests easier to write/understand, and allows these pages to // display the examples as text instead of screen shots. var table = new Table({ head: ['Rel', 'Change', 'By', 'When'] , style: { head: [] //disable colors in header cells , border: [] //disable colors for the border } , colWidths: [6, 21, 25, 17] //set the widths of each column (optional) }); table.push( ['v0.1', 'Testing something cool', 'rauchg@gmail.com', '7 minutes ago'] , ['v0.1', 'Testing something cool', 'rauchg@gmail.com', '8 minutes ago'] ); return table; } var expected = [ '┌──────┬─────────────────────┬─────────────────────────┬─────────────────┐' , '│ Rel │ Change │ By │ When │' , '├──────┼─────────────────────┼─────────────────────────┼─────────────────┤' , '│ v0.1 │ Testing something … │ rauchg@gmail.com │ 7 minutes ago │' , '├──────┼─────────────────────┼─────────────────────────┼─────────────────┤' , '│ v0.1 │ Testing something … │ rauchg@gmail.com │ 8 minutes ago │' , '└──────┴─────────────────────┴─────────────────────────┴─────────────────┘' ]; return [makeTable,expected]; }); it('Create vertical tables by adding objects a that specify key-value pairs', function() { function makeTable(){ var table = new Table({ style: {'padding-left':0, 'padding-right':0, head:[], border:[]} }); table.push( {'v0.1': 'Testing something cool'} , {'v0.1': 'Testing something cool'} ); return table; } var expected = [ '┌────┬──────────────────────┐' , '│v0.1│Testing something cool│' , '├────┼──────────────────────┤' , '│v0.1│Testing something cool│' , '└────┴──────────────────────┘' ]; return [makeTable,expected]; }); it('Cross tables are similar to vertical tables, but include an empty string for the first header', function() { function makeTable(){ var table = new Table({ head: ["", "Header 1", "Header 2"], style: {'padding-left':0, 'padding-right':0, head:[], border:[]} }); // clear styles to prevent color output table.push( {"Header 3": ['v0.1', 'Testing something cool'] } , {"Header 4": ['v0.1', 'Testing something cool'] } ); return table; } var expected = [ '┌────────┬────────┬──────────────────────┐' , '│ │Header 1│Header 2 │' , '├────────┼────────┼──────────────────────┤' , '│Header 3│v0.1 │Testing something cool│' , '├────────┼────────┼──────────────────────┤' , '│Header 4│v0.1 │Testing something cool│' , '└────────┴────────┴──────────────────────┘' ]; return [makeTable,expected]; }); it('Stylize the table with custom border characters', function (){ function makeTable(){ var table = new Table({ chars: { 'top': '═' , 'top-mid': '╤' , 'top-left': '╔' , 'top-right': '╗' , 'bottom': '═' , 'bottom-mid': '╧' , 'bottom-left': '╚' , 'bottom-right': '╝' , 'left': '║' , 'left-mid': '╟' , 'right': '║' , 'right-mid': '╢' }, style: { head: [] , border: [] } }); table.push( ['foo', 'bar', 'baz'] , ['frob', 'bar', 'quuz'] ); return table; } var expected = [ '╔══════╤═════╤══════╗' , '║ foo │ bar │ baz ║' , '╟──────┼─────┼──────╢' , '║ frob │ bar │ quuz ║' , '╚══════╧═════╧══════╝' ]; return [makeTable,expected]; }); it('Use ansi colors (i.e. colors.js) to style text within the cells at will, even across multiple lines',function(){ function makeTable(){ var table = new Table({style:{border:[],header:[]}}); table.push([ colors.red('Hello\nhow\nare\nyou?'), colors.blue('I\nam\nfine\nthanks!') ]); return table; } var expected = [ '┌───────┬─────────┐' , '│ ' + colors.red('Hello') + ' │ ' + colors.blue('I') + ' │' , '│ ' + colors.red('how') + ' │ ' + colors.blue('am') + ' │' , '│ ' + colors.red('are') + ' │ ' + colors.blue('fine') + ' │' , '│ ' + colors.red('you?') + ' │ ' + colors.blue('thanks!') + ' │' , '└───────┴─────────┘' ]; return [makeTable,expected,'multi-line-colors']; }); it('Set `wordWrap` to true to make lines of text wrap instead of being truncated',function(){ function makeTable(){ var table = new Table({ style:{border:[],header:[]}, colWidths:[7,9], wordWrap:true }); table.push([ 'Hello how are you?', 'I am fine thanks!' ]); return table; } var expected = [ '┌───────┬─────────┐' , '│ Hello │ I am │' , '│ how │ fine │' , '│ are │ thanks! │' , '│ you? │ │' , '└───────┴─────────┘' ]; return [makeTable,expected]; }); }; /* Expectation - ready to be copy/pasted and filled in. DO NOT DELETE THIS var expected = [ '┌──┬───┬──┬──┐' , '│ │ │ │ │' , '├──┼───┼──┼──┤' , '│ │ … │ │ │' , '├──┼───┼──┼──┤' , '│ │ … │ │ │' , '└──┴───┴──┴──┘' ]; */cli-table2-0.2.0/examples/col-and-row-span-examples.js000066400000000000000000000243641265445240400225170ustar00rootroot00000000000000var Table = require('../src/table'); var colors = require('colors/safe'); module.exports = function(runTest) { function it(name,fn) { var result = fn(); runTest(name,result[0],result[1],result[2]); } it('use colSpan to span columns - (colSpan above normal cell)',function(){ function makeTable(){ var table = new Table({style:{head:[],border:[]}}); table.push( [{colSpan:2,content:'greetings'}], [{colSpan:2,content:'greetings'}], ['hello','howdy'] ); return table; } var expected = [ '┌───────────────┐' , '│ greetings │' , '├───────────────┤' , '│ greetings │' , '├───────┬───────┤' , '│ hello │ howdy │' , '└───────┴───────┘' ]; return [makeTable,expected]; }); it('use colSpan to span columns - (colSpan below normal cell)',function(){ function makeTable(){ var table = new Table({style:{head:[],border:[]}}); table.push( ['hello','howdy'], [{colSpan:2,content:'greetings'}], [{colSpan:2,content:'greetings'}] ); return table; } var expected = [ '┌───────┬───────┐' , '│ hello │ howdy │' , '├───────┴───────┤' , '│ greetings │' , '├───────────────┤' , '│ greetings │' , '└───────────────┘' ]; return [makeTable,expected]; }); it('use rowSpan to span rows - (rowSpan on the left side)',function(){ function makeTable(){ var table = new Table({style:{head:[],border:[]}}); table.push( [{rowSpan:2,content:'greetings'},{rowSpan:2,content:'greetings',vAlign:'center'},'hello'], ['howdy'] ); return table; } var expected = [ '┌───────────┬───────────┬───────┐' , '│ greetings │ │ hello │' , '│ │ greetings ├───────┤' , '│ │ │ howdy │' , '└───────────┴───────────┴───────┘' ]; return [makeTable,expected]; }); it('use rowSpan to span rows - (rowSpan on the right side)',function(){ function makeTable(){ var table = new Table({style:{head:[],border:[]}}); table.push( ['hello',{rowSpan:2,content:'greetings'},{rowSpan:2,content:'greetings',vAlign:'bottom'}], ['howdy'] ); return table; } var expected = [ '┌───────┬───────────┬───────────┐' , '│ hello │ greetings │ │' , '├───────┤ │ │' , '│ howdy │ │ greetings │' , '└───────┴───────────┴───────────┘' ]; return[makeTable,expected]; }); it('mix rowSpan and colSpan together for complex table layouts',function(){ function makeTable(){ var table = new Table({style:{head:[],border:[]}}); table.push( [{content:'hello',colSpan:2},{rowSpan:2, colSpan:2,content:'sup'},{rowSpan:3,content:'hi'}], [{content:'howdy',colSpan:2}], ['o','k','',''] ); return table; } var expected = [ '┌───────┬─────┬────┐' , '│ hello │ sup │ hi │' , '├───────┤ │ │' , '│ howdy │ │ │' , '├───┬───┼──┬──┤ │' , '│ o │ k │ │ │ │' , '└───┴───┴──┴──┴────┘' ]; return [makeTable,expected]; }); it('multi-line content will flow across rows in rowSpan cells',function(){ function makeTable(){ var table = new Table({style:{head:[],border:[]}}); table.push( ['hello',{rowSpan:2,content:'greetings\nfriends'},{rowSpan:2,content:'greetings\nfriends'}], ['howdy'] ); return table; } var expected = [ '┌───────┬───────────┬───────────┐' , '│ hello │ greetings │ greetings │' , '├───────┤ friends │ friends │' , '│ howdy │ │ │' , '└───────┴───────────┴───────────┘' ]; return [makeTable, expected]; }); it('multi-line content will flow across rows in rowSpan cells - (complex layout)',function(){ function makeTable(){ var table = new Table({style:{head:[],border:[]}}); table.push( [{content:'hello',colSpan:2},{rowSpan:2, colSpan:2,content:'sup\nman\nhey'},{rowSpan:3,content:'hi\nyo'}], [{content:'howdy',colSpan:2}], ['o','k','',''] ); return table; } var expected = [ '┌───────┬─────┬────┐' , '│ hello │ sup │ hi │' , '├───────┤ man │ yo │' , '│ howdy │ hey │ │' , '├───┬───┼──┬──┤ │' , '│ o │ k │ │ │ │' , '└───┴───┴──┴──┴────┘' ]; return [makeTable,expected]; }); it('rowSpan cells can have a staggered layout',function(){ function makeTable(){ var table = new Table({style:{head:[],border:[]}}); table.push( [{content:'a',rowSpan:2},'b'], [{content:'c',rowSpan:2}], ['d'] ); return table; } var expected = [ '┌───┬───┐' , '│ a │ b │' , '│ ├───┤' , '│ │ c │' , '├───┤ │' , '│ d │ │' , '└───┴───┘' ]; return [makeTable,expected]; }); it('the layout manager automatically create empty cells to fill in the table',function(){ function makeTable(){ var table = new Table({style:{head:[],border:[]}}); //notice we only create 3 cells here, but the table ends up having 6. table.push( [{content:'a',rowSpan:3,colSpan:2},'b'], [], [{content:'c',rowSpan:2,colSpan:2}], [] ); return table; } var expected = [ '┌───┬───┬──┐' , '│ a │ b │ │' // top-right and bottom-left cells are automatically created to fill the empty space , '│ ├───┤ │' , '│ │ │ │' , '│ ├───┴──┤' , '│ │ c │' , '├───┤ │' , '│ │ │' , '└───┴──────┘' ]; return [makeTable,expected]; }); it('use table `rowHeights` option to fix row height. The truncation symbol will be shown on the last line.',function(){ function makeTable(){ var table = new Table({rowHeights:[2],style:{head:[],border:[]}}); table.push(['hello\nhi\nsup']); return table; } var expected = [ '┌───────┐' , '│ hello │' , '│ hi… │' , '└───────┘' ]; return [makeTable,expected]; }); it('if `colWidths` is not specified, the layout manager will automatically widen rows to fit the content',function(){ function makeTable(){ var table = new Table({style:{head:[],border:[]}}); table.push( [{colSpan:2,content:'hello there'}], ['hi', 'hi'] ); return table; } var expected = [ '┌─────────────┐' , '│ hello there │' , '├──────┬──────┤' , '│ hi │ hi │' , '└──────┴──────┘' ]; return [makeTable,expected]; }); it('you can specify a column width for only the first row, other rows will be automatically widened to fit content',function(){ function makeTable(){ var table = new Table({colWidths:[4],style:{head:[],border:[]}}); table.push( [{colSpan:2,content:'hello there'}], ['hi',{hAlign:'center',content:'hi'}] ); return table; } var expected = [ '┌─────────────┐' , '│ hello there │' , '├────┬────────┤' , '│ hi │ hi │' , '└────┴────────┘' ]; return [makeTable, expected]; }); it('a column with a null column width will be automatically widened to fit content',function(){ function makeTable(){ var table = new Table({colWidths:[null, 4],style:{head:[],border:[]}}); table.push( [{colSpan:2,content:'hello there'}], [{hAlign:'right',content:'hi'}, 'hi'] ); return table; } var expected = [ '┌─────────────┐' , '│ hello there │' , '├────────┬────┤' , '│ hi │ hi │' , '└────────┴────┘' ]; return [makeTable,expected]; }); it('feel free to use colors in your content strings, column widths will be calculated correctly',function(){ function makeTable(){ var table = new Table({colWidths:[5],style:{head:[],border:[]}}); table.push([colors.red('hello')]); return table; } var expected = [ '┌─────┐' , '│ ' + colors.red('he') + '… │' , '└─────┘' ]; return [makeTable,expected,'truncation-with-colors']; }); }; /* var expected = [ '┌──┬───┬──┬──┐' , '│ │ │ │ │' , '├──┼───┼──┼──┤' , '│ │ … │ │ │' , '├──┼───┼──┼──┤' , '│ │ … │ │ │' , '└──┴───┴──┴──┘' ]; */cli-table2-0.2.0/examples/screenshots/000077500000000000000000000000001265445240400176135ustar00rootroot00000000000000cli-table2-0.2.0/examples/screenshots/basic-usage-with-colors.png000066400000000000000000000141711265445240400247600ustar00rootroot00000000000000PNG  IHDR4 EiCCPICC ProfileH WwXS 0eO[P)AH #@Pq+VEZԁۢEAŁ ߹aاO>9}sOд幸@P̟go0 Aqq1כQƫTtwH\ 9CT Cg#+ h-Q(p'º $Ra:RR@`E'"a!$IeF_( s QyyDl3'oX )d \ sT?]^Ku-QDƣ.Ɯf#_1!aHpD0.,A¯Ehp2')h[ `iaT NVLgr'PHQCB\xΔG!X0҉7I' A '@ŹR, xBOiD|g"T s@,}ĻJ#1"qh$,iP!Sq(byj~#D87^P04t"Q݈قq|E8&w! |P!׀%, 34"Ee>O!q*i*kjD5RN~H?NHCp$P&AdCգT+}P݇(8s9*2Bor"'-q8C Gzlj"qƒU~Z9(鐏SSǡ_ù C)♅hAt,4KRB%wqrvtOVc_&2P)X~ }x>G/ ?п&2 ,  !K s`!B956?#pN  z a40.fbVyaXcX:0%6[cl+VN`66^bpg㺸1n <OħYx>^ux5Ox; %P'xHx!D,Fd bQFT^D;M'$䓎h~FI'K .l!3MfDsТhhYRZ%mv:hot:nCDf*=>Do?2 Ï0 =+;:Ӕ g1eEJn1fZHmrjj:X,+ZZ:źzn>Q]@}~߳udľ~aQLF}w.g4'#Tq8W85444jkVjԼ٭e%КUuXV6WY;V;O{nsڝ: k0N6:ׂrssOq;t6Qٺ?%ԫ;#xּ(^.o9A##;ʈ#e047gHN4aaHݑ##Fndoo4hE^ccz&<@l&LLRզMA\:~ ,Liլլ<|>{, /L=-XZffe%Zkuꭵu7֝66Q666wm5llmmr6]%Up&QQޣdGtd;99:>3zXIr̙1ܝr;qqȹХ嚫k|nnbnܹݿqovi󦗮WR4`Gx7woX>3mk` xh( $.(;hO``E!>!sCBЈв0 aók{"#fG4E"#WFތ2FD7w\K4;:!zCELx|ߝ`5A6>bbWދˏe"}bĪğI&LK؝&18qy$$eRsf)))L;Ba4!#|1}rSl̜rnܩGiNL;NKOIߝQ+fDel EE]b?qI_fEfg_֪.IR- nȎޒ6'6ggNnJΗ;W\*\z;}׿,sYrWWVXrWvEqţUWխ.[zʹ5**eUm_a?nl^\o%nm9p-[ʷ|^[몭+ѷm{=y~a|ǧwx6ڽUv홼?6uܻuo_~دn>|ޟ~x{US/ooHmh;Lxxѳ? QXq'5.G».?i3?ugRO ŋK_uso\7yoޖ3x3R> 136 136 mF 1IDATxmL[ǯ`X o!b,J ƤD"k)j4>@Ĕjiِar5NQ"mhM:',%Y uL 1ؼcs{~ {sW0 .::X9 mg+r&Xs:݁0j)?/:VەC+c_}߾}?o2·e@?>dZUF)z-r-~ϊjίa,% 'LW0Tt;E1hRqD"0$0] ]?EC0ԬZ4CJ ]?EC0ԬZ4CJx,/Vtk-u)ڠ =K+H&uYN}EFH.ueIg %ǀ(A%; [C)a!-J}{~ ^A1B'}WY`nqf ^4*0p@= |B} ӧ7;cFyXk0063R L|IެRa(U7w!LRFx&B%$U`|0<0`"b~gah{l9fRa ~ޥ?\ h {E(<#3㋳'F-'Xou]O\2ѾŢ|6m2p d*PD 9ֻp@2= 㨄J rBU{c/#L i*6/-ܥQg` ry8$r][,1iأGS.K 0d+,DOkUhU#W0Ũ}+7܋AFd§}A([~uy1f:ggK|8)i(RmL@ kI<;WB:Zz^=JdM&]z5lшJ b,3hwyz%/K)0Qr#SR¦HOoKJ'. %軗tQE `"㲬UO)<3 ^fdo+4mknϙK9}kQKTvL MVi0Z%<. xo=.9hgtw֑#ǜ#ܙ"\{afwHx8Xwa+1l5_Gr%{Pg3l!M=qa\`<ˋVN-8 0\.w^l:vL3: eE0"E`H,*nu%"}t15uarsɸ"="rP'/WyF)uI)m`DHeaA0"u@ : RYcH,1R'|BtMY<˓NLUDl~S`$Nj`6m/KV^Q`9QF%nsL"JG'^IR3_*:y͎$#9󥢓 P&9󥢓@D=nCyT`H\ t* KA0NR%!qI<`rq|r\R<)h;plk +BW}ǰ]>sZs}2 a}uxjדgz `ӃM;B]gik}AaagyﵶtjVcdwЖbLEAM\,VmpƖt*G7 eYoJnU`D : RY=&C:~)cL (?yБQ2qd@`r&U L\(`LΤ ke əT`2q 09*L&A0&gR̙/$Ke|F*sKE' ̟G\0̭w9}sOд幸@P̟go0 Aqq1כQƫTtwH\ 9CT Cg#+ h-Q(p'º $Ra:RR@`E'"a!$IeF_( s QyyDl3'oX )d \ sT?]^Ku-QDƣ.Ɯf#_1!aHpD0.,A¯Ehp2')h[ `iaT NVLgr'PHQCB\xΔG!X0҉7I' A '@ŹR, xBOiD|g"T s@,}ĻJ#1"qh$,iP!Sq(byj~#D87^P04t"Q݈قq|E8&w! |P!׀%, 34"Ee>O!q*i*kjD5RN~H?NHCp$P&AdCգT+}P݇(8s9*2Bor"'-q8C Gzlj"qƒU~Z9(鐏SSǡ_ù C)♅hAt,4KRB%wqrvtOVc_&2P)X~ }x>G/ ?п&2 ,  !K s`!B956?#pN  z a40.fbVyaXcX:0%6[cl+VN`66^bpg㺸1n <OħYx>^ux5Ox; %P'xHx!D,Fd bQFT^D;M'$䓎h~FI'K .l!3MfDsТhhYRZ%mv:hot:nCDf*=>Do?2 Ï0 =+;:Ӕ g1eEJn1fZHmrjj:X,+ZZ:źzn>Q]@}~߳udľ~aQLF}w.g4'#Tq8W85444jkVjԼ٭e%КUuXV6WY;V;O{nsڝ: k0N6:ׂrssOq;t6Qٺ?%ԫ;#xּ(^.o9A##;ʈ#e047gHN4aaHݑ##Fndoo4hE^ccz&<@l&LLRզMA\:~ ,Liլլ<|>{, /L=-XZffe%Zkuꭵu7֝66Q666wm5llmmr6]%Up&QQޣdGtd;99:>3zXIr̙1ܝr;qqȹХ嚫k|nnbnܹݿqovi󦗮WR4`Gx7woX>3mk` xh( $.(;hO``E!>!sCBЈв0 aók{"#fG4E"#WFތ2FD7w\K4;:!zCELx|ߝ`5A6>bbWދˏe"}bĪğI&LK؝&18qy$$eRsf)))L;Ba4!#|1}rSl̜rnܩGiNL;NKOIߝQ+fDel EE]b?qI_fEfg_֪.IR- nȎޒ6'6ggNnJΗ;W\*\z;}׿,sYrWWVXrWvEqţUWխ.[zʹ5**eUm_a?nl^\o%nm9p-[ʷ|^[몭+ѷm{=y~a|ǧwx6ڽUv홼?6uܻuo_~دn>|ޟ~x{US/ooHmh;Lxxѳ? QXq'5.G».?i3?ugRO ŋK_uso\7yoޖ3x3R> 272 168 "$IDATx} pיn{g43i !"V0ze7qp]galau])'ލ_lw㻸qn` Z^ldHIHѼ5﹧_34.y;  D"@ D"@ D"317|/$HIih C#|UCyH ~F|-OK@#pokO8_A! S3CNz %zdtƌ.y©+Fq {9izIfBx?6n5@<ǎT+/KF%! j19ltDta8D`! ZwN@ >x! ZwN@ >x! ZwN@ >x! ZwN@ >x!0)ep/4\R_gQ`-h(#aBT _)D@< bqF D~"V\,w'4[e$ -$ xJs%JIN IY_52$B񜮙oZo1i8E˚}q+ 8w ˱lxP =-1Ch}$*L-Q{,ݏxGz``0%iW7+^5'xb$EǴ:rB$   @-@^El.m6SB hr=fL8tjt|~( 5 fZhF"9ns2e S0xb)2=f ?5Wwo⎉j G iN-jp$|j{vpfPjs!("!ހGf/+WO gK cw $A(s.znW:k6HN/XY?6>H[}T}5l*lkkULs^ V S<Ӡ'̰z#Ҍ8[,΀ݠ gޫ߀]uf:`ՠt_\9ӧ2BqRle{IȱRic WXa,v@%%#qOQPQt]:#Ԣb &-pӟ"5V|J [p&@)}mx_Wv _q5 L=cj@E"PHruY'1iˉy&Lxjl;d?Ty zK~4ܼT.*rg"c2tWV? Jv5vze*95J#a)N$^B)&w8a)#ĭubǵϼŰ' }>J^8V;3CFIe7:gaI*20g>d >aL !g89:?\#JJYѨ;p'Lknoze9h6?a6wu$6ko梙Ϛ_ ,!l&E9&9T+H^5uWVa&%+.Yɢ $ <dB&:D H@!D  MtjzVE*R$I6y7Prl`y AU~#2#0.Y ;;G},F%XCAgL?[=c;M+H1C^,MR cC~Q Tw}M-rNqYĤҤCTa)PQ3;OKnD%Go5JQ^A{Yb;ј!ھ2x憎̭mp ] R&t|d 05!=L7=5އ[mY+c]ݓP{I\?!q  PpC)h%t8h_NDBt=0h$ݳ_s a cu2 y'2ݧWCڀWwNfﲚZVFQL1P~ޛ)&WIFU Ɏ.W|TcX'CwMk+H!2D( $ v3rkoxV Ki ,4cU„" ݰf D`0h;/)XGˈ=g9blL?z8"\SiŪz1j$jQ#Y%Ld̆6K%xxykj;&Tr+k+ S|q5To{D[=tU]zcĦM+PE>Z ?PV(1wFt![<q0Zjgx,d$JeR=zR \? ߿iO%>cPD>Z~'_Ə,ɑC;TH[]_]{0Q<)ab~%ٝ4 ~lx p3|b&`;f:U׶ uץNl9yn,ɵ`V@Eȧ/!J<;/ep]?Sj%KVNK!@O,ر<7ą82BL+\X'L.]0 z{ 17}֓/L~&NX^q"r}nUK_h ڈpYa{s$k$bD`Gaѥ$LxGaѥ@FdS2/ί?ҳQFdS2'3WQFdS2jjē-+[e$L<`@"}ҟG%zԶv1P!=M,깭--fovh,$LXq3f5dwEbXjN&R&`;0cŘ(PqQ2"B@aã\)nƓ5??Kaꤳf~&Y09(rt/y]qõ)X"LAZE* -F6O:+ wh/0O})*F_:/O/~#v]t`V 'c?m?kܰڼ&h\@#L +gꌳ8d>fv'o!,ƍhtj :2KMrVTy2M3æCf }{Zj0n>;bzDFh6iR4YI+T315 ${;B/m_7Yc'$Rt$ Uu#u2oqF%"ȟ4l͉j9z'^~Yü30.fج/ߙ~m4N{~H~1 NorB>C,ME1-M,24HM\ Дڈ4'A'1S}G_a"rgpkhU\@i?7 ,whԷM䘮RKGN$Ca*pFt}v@0 ɉT_>/@Ci:KČ6av/k'5X:b ;˫Ȓbp`h<!X7%SSdI)ʶog0bl 7]& ̋""ٶJ}OH%Bb  8nנwg[K!r:u> 3 ĭ=Z\%5i@}#t"uF0Pp8F^H7P8N LR-q)/XQ k%m]L[36Cɨ]W>z#~{ IIS@ O?3Cɫ-XN8dNT &= (fl~l˰]6=3LI䎋X{$x߹fGݕ23Fݡ~ Nbr:?c}F S{_d R=v1D]{> #vױqI"%XK|׹`(©qqSV\bW` H0eьl! Ұ@ #a),V"XT6HlJhӂM~gkɦdsB'#5(#aRe  Hy#+pIwu2žK9\Y3t{|$NϿ'fzM CS(}Hs9F"5OK).  ʗub@U_y߽5A B$EF6(AD^k& TV+`LP#mQYh8nc5m\ݒ5P ~c-(5߬n3jU0JM}LM(HyC _= Z$mF[5xo5(/b^8X[ ˂ yo~筶:[H`GK(-lz H yolTDd07V뱯#WG'@:B>7cxqy 1CP g-? bX1¿}K&TvkLf!{ #0-c)pDDz _3ߥkRpWM+4uT2ag[? a$xRg2~hf1,701/ƹ5 H"bv%MSFeuQ/:uKJbɶVdD#a0SL*n+#~b骷#|M˱V9A=D 4&aj\#no1ɚݫU%@xh|}t?~F~:q]~j⺋ bl fghW.w4SAݿ!8F:t̜+ƉEJbKt>cuII^l%D ĈFL)2EǗ'~E{}w:z5 iiiC{g678ٲbKƕK[o;(+:Rl8~w`2e359t`nUFwijU3ѓgX!Fw/HJglZTXliť3@GcȷzB?b+ ޙ^,Hvg[>V]J i5ϖ'-*6ڻIV/_Ptnq^B%?齒^CN<~Mw=eɮI` wK=OʚPT[֒l.^dF L1vʅ ,/= 0ד jT5#Nڵ("1Y 7Mêp/ZAz|ިll`-8Yi%g'rSi.ٮEkEQ̫VK'V}dhĥ(1.ߺy#x\; 26DVD8&?_259I -?y쾍.oYGȜPW$:pOlEsx6 ՚֌3}6ږ&.?5'60yVgXWTSŖ TݼX kB&E>dF라8_|3KdwՐG*~5+ K;'H6r謔&Nc1<2|GVig*j°.mdE[I[k/>a~p>T69+16~;cU=ˌ^`)6~!%2aO[$uly]?p^?vyֆE5Fpx:DZ$mXMxVĒg+XfA9-"[Z|ddWS.Z~Oߴos 2b1vQp]`'N!0b΁UP9X*"D_a9k_3kۅy_҃sx).k}*X|͑+rQPvx??KQ °vo uM:ADZ!otd'iM+c}  wp*TyGW}W^[& SK89-'8شry7 L܄CI;AL"`@ P6~w k}#kDr(uMoz n˷i_%v#s9m_9!5& 6k/y'hQ@|c ~S{E}<3ߺ=*x HF#o h"cRv-F)zB@Og |j&W87#co䝨` lǧݚ}I Vj;O~!m˂A 3+Ѩ7h316*ˀVDhoF0?@`0Nˎ"ElE5kdVΦdΚeRē 2&9- !jTdkɦd@gzlr&[e$ W*pH$)fFrH$)fFrH$)fFrH$)fFrH$)fFr sޒFn3Rmœ1[)駱F΀RN9cP# +cWHb&BtJI]@NPك+HwgadӓO.A$nRb=2:Jf@Ƅ(e<)^!޻FfYD"@ D"@ D"dC|CIENDB`cli-table2-0.2.0/examples/screenshots/truncation-with-colors.png000066400000000000000000000116321265445240400247620ustar00rootroot00000000000000PNG  IHDRjH' EiCCPICC ProfileH WwXS 0eO[P)AH #@Pq+VEZԁۢEAŁ ߹aاO>9}sOд幸@P̟go0 Aqq1כQƫTtwH\ 9CT Cg#+ h-Q(p'º $Ra:RR@`E'"a!$IeF_( s QyyDl3'oX )d \ sT?]^Ku-QDƣ.Ɯf#_1!aHpD0.,A¯Ehp2')h[ `iaT NVLgr'PHQCB\xΔG!X0҉7I' A '@ŹR, xBOiD|g"T s@,}ĻJ#1"qh$,iP!Sq(byj~#D87^P04t"Q݈قq|E8&w! |P!׀%, 34"Ee>O!q*i*kjD5RN~H?NHCp$P&AdCգT+}P݇(8s9*2Bor"'-q8C Gzlj"qƒU~Z9(鐏SSǡ_ù C)♅hAt,4KRB%wqrvtOVc_&2P)X~ }x>G/ ?п&2 ,  !K s`!B956?#pN  z a40.fbVyaXcX:0%6[cl+VN`66^bpg㺸1n <OħYx>^ux5Ox; %P'xHx!D,Fd bQFT^D;M'$䓎h~FI'K .l!3MfDsТhhYRZ%mv:hot:nCDf*=>Do?2 Ï0 =+;:Ӕ g1eEJn1fZHmrjj:X,+ZZ:źzn>Q]@}~߳udľ~aQLF}w.g4'#Tq8W85444jkVjԼ٭e%КUuXV6WY;V;O{nsڝ: k0N6:ׂrssOq;t6Qٺ?%ԫ;#xּ(^.o9A##;ʈ#e047gHN4aaHݑ##Fndoo4hE^ccz&<@l&LLRզMA\:~ ,Liլլ<|>{, /L=-XZffe%Zkuꭵu7֝66Q666wm5llmmr6]%Up&QQޣdGtd;99:>3zXIr̙1ܝr;qqȹХ嚫k|nnbnܹݿqovi󦗮WR4`Gx7woX>3mk` xh( $.(;hO``E!>!sCBЈв0 aók{"#fG4E"#WFތ2FD7w\K4;:!zCELx|ߝ`5A6>bbWދˏe"}bĪğI&LK؝&18qy$$eRsf)))L;Ba4!#|1}rSl̜rnܩGiNL;NKOIߝQ+fDel EE]b?qI_fEfg_֪.IR- nȎޒ6'6ggNnJΗ;W\*\z;}׿,sYrWWVXrWvEqţUWխ.[zʹ5**eUm_a?nl^\o%nm9p-[ʷ|^[몭+ѷm{=y~a|ǧwx6ڽUv홼?6uܻuo_~دn>|ޟ~x{US/ooHmh;Lxxѳ? QXq'5.G».?i3?ugRO ŋK_uso\7yoޖ3x3R> 106 72 SIDATx}h[Uo{4{M6@GWtM'8lXQ,lAtsJv *ҁC*:Wa ,0躤nfԤGz^>^o]^{!9=*] %)Ԑ%P|Xy@Q|XiQ|Xiac?{FcUN8/\yXV&m[wn]R+ePEk/Gr 6=?! 7nmZ([Pf%?jjgBgn<(Ğ/:h6RUODa F%`D$t:<%7Jò"r'f!K#9Νwx8u=p u]׋ՕDaΉswݙnz_8?NgN'?w#O9WwDا;zzSIgs_eE3NڽķMGvc?#?y#JHeMv]~HŌwNo"`xG<?q#>]>㏆gj^GfG6Xqخ;`sZB>ٝQFhضily x+ApF&X9hY.G8x~]pu,HVU|,, p,JUM}ߘo Φoߓ>?=qU :cX`H҄K2"mQ|X)S8r5V;2(WxR; yx,Sk9.y/JW2````+>-XQߘMMA;K_g␋(|SRM 5 KT@|2PסC}%u?&ɥNԮ oj۷|4/D KPpXʔ71sf@ >o 4IENDB`cli-table2-0.2.0/gulpfile.js000066400000000000000000000037631265445240400156130ustar00rootroot00000000000000var gulp = require('gulp'); var gutil = require('gulp-util'); var mocha = require('gulp-mocha'); var istanbul = require('gulp-istanbul'); var printExample = require('./lib/print-example'); var _ = require('lodash'); gulp.task('test',mochaTask); gulp.task('coverage',coverage()); gulp.task('coverage-api',coverage({grep:'@api'})); gulp.task('watch-test',function(){ gulp.watch(['test/**','src/**','examples/**'],['test']); mochaTask(); }); gulp.task('example',function(){ printExample.logExample(require('./examples/basic-usage-examples')); printExample.logExample(require('./examples/col-and-row-span-examples')); }); /** * Do NOT run this in the same commit when you are adding images. * Commit the images, then run this. */ gulp.task('example-md',['example-md-basic','example-md-advanced']); gulp.task('example-md-basic',function(cb){ printExample.mdExample(require('./examples/basic-usage-examples'),'basic-usage.md',cb); }); gulp.task('example-md-advanced',function(cb){ printExample.mdExample(require('./examples/col-and-row-span-examples'),'advanced-usage.md',cb); }); function coverage(opts){ opts = opts || {}; function coverageTask(cb){ gulp.src(['src/*.js']) .pipe(istanbul()) // Covering files .pipe(istanbul.hookRequire()) // Force `require` to return covered files .on('error', logMochaError) .on('finish', function () { gulp.src(['test/*.js']) .pipe(mocha(opts)) .on('error',function(err){ logMochaError(err); if(cb) cb(err); }) .pipe(istanbul.writeReports()) // Creating the reports after tests run .on('end', function(){ if(cb) cb(); }); }); } return coverageTask; } function mochaTask(){ return gulp.src(['test/*.js'],{read:false}) .pipe(mocha({ growl:true })) .on('error',logMochaError); } function logMochaError(err){ if(err && err.message){ gutil.log(err.message); } else { gutil.log.apply(gutil,arguments); } }cli-table2-0.2.0/index.js000066400000000000000000000000501265445240400150750ustar00rootroot00000000000000module.exports = require('./src/table');cli-table2-0.2.0/lib/000077500000000000000000000000001265445240400142035ustar00rootroot00000000000000cli-table2-0.2.0/lib/print-example.js000066400000000000000000000067711265445240400173410ustar00rootroot00000000000000var chai = require('chai'); var expect = chai.expect; var colors = require('colors/safe'); var _ = require('lodash'); var fs = require('fs'); var git = require('git-rev'); function logExample(fn){ runPrintingExample(fn, function logName(name){ console.log(colors.gray('========= ') + name + colors.gray(' ================')); }, console.log, //logTable console.log, //logCode console.log, //logSeparator identity //screenShot ) } function mdExample(fn,file,cb){ git.long(function(commitHash){ var buffer = []; runPrintingExample(fn, function logName(name){ buffer.push('##### ' + name); }, function logTable(table){ //md files won't render color strings properly. table = stripColors(table); // indent table so is displayed preformatted text table = ' ' + (table.split('\n').join('\n ')); buffer.push(table); }, function logCode(code){ buffer.push('```javascript'); buffer.push(stripColors(code)); buffer.push('```'); }, function logSeparator(sep){ buffer.push(stripColors(sep)); }, function logScreenShot(image){ buffer.push('![table image](https://cdn.rawgit.com/jamestalmage/cli-table2/' + commitHash + '/examples/screenshots/' + image + '.png)'); } ); fs.writeFileSync(file,buffer.join('\n')); if(cb){cb();} }); } /** * Actually runs the tests and verifies the functions create the expected output. * @param name of the test suite, used in the mocha.describe call. * @param fn a function which creates the test suite. */ function runTest(name,fn){ function testExample(name,fn,expected){ it(name,function(){ expect(fn().toString()).to.equal(expected.join('\n')); }); } describe(name,function () { fn(testExample,identity); }); } /** * Common execution for runs that print output (either to console or to a Markdown file); * @param fn - a function containing the tests/demos. * @param logName - callback to print the name of this test to the console or file. * @param logTable - callback to print the output of the table to the console or file. * @param logCode - callback to print the output of the table to the console or file. * @param logSeparator - callback to print extra whitespace between demos. * @param logScreenShot - write out a link to the screenShot image. */ function runPrintingExample(fn,logName,logTable,logCode,logSeparator,logScreenShot){ /** * Called by every test/demo * @param name - the name of this test. * @param makeTable - a function which builds the table under test. Also, The contents of this function will be printed. * @param expected - The expected result. * @param screenshot - If present, there is an image containing a screenshot of the output */ function printExample(name,makeTable,expected,screenshot){ var code = makeTable.toString().split('\n').slice(1,-2).join('\n'); logName(name); if(screenshot && logScreenShot){ logScreenShot(screenshot); } else { logTable(makeTable().toString()); } logCode(code); logSeparator('\n'); } fn(printExample); } // removes all the color characters from a string function stripColors(str){ return str.split( /\u001b\[(?:\d*;){0,5}\d*m/g).join(''); } // returns the first arg - used as snapshot function function identity(str){ return str; } module.exports = { mdExample:mdExample, logExample:logExample, runTest:runTest };cli-table2-0.2.0/package.json000066400000000000000000000022401265445240400157210ustar00rootroot00000000000000{ "name": "cli-table2", "version": "0.2.0", "description": "Pretty unicode tables for the command line. Based on the original cli-table.", "main": "index.js", "directories": { "test": "test" }, "dependencies": { "lodash": "^3.10.1", "string-width": "^1.0.1" }, "devDependencies": { "ansi-256-colors": "^1.1.0", "chai": "^3.4.1", "cli-table": "^0.3.1", "coveralls": "^2.11.4", "git-rev": "^0.2.1", "growl": "^1.8.1", "gulp": "^3.9.0", "gulp-istanbul": "^0.10.3", "gulp-mocha": "^2.2.0", "gulp-util": "^3.0.7", "sinon": "^1.17.2", "sinon-chai": "^2.8.0" }, "optionalDependencies": { "colors": "^1.1.2" }, "scripts": { "test": "gulp coverage" }, "repository": { "type": "git", "url": "https://github.com/jamestalmage/cli-table2.git" }, "keywords": [ "node", "command", "line", "cli", "table", "tables", "tabular", "unicode", "colors", "grid" ], "author": "James Talmage", "license": "MIT", "bugs": { "url": "https://github.com/jamestalmage/cli-table2/issues" }, "homepage": "https://github.com/jamestalmage/cli-table2" } cli-table2-0.2.0/src/000077500000000000000000000000001265445240400142245ustar00rootroot00000000000000cli-table2-0.2.0/src/cell.js000066400000000000000000000272051265445240400155070ustar00rootroot00000000000000var _ = require('lodash'); var utils = require('./utils'); /** * A representation of a cell within the table. * Implementations must have `init` and `draw` methods, * as well as `colSpan`, `rowSpan`, `desiredHeight` and `desiredWidth` properties. * @param options * @constructor */ function Cell(options){ this.setOptions(options); } Cell.prototype.setOptions = function(options){ if(_.isString(options) || _.isNumber(options) || _.isBoolean(options)){ options = {content:''+options}; } options = options || {}; this.options = options; var content = options.content; if (_.isString(content) || _.isNumber(content) || _.isBoolean(content)) { this.content = String(content); } else if (!content) { this.content = ''; } else { throw new Error('Content needs to be a primitive, got: ' + (typeof content)); } this.colSpan = options.colSpan || 1; this.rowSpan = options.rowSpan || 1; }; Cell.prototype.mergeTableOptions = function(tableOptions,cells){ this.cells = cells; var optionsChars = this.options.chars || {}; var tableChars = tableOptions.chars; var chars = this.chars = {}; _.forEach(CHAR_NAMES,function(name){ setOption(optionsChars,tableChars,name,chars); }); this.truncate = this.options.truncate || tableOptions.truncate; var style = this.options.style = this.options.style || {}; var tableStyle = tableOptions.style; setOption(style, tableStyle, 'padding-left', this); setOption(style, tableStyle, 'padding-right', this); this.head = style.head || tableStyle.head; this.border = style.border || tableStyle.border; var fixedWidth = tableOptions.colWidths[this.x]; if(tableOptions.wordWrap && fixedWidth){ fixedWidth -= this.paddingLeft + this.paddingRight; this.lines = utils.colorizeLines(utils.wordWrap(fixedWidth,this.content)); } else { this.lines = utils.colorizeLines(this.content.split('\n')); } this.desiredWidth = utils.strlen(this.content) + this.paddingLeft + this.paddingRight; this.desiredHeight = this.lines.length; }; /** * Each cell will have it's `x` and `y` values set by the `layout-manager` prior to * `init` being called; * @type {Number} */ Cell.prototype.x = null; Cell.prototype.y = null; /** * Initializes the Cells data structure. * * @param tableOptions - A fully populated set of tableOptions. * In addition to the standard default values, tableOptions must have fully populated the * `colWidths` and `rowWidths` arrays. Those arrays must have lengths equal to the number * of columns or rows (respectively) in this table, and each array item must be a Number. * */ Cell.prototype.init = function(tableOptions){ var x = this.x; var y = this.y; this.widths = tableOptions.colWidths.slice(x, x + this.colSpan); this.heights = tableOptions.rowHeights.slice(y, y + this.rowSpan); this.width = _.reduce(this.widths,sumPlusOne); this.height = _.reduce(this.heights,sumPlusOne); this.hAlign = this.options.hAlign || tableOptions.colAligns[x]; this.vAlign = this.options.vAlign || tableOptions.rowAligns[y]; this.drawRight = x + this.colSpan == tableOptions.colWidths.length; }; /** * Draws the given line of the cell. * This default implementation defers to methods `drawTop`, `drawBottom`, `drawLine` and `drawEmpty`. * @param lineNum - can be `top`, `bottom` or a numerical line number. * @param spanningCell - will be a number if being called from a RowSpanCell, and will represent how * many rows below it's being called from. Otherwise it's undefined. * @returns {String} The representation of this line. */ Cell.prototype.draw = function(lineNum,spanningCell){ if(lineNum == 'top') return this.drawTop(this.drawRight); if(lineNum == 'bottom') return this.drawBottom(this.drawRight); var padLen = Math.max(this.height - this.lines.length, 0); var padTop; switch (this.vAlign){ case 'center': padTop = Math.ceil(padLen / 2); break; case 'bottom': padTop = padLen; break; default : padTop = 0; } if( (lineNum < padTop) || (lineNum >= (padTop + this.lines.length))){ return this.drawEmpty(this.drawRight,spanningCell); } var forceTruncation = (this.lines.length > this.height) && (lineNum + 1 >= this.height); return this.drawLine(lineNum - padTop, this.drawRight, forceTruncation,spanningCell); }; /** * Renders the top line of the cell. * @param drawRight - true if this method should render the right edge of the cell. * @returns {String} */ Cell.prototype.drawTop = function(drawRight){ var content = []; if(this.cells){ //TODO: cells should always exist - some tests don't fill it in though _.forEach(this.widths,function(width,index){ content.push(this._topLeftChar(index)); content.push( utils.repeat(this.chars[this.y == 0 ? 'top' : 'mid'],width) ); },this); } else { content.push(this._topLeftChar(0)); content.push(utils.repeat(this.chars[this.y == 0 ? 'top' : 'mid'],this.width)); } if(drawRight){ content.push(this.chars[this.y == 0 ? 'topRight' : 'rightMid']); } return this.wrapWithStyleColors('border',content.join('')); }; Cell.prototype._topLeftChar = function(offset){ var x = this.x+offset; var leftChar; if(this.y == 0){ leftChar = x == 0 ? 'topLeft' : (offset == 0 ? 'topMid' : 'top'); } else { if(x == 0){ leftChar = 'leftMid'; } else { leftChar = offset == 0 ? 'midMid' : 'bottomMid'; if(this.cells){ //TODO: cells should always exist - some tests don't fill it in though var spanAbove = this.cells[this.y-1][x] instanceof Cell.ColSpanCell; if(spanAbove){ leftChar = offset == 0 ? 'topMid' : 'mid'; } if(offset == 0){ var i = 1; while(this.cells[this.y][x-i] instanceof Cell.ColSpanCell){ i++; } if(this.cells[this.y][x-i] instanceof Cell.RowSpanCell){ leftChar = 'leftMid'; } } } } } return this.chars[leftChar]; }; Cell.prototype.wrapWithStyleColors = function(styleProperty,content){ if(this[styleProperty] && this[styleProperty].length){ try { var colors = require('colors/safe'); for(var i = this[styleProperty].length - 1; i >= 0; i--){ colors = colors[this[styleProperty][i]]; } return colors(content); } catch (e) { return content; } } else { return content; } }; /** * Renders a line of text. * @param lineNum - Which line of text to render. This is not necessarily the line within the cell. * There may be top-padding above the first line of text. * @param drawRight - true if this method should render the right edge of the cell. * @param forceTruncationSymbol - `true` if the rendered text should end with the truncation symbol even * if the text fits. This is used when the cell is vertically truncated. If `false` the text should * only include the truncation symbol if the text will not fit horizontally within the cell width. * @param spanningCell - a number of if being called from a RowSpanCell. (how many rows below). otherwise undefined. * @returns {String} */ Cell.prototype.drawLine = function(lineNum,drawRight,forceTruncationSymbol,spanningCell){ var left = this.chars[this.x == 0 ? 'left' : 'middle']; if(this.x && spanningCell && this.cells){ var cellLeft = this.cells[this.y+spanningCell][this.x-1]; while(cellLeft instanceof ColSpanCell){ cellLeft = this.cells[cellLeft.y][cellLeft.x-1]; } if(!(cellLeft instanceof RowSpanCell)){ left = this.chars['rightMid']; } } var leftPadding = utils.repeat(' ', this.paddingLeft); var right = (drawRight ? this.chars['right'] : ''); var rightPadding = utils.repeat(' ', this.paddingRight); var line = this.lines[lineNum]; var len = this.width - (this.paddingLeft + this.paddingRight); if(forceTruncationSymbol) line += this.truncate || '…'; var content = utils.truncate(line,len,this.truncate); content = utils.pad(content, len, ' ', this.hAlign); content = leftPadding + content + rightPadding; return this.stylizeLine(left,content,right); }; Cell.prototype.stylizeLine = function(left,content,right){ left = this.wrapWithStyleColors('border',left); right = this.wrapWithStyleColors('border',right); if(this.y === 0){ content = this.wrapWithStyleColors('head',content); } return left + content + right; }; /** * Renders the bottom line of the cell. * @param drawRight - true if this method should render the right edge of the cell. * @returns {String} */ Cell.prototype.drawBottom = function(drawRight){ var left = this.chars[this.x == 0 ? 'bottomLeft' : 'bottomMid']; var content = utils.repeat(this.chars.bottom,this.width); var right = drawRight ? this.chars['bottomRight'] : ''; return this.wrapWithStyleColors('border',left + content + right); }; /** * Renders a blank line of text within the cell. Used for top and/or bottom padding. * @param drawRight - true if this method should render the right edge of the cell. * @param spanningCell - a number of if being called from a RowSpanCell. (how many rows below). otherwise undefined. * @returns {String} */ Cell.prototype.drawEmpty = function(drawRight,spanningCell){ var left = this.chars[this.x == 0 ? 'left' : 'middle']; if(this.x && spanningCell && this.cells){ var cellLeft = this.cells[this.y+spanningCell][this.x-1]; while(cellLeft instanceof ColSpanCell){ cellLeft = this.cells[cellLeft.y][cellLeft.x-1]; } if(!(cellLeft instanceof RowSpanCell)){ left = this.chars['rightMid']; } } var right = (drawRight ? this.chars['right'] : ''); var content = utils.repeat(' ',this.width); return this.stylizeLine(left , content , right); }; /** * A Cell that doesn't do anything. It just draws empty lines. * Used as a placeholder in column spanning. * @constructor */ function ColSpanCell(){} ColSpanCell.prototype.draw = function(){ return ''; }; ColSpanCell.prototype.init = function(tableOptions){}; /** * A placeholder Cell for a Cell that spans multiple rows. * It delegates rendering to the original cell, but adds the appropriate offset. * @param originalCell * @constructor */ function RowSpanCell(originalCell){ this.originalCell = originalCell; } RowSpanCell.prototype.init = function(tableOptions){ var y = this.y; var originalY = this.originalCell.y; this.cellOffset = y - originalY; this.offset = findDimension(tableOptions.rowHeights,originalY,this.cellOffset); }; RowSpanCell.prototype.draw = function(lineNum){ if(lineNum == 'top'){ return this.originalCell.draw(this.offset,this.cellOffset); } if(lineNum == 'bottom'){ return this.originalCell.draw('bottom'); } return this.originalCell.draw(this.offset + 1 + lineNum); }; ColSpanCell.prototype.mergeTableOptions = RowSpanCell.prototype.mergeTableOptions = function(){}; // HELPER FUNCTIONS function setOption(objA,objB,nameB,targetObj){ var nameA = nameB.split('-'); if(nameA.length > 1) { nameA[1] = nameA[1].charAt(0).toUpperCase() + nameA[1].substr(1); nameA = nameA.join(''); targetObj[nameA] = objA[nameA] || objA[nameB] || objB[nameA] || objB[nameB]; } else { targetObj[nameB] = objA[nameB] || objB[nameB]; } } function findDimension(dimensionTable, startingIndex, span){ var ret = dimensionTable[startingIndex]; for(var i = 1; i < span; i++){ ret += 1 + dimensionTable[startingIndex + i]; } return ret; } function sumPlusOne(a,b){ return a+b+1; } var CHAR_NAMES = [ 'top' , 'top-mid' , 'top-left' , 'top-right' , 'bottom' , 'bottom-mid' , 'bottom-left' , 'bottom-right' , 'left' , 'left-mid' , 'mid' , 'mid-mid' , 'right' , 'right-mid' , 'middle' ]; module.exports = Cell; module.exports.ColSpanCell = ColSpanCell; module.exports.RowSpanCell = RowSpanCell;cli-table2-0.2.0/src/layout-manager.js000066400000000000000000000141251265445240400175120ustar00rootroot00000000000000var _ = require('lodash'); var Cell = require('./cell'); var RowSpanCell = Cell.RowSpanCell; var ColSpanCell = Cell.ColSpanCell; (function(){ function layoutTable(table){ _.forEach(table,function(row,rowIndex){ _.forEach(row,function(cell,columnIndex){ cell.y = rowIndex; cell.x = columnIndex; for(var y = rowIndex; y >= 0; y--){ var row2 = table[y]; var xMax = (y === rowIndex) ? columnIndex : row2.length; for(var x = 0; x < xMax; x++){ var cell2 = row2[x]; while(cellsConflict(cell,cell2)){ cell.x++; } } } }); }); } function maxWidth(table) { var mw = 0; _.forEach(table, function (row) { _.forEach(row, function (cell) { mw = Math.max(mw,cell.x + (cell.colSpan || 1)); }); }); return mw; } function maxHeight(table){ return table.length; } function cellsConflict(cell1,cell2){ var yMin1 = cell1.y; var yMax1 = cell1.y - 1 + (cell1.rowSpan || 1); var yMin2 = cell2.y; var yMax2 = cell2.y - 1 + (cell2.rowSpan || 1); var yConflict = !(yMin1 > yMax2 || yMin2 > yMax1); var xMin1= cell1.x; var xMax1 = cell1.x - 1 + (cell1.colSpan || 1); var xMin2= cell2.x; var xMax2 = cell2.x - 1 + (cell2.colSpan || 1); var xConflict = !(xMin1 > xMax2 || xMin2 > xMax1); return yConflict && xConflict; } function conflictExists(rows,x,y){ var i_max = Math.min(rows.length-1,y); var cell = {x:x,y:y}; for(var i = 0; i <= i_max; i++){ var row = rows[i]; for(var j = 0; j < row.length; j++){ if(cellsConflict(cell,row[j])){ return true; } } } return false; } function allBlank(rows,y,xMin,xMax){ for(var x = xMin; x < xMax; x++){ if(conflictExists(rows,x,y)){ return false; } } return true; } function addRowSpanCells(table){ _.forEach(table,function(row,rowIndex){ _.forEach(row,function(cell){ for(var i = 1; i < cell.rowSpan; i++){ var rowSpanCell = new RowSpanCell(cell); rowSpanCell.x = cell.x; rowSpanCell.y = cell.y + i; rowSpanCell.colSpan = cell.colSpan; insertCell(rowSpanCell,table[rowIndex+i]); } }); }); } function addColSpanCells(cellRows){ for(var rowIndex = cellRows.length-1; rowIndex >= 0; rowIndex--) { var cellColumns = cellRows[rowIndex]; for (var columnIndex = 0; columnIndex < cellColumns.length; columnIndex++) { var cell = cellColumns[columnIndex]; for (var k = 1; k < cell.colSpan; k++) { var colSpanCell = new ColSpanCell(); colSpanCell.x = cell.x + k; colSpanCell.y = cell.y; cellColumns.splice(columnIndex + 1, 0, colSpanCell); } } } } function insertCell(cell,row){ var x = 0; while(x < row.length && (row[x].x < cell.x)) { x++; } row.splice(x,0,cell); } function fillInTable(table){ var h_max = maxHeight(table); var w_max = maxWidth(table); for(var y = 0; y < h_max; y++){ for(var x = 0; x < w_max; x++){ if(!conflictExists(table,x,y)){ var opts = {x:x,y:y,colSpan:1,rowSpan:1}; x++; while(x < w_max && !conflictExists(table,x,y)){ opts.colSpan++; x++; } var y2 = y + 1; while(y2 < h_max && allBlank(table,y2,opts.x,opts.x+opts.colSpan)){ opts.rowSpan++; y2++; } var cell = new Cell(opts); cell.x = opts.x; cell.y = opts.y; insertCell(cell,table[y]); } } } } function generateCells(rows){ return _.map(rows,function(row){ if(!_.isArray(row)){ var key = Object.keys(row)[0]; row = row[key]; if(_.isArray(row)){ row = row.slice(); row.unshift(key); } else { row = [key,row]; } } return _.map(row,function(cell){ return new Cell(cell); }); }); } function makeTableLayout(rows){ var cellRows = generateCells(rows); layoutTable(cellRows); fillInTable(cellRows); addRowSpanCells(cellRows); addColSpanCells(cellRows); return cellRows; } module.exports = { makeTableLayout: makeTableLayout, layoutTable: layoutTable, addRowSpanCells: addRowSpanCells, maxWidth:maxWidth, fillInTable:fillInTable, computeWidths:makeComputeWidths('colSpan','desiredWidth','x',1), computeHeights:makeComputeWidths('rowSpan','desiredHeight','y',1) }; })(); function makeComputeWidths(colSpan,desiredWidth,x,forcedMin){ return function(vals,table){ var result = []; var spanners = []; _.forEach(table,function(row){ _.forEach(row,function(cell){ if((cell[colSpan] || 1) > 1){ spanners.push(cell); } else { result[cell[x]] = Math.max(result[cell[x]] || 0, cell[desiredWidth] || 0, forcedMin); } }); }); _.forEach(vals,function(val,index){ if(_.isNumber(val)){ result[index] = val; } }); //_.forEach(spanners,function(cell){ for(var k = spanners.length - 1; k >=0; k--){ var cell = spanners[k]; var span = cell[colSpan]; var col = cell[x]; var existingWidth = result[col]; var editableCols = _.isNumber(vals[col]) ? 0 : 1; for(var i = 1; i < span; i ++){ existingWidth += 1 + result[col + i]; if(!_.isNumber(vals[col + i])){ editableCols++; } } if(cell[desiredWidth] > existingWidth){ i = 0; while(editableCols > 0 && cell[desiredWidth] > existingWidth){ if(!_.isNumber(vals[col+i])){ var dif = Math.round( (cell[desiredWidth] - existingWidth) / editableCols ); existingWidth += dif; result[col + i] += dif; editableCols--; } i++; } } } _.extend(vals,result); for(var j = 0; j < vals.length; j++){ vals[j] = Math.max(forcedMin, vals[j] || 0); } }; } cli-table2-0.2.0/src/table.js000066400000000000000000000034601265445240400156540ustar00rootroot00000000000000 var utils = require('./utils'); var tableLayout = require('./layout-manager'); var _ = require('lodash'); function Table(options){ this.options = utils.mergeOptions(options); } Table.prototype.__proto__ = Array.prototype; Table.prototype.toString = function(){ var array = this; var headersPresent = this.options.head && this.options.head.length; if(headersPresent){ array = [this.options.head]; if(this.length){ array.push.apply(array,this); } } else { this.options.style.head=[]; } var cells = tableLayout.makeTableLayout(array); _.forEach(cells,function(row){ _.forEach(row,function(cell){ cell.mergeTableOptions(this.options,cells); },this); },this); tableLayout.computeWidths(this.options.colWidths,cells); tableLayout.computeHeights(this.options.rowHeights,cells); _.forEach(cells,function(row,rowIndex){ _.forEach(row,function(cell,cellIndex){ cell.init(this.options); },this); },this); var result = []; for(var rowIndex = 0; rowIndex < cells.length; rowIndex++){ var row = cells[rowIndex]; var heightOfRow = this.options.rowHeights[rowIndex]; if(rowIndex === 0 || !this.options.style.compact || (rowIndex == 1 && headersPresent)){ doDraw(row,'top',result); } for(var lineNum = 0; lineNum < heightOfRow; lineNum++){ doDraw(row,lineNum,result); } if(rowIndex + 1 == cells.length){ doDraw(row,'bottom',result); } } return result.join('\n'); }; function doDraw(row,lineNum,result){ var line = []; _.forEach(row,function(cell){ line.push(cell.draw(lineNum)); }); var str = line.join(''); if(str.length) result.push(str); } Table.prototype.__defineGetter__('width', function (){ var str = this.toString().split("\n"); return str[0].length; }); module.exports = Table;cli-table2-0.2.0/src/utils.js000066400000000000000000000157471265445240400157400ustar00rootroot00000000000000var _ = require('lodash'); var stringWidth = require('string-width'); function codeRegex(capture){ return capture ? /\u001b\[((?:\d*;){0,5}\d*)m/g : /\u001b\[(?:\d*;){0,5}\d*m/g } function strlen(str){ var code = codeRegex(); var stripped = ("" + str).replace(code,''); var split = stripped.split("\n"); return split.reduce(function (memo, s) { return (stringWidth(s) > memo) ? stringWidth(s) : memo }, 0); } function repeat(str,times){ return Array(times + 1).join(str); } function pad(str, len, pad, dir) { var length = strlen(str); if (len + 1 >= length) { var padlen = len - length; switch (dir) { case 'right': str = repeat(pad, padlen) + str; break; case 'center': var right = Math.ceil((padlen) / 2); var left = padlen - right; str = repeat(pad, left) + str + repeat(pad, right); break; default : str = str + repeat(pad,padlen); break; } } return str; } var codeCache = {}; function addToCodeCache(name,on,off){ on = '\u001b[' + on + 'm'; off = '\u001b[' + off + 'm'; codeCache[on] = {set:name,to:true}; codeCache[off] = {set:name,to:false}; codeCache[name] = {on:on,off:off}; } //https://github.com/Marak/colors.js/blob/master/lib/styles.js addToCodeCache('bold', 1, 22); addToCodeCache('italics', 3, 23); addToCodeCache('underline', 4, 24); addToCodeCache('inverse', 7, 27); addToCodeCache('strikethrough', 9, 29); function updateState(state, controlChars){ var controlCode = controlChars[1] ? parseInt(controlChars[1].split(';')[0]) : 0; if ( (controlCode >= 30 && controlCode <= 39) || (controlCode >= 90 && controlCode <= 97) ) { state.lastForegroundAdded = controlChars[0]; return; } if ( (controlCode >= 40 && controlCode <= 49) || (controlCode >= 100 && controlCode <= 107) ) { state.lastBackgroundAdded = controlChars[0]; return; } if (controlCode === 0) { for (var i in state) { /* istanbul ignore else */ if (state.hasOwnProperty(i)) { delete state[i]; } } return; } var info = codeCache[controlChars[0]]; if (info) { state[info.set] = info.to; } } function readState(line){ var code = codeRegex(true); var controlChars = code.exec(line); var state = {}; while(controlChars !== null){ updateState(state, controlChars); controlChars = code.exec(line); } return state; } function unwindState(state,ret){ var lastBackgroundAdded = state.lastBackgroundAdded; var lastForegroundAdded = state.lastForegroundAdded; delete state.lastBackgroundAdded; delete state.lastForegroundAdded; _.forEach(state,function(value,key){ if(value){ ret += codeCache[key].off; } }); if(lastBackgroundAdded && (lastBackgroundAdded != '\u001b[49m')){ ret += '\u001b[49m'; } if(lastForegroundAdded && (lastForegroundAdded != '\u001b[39m')){ ret += '\u001b[39m'; } return ret; } function rewindState(state,ret){ var lastBackgroundAdded = state.lastBackgroundAdded; var lastForegroundAdded = state.lastForegroundAdded; delete state.lastBackgroundAdded; delete state.lastForegroundAdded; _.forEach(state,function(value,key){ if(value){ ret = codeCache[key].on + ret; } }); if(lastBackgroundAdded && (lastBackgroundAdded != '\u001b[49m')){ ret = lastBackgroundAdded + ret; } if(lastForegroundAdded && (lastForegroundAdded != '\u001b[39m')){ ret = lastForegroundAdded + ret; } return ret; } function truncateWidth(str, desiredLength){ if (str.length === strlen(str)) { return str.substr(0, desiredLength); } while (strlen(str) > desiredLength){ str = str.slice(0, -1); } return str; } function truncateWidthWithAnsi(str, desiredLength){ var code = codeRegex(true); var split = str.split(codeRegex()); var splitIndex = 0; var retLen = 0; var ret = ''; var myArray; var state = {}; while(retLen < desiredLength){ myArray = code.exec(str); var toAdd = split[splitIndex]; splitIndex++; if (retLen + strlen(toAdd) > desiredLength){ toAdd = truncateWidth(toAdd, desiredLength - retLen); } ret += toAdd; retLen += strlen(toAdd); if(retLen < desiredLength){ if (!myArray) { break; } // full-width chars may cause a whitespace which cannot be filled ret += myArray[0]; updateState(state,myArray); } } return unwindState(state,ret); } function truncate(str, desiredLength, truncateChar){ truncateChar = truncateChar || '…'; var lengthOfStr = strlen(str); if(lengthOfStr <= desiredLength){ return str; } desiredLength -= strlen(truncateChar); ret = truncateWidthWithAnsi(str, desiredLength); return ret + truncateChar; } function defaultOptions(){ return{ chars: { 'top': '─' , 'top-mid': '┬' , 'top-left': '┌' , 'top-right': '┐' , 'bottom': '─' , 'bottom-mid': '┴' , 'bottom-left': '└' , 'bottom-right': '┘' , 'left': '│' , 'left-mid': '├' , 'mid': '─' , 'mid-mid': '┼' , 'right': '│' , 'right-mid': '┤' , 'middle': '│' } , truncate: '…' , colWidths: [] , rowHeights: [] , colAligns: [] , rowAligns: [] , style: { 'padding-left': 1 , 'padding-right': 1 , head: ['red'] , border: ['grey'] , compact : false } , head: [] }; } function mergeOptions(options,defaults){ options = options || {}; defaults = defaults || defaultOptions(); var ret = _.extend({}, defaults, options); ret.chars = _.extend({}, defaults.chars, options.chars); ret.style = _.extend({}, defaults.style, options.style); return ret; } function wordWrap(maxLength,input){ var lines = []; var split = input.split(/(\s+)/g); var line = []; var lineLength = 0; var whitespace; for (var i = 0; i < split.length; i += 2) { var word = split[i]; var newLength = lineLength + strlen(word); if (lineLength > 0 && whitespace) { newLength += whitespace.length; } if(newLength > maxLength){ if(lineLength !== 0){ lines.push(line.join('')); } line = [word]; lineLength = strlen(word); } else { line.push(whitespace || '', word); lineLength = newLength; } whitespace = split[i+1]; } if(lineLength){ lines.push(line.join('')); } return lines; } function multiLineWordWrap(maxLength, input){ var output = []; input = input.split('\n'); for(var i = 0; i < input.length; i++){ output.push.apply(output,wordWrap(maxLength,input[i])); } return output; } function colorizeLines(input){ var state = {}; var output = []; for(var i = 0; i < input.length; i++){ var line = rewindState(state,input[i]) ; state = readState(line); var temp = _.extend({},state); output.push(unwindState(temp,line)); } return output; } module.exports = { strlen:strlen, repeat:repeat, pad:pad, truncate:truncate, mergeOptions:mergeOptions, wordWrap:multiLineWordWrap, colorizeLines:colorizeLines }; cli-table2-0.2.0/test/000077500000000000000000000000001265445240400144145ustar00rootroot00000000000000cli-table2-0.2.0/test/cell-test.js000066400000000000000000000727461265445240400166660ustar00rootroot00000000000000describe('Cell',function(){ var chai = require('chai'); var expect = chai.expect; var sinon = require('sinon'); var sinonChai = require("sinon-chai"); chai.use(sinonChai); var colors = require('colors'); var Cell = require('../src/cell'); var RowSpanCell = Cell.RowSpanCell; var ColSpanCell = Cell.ColSpanCell; var mergeOptions = require('../src/utils').mergeOptions; function defaultOptions(){ //overwrite coloring of head and border by default for easier testing. return mergeOptions({style:{head:[],border:[]}}); } function defaultChars(){ return { 'top': '─' , 'topMid': '┬' , 'topLeft': '┌' , 'topRight': '┐' , 'bottom': '─' , 'bottomMid': '┴' , 'bottomLeft': '└' , 'bottomRight': '┘' , 'left': '│' , 'leftMid': '├' , 'mid': '─' , 'midMid': '┼' , 'right': '│' , 'rightMid': '┤' , 'middle': '│' }; } describe('constructor',function(){ it('colSpan and rowSpan default to 1',function(){ var cell = new Cell(); expect(cell.colSpan).to.equal(1); expect(cell.rowSpan).to.equal(1); }); it('colSpan and rowSpan can be set via constructor',function(){ var cell = new Cell({rowSpan:2,colSpan:3}); expect(cell.rowSpan).to.equal(2); expect(cell.colSpan).to.equal(3); }); it('content can be set as a string',function(){ var cell = new Cell('hello\nworld'); expect(cell.content).to.equal('hello\nworld'); }); it('content can be set as a options property',function(){ var cell = new Cell({content:'hello\nworld'}); expect(cell.content).to.equal('hello\nworld'); }); it('default content is an empty string',function(){ var cell = new Cell(); expect(cell.content).to.equal(''); }); it('new Cell(null) will have empty string content',function(){ var cell = new Cell(null); expect(cell.content).to.equal(''); }); it('new Cell({content: null}) will have empty string content',function(){ var cell = new Cell({content: null}); expect(cell.content).to.equal(''); }); it('new Cell(0) will have "0" as content',function(){ var cell = new Cell(0); expect(cell.content).to.equal('0'); }); it('new Cell({content: 0}) will have "0" as content',function(){ var cell = new Cell({content: 0}); expect(cell.content).to.equal('0'); }); it('new Cell(false) will have "false" as content',function(){ var cell = new Cell(false); expect(cell.content).to.equal('false'); }); it('new Cell({content: false}) will have "false" as content',function(){ var cell = new Cell({content: false}); expect(cell.content).to.equal('false'); }); }); describe('mergeTableOptions',function(){ describe('chars',function(){ it('unset chars take on value of table',function(){ var cell = new Cell(); var tableOptions = defaultOptions(); cell.mergeTableOptions(tableOptions); expect(cell.chars).to.eql(defaultChars()); }); it('set chars override the value of table',function(){ var cell = new Cell({chars:{bottomRight:'='}}); cell.mergeTableOptions(defaultOptions()); var chars = defaultChars(); chars.bottomRight = '='; expect(cell.chars).to.eql(chars); }); it('hyphenated names will be converted to camel-case',function(){ var cell = new Cell({chars:{'bottom-left':'='}}); cell.mergeTableOptions(defaultOptions()); var chars = defaultChars(); chars.bottomLeft = '='; expect(cell.chars).to.eql(chars); }); }); describe('truncate',function(){ it('if unset takes on value of table',function(){ var cell = new Cell(); cell.mergeTableOptions(defaultOptions()); expect(cell.truncate).to.equal('…'); }); it('if set overrides value of table',function(){ var cell = new Cell({truncate:'...'}); cell.mergeTableOptions(defaultOptions()); expect(cell.truncate).to.equal('...'); }); }); describe('style.padding-left', function () { it('if unset will be copied from tableOptions.style', function () { var cell = new Cell(); cell.mergeTableOptions(defaultOptions()); expect(cell.paddingLeft).to.equal(1); cell = new Cell(); var tableOptions = defaultOptions(); tableOptions.style['padding-left'] = 2; cell.mergeTableOptions(tableOptions); expect(cell.paddingLeft).to.equal(2); cell = new Cell(); tableOptions = defaultOptions(); tableOptions.style.paddingLeft = 3; cell.mergeTableOptions(tableOptions); expect(cell.paddingLeft).to.equal(3); }); it('if set will override tableOptions.style', function () { var cell = new Cell({style:{'padding-left':2}}); cell.mergeTableOptions(defaultOptions()); expect(cell.paddingLeft).to.equal(2); cell = new Cell({style:{paddingLeft:3}}); cell.mergeTableOptions(defaultOptions()); expect(cell.paddingLeft).to.equal(3); }); }); describe('style.padding-right', function () { it('if unset will be copied from tableOptions.style', function () { var cell = new Cell(); cell.mergeTableOptions(defaultOptions()); expect(cell.paddingRight).to.equal(1); cell = new Cell(); var tableOptions = defaultOptions(); tableOptions.style['padding-right'] = 2; cell.mergeTableOptions(tableOptions); expect(cell.paddingRight).to.equal(2); cell = new Cell(); tableOptions = defaultOptions(); tableOptions.style.paddingRight = 3; cell.mergeTableOptions(tableOptions); expect(cell.paddingRight).to.equal(3); }); it('if set will override tableOptions.style', function () { var cell = new Cell({style:{'padding-right':2}}); cell.mergeTableOptions(defaultOptions()); expect(cell.paddingRight).to.equal(2); cell = new Cell({style:{paddingRight:3}}); cell.mergeTableOptions(defaultOptions()); expect(cell.paddingRight).to.equal(3); }); }); describe('desiredWidth',function(){ it('content(hello) padding(1,1) == 7',function(){ var cell = new Cell('hello'); cell.mergeTableOptions(defaultOptions()); expect(cell.desiredWidth).to.equal(7); }); it('content(hi) padding(1,2) == 5',function(){ var cell = new Cell({content:'hi',style:{paddingRight:2}}); var tableOptions = defaultOptions(); cell.mergeTableOptions(tableOptions); expect(cell.desiredWidth).to.equal(5); }); it('content(hi) padding(3,2) == 7',function(){ var cell = new Cell({content:'hi',style:{paddingLeft:3,paddingRight:2}}); var tableOptions = defaultOptions(); cell.mergeTableOptions(tableOptions); expect(cell.desiredWidth).to.equal(7); }); }); describe('desiredHeight',function(){ it('1 lines of text',function(){ var cell = new Cell('hi'); cell.mergeTableOptions(defaultOptions()); expect(cell.desiredHeight).to.equal(1); }); it('2 lines of text',function(){ var cell = new Cell('hi\nbye'); cell.mergeTableOptions(defaultOptions()); expect(cell.desiredHeight).to.equal(2); }); it('2 lines of text',function(){ var cell = new Cell('hi\nbye\nyo'); cell.mergeTableOptions(defaultOptions()); expect(cell.desiredHeight).to.equal(3); }); }); }); describe('init',function(){ describe('hAlign',function(){ it('if unset takes colAlign value from tableOptions',function(){ var tableOptions = defaultOptions(); tableOptions.colAligns = ['left','right','both']; var cell = new Cell(); cell.x = 0; cell.mergeTableOptions(tableOptions); cell.init(tableOptions); expect(cell.hAlign).to.equal('left'); cell = new Cell(); cell.x = 1; cell.mergeTableOptions(tableOptions); cell.init(tableOptions); expect(cell.hAlign).to.equal('right'); cell = new Cell(); cell.mergeTableOptions(tableOptions); cell.x=2; cell.init(tableOptions); expect(cell.hAlign).to.equal('both'); }); it('if set overrides tableOptions',function(){ var tableOptions = defaultOptions(); tableOptions.colAligns = ['left','right','both']; var cell = new Cell({hAlign:'right'}); cell.x = 0; cell.mergeTableOptions(tableOptions); cell.init(tableOptions); expect(cell.hAlign).to.equal('right'); cell = new Cell({hAlign:'left'}); cell.x = 1; cell.mergeTableOptions(tableOptions); cell.init(tableOptions); expect(cell.hAlign).to.equal('left'); cell = new Cell({hAlign:'right'}); cell.x = 2; cell.mergeTableOptions(tableOptions); cell.init(tableOptions); expect(cell.hAlign).to.equal('right'); }); }); describe('vAlign',function(){ it('if unset takes rowAlign value from tableOptions',function(){ var tableOptions = defaultOptions(); tableOptions.rowAligns = ['top','bottom','center']; var cell = new Cell(); cell.y=0; cell.mergeTableOptions(tableOptions); cell.init(tableOptions); expect(cell.vAlign).to.equal('top'); cell = new Cell(); cell.y = 1; cell.mergeTableOptions(tableOptions); cell.init(tableOptions); expect(cell.vAlign).to.equal('bottom'); cell = new Cell(); cell.y = 2; cell.mergeTableOptions(tableOptions); cell.init(tableOptions); expect(cell.vAlign).to.equal('center'); }); it('if set overrides tableOptions',function(){ var tableOptions = defaultOptions(); tableOptions.rowAligns = ['top','bottom','center']; var cell = new Cell({vAlign:'bottom'}); cell.y = 0; cell.mergeTableOptions(tableOptions); cell.init(tableOptions); expect(cell.vAlign).to.equal('bottom'); cell = new Cell({vAlign:'top'}); cell.y = 1; cell.mergeTableOptions(tableOptions); cell.init(tableOptions); expect(cell.vAlign).to.equal('top'); cell = new Cell({vAlign:'center'}); cell.y = 2; cell.mergeTableOptions(tableOptions); cell.init(tableOptions); expect(cell.vAlign).to.equal('center'); }); }); describe('width', function(){ it('will match colWidth of x',function(){ var tableOptions = defaultOptions(); tableOptions.colWidths = [5,10,15]; var cell = new Cell(); cell.x = 0; cell.mergeTableOptions(tableOptions); cell.init(tableOptions); expect(cell.width).to.equal(5); cell = new Cell(); cell.x = 1; cell.mergeTableOptions(tableOptions); cell.init(tableOptions); expect(cell.width).to.equal(10); cell = new Cell(); cell.x = 2; cell.mergeTableOptions(tableOptions); cell.init(tableOptions); expect(cell.width).to.equal(15); }); it('will add colWidths if colSpan > 1',function(){ var tableOptions = defaultOptions(); tableOptions.colWidths = [5,10,15]; var cell = new Cell({colSpan:2}); cell.x=0; cell.mergeTableOptions(tableOptions); cell.init(tableOptions); expect(cell.width).to.equal(16); cell = new Cell({colSpan:2}); cell.x=1; cell.mergeTableOptions(tableOptions); cell.init(tableOptions); expect(cell.width).to.equal(26); cell = new Cell({colSpan:3}); cell.x=0; cell.mergeTableOptions(tableOptions); cell.init(tableOptions); expect(cell.width).to.equal(32); }); }); describe('height', function(){ it('will match rowHeight of x',function(){ var tableOptions = defaultOptions(); tableOptions.rowHeights = [5,10,15]; var cell = new Cell(); cell.y=0; cell.mergeTableOptions(tableOptions); cell.init(tableOptions); expect(cell.height).to.equal(5); cell = new Cell(); cell.y=1; cell.mergeTableOptions(tableOptions); cell.init(tableOptions); expect(cell.height).to.equal(10); cell = new Cell(); cell.y=2; cell.mergeTableOptions(tableOptions); cell.init(tableOptions); expect(cell.height).to.equal(15); }); it('will add rowHeights if rowSpan > 1',function(){ var tableOptions = defaultOptions(); tableOptions.rowHeights = [5,10,15]; var cell = new Cell({rowSpan:2}); cell.y = 0; cell.mergeTableOptions(tableOptions); cell.init(tableOptions); expect(cell.height).to.equal(16); cell = new Cell({rowSpan:2}); cell.y = 1; cell.mergeTableOptions(tableOptions); cell.init(tableOptions); expect(cell.height).to.equal(26); cell = new Cell({rowSpan:3}); cell.y = 0; cell.mergeTableOptions(tableOptions); cell.init(tableOptions); expect(cell.height).to.equal(32); }); }); describe('drawRight', function(){ var tableOptions; beforeEach(function(){ tableOptions = defaultOptions(); tableOptions.colWidths = [20,20,20]; }); it('col 1 of 3, with default colspan',function(){ var cell = new Cell(); cell.x = 0; cell.mergeTableOptions(tableOptions); cell.init(tableOptions); expect(cell.drawRight).to.equal(false); }); it('col 2 of 3, with default colspan',function(){ var cell = new Cell(); cell.x = 1; cell.mergeTableOptions(tableOptions); cell.init(tableOptions); expect(cell.drawRight).to.equal(false); }); it('col 3 of 3, with default colspan',function(){ var cell = new Cell(); cell.x = 2; cell.mergeTableOptions(tableOptions); cell.init(tableOptions); expect(cell.drawRight).to.equal(true); }); it('col 3 of 4, with default colspan',function(){ var cell = new Cell(); cell.x = 2; tableOptions.colWidths = [20,20,20,20]; cell.mergeTableOptions(tableOptions); cell.init(tableOptions); expect(cell.drawRight).to.equal(false); }); it('col 2 of 3, with colspan of 2',function(){ var cell = new Cell({colSpan:2}); cell.x=1; cell.mergeTableOptions(tableOptions); cell.init(tableOptions); expect(cell.drawRight).to.equal(true); }); it('col 1 of 3, with colspan of 3',function(){ var cell = new Cell({colSpan:3}); cell.x = 0; cell.mergeTableOptions(tableOptions); cell.init(tableOptions); expect(cell.drawRight).to.equal(true); }); it('col 1 of 3, with colspan of 2',function(){ var cell = new Cell({colSpan:2}); cell.x = 0; cell.mergeTableOptions(tableOptions); cell.init(tableOptions); expect(cell.drawRight).to.equal(false); }); }); }); describe('drawLine', function(){ var cell; beforeEach(function () { cell = new Cell(); //manually init cell.chars = defaultChars(); cell.paddingLeft = cell.paddingRight = 1; cell.width = 7; cell.height = 3; cell.hAlign = 'center'; cell.vAlign = 'center'; cell.chars.left = 'L'; cell.chars.right = 'R'; cell.chars.middle = 'M'; cell.content = 'hello\nhowdy\ngoodnight'; cell.lines = cell.content.split('\n'); cell.x = cell.y = 0; }); describe('top line',function(){ it('will draw the top left corner when x=0,y=0',function(){ cell.x = cell.y = 0; expect(cell.draw('top')).to.equal('┌───────'); cell.drawRight = true; expect(cell.draw('top')).to.equal('┌───────┐'); }); it('will draw the top mid corner when x=1,y=0',function(){ cell.x = 1; cell.y = 0; expect(cell.draw('top')).to.equal('┬───────'); cell.drawRight = true; expect(cell.draw('top')).to.equal('┬───────┐'); }); it('will draw the left mid corner when x=0,y=1',function(){ cell.x = 0; cell.y = 1; expect(cell.draw('top')).to.equal('├───────'); cell.drawRight = true; expect(cell.draw('top')).to.equal('├───────┤'); }); it('will draw the mid mid corner when x=1,y=1',function(){ cell.x = 1; cell.y = 1; expect(cell.draw('top')).to.equal('┼───────'); cell.drawRight = true; expect(cell.draw('top')).to.equal('┼───────┤'); }); it('will draw in the color specified by border style',function(){ cell.border = ['gray']; expect(cell.draw('top')).to.equal(colors.gray('┌───────')) }); }); describe('bottom line',function(){ it('will draw the bottom left corner if x=0',function(){ cell.x = 0; cell.y = 1; expect(cell.draw('bottom')).to.equal('└───────'); cell.drawRight = true; expect(cell.draw('bottom')).to.equal('└───────┘'); }); it('will draw the bottom left corner if x=1',function(){ cell.x = 1; cell.y = 1; expect(cell.draw('bottom')).to.equal('┴───────'); cell.drawRight = true; expect(cell.draw('bottom')).to.equal('┴───────┘'); }); it('will draw in the color specified by border style',function(){ cell.border = ['gray']; expect(cell.draw('bottom')).to.equal(colors.gray('└───────')) }); }); describe('drawBottom',function(){ it('draws an empty line',function(){ expect(cell.drawEmpty()).to.equal('L '); expect(cell.drawEmpty(true)).to.equal('L R'); }); it('draws an empty line',function(){ cell.border = ['gray']; cell.head = ['red']; expect(cell.drawEmpty()).to.equal(colors.gray('L') + colors.red(' ')); expect(cell.drawEmpty(true)).to.equal(colors.gray('L') + colors.red(' ') + colors.gray('R')); }); }); describe('first line of text',function(){ beforeEach(function () { cell.width = 9; }); it('will draw left side if x=0',function(){ cell.x = 0; expect(cell.draw(0)).to.equal('L hello '); cell.drawRight = true; expect(cell.draw(0)).to.equal('L hello R'); }); it('will draw mid side if x=1',function(){ cell.x = 1; expect(cell.draw(0)).to.equal('M hello '); cell.drawRight = true; expect(cell.draw(0)).to.equal('M hello R'); }); it('will align left',function(){ cell.x = 1; cell.hAlign = 'left'; expect(cell.draw(0)).to.equal('M hello '); cell.drawRight = true; expect(cell.draw(0)).to.equal('M hello R'); }); it('will align right',function(){ cell.x = 1; cell.hAlign = 'right'; expect(cell.draw(0)).to.equal('M hello '); cell.drawRight = true; expect(cell.draw(0)).to.equal('M hello R'); }); it('left and right will be drawn in color of border style',function(){ cell.border = ['gray']; cell.x = 0; expect(cell.draw(0)).to.equal(colors.gray('L') + ' hello '); cell.drawRight = true; expect(cell.draw(0)).to.equal(colors.gray('L') + ' hello ' + colors.gray('R')); }); it('text will be drawn in color of head style if y == 0',function(){ cell.head = ['red']; cell.x = cell.y = 0; expect(cell.draw(0)).to.equal('L' + colors.red(' hello ')); cell.drawRight = true; expect(cell.draw(0)).to.equal('L' + colors.red(' hello ') + 'R'); }); it('text will NOT be drawn in color of head style if y == 1',function(){ cell.head = ['red']; cell.x = cell.y = 1; expect(cell.draw(0)).to.equal('M hello '); cell.drawRight = true; expect(cell.draw(0)).to.equal('M hello R'); }); it('head and border colors together',function(){ cell.border = ['gray']; cell.head = ['red']; cell.x = cell.y = 0; expect(cell.draw(0)).to.equal(colors.gray('L') + colors.red(' hello ')); cell.drawRight = true; expect(cell.draw(0)).to.equal(colors.gray('L') + colors.red(' hello ') + colors.gray('R')); }); }); describe('second line of text',function(){ beforeEach(function () { cell.width = 9; }); it('will draw left side if x=0',function(){ cell.x = 0; expect(cell.draw(1)).to.equal('L howdy '); cell.drawRight = true; expect(cell.draw(1)).to.equal('L howdy R'); }); it('will draw mid side if x=1',function(){ cell.x = 1; expect(cell.draw(1)).to.equal('M howdy '); cell.drawRight = true; expect(cell.draw(1)).to.equal('M howdy R'); }); it('will align left',function(){ cell.x = 1; cell.hAlign = 'left'; expect(cell.draw(1)).to.equal('M howdy '); cell.drawRight = true; expect(cell.draw(1)).to.equal('M howdy R'); }); it('will align right',function(){ cell.x = 1; cell.hAlign = 'right'; expect(cell.draw(1)).to.equal('M howdy '); cell.drawRight = true; expect(cell.draw(1)).to.equal('M howdy R'); }); }); describe('truncated line of text',function(){ beforeEach(function () { cell.width = 9; }); it('will draw left side if x=0',function(){ cell.x = 0; expect(cell.draw(2)).to.equal('L goodni… '); cell.drawRight = true; expect(cell.draw(2)).to.equal('L goodni… R'); }); it('will draw mid side if x=1',function(){ cell.x = 1; expect(cell.draw(2)).to.equal('M goodni… '); cell.drawRight = true; expect(cell.draw(2)).to.equal('M goodni… R'); }); it('will not change when aligned left',function(){ cell.x = 1; cell.hAlign = 'left'; expect(cell.draw(2)).to.equal('M goodni… '); cell.drawRight = true; expect(cell.draw(2)).to.equal('M goodni… R'); }); it('will not change when aligned right',function(){ cell.x = 1; cell.hAlign = 'right'; expect(cell.draw(2)).to.equal('M goodni… '); cell.drawRight = true; expect(cell.draw(2)).to.equal('M goodni… R'); }); }); describe('vAlign',function(){ beforeEach(function () { cell.height = '5'; }); it('center',function(){ cell.vAlign = 'center'; expect(cell.draw(0)).to.equal('L '); expect(cell.draw(1)).to.equal('L hello '); expect(cell.draw(2)).to.equal('L howdy '); expect(cell.draw(3)).to.equal('L good… '); expect(cell.draw(4)).to.equal('L '); cell.drawRight = true; expect(cell.draw(0)).to.equal('L R'); expect(cell.draw(1)).to.equal('L hello R'); expect(cell.draw(2)).to.equal('L howdy R'); expect(cell.draw(3)).to.equal('L good… R'); expect(cell.draw(4)).to.equal('L R'); cell.x = 1; cell.drawRight = false; expect(cell.draw(0)).to.equal('M '); expect(cell.draw(1)).to.equal('M hello '); expect(cell.draw(2)).to.equal('M howdy '); expect(cell.draw(3)).to.equal('M good… '); expect(cell.draw(4)).to.equal('M '); }); it('top',function(){ cell.vAlign = 'top'; expect(cell.draw(0)).to.equal('L hello '); expect(cell.draw(1)).to.equal('L howdy '); expect(cell.draw(2)).to.equal('L good… '); expect(cell.draw(3)).to.equal('L '); expect(cell.draw(4)).to.equal('L '); cell.vAlign = null; //top is the default cell.drawRight = true; expect(cell.draw(0)).to.equal('L hello R'); expect(cell.draw(1)).to.equal('L howdy R'); expect(cell.draw(2)).to.equal('L good… R'); expect(cell.draw(3)).to.equal('L R'); expect(cell.draw(4)).to.equal('L R'); cell.x = 1; cell.drawRight = false; expect(cell.draw(0)).to.equal('M hello '); expect(cell.draw(1)).to.equal('M howdy '); expect(cell.draw(2)).to.equal('M good… '); expect(cell.draw(3)).to.equal('M '); expect(cell.draw(4)).to.equal('M '); }); it('center',function(){ cell.vAlign = 'bottom'; expect(cell.draw(0)).to.equal('L '); expect(cell.draw(1)).to.equal('L '); expect(cell.draw(2)).to.equal('L hello '); expect(cell.draw(3)).to.equal('L howdy '); expect(cell.draw(4)).to.equal('L good… '); cell.drawRight = true; expect(cell.draw(0)).to.equal('L R'); expect(cell.draw(1)).to.equal('L R'); expect(cell.draw(2)).to.equal('L hello R'); expect(cell.draw(3)).to.equal('L howdy R'); expect(cell.draw(4)).to.equal('L good… R'); cell.x = 1; cell.drawRight = false; expect(cell.draw(0)).to.equal('M '); expect(cell.draw(1)).to.equal('M '); expect(cell.draw(2)).to.equal('M hello '); expect(cell.draw(3)).to.equal('M howdy '); expect(cell.draw(4)).to.equal('M good… '); }); }); it('vertically truncated will show truncation on last visible line',function(){ cell.height = 2; expect(cell.draw(0)).to.equal('L hello '); expect(cell.draw(1)).to.equal('L howd… '); }); it("won't vertically truncate if the lines just fit",function(){ cell.height = 2; cell.content = "hello\nhowdy"; cell.lines = cell.content.split("\n"); expect(cell.draw(0)).to.equal('L hello '); expect(cell.draw(1)).to.equal('L howdy '); }); it("will vertically truncate even if last line is short",function(){ cell.height = 2; cell.content = "hello\nhi\nhowdy"; cell.lines = cell.content.split("\n"); expect(cell.draw(0)).to.equal('L hello '); expect(cell.draw(1)).to.equal('L hi… '); }); it("allows custom truncation",function(){ cell.height = 2; cell.truncate = '...'; cell.content = "hello\nhi\nhowdy"; cell.lines = cell.content.split("\n"); expect(cell.draw(0)).to.equal('L hello '); expect(cell.draw(1)).to.equal('L hi... '); cell.content = "hello\nhowdy\nhi"; cell.lines = cell.content.split("\n"); expect(cell.draw(0)).to.equal('L hello '); expect(cell.draw(1)).to.equal('L ho... '); }); }); describe("ColSpanCell",function(){ it('has an init function',function(){ expect(new ColSpanCell()).to.respondTo('init'); new ColSpanCell().init(); // nothing happens. }); it('draw returns an empty string',function(){ expect(new ColSpanCell().draw('top')).to.equal(''); expect(new ColSpanCell().draw('bottom')).to.equal(''); expect(new ColSpanCell().draw(1)).to.equal(''); }); }); describe("RowSpanCell",function(){ var original, tableOptions; beforeEach(function () { original = { rowSpan:3, y:0, draw:sinon.spy() }; tableOptions = { rowHeights:[2,3,4,5] } }); it('drawing top of the next row',function(){ var spanner = new RowSpanCell(original); spanner.x = 0; spanner.y = 1; spanner.init(tableOptions); spanner.draw('top'); expect(original.draw).to.have.been.calledOnce.and.calledWith(2); }); it('drawing line 0 of the next row',function(){ var spanner = new RowSpanCell(original); spanner.x = 0; spanner.y = 1; spanner.init(tableOptions); spanner.draw(0); expect(original.draw).to.have.been.calledOnce.and.calledWith(3); }); it('drawing line 1 of the next row',function(){ var spanner = new RowSpanCell(original); spanner.x = 0; spanner.y = 1; spanner.init(tableOptions); spanner.draw(1); expect(original.draw).to.have.been.calledOnce.and.calledWith(4); }); it('drawing top of two rows below',function(){ var spanner = new RowSpanCell(original); spanner.x = 0; spanner.y = 2; spanner.init(tableOptions); spanner.draw('top'); expect(original.draw).to.have.been.calledOnce.and.calledWith(6); }); it('drawing line 0 of two rows below',function(){ var spanner = new RowSpanCell(original); spanner.x = 0; spanner.y = 2; spanner.init(tableOptions); spanner.draw(0); expect(original.draw).to.have.been.calledOnce.and.calledWith(7); }); it('drawing line 1 of two rows below',function(){ var spanner = new RowSpanCell(original); spanner.x = 0; spanner.y = 2; spanner.init(tableOptions); spanner.draw(1); expect(original.draw).to.have.been.calledOnce.and.calledWith(8); }); it('drawing bottom',function(){ var spanner = new RowSpanCell(original); spanner.x = 0; spanner.y = 1; spanner.init(tableOptions); spanner.draw('bottom'); expect(original.draw).to.have.been.calledOnce.and.calledWith('bottom'); }); }); }); cli-table2-0.2.0/test/example-tests.js000066400000000000000000000004231265445240400175440ustar00rootroot00000000000000var printExamples = require('../lib/print-example'); var examples = require('../examples/col-and-row-span-examples'); var usage = require('../examples/basic-usage-examples'); printExamples.runTest('@api Usage',usage); printExamples.runTest('@api Table (examples)',examples);cli-table2-0.2.0/test/layout-manager-test.js000066400000000000000000000104121265445240400206520ustar00rootroot00000000000000describe('layout-manager',function(){ var chai = require('chai'); var expect = chai.expect; var layoutManager = require('../src/layout-manager'); var layoutTable = layoutManager.layoutTable; var addRowSpanCells = layoutManager.addRowSpanCells; var maxWidth = layoutManager.maxWidth; var Cell = require('../src/cell'); var RowSpanCell = Cell.RowSpanCell; describe('layoutTable',function(){ it('sets x and y',function(){ var table = [ [{},{}], [{},{}] ]; layoutTable(table); expect(table).to.eql([ [{x:0,y:0},{x:1,y:0}], [{x:0,y:1},{x:1,y:1}] ]); var w = maxWidth(table); expect(w).to.equal(2); }); it('colSpan will push x values to the right',function(){ var table = [ [{colSpan:2},{}], [{},{colSpan:2}] ]; layoutTable(table); expect(table).to.eql([ [{x:0,y:0,colSpan:2},{x:2,y:0}], [{x:0,y:1},{x:1,y:1,colSpan:2}] ]); expect(maxWidth(table)).to.equal(3); }); it('rowSpan will push x values on cells below',function(){ var table = [ [{rowSpan:2},{}], [{}] ]; layoutTable(table); expect(table).to.eql([ [{x:0,y:0,rowSpan:2},{x:1,y:0}], [{x:1,y:1}] ]); expect(maxWidth(table)).to.equal(2); }); it('colSpan and rowSpan together',function(){ var table = [ [{rowSpan:2,colSpan:2},{}], [{}] ]; layoutTable(table); expect(table).to.eql([ [{x:0,y:0,rowSpan:2,colSpan:2},{x:2,y:0}], [{x:2,y:1}] ]); expect(maxWidth(table)).to.equal(3); }); it('complex layout',function(){ var table = [ [{c:'a'},{c:'b'}, {c:'c',rowSpan:3,colSpan:2}, {c:'d'}], [{c:'e',rowSpan:2,colSpan:2}, {c:'f'}], [ {c:'g'}] ]; layoutTable(table); expect(table).to.eql([ [{c:'a',y:0,x:0}, {c:'b',y:0,x:1}, {c:'c',y:0,x:2,rowSpan:3,colSpan:2}, {c:'d',y:0,x:4}], [{c:'e',rowSpan:2,colSpan:2,y:1,x:0}, {c:'f',y:1,x:4}], [{c:'g',y:2,x:4}] ]); }); it('maxWidth of single element',function(){ var table = [[{}]]; layoutTable(table) expect(maxWidth(table)).to.equal(1); }); }); describe('addRowSpanCells',function(){ it('will insert a rowSpan cell - beginning of line',function(){ var table = [ [{x:0,y:0,rowSpan:2},{x:1,y:0}], [{x:1,y:1}] ]; addRowSpanCells(table); expect(table[0]).to.eql([{x:0,y:0,rowSpan:2},{x:1,y:0}]); expect(table[1].length).to.equal(2); expect(table[1][0]).to.be.instanceOf(RowSpanCell); expect(table[1][1]).to.eql({x:1,y:1}); }); it('will insert a rowSpan cell - end of line',function(){ var table = [ [{x:0,y:0},{x:1,y:0,rowSpan:2}], [{x:0,y:1}] ]; addRowSpanCells(table); expect(table[0]).to.eql([{x:0,y:0},{rowSpan:2,x:1,y:0}]); expect(table[1].length).to.equal(2); expect(table[1][0]).to.eql({x:0,y:1}); expect(table[1][1]).to.be.instanceOf(RowSpanCell); }); it('will insert a rowSpan cell - middle of line',function(){ var table = [ [{x:0,y:0},{x:1,y:0,rowSpan:2},{x:2,y:0}], [{x:0,y:1},{x:2,y:1}] ]; addRowSpanCells(table); expect(table[0]).to.eql([{x:0,y:0},{rowSpan:2,x:1,y:0},{x:2,y:0}]); expect(table[1].length).to.equal(3); expect(table[1][0]).to.eql({x:0,y:1}); expect(table[1][1]).to.be.instanceOf(RowSpanCell); expect(table[1][2]).to.eql({x:2,y:1}); }); it('will insert a rowSpan cell - multiple on the same line',function(){ var table = [ [{x:0,y:0},{x:1,y:0,rowSpan:2},{x:2,y:0,rowSpan:2},{x:3,y:0}], [{x:0,y:1},{x:3,y:1}] ]; addRowSpanCells(table); expect(table[0]).to.eql([{x:0,y:0},{rowSpan:2,x:1,y:0},{rowSpan:2,x:2,y:0},{x:3,y:0}]); expect(table[1].length).to.equal(4); expect(table[1][0]).to.eql({x:0,y:1}); expect(table[1][1]).to.be.instanceOf(RowSpanCell); expect(table[1][2]).to.be.instanceOf(RowSpanCell); expect(table[1][3]).to.eql({x:3,y:1}); }); }); });cli-table2-0.2.0/test/original-cli-table-index-tests.js000066400000000000000000000245171265445240400226660ustar00rootroot00000000000000describe('@api original-cli-table index tests',function(){ var Table = require('../src/table'); var chai = require('chai'); var expect = chai.expect; it('test complete table', function (){ var table = new Table({ head: ['Rel', 'Change', 'By', 'When'] , style: { 'padding-left': 1 , 'padding-right': 1 , head: [] , border: [] } , colWidths: [6, 21, 25, 17] }); table.push( ['v0.1', 'Testing something cool', 'rauchg@gmail.com', '7 minutes ago'] , ['v0.1', 'Testing something cool', 'rauchg@gmail.com', '8 minutes ago'] ); var expected = [ '┌──────┬─────────────────────┬─────────────────────────┬─────────────────┐' , '│ Rel │ Change │ By │ When │' , '├──────┼─────────────────────┼─────────────────────────┼─────────────────┤' , '│ v0.1 │ Testing something … │ rauchg@gmail.com │ 7 minutes ago │' , '├──────┼─────────────────────┼─────────────────────────┼─────────────────┤' , '│ v0.1 │ Testing something … │ rauchg@gmail.com │ 8 minutes ago │' , '└──────┴─────────────────────┴─────────────────────────┴─────────────────┘' ]; expect(table.toString()).to.equal(expected.join("\n")); //expect(table.render()).should.eql(expected.join("\n")); }); it('test width property', function (){ var table = new Table({ head: ['Cool'], style: { head: [], border: [] } }); expect(table.width).to.equal(8); }); it('test vertical table output', function() { var table = new Table({ style: {'padding-left':0, 'padding-right':0, head:[], border:[]} }); // clear styles to prevent color output table.push( {'v0.1': 'Testing something cool'} , {'v0.1': 'Testing something cool'} ); var expected = [ '┌────┬──────────────────────┐' , '│v0.1│Testing something cool│' , '├────┼──────────────────────┤' , '│v0.1│Testing something cool│' , '└────┴──────────────────────┘' ]; expect(table.toString()).to.equal(expected.join("\n")); }); it('test cross table output', function() { var table = new Table({ head: ["", "Header 1", "Header 2"], style: {'padding-left':0, 'padding-right':0, head:[], border:[]} }); // clear styles to prevent color output table.push( {"Header 3": ['v0.1', 'Testing something cool'] } , {"Header 4": ['v0.1', 'Testing something cool'] } ); var expected = [ '┌────────┬────────┬──────────────────────┐' , '│ │Header 1│Header 2 │' , '├────────┼────────┼──────────────────────┤' , '│Header 3│v0.1 │Testing something cool│' , '├────────┼────────┼──────────────────────┤' , '│Header 4│v0.1 │Testing something cool│' , '└────────┴────────┴──────────────────────┘' ]; expect(table.toString()).to.equal(expected.join("\n")); }); it('test table colors', function(){ var table = new Table({ head: ['Rel', 'By'], style: {head: ['red'], border: ['grey']} }); /*var off = '' , red = '' , orange = '' , grey = ''*/ var off = '\u001b[39m' , red = '\u001b[31m' , orange = '\u001b[38;5;221m' , grey = '\u001b[90m' , c256s = orange + 'v0.1' + off; table.push( [c256s, 'rauchg@gmail.com'] ); // The expectation from the original cli-table is commented out below. // The output from cli-table2 will still look the same, but the border color is // toggled off and back on at the border of each cell. /*var expected = [ grey + '┌──────┬──────────────────┐' + off , grey + '│' + off + red + ' Rel ' + off + grey + '│' + off + red + ' By ' + off + grey + '│' + off , grey + '├──────┼──────────────────┤' + off , grey + '│' + off + ' ' + c256s + ' ' + grey + '│' + off + ' rauchg@gmail.com ' + grey + '│' + off , grey + '└──────┴──────────────────┘' + off ];*/ var expected = [ grey + '┌──────'+off+grey+'┬──────────────────┐' + off , grey + '│' + off + red + ' Rel ' + off + grey + '│' + off + red + ' By ' + off + grey + '│' + off , grey + '├──────'+off+grey+'┼──────────────────┤' + off , grey + '│' + off + ' ' + c256s + ' ' + grey + '│' + off + ' rauchg@gmail.com ' + grey + '│' + off , grey + '└──────'+off+grey+'┴──────────────────┘' + off ]; expect(table.toString()).to.equal(expected.join("\n")); }); it('test custom chars', function (){ var table = new Table({ chars: { 'top': '═' , 'top-mid': '╤' , 'top-left': '╔' , 'top-right': '╗' , 'bottom': '═' , 'bottom-mid': '╧' , 'bottom-left': '╚' , 'bottom-right': '╝' , 'left': '║' , 'left-mid': '╟' , 'right': '║' , 'right-mid': '╢' }, style: { head: [] , border: [] } }); table.push( ['foo', 'bar', 'baz'] , ['frob', 'bar', 'quuz'] ); var expected = [ '╔══════╤═════╤══════╗' , '║ foo │ bar │ baz ║' , '╟──────┼─────┼──────╢' , '║ frob │ bar │ quuz ║' , '╚══════╧═════╧══════╝' ]; expect(table.toString()).to.equal(expected.join("\n")); }); it('test compact shortand', function (){ var table = new Table({ style: { head: [] , border: [] , compact : true } }); table.push( ['foo', 'bar', 'baz'] , ['frob', 'bar', 'quuz'] ); var expected = [ '┌──────┬─────┬──────┐' , '│ foo │ bar │ baz │' , '│ frob │ bar │ quuz │' , '└──────┴─────┴──────┘' ]; expect(table.toString()).to.equal(expected.join("\n")); }); it('test compact empty mid line', function (){ var table = new Table({ chars: { 'mid': '' , 'left-mid': '' , 'mid-mid': '' , 'right-mid': '' }, style: { head: [] , border: [] } }); table.push( ['foo', 'bar', 'baz'] , ['frob', 'bar', 'quuz'] ); var expected = [ '┌──────┬─────┬──────┐' , '│ foo │ bar │ baz │' , '│ frob │ bar │ quuz │' , '└──────┴─────┴──────┘' ]; expect(table.toString()).to.equal(expected.join("\n")); }); it('test decoration lines disabled', function (){ var table = new Table({ chars: { 'top': '' , 'top-mid': '' , 'top-left': '' , 'top-right': '' , 'bottom': '' , 'bottom-mid': '' , 'bottom-left': '' , 'bottom-right': '' , 'left': '' , 'left-mid': '' , 'mid': '' , 'mid-mid': '' , 'right': '' , 'right-mid': '' , 'middle': ' ' // a single space }, style: { head: [] , border: [] , 'padding-left': 0 , 'padding-right': 0 } }); table.push( ['foo', 'bar', 'baz'] , ['frobnicate', 'bar', 'quuz'] ); var expected = [ 'foo bar baz ' , 'frobnicate bar quuz' ]; expect(table.toString()).to.equal(expected.join("\n")); }); it('test with null/undefined as values or column names', function (){ var table = new Table({ style: { head: [] , border: [] } }); table.push( [null, undefined, 0] ); // This is the expectation from the original cli-table. // The empty columns have widths based on the strings `null` and `undefined` // That does not make sense to me, so I am deviating from the original behavior here. /*var expected = [ '┌──────┬───────────┬───┐' , '│ │ │ 0 │' , '└──────┴───────────┴───┘' ]; */ var expected = [ '┌──┬──┬───┐' , '│ │ │ 0 │' , '└──┴──┴───┘' ]; expect(table.toString()).to.equal(expected.join("\n")); }); }); cli-table2-0.2.0/test/original-cli-table-newlines-test.js000066400000000000000000000050541265445240400232130ustar00rootroot00000000000000describe('@api original-cli-table newline tests',function(){ var Table = require('../src/table'); var chai = require('chai'); var expect = chai.expect; it('test table with newlines in headers', function() { var table = new Table({ head: ['Test', "1\n2\n3"] , style: { 'padding-left': 1 , 'padding-right': 1 , head: [] , border: [] } }); var expected = [ '┌──────┬───┐' , '│ Test │ 1 │' , '│ │ 2 │' , '│ │ 3 │' , '└──────┴───┘' ]; expect(table.toString()).to.equal(expected.join("\n")); }); it('test column width is accurately reflected when newlines are present', function() { var table = new Table({ head: ['Test\nWidth'], style: {head:[], border:[]} }); expect(table.width).to.equal(9); }); it('test newlines in body cells', function() { var table = new Table({style: {head:[], border:[]}}); table.push(["something\nwith\nnewlines"]); var expected = [ '┌───────────┐' , '│ something │' , '│ with │' , '│ newlines │' , '└───────────┘' ]; expect(table.toString()).to.equal(expected.join("\n")); }); it('test newlines in vertical cell header and body', function() { var table = new Table({ style: {'padding-left':0, 'padding-right':0, head:[], border:[]} }); table.push( {'v\n0.1': 'Testing\nsomething cool'} ); var expected = [ '┌───┬──────────────┐' , '│v │Testing │' , '│0.1│something cool│' , '└───┴──────────────┘' ]; expect(table.toString()).to.equal(expected.join("\n")); }); it('test newlines in cross table header and body', function() { var table = new Table({ head: ["", "Header\n1"], style: {'padding-left':0, 'padding-right':0, head:[], border:[]} }); table.push({ "Header\n2": ['Testing\nsomething\ncool'] }); var expected = [ '┌──────┬─────────┐' , '│ │Header │' , '│ │1 │' , '├──────┼─────────┤' , '│Header│Testing │' , '│2 │something│' , '│ │cool │' , '└──────┴─────────┘' ]; expect(table.toString()).to.equal(expected.join("\n")); }); }); cli-table2-0.2.0/test/table-layout-test.js000066400000000000000000000314371265445240400203410ustar00rootroot00000000000000describe('tableLayout', function () { var Cell = require('../src/cell'); var layoutManager = require('../src/layout-manager'); var layoutTable = layoutManager.layoutTable; var makeTableLayout = layoutManager.makeTableLayout; var addRowSpanCells = layoutManager.addRowSpanCells; var maxWidth = layoutManager.maxWidth; var fillInTable = layoutManager.fillInTable; var computeWidths = layoutManager.computeWidths; var computeHeights = layoutManager.computeHeights; var chai = require('chai'); var expect = chai.expect; var _ = require('lodash'); it('simple 2x2 layout',function(){ var actual = makeTableLayout([ ['hello','goodbye'], ['hola','adios'] ]); var expected = [ ['hello','goodbye'], ['hola','adios'] ]; checkLayout(actual,expected); }); it('cross table',function(){ var actual = makeTableLayout([ {'1.0':['yes','no']}, {'2.0':['hello','goodbye']} ]); var expected = [ ['1.0','yes','no'], ['2.0','hello','goodbye'] ]; checkLayout(actual,expected); }); it('vertical table',function(){ var actual = makeTableLayout([ {'1.0':'yes'}, {'2.0':'hello'} ]); var expected = [ ['1.0','yes'], ['2.0','hello'] ]; checkLayout(actual,expected); }); it('colSpan adds RowSpanCells to the right',function(){ var actual = makeTableLayout([ [{content:'hello',colSpan:2}], ['hola','adios'] ]); var expected = [ [{content:'hello',colSpan:2},null], ['hola','adios'] ]; checkLayout(actual,expected); }); it('rowSpan adds RowSpanCell below',function(){ var actual = makeTableLayout([ [{content:'hello',rowSpan:2},'goodbye'], ['adios'] ]); var expected = [ ['hello' , 'goodbye'], [{spannerFor:[0,0]} , 'adios'] ]; checkLayout(actual,expected); }); it('rowSpan and cellSpan together',function(){ var actual = makeTableLayout([ [{content:'hello',rowSpan:2,colSpan:2},'goodbye'], ['adios'] ]); var expected = [ ['hello' , null, 'goodbye'], [{spannerFor:[0,0]} , null, 'adios'] ]; checkLayout(actual,expected); }); it('complex layout',function(){ var actual = makeTableLayout([ [{content:'hello',rowSpan:2,colSpan:2},{content:'yo',rowSpan:2,colSpan:2},'goodbye'], ['adios'] ]); var expected = [ ['hello' , null, 'yo' , null, 'goodbye'], [{spannerFor:[0,0]} , null, {spannerFor:[0,2]} , null, 'adios'] ]; checkLayout(actual,expected); }); it('complex layout2',function(){ var actual = makeTableLayout([ ['a','b', {content:'c',rowSpan:3,colSpan:2},'d'], [{content:'e',rowSpan:2,colSpan:2}, 'f'], ['g'] ]); var expected = [ ['a', 'b', 'c', null, 'd'], ['e', null, {spannerFor:[0,2]}, null, 'f'], [{spannerFor:[1,0]}, null, {spannerFor:[0,2]}, null, 'g'] ]; checkLayout(actual,expected); }); it('stairstep spans',function(){ var actual = makeTableLayout([ [{content:'',rowSpan:2},''], [{content:'',rowSpan:2}], [''] ]); var expected = [ [{content:'',rowSpan:2}, ''], [{spannerFor:[0,0]},{content:'',rowSpan:2}], ['',{spannerFor:[1,1]}] ]; checkLayout(actual,expected); }); describe('fillInTable',function(){ function mc(opts,y,x){ var cell = new Cell(opts); cell.x = x; cell.y = y; return cell; } it('will blank out individual cells',function(){ var cells = [ [mc('a',0,1)], [mc('b',1,0)] ]; fillInTable(cells); checkLayout(cells,[ ['', 'a'], ['b', ''] ]); }); it('will autospan to the right',function(){ var cells = [ [], [mc('a',1,1)] ]; fillInTable(cells); checkLayout(cells,[ [{content:'',colSpan:2}, null], ['', 'a'] ]); }); it('will autospan down',function(){ var cells = [ [ mc('a',0,1)], [] ]; fillInTable(cells); addRowSpanCells(cells); checkLayout(cells,[ [{content:'',rowSpan:2}, 'a'], [{spannerFor:[0,0]}, ''] ]); }); it('will autospan right and down',function(){ var cells = [ [ mc('a',0,2)], [], [ mc('b',2,1)] ]; fillInTable(cells); addRowSpanCells(cells); checkLayout(cells,[ [{content:'',colSpan:2, rowSpan:2}, null, 'a'], [{spannerFor:[0,0]}, null, {content:'', colSpan:1, rowSpan:2}], ['','b',{spannerFor:[1,2]}] ]); }); }); describe('computeWidths',function() { function mc(y,x,desiredWidth, colSpan) { return {x:x,y:y,desiredWidth:desiredWidth,colSpan:colSpan}; } it('finds the maximum desired width of each column', function () { var widths = []; var cells = [ [mc(0,0,7), mc(0,1,3), mc(0,2,5)], [mc(1,0,8), mc(1,1,5), mc(1,2,2)], [mc(2,0,6), mc(2,1,9), mc(2,2,1)] ]; computeWidths(widths, cells); expect(widths).to.eql([8, 9, 5]); }); it('won\'t touch hard coded values', function () { var widths = [null, 3]; var cells = [ [mc(0,0,7), mc(0,1,3), mc(0,2,5)], [mc(1,0,8), mc(1,1,5), mc(1,2,2)], [mc(2,0,6), mc(2,1,9), mc(2,2,1)] ]; computeWidths(widths, cells); expect(widths).to.eql([8, 3, 5]); }); it('assumes undefined desiredWidth is 1', function () { var widths = []; var cells = [[{x:0,y:0}], [{x:0,y:1}], [{x:0,y:2}]]; computeWidths(widths, cells); expect(widths).to.eql([1]) }); it('takes into account colSpan and wont over expand', function () { var widths = []; var cells = [ [mc(0,0,10, 2), mc(0,2,5)], [mc(1,0,5), mc(1,1,5), mc(1,2,2)], [mc(2,0,4), mc(2,1,2), mc(2,2,1)] ]; computeWidths(widths, cells); expect(widths).to.eql([5, 5, 5]); }); it('will expand rows involved in colSpan in a balanced way', function () { var widths = []; var cells = [ [mc(0,0,13,2), mc(0,2,5)], [mc(1,0,5), mc(1,1,5), mc(1,2,2)], [mc(2,0,4), mc(2,1,2), mc(2,2,1)] ]; computeWidths(widths, cells); expect(widths).to.eql([6, 6, 5]); }); it('expands across 3 cols', function () { var widths = []; var cells = [ [mc(0,0,25,3) ], [mc(1,0,5), mc(1,1,5), mc(1,2,2) ], [mc(2,0,4), mc(2,1,2), mc(2,2,1) ] ]; computeWidths(widths, cells); expect(widths).to.eql([9, 9, 5]); }); it('multiple spans in same table', function () { var widths = []; var cells = [ [mc(0,0,25,3) ], [mc(1,0,30,3) ], [mc(2,0,4), mc(2,1,2), mc(2,2,1) ] ]; computeWidths(widths, cells); expect(widths).to.eql([11, 9, 8]); }); it('spans will only edit uneditable tables',function(){ var widths = [null, 3]; var cells = [ [mc(0,0,20,3) ], [mc(1,0,4), mc(1,1,20), mc(1,2,5) ] ]; computeWidths(widths, cells); expect(widths).to.eql([7,3,8]) }); it('spans will only edit uneditable tables - first column uneditable',function(){ var widths = [3]; var cells = [ [mc(0,0,20,3) ], [mc(1,0,4), mc(1,1,3), mc(1,2,5) ] ]; computeWidths(widths, cells); expect(widths).to.eql([3,7,8]) }); }); describe('computeHeights',function(){ function mc(y,x,desiredHeight,colSpan){ return {x:x,y:y,desiredHeight:desiredHeight,rowSpan:colSpan}; } it('finds the maximum desired height of each row',function(){ var heights = []; var cells = [ [mc(0,0,7), mc(0,1,3), mc(0,2,5) ], [mc(1,0,8), mc(1,1,5), mc(1,2,2) ], [mc(2,0,6), mc(2,1,9), mc(2,2,1) ] ]; computeHeights(heights,cells); expect(heights).to.eql([7,8,9]); }); it('won\'t touch hard coded values',function(){ var heights = [null,3]; var cells = [ [mc(0,0,7), mc(0,1,3), mc(0,2,5)], [mc(1,0,8), mc(1,1,5), mc(1,2,2)], [mc(2,0,6), mc(2,1,9), mc(2,2,1)] ]; computeHeights(heights,cells); expect(heights).to.eql([7,3,9]); }); it('assumes undefined desiredHeight is 1',function(){ var heights = []; var cells = [[{x:0,y:0},{x:1,y:0},{x:2,y:0}]]; computeHeights(heights,cells); expect(heights).to.eql([1]) }); it('takes into account rowSpan and wont over expand',function(){ var heights = []; var cells = [ [mc(0,0,10,2), mc(0,1,5), mc(0,2,2)], [ mc(1,1,5), mc(1,2,2)], [mc(2,0,4), mc(2,1,2), mc(2,2,1)] ]; computeHeights(heights,cells); expect(heights).to.eql([5,5,4]); }); it('will expand rows involved in rowSpan in a balanced way',function(){ var heights = []; var cells = [ [mc(0,0,13,2), mc(0,1,5), mc(0,2,5)], [ mc(1,1,5), mc(1,2,2)], [mc(2,0,4), mc(2,1,2), mc(2,2,1)] ]; computeHeights(heights,cells); expect(heights).to.eql([6,6,4]); }); it('expands across 3 rows',function(){ var heights = []; var cells = [ [mc(0,0,25,3), mc(0,1,5), mc(0,2,4)], [ mc(1,1,5), mc(1,2,2)], [ mc(2,1,2), mc(2,2,1)] ]; computeHeights(heights,cells); expect(heights).to.eql([9,9,5]); }); it('multiple spans in same table',function(){ var heights = []; var cells = [ [mc(0,0,25,3), mc(0,1,30,3), mc(0,2,4)], [ mc(1,2,2)], [ mc(2,2,1)] ]; computeHeights(heights,cells); expect(heights).to.eql([11,9,8]); }); }); /** * Provides a shorthand for validating a table of cells. * To pass, both arrays must have the same dimensions, and each cell in `actualRows` must * satisfy the shorthand assertion of the corresponding location in `expectedRows`. * * Available Expectations Can Be: * * * A `String` - Must be a normal cell with contents equal to the String value. * * `null` - Must be a RowSpanCell * * Or an `Object` with any of the following properties (multiple properties allowed): * * rowSpan:Number - Must be a normal cell with the given rowSpan. * * colSpan:Number - Must be a normal cell with the given colSpan. * * content:String - Must be a normal cell with the given content. * * spannerFor:[row,col] - Must be a RowSpanCell delegating to the cell at the given coordinates. * * @param actualRows - the table of cells under test. * @param expectedRows - a table of shorthand assertions. */ function checkLayout(actualTable,expectedTable){ _.forEach(expectedTable,function(expectedRow,y){ _.forEach(expectedRow,function(expectedCell,x){ if(expectedCell !== null){ var actualCell = findCell(actualTable,x,y); checkExpectation(actualCell,expectedCell,x,y,actualTable); } }); }); } function findCell(table,x,y){ for(var i = 0; i < table.length; i++){ var row = table[i]; for(var j = 0; j < row.length; j++){ var cell = row[j]; if(cell.x === x && cell.y === y){ return cell; } } } } function checkExpectation(actualCell,expectedCell,x,y,actualTable){ if(_.isString(expectedCell)){ expectedCell = {content:expectedCell}; } var address = '(' + y + ',' + x + ')'; if(expectedCell.hasOwnProperty('content')){ expect(actualCell, address).to.be.instanceOf(Cell); expect(actualCell.content,'content of ' + address).to.equal(expectedCell.content); } if(expectedCell.hasOwnProperty('rowSpan')){ expect(actualCell, address).to.be.instanceOf(Cell); expect(actualCell.rowSpan, 'rowSpan of ' + address).to.equal(expectedCell.rowSpan); } if(expectedCell.hasOwnProperty('colSpan')){ expect(actualCell, address).to.be.instanceOf(Cell); expect(actualCell.colSpan, 'colSpan of ' + address).to.equal(expectedCell.colSpan); } if(expectedCell.hasOwnProperty('spannerFor')){ expect(actualCell, address).to.be.instanceOf(Cell.RowSpanCell); expect(actualCell.originalCell,address + 'originalCell should be a cell').to.be.instanceOf(Cell); expect(actualCell.originalCell,address + 'originalCell not right').to.equal(findCell(actualTable, expectedCell.spannerFor[1], expectedCell.spannerFor[0] )); //TODO: retest here x,y coords } } });cli-table2-0.2.0/test/table-test.js000066400000000000000000000054651265445240400170300ustar00rootroot00000000000000describe('@api Table ',function(){ var chai = require('chai'); var expect = chai.expect; var Table = require('..'); var colors = require('colors/safe'); it('wordWrap with colored text',function(){ var table = new Table({style:{border:[],head:[]},wordWrap:true,colWidths:[7,9]}); table.push([colors.red('Hello how are you?'),colors.blue('I am fine thanks!')]); var expected = [ '┌───────┬─────────┐' , '│ ' + colors.red('Hello') + ' │ ' + colors.blue('I am') + ' │' , '│ ' + colors.red('how') + ' │ ' + colors.blue('fine') + ' │' , '│ ' + colors.red('are') + ' │ ' + colors.blue('thanks!') + ' │' , '│ ' + colors.red('you?') + ' │ │' , '└───────┴─────────┘' ]; expect(table.toString()).to.equal(expected.join('\n')); }); it('allows numbers as `content` property of cells defined using object notation', function() { var table = new Table({style:{border:[],head:[]}}); table.push([{content: 12}]); var expected = [ '┌────┐' , '│ 12 │' , '└────┘' ]; expect(table.toString()).to.equal(expected.join('\n')); }); it('throws if content is not a string or number', function() { var table = new Table({style:{border:[],head:[]}}); expect(function() { table.push([{content: {a:'b'}}]); table.toString(); }).to.throw(); }); it('works with CJK values', function () { var table = new Table({style: {border:[],head:[]}, colWidths: [5, 10, 5]}); table.push( ['foobar', 'English test', 'baz'] , ['foobar', '中文测试', 'baz'] , ['foobar', '日本語テスト', 'baz'] , ['foobar', '한국어테스트', 'baz'] ); var expected = [ '┌─────┬──────────┬─────┐' , '│ fo… │ English… │ baz │' , '├─────┼──────────┼─────┤' , '│ fo… │ 中文测试 │ baz │' , '├─────┼──────────┼─────┤' , '│ fo… │ 日本語… │ baz │' , '├─────┼──────────┼─────┤' , '│ fo… │ 한국어… │ baz │' , '└─────┴──────────┴─────┘' ]; expect(table.toString()).to.equal(expected.join("\n")); }); }); /* var expected = [ '┌──┬───┬──┬──┐' , '│ │ │ │ │' , '├──┼───┼──┼──┤' , '│ │ … │ │ │' , '├──┼───┼──┼──┤' , '│ │ … │ │ │' , '└──┴───┴──┴──┘' ]; */ cli-table2-0.2.0/test/utils-test.js000066400000000000000000000322031265445240400170670ustar00rootroot00000000000000describe('utils',function(){ var colors = require('colors/safe'); var chai = require('chai'); var utils = require('../src/utils'); var expect = chai.expect; var strlen = utils.strlen; var repeat = utils.repeat; var pad = utils.pad; var truncate = utils.truncate; var mergeOptions = utils.mergeOptions; var wordWrap = utils.wordWrap; describe('strlen',function(){ it('length of "hello" is 5',function(){ expect(strlen('hello')).to.equal(5); }); it('length of "hi" is 2',function(){ expect(strlen('hi')).to.equal(2); }); it('length of "hello" in red is 5',function(){ expect(strlen(colors.red('hello'))).to.equal(5); }); it('length of "hello" in zebra is 5',function(){ expect(strlen(colors.zebra('hello'))).to.equal(5); }); it('length of "hello\\nhi\\nheynow" is 6',function(){ expect(strlen('hello\nhi\nheynow')).to.equal(6); }); it('length of "中文字符" is 8',function(){ expect(strlen('中文字符')).to.equal(8); }); it('length of "日本語の文字" is 12',function(){ expect(strlen('日本語の文字')).to.equal(12); }); it('length of "한글" is 4',function(){ expect(strlen('한글')).to.equal(4); }); }); describe('repeat',function(){ it('"-" x 3',function(){ expect(repeat('-',3)).to.equal('---'); }); it('"-" x 4',function(){ expect(repeat('-',4)).to.equal('----'); }); it('"=" x 4',function(){ expect(repeat('=',4)).to.equal('===='); }); }); describe('pad',function(){ it("pad('hello',6,' ', right) == ' hello'", function () { expect(pad('hello',6,' ','right')).to.equal(' hello'); }); it("pad('hello',7,' ', left) == 'hello '", function () { expect(pad('hello',7,' ','left')).to.equal('hello '); }); it("pad('hello',8,' ', center) == ' hello '", function () { expect(pad('hello',8,' ','center')).to.equal(' hello '); }); it("pad('hello',9,' ', center) == ' hello '", function () { expect(pad('hello',9,' ','center')).to.equal(' hello '); }); it("pad('yo',4,' ', center) == ' yo '", function () { expect(pad('yo',4,' ','center')).to.equal(' yo '); }); it('pad red(hello)', function(){ expect(pad(colors.red('hello'),7,' ','right')).to.equal(' ' + colors.red('hello')); }); it("pad('hello', 2, ' ', right) == 'hello'", function(){ expect(pad('hello', 2, ' ', 'right')).to.equal('hello'); }); }); describe('truncate',function(){ it('truncate("hello", 5) === "hello"',function(){ expect(truncate('hello',5)).to.equal('hello'); }); it('truncate("hello sir", 7, "…") == "hello …"',function(){ expect(truncate('hello sir', 7, '…')).to.equal('hello …'); }); it('truncate("hello sir", 6, "…") == "hello…"',function(){ expect(truncate('hello sir', 6, '…')).to.equal('hello…'); }); it('truncate("goodnight moon", 8, "…") == "goodnig…"',function(){ expect(truncate('goodnight moon', 8, '…')).to.equal('goodnig…'); }); it('truncate(colors.zebra("goodnight moon"), 15, "…") == colors.zebra("goodnight moon")',function(){ var original = colors.zebra('goodnight moon'); expect(truncate(original, 15, '…')).to.equal(original); }); it('truncate(colors.zebra("goodnight moon"), 8, "…") == colors.zebra("goodnig") + "…"',function(){ var original = colors.zebra('goodnight moon'); var expected = colors.zebra('goodnig') + '…'; expect(truncate(original, 8, '…')).to.equal(expected); }); it('truncate(colors.zebra("goodnight moon"), 9, "…") == colors.zebra("goodnig") + "…"',function(){ var original = colors.zebra('goodnight moon'); var expected = colors.zebra('goodnigh') + '…'; expect(truncate(original, 9, '…')).to.equal(expected); }); it('red(hello) + green(world) truncated to 9 chars',function(){ var original = colors.red('hello') + colors.green(' world'); var expected = colors.red('hello') + colors.green(' wo') + '…'; expect(truncate(original, 9)).to.equal(expected); }); it('red-on-green(hello) + green-on-red(world) truncated to 9 chars',function(){ var original = colors.red.bgGreen('hello') + colors.green.bgRed(' world'); var expected = colors.red.bgGreen('hello') + colors.green.bgRed(' wo') + '…'; expect(truncate(original,9)).to.equal(expected); }); it('red-on-green(hello) + green-on-red(world) truncated to 10 chars - using inverse',function(){ var original = colors.red.bgGreen('hello' + colors.inverse(' world')); var expected = colors.red.bgGreen('hello' + colors.inverse(' wor')) + '…'; expect(truncate(original,10)).to.equal(expected); }); it('red-on-green( zebra (hello world) ) truncated to 11 chars',function(){ var original = colors.red.bgGreen(colors.zebra('hello world')); var expected = colors.red.bgGreen(colors.zebra('hello world')); expect(truncate(original,11)).to.equal(expected); }); it('red-on-green( zebra (hello world) ) truncated to 10 chars',function(){ var original = colors.red.bgGreen(colors.zebra('hello world')); var expected = colors.red.bgGreen(colors.zebra('hello wor')) + '…'; expect(truncate(original,10)).to.equal(expected); }); it('handles reset code', function() { var original = '\x1b[31mhello\x1b[0m world'; var expected = '\x1b[31mhello\x1b[0m wor…'; expect(truncate(original,10)).to.equal(expected); }); it('handles reset code (EMPTY VERSION)', function() { var original = '\x1b[31mhello\x1b[0m world'; var expected = '\x1b[31mhello\x1b[0m wor…'; expect(truncate(original,10)).to.equal(expected); }); it('truncateWidth("漢字テスト", 15) === "漢字テスト"',function(){ expect(truncate('漢字テスト',15)).to.equal('漢字テスト'); }); it('truncateWidth("漢字テスト", 6) === "漢字…"',function(){ expect(truncate('漢字テスト',6)).to.equal('漢字…'); }); it('truncateWidth("漢字テスト", 5) === "漢字…"',function(){ expect(truncate('漢字テスト',5)).to.equal('漢字…'); }); it('truncateWidth("漢字testてすと", 12) === "漢字testて…"',function(){ expect(truncate('漢字testてすと',12)).to.equal('漢字testて…'); }); it('handles color code with CJK chars',function(){ var original = '漢字\x1b[31m漢字\x1b[0m漢字'; var expected = '漢字\x1b[31m漢字\x1b[0m漢…'; expect(truncate(original,11)).to.equal(expected); }); }); function defaultOptions(){ return { chars: { 'top': '─' , 'top-mid': '┬' , 'top-left': '┌' , 'top-right': '┐' , 'bottom': '─' , 'bottom-mid': '┴' , 'bottom-left': '└' , 'bottom-right': '┘' , 'left': '│' , 'left-mid': '├' , 'mid': '─' , 'mid-mid': '┼' , 'right': '│' , 'right-mid': '┤' , 'middle': '│' } , truncate: '…' , colWidths: [] , rowHeights: [] , colAligns: [] , rowAligns: [] , style: { 'padding-left': 1 , 'padding-right': 1 , head: ['red'] , border: ['grey'] , compact : false } , head: [] }; } describe('mergeOptions',function(){ it('allows you to override chars',function(){ expect(mergeOptions()).to.eql(defaultOptions()); }); it('chars will be merged deeply',function(){ var expected = defaultOptions(); expected.chars.left = 'L'; expect(mergeOptions({chars:{left:'L'}})).to.eql(expected); }); it('style will be merged deeply',function(){ var expected = defaultOptions(); expected.style['padding-left'] = 2; expect(mergeOptions({style:{'padding-left':2}})).to.eql(expected); }); it('head will be overwritten',function(){ var expected = defaultOptions(); expected.style.head = []; //we can't use lodash's `merge()` in implementation because it would deeply copy array. expect(mergeOptions({style:{'head':[]}})).to.eql(expected); }); it('border will be overwritten',function(){ var expected = defaultOptions(); expected.style.border = []; //we can't use lodash's `merge()` in implementation because it would deeply copy array. expect(mergeOptions({style:{'border':[]}})).to.eql(expected); }); }); describe('wordWrap',function(){ it('length',function(){ var input = 'Hello, how are you today? I am fine, thank you!'; var expected = 'Hello, how\nare you\ntoday? I\nam fine,\nthank you!'; expect(wordWrap(10,input).join('\n')).to.equal(expected); }); it('length with colors',function(){ var input = colors.red('Hello, how are') + colors.blue(' you today? I') + colors.green(' am fine, thank you!'); var expected = colors.red('Hello, how\nare') + colors.blue(' you\ntoday? I') + colors.green('\nam fine,\nthank you!'); expect(wordWrap(10,input).join('\n')).to.equal(expected); }); it('will not create an empty last line',function(){ var input = 'Hello Hello '; var expected = 'Hello\nHello'; expect(wordWrap(5,input).join('\n')).to.equal(expected); }); it('will handle color reset code',function(){ var input = '\x1b[31mHello\x1b[0m Hello '; var expected = '\x1b[31mHello\x1b[0m\nHello'; expect(wordWrap(5,input).join('\n')).to.equal(expected); }); it('will handle color reset code (EMPTY version)',function(){ var input = '\x1b[31mHello\x1b[m Hello '; var expected = '\x1b[31mHello\x1b[m\nHello'; expect(wordWrap(5,input).join('\n')).to.equal(expected); }); it('words longer than limit will not create extra newlines',function(){ var input = 'disestablishment is a multiplicity someotherlongword'; var expected = 'disestablishment\nis a\nmultiplicity\nsomeotherlongword'; expect(wordWrap(7,input).join('\n')).to.equal(expected); }); it('multiple line input',function(){ var input = 'a\nb\nc d e d b duck\nm\nn\nr'; var expected = ['a', 'b', 'c d', 'e d', 'b', 'duck', 'm', 'n', 'r']; expect(wordWrap(4,input)).to.eql(expected); }); it('will not start a line with whitespace', function(){ var input = 'ab cd ef gh ij kl'; var expected = ['ab cd','ef gh', 'ij kl']; expect(wordWrap(7, input)).to.eql(expected); }); it('wraps CJK chars', function(){ var input = '漢字 漢\n字 漢字'; var expected = ['漢字 漢','字 漢字']; expect(wordWrap(7, input)).to.eql(expected); }); it('wraps CJK chars with colors', function(){ var input = '\x1b[31m漢字\x1b[0m\n 漢字'; var expected = ['\x1b[31m漢字\x1b[0m', ' 漢字']; expect(wordWrap(5, input)).to.eql(expected); }); }); describe('colorizeLines',function(){ it('foreground colors continue on each line',function(){ var input = colors.red('Hello\nHi').split('\n'); expect(utils.colorizeLines(input)).to.eql([ colors.red('Hello'), colors.red('Hi') ]); }); it('foreground colors continue on each line',function(){ var input = colors.bgRed('Hello\nHi').split('\n'); expect(utils.colorizeLines(input)).to.eql([ colors.bgRed('Hello'), colors.bgRed('Hi') ]); }); it('styles will continue on each line',function(){ var input = colors.underline('Hello\nHi').split('\n'); expect(utils.colorizeLines(input)).to.eql([ colors.underline('Hello'), colors.underline('Hi') ]); }); it('styles that end before the break will not be applied to the next line',function(){ var input = (colors.underline('Hello') +'\nHi').split('\n'); expect(utils.colorizeLines(input)).to.eql([ colors.underline('Hello'), 'Hi' ]); }); it('the reset code can be used to drop styles', function() { var input = '\x1b[31mHello\x1b[0m\nHi'.split('\n'); expect(utils.colorizeLines(input)).to.eql([ "\x1b[31mHello\x1b[0m", "Hi" ]); }); it('handles aixterm 16-color foreground', function() { var input = '\x1b[90mHello\nHi\x1b[0m'.split('\n'); expect(utils.colorizeLines(input)).to.eql([ '\x1b[90mHello\x1b[39m', '\x1b[90mHi\x1b[0m' ]); }); it('handles aixterm 16-color background', function() { var input = '\x1b[100mHello\nHi\x1b[m\nHowdy'.split('\n'); expect(utils.colorizeLines(input)).to.eql([ '\x1b[100mHello\x1b[49m', '\x1b[100mHi\x1b[m', 'Howdy' ]); }); it('handles aixterm 256-color foreground', function() { var input ='\x1b[48;5;8mHello\nHi\x1b[0m\nHowdy'.split('\n'); expect(utils.colorizeLines(input)).to.eql([ '\x1b[48;5;8mHello\x1b[49m', '\x1b[48;5;8mHi\x1b[0m', 'Howdy' ]); }); it('handles CJK chars',function(){ var input = colors.red('漢字\nテスト').split('\n'); expect(utils.colorizeLines(input)).to.eql([ colors.red('漢字'), colors.red('テスト') ]); }); }); });cli-table2-0.2.0/test/verify-legacy-compatibility-test.js000066400000000000000000000117401265445240400233470ustar00rootroot00000000000000(function(){ describe('verify original cli-table behavior',function(){ commonTests(require('cli-table')); }); describe('@api cli-table2 matches verified behavior',function(){ commonTests(require('../src/table')); }); function commonTests(Table){ var chai = require('chai'); var expect = chai.expect; var colors = require('colors/safe'); it('empty table has a width of 0',function(){ var table = new Table(); expect(table.width).to.equal(0); expect(table.toString()).to.equal(''); }); it('header text will be colored according to style',function(){ var table = new Table({head:['hello','goodbye'],style:{border:[],head:['red','bgWhite']}}); var expected = [ '┌───────┬─────────┐' , '│' + colors.bgWhite.red(' hello ') +'│' + colors.bgWhite.red(' goodbye ') + '│' , '└───────┴─────────┘' ]; expect(table.toString()).to.equal(expected.join('\n')); }); it('tables with one row of data will not be treated as headers',function(){ var table = new Table({style:{border:[],head:['red']}}); table.push(['hello','goodbye']); var expected = [ '┌───────┬─────────┐' , '│ hello │ goodbye │' , '└───────┴─────────┘' ]; expect(table.toString()).to.equal(expected.join('\n')); }); it('table with headers and data headers',function(){ var table = new Table({head:['hello','goodbye'],style:{border:[],head:['red']}}); table.push(['hola','adios']); var expected = [ '┌───────┬─────────┐' , '│' + colors.red(' hello ') +'│' + colors.red(' goodbye ') + '│' , '├───────┼─────────┤' , '│ hola │ adios │' , '└───────┴─────────┘' ]; expect(table.toString()).to.equal(expected.join('\n')); }); it('compact shorthand',function(){ var table = new Table({style:{compact:true,border:[],head:['red']}}); table.push(['hello','goodbye'],['hola','adios']); var expected = [ '┌───────┬─────────┐' , '│ hello │ goodbye │' , '│ hola │ adios │' , '└───────┴─────────┘' ]; expect(table.toString()).to.equal(expected.join('\n')); }); it('compact shorthand - headers are still rendered with separator',function(){ var table = new Table({head:['hello','goodbye'],style:{compact:true,border:[],head:[]}}); table.push(['hola','adios'],['hi','bye']); var expected = [ '┌───────┬─────────┐' , '│ hello │ goodbye │' , '├───────┼─────────┤' , '│ hola │ adios │' , '│ hi │ bye │' , '└───────┴─────────┘' ]; expect(table.toString()).to.equal(expected.join('\n')); }); it('compact longhand - headers are not rendered with separator',function(){ var table = new Table({ chars: { 'mid': '' , 'left-mid': '' , 'mid-mid': '' , 'right-mid': '' }, head:['hello','goodbye'], style:{border:[],head:[]}} ); table.push(['hola','adios'],['hi','bye']); var expected = [ '┌───────┬─────────┐' , '│ hello │ goodbye │' , '│ hola │ adios │' , '│ hi │ bye │' , '└───────┴─────────┘' ]; expect(table.toString()).to.equal(expected.join('\n')); }); it('compact longhand',function(){ var table = new Table({ chars: { 'mid': '' , 'left-mid': '' , 'mid-mid': '' , 'right-mid': '' }, style:{border:[],head:['red']} }); table.push(['hello','goodbye'],['hola','adios']); var expected = [ '┌───────┬─────────┐' , '│ hello │ goodbye │' , '│ hola │ adios │' , '└───────┴─────────┘' ]; expect(table.toString()).to.equal(expected.join('\n')); }); it('objects with multiple properties in a cross-table',function(){ var table = new Table({style:{border:[],head:[]}}); table.push( {'a':['b'], c:['d']} // value of property 'c' will be discarded ); var expected = [ '┌───┬───┐' , '│ a │ b │' , '└───┴───┘' ]; expect(table.toString()).to.equal(expected.join('\n')); }); } })();