master bcde34baa17d cached
13 files
35.7 KB
9.4k tokens
18 symbols
1 requests
Download .txt
Repository: devongovett/tree-sitter-highlight
Branch: master
Commit: bcde34baa17d
Files: 13
Total size: 35.7 KB

Directory structure:
gitextract_mngzxg9r/

├── .cargo/
│   └── config.toml
├── .github/
│   └── workflows/
│       └── tag-release.yml
├── .gitignore
├── Cargo.toml
├── LICENSE
├── README.md
├── bench.js
├── build.rs
├── index.d.ts
├── index.js
├── package.json
└── src/
    ├── highlight_names.rs
    └── lib.rs

================================================
FILE CONTENTS
================================================

================================================
FILE: .cargo/config.toml
================================================
[target.'cfg(target_env = "gnu")']
rustflags = ["-C", "link-args=-Wl,-z,nodelete"]

[target.arm-unknown-linux-gnueabihf]
linker = "arm-linux-gnueabihf-gcc"

[target.armv7-unknown-linux-gnueabihf]
linker = "arm-linux-gnueabihf-gcc"

[target.aarch64-unknown-linux-gnu]
linker = "aarch64-linux-gnu-gcc"

[target.aarch64-unknown-linux-musl]
linker = "aarch64-linux-musl-gcc"


================================================
FILE: .github/workflows/tag-release.yml
================================================
name: tag-release
on:
  release:
    types: [published]
  workflow_dispatch:
