├── 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 | [90m{- this is a {- nested -} comment -}[39m
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 | [35m#!/usr/bin/env node[39m
2 |
3 | [32mvar[39m a = [36m1[39m;
4 |
--------------------------------------------------------------------------------
/test/fixture/go-numbers/output.txt:
--------------------------------------------------------------------------------
1 | float_var := [36m1.0e10[39mf
2 | complex_var := [36m1.2e5[39m+[36m2.3i[39m
3 |
--------------------------------------------------------------------------------
/test/fixture/md-sublanguage/input.txt:
--------------------------------------------------------------------------------
1 | This is _markdown_ with some HTML
2 |
--------------------------------------------------------------------------------
/test/fixture/rust-comments/output.txt:
--------------------------------------------------------------------------------
1 | [90m/* rust has[39m
2 | [90m/* nested /* block */ */[39m
3 | [90m*/[39m comments
4 |
--------------------------------------------------------------------------------
/test/fixture/xml-sublanguages/input.txt:
--------------------------------------------------------------------------------
1 |
2 |
7 |
--------------------------------------------------------------------------------
/test/fixture/haskell-infix/output.txt:
--------------------------------------------------------------------------------
1 | [32minfix[39m [36m3[39m `foo`
2 | [32minfixl[39m [36m6[39m `bar`
3 | [32minfixr[39m [36m9[39m `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 | [32mlet[39m [33mfoo[39m;
2 | [32mlet[39m [32mmut [39m[33mbar[39m;
3 | [32mlet[39m [33m_foo_bar[39m;
4 |
--------------------------------------------------------------------------------
/test/fixture/css-pseudo-selector/output.txt:
--------------------------------------------------------------------------------
1 | [32mli[39m[35m:not[39m([34m.red[39m){}
2 | [32mli[39m[35m:not[39m([34m.red[39m)[35m:not[39m([34m.green[39m){}
3 |
--------------------------------------------------------------------------------
/test/fixture/md-sublanguage/output.txt:
--------------------------------------------------------------------------------
1 | This is [3m_markdown_[23m with some <[34mabbr[39m [33mtitle[39m=[36m"Hypertext Markup Language"[39m>HTML[34mabbr[39m>
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 | [90m[39m
2 | <[34mstyle[39m>
3 | [34m.foo[39m {
4 | [33mcolor[39m: red;
5 | }
6 | [34mstyle[39m>
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 | [90m# numbers aren't highlighted in bash as their semantics is[39m
2 | [90m# not strictly defined for command line parameters[39m
3 | $ [31mtail[39m -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 | [90m# Divisions[39m
2 | x = [36m6[39m/foo/i
3 | x = [36m6[39m /foo
4 | x = [36m6[39m / foo
5 | x = [36m6[39m /foo * [36m2[39m/gm
6 | x = f /foo
7 | x = f / foo / gm
8 | x = f /foo * [36m2[39m/[36m6[39m
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 | [32mfn[39m [34msqr[39m(i: [33mi32[39m) { i * i }
2 | [32mtrait[39m [34mMinimum[39m : [31mCopy[39m {}
3 | [32mpub[39m [32mtrait[39m [34mBuilder[39m [32mwhere[39m [32mSelf[39m: [31mSized[39m + [31mIterator[39m- {}
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 |
2 | (|spaces and
3 | newlines| x)
4 | (x '|quoted|)
5 |
--------------------------------------------------------------------------------
/test/fixture/swift-functions/output.txt:
--------------------------------------------------------------------------------
1 | [32mprotocol[39m [34mProtocol[39m {
2 | [32mfunc[39m [34mf1[39m()
3 | [32mfunc[39m [34mf2[39m()
4 | }
5 |
6 | [32mclass[39m [34mMyClass[39m {
7 | [32mfunc[39m [34mf[39m() {
8 | [32mreturn[39m [36mtrue[39m
9 | }
10 | }
11 |
--------------------------------------------------------------------------------
/test/fixture/http-default/output.txt:
--------------------------------------------------------------------------------
1 | [32mPOST[39m [36m/task?id=1[39m [35mHTTP/1.1[39m
2 | [33mHost[39m: example.org
3 | [33mContent-Type[39m: application/json; charset=utf-8
4 | [33mContent-Length[39m: 19
5 |
6 | {[33m"status"[39m: [36m"ok"[39m, [33m"extended"[39m: [36m[32mtrue[39m[36m[39m}
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 | [36m'a'[39m;
2 | [36m'\n'[39m;
3 | [36m'\x1A'[39m;
4 | [36m'\u12AS'[39m;
5 | [36m'\U1234ASDF'[39m;
6 | [36mb'a'[39m;
7 |
8 | [36m"hello"[39m;
9 | [36mb"hello"[39m;
10 |
11 | [36mr"hello"[39m;
12 | [36mr###"world"###[39m;
13 | [36mr##" "### "# "##[39m;
14 |
--------------------------------------------------------------------------------
/test/fixture/coffee-regex/output.txt:
--------------------------------------------------------------------------------
1 | [90m# Regexps[39m
2 | x = [36m/\//[39m
3 | x = [36m/\n/[39m
4 | x = [36m/ab\/ ab/[39m
5 | x = f [36m/6 * 2/[39m - [36m3[39m
6 | x = f [36m/foo * 2/gm[39m
7 | x = [32mif[39m [36mtrue[39m [32mthen[39m [36m/\n/[39m [32melse[39m [36m/[.,]+/[39m
8 | x = [36m///^key-[35m#{key}[39m[36m-\d+///[39m
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 | [36m123[39m;
2 | [36m123usize[39m;
3 | [36m123_usize[39m;
4 | [36m0xff00[39m;
5 | [36m0xff_u8[39m;
6 | [36m0b1111111110010000[39m;
7 | [36m0b1111_1111_1001_0000_i32[39m;
8 | [36m0o764317[39m;
9 | [36m0o764317_u16[39m;
10 | [36m123.0[39m;
11 | [36m0.1[39m;
12 | [36m0.1f32[39m;
13 | [36m12E+99_f64[39m;
14 |
--------------------------------------------------------------------------------
/test/fixture/js-class/output.txt:
--------------------------------------------------------------------------------
1 | [32mclass[39m [34mCar[39m [32mextends[39m [34mVehicle[39m {
2 | [34mconstructor[39m(speed, cost) {
3 | [33msuper[39m(speed);
4 |
5 | [32mvar[39m c = [34mSymbol[39m([36m'cost'[39m);
6 | [33mthis[39m[c] = cost;
7 |
8 | [33mthis[39m.intro = [36m`This is a car runs at[39m
9 | [36m [35m${speed}[39m[36m.`[39m;
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 | [32mvar[39m jsx = <[34mnode[39m/>;
2 | [32mvar[39m jsx = <[34mnode[39m><[34mchild[39m/>[34mnode[39m>;
3 | [32mvar[39m jsx = <[34mnode[39m>...<[34mchild[39m>...[34mchild[39m>[34mnode[39m>;
4 | [32mvar[39m jsx = <[34mdiv[39m><[34mbr[39m />[34mdiv[39m>;
5 | [32mvar[39m x = [36m5[39m;
6 | [32mreturn[39m (<[34mnode[39m [33mattr[39m=[36m"value"[39m>[34mnode[39m>);
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 | [35m[39m
2 | <[34mresponse[39m [33mvalue[39m=[36m"ok"[39m [33mxml:lang[39m=[36m"en"[39m>
3 | <[34mtext[39m>Ok[34mtext[39m>
4 | <[34mcomment[39m [33mhtml_allowed[39m=[36m"true"[39m/>
5 | <[34mns1:description[39m> magical.
7 | ]]>[34mns1:description[39m>
8 | <[34ma[39m>[34ma[39m> <[34ma[39m/>
9 | [34mresponse[39m>
10 |
--------------------------------------------------------------------------------
/test/fixture/js-modules/output.txt:
--------------------------------------------------------------------------------
1 | [90m//------ underscore.js ------[39m
2 | [32mexport[39m [32mdefault[39m [32mfunction[39m (obj) {};
3 | [32mexport[39m [32mfunction[39m [34meach[39m(obj, iterator, context) {};
4 | [32mexport[39m { each [32mas[39m forEach };
5 | [32mexport[39m [32mfunction[39m [34msomething[39m() {};
6 |
7 | [90m//------ main.js ------[39m
8 | [32mimport[39m _, { each, something [32mas[39m otherthing } [32mfrom[39m [36m'underscore'[39m;
9 |
--------------------------------------------------------------------------------
/test/fixture/coffee-function/output.txt:
--------------------------------------------------------------------------------
1 | [34mreturnNull[39m = -> [36mnull[39m
2 | [34mreturnTrue[39m = () -> [36mtrue[39m
3 | [34msquare[39m = (x) -> x * x
4 |
5 | npmWishlist.sha256 = (str) ->
6 | [32mthrow[39m [32mnew[39m [31mError[39m()
7 |
8 | str.split([36m" "[39m).map((m) -> m.charCodeAt([36m0[39m))
9 |
10 | fs.readFile([36m"package.json"[39m, [36m"utf-8"[39m, (err, content) ->
11 | data = [31mJSON[39m.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 | [32mfunction[39m [34m$initHighlight[39m(block, cls) {
2 | [32mtry[39m {
3 | [32mif[39m (cls.[34msearch[39m([36m/\bno\-highlight\b/[39m) != -[36m1[39m)
4 | [32mreturn[39m [34mprocess[39m(block, [36mtrue[39m, [36m0x0F[39m) +
5 | [36m' class=""'[39m;
6 | } [32mcatch[39m (e) {
7 | [90m/* handle exception */[39m
8 | }
9 | [32mfor[39m ([32mvar[39m i = [36m0[39m / [36m2[39m; i < classes.length; i++) {
10 | [32mif[39m ([34mcheckCondition[39m(classes[i]) === [36mundefined[39m)
11 | [32mreturn[39m [36m/\d+[\s/]/g[39m;
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 | [32mfunction[39m [34mvisibleTodoFilter[39m(state = [36m'watch'[39m, action) {
2 | [32mswitch[39m (action.type) {
3 | [32mcase[39m [36m'CHANGE_VISIBLE_FILTER'[39m:
4 | [32mreturn[39m action.filter;
5 | [33mdefault[39m:
6 | [32mreturn[39m state;
7 | }
8 | }
9 |
10 | [32mfunction[39m [34mtodos[39m(state, action) {
11 | [32mswitch[39m (action.type) {
12 | [32mcase[39m [36m'ADD_TODO'[39m:
13 | [32mreturn[39m [...state, {
14 | [33mtext[39m: action.text,
15 | [33mcompleted[39m: [36mfalse[39m
16 | }];
17 | [32mcase[39m [36m'COMPLETE_TODO'[39m:
18 | [32mreturn[39m [
19 | ...state.[34mslice[39m([36m0[39m, action.index),
20 | [34mObject[39m.[34massign[39m({}, state[action.index], {
21 | [33mcompleted[39m: [36mtrue[39m
22 | }),
23 | ...state.[34mslice[39m(action.index + [36m1[39m)
24 | ]
25 | [33mdefault[39m:
26 | [32mreturn[39m state;
27 | }
28 | }
29 |
30 | [32mimport[39m { combineReducers, createStore } [32mfrom[39m [36m'redux'[39m;
31 | [32mlet[39m reducer = [34mcombineReducers[39m({ visibleTodoFilter, todos });
32 | [32mlet[39m store = [34mcreateStore[39m(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 | 
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 |
--------------------------------------------------------------------------------