mrkeyoor.com_
Wed 23 Sept 00:37 UTC
npmUtilsupdated 22 Sept 2026

@chevrotain/regexp-to-ast review

`@chevrotain/regexp-to-ast` 13.2.0 turns a slash-delimited JavaScript-style regular expression into the AST used by Chevrotain's lexer analysis. The result records alternatives, groups, assertions, character sets, numeric backreferences, quantifiers, flags, and source offsets; a base visitor walks those nodes. Our install also showed why this is a specialist package: it is a 148 KB ESM-only module whose CommonJS entry fails, and its accepted regex dialect omits several newer ECMAScript features.

Verdict

`@chevrotain/regexp-to-ast` 13.2.0 installed in 1.3 seconds and bundled to 2.9 KB gzipped in our sandbox, but `require()` failed and modern regex constructs are absent. Install it for Chevrotain AST compatibility; choose `@eslint-community/regexpp` for general ECMAScript regex tooling.

We installed it

Lab card: what happened when we installed @chevrotain/regexp-to-astScreenshot of @chevrotain/regexp-to-ast documentation
Install✓ · 1.3s1 package on disk · 1 MB
Import½ESM import works · require() fails · ESM package with exports map
Browser2.9 KBgzipped (10.6 KB minified), bundled with esbuild
TypesTypeScript types bundled
Known vulns00 critical · 0 high · 0 moderate · 0 low (npm audit)

Answers from our run

Does @chevrotain/regexp-to-ast install cleanly?

Yes. In a fresh container with an empty cache, npm install @chevrotain/regexp-to-ast finished in 1 seconds, leaving 1 package and 1 MB on disk. npm audit reported no known vulnerabilities.

How much does @chevrotain/regexp-to-ast add to a browser bundle?

2.9 KB gzipped (10.6 KB minified) when the whole package is bundled for the browser with esbuild. Importing only part of it is usually smaller.

Does @chevrotain/regexp-to-ast work with both ESM and CommonJS?

ESM only. import '@chevrotain/regexp-to-ast' worked, require('@chevrotain/regexp-to-ast') failed in our run, so CommonJS projects need a dynamic import or a build step.

Does @chevrotain/regexp-to-ast include TypeScript types?

Yes, type declarations ship inside the package, so no @types install is needed.

@chevrotain/regexp-to-ast or @eslint-community/regexpp: which should you use?

@eslint-community/regexpp: Use it when current ECMAScript regex parsing and validation matter more than matching Chevrotain's private tree shape. @chevrotain/regexp-to-ast 13.2.0 installed in 1.3 seconds and bundled to 2.9 KB gzipped in our sandbox, but require() failed and modern regex constructs are absent.

When should you not use @chevrotain/regexp-to-ast?

Your tool must understand current ECMAScript regex syntax. Version 13.2.0 does not model the d, s, or v flags, named captures, named backreferences, Unicode property escapes, or Unicode set operations.

API stability3/5Version 13.2.0 exports 2 main classes, `RegExpParser` and `BaseRegExpVisitor`, and the bundled declarations spell out every current node interface. That small surface is easy to inspect. There is no independent compatibility promise, though, and consumers commonly switch on AST node kinds. Adding the missing ECMAScript constructs could therefore require downstream code changes even if the parser entry point stays the same.
Docs2/5The package includes a detailed declaration file and the repository tests demonstrate supported groups, sets, assertions, flags, quantifiers, locations, and visitor hooks. It does not include its own README, input-format example, limitations table, or error reference. Chevrotain's main documentation covers the parser toolkit, so a direct user of this 148 KB subpackage must read types, tests, and source to learn its actual contract.
Maintenance5/5Release 13.2.0 reached npm on August 1, 2026, and GitHub shows the Chevrotain monorepo was pushed on August 25, 2026. The repository is unarchived and has 29 open issues and pull requests in GitHub's combined counter. Tests and declarations live beside the source, while coordinated monorepo releases keep this package aligned with the lexer code that consumes its AST.
Ecosystem3/5The npm endpoint counted 4,912,599 downloads in the latest completed week, and the Chevrotain repository has 2,797 stars. Much of that package traffic is likely transitive because the AST parser supports Chevrotain's lexer internals. Direct adopters get no plugin catalog or standalone examples, and the tree is Chevrotain-specific rather than a shared ESTree-style regex format.

