├── funding.yml ├── .prettierignore ├── .npmrc ├── test ├── fixture │ ├── js-shebang │ │ ├── input.txt │ │ └── output.txt │ ├── go-numbers │ │ ├── input.txt │ │ └── output.txt │ ├── haskell-nested-comments │ │ ├── input.txt │ │ ├── output.txt │ │ └── lisp-mec │ │ │ ├── input.txt │ │ │ └── output.txt │ ├── rust-variables │ │ ├── input.txt │ │ └── output.txt │ ├── css-pseudo-selector │ │ ├── input.txt │ │ └── output.txt │ ├── haskell-infix │ │ ├── input.txt │ │ └── output.txt │ ├── rust-comments │ │ ├── input.txt │ │ └── output.txt │ ├── md-sublanguage │ │ ├── input.txt │ │ └── output.txt │ ├── xml-sublanguages │ │ ├── input.txt │ │ └── output.txt │ ├── rust-traits │ │ ├── input.txt │ │ └── output.txt │ ├── bash-no-numbers │ │ ├── input.txt │ │ └── output.txt │ ├── coffee-division │ │ ├── input.txt │ │ └── output.txt │ ├── swift-functions │ │ ├── input.txt │ │ └── output.txt │ ├── http-default │ │ ├── input.txt │ │ └── output.txt │ ├── coffee-regex │ │ ├── input.txt │ │ └── output.txt │ ├── rust-strings │ │ ├── input.txt │ │ └── output.txt │ ├── js-jsx │ │ ├── input.txt │ │ └── output.txt │ ├── rust-numbers │ │ ├── input.txt │ │ └── output.txt │ ├── js-class │ │ ├── input.txt │ │ └── output.txt │ ├── xml-large │ │ ├── input.txt │ │ └── output.txt │ ├── js-modules │ │ ├── input.txt │ │ └── output.txt │ ├── coffee-function │ │ ├── input.txt │ │ └── output.txt │ ├── js-keywords │ │ ├── input.txt │ │ └── output.txt │ └── js-default-parameters │ │ ├── input.txt │ │ └── output.txt └── index.js ├── screenshot.png ├── .gitignore ├── .editorconfig ├── index.js ├── tsconfig.json ├── .github └── workflows │ └── main.yml ├── license ├── package.json ├── lib └── index.js └── readme.md /funding.yml: -------------------------------------------------------------------------------- 1 | github: wooorm 2 | -------------------------------------------------------------------------------- /.prettierignore: -------------------------------------------------------------------------------- 1 | coverage/ 2 | *.md 3 | -------------------------------------------------------------------------------- /.npmrc: -------------------------------------------------------------------------------- 1 | ignore-scripts=true 2 | package-lock=false 3 | -------------------------------------------------------------------------------- /test/fixture/js-shebang/input.txt: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | var a = 1; 4 | -------------------------------------------------------------------------------- /screenshot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wooorm/emphasize/HEAD/screenshot.png -------------------------------------------------------------------------------- /test/fixture/go-numbers/input.txt: -------------------------------------------------------------------------------- 1 | float_var := 1.0e10f 2 | complex_var := 1.2e5+2.3i -------------------------------------------------------------------------------- /test/fixture/haskell-nested-comments/input.txt: -------------------------------------------------------------------------------- 1 | {- this is a {- nested -} comment -} 2 | -------------------------------------------------------------------------------- /test/fixture/rust-variables/input.txt: -------------------------------------------------------------------------------- 1 | let foo; 2 | let mut bar; 3 | let _foo_bar; 4 | -------------------------------------------------------------------------------- /test/fixture/css-pseudo-selector/input.txt: -------------------------------------------------------------------------------- 1 | li:not(.red){} 2 | li:not(.red):not(.green){} 3 | -------------------------------------------------------------------------------- /test/fixture/haskell-infix/input.txt: -------------------------------------------------------------------------------- 1 | infix 3 `foo` 2 | infixl 6 `bar` 3 | infixr 9 `baz` 4 | -------------------------------------------------------------------------------- /test/fixture/haskell-nested-comments/output.txt: -------------------------------------------------------------------------------- 1 | {- this is a {- nested -} comment -} 2 | -------------------------------------------------------------------------------- /test/fixture/rust-comments/input.txt: -------------------------------------------------------------------------------- 1 | /* rust has 2 | /* nested /* block */ */ 3 | */ comments 4 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | coverage/ 2 | node_modules/ 3 | *.d.ts 4 | *.log 5 | *.map 6 | .DS_Store 7 | yarn.lock 8 | -------------------------------------------------------------------------------- /test/fixture/js-shebang/output.txt: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | var a = 1; 4 | -------------------------------------------------------------------------------- /test/fixture/go-numbers/output.txt: -------------------------------------------------------------------------------- 1 | float_var := 1.0e10f 2 | complex_var := 1.2e5+2.3i 3 | -------------------------------------------------------------------------------- /test/fixture/md-sublanguage/input.txt: -------------------------------------------------------------------------------- 1 | This is _markdown_ with some HTML 2 | -------------------------------------------------------------------------------- /test/fixture/rust-comments/output.txt: -------------------------------------------------------------------------------- 1 | /* rust has 2 | /* nested /* block */ */ 3 | */ comments 4 | -------------------------------------------------------------------------------- /test/fixture/xml-sublanguages/input.txt: -------------------------------------------------------------------------------- 1 | 2 | 7 | -------------------------------------------------------------------------------- /test/fixture/haskell-infix/output.txt: -------------------------------------------------------------------------------- 1 | infix 3 `foo` 2 | infixl 6 `bar` 3 | infixr 9 `baz` 4 | -------------------------------------------------------------------------------- /test/fixture/rust-traits/input.txt: -------------------------------------------------------------------------------- 1 | fn sqr(i: i32) { i * i } 2 | trait Minimum : Copy {} 3 | pub trait Builder where Self: Sized + Iterator {} 4 | -------------------------------------------------------------------------------- /test/fixture/rust-variables/output.txt: -------------------------------------------------------------------------------- 1 | let foo; 2 | let mut bar; 3 | let _foo_bar; 4 | -------------------------------------------------------------------------------- /test/fixture/css-pseudo-selector/output.txt: -------------------------------------------------------------------------------- 1 | li:not(.red){} 2 | li:not(.red):not(.green){} 3 | -------------------------------------------------------------------------------- /test/fixture/md-sublanguage/output.txt: -------------------------------------------------------------------------------- 1 | This is _markdown_ with some <abbr title="Hypertext Markup Language">HTML 2 | -------------------------------------------------------------------------------- /test/fixture/bash-no-numbers/input.txt: -------------------------------------------------------------------------------- 1 | # numbers aren't highlighted in bash as their semantics is 2 | # not strictly defined for command line parameters 3 | $ tail -10 access.log 4 | -------------------------------------------------------------------------------- /test/fixture/coffee-division/input.txt: -------------------------------------------------------------------------------- 1 | # Divisions 2 | x = 6/foo/i 3 | x = 6 /foo 4 | x = 6 / foo 5 | x = 6 /foo * 2/gm 6 | x = f /foo 7 | x = f / foo / gm 8 | x = f /foo * 2/6 9 | -------------------------------------------------------------------------------- /test/fixture/swift-functions/input.txt: -------------------------------------------------------------------------------- 1 | protocol Protocol { 2 | func f1() 3 | func f2() 4 | } 5 | 6 | class MyClass { 7 | func f() { 8 | return true 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /test/fixture/xml-sublanguages/output.txt: -------------------------------------------------------------------------------- 1 |  2 | <style> 3 | .foo { 4 | color: red; 5 | } 6 | 7 | -------------------------------------------------------------------------------- /test/fixture/haskell-nested-comments/lisp-mec/input.txt: -------------------------------------------------------------------------------- 1 | ; MEC: Multiple Escape Characters. See https://github.com/isagalaev/highlight.js/issues/615 2 | (|spaces and 3 | newlines| x) 4 | (x '|quoted|) 5 | -------------------------------------------------------------------------------- /test/fixture/http-default/input.txt: -------------------------------------------------------------------------------- 1 | POST /task?id=1 HTTP/1.1 2 | Host: example.org 3 | Content-Type: application/json; charset=utf-8 4 | Content-Length: 19 5 | 6 | {"status": "ok", "extended": true} 7 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | indent_style = space 5 | indent_size = 2 6 | end_of_line = lf 7 | charset = utf-8 8 | trim_trailing_whitespace = true 9 | insert_final_newline = true 10 | -------------------------------------------------------------------------------- /test/fixture/coffee-regex/input.txt: -------------------------------------------------------------------------------- 1 | # Regexps 2 | x = /\// 3 | x = /\n/ 4 | x = /ab\/ ab/ 5 | x = f /6 * 2/ - 3 6 | x = f /foo * 2/gm 7 | x = if true then /\n/ else /[.,]+/ 8 | x = ///^key-#{key}-\d+/// 9 | -------------------------------------------------------------------------------- /test/fixture/bash-no-numbers/output.txt: -------------------------------------------------------------------------------- 1 | # numbers aren't highlighted in bash as their semantics is 2 | # not strictly defined for command line parameters 3 | $ tail -10 access.log 4 | -------------------------------------------------------------------------------- /test/fixture/rust-strings/input.txt: -------------------------------------------------------------------------------- 1 | 'a'; 2 | '\n'; 3 | '\x1A'; 4 | '\u12AS'; 5 | '\U1234ASDF'; 6 | b'a'; 7 | 8 | "hello"; 9 | b"hello"; 10 | 11 | r"hello"; 12 | r###"world"###; 13 | r##" "### "# "##; 14 | -------------------------------------------------------------------------------- /test/fixture/js-jsx/input.txt: -------------------------------------------------------------------------------- 1 | var jsx = ; 2 | var jsx = ; 3 | var jsx = ......; 4 | var jsx =