jobs:
  build-windows:
    name: windows
    runs-on: windows-latest
    steps:
      - uses: actions/checkout@v1
      - name: Install Rust
        uses: actions-rs/toolchain@v1
        with:
          toolchain: stable
          profile: minimal
          override: true
      - uses: bahmutov/npm-install@v1.1.0
      - name: Build native packages
        run: yarn build-release
      - name: Upload artifacts
        uses: actions/upload-artifact@v4
        with:
          name: bindings-windows
          path: ./*.node
      - name: Smoke test
        run: node -e "require('./')"

  build-linux-gnu-x64:
    name: linux-gnu-x64
    runs-on: ubuntu-latest
    container:
      image: node:20
    steps:
      - uses: actions/checkout@v1
      - name: Install Rust
        uses: actions-rs/toolchain@v1
        with:
          toolchain: stable
          profile: minimal
          override: true
      - uses: bahmutov/npm-install@v1.1.0
      - name: Build native packages
        run: yarn build-release
        env:
          CFLAGS: -std=c99
      - name: Strip debug symbols # https://github.com/rust-lang/rust/issues/46034
        run: strip ./*.node
      - name: Upload artifacts
        uses: actions/upload-artifact@v4
        with:
          name: bindings-linux-gnu-x64
          path: ./*.node
      - name: debug
        run: ls -l ./*.node
      - name: Smoke test
        run: node -e 'require("./")'

  build-linux-gnu-arm:
    strategy:
      fail-fast: false
      matrix:
        include:
          - target: arm-unknown-linux-gnueabihf
            arch: armhf
            strip: arm-linux-gnueabihf-strip
          - target: aarch64-unknown-linux-gnu
            arch: arm64
            strip: aarch64-linux-gnu-strip
    name: ${{ matrix.target }}
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v1
      - name: Install Rust
        uses: actions-rs/toolchain@v1
        with:
          toolchain: stable
          profile: minimal
          override: true
          target: ${{ matrix.target }}
      - name: Install cross compile toolchains
        run: |
          sudo apt-get update
          sudo apt-get install gcc-arm-linux-gnueabihf gcc-aarch64-linux-gnu g++-aarch64-linux-gnu -y
      - uses: bahmutov/npm-install@v1.1.0
      - name: Build native packages
        run: yarn build-release --target ${{ matrix.target }}
      - name: Strip debug symbols # https://github.com/rust-lang/rust/issues/46034
        run: ${{ matrix.strip }} ./*.node
      - name: Upload artifacts
        uses: actions/upload-artifact@v4
        with:
          name: bindings-${{ matrix.target }}
          path: ./*.node
      - name: debug
        run: ls -l ./*.node
      - name: Configure binfmt-support
        run: docker run --rm --privileged multiarch/qemu-user-static:register --reset

  build-linux-musl:
    strategy:
      fail-fast: false
      matrix:
        include:
          - target: x86_64-unknown-linux-musl
            strip: strip
          - target: aarch64-unknown-linux-musl
            strip: aarch64-linux-musl-strip
    name: ${{ matrix.target }}
    runs-on: ubuntu-latest
    container:
      image: node:20-alpine
    steps:
      - uses: actions/checkout@v1
      - name: Install build tools
        run: apk add --no-cache python3 make gcc g++ musl-dev curl tar
      - name: Install Rust
        uses: actions-rs/toolchain@v1
        with:
          toolchain: stable
          profile: minimal
          override: true
          target: ${{ matrix.target }}
      - name: Install cross compile toolchains
        if: ${{ matrix.target == 'aarch64-unknown-linux-musl' }}
        run: |
          curl -L -O https://github.com/devongovett/linux-musl-cross/releases/download/v1/aarch64-linux-musl-cross.tgz
          tar -xzf aarch64-linux-musl-cross.tgz
          cp -R aarch64-linux-musl-cross/* /usr
      - uses: bahmutov/npm-install@v1.1.0
      - name: Build native packages
        run: yarn build-release --target ${{ matrix.target }}
      - name: Strip debug symbols # https://github.com/rust-lang/rust/issues/46034
        run: ${{ matrix.strip }} ./*.node
      - name: Upload artifacts
        uses: actions/upload-artifact@v4
        with:
          name: bindings-${{ matrix.target }}
          path: ./*.node
      - name: debug
        run: ls -l ./*.node
      - name: Smoke test
        if: ${{ matrix.target == 'x86_64-unknown-linux-musl' }}
        run: node -e 'require("./")'

  build-macos:
    strategy:
      fail-fast: false
      matrix:
        include:
          - name: aarch64-apple-darwin
            target: aarch64-apple-darwin
          - name: x86_64-apple-darwin
            target: x86_64-apple-darwin
    name: ${{ matrix.name }}
    runs-on: macos-latest
    steps:
      - uses: actions/checkout@v1
      - name: Install Rust
        uses: actions-rs/toolchain@v1
        with:
          toolchain: stable
          profile: minimal
          override: true
          target: ${{ matrix.target }}
      - uses: bahmutov/npm-install@v1.1.0
      - name: Build native packages
        run: |
          sudo rm -Rf /Library/Developer/CommandLineTools/SDKs/*;
          export CC=$(xcrun -f clang);
          export CXX=$(xcrun -f clang++);
          SYSROOT=$(xcrun --sdk macosx --show-sdk-path);
          export CFLAGS="-isysroot $SYSROOT -isystem $SYSROOT";
          export MACOSX_DEPLOYMENT_TARGET="10.9";
          yarn build-release --target ${{ matrix.target }}
      - name: Strip debug symbols
        run: strip -x ./*.node
      - name: Upload artifacts
        uses: actions/upload-artifact@v4
        with:
          name: bindings-${{ matrix.target }}
          path: ./*.node
      - name: debug
        run: ls -l ./*.node

  build-and-release:
    runs-on: ubuntu-latest
    name: Build and release the tagged version
    needs:
      - build-windows
      - build-linux-musl
      - build-linux-gnu-arm
      - build-macos
    steps:
      - uses: actions/checkout@v1
      - uses: bahmutov/npm-install@v1.1.0
      - name: Download artifacts
        uses: actions/download-artifact@v4
        with:
          path: artifacts
      - name: Move artifacts
        run: mv artifacts/*/*.node .
      - name: Debug
        run: ls -l ./*.node
      - run: echo //registry.npmjs.org/:_authToken=${NPM_TOKEN} > .npmrc
        env:
          NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
      - run: npm publish


================================================
FILE: .gitignore
================================================
/target
node_modules
Cargo.lock
*.node


================================================
FILE: Cargo.toml
================================================
[package]
name = "node-tree-sitter-highlight"
version = "0.1.0"
edition = "2021"

[lib]
crate-type = ["cdylib"]


[dependencies]
napi = "2"
napi-derive = "2"
lazy_static = "1.4"
tree-sitter-highlight = "0.26.3"
tree-sitter-javascript = "0.25.0"
tree-sitter-typescript = "0.23.2"
tree-sitter-jsdoc = "0.25.0"
tree-sitter-json = "0.24.8"
tree-sitter-css = "0.25.0"
tree-sitter-regex = "0.25.0"
tree-sitter-yaml = "0.7.2"
tree-sitter-html = "0.23.2"
tree-sitter-c = "0.24.1"
tree-sitter-bash = "0.25.1"
tree-sitter-rust = "0.24.0"

[build-dependencies]
napi-build = { version = "1" }
tree-sitter = "0.26.3"
tree-sitter-highlight = "0.26.3"
tree-sitter-javascript = "0.25.0"
tree-sitter-typescript = "0.23.2"
tree-sitter-jsdoc = "0.25.0"
tree-sitter-json = "0.24.8"
tree-sitter-css = "0.25.0"
tree-sitter-regex = "0.25.0"
tree-sitter-yaml = "0.7.2"
tree-sitter-html = "0.23.2"
tree-sitter-c = "0.24.1"
tree-sitter-bash = "0.25.1"
tree-sitter-rust = "0.24.0"

[profile.release]
opt-level = 3
lto = true


================================================
FILE: LICENSE
================================================
MIT License

Copyright (c) 2021 Devon Govett

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.


================================================
FILE: README.md
================================================
# tree-sitter-highlight

A syntax highlighter for Node.js powered by [Tree Sitter](https://github.com/tree-sitter/tree-sitter). Written in Rust.

## Usage

The following will output HTML:

```js
const treeSitter = require('tree-sitter-highlight');

treeSitter.highlight('const foo = "hi";', treeSitter.Language.JS);
// => '<span class="source">...</span>'
```

You can also output a [HAST](https://github.com/syntax-tree/hast) AST, which is useful for integrating with Markdown or MDX processors (e.g. Remark).

```js
treeSitter.highlightHast('const foo = "hi";', treeSitter.Language.JS);
// => {type: 'element', children: [...]}
```

## Themes

The output HTML will contain CSS class names for various tokens. These will depend on the language, but there are several common names used across languages. Here is a basic example theme:

```css
.keyword {
  color: purple;
}

.function {
  color: blue;
}

.type {
  color: pink;
}

.string {
  color: green;
}

.number {
  color: brown;
}

.operator {
  color: gray;
}

.comment {
  color: lightgray;
}
```

Inspect the generated output HTML and design your CSS accordingly.

## License

MIT


================================================
FILE: bench.js
================================================
const {Benchmark} = require("tiny-benchy");
const ts = require('./');

let input = `
function Example() {
  let alertDismiss = (close) => {
    close();
    alert('Dialog dismissed.');
  };
  return (
    <DialogTrigger isDismissable>
      <ActionButton>Info</ActionButton>
      {(close) => (
        <Dialog onDismiss={() => alertDismiss(close)}>
          <Heading>Version Info</Heading>
          <Divider />
          <Content>
            <Text>Version 1.0.0, Copyright 2020</Text>
          </Content>
        </Dialog>
      )}
    </DialogTrigger>
  );
}
`;

let suite = new Benchmark({iterations: 50});

suite.add('html', () => {
  ts.highlight(input, ts.Language.JSX);
});

suite.add('hast', () => {
  ts.highlightHast(input, ts.Language.JSX);
});

suite.run();


================================================
FILE: build.rs
================================================
use tree_sitter::Language;

extern crate napi_build;

fn main() {
    let mut queries = String::new();
    queries.push_str(tree_sitter_javascript::HIGHLIGHT_QUERY);
    queries.push_str(tree_sitter_javascript::JSX_HIGHLIGHT_QUERY);

    let mut highlight_names = Vec::new();
    add_highlight_names(
        tree_sitter_javascript::LANGUAGE.into(),
        &queries,
        &mut highlight_names,
    );

    add_highlight_names(
        tree_sitter_typescript::LANGUAGE_TSX.into(),
        tree_sitter_typescript::HIGHLIGHTS_QUERY,
        &mut highlight_names,
    );
    add_highlight_names(
        tree_sitter_css::LANGUAGE.into(),
        tree_sitter_css::HIGHLIGHTS_QUERY,
        &mut highlight_names,
    );
    add_highlight_names(
        tree_sitter_regex::LANGUAGE.into(),
        tree_sitter_regex::HIGHLIGHTS_QUERY,
        &mut highlight_names,
    );
    add_highlight_names(
        tree_sitter_jsdoc::LANGUAGE.into(),
        tree_sitter_jsdoc::HIGHLIGHTS_QUERY,
        &mut highlight_names,
    );
    add_highlight_names(
        tree_sitter_json::LANGUAGE.into(),
        tree_sitter_json::HIGHLIGHTS_QUERY,
        &mut highlight_names,
    );
    add_highlight_names(
        tree_sitter_yaml::LANGUAGE.into(),
        tree_sitter_yaml::HIGHLIGHTS_QUERY,
        &mut highlight_names,
    );
    add_highlight_names(
        tree_sitter_html::LANGUAGE.into(),
        tree_sitter_html::HIGHLIGHTS_QUERY,
        &mut highlight_names,
    );
    add_highlight_names(
        tree_sitter_c::LANGUAGE.into(),
        tree_sitter_c::HIGHLIGHT_QUERY,
        &mut highlight_names,
    );
    add_highlight_names(
        tree_sitter_bash::LANGUAGE.into(),
        tree_sitter_bash::HIGHLIGHT_QUERY,
        &mut highlight_names,
    );
    add_highlight_names(
        tree_sitter_rust::LANGUAGE.into(),
        tree_sitter_rust::HIGHLIGHTS_QUERY,
        &mut highlight_names,
    );

    highlight_names.sort();

    let html_attrs: Vec<String> = highlight_names
        .iter()
        .map(|s| format!("class=\"{}\"", s.replace('.', " ")))
        .collect();

    let class_names: Vec<String> = highlight_names
        .iter()
        .map(|s| s.replace('.', " "))
        .collect();

    std::fs::write(
        "src/highlight_names.rs",
        format!(
            "pub const HIGHLIGHT_NAMES: &[&str] = &{:#?};\n\npub const HTML_ATTRS: &[&str] = &{:#?};\n\npub const CLASS_NAMES: &[&str] = &{:#?};\n",
            highlight_names,
            html_attrs,
            class_names
        ),
    )
    .expect("write error");

    napi_build::setup();
}

fn add_highlight_names(lang: Language, source: &str, highlights: &mut Vec<String>) {
    let query = tree_sitter::Query::new(&lang, source).unwrap();
    for capture in query.capture_names() {
        if !highlights.iter().any(|h| h == capture) {
            highlights.push(capture.to_string());
        }
    }
}


================================================
FILE: index.d.ts
================================================
/* tslint:disable */
/* eslint-disable */

