diff --git a/.editorconfig b/.editorconfig index 98a761d..1c6314a 100644 --- a/.editorconfig +++ b/.editorconfig @@ -7,6 +7,6 @@ charset = utf-8 trim_trailing_whitespace = true insert_final_newline = true -[{package.json,*.yml}] +[*.yml] indent_style = space indent_size = 2 diff --git a/.travis.yml b/.travis.yml index 2c6e9b0..7d69d74 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,7 +1,5 @@ -sudo: false language: node_js node_js: + - '8' - '6' - '4' - - '0.12' - - '0.10' diff --git a/fixtures/ansi-codes.js b/fixtures/ansi-codes.js index f5720f6..f1a808d 100644 --- a/fixtures/ansi-codes.js +++ b/fixtures/ansi-codes.js @@ -1,24 +1,24 @@ 'use strict'; -// from http://www.umich.edu/~archive/apple2/misc/programmers/vt100.codes.txt +// From http://www.umich.edu/~archive/apple2/misc/programmers/vt100.codes.txt exports.vt52Codes = { - 'A': ['Cursor up'], - 'B': ['Cursor down'], - 'C': ['Cursor right'], - 'D': ['Cursor left'], - 'H': ['Cursor to home'], - 'I': ['Reverse line feed'], - 'J': ['Erase to end of screen'], - 'K': ['Erase to end of line'], - 'Z': ['Identify'], + A: ['Cursor up'], + B: ['Cursor down'], + C: ['Cursor right'], + D: ['Cursor left'], + H: ['Cursor to home'], + I: ['Reverse line feed'], + J: ['Erase to end of screen'], + K: ['Erase to end of line'], + Z: ['Identify'], '=': ['Enter alternate keypad mode'], '>': ['Exit alternate keypad mode'], - '1': ['Graphics processor on'], - '2': ['Graphics processor off'], + 1: ['Graphics processor on'], + 2: ['Graphics processor off'], '<': ['Enter ANSI mode'] }; -// from http://www.umich.edu/~archive/apple2/misc/programmers/vt100.codes.txt +// From http://www.umich.edu/~archive/apple2/misc/programmers/vt100.codes.txt exports.ansiCompatible = { '[176A': ['Cursor up Pn lines'], '[176B': ['Cursor down Pn lines'], @@ -27,8 +27,8 @@ exports.ansiCompatible = { '[176;176H': ['Direct cursor addressing, where Pl is line#, Pc is column#'], '[176;176f': ['Direct cursor addressing, where Pl is line#, Pc is column#'], - '7': ['Save cursor and attributes'], - '8': ['Restore cursor and attributes'], + 7: ['Save cursor and attributes'], + 8: ['Restore cursor and attributes'], '#3': ['Change this line to double-height top half'], '#4': ['Change this line to double-height bottom half'], @@ -45,7 +45,7 @@ exports.ansiCompatible = { '[J': ['Erase from cursor to end of screen'], '[0J': ['Same'], '[2J': ['Erase entire screen'], - '[P' : ['Delete character'], + '[P': ['Delete character'], '[0P': ['Delete character (0P)'], '[2P': ['Delete 2 characters'], @@ -60,7 +60,7 @@ exports.ansiCompatible = { '(2': ['Alternative graphic ROM (Character Set G0)'], ')2': ['Alternative graphic ROM (Character Set G1)'], - 'H': ['Set tab at current column'], + H: ['Set tab at current column'], '[g': ['Clear tab at current column'], '[0g': ['Same'], '[3g': ['Clear all tabs'], @@ -72,12 +72,12 @@ exports.ansiCompatible = { '[0c': ['(response; teminal not Ok)'], '[?1;176c': ['response; where Ps is option present:'], - 'c': ['Causes power-up reset routine to be executed'], + c: ['Causes power-up reset routine to be executed'], '#8': ['Fill screen with "E"'], '[2;176y': ['Invoke Test(s), where Ps is a decimal computed by adding the numbers of the desired tests to be executed'] }; -// from http://ascii-table.com/ansi-escape-sequences-vt-100.php +// From http://ascii-table.com/ansi-escape-sequences-vt-100.php exports.commonCodes = { '[176A': ['Move cursor up n lines', 'CUU'], '[176B': ['Move cursor down n lines', 'CUD'], @@ -110,8 +110,8 @@ exports.commonCodes = { '[?8l': ['Reset auto-repeat mode', 'DECARM'], '[?9l': ['Reset interlacing mode', 'DECINLM'], - 'N': ['Set single shift 2', 'SS2'], - 'O': ['Set single shift 3', 'SS3'], + N: ['Set single shift 2', 'SS2'], + O: ['Set single shift 3', 'SS3'], '[m': ['Turn off character attributes', 'SGR0'], '[0m': ['Turn off character attributes', 'SGR0'], @@ -151,10 +151,10 @@ exports.commonCodes = { '[;H': ['Move cursor to upper left corner', 'cursorhome'], '[f': ['Move cursor to upper left corner', 'hvhome'], '[;f': ['Move cursor to upper left corner', 'hvhome'], - 'M': ['Move/scroll window down one line', 'RI'], - 'E': ['Move to next line', 'NEL'], + M: ['Move/scroll window down one line', 'RI'], + E: ['Move to next line', 'NEL'], - 'H': ['Set a tab at the current column', 'HTS'], + H: ['Set a tab at the current column', 'HTS'], '[g': ['Clear a tab at the current column', 'TBC'], '[0g': ['Clear a tab at the current column', 'TBC'], '[3g': ['Clear all tabs', 'TBC'], @@ -170,7 +170,7 @@ exports.commonCodes = { '[c': ['Identify what terminal type', 'DA'], '[0c': ['Identify what terminal type (another)', 'DA'], - 'c': ['Reset terminal to initial state', 'RIS'], + c: ['Reset terminal to initial state', 'RIS'], '[2;1y': ['Confidence power up test', 'DECTST'], '[2;2y': ['Confidence loopback test', 'DECTST'], '[2;9y': ['Repeat power up test', 'DECTST'], @@ -182,10 +182,10 @@ exports.commonCodes = { '[4q': ['Turn on LED #4', 'DECLL4'] }; -// from http://ascii-table.com/ansi-escape-sequences-vt-100.php +// From http://ascii-table.com/ansi-escape-sequences-vt-100.php exports.otherCode = { - '7': ['Save cursor position and attributes', 'DECSC'], - '8': ['Restore cursor position and attributes', 'DECSC'], + 7: ['Save cursor position and attributes', 'DECSC'], + 8: ['Restore cursor position and attributes', 'DECSC'], '=': ['Set alternate keypad mode', 'DECKPAM'], '>': ['Set numeric keypad mode', 'DECKPNM'], diff --git a/fixtures/view-codes.js b/fixtures/view-codes.js index 16e45d2..a13105a 100644 --- a/fixtures/view-codes.js +++ b/fixtures/view-codes.js @@ -1,27 +1,28 @@ 'use strict'; -var ansiRegex = require('../'); -var ansiCodes = require('./ansi-codes'); -var allCodes = {}; -var supported = []; -var unsupported = []; +const ansiRegex = require('..'); +const ansiCodes = require('./ansi-codes'); + +const allCodes = {}; +const supported = []; +const unsupported = []; function addCodesToTest(codes) { - for (var code in codes) { + for (const code in codes) { allCodes[code] = codes[code]; } } function identifySupportedCodes() { - var codeSupport = {}; + let codeSupport = {}; - for (var code in allCodes) { + for (const code in allCodes) { codeSupport = { - code: code, - matches: ('\u001b' + code).match(ansiRegex()), + code, + matches: `\u001B${code}`.match(ansiRegex()), description: allCodes[code][0] }; - if (codeSupport.matches !== null && codeSupport.matches[0] === '\u001b' + code) { + if (codeSupport.matches !== null && codeSupport.matches[0] === `\u001B${code}`) { supported.push(codeSupport); } else { unsupported.push(codeSupport); @@ -30,21 +31,21 @@ function identifySupportedCodes() { } function displaySupport() { - process.stdout.write('\u001b[32m'); + process.stdout.write('\u001B[32m'); console.log('SUPPORTED'); - for (var i = 0; i < supported.length; i++) { - console.log(supported[i]); + for (const el of supported) { + console.log(el); } - process.stdout.write('\u001b[31m'); + process.stdout.write('\u001B[31m'); console.log('UNSUPPORTED'); - for (var j = 0; j < unsupported.length; j++) { - console.log(unsupported[j]); + for (const el of unsupported) { + console.log(el); } - process.stdout.write('\u001b[0m'); + process.stdout.write('\u001B[0m'); } addCodesToTest(ansiCodes.vt52Codes); diff --git a/index.js b/index.js index b9574ed..c988ab7 100644 --- a/index.js +++ b/index.js @@ -1,4 +1,2 @@ 'use strict'; -module.exports = function () { - return /[\u001b\u009b][[()#;?]*(?:[0-9]{1,4}(?:;[0-9]{0,4})*)?[0-9A-PRZcf-nqry=><]/g; -}; +module.exports = () => (/[\u001B\u009B][[()#;?]*(?:\d{1,4}(?:;\d{0,4})*)?[\dA-PRZcf-nqry=><]/g); diff --git a/license b/license index 654d0bf..e7af2f7 100644 --- a/license +++ b/license @@ -1,21 +1,9 @@ -The MIT License (MIT) +MIT License Copyright (c) Sindre Sorhus (sindresorhus.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: +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 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. +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. diff --git a/package.json b/package.json index eb44fb5..f30b58b 100644 --- a/package.json +++ b/package.json @@ -1,64 +1,58 @@ { - "name": "ansi-regex", - "version": "2.1.1", - "description": "Regular expression for matching ANSI escape codes", - "license": "MIT", - "repository": "chalk/ansi-regex", - "author": { - "name": "Sindre Sorhus", - "email": "sindresorhus@gmail.com", - "url": "sindresorhus.com" - }, - "maintainers": [ - "Sindre Sorhus (sindresorhus.com)", - "Joshua Appelman (jbnicolai.com)", - "JD Ballard (github.com/qix-)" - ], - "engines": { - "node": ">=0.10.0" - }, - "scripts": { - "test": "xo && ava --verbose", - "view-supported": "node fixtures/view-codes.js" - }, - "files": [ - "index.js" - ], - "keywords": [ - "ansi", - "styles", - "color", - "colour", - "colors", - "terminal", - "console", - "cli", - "string", - "tty", - "escape", - "formatting", - "rgb", - "256", - "shell", - "xterm", - "command-line", - "text", - "regex", - "regexp", - "re", - "match", - "test", - "find", - "pattern" - ], - "devDependencies": { - "ava": "0.17.0", - "xo": "0.16.0" - }, - "xo": { - "rules": { - "guard-for-in": 0, - "no-loop-func": 0 - } - } + "name": "ansi-regex", + "version": "2.1.1", + "description": "Regular expression for matching ANSI escape codes", + "license": "MIT", + "repository": "chalk/ansi-regex", + "author": { + "name": "Sindre Sorhus", + "email": "sindresorhus@gmail.com", + "url": "sindresorhus.com" + }, + "engines": { + "node": ">=4" + }, + "scripts": { + "test": "xo && ava", + "view-supported": "node fixtures/view-codes.js" + }, + "files": [ + "index.js" + ], + "keywords": [ + "ansi", + "styles", + "color", + "colour", + "colors", + "terminal", + "console", + "cli", + "string", + "tty", + "escape", + "formatting", + "rgb", + "256", + "shell", + "xterm", + "command-line", + "text", + "regex", + "regexp", + "re", + "match", + "test", + "find", + "pattern" + ], + "devDependencies": { + "ava": "*", + "xo": "*" + }, + "xo": { + "rules": { + "guard-for-in": 0 + } + } } diff --git a/readme.md b/readme.md index 6a928ed..22db1c3 100644 --- a/readme.md +++ b/readme.md @@ -1,12 +1,12 @@ # ansi-regex [![Build Status](https://travis-ci.org/chalk/ansi-regex.svg?branch=master)](https://travis-ci.org/chalk/ansi-regex) -> Regular expression for matching [ANSI escape codes](http://en.wikipedia.org/wiki/ANSI_escape_code) +> Regular expression for matching [ANSI escape codes](https://en.wikipedia.org/wiki/ANSI_escape_code) ## Install ``` -$ npm install --save ansi-regex +$ npm install ansi-regex ``` @@ -15,25 +15,32 @@ $ npm install --save ansi-regex ```js const ansiRegex = require('ansi-regex'); -ansiRegex().test('\u001b[4mcake\u001b[0m'); +ansiRegex().test('\u001B[4mcake\u001B[0m'); //=> true ansiRegex().test('cake'); //=> false -'\u001b[4mcake\u001b[0m'.match(ansiRegex()); -//=> ['\u001b[4m', '\u001b[0m'] +'\u001B[4mcake\u001B[0m'.match(ansiRegex()); +//=> ['\u001B[4m', '\u001B[0m'] ``` + ## FAQ ### Why do you test for codes not in the ECMA 48 standard? -Some of the codes we run as a test are codes that we acquired finding various lists of non-standard or manufacturer specific codes. If I recall correctly, we test for both standard and non-standard codes, as most of them follow the same or similar format and can be safely matched in strings without the risk of removing actual string content. There are a few non-standard control codes that do not follow the traditional format (i.e. they end in numbers) thus forcing us to exclude them from the test because we cannot reliably match them. +Some of the codes we run as a test are codes that we acquired finding various lists of non-standard or manufacturer specific codes. We test for both standard and non-standard codes, as most of them follow the same or similar format and can be safely matched in strings without the risk of removing actual string content. There are a few non-standard control codes that do not follow the traditional format (i.e. they end in numbers) thus forcing us to exclude them from the test because we cannot reliably match them. On the historical side, those ECMA standards were established in the early 90's whereas the VT100, for example, was designed in the mid/late 70's. At that point in time, control codes were still pretty ungoverned and engineers used them for a multitude of things, namely to activate hardware ports that may have been proprietary. Somewhere else you see a similar 'anarchy' of codes is in the x86 architecture for processors; there are a ton of "interrupts" that can mean different things on certain brands of processors, most of which have been phased out. +## Maintainers + +- [Sindre Sorhus](https://github.com/sindresorhus) +- [Josh Junon](https://github.com/qix-) + + ## License -MIT © [Sindre Sorhus](http://sindresorhus.com) +MIT diff --git a/test.js b/test.js index f6045bb..4dca88d 100644 --- a/test.js +++ b/test.js @@ -1,72 +1,71 @@ import test from 'ava'; import ansiCodes from './fixtures/ansi-codes'; -import m from './'; +import m from '.'; const consumptionChars = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ!@#$%^&*()_+1234567890-=[]{};\':"./>?,<\\|'; -// testing against codes found at: http://ascii-table.com/ansi-escape-sequences-vt-100.php +// Testing against codes found at: http://ascii-table.com/ansi-escape-sequences-vt-100.php test('match ansi code in a string', t => { - t.true(m().test('foo\u001b[4mcake\u001b[0m')); - t.true(m().test('\u001b[4mcake\u001b[0m')); - t.true(m().test('foo\u001b[4mcake\u001b[0m')); - t.true(m().test('\u001b[0m\u001b[4m\u001b[42m\u001b[31mfoo\u001b[39m\u001b[49m\u001b[24mfoo\u001b[0m')); - t.true(m().test('foo\u001b[mfoo')); + t.regex('foo\u001B[4mcake\u001B[0m', m()); + t.regex('\u001B[4mcake\u001B[0m', m()); + t.regex('foo\u001B[4mcake\u001B[0m', m()); + t.regex('\u001B[0m\u001B[4m\u001B[42m\u001B[31mfoo\u001B[39m\u001B[49m\u001B[24mfoo\u001B[0m', m()); + t.regex('foo\u001B[mfoo', m()); }); test('match ansi code from ls command', t => { - t.true(m().test('\u001b[00;38;5;244m\u001b[m\u001b[00;38;5;33mfoo\u001b[0m')); + t.regex('\u001B[00;38;5;244m\u001B[m\u001B[00;38;5;33mfoo\u001B[0m', m()); }); test('match reset;setfg;setbg;italics;strike;underline sequence in a string', t => { - t.true(m().test('\u001b[0;33;49;3;9;4mbar\u001b[0m')); - t.is('foo\u001b[0;33;49;3;9;4mbar'.match(m())[0], '\u001b[0;33;49;3;9;4m'); + t.regex('\u001B[0;33;49;3;9;4mbar\u001B[0m', m()); + t.is('foo\u001B[0;33;49;3;9;4mbar'.match(m())[0], '\u001B[0;33;49;3;9;4m'); }); test('match clear tabs sequence in a string', t => { - t.true(m().test('foo\u001b[0gbar')); - t.is('foo\u001b[0gbar'.match(m())[0], '\u001b[0g'); + t.regex('foo\u001B[0gbar', m()); + t.is('foo\u001B[0gbar'.match(m())[0], '\u001B[0g'); }); test('match clear line from cursor right in a string', t => { - t.true(m().test('foo\u001b[Kbar')); - t.is('foo\u001b[Kbar'.match(m())[0], '\u001b[K'); + t.regex('foo\u001B[Kbar', m()); + t.is('foo\u001B[Kbar'.match(m())[0], '\u001B[K'); }); test('match clear screen in a string', t => { - t.true(m().test('foo\u001b[2Jbar')); - t.is('foo\u001b[2Jbar'.match(m())[0], '\u001b[2J'); + t.regex('foo\u001B[2Jbar', m()); + t.is('foo\u001B[2Jbar'.match(m())[0], '\u001B[2J'); }); -// testing against extended codes (excluding codes ending in 0-9) +// Testing against extended codes (excluding codes ending in 0-9) for (const codeSet in ansiCodes) { - for (var code in ansiCodes[codeSet]) { + for (const code in ansiCodes[codeSet]) { const codeInfo = ansiCodes[codeSet][code]; - const skip = /[0-9]$/.test(code); + const skip = /\d$/.test(code); const skipText = skip ? '[SKIP] ' : ''; - const ecode = '\u001b' + code; + const ecode = `\u001B${code}`; - test(skipText + code + ' -> ' + codeInfo[0], t => { + test(`${skipText}${code} → ${codeInfo[0]}`, t => { if (skip) { + t.pass(); return; } - const string = 'hel' + ecode + 'lo'; - - t.true(m().test(string)); + const string = `hel${ecode}lo`; + t.regex(string, m()); t.is(string.match(m())[0], ecode); t.is(string.replace(m(), ''), 'hello'); }); - test(skipText + code + ' should not overconsume', t => { + test(`${skipText}${code} should not overconsume`, t => { if (skip) { + t.pass(); return; } - for (var i = 0; i < consumptionChars.length; i++) { - const c = consumptionChars[i]; + for (const c of consumptionChars) { const string = ecode + c; - - t.true(m().test(string)); + t.regex(string, m()); t.is(string.match(m())[0], ecode); t.is(string.replace(m(), ''), c); }