Use it if

  • You are extending Chevrotain lexer analysis and must consume the exact regex tree that the parent project expects.
  • Your inputs stay within numbered captures, classic sets, lookarounds, quantifiers, backreferences, and the `gimuy` flag set.
  • A dependency-free parser with source offsets and a recursive visitor is enough, and you can treat the declarations and tests as the API reference.
Skip it if

Setup reality

We installed @chevrotain/regexp-to-ast 13.2.0 in 1.3 seconds on Node 22 Bookworm. The clean install left 1 package and 1 MB on disk. The published package is 148 KB unpacked, declares 0 direct and 0 peer dependencies, bundles TypeScript declarations, and produced 0 npm audit findings. Our browser build measured 10.6 KB minified and 2.9 KB gzipped.

Module loading is the first hard boundary. This package has type: module and an exports map with an import condition only. ESM import worked under Node 22.23.2, while require() failed. Migrate the caller to ESM or choose another parser; a compatibility wrapper cannot make Node resolve a CommonJS target that the package does not publish.

pattern() takes text shaped like '/[a-z]+/i', not a RegExp instance and not '[a-z]+'. Locations are offsets into that complete input. Character nodes store numeric UTF-16 values, ranges use {from, to}, and an open quantifier uses Infinity. Convert that value before JSON serialization because JSON writes non-finite numbers as null. Parse errors arrive as synchronous exceptions rather than a list of recoverable diagnostics.

Version 13.2.0 recognizes 5 flags: g, i, m, u, and y. Its node declarations do not cover named groups, property escapes, dotAll, indices, or Unicode Sets. The base visitor descends after each specialized hook, so override visitChildren() when traversal must stop at a node. Pin the package if stored data depends on exact node shapes; releases follow the larger Chevrotain monorepo and there is no separate AST compatibility policy.

Patterns

Parse a complete regex literal parse-regex-literal

import { RegExpParser } from '@chevrotain/regexp-to-ast';

const parser = new RegExpParser();
const ast = parser.pattern('/^[a-z]+$/i');
console.log(ast.type, ast.flags.ignoreCase);

`pattern()` requires slash delimiters and trailing flags in the string. Version 13.2.0 does not accept a `RegExp` object or bare `.source` value.

Enumerate top-level branches inspect-alternatives

const ast = parser.pattern('/cat|dog|fox/');
const alternatives = ast.value.value;
console.log(alternatives.length); // 3

A Pattern contains a Disjunction, whose value is the Alternative array. Groups and lookarounds add nested Disjunction nodes.

Recover text from node offsets read-source-locations

const input = '/ab+c/';
const ast = parser.pattern(input);
const first = ast.value.value[0].value[0];
console.log(input.slice(first.loc.begin, first.loc.end)); // a

The 0-based offsets refer to the full slash-delimited string, including the opening delimiter, rather than `RegExp.source`.

Collect literal character values visit-every-character

import { BaseRegExpVisitor } from '@chevrotain/regexp-to-ast';
import type { Character } from '@chevrotain/regexp-to-ast';

class CharacterCollector extends BaseRegExpVisitor {
  values: number[] = [];
  visitCharacter(node: Character) { this.values.push(node.value); }
}

const visitor = new CharacterCollector();
visitor.visit(parser.pattern('/abc/'));
console.log(visitor.values.map(String.fromCharCode));

Each Character node holds a numeric UTF-16 code unit. The base visitor continues into children after it calls a specialized hook.