/* auto-generated by NAPI-RS */

export const enum Language {
  JS = 0,
  JSX = 1,
  TS = 2,
  TSX = 3,
  JSON = 4,
  YAML = 5,
  CSS = 6,
  HTML = 7,
  Regex = 8,
  JsDoc = 9,
  C = 10,
  Bash = 11,
  Rust = 12
}
export declare function highlight(code: string, language: Language): string
export interface HastProperties {
  className: string
}
export interface HastNode {
  type: string
  tagName: string
  properties: HastProperties
  children: Array<HastNode | HastTextNode>
}
export interface HastTextNode {
  type: string
  value: string
}
export declare function highlightHast(code: string, language: Language): HastNode


================================================
FILE: index.js
================================================
/* tslint:disable */
/* eslint-disable */
/* prettier-ignore */

/* auto-generated by NAPI-RS */

const { existsSync, readFileSync } = require('fs')
const { join } = require('path')

const { platform, arch } = process

let nativeBinding = null
let localFileExisted = false
let loadError = null

function isMusl() {
  // For Node 10
  if (!process.report || typeof process.report.getReport !== 'function') {
    try {
      const lddPath = require('child_process').execSync('which ldd').toString().trim()
      return readFileSync(lddPath, 'utf8').includes('musl')
    } catch (e) {
      return true
    }
  } else {
    const { glibcVersionRuntime } = process.report.getReport().header
    return !glibcVersionRuntime
  }
}

