From 72a33c0de653f86e48024b9503ba28fa40ed5105 Mon Sep 17 00:00:00 2001 From: Myrotvorets Date: Fri, 6 Oct 2023 01:08:15 +0300 Subject: [PATCH] Big Rewrite --- .github/renovate.json | 6 ++ .github/workflows/build.yml | 39 ++++++++++ .github/workflows/codeql.yml | 53 +++++++++++++ .github/workflows/package-audit.yml | 31 ++++++++ README.md | 102 ++++++++++++++++--------- lib/ansi-color.d.ts | 19 +++++ lib/ansi-color.js | 111 +++++++++++++++------------- package.json | 58 ++++++++------- test/ansi-color.test.js | 45 +++++++++++ 9 files changed, 352 insertions(+), 112 deletions(-) create mode 100644 .github/renovate.json create mode 100644 .github/workflows/build.yml create mode 100644 .github/workflows/codeql.yml create mode 100644 .github/workflows/package-audit.yml create mode 100644 lib/ansi-color.d.ts create mode 100644 test/ansi-color.test.js diff --git a/.github/renovate.json b/.github/renovate.json new file mode 100644 index 0000000..6b9fc3a --- /dev/null +++ b/.github/renovate.json @@ -0,0 +1,6 @@ +{ + "$schema": "https://docs.renovatebot.com/renovate-schema.json", + "extends": [ + "local>myrotvorets/.github:renovate-config" + ] +} diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml new file mode 100644 index 0000000..8ae21d1 --- /dev/null +++ b/.github/workflows/build.yml @@ -0,0 +1,39 @@ +name: Build and Test + +on: + push: + branches: + - '**' + workflow_dispatch: + +permissions: + contents: none + +jobs: + build: + runs-on: ubuntu-latest + if: ${{ !contains(github.event.head_commit.message, '[ci skip]') || github.event_name == 'workflow_dispatch' }} + strategy: + matrix: + node: + - { name: Current, version: current } + - { name: LTS, version: lts/* } + name: Build and test (Node ${{ matrix.node.name }}) + permissions: + contents: read + steps: + - name: Harden Runner + uses: step-security/harden-runner@8ca2b8b2ece13480cda6dacd3511b49857a23c09 # v2.5.1 + with: + disable-sudo: true + egress-policy: block + allowed-endpoints: > + api.github.com:443 + github.com:443 + nodejs.org:443 + registry.npmjs.org:443 + + - name: Build and test + uses: myrotvorets/composite-actions/build-test-nodejs@master + with: + node-version: ${{ matrix.node.version }} diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml new file mode 100644 index 0000000..61bedff --- /dev/null +++ b/.github/workflows/codeql.yml @@ -0,0 +1,53 @@ +name: CodeQL + +on: + push: + branches: + - master + pull_request: + branches: + - master + schedule: + - cron: "57 17 * * 4" + +jobs: + analyze: + name: Analyze + runs-on: ubuntu-latest + permissions: + actions: read + contents: read + security-events: write + strategy: + fail-fast: false + matrix: + language: + - javascript + steps: + - name: Harden Runner + uses: step-security/harden-runner@1b05615854632b887b69ae1be8cbefe72d3ae423 # v2.6.0 + with: + disable-sudo: true + egress-policy: block + allowed-endpoints: > + api.github.com:443 + github.com:443 + uploads.github.com:443 + objects.githubusercontent.com:443 + + - name: Checkout + uses: actions/checkout@8ade135a41bc03ea155e62e844d188df1ea18608 # v4.1.0 + + - name: Initialize CodeQL + uses: github/codeql-action/init@ddccb873888234080b77e9bc2d4764d5ccaaccf9 # v2.21.9 + with: + languages: ${{ matrix.language }} + queries: +security-and-quality + + - name: Autobuild + uses: github/codeql-action/autobuild@ddccb873888234080b77e9bc2d4764d5ccaaccf9 # v2.21.9 + + - name: Perform CodeQL Analysis + uses: github/codeql-action/analyze@ddccb873888234080b77e9bc2d4764d5ccaaccf9 # v2.21.9 + with: + category: "/language:${{ matrix.language }}" diff --git a/.github/workflows/package-audit.yml b/.github/workflows/package-audit.yml new file mode 100644 index 0000000..74e6e4d --- /dev/null +++ b/.github/workflows/package-audit.yml @@ -0,0 +1,31 @@ +name: Package Audit + +on: + push: + branches: + - '**' + paths: + - package.json + - package-lock.json + - .github/workflows/package-audit.yml + workflow_dispatch: + +permissions: + contents: read + +jobs: + audit-npm: + name: NPM Audit + runs-on: ubuntu-latest + steps: + - name: Harden Runner + uses: step-security/harden-runner@1b05615854632b887b69ae1be8cbefe72d3ae423 # v2.6.0 + with: + disable-sudo: true + allowed-endpoints: + api.github.com:443 + github.com:443 + registry.npmjs.org:443 + + - name: Audit with NPM + uses: myrotvorets/composite-actions/node-package-audit@master diff --git a/README.md b/README.md index 9fa40d7..660bc37 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,4 @@ -ANSI Color Code Output Support for CommonJS + Node.js -=========================================== +# ANSI Color Code Output Support for Node.js This CommonJS module provides basic ANSI color code support, to allow you to format your console output with foreground and background colors as well as @@ -8,43 +7,74 @@ providing bold and underline support. This module does not modify any built-in object prototypes, and so is safe to use with other modules. -Tested on node.js. +This fork: + - rewrites the code into modern JavaScript; + - is Node.js-only; + - fixes the "Legacy octal escape is not permitted in strict mode" issue; + - adds some tests. -Basic usage: ------------ - // Load the module - var color = require("ansi-color").set; +**How to use:** - // Print the word "Error" to stdout in red - console.log(color("Error", "red")); +Yarn: +```json +"resolutions": { + "ansi-color": "github:@myrotvorets/ansi-color#master" +} +``` - // Print the word "Error" in red and underlined - console.log(color("Error", "red+underline")); +npm: +```json +"overrides": { + "ansi-color": "github:@myrotvorets/ansi-color#master" +} +``` - // Print the word "Success" in bold green, followed by a message - console.log(color("Success", "green+bold"), "Something was successful!"); +pnpm: +```json +"pnpm": { + "overrides": { + "ansi-color": "github:@myrotvorets/ansi-color#master" + } +} +``` + +## Basic usage + +```js +// Load the module +var color = require("ansi-color").set; + +// Print the word "Error" to stdout in red +console.log(color("Error", "red")); + +// Print the word "Error" in red and underlined +console.log(color("Error", "red+underline")); + +// Print the word "Success" in bold green, followed by a message +console.log(color("Success", "green+bold"), "Something was successful!"); +``` + +## Supported Colors/Formats -Supported Colors/Formats: -------------------------- Note: Any of the below formatting strings can be combined together by joining -together desired formats with a + symbol. Eg: bold+cyan+white_bg - -- Bold Text: bold -- Underlined Text: underline -- Blinking Text: blink -- Black Text: black -- Red Text: red -- Green Text: green -- Yellow Text: yellow -- Blue Text: blue -- Magenta Text: magenta -- Cyan Text: cyan -- White Text: white -- Black Background: black_bg -- Red Background: red_bg -- Green Background: green_bg -- Yellow Background: yellow_bg -- Blue Background: blue_bg -- Magenta Background: magenta_bg -- Cyan Background: cyan_bg -- White Background: white_bg +together desired formats with a `+` symbol. E.g.: `bold+cyan+white_bg` + +- Bold Text: `bold` +- Underlined Text: `underline` +- Blinking Text: `blink` +- Black Text: `black` +- Red Text: `red` +- Green Text: `green` +- Yellow Text: `yellow` +- Blue Text: `blue` +- Magenta Text: `magenta` +- Cyan Text: `cyan` +- White Text: `white` +- Black Background: `black_bg` +- Red Background: `red_bg` +- Green Background: `green_bg` +- Yellow Background: `yellow_bg` +- Blue Background: `blue_bg` +- Magenta Background: `magenta_bg` +- Cyan Background: `cyan_bg` +- White Background: `white_bg` diff --git a/lib/ansi-color.d.ts b/lib/ansi-color.d.ts new file mode 100644 index 0000000..fcb60e4 --- /dev/null +++ b/lib/ansi-color.d.ts @@ -0,0 +1,19 @@ +/** + * @param {string} message + * @param {string} color + * @return {void} + */ +export function log(message: string, color: string): void; +/** + * @param {string} str + * @param {string} color + * @return {string} + */ +export function set(str: string, color: string): string; +/** + * @param {string} full_text + * @param {string} search_regex + * @param {string} color + * @return {string} + */ +export function replace(full_text: string, search_regex: string, color: string): string; diff --git a/lib/ansi-color.js b/lib/ansi-color.js index 20fe35f..6d248c9 100644 --- a/lib/ansi-color.js +++ b/lib/ansi-color.js @@ -1,62 +1,73 @@ -(function() { -// ANSI color code outputs for strings - -var ANSI_CODES = { - "off": 0, - "bold": 1, - "italic": 3, - "underline": 4, - "blink": 5, - "inverse": 7, - "hidden": 8, - "black": 30, - "red": 31, - "green": 32, - "yellow": 33, - "blue": 34, - "magenta": 35, - "cyan": 36, - "white": 37, - "black_bg": 40, - "red_bg": 41, - "green_bg": 42, - "yellow_bg": 43, - "blue_bg": 44, - "magenta_bg": 45, - "cyan_bg": 46, - "white_bg": 47 +const ANSI_CODES = { + off: 0, + bold: 1, + italic: 3, + underline: 4, + blink: 5, + inverse: 7, + hidden: 8, + black: 30, + red: 31, + green: 32, + yellow: 33, + blue: 34, + magenta: 35, + cyan: 36, + white: 37, + black_bg: 40, + red_bg: 41, + green_bg: 42, + yellow_bg: 43, + blue_bg: 44, + magenta_bg: 45, + cyan_bg: 46, + white_bg: 47 }; -function setColor(str,color) { - if(!color) return str; - var color_attrs = color.split("+"); - var ansi_str = ""; - for(var i=0, attr; attr = color_attrs[i]; i++) { - ansi_str += "\033[" + ANSI_CODES[attr] + "m"; +/** + * @param {string} str + * @param {string} color + * @return {string} + */ +function set(str, color) { + if (color) { + const attributes = color.split('+'); + let ansiStr = ""; + for (const attr of attributes) { + ansiStr += `\u001B[${ANSI_CODES[attr]}m`; + } + + ansiStr += str + `\u001B[${ANSI_CODES["off"]}m`; + return ansiStr; } - ansi_str += str + "\033[" + ANSI_CODES["off"] + "m"; - return ansi_str; + + return str; } -function logMessage(message,color) { - console.log(setColor(message,color)); +/** + * @param {string} message + * @param {string} color + * @return {void} + */ +function log(message, color) { + console.log(set(message,color)); } +/** + * @param {string} full_text + * @param {string} search_regex + * @param {string} color + * @return {string} + */ function replace(full_text, search_regex, color) { try { - var regex = new RegExp('(' + search_regex + ')', 'ig'); - var new_text = full_text.replace(regex, setColor('$1', color)); - return new_text; - } catch (e) { - return full_text; + const regex = new RegExp('(' + search_regex + ')', 'ig'); + return full_text.replace(regex, set('$1', color)); + } catch { + return full_text; } } -if (typeof exports !== "undefined") { - exports.log = logMessage; - exports.set = setColor; - exports.replace = replace; -} else if (typeof define !== "undefined") { - define([], function() { return { set: setColor, log: logMessage }; }); -} -}()); \ No newline at end of file +exports.log = log; +exports.set = set; +exports.replace = replace; diff --git a/package.json b/package.json index 03fec66..507b00f 100644 --- a/package.json +++ b/package.json @@ -1,27 +1,33 @@ { - "name": "ansi-color", - "version": "0.2.1", - "description": "This module provides basic ANSI color code support, to allow you to format your console output with foreground and background colors as well as providing bold, italic and underline support.", - "author": "James Smith ", - "directories": { - "lib": "./lib" - }, - "main": "./lib/ansi-color.js", - "repository": { - "type": "git", - "url": "https://github.com/loopj/commonjs-ansi-color.git" - }, - "bugs": { - "url": "https://github.com/loopj/commonjs-ansi-color/issues" - }, - "keywords": [ - "ansi", - "color", - "console" - ], - "license": "BSD License", - "contributors": [{ - "name": "vBm", - "email": "the.vbm@gmail.com" - }] -} \ No newline at end of file + "name": "@myrotvorets/ansi-color", + "version": "0.2.2", + "description": "This module provides basic ANSI color code support, to allow you to format your console output with foreground and background colors as well as providing bold, italic and underline support.", + "author": "James Smith ", + "main": "./lib/ansi-color.js", + "typings": "./lib/ansi-color.d.ts", + "scripts": { + "test": "node --test" + }, + "repository": { + "type": "git", + "url": "git+https://github.com/myrotvorets/ansi-color.git" + }, + "bugs": { + "url": "https://github.com/myrotvorets/ansi-color/issues" + }, + "keywords": [ + "ansi", + "color", + "console" + ], + "license": "BSD License", + "contributors": [ + "vBm ", + "Myrotvorets (https://myrotvorets.center/)" + ], + "homepage": "https://github.com/myrotvorets/ansi-color#readme", + "directories": { + "lib": "lib", + "test": "test" + } +} diff --git a/test/ansi-color.test.js b/test/ansi-color.test.js new file mode 100644 index 0000000..ac8a9fc --- /dev/null +++ b/test/ansi-color.test.js @@ -0,0 +1,45 @@ +const { afterEach, before, describe, it } = require('node:test'); +const { strictEqual } = require('node:assert/strict'); +const { log, set, replace } = require('../lib/ansi-color'); + +describe('ansiColor', function() { + describe('#set()', function() { + it('should return a string with the specified color', function() { + strictEqual(set('hello', 'red'), '\u001B[31mhello\u001B[0m'); + strictEqual(set('world', 'green'), '\u001B[32mworld\u001B[0m'); + }); + + it('should not modify the string when color is empty', function() { + strictEqual(set('hello', ''), 'hello'); + }); + }); + + describe('#log()', function() { + let consoleLog; + + before(() => { + consoleLog = console.log; + }); + + afterEach(() => { + console.log = consoleLog; + }); + + it('should log a message with the specified color', function() { + let output = ''; + console.log = function(message) { + output += message; + }; + + log('hello', 'red'); + strictEqual(output, '\u001B[31mhello\u001B[0m'); + }); + }); + + describe('#replace()', function() { + it('should replace all occurrences of a regex with the specified color', function() { + strictEqual(replace('hello world', 'l', 'red'), 'he\u001B[31ml\u001B[0m\u001B[31ml\u001B[0mo wor\u001B[31ml\u001B[0md'); + strictEqual(replace('foo bar baz', 'a', 'green'), 'foo b\u001B[32ma\u001B[0mr b\u001B[32ma\u001B[0mz'); + }); + }); +});