npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@adguard/rules-editor

v2.0.0

Published

User rules text editor based on Codemirror and AdGuard textmate highlight

Readme

AdGuard Rules Editor

A browser-based library for editing and tokenizing AdGuard filter rules. It provides a CodeMirror 6 text editor with TextMate syntax highlighting (via WebAssembly Oniguruma backed by vscode-textmate + vscode-oniguruma) and a WASM-backed tokenizer for custom rule rendering.

Installation

vscode-oniguruma and CodeMirror/Lezer packages are peer dependencies — your project must install them separately. vscode-oniguruma is required so the WASM binary is available in your bundle; the CodeMirror packages are required because the library returns a live EditorView instance. CodeMirror's @codemirror/state relies on instanceof checks for extensions and facets — if your bundler duplicates @codemirror/state (the library bundles one copy and your app another), these checks will fail. Externalizing the peer deps ensures a single shared copy.`

pnpm add @adguard/rules-editor vscode-oniguruma @codemirror/state @codemirror/view @codemirror/language @codemirror/commands @codemirror/search @lezer/highlight

Key Concepts

  • Editor — a CodeMirror 6 instance with adblock syntax highlighting (embedded JavaScript regions are scoped as source.js but use a minimal placeholder grammar to keep the bundle small), powered by WASM-based Oniguruma regex from vscode-oniguruma.
  • Tokenizer — splits a rule into highlighted segments using WASM; highest precision.
  • Token — an enum of token types aligned with the CodeMirror 6 / @lezer/highlight tag taxonomy (keyword, operator, string, comment, regexp, etc.).
  • inspectLine — returns per-token segments with full TextMate scope stacks for debugging and tests.

Quick Start

Editor

import { initEditor } from '@adguard/rules-editor';

// Let your bundler (rspack / Vite) emit the asset and compute the URL.
const wasm = new URL('vscode-oniguruma/release/onig.wasm', import.meta.url);

const textarea = document.getElementById('textarea');
const view = await initEditor(textarea, wasm, {
    hotkeys: { mode: 'mac' },
});
view.dispatch({ changes: { from: 0, insert: '||example.org^' } });

Theming

Tokens are highlighted using standard @lezer/highlight tags, so any CodeMirror 6 theme works out of the box. By default the editor applies CodeMirror's defaultHighlightStyle; pass your own theme (or HighlightStyle) via conf.extensions to override it:

import { oneDark } from '@codemirror/theme-one-dark';

const view = await initEditor(textarea, wasm, {
    hotkeys: { mode: 'mac' },
    extensions: [oneDark],
});

Highlighting strategy

By default the editor uses full TextMate highlighting backed by Oniguruma WASM. When you do not need syntax highlighting, choose highlight: 'none' — it never loads WASM, so the wasm argument can be undefined:

// No highlighting at all, no WASM:
const plain = await initEditor(textarea, undefined, {
    hotkeys: { mode: 'mac' },
    highlight: 'none',
});

initEditor still returns a Promise<EditorView> for every strategy, so existing await initEditor(...) call sites are unaffected.

Tokenizing a Rule

import { getTokenizer } from '@adguard/rules-editor';

// WASM-based (async init, highest precision)
const wasm = new URL('vscode-oniguruma/release/onig.wasm', import.meta.url);
const tokenize = await getTokenizer(wasm);
const tokens = tokenize('||example.org^$important');

Inspecting a Line (scope debugging)

import { inspectLine } from '@adguard/rules-editor';

const wasm = new URL('vscode-oniguruma/release/onig.wasm', import.meta.url);
const segments = await inspectLine(wasm, '||example.org^$important');
// segments: TokenSegment[] — each with text, startIndex, endIndex,
//            scopes (full TextMate scope stack), and token (resolved class)

API

initEditor

async function initEditor(
    element: HTMLTextAreaElement,
    wasm: WasmSource,
    conf: InitEditorConfig,
): Promise<EditorView>

| Parameter | Description | | --- | --- | | element | Textarea element to attach the editor to | | wasm | WASM source — URL/string (fetched), Response, ArrayBuffer, or a Promise/thunk of these. Required for highlight: 'full' (the default); pass undefined when using 'none' | | conf.hotkeys.mode | OS mode for hotkey mapping ('windows' or 'mac') | | conf.hotkeys.toggleRule | Callback for Ctrl/Cmd+/ (toggle rule breakpoint) | | conf.hotkeys.onSave | Callback for Ctrl/Cmd+S | | conf.hotkeys.markerColor | CSS color for the breakpoint marker | | conf.hotkeys.markerHTML | Custom innerHTML for the breakpoint marker | | conf.withBreakpoints | Enable breakpoint gutter | | conf.onChange | Called after each document change | | conf.extensions | Extra CodeMirror 6 extensions appended last | | conf.highlight | Highlight strategy: 'full' (WASM TextMate, default) or 'none' (no WASM) |

