lowlight

repository·main·Indexed 21 days ago

https://github.com/wooorm/lowlight

A virtual syntax highlighting library based on highlight.js that outputs ASTs (specifically hast) instead of HTML strings. This makes it suitable for virtual DOM environments like React and Preact, CLI tools, and AST-based processing pipelines such as rehype. It supports over 190 programming languages and provides utilities for manual or automatic language detection, grammar registration, and alias mapping.

Tokens
3.6K
Snippets
18
Records
22
Agent score
66%

What's inside lowlight

  1. How lowlight works

    main

    lowlight provides virtual syntax highlighting by using highlight.js grammars to output Abstract Syntax Trees (ASTs) instead of serialized HTML strings. This makes it ideal for:

    • Rendering to ANSI sequences for CLIs.
    • Using virtual DOM frameworks (React, Preact, etc.) where AST-to-VDOM conversion allows for performant diffing.
    • Working with ASTs in tools like rehype.

    It supports over 190 programming languages.

  2. Install lowlight

    main

    lowlight is an ESM-only package.

    In Node.js (version 16+), install via npm:

    npm install lowlight

    In Deno using esm.sh:

    import {all, common, createLowlight} from 'https://esm.sh/lowlight@3'

    In browsers using esm.sh:

    <script type="module">
      import {all, common, createLowlight} from 'https://esm.sh/lowlight@3?bundle'
    </script>
    npm install lowlight
  3. Apply CSS for syntax highlighting

    main

    The lowlight package does not inject CSS for the highlighted code. If you are rendering the output in a browser, you must include a highlight.js theme via a stylesheet.

    Example using GitHub Dark from cdnjs:

    <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.11.0/styles/github-dark.min.css">
  4. TypeScript integration for hast data fields

    main

    lowlight registers root.data with @types/hast. To ensure TypeScript recognizes the new fields (like language and relevance) on your hast objects, you must import lowlight somewhere in your type definitions.

    /**
     * @import {Root} from 'hast'
     * @import {} from 'lowlight'
     */
    
    import {VFile} from 'vfile'
    
    /** @type {Root} */
    const root = {type: 'root', children: []}
    
    // TS now knows that this is a `string?`.
    console.log(root.data?.language)
  5. Configure syntax grammars for `createLowlight()`

    main

    When using createLowlight(), no syntaxes are included by default. You must provide grammars to enable highlighting. You have three main ways to provide them:

    1. Use all: Includes all supported syntaxes.
    2. Use common: Includes a subset of frequently used syntaxes.
    3. Manual Import: Import specific syntaxes from highlight.js/lib/languages/xxx (e.g., 'highlight.js/lib/languages/wasm').

    Example of using all or common with createLowlight():

    import { createLowlight, all, common } from 'lowlight'
    
    // Use all syntaxes
    const lowlightAll = createLowlight(all)
    
    // Use common syntaxes
    const lowlightCommon = createLowlight(common)
  6. Serialize lowlight hast trees to HTML

    main

    Since lowlight returns a hast (Hypertext Abstract Syntax Tree), you can use hast-util-to-html to convert the tree into a standard HTML string.

    import {common, createLowlight} from 'lowlight'
    import {toHtml} from 'hast-util-to-html'
    
    const lowlight = createLowlight(common)
    const tree = lowlight.highlight('js', '"use strict";')
    
    console.log(toHtml(tree))
    // Yields: <span class="hljs-meta">"use strict"</span>;
    import {common, createLowlight} from 'lowlight'
    import {toHtml} from 'hast-util-to-html'
    
    const lowlight = createLowlight(common)
    
    const tree = lowlight.highlight('js', '"use strict";')
    
    console.log(toHtml(tree))
  7. Convert lowlight hast trees to JSX (React, Preact, etc.)

    main

    You can transform the hast tree returned by lowlight into nodes for any JSX-compatible framework (React, Preact, Solid, Svelte, Vue) using hast-util-to-jsx-runtime.

    import {toJsxRuntime} from 'hast-util-to-jsx-runtime'
    // @ts-expect-error: react types don’t type these.
    import {Fragment, jsx, jsxs} from 'react/jsx-runtime'
    import {common, createLowlight} from 'lowlight'
    
    const lowlight = createLowlight(common)
    const tree = lowlight.highlight('js', '"use strict";')
    
    console.log(toJsxRuntime(tree, {Fragment, jsx, jsxs}))
    import {toJsxRuntime} from 'hast-util-to-jsx-runtime'
    // @ts-expect-error: react types don’t type these.
    import {Fragment, jsx, jsxs} from 'react/jsx-runtime'
    import {common, createLowlight} from 'lowlight'
    
    const lowlight = createLowlight(common)
    
    const tree = lowlight.highlight('js', '"use strict";')
    
    console.log(toJsxRuntime(tree, {Fragment, jsx, jsxs}))
  8. Create a lowlight instance with createLowlight()

    main

    Use createLowlight([grammars]) to instantiate a new lowlight instance. You can pass an optional map of grammars to include upon creation.

    Commonly, you will pass the common identifier (which contains 37 common grammars) to get a ready-to-use instance.

    import {common, createLowlight} from 'lowlight'
    
    const lowlight = createLowlight(common)
  9. Auto-detect language with lowlight.highlightAuto()

    main

    Highlight code by automatically guessing the programming language.

    Parameters:

    • value (string): The code to highlight.
    • options (AutoOptions, optional): Configuration object.

    Returns: A Root (hast) tree. The tree's data field contains:

    • language (string): The detected programming language name.
    • relevance (number): A score indicating how sure lowlight is that the code matches the language.
    import {common, createLowlight} from 'lowlight'
    
    const lowlight = createLowlight(common)
    
    const tree = lowlight.highlightAuto('"hello, " + name + "!"')
    console.log(tree)
    // Yields: {type: 'root', children: [Array], data: {language: 'arduino', relevance: 2}}
  10. Register new languages with lowlight.register()

    main

    Add new grammars to an existing lowlight instance.

    Signatures:

    • register(name, grammar)
    • register(grammars)

    Parameters:

    • name (string): The programming language name.
    • grammar (LanguageFn): The highlight.js grammar.
    • grammars (Record<string, LanguageFn>, optional): A map of grammars to register.

    Example:

    import {createLowlight} from 'lowlight'
    import xml from 'highlight.js/lib/languages/xml'
    
    const lowlight = createLowlight()
    lowlight.register({xml})
    
    // Now you can highlight using 'xml' or its alias 'html'
    lowlight.highlight('html', '<em>Emphasis</em>')
    import {createLowlight} from 'lowlight'
    import xml from 'highlight.js/lib/languages/xml'
    
    const lowlight = createLowlight()
    lowlight.register({xml})
    
    lowlight.highlight('html', '<em>Emphasis</em>')
  11. Register aliases with lowlight.registerAlias()

    main

    Map one or more aliases to a registered programming language.

    Signatures:

    • registerAlias(aliases)
    • registerAlias(name, alias)

    Parameters:

    • aliases (Record<string, Array<string> | string>): A map of language names to one or more aliases.
    • name (string): The primary language name.
    • alias (Array<string> | string): One or more aliases for that language.

    Example:

    import {createLowlight} from 'lowlight'
    import markdown from 'highlight.js/lib/languages/markdown'
    
    const lowlight = createLowlight()
    lowlight.register({markdown})
    
    // Register multiple aliases for markdown
    lowlight.registerAlias({markdown: ['mdown', 'mkdn', 'mdwn', 'ron']})
    
    // This now works instead of throwing an error
    lowlight.highlight('mdown', '<em>Emphasis</em>')
    import {createLowlight} from 'lowlight'
    import markdown from 'highlight.js/lib/languages/markdown'
    
    const lowlight = createLowlight()
    lowlight.register({markdown})
    lowlight.registerAlias({markdown: ['mdown', 'mkdn', 'mdwn', 'ron']})
    lowlight.highlight('mdown', '<em>Emphasis</em>')
  12. Check registered languages with lowlight.registered()

    main

    Check whether a specific language name or alias is currently registered in the lowlight instance.

    Parameters:

    • aliasOrlanguage (string): The name or alias to check.

    Returns: boolean indicating if it is registered.

    import {createLowlight} from 'lowlight'
    import javascript from 'highlight.js/lib/languages/javascript'
    
    const lowlight = createLowlight({javascript})
    
    console.log(lowlight.registered('funkyscript')) // => false
    
    lowlight.registerAlias({javascript: 'funkyscript'})
    console.log(lowlight.registered('funkyscript')) // => true