Report members of a character set inspect-character-ranges

import type { Set } from '@chevrotain/regexp-to-ast';

class SetReporter extends BaseRegExpVisitor {
  visitSet(node: Set) {
    console.log({ complement: node.complement, entries: node.value });
  }
}
new SetReporter().visit(parser.pattern('/[^a-z0-9]/'));

Ranges use `{from, to}` and single entries are numbers. Escapes such as `\d` are expanded into entries rather than retained as source tokens.

Read repetition limits and greediness inspect-quantifiers

import type { Quantifier } from '@chevrotain/regexp-to-ast';

class QuantifierReporter extends BaseRegExpVisitor {
  visitQuantifier(node: Quantifier) {
    console.log(node.atLeast, node.atMost, node.greedy);
  }
}
new QuantifierReporter().visit(parser.pattern('/a+?b{2,}/'));

An unlimited `atMost` is `Infinity`. Map it to a string or sentinel before JSON serialization, which otherwise turns it into `null`.

Count lookaround assertions find-lookarounds

import type { Assertion } from '@chevrotain/regexp-to-ast';

class LookaroundCounter extends BaseRegExpVisitor {
  count = 0;
  visitLookahead(_node: Assertion) { this.count += 1; }
  visitNegativeLookahead(_node: Assertion) { this.count += 1; }
  visitLookbehind(_node: Assertion) { this.count += 1; }
  visitNegativeLookbehind(_node: Assertion) { this.count += 1; }
}

const visitor = new LookaroundCounter();
visitor.visit(parser.pattern('/(?<=a)b(?!c)/'));
console.log(visitor.count); // 2

Each lookaround owns a nested Disjunction. Version 13.2.0 handles these 4 assertion kinds but does not parse named captures.

List numbered capture indexes inspect-capturing-groups

import type { Group } from '@chevrotain/regexp-to-ast';

class GroupCollector extends BaseRegExpVisitor {
  groups: number[] = [];
  visitGroup(node: Group) {
    if (node.capturing && node.idx !== undefined) this.groups.push(node.idx);
  }
}
const visitor = new GroupCollector();
visitor.visit(parser.pattern('/(a)(?:b)(c)/'));
console.log(visitor.groups); // [1, 2]

Capturing groups receive numeric indexes. A noncapturing group has `capturing: false` and no `idx`; named capture fields do not exist.

Limit input to the supported flags validate-supported-flags

function parseSupported(input: string) {
  if (!/^\/(?:\\.|[^/])*\/[gimuy]*$/.test(input)) {
    throw new Error('Expected a simple /pattern/gimuy literal');
  }
  return parser.pattern(input);
}

The guard deliberately accepts only 5 flags and does not solve every escaped-slash case. The parser rejects `d`, `s`, and `v`.

Convert a thrown parse failure handle-parse-error

try {
  const ast = parser.pattern(candidate);
  analyze(ast);
} catch (error) {
  const message = error instanceof Error ? error.message : String(error);
  console.error({ candidate, message });
}

The parser throws synchronously at the first invalid construct. It does not return error codes, recover an AST, or collect several diagnostics.

Alternatives

PackageRegistryPick it when
@eslint-community/regexppnpmUse it when current ECMAScript regex parsing and validation matter more than matching Chevrotain's private tree shape.
regexp-treenpmUse it for parsing, traversal, transformation, optimization, and printing in one toolkit.
regexppnpmUse it only when an older ESLint integration already depends on its established AST format.
chevrotainnpmUse the parent package when you are building a lexer or parser rather than inspecting regex syntax directly.

More utils guides

lru-cache · ajv · type-fest · p-limit · find-up · js-yaml · the whole shelf →

How this guide is made: grounded in the library's documentation, release notes, changelog, and issue history, on a fixed rubric — not a hands-on install of every release. The 50 most-downloaded entries are additionally install-verified in clean containers. Corrections: contact the desk.