switch (platform) {
  case 'android':
    switch (arch) {
      case 'arm64':
        localFileExisted = existsSync(join(__dirname, 'tree-sitter-highlight.android-arm64.node'))
        try {
          if (localFileExisted) {
            nativeBinding = require('./tree-sitter-highlight.android-arm64.node')
          } else {
            nativeBinding = require('tree-sitter-highlight-android-arm64')
          }
        } catch (e) {
          loadError = e
        }
        break
      case 'arm':
        localFileExisted = existsSync(join(__dirname, 'tree-sitter-highlight.android-arm-eabi.node'))
        try {
          if (localFileExisted) {
            nativeBinding = require('./tree-sitter-highlight.android-arm-eabi.node')
          } else {
            nativeBinding = require('tree-sitter-highlight-android-arm-eabi')
          }
        } catch (e) {
          loadError = e
        }
        break
      default:
        throw new Error(`Unsupported architecture on Android ${arch}`)
    }
    break
  case 'win32':
    switch (arch) {
      case 'x64':
        localFileExisted = existsSync(
          join(__dirname, 'tree-sitter-highlight.win32-x64-msvc.node')
        )
        try {
          if (localFileExisted) {
            nativeBinding = require('./tree-sitter-highlight.win32-x64-msvc.node')
          } else {
            nativeBinding = require('tree-sitter-highlight-win32-x64-msvc')
          }
        } catch (e) {
          loadError = e
        }
        break
      case 'ia32':
        localFileExisted = existsSync(
          join(__dirname, 'tree-sitter-highlight.win32-ia32-msvc.node')
        )
        try {
          if (localFileExisted) {
            nativeBinding = require('./tree-sitter-highlight.win32-ia32-msvc.node')
          } else {
            nativeBinding = require('tree-sitter-highlight-win32-ia32-msvc')
          }
        } catch (e) {
          loadError = e
        }
        break
      case 'arm64':
        localFileExisted = existsSync(
          join(__dirname, 'tree-sitter-highlight.win32-arm64-msvc.node')
        )
        try {
          if (localFileExisted) {
            nativeBinding = require('./tree-sitter-highlight.win32-arm64-msvc.node')
          } else {
            nativeBinding = require('tree-sitter-highlight-win32-arm64-msvc')
          }
        } catch (e) {
          loadError = e
        }
        break
      default:
        throw new Error(`Unsupported architecture on Windows: ${arch}`)
    }
    break
  case 'darwin':
    localFileExisted = existsSync(join(__dirname, 'tree-sitter-highlight.darwin-universal.node'))
    try {
      if (localFileExisted) {
        nativeBinding = require('./tree-sitter-highlight.darwin-universal.node')
      } else {
        nativeBinding = require('tree-sitter-highlight-darwin-universal')
      }
      break
    } catch {}
    switch (arch) {
      case 'x64':
        localFileExisted = existsSync(join(__dirname, 'tree-sitter-highlight.darwin-x64.node'))
        try {
          if (localFileExisted) {
            nativeBinding = require('./tree-sitter-highlight.darwin-x64.node')
          } else {
            nativeBinding = require('tree-sitter-highlight-darwin-x64')
          }
        } catch (e) {
          loadError = e
        }
        break
      case 'arm64':
        localFileExisted = existsSync(
          join(__dirname, 'tree-sitter-highlight.darwin-arm64.node')
        )
        try {
          if (localFileExisted) {
            nativeBinding = require('./tree-sitter-highlight.darwin-arm64.node')
          } else {
            nativeBinding = require('tree-sitter-highlight-darwin-arm64')
          }
        } catch (e) {
          loadError = e
        }
        break
      default:
        throw new Error(`Unsupported architecture on macOS: ${arch}`)
    }
    break
  case 'freebsd':
    if (arch !== 'x64') {
      throw new Error(`Unsupported architecture on FreeBSD: ${arch}`)
    }
    localFileExisted = existsSync(join(__dirname, 'tree-sitter-highlight.freebsd-x64.node'))
    try {
      if (localFileExisted) {
        nativeBinding = require('./tree-sitter-highlight.freebsd-x64.node')
      } else {
        nativeBinding = require('tree-sitter-highlight-freebsd-x64')
      }
    } catch (e) {
      loadError = e
    }
    break
  case 'linux':
    switch (arch) {
      case 'x64':
        if (isMusl()) {
          localFileExisted = existsSync(
            join(__dirname, 'tree-sitter-highlight.linux-x64-musl.node')
          )
          try {
            if (localFileExisted) {
              nativeBinding = require('./tree-sitter-highlight.linux-x64-musl.node')
            } else {
              nativeBinding = require('tree-sitter-highlight-linux-x64-musl')
            }
          } catch (e) {
            loadError = e
          }
        } else {
          localFileExisted = existsSync(
            join(__dirname, 'tree-sitter-highlight.linux-x64-gnu.node')
          )
          try {
            if (localFileExisted) {
              nativeBinding = require('./tree-sitter-highlight.linux-x64-gnu.node')
            } else {
              nativeBinding = require('tree-sitter-highlight-linux-x64-gnu')
            }
          } catch (e) {
            loadError = e
          }
        }
        break
      case 'arm64':
        if (isMusl()) {
          localFileExisted = existsSync(
            join(__dirname, 'tree-sitter-highlight.linux-arm64-musl.node')
          )
          try {
            if (localFileExisted) {
              nativeBinding = require('./tree-sitter-highlight.linux-arm64-musl.node')
            } else {
              nativeBinding = require('tree-sitter-highlight-linux-arm64-musl')
            }
          } catch (e) {
            loadError = e
          }
        } else {
          localFileExisted = existsSync(
            join(__dirname, 'tree-sitter-highlight.linux-arm64-gnu.node')
          )
          try {
            if (localFileExisted) {
              nativeBinding = require('./tree-sitter-highlight.linux-arm64-gnu.node')
            } else {
              nativeBinding = require('tree-sitter-highlight-linux-arm64-gnu')
            }
          } catch (e) {
            loadError = e
          }
        }
        break
      case 'arm':
        if (isMusl()) {
          localFileExisted = existsSync(
            join(__dirname, 'tree-sitter-highlight.linux-arm-musleabihf.node')
          )
          try {
            if (localFileExisted) {
              nativeBinding = require('./tree-sitter-highlight.linux-arm-musleabihf.node')
            } else {
              nativeBinding = require('tree-sitter-highlight-linux-arm-musleabihf')
            }
          } catch (e) {
            loadError = e
          }
        } else {
          localFileExisted = existsSync(
            join(__dirname, 'tree-sitter-highlight.linux-arm-gnueabihf.node')
          )
          try {
            if (localFileExisted) {
              nativeBinding = require('./tree-sitter-highlight.linux-arm-gnueabihf.node')
            } else {
              nativeBinding = require('tree-sitter-highlight-linux-arm-gnueabihf')
            }
          } catch (e) {
            loadError = e
          }
        }
        break
      case 'riscv64':
        if (isMusl()) {
          localFileExisted = existsSync(
            join(__dirname, 'tree-sitter-highlight.linux-riscv64-musl.node')
          )
          try {
            if (localFileExisted) {
              nativeBinding = require('./tree-sitter-highlight.linux-riscv64-musl.node')
            } else {
              nativeBinding = require('tree-sitter-highlight-linux-riscv64-musl')
            }
          } catch (e) {
            loadError = e
          }
        } else {
          localFileExisted = existsSync(
            join(__dirname, 'tree-sitter-highlight.linux-riscv64-gnu.node')
          )
          try {
            if (localFileExisted) {
              nativeBinding = require('./tree-sitter-highlight.linux-riscv64-gnu.node')
            } else {
              nativeBinding = require('tree-sitter-highlight-linux-riscv64-gnu')
            }
          } catch (e) {
            loadError = e
          }
        }
        break
      case 's390x':
        localFileExisted = existsSync(
          join(__dirname, 'tree-sitter-highlight.linux-s390x-gnu.node')
        )
        try {
          if (localFileExisted) {
            nativeBinding = require('./tree-sitter-highlight.linux-s390x-gnu.node')
          } else {
            nativeBinding = require('tree-sitter-highlight-linux-s390x-gnu')
          }
        } catch (e) {
          loadError = e
        }
        break
      default:
        throw new Error(`Unsupported architecture on Linux: ${arch}`)
    }
    break
  default:
    throw new Error(`Unsupported OS: ${platform}, architecture: ${arch}`)
}