; 5 | var x = 5; 6 | return (); 7 | -------------------------------------------------------------------------------- /test/fixture/rust-numbers/input.txt: -------------------------------------------------------------------------------- 1 | 123; 2 | 123usize; 3 | 123_usize; 4 | 0xff00; 5 | 0xff_u8; 6 | 0b1111111110010000; 7 | 0b1111_1111_1001_0000_i32; 8 | 0o764317; 9 | 0o764317_u16; 10 | 123.0; 11 | 0.1; 12 | 0.1f32; 13 | 12E+99_f64; 14 | -------------------------------------------------------------------------------- /test/fixture/coffee-division/output.txt: -------------------------------------------------------------------------------- 1 | # Divisions 2 | x = 6/foo/i 3 | x = 6 /foo 4 | x = 6 / foo 5 | x = 6 /foo * 2/gm 6 | x = f /foo 7 | x = f / foo / gm 8 | x = f /foo * 2/6 9 | -------------------------------------------------------------------------------- /test/fixture/js-class/input.txt: -------------------------------------------------------------------------------- 1 | class Car extends Vehicle { 2 | constructor(speed, cost) { 3 | super(speed); 4 | 5 | var c = Symbol('cost'); 6 | this[c] = cost; 7 | 8 | this.intro = `This is a car runs at 9 | ${speed}.`; 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /test/fixture/rust-traits/output.txt: -------------------------------------------------------------------------------- 1 | fn sqr(i: i32) { i * i } 2 | trait Minimum : Copy {} 3 | pub trait Builder where Self: Sized + Iterator {} 4 | -------------------------------------------------------------------------------- /test/fixture/xml-large/input.txt: -------------------------------------------------------------------------------- 1 | 2 | 3 | Ok 4 | 5 | magical. 7 | ]]> 8 | 9 | 10 | -------------------------------------------------------------------------------- /test/fixture/haskell-nested-comments/lisp-mec/output.txt: -------------------------------------------------------------------------------- 1 | ; MEC: Multiple Escape Characters. See https://github.com/isagalaev/highlight.js/issues/615 2 | (|spaces and 3 | newlines| x) 4 | (x '|quoted|) 5 | -------------------------------------------------------------------------------- /test/fixture/swift-functions/output.txt: -------------------------------------------------------------------------------- 1 | protocol Protocol { 2 | func f1() 3 | func f2() 4 | } 5 | 6 | class MyClass { 7 | func f() { 8 | return true 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /test/fixture/http-default/output.txt: -------------------------------------------------------------------------------- 1 | POST /task?id=1 HTTP/1.1 2 | Host: example.org 3 | Content-Type: application/json; charset=utf-8 4 | Content-Length: 19 5 | 6 | {"status": "ok", "extended": true} 7 | -------------------------------------------------------------------------------- /test/fixture/js-modules/input.txt: -------------------------------------------------------------------------------- 1 | //------ underscore.js ------ 2 | export default function (obj) {}; 3 | export function each(obj, iterator, context) {}; 4 | export { each as forEach }; 5 | export function something() {}; 6 | 7 | //------ main.js ------ 8 | import _, { each, something as otherthing } from 'underscore'; 9 | -------------------------------------------------------------------------------- /test/fixture/rust-strings/output.txt: -------------------------------------------------------------------------------- 1 | 'a'; 2 | '\n'; 3 | '\x1A'; 4 | '\u12AS'; 5 | '\U1234ASDF'; 6 | b'a'; 7 | 8 | "hello"; 9 | b"hello"; 10 | 11 | r"hello"; 12 | r###"world"###; 13 | r##" "### "# "##; 14 | -------------------------------------------------------------------------------- /test/fixture/coffee-regex/output.txt: -------------------------------------------------------------------------------- 1 | # Regexps 2 | x = /\// 3 | x = /\n/ 4 | x = /ab\/ ab/ 5 | x = f /6 * 2/ - 3 6 | x = f /foo * 2/gm 7 | x = if true then /\n/ else /[.,]+/ 8 | x = ///^key-#{key}-\d+/// 9 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @typedef {import('lowlight').LanguageFn} LanguageFn 3 | * @typedef {import('./lib/index.js').AutoOptions} AutoOptions 4 | * @typedef {import('./lib/index.js').Result} Result 5 | * @typedef {import('./lib/index.js').Sheet} Sheet 6 | */ 7 | 8 | export {all, common} from 'lowlight' 9 | export {createEmphasize} from './lib/index.js' 10 | -------------------------------------------------------------------------------- /test/fixture/coffee-function/input.txt: -------------------------------------------------------------------------------- 1 | returnNull = -> null 2 | returnTrue = () -> true 3 | square = (x) -> x * x 4 | 5 | npmWishlist.sha256 = (str) -> 6 | throw new Error() 7 | 8 | str.split(" ").map((m) -> m.charCodeAt(0)) 9 | 10 | fs.readFile("package.json", "utf-8", (err, content) -> 11 | data = JSON.parse(content) 12 | 13 | data.version 14 | ) 15 | -------------------------------------------------------------------------------- /test/fixture/rust-numbers/output.txt: -------------------------------------------------------------------------------- 1 | 123; 2 | 123usize; 3 | 123_usize; 4 | 0xff00; 5 | 0xff_u8; 6 | 0b1111111110010000; 7 | 0b1111_1111_1001_0000_i32; 8 | 0o764317; 9 | 0o764317_u16; 10 | 123.0; 11 | 0.1; 12 | 0.1f32; 13 | 12E+99_f64; 14 | -------------------------------------------------------------------------------- /test/fixture/js-class/output.txt: -------------------------------------------------------------------------------- 1 | class Car extends Vehicle { 2 | constructor(speed, cost) { 3 | super(speed); 4 | 5 | var c = Symbol('cost'); 6 | this[c] = cost; 7 | 8 | this.intro = `This is a car runs at 9 |  ${speed}.`; 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /test/fixture/js-keywords/input.txt: -------------------------------------------------------------------------------- 1 | function $initHighlight(block, cls) { 2 | try { 3 | if (cls.search(/\bno\-highlight\b/) != -1) 4 | return process(block, true, 0x0F) + 5 | ' class=""'; 6 | } catch (e) { 7 | /* handle exception */ 8 | } 9 | for (var i = 0 / 2; i < classes.length; i++) { 10 | if (checkCondition(classes[i]) === undefined) 11 | return /\d+[\s/]/g; 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /test/fixture/js-jsx/output.txt: -------------------------------------------------------------------------------- 1 | var jsx = <node/>; 2 | var jsx = <node><child/>; 3 | var jsx = <node>...<child>...; 4 | var jsx = <div><br />; 5 | var x = 5; 6 | return (<node attr="value">); 7 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "checkJs": true, 4 | "customConditions": ["development"], 5 | "declaration": true, 6 | "declarationMap": true, 7 | "emitDeclarationOnly": true, 8 | "exactOptionalPropertyTypes": true, 9 | "lib": ["es2022"], 10 | "module": "node16", 11 | "strict": true, 12 | "target": "es2022" 13 | }, 14 | "exclude": ["coverage/", "node_modules/"], 15 | "include": ["**/*.js"] 16 | } 17 | -------------------------------------------------------------------------------- /test/fixture/xml-large/output.txt: -------------------------------------------------------------------------------- 1 |  2 | <response value="ok" xml:lang="en"> 3 | <text>Ok 4 | <comment html_allowed="true"/> 5 | <ns1:description> magical. 7 | ]]> 8 | <a> <a/> 9 | 10 | -------------------------------------------------------------------------------- /test/fixture/js-modules/output.txt: -------------------------------------------------------------------------------- 1 | //------ underscore.js ------ 2 | export default function (obj) {}; 3 | export function each(obj, iterator, context) {}; 4 | export { each as forEach }; 5 | export function something() {}; 6 | 7 | //------ main.js ------ 8 | import _, { each, something as otherthing } from 'underscore'; 9 | -------------------------------------------------------------------------------- /test/fixture/coffee-function/output.txt: -------------------------------------------------------------------------------- 1 | returnNull = -> null 2 | returnTrue = () -> true 3 | square = (x) -> x * x 4 | 5 | npmWishlist.sha256 = (str) -> 6 | throw new Error() 7 | 8 | str.split(" ").map((m) -> m.charCodeAt(0)) 9 | 10 | fs.readFile("package.json", "utf-8", (err, content) -> 11 | data = JSON.parse(content) 12 | 13 | data.version 14 | ) 15 | -------------------------------------------------------------------------------- /.github/workflows/main.yml: -------------------------------------------------------------------------------- 1 | jobs: 2 | main: 3 | name: ${{matrix.node}} 4 | runs-on: ubuntu-latest 5 | steps: 6 | - uses: actions/checkout@v4 7 | - uses: actions/setup-node@v4 8 | with: 9 | node-version: ${{matrix.node}} 10 | - run: npm install 11 | - run: npm test 12 | - uses: codecov/codecov-action@v3 13 | strategy: 14 | matrix: 15 | node: 16 | - lts/gallium 17 | - node 18 | name: main 19 | on: 20 | - pull_request 21 | - push 22 | -------------------------------------------------------------------------------- /test/fixture/js-keywords/output.txt: -------------------------------------------------------------------------------- 1 | function $initHighlight(block, cls) { 2 | try { 3 | if (cls.search(/\bno\-highlight\b/) != -1) 4 | return process(block, true, 0x0F) + 5 | ' class=""'; 6 | } catch (e) { 7 | /* handle exception */ 8 | } 9 | for (var i = 0 / 2; i < classes.length; i++) { 10 | if (checkCondition(classes[i]) === undefined) 11 | return /\d+[\s/]/g; 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /test/fixture/js-default-parameters/input.txt: -------------------------------------------------------------------------------- 1 | function visibleTodoFilter(state = 'watch', action) { 2 | switch (action.type) { 3 | case 'CHANGE_VISIBLE_FILTER': 4 | return action.filter; 5 | default: 6 | return state; 7 | } 8 | } 9 | 10 | function todos(state, action) { 11 | switch (action.type) { 12 | case 'ADD_TODO': 13 | return [...state, { 14 | text: action.text, 15 | completed: false 16 | }]; 17 | case 'COMPLETE_TODO': 18 | return [ 19 | ...state.slice(0, action.index), 20 | Object.assign({}, state[action.index], { 21 | completed: true 22 | }), 23 | ...state.slice(action.index + 1) 24 | ] 25 | default: 26 | return state; 27 | } 28 | } 29 | 30 | import { combineReducers, createStore } from 'redux'; 31 | let reducer = combineReducers({ visibleTodoFilter, todos }); 32 | let store = createStore(reducer); 33 | -------------------------------------------------------------------------------- /license: -------------------------------------------------------------------------------- 1 | (The MIT License) 2 | 3 | Copyright (c) 2016 Titus Wormer 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining 6 | a copy of this software and associated documentation files (the 7 | 'Software'), to deal in the Software without restriction, including 8 | without limitation the rights to use, copy, modify, merge, publish, 9 | distribute, sublicense, and/or sell copies of the Software, and to 10 | permit persons to whom the Software is furnished to do so, subject to 11 | the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be 14 | included in all copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, 17 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 18 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 19 | IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 20 | CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 21 | TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 22 | SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 23 | -------------------------------------------------------------------------------- /test/fixture/js-default-parameters/output.txt: -------------------------------------------------------------------------------- 1 | function visibleTodoFilter(state = 'watch', action) { 2 | switch (action.type) { 3 | case 'CHANGE_VISIBLE_FILTER': 4 | return action.filter; 5 | default: 6 | return state; 7 | } 8 | } 9 | 10 | function todos(state, action) { 11 | switch (action.type) { 12 | case 'ADD_TODO': 13 | return [...state, { 14 | text: action.text, 15 | completed: false 16 | }]; 17 | case 'COMPLETE_TODO': 18 | return [ 19 | ...state.slice(0, action.index), 20 | Object.assign({}, state[action.index], { 21 | completed: true 22 | }), 23 | ...state.slice(action.index + 1) 24 | ] 25 | default: 26 | return state; 27 | } 28 | } 29 | 30 | import { combineReducers, createStore } from 'redux'; 31 | let reducer = combineReducers({ visibleTodoFilter, todos }); 32 | let store = createStore(reducer); 33 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "emphasize", 3 | "version": "7.0.0", 4 | "description": "ANSI syntax highlighting for the terminal", 5 | "license": "MIT", 6 | "keywords": [ 7 | "ansi", 8 | "code", 9 | "highlight", 10 | "highlighting", 11 | "syntax", 12 | "terminal" 13 | ], 14 | "repository": "wooorm/emphasize", 15 | "bugs": "https://github.com/wooorm/emphasize/issues", 16 | "funding": { 17 | "type": "github", 18 | "url": "https://github.com/sponsors/wooorm" 19 | }, 20 | "author": "Titus Wormer (https://wooorm.com)", 21 | "contributors": [ 22 | "Titus Wormer (https://wooorm.com)" 23 | ], 24 | "sideEffects": false, 25 | "type": "module", 26 | "exports": "./index.js", 27 | "files": [ 28 | "lib/", 29 | "index.d.ts", 30 | "index.js", 31 | "index.map" 32 | ], 33 | "dependencies": { 34 | "@types/hast": "^3.0.0", 35 | "chalk": "^5.0.0", 36 | "highlight.js": "~11.9.0", 37 | "lowlight": "~3.1.0" 38 | }, 39 | "devDependencies": { 40 | "@types/node": "^20.0.0", 41 | "c8": "^8.0.0", 42 | "prettier": "^3.0.0", 43 | "remark-cli": "^11.0.0", 44 | "remark-preset-wooorm": "^9.0.0", 45 | "type-coverage": "^2.0.0", 46 | "typescript": "^5.0.0", 47 | "xo": "^0.56.0" 48 | }, 49 | "scripts": { 50 | "build": "tsc --build --clean && tsc --build && type-coverage", 51 | "format": "remark . --frail --output --quiet && prettier . --log-level warn --write && xo --fix", 52 | "prepack": "npm run build && npm run format", 53 | "test": "npm run build && npm run format && npm run test-coverage", 54 | "test-api": "node --conditions development test/index.js", 55 | "test-coverage": "c8 --100 --reporter lcov npm run test-api" 56 | }, 57 | "prettier": { 58 | "bracketSpacing": false, 59 | "singleQuote": true, 60 | "semi": false, 61 | "tabWidth": 2, 62 | "trailingComma": "none", 63 | "useTabs": false 64 | }, 65 | "remarkConfig": { 66 | "plugins": [ 67 | "remark-preset-wooorm" 68 | ] 69 | }, 70 | "typeCoverage": { 71 | "atLeast": 100, 72 | "detail": true, 73 | "ignoreCatch": true, 74 | "strict": true 75 | }, 76 | "xo": { 77 | "overrides": [ 78 | { 79 | "files": [ 80 | "test/**/*.js" 81 | ], 82 | "rules": { 83 | "no-await-in-loop": "off" 84 | } 85 | } 86 | ], 87 | "prettier": true, 88 | "rules": { 89 | "unicorn/import-style": "off", 90 | "unicorn/prefer-string-replace-all": "off" 91 | } 92 | } 93 | } 94 | -------------------------------------------------------------------------------- /test/index.js: -------------------------------------------------------------------------------- 1 | import assert from 'node:assert/strict' 2 | import fs from 'node:fs/promises' 3 | import process from 'node:process' 4 | import test from 'node:test' 5 | import {Chalk} from 'chalk' 6 | import {all, common, createEmphasize} from 'emphasize' 7 | 8 | const chalk = new Chalk({level: 2}) 9 | 10 | test('emphasize', async function (t) { 11 | await t.test('should expose the public api', async function () { 12 | assert.deepEqual(Object.keys(await import('emphasize')).sort(), [ 13 | 'all', 14 | 'common', 15 | 'createEmphasize' 16 | ]) 17 | }) 18 | }) 19 | 20 | test('highlight', async function (t) { 21 | await t.test( 22 | 'should throw when not given `string` for `name`', 23 | async function () { 24 | const emphasize = createEmphasize() 25 | 26 | assert.throws(function () { 27 | // @ts-expect-error: check how the runtime handles an invalid value. 28 | emphasize.highlight(true) 29 | }, /expected `string` as `name`/) 30 | } 31 | ) 32 | 33 | await t.test( 34 | 'should throw when not given `string` for `value`', 35 | async function () { 36 | const emphasize = createEmphasize() 37 | 38 | assert.throws(function () { 39 | // @ts-expect-error: check how the runtime handles an invalid value. 40 | emphasize.highlight('js', true) 41 | }, /expected `string` as `value`/) 42 | } 43 | ) 44 | 45 | await t.test( 46 | 'should throw when given an unknown `language`', 47 | async function () { 48 | const emphasize = createEmphasize() 49 | 50 | assert.throws(function () { 51 | emphasize.highlight('fooscript', '') 52 | }, /^Error: Unknown language: `fooscript` is not registered$/) 53 | } 54 | ) 55 | 56 | await t.test('should work when empty', async function () { 57 | const emphasize = createEmphasize(common) 58 | assert.deepEqual(emphasize.highlight('js', ''), { 59 | language: 'js', 60 | relevance: 0, 61 | value: '' 62 | }) 63 | }) 64 | 65 | await t.test('should work', function () { 66 | const emphasize = createEmphasize(common) 67 | 68 | assert.deepEqual( 69 | emphasize.highlight('java', 'public void moveTo(int x, int y, int z);'), 70 | { 71 | language: 'java', 72 | relevance: 6, 73 | value: 74 | '\u001B[32mpublic\u001B[39m \u001B[32mvoid\u001B[39m \u001B[34mmoveTo\u001B[39m(\u001B[33mint\u001B[39m x, \u001B[33mint\u001B[39m y, \u001B[33mint\u001B[39m z);' 75 | } 76 | ) 77 | }) 78 | 79 | await t.test('should support custom sheets', function () { 80 | const emphasize = createEmphasize(common) 81 | 82 | assert.equal( 83 | emphasize.highlight('java', 'public void moveTo(int x, int y, int z);', { 84 | keyword: chalk.bold, 85 | title: chalk.italic 86 | }).value, 87 | '\u001B[1mpublic\u001B[22m \u001B[1mvoid\u001B[22m \u001B[3mmoveTo\u001B[23m(int x, int y, int z);' 88 | ) 89 | }) 90 | 91 | await t.test('should silently ignore illegals', async function () { 92 | const emphasize = createEmphasize(common) 93 | 94 | assert.deepEqual(emphasize.highlight('js', '# foo'), { 95 | language: 'js', 96 | relevance: 0, 97 | value: '# foo' 98 | }) 99 | }) 100 | }) 101 | 102 | test('highlightAuto', async function (t) { 103 | await t.test('should throw when not given a string', async function () { 104 | const emphasize = createEmphasize(common) 105 | 106 | assert.throws(function () { 107 | // @ts-expect-error: check how the runtime handles an invalid value. 108 | emphasize.highlightAuto(true) 109 | }, /expected `string` as `value`/) 110 | }) 111 | 112 | await t.test('should work when empty', async function () { 113 | const emphasize = createEmphasize(common) 114 | const result = emphasize.highlightAuto('') 115 | assert.deepEqual(result, { 116 | language: undefined, 117 | relevance: 0, 118 | value: '' 119 | }) 120 | }) 121 | 122 | await t.test('should work', async function () { 123 | const emphasize = createEmphasize(common) 124 | const result = emphasize.highlightAuto('"use strict";') 125 | 126 | assert.deepEqual(result, { 127 | language: 'javascript', 128 | relevance: 10, 129 | value: '\u001B[35m"use strict"\u001B[39m;' 130 | }) 131 | }) 132 | 133 | await t.test('should support custom sheets', async function () { 134 | const emphasize = createEmphasize(common) 135 | const result = emphasize.highlightAuto('"use strict";', { 136 | meta: chalk.bold 137 | }) 138 | 139 | assert.deepEqual(result, { 140 | language: 'javascript', 141 | relevance: 10, 142 | value: '\u001B[1m"use strict"\u001B[22m;' 143 | }) 144 | }) 145 | 146 | await t.test('should support a `subset`', async function () { 147 | const emphasize = createEmphasize(common) 148 | const result = emphasize.highlightAuto('"use strict";', {subset: ['java']}) 149 | 150 | assert.equal(result.language, 'java') 151 | }) 152 | 153 | await t.test( 154 | 'should ignore unregistered subset languages (#1)', 155 | async function () { 156 | const emphasize = createEmphasize(common) 157 | const result = emphasize.highlightAuto('"use strict";', { 158 | subset: ['fooscript', 'javascript'] 159 | }) 160 | 161 | assert.equal(result.language, 'javascript') 162 | } 163 | ) 164 | }) 165 | 166 | test('fixtures', async function (t) { 167 | const base = new URL('fixture/', import.meta.url) 168 | const files = await fs.readdir(base) 169 | let index = -1 170 | const emphasize = createEmphasize(all) 171 | 172 | while (++index < files.length) { 173 | const dirname = files[index] 174 | 175 | if (dirname.charAt(0) === '.') continue 176 | 177 | const folder = new URL(dirname + '/', base) 178 | const language = dirname.split('-')[0] 179 | 180 | await t.test(dirname, async function () { 181 | const input = String( 182 | await fs.readFile(new URL('input.txt', folder)) 183 | ).trim() 184 | const actual = emphasize.highlight(language, input).value 185 | /** @type {string} */ 186 | let expected 187 | 188 | try { 189 | if ('UPDATE' in process.env) { 190 | throw new Error('Updating') 191 | } 192 | 193 | expected = String( 194 | await fs.readFile(new URL('output.txt', folder)) 195 | ).trim() 196 | } catch { 197 | expected = actual 198 | await fs.writeFile(new URL('output.txt', folder), actual + '\n') 199 | } 200 | 201 | assert.equal(actual, expected) 202 | }) 203 | } 204 | }) 205 | -------------------------------------------------------------------------------- /lib/index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @typedef {import('hast').Element} Element 3 | * @typedef {import('hast').Root} Root 4 | * @typedef {import('hast').RootData} RootData 5 | * @typedef {import('hast').Text} Text 6 | * 7 | * @typedef {import('lowlight').AutoOptions} LowlightAutoOptions 8 | * @typedef {import('lowlight').LanguageFn} LanguageFn 9 | */ 10 | 11 | /** 12 | * @typedef AutoFieldsExtra 13 | * Extra fields. 14 | * @property {Sheet | null | undefined} [sheet] 15 | * Sheet (optional). 16 | * 17 | * @typedef {Pick} AutoFieldsPicked 18 | * Picked fields. 19 | * 20 | * @typedef {AutoFieldsExtra & AutoFieldsPicked} AutoOptions 21 | * Configuration for `highlightAuto`. 22 | * 23 | * @typedef Result 24 | * Result. 25 | * @property {string | undefined} language 26 | * Detected programming language. 27 | * @property {number | undefined} relevance 28 | * How sure `lowlight` is that the given code is in the language. 29 | * @property {string} value 30 | * Highlighted code. 31 | * 32 | * @typedef {Record} Sheet 33 | * Map `highlight.js` classes to styles functions. 34 | * 35 | * The `hljs-` prefix must not be used in those classes. 36 | * The “descendant selector” (a space) is supported. 37 | * 38 | * For convenience [chalk’s chaining of styles][styles] is suggested. 39 | * An abbreviated example is as follows: 40 | * 41 | * ```js 42 | * { 43 | * 'comment': chalk.gray, 44 | * 'meta meta-string': chalk.cyan, 45 | * 'meta keyword': chalk.magenta, 46 | * 'emphasis': chalk.italic, 47 | * 'strong': chalk.bold, 48 | * 'formula': chalk.inverse 49 | * } 50 | * ``` 51 | * 52 | * @callback Style 53 | * Color something. 54 | * @param {string} value 55 | * Input. 56 | * @returns {string} 57 | * Output. 58 | */ 59 | 60 | import {Chalk} from 'chalk' 61 | import {createLowlight} from 'lowlight' 62 | 63 | const chalk = new Chalk({level: 2}) 64 | 65 | /** 66 | * Default style sheet. 67 | * 68 | * @type {Readonly} 69 | */ 70 | const defaultSheet = { 71 | comment: chalk.gray, 72 | quote: chalk.gray, 73 | 74 | keyword: chalk.green, 75 | 'selector-tag': chalk.green, 76 | addition: chalk.green, 77 | 78 | number: chalk.cyan, 79 | string: chalk.cyan, 80 | 'meta meta-string': chalk.cyan, 81 | literal: chalk.cyan, 82 | doctag: chalk.cyan, 83 | regexp: chalk.cyan, 84 | 85 | title: chalk.blue, 86 | section: chalk.blue, 87 | name: chalk.blue, 88 | 'selector-id': chalk.blue, 89 | 'selector-class': chalk.blue, 90 | 91 | attribute: chalk.yellow, 92 | attr: chalk.yellow, 93 | variable: chalk.yellow, 94 | 'template-variable': chalk.yellow, 95 | 'class title': chalk.yellow, 96 | type: chalk.yellow, 97 | 98 | symbol: chalk.magenta, 99 | bullet: chalk.magenta, 100 | subst: chalk.magenta, 101 | meta: chalk.magenta, 102 | 'meta keyword': chalk.magenta, 103 | 'selector-attr': chalk.magenta, 104 | 'selector-pseudo': chalk.magenta, 105 | link: chalk.magenta, 106 | 107 | /* eslint-disable camelcase */ 108 | built_in: chalk.red, 109 | /* eslint-enable camelcase */ 110 | deletion: chalk.red, 111 | 112 | emphasis: chalk.italic, 113 | strong: chalk.bold, 114 | formula: chalk.inverse 115 | } 116 | 117 | /** 118 | * Create an `emphasize` instance. 119 | * 120 | * @param {Readonly> | null | undefined} [grammars] 121 | * Grammars to add (optional). 122 | * @returns 123 | * Emphasize. 124 | */ 125 | export function createEmphasize(grammars) { 126 | const lowlight = createLowlight(grammars) 127 | 128 | return { 129 | highlight, 130 | highlightAuto, 131 | listLanguages: lowlight.listLanguages, 132 | register: lowlight.register, 133 | registerAlias: lowlight.registerAlias, 134 | registered: lowlight.registered 135 | } 136 | 137 | /** 138 | * Highlight `value` (code) as `language` (name). 139 | * 140 | * @param {string} language 141 | * Programming language name. 142 | * @param {string} value 143 | * Code to highlight. 144 | * @param {Readonly | null | undefined} [sheet] 145 | * Style sheet (optional). 146 | * @returns {Result} 147 | * Result. 148 | */ 149 | function highlight(language, value, sheet) { 150 | const result = lowlight.highlight(language, value) 151 | const data = /** @type {RootData} */ (result.data) 152 | 153 | return { 154 | language: data.language, 155 | relevance: data.relevance, 156 | value: visit(sheet || defaultSheet, result) 157 | } 158 | } 159 | 160 | /** 161 | * Highlight `value` (code) and guess its programming language. 162 | * 163 | * @param {string} value 164 | * Code to highlight. 165 | * @param {Readonly | Readonly | null | undefined} [options] 166 | * Configuration or style sheet (optional). 167 | * @returns {Result} 168 | * Result. 169 | */ 170 | function highlightAuto(value, options) { 171 | /** @type {Readonly | null | undefined} */ 172 | let sheet 173 | /** @type {Readonly | undefined} */ 174 | let config 175 | 176 | if (options && ('subset' in options || 'sheet' in options)) { 177 | const settings = /** @type {Readonly} */ (options) 178 | config = {subset: settings.subset} 179 | sheet = settings.sheet 180 | } else { 181 | sheet = /** @type {Readonly | null | undefined} */ (options) 182 | } 183 | 184 | const result = lowlight.highlightAuto(value, config) 185 | const data = /** @type {RootData} */ (result.data) 186 | return { 187 | language: data.language, 188 | relevance: data.relevance, 189 | value: visit(sheet || defaultSheet, result) 190 | } 191 | } 192 | } 193 | 194 | /** 195 | * Visit one `node`. 196 | * 197 | * @param {Readonly} sheet 198 | * Sheet. 199 | * @param {Readonly | Readonly | Readonly} node 200 | * Node. 201 | * @returns {string} 202 | * Result. 203 | */ 204 | function visit(sheet, node) { 205 | const names = new Set( 206 | node.type === 'element' && Array.isArray(node.properties.className) 207 | ? node.properties.className.map(function (d) { 208 | return String(d).replace(/^hljs-/, '') 209 | }) 210 | : [] 211 | ) 212 | /** @type {Sheet} */ 213 | const scoped = {} 214 | /** @type {Style | undefined} */ 215 | let style 216 | /** @type {string} */ 217 | let content = '' 218 | /** @type {string} */ 219 | let key 220 | 221 | for (key in sheet) { 222 | if (Object.hasOwn(sheet, key)) { 223 | const parts = key.split(' ') 224 | const color = sheet[key] 225 | 226 | if (names.has(parts[0])) { 227 | if (parts.length === 1) { 228 | style = color 229 | } else { 230 | scoped[parts.slice(1).join(' ')] = color 231 | } 232 | } else { 233 | scoped[key] = color 234 | } 235 | } 236 | } 237 | 238 | if ('value' in node) { 239 | content = node.value 240 | } else if ('children' in node) { 241 | content = all( 242 | scoped, 243 | /** @type {ReadonlyArray} */ (node.children) 244 | ) 245 | } 246 | 247 | if (style) { 248 | content = style(content) 249 | } 250 | 251 | return content 252 | } 253 | 254 | /** 255 | * Visit children in `node`. 256 | * 257 | * @param {Readonly} sheet 258 | * Sheet. 259 | * @param {ReadonlyArray} nodes 260 | * Nodes. 261 | * @returns {string} 262 | * Result. 263 | */ 264 | function all(sheet, nodes) { 265 | /** @type {Array} */ 266 | const result = [] 267 | let index = -1 268 | 269 | while (++index < nodes.length) { 270 | result.push(visit(sheet, nodes[index])) 271 | } 272 | 273 | return result.join('') 274 | } 275 | -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | # emphasize 2 | 3 | [![Build][badge-build-image]][badge-build-url] 4 | [![Coverage][badge-coverage-image]][badge-coverage-url] 5 | [![Downloads][badge-downloads-image]][badge-downloads-url] 6 | [![Size][badge-size-image]][badge-size-url] 7 | 8 | ANSI syntax highlighting for the terminal. 9 | 10 | ## Contents 11 | 12 | * [What is this?](#what-is-this) 13 | * [When should I use this?](#when-should-i-use-this) 14 | * [Install](#install) 15 | * [Use](#use) 16 | * [API](#api) 17 | * [`all`](#all) 18 | * [`common`](#common) 19 | * [`createEmphasize(grammars?)`](#createemphasizegrammars) 20 | * [`emphasize.highlight(language, value[, options])`](#emphasizehighlightlanguage-value-options) 21 | * [`emphasize.highlightAuto(value[, options])`](#emphasizehighlightautovalue-options) 22 | * [`emphasize.listLanguages()`](#emphasizelistlanguages) 23 | * [`emphasize.register(grammars)`](#emphasizeregistergrammars) 24 | * [`emphasize.registerAlias(aliases)`](#emphasizeregisteraliasaliases) 25 | * [`emphasize.registered(aliasOrLanguage)`](#emphasizeregisteredaliasorlanguage) 26 | * [`AutoOptions`](#autooptions) 27 | * [`LanguageFn`](#languagefn) 28 | * [`Result`](#result) 29 | * [`Sheet`](#sheet) 30 | * [`Style`](#style) 31 | * [Compatibility](#compatibility) 32 | * [Security](#security) 33 | * [Contribute](#contribute) 34 | * [License](#license) 35 | 36 | ## What is this? 37 | 38 | This package wraps [`lowlight`][github-lowlight] to output ANSI syntax 39 | highlighting instead of HTML. 40 | It can support 190+ programming languages. 41 | 42 | ## When should I use this? 43 | 44 | This package is useful when you want to display code on a terminal. 45 | 46 | ## Install 47 | 48 | This package is [ESM only][github-gist-esm]. 49 | In Node.js (version 16+), 50 | install with [npm][npm-install]: 51 | 52 | ```sh 53 | npm install emphasize 54 | ``` 55 | 56 | In Deno with [`esm.sh`][esm-sh]: 57 | 58 | ```js 59 | import {all, common, createEmphasize} from 'https://esm.sh/emphasize@7' 60 | ``` 61 | 62 | In browsers with [`esm.sh`][esm-sh]: 63 | 64 | ```html 65 | 68 | ``` 69 | 70 | ## Use 71 | 72 | Say `example.css` looks as follows: 73 | 74 | ```css 75 | @font-face { 76 | font-family: Alpha; 77 | src: url('Bravo.otf'); 78 | } 79 | 80 | body, .charlie, #delta { 81 | color: #bada55; 82 | background-color: rgba(33, 33, 33, 0.33); 83 | font-family: "Alpha", sans-serif; 84 | } 85 | 86 | @import url(echo.css); 87 | 88 | @media print { 89 | a[href^=http]::after { 90 | content: attr(href) 91 | } 92 | } 93 | ``` 94 | 95 | …and `example.js` contains the following: 96 | 97 | ```js 98 | import fs from 'node:fs/promises' 99 | import {emphasize} from 'emphasize' 100 | 101 | const doc = String(await fs.readFile('example.css')) 102 | 103 | const output = emphasize.highlightAuto(doc).value 104 | 105 | console.log(output) 106 | ``` 107 | 108 | …now running `node example.js` yields: 109 | 110 | ```txt 111 | \x1B[32m@font-face\x1B[39m { 112 | \x1B[33mfont-family\x1B[39m: Alpha; 113 | \x1B[33msrc\x1B[39m: \x1B[31murl\x1B[39m(\x1B[36m'Bravo.otf'\x1B[39m); 114 | } 115 | 116 | \x1B[32mbody\x1B[39m, \x1B[34m.charlie\x1B[39m, \x1B[34m#delta\x1B[39m { 117 | \x1B[33mcolor\x1B[39m: \x1B[36m#bada55\x1B[39m; 118 | \x1B[33mbackground-color\x1B[39m: \x1B[31mrgba\x1B[39m(\x1B[36m33\x1B[39m, \x1B[36m33\x1B[39m, \x1B[36m33\x1B[39m, \x1B[36m0.33\x1B[39m); 119 | \x1B[33mfont-family\x1B[39m: \x1B[36m"Alpha"\x1B[39m, sans-serif; 120 | } 121 | 122 | \x1B[32m@import\x1B[39m url(echo.css); 123 | 124 | \x1B[32m@media\x1B[39m print { 125 | \x1B[32ma\x1B[39m\x1B[35m[href^=http]\x1B[39m\x1B[35m::after\x1B[39m { 126 | \x1B[33mcontent\x1B[39m: \x1B[31mattr\x1B[39m(href) 127 | } 128 | } 129 | ``` 130 | 131 | …which looks as follows: 132 | 133 | ![Screenshot showing the code in terminal](screenshot.png) 134 | 135 | ## API 136 | 137 | This package exports the identifiers 138 | [`all`][api-all], 139 | [`common`][api-common], 140 | and [`createEmphasize`][api-create-emphasize]. 141 | There is no default export. 142 | 143 | It exports the [TypeScript][] types 144 | [`AutoOptions`][api-auto-options], 145 | [`LanguageFn`][api-language-fn], 146 | [`Result`][api-result], 147 | [`Sheet`][api-sheet], 148 | and [`Style`][api-style]. 149 | 150 | ### `all` 151 | 152 | Map of all (±190) grammars ([`Record`][api-language-fn]). 153 | 154 | See [`all` from `lowlight`][github-lowlight-all]. 155 | 156 | ### `common` 157 | 158 | Map of common (37) grammars ([`Record`][api-language-fn]). 159 | 160 | See [`common` from `lowlight`][github-lowlight-common]. 161 | 162 | ### `createEmphasize(grammars?)` 163 | 164 | Create a `emphasize` instance. 165 | 166 | ###### Parameters 167 | 168 | * `grammars` ([`Record`][api-language-fn], optional) 169 | — grammars to add 170 | 171 | ###### Returns 172 | 173 | Emphasize (`emphasize`). 174 | 175 | ### `emphasize.highlight(language, value[, options])` 176 | 177 | Highlight `value` (code) as `language` (name). 178 | 179 | ###### Parameters 180 | 181 | * `language` (`string`) 182 | — programming language [name][github-highlight-names] 183 | * `value` (`string`) 184 | — code to highlight 185 | * `sheet` ([`Sheet`][api-sheet], optional) 186 | — style sheet 187 | 188 | ###### Returns 189 | 190 | [`Result`][api-result]. 191 | 192 | ### `emphasize.highlightAuto(value[, options])` 193 | 194 | Highlight `value` (code) and guess its programming language. 195 | 196 | ###### Parameters 197 | 198 | * `value` (`string`) 199 | — code to highlight 200 | * `options` ([`AutoOptions`][api-auto-options] or [`Sheet`][api-sheet], 201 | optional) 202 | — configuration or style sheet 203 | 204 | ###### Returns 205 | 206 | [`Result`][api-result]. 207 | 208 | ### `emphasize.listLanguages()` 209 | 210 | List registered languages. 211 | 212 | See [`lowlight.listLanguages`][github-lowlight-list-languages]. 213 | 214 | ### `emphasize.register(grammars)` 215 | 216 | Register languages. 217 | 218 | See [`lowlight.register`][github-lowlight-register]. 219 | 220 | ### `emphasize.registerAlias(aliases)` 221 | 222 | Register aliases. 223 | 224 | See [`lowlight.registerAlias`][github-lowlight-register-alias]. 225 | 226 | ### `emphasize.registered(aliasOrLanguage)` 227 | 228 | Check whether an alias or name is registered. 229 | 230 | See [`lowlight.registered`][github-lowlight-registered]. 231 | 232 | ### `AutoOptions` 233 | 234 | Configuration for `highlightAuto` (TypeScript type). 235 | 236 | ###### Fields 237 | 238 | * `sheet` ([`Sheet`][api-sheet], optional) 239 | — sheet 240 | * `subset` (`Array`, default: all registered languages) 241 | — list of allowed languages 242 | 243 | ### `LanguageFn` 244 | 245 | Highlight.js grammar (TypeScript type). 246 | 247 | See [`LanguageFn` from `lowlight`][github-lowlight-langauge-fn]. 248 | 249 | ### `Result` 250 | 251 | Result (TypeScript type). 252 | 253 | ###### Fields 254 | 255 | * `language` (`string` or `undefined`) 256 | — detected programming language. 257 | * `relevance` (`number` or `undefined`) 258 | — how sure `lowlight` is that the given code is in the language 259 | * `value` (`string`) 260 | — highlighted code 261 | 262 | ### `Sheet` 263 | 264 | Map [`highlight.js` classes][github-highlight-classes] to styles functions 265 | (TypeScript type). 266 | 267 | The `hljs-` prefix must not be used in those classes. 268 | The “descendant selector” (a space) is supported. 269 | 270 | For convenience [chalk’s chaining of styles][github-chalk-styles] is suggested. 271 | An abbreviated example is as follows: 272 | 273 | ```js 274 | { 275 | 'comment': chalk.gray, 276 | 'meta meta-string': chalk.cyan, 277 | 'meta keyword': chalk.magenta, 278 | 'emphasis': chalk.italic, 279 | 'strong': chalk.bold, 280 | 'formula': chalk.inverse 281 | } 282 | ``` 283 | 284 | ###### Type 285 | 286 | ```ts 287 | type Sheet = Record 288 | ``` 289 | 290 | ### `Style` 291 | 292 | Color something (TypeScript type). 293 | 294 | ###### Parameters 295 | 296 | * `value` (`string`) 297 | — input 298 | 299 | ###### Returns 300 | 301 | Output (`string`). 302 | 303 | ## Compatibility 304 | 305 | This projects is compatible with maintained versions of Node.js. 306 | 307 | When we cut a new major release, 308 | we drop support for unmaintained versions of Node. 309 | This means we try to keep the current release line, 310 | `emphasize@7`, 311 | compatible with Node.js 16. 312 | 313 | ## Security 314 | 315 | This package is safe. 316 | 317 | ## Contribute 318 | 319 | Yes please! 320 | See [How to Contribute to Open Source][open-source-guide-contribute]. 321 | 322 | ## License 323 | 324 | [MIT][file-license] © [Titus Wormer][wooorm] 325 | 326 | 327 | 328 | [api-all]: #all 329 | 330 | [api-auto-options]: #autooptions 331 | 332 | [api-common]: #common 333 | 334 | [api-create-emphasize]: #createemphasizegrammars 335 | 336 | [api-language-fn]: #languagefn 337 | 338 | [api-result]: #result 339 | 340 | [api-sheet]: #sheet 341 | 342 | [api-style]: #style 343 | 344 | [badge-build-image]: https://github.com/wooorm/emphasize/workflows/main/badge.svg 345 | 346 | [badge-build-url]: https://github.com/wooorm/emphasize/actions 347 | 348 | [badge-coverage-image]: https://img.shields.io/codecov/c/github/wooorm/emphasize.svg 349 | 350 | [badge-coverage-url]: https://codecov.io/github/wooorm/emphasize 351 | 352 | [badge-downloads-image]: https://img.shields.io/npm/dm/emphasize.svg 353 | 354 | [badge-downloads-url]: https://www.npmjs.com/package/emphasize 355 | 356 | [badge-size-image]: https://img.shields.io/bundlejs/size/emphasize 357 | 358 | [badge-size-url]: https://bundlejs.com/?q=emphasize 359 | 360 | [npm-install]: https://docs.npmjs.com/cli/install 361 | 362 | [esm-sh]: https://esm.sh 363 | 364 | [file-license]: license 365 | 366 | [github-chalk-styles]: https://github.com/chalk/chalk#styles 367 | 368 | [github-gist-esm]: https://gist.github.com/sindresorhus/a39789f98801d908bbc7ff3ecc99d99c 369 | 370 | [github-highlight-classes]: https://highlightjs.readthedocs.io/en/latest/css-classes-reference.html 371 | 372 | [github-highlight-names]: https://github.com/highlightjs/highlight.js/blob/main/SUPPORTED_LANGUAGES.md 373 | 374 | [github-lowlight]: https://github.com/wooorm/lowlight 375 | 376 | [github-lowlight-all]: https://github.com/wooorm/lowlight#all 377 | 378 | [github-lowlight-common]: https://github.com/wooorm/lowlight#common 379 | 380 | [github-lowlight-langauge-fn]: https://github.com/wooorm/lowlight#languagefn 381 | 382 | [github-lowlight-list-languages]: https://github.com/wooorm/lowlight#lowlightlistlanguages 383 | 384 | [github-lowlight-register]: https://github.com/wooorm/lowlight#lowlightregistergrammars 385 | 386 | [github-lowlight-register-alias]: https://github.com/wooorm/lowlight#lowlightregisteraliasaliases 387 | 388 | [github-lowlight-registered]: https://github.com/wooorm/lowlight#lowlightregisteredaliasorlanguage 389 | 390 | [open-source-guide-contribute]: https://opensource.guide/how-to-contribute/ 391 | 392 | [typescript]: https://www.typescriptlang.org 393 | 394 | [wooorm]: https://wooorm.com 395 | --------------------------------------------------------------------------------