From 631c19de8e10338ea407889eeb710f3cb422a3b8 Mon Sep 17 00:00:00 2001 From: Marc Abramowitz Date: Fri, 24 Sep 2021 18:16:11 -0700 Subject: [PATCH] Fix width calc w/ certain new ANSI escapes Fixes width calculations that were off when table contained terminal hyperlink ANSI escape codes, which are some newer kind of ANSI escape codes, supported by some terminals, such as iTerm. This was accomplished by replacing regexes with use of the [strip-ansi](https://www.npmjs.com/package/strip-ansi) module, which presumably has more up-to-date regexes that know how to deal with these newer ANSI escape codes. --- examples/revs.js | 27 ++++++++++++++++++++---- lib/utils.js | 4 ++-- package-lock.json | 52 +++++++++++++++++++++++++++++----------------- package.json | 4 +++- test/index.test.js | 32 ++++++++++++++++++++++++++++ 5 files changed, 93 insertions(+), 26 deletions(-) diff --git a/examples/revs.js b/examples/revs.js index 83d0105..0a54976 100644 --- a/examples/revs.js +++ b/examples/revs.js @@ -4,6 +4,7 @@ */ var Table = require('../lib'); +var hyperlinker = require('hyperlinker'); /** * Example. @@ -22,12 +23,16 @@ table.push( console.log(table.toString()); - /* compact */ var table = new Table({ - head: ['Rel', 'Change', 'By', 'When'] - , colWidths: [6, 21, 25, 17] - , style : {compact : true, 'padding-left' : 1} + head: ['Rel', 'Change', 'By', 'Link', 'When'] + , style: { + 'padding-left': 1 + , 'padding-right': 1 + , head: [] + , border: [] + } + , colWidths: [6, 21, 25, 17, 17] }); table.push( @@ -39,6 +44,20 @@ table.push( console.log(table.toString()); +/* with hyperlinks */ +var table = new Table({ + head: ['Rel', 'Change', 'By', 'Link', 'When'] + , colWidths: [6, 21, 25, 17, 17] + , style : {compact : true, 'padding-left' : 1} +}); + +table.push( + ['v0.1', 'testing something cool', 'rauchg@gmail.com', hyperlinker('link', 'https://adobe.com'), '7 minutes ago'] + , ['v0.1', 'testing something cool', 'rauchg@gmail.com', hyperlinker('link', 'https://adobe.com'), '8 minutes ago'] +); + +console.log(table.toString()); + /* headless */ var headless_table = new Table(); headless_table.push(['v0.1', 'Testing something cool', 'rauchg@gmail.com', '7 minutes ago']); diff --git a/lib/utils.js b/lib/utils.js index 61cbe10..a4dd31a 100644 --- a/lib/utils.js +++ b/lib/utils.js @@ -1,3 +1,4 @@ +var stripAnsi = require('strip-ansi'); /** * Repeats a string. @@ -80,8 +81,7 @@ exports.options = options; // see: http://en.wikipedia.org/wiki/ANSI_escape_code // exports.strlen = function(str){ - var code = /\u001b\[(?:\d*;){0,5}\d*m/g; - var stripped = ("" + str).replace(code,''); + var stripped = stripAnsi(str); var split = stripped.split("\n"); return split.reduce(function (memo, s) { return (s.length > memo) ? s.length : memo }, 0); } diff --git a/package-lock.json b/package-lock.json index c8cc726..6e6fde2 100644 --- a/package-lock.json +++ b/package-lock.json @@ -5,15 +5,18 @@ "requires": true, "packages": { "": { + "name": "cli-table", "version": "0.4.0-dev", "dependencies": { - "colors": "1.0.3" + "colors": "1.0.3", + "strip-ansi": "^6.0.1" }, "devDependencies": { "eslint": "^7.23.0", "eslint-plugin-json": "^2.1.2", "eslint-plugin-no-async-foreach": "^0.1.1", "expresso": "~0.9", + "hyperlinker": "^1.0.0", "should": "~0.6" }, "engines": { @@ -199,10 +202,9 @@ } }, "node_modules/ansi-regex": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.0.tgz", - "integrity": "sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg==", - "dev": true, + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", "engines": { "node": ">=8" } @@ -741,6 +743,15 @@ "node": ">=8" } }, + "node_modules/hyperlinker": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/hyperlinker/-/hyperlinker-1.0.0.tgz", + "integrity": "sha512-Ty8UblRWFEcfSuIaajM34LdPXIhbs1ajEX/BBPv24J+enSVaEVY63xQ6lTO9VRYS5LAoghIG0IDJ+p+IPzKUQQ==", + "dev": true, + "engines": { + "node": ">=4" + } + }, "node_modules/ignore": { "version": "4.0.6", "resolved": "https://registry.npmjs.org/ignore/-/ignore-4.0.6.tgz", @@ -1139,12 +1150,11 @@ } }, "node_modules/strip-ansi": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz", - "integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==", - "dev": true, + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", "dependencies": { - "ansi-regex": "^5.0.0" + "ansi-regex": "^5.0.1" }, "engines": { "node": ">=8" @@ -1475,10 +1485,9 @@ "dev": true }, "ansi-regex": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.0.tgz", - "integrity": "sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg==", - "dev": true + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==" }, "ansi-styles": { "version": "4.3.0", @@ -1885,6 +1894,12 @@ "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", "dev": true }, + "hyperlinker": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/hyperlinker/-/hyperlinker-1.0.0.tgz", + "integrity": "sha512-Ty8UblRWFEcfSuIaajM34LdPXIhbs1ajEX/BBPv24J+enSVaEVY63xQ6lTO9VRYS5LAoghIG0IDJ+p+IPzKUQQ==", + "dev": true + }, "ignore": { "version": "4.0.6", "resolved": "https://registry.npmjs.org/ignore/-/ignore-4.0.6.tgz", @@ -2184,12 +2199,11 @@ } }, "strip-ansi": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz", - "integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==", - "dev": true, + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", "requires": { - "ansi-regex": "^5.0.0" + "ansi-regex": "^5.0.1" } }, "strip-json-comments": { diff --git a/package.json b/package.json index b379c9e..f115a6f 100644 --- a/package.json +++ b/package.json @@ -17,13 +17,15 @@ "table" ], "dependencies": { - "colors": "1.0.3" + "colors": "1.0.3", + "strip-ansi": "^6.0.1" }, "devDependencies": { "eslint": "^7.23.0", "eslint-plugin-json": "^2.1.2", "eslint-plugin-no-async-foreach": "^0.1.1", "expresso": "~0.9", + "hyperlinker": "^1.0.0", "should": "~0.6" }, "main": "lib", diff --git a/test/index.test.js b/test/index.test.js index 5e01d3b..11af839 100644 --- a/test/index.test.js +++ b/test/index.test.js @@ -4,6 +4,7 @@ */ require('should'); +var hyperlinker = require('hyperlinker'); var Table = require('../'); @@ -43,6 +44,37 @@ module.exports = { table.toString().should.eql(expected.join("\n")); }, + 'test table with ANSI hyperlink escape codes': function (){ + var table = new Table({ + head: ['Rel', 'Change', 'By', 'Link', 'When'] + , colWidths: [6, 21, 25, 17, 17] + , style : {compact : true, 'padding-left' : 1, head: [], border: []} + }); + + table.push( + ['v0.1', 'Testing something cool', 'rauchg@gmail.com', hyperlinker('link', 'https://adobe.com'), '7 minutes ago'] + , ['v0.1', 'Testing something cool', 'rauchg@gmail.com', hyperlinker('link', 'https://adobe.com'), '8 minutes ago'] + ); + + var expected = [ + '┌──────┬─────────────────────┬─────────────────────────┬─────────────────┬─────────────────┐' + , '│ Rel │ Change │ By │ Link │ When │' + , '├──────┼─────────────────────┼─────────────────────────┼─────────────────┼─────────────────┤' + , '│ v0.1 │ Testing something … │ rauchg@gmail.com │ \x1B]8;;https://adobe.com\x07link\x1B]8;;\x07 │ 7 minutes ago │' + , '│ v0.1 │ Testing something … │ rauchg@gmail.com │ \x1B]8;;https://adobe.com\x07link\x1B]8;;\x07 │ 8 minutes ago │' + , '└──────┴─────────────────────┴─────────────────────────┴─────────────────┴─────────────────┘' + // '┌──────┬─────────────────────┬─────────────────────────┬─────────────────┐' + // , '│ Rel │ Change │ By │ When │' + // , '├──────┼─────────────────────┼─────────────────────────┼─────────────────┤' + // , '│ v0.1 │ Testing something … │ rauchg@gmail.com │ 7 minutes ago │' + // , '├──────┼─────────────────────┼─────────────────────────┼─────────────────┤' + // , '│ v0.1 │ Testing something … │ rauchg@gmail.com │ 8 minutes ago │' + // , '└──────┴─────────────────────┴─────────────────────────┴─────────────────┘' + ]; + + table.toString().should.eql(expected.join("\n")); + }, + 'test width property': function (){ var table = new Table({ head: ['Cool'],