if (!nativeBinding) {
  if (loadError) {
    throw loadError
  }
  throw new Error(`Failed to load native binding`)
}

const { Language, highlight, highlightHast } = nativeBinding

module.exports.Language = Language
module.exports.highlight = highlight
module.exports.highlightHast = highlightHast


================================================
FILE: package.json
================================================
{
  "name": "tree-sitter-highlight",
  "version": "1.1.2",
  "description": "A syntax highlighter for Node powered by Tree Sitter. Written in Rust.",
  "repository": "https://github.com/devongovett/tree-sitter-highlight",
  "author": "Devon Govett <devongovett@gmail.com>",
  "license": "MIT",
  "napi": {
    "name": "tree-sitter-highlight"
  },
  "files": [
    "*.node",
    "index.js",
    "index.d.ts"
  ],
  "scripts": {
    "build": "napi build --platform",
    "build-release": "napi build --platform --release"
  },
  "devDependencies": {
    "@napi-rs/cli": "^2.0.0",
    "tiny-benchy": "^2.1.0"
  }
}


================================================
FILE: src/highlight_names.rs
================================================
pub const HIGHLIGHT_NAMES: &[&str] = &[
    "attribute",
    "boolean",
    "character.special",
    "comment",
    "comment.documentation",
    "constant",
    "constant.builtin",
    "constant.character",
    "constructor",
    "delimiter",
    "embedded",
    "escape",
    "function",
    "function.builtin",
    "function.macro",
    "function.method",
    "function.special",
    "keyword",
    "label",
    "number",
    "operator",
    "property",
    "punctuation.bracket",
    "punctuation.delimiter",
    "punctuation.special",
    "string",
    "string.special",
    "string.special.key",
    "tag",
    "tag.error",
    "type",
    "type.builtin",
    "variable",
    "variable.builtin",
    "variable.parameter",
];