Returns a CodeMirror.EditorView instance. See the CodeMirror 6 docs for events and keymaps.

getTokenizer

async function getTokenizer(
    wasm: WasmSource,
): Promise<(rule: string) => RuleTokens>

| Parameter | Description | | --- | --- | | wasm | WASM source — URL/string (fetched), Response, ArrayBuffer, or a Promise/thunk of these |

Returns a function that accepts a rule string and returns RuleTokens ({ str: string, token: Token | null }[]).

inspectLine

async function inspectLine(
    wasm: WasmSource,
    line: string,
    scopeName?: string,
): Promise<TokenSegment[]>

| Parameter | Description | | --- | --- | | wasm | WASM source — URL/string (fetched), Response, ArrayBuffer, or a Promise/thunk of these | | line | The line of filter rule text to tokenize | | scopeName | Grammar scope; defaults to text.adblock |

Returns a contiguous, gap-free array of TokenSegment objects covering the input line. Each segment has text, startIndex, endIndex, scopes (full scope stack), and token (resolved class or null).

Rendering tokens to HTML (display-only)

For read-only views (e.g. a virtualized list of rule rows) you can render a token list to colorized HTML whose classes match the editor — without creating a CodeMirror editor per row. Set white-space: pre on the container to preserve spacing.

renderTokensToHtml

function renderTokensToHtml(
    tokens: RuleTokens,
    options?: RenderOptions,
): string

| Parameter | Description | | --- | --- | | tokens | Token list from getTokenizer | | options.highlightStyle | HighlightStyle or array; defaults to defaultHighlightStyle |

Returns an HTML string safe for innerHTML/dangerouslySetInnerHTML.

getHtmlRenderer

async function getHtmlRenderer(
    wasm: WasmSource,
    options?: RenderOptions,
): Promise<(rule: string, search?: SearchHighlightOptions) => string>

| Parameter | Description | | --- | --- | | wasm | WASM source — URL/string/Response/ArrayBuffer/Promise/thunk | | options.highlightStyle | Same as renderTokensToHtml |

Returns an async factory that initializes the grammar once, then returns a synchronous (rule, search?) => html function for full-precision (WASM) highlighting reusable across many rows.

The returned function accepts an optional search argument to highlight a search term within the rule:

interface SearchHighlightOptions {
    searchTerm?: string;     // plain-text, case-insensitive
    searchClassName?: string; // CSS class on each matched chunk
}

When searchTerm is a non-empty string, every case-insensitive occurrence — including matches that span multiple tokens — is wrapped in a <span> carrying searchClassName. Omitting search (or passing an empty term) leaves the output identical to plain rendering. Both the matched text and searchClassName are HTML-escaped.

const render = await getHtmlRenderer(wasm);
// Plain rendering — unchanged from previous versions:
const html = render('||example.org^');
// With search highlighting:
const highlighted = render('||example.org^', {
    searchTerm: 'example',
    searchClassName: 'search-hit',
});

mountHighlightStyle

function mountHighlightStyle(
    highlightStyle?: HighlightStyle,
    root?: Document | ShadowRoot,
): void

| Parameter | Description | | --- | --- | | highlightStyle | Style whose CSS to mount; defaults to defaultHighlightStyle | | root | Target document or shadow root; defaults to document (no-ops in non-browser envs) |

Mounts a HighlightStyle's CSS so emitted classes are colorized without an editor. Call once; repeated calls are idempotent.

RenderOptions

interface RenderOptions {
    highlightStyle?: HighlightStyle | HighlightStyle[];
}

Pass a custom HighlightStyle (e.g. oneDarkHighlightStyle) to match a custom editor theme.

Error Classes

| Class | Description | | --- | --- | | WasmLoadError | Thrown when the Oniguruma WASM binary fails to load | | GrammarNotFoundError | Thrown when a grammar scope has no registration |

Peer Dependencies

| Package | Version | | --- | --- | | vscode-oniguruma | ^2.0.1 | | @codemirror/commands | ^6.10.3 | | @codemirror/language | ^6.12.3 | | @codemirror/search | ^6.7.0 | | @codemirror/state | ^6.6.0 | | @codemirror/view | ^6.43.0 | | @lezer/highlight | ^1.2.3 |