pub const HTML_ATTRS: &[&str] = &[
    "class=\"attribute\"",
    "class=\"boolean\"",
    "class=\"character special\"",
    "class=\"comment\"",
    "class=\"comment documentation\"",
    "class=\"constant\"",
    "class=\"constant builtin\"",
    "class=\"constant character\"",
    "class=\"constructor\"",
    "class=\"delimiter\"",
    "class=\"embedded\"",
    "class=\"escape\"",
    "class=\"function\"",
    "class=\"function builtin\"",
    "class=\"function macro\"",
    "class=\"function method\"",
    "class=\"function special\"",
    "class=\"keyword\"",
    "class=\"label\"",
    "class=\"number\"",
    "class=\"operator\"",
    "class=\"property\"",
    "class=\"punctuation bracket\"",
    "class=\"punctuation delimiter\"",
    "class=\"punctuation special\"",
    "class=\"string\"",
    "class=\"string special\"",
    "class=\"string special key\"",
    "class=\"tag\"",
    "class=\"tag error\"",
    "class=\"type\"",
    "class=\"type builtin\"",
    "class=\"variable\"",
    "class=\"variable builtin\"",
    "class=\"variable parameter\"",
];

pub const CLASS_NAMES: &[&str] = &[
    "attribute",
    "boolean",
    "character special",
    "comment",
    "comment documentation",
    "constant",
    "constant builtin",
    "constant character",
    "constructor",
    "delimiter",
    "embedded",
    "escape",
    "function",
    "function builtin",
    "function macro",
    "function method",
    "function special",
    "keyword",
    "label",
    "number",
    "operator",
    "property",
    "punctuation bracket",
    "punctuation delimiter",
    "punctuation special",
    "string",
    "string special",
    "string special key",
    "tag",
    "tag error",
    "type",
    "type builtin",
    "variable",
    "variable builtin",
    "variable parameter",
];


================================================
FILE: src/lib.rs
================================================
mod highlight_names;

use highlight_names::{CLASS_NAMES, HIGHLIGHT_NAMES, HTML_ATTRS};
use lazy_static::lazy_static;
use napi::bindgen_prelude::*;
use napi_derive::napi;
use tree_sitter_highlight::{HighlightConfiguration, HighlightEvent, Highlighter, HtmlRenderer};

#[napi]
pub enum Language {
    JS,
    JSX,
    TS,
    TSX,
    JSON,
    YAML,
    CSS,
    HTML,
    Regex,
    JsDoc,
    C,
    Bash,
    Rust,
}

macro_rules! language {
    ($mod: ident, $name: literal, $highlights: ident) => {{
        let mut config =
            HighlightConfiguration::new($mod::LANGUAGE.into(), $name, $mod::$highlights, "", "")
                .unwrap();
        config.configure(HIGHLIGHT_NAMES);
        config
    }};
    ($mod: ident, $name: literal, $highlights: ident, $injections: ident) => {{
        let mut config = HighlightConfiguration::new(
            $mod::LANGUAGE.into(),
            $name,
            $mod::$highlights,
            $mod::$injections,
            "",
        )
        .unwrap();
        config.configure(HIGHLIGHT_NAMES);
        config
    }};
}

lazy_static! {
    static ref JS_CONFIG: HighlightConfiguration = {
        let mut config = HighlightConfiguration::new(
            tree_sitter_javascript::LANGUAGE.into(),
            "javascript",
            tree_sitter_javascript::HIGHLIGHT_QUERY,
            tree_sitter_javascript::INJECTIONS_QUERY,
            tree_sitter_javascript::LOCALS_QUERY,
        )
        .unwrap();
        config.configure(HIGHLIGHT_NAMES);
        config
    };
    static ref JSX_CONFIG: HighlightConfiguration = {
        let mut highlights = tree_sitter_javascript::JSX_HIGHLIGHT_QUERY.to_owned();
        highlights.push_str(tree_sitter_javascript::HIGHLIGHT_QUERY);

        let mut config = HighlightConfiguration::new(
            tree_sitter_javascript::LANGUAGE.into(),
            "jsx",
            &highlights,
            tree_sitter_javascript::INJECTIONS_QUERY,
            tree_sitter_javascript::LOCALS_QUERY,
        )
        .unwrap();

        config.configure(HIGHLIGHT_NAMES);
        config
    };
    static ref TS_CONFIG: HighlightConfiguration = {
        let mut highlights = tree_sitter_typescript::HIGHLIGHTS_QUERY.to_owned();
        highlights.push_str(tree_sitter_javascript::HIGHLIGHT_QUERY);

        let mut locals = tree_sitter_typescript::LOCALS_QUERY.to_owned();
        locals.push_str(tree_sitter_javascript::LOCALS_QUERY);

        let mut config = HighlightConfiguration::new(
            tree_sitter_typescript::LANGUAGE_TYPESCRIPT.into(),
            "typescript",
            &highlights,
            tree_sitter_javascript::INJECTIONS_QUERY,
            &locals,
        )
        .unwrap();

        config.configure(HIGHLIGHT_NAMES);
        config
    };
    static ref TSX_CONFIG: HighlightConfiguration = {
        let mut highlights = tree_sitter_javascript::JSX_HIGHLIGHT_QUERY.to_owned();
        highlights.push_str(tree_sitter_typescript::HIGHLIGHTS_QUERY);
        highlights.push_str(tree_sitter_javascript::HIGHLIGHT_QUERY);

        let mut locals = tree_sitter_typescript::LOCALS_QUERY.to_owned();
        locals.push_str(tree_sitter_javascript::LOCALS_QUERY);

        let mut config = HighlightConfiguration::new(
            tree_sitter_typescript::LANGUAGE_TSX.into(),
            "tsx",
            &highlights,
            tree_sitter_javascript::INJECTIONS_QUERY,
            &locals,
        )
        .unwrap();

        config.configure(HIGHLIGHT_NAMES);
        config
    };
    static ref JSDOC_CONFIG: HighlightConfiguration =
        language!(tree_sitter_jsdoc, "jsdoc", HIGHLIGHTS_QUERY);
    static ref JSON_CONFIG: HighlightConfiguration =
        language!(tree_sitter_json, "json", HIGHLIGHTS_QUERY);
    static ref YAML_CONFIG: HighlightConfiguration =
        language!(tree_sitter_yaml, "yaml", HIGHLIGHTS_QUERY);
    static ref CSS_CONFIG: HighlightConfiguration =
        language!(tree_sitter_css, "css", HIGHLIGHTS_QUERY);
    static ref HTML_CONFIG: HighlightConfiguration =
        language!(tree_sitter_html, "html", INJECTIONS_QUERY);
    static ref REGEX_CONFIG: HighlightConfiguration =
        language!(tree_sitter_regex, "regex", HIGHLIGHTS_QUERY);
    static ref C_CONFIG: HighlightConfiguration = language!(tree_sitter_c, "c", HIGHLIGHT_QUERY);
    static ref BASH_CONFIG: HighlightConfiguration =
        language!(tree_sitter_bash, "bash", HIGHLIGHT_QUERY);
    static ref RUST_CONFIG: HighlightConfiguration =
        language!(tree_sitter_rust, "rust", HIGHLIGHTS_QUERY);
}

impl Language {
    fn highlight_config(&self) -> &'static HighlightConfiguration {
        match self {
            Language::JS => &*JS_CONFIG,
            Language::JSX => &*JSX_CONFIG,
            Language::TS => &*TS_CONFIG,
            Language::TSX => &*TSX_CONFIG,
            Language::JSON => &*JSON_CONFIG,
            Language::YAML => &*YAML_CONFIG,
            Language::CSS => &*CSS_CONFIG,
            Language::HTML => &*HTML_CONFIG,
            Language::Regex => &*REGEX_CONFIG,
            Language::JsDoc => &*JSDOC_CONFIG,
            Language::C => &*C_CONFIG,
            Language::Bash => &*BASH_CONFIG,
            Language::Rust => &*RUST_CONFIG,
        }
    }

    fn from_name(name: &str) -> Option<Language> {
        Some(match name {
            "js" | "javascript" => Language::JS,
            "jsx" => Language::JSX,
            "ts" | "typescript" => Language::TS,
            "tsx" => Language::TSX,
            "json" => Language::JSON,
            "yaml" => Language::YAML,
            "css" => Language::CSS,
            "html" => Language::HTML,
            "regex" => Language::Regex,
            "jsdoc" => Language::JsDoc,
            "c" => Language::C,
            "bash" => Language::Bash,
            "sh" => Language::Bash,
            "rust" => Language::Rust,
            "rs" => Language::Rust,
            _ => return None,
        })
    }
}

#[napi]
pub fn highlight(code: String, language: Language) -> String {
    let config = language.highlight_config();
    let mut highlighter = Highlighter::new();
    let highlights = highlighter
        .highlight(&config, code.as_bytes(), None, |lang| {
            Language::from_name(lang).map(|l| l.highlight_config())
        })
        .unwrap();

    let mut renderer = HtmlRenderer::new();
    renderer
        .render(highlights, code.as_bytes(), &|highlight, res| {
            res.extend_from_slice(HTML_ATTRS[highlight.0].as_bytes())
        })
        .unwrap();
    unsafe { String::from_utf8_unchecked(renderer.html) }
}

#[derive(Debug)]
#[napi(object)]
pub struct HastProperties {
    pub class_name: String,
}

#[derive(Debug)]
#[napi(object)]
pub struct HastNode {
    #[napi(js_name = "type")]
    pub kind: String,
    pub tag_name: String,
    pub properties: HastProperties,
    pub children: Vec<Either<HastNode, HastTextNode>>,
}

#[derive(Debug)]
#[napi(object)]
pub struct HastTextNode {
    #[napi(js_name = "type")]
    pub kind: String,
    pub value: String,
}

#[napi]
pub fn highlight_hast(code: String, language: Language) -> HastNode {
    let config = language.highlight_config();
    let mut highlighter = Highlighter::new();
    let highlights = highlighter
        .highlight(&config, code.as_bytes(), None, |lang| {
            Language::from_name(lang).map(|l| l.highlight_config())
        })
        .unwrap();

    let mut stack = Vec::new();
    stack.push(HastNode {
        kind: "element".into(),
        tag_name: "span".into(),
        properties: HastProperties {
            class_name: "source".into(),
        },
        children: Vec::new(),
    });

    for event in highlights {
        match event.unwrap() {
            HighlightEvent::HighlightStart(highlight) => {
                let node = HastNode {
                    kind: "element".into(),
                    tag_name: "span".into(),
                    properties: HastProperties {
                        class_name: CLASS_NAMES[highlight.0].to_owned(),
                    },
                    children: Vec::new(),
                };
                stack.push(node);
            }
            HighlightEvent::Source { start, end } => {
                let slice = &code[start..end];
                let parent = stack.last_mut().unwrap();
                if let Some(Either::B(text_node)) = parent.children.last_mut() {
                    text_node.value.push_str(slice);
                } else {
                    let text_node = HastTextNode {
                        kind: "text".into(),
                        value: slice.into(),
                    };
                    parent.children.push(Either::B(text_node));
                }
            }
            HighlightEvent::HighlightEnd => {
                let node = stack.pop().unwrap();
                let parent = stack.last_mut().unwrap();
                parent.children.push(Either::A(node));
            }
        }
    }

    stack.pop().unwrap()
}
Download .txt
gitextract_mngzxg9r/

├── .cargo/
│   └── config.toml
├── .github/
│   └── workflows/
│       └── tag-release.yml
├── .gitignore
├── Cargo.toml
├── LICENSE
├── README.md
├── bench.js
├── build.rs
├── index.d.ts
├── index.js
├── package.json
└── src/
    ├── highlight_names.rs
    └── lib.rs
Download .txt
SYMBOL INDEX (18 symbols across 5 files)

FILE: build.rs
  function main (line 5) | fn main() {
  function add_highlight_names (line 94) | fn add_highlight_names(lang: Language, source: &str, highlights: &mut Ve...

FILE: index.d.ts
  type Language (line 6) | const enum Language {
  type HastProperties (line 22) | interface HastProperties {
  type HastNode (line 25) | interface HastNode {
  type HastTextNode (line 31) | interface HastTextNode {

FILE: index.js
  function isMusl (line 16) | function isMusl() {

FILE: src/highlight_names.rs
  constant HIGHLIGHT_NAMES (line 1) | pub const HIGHLIGHT_NAMES: &[&str] = &[
  constant HTML_ATTRS (line 39) | pub const HTML_ATTRS: &[&str] = &[
  constant CLASS_NAMES (line 77) | pub const CLASS_NAMES: &[&str] = &[

FILE: src/lib.rs
  type Language (line 10) | pub enum Language {
    method highlight_config (line 136) | fn highlight_config(&self) -> &'static HighlightConfiguration {
    method from_name (line 154) | fn from_name(name: &str) -> Option<Language> {
  function highlight (line 177) | pub fn highlight(code: String, language: Language) -> String {
  type HastProperties (line 197) | pub struct HastProperties {
  type HastNode (line 203) | pub struct HastNode {
  type HastTextNode (line 213) | pub struct HastTextNode {
  function highlight_hast (line 220) | pub fn highlight_hast(code: String, language: Language) -> HastNode {
Condensed preview — 13 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (39K chars).
[
  {
    "path": ".cargo/config.toml",
    "chars": 371,
    "preview": "[target.'cfg(target_env = \"gnu\")']\nrustflags = [\"-C\", \"link-args=-Wl,-z,nodelete\"]\n\n[target.arm-unknown-linux-gnueabihf]"
  },
  {
    "path": ".github/workflows/tag-release.yml",
    "chars": 6508,
    "preview": "name: tag-release\non:\n  release:\n    types: [published]\n  workflow_dispatch:\njobs:\n  build-windows:\n    name: windows\n  "
  },
  {
    "path": ".gitignore",
    "chars": 39,
    "preview": "/target\nnode_modules\nCargo.lock\n*.node\n"
  },
  {
    "path": "Cargo.toml",
    "chars": 998,
    "preview": "[package]\nname = \"node-tree-sitter-highlight\"\nversion = \"0.1.0\"\nedition = \"2021\"\n\n[lib]\ncrate-type = [\"cdylib\"]\n\n\n[depen"
  },
  {
    "path": "LICENSE",
    "chars": 1069,
    "preview": "MIT License\n\nCopyright (c) 2021 Devon Govett\n\nPermission is hereby granted, free of charge, to any person obtaining a co"
  },
  {
    "path": "README.md",
    "chars": 1140,
    "preview": "# tree-sitter-highlight\n\nA syntax highlighter for Node.js powered by [Tree Sitter](https://github.com/tree-sitter/tree-s"
  },
  {
    "path": "bench.js",
    "chars": 774,
    "preview": "const {Benchmark} = require(\"tiny-benchy\");\nconst ts = require('./');\n\nlet input = `\nfunction Example() {\n  let alertDis"
  },
  {
    "path": "build.rs",
    "chars": 2898,
    "preview": "use tree_sitter::Language;\n\nextern crate napi_build;\n\nfn main() {\n    let mut queries = String::new();\n    queries.push_"
  },
  {
    "path": "index.d.ts",
    "chars": 671,
    "preview": "/* tslint:disable */\n/* eslint-disable */\n\n/* auto-generated by NAPI-RS */\n\nexport const enum Language {\n  JS = 0,\n  JSX"
  },
  {
    "path": "index.js",
    "chars": 9920,
    "preview": "/* tslint:disable */\n/* eslint-disable */\n/* prettier-ignore */\n\n/* auto-generated by NAPI-RS */\n\nconst { existsSync, re"
  },
  {
    "path": "package.json",
    "chars": 612,
    "preview": "{\n  \"name\": \"tree-sitter-highlight\",\n  \"version\": \"1.1.2\",\n  \"description\": \"A syntax highlighter for Node powered by Tr"
  },
  {
    "path": "src/highlight_names.rs",
    "chars": 2533,
    "preview": "pub const HIGHLIGHT_NAMES: &[&str] = &[\n    \"attribute\",\n    \"boolean\",\n    \"character.special\",\n    \"comment\",\n    \"com"
  },
  {
    "path": "src/lib.rs",
    "chars": 9000,
    "preview": "mod highlight_names;\n\nuse highlight_names::{CLASS_NAMES, HIGHLIGHT_NAMES, HTML_ATTRS};\nuse lazy_static::lazy_static;\nuse"
  }
]

About this extraction

This page contains the full source code of the devongovett/tree-sitter-highlight GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 13 files (35.7 KB), approximately 9.4k tokens, and a symbol index with 18 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.

Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.

Copied to clipboard!