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

@r1ck404/fast-acorn

v8.18.2

Published

Faster drop-in replacement for acorn 8.18: identical ASTs, errors and callbacks, 2.5-3x faster parsing, fast paths for acorn-jsx and parseFunctionBody overrides

Readme

@r1ck404/fast-acorn

Long unescaped string literals now scan their tail with a native regular expression after a 128-character prefix. Escapes, line terminators, error positions, tokens and callbacks retain the original path. Ordinary short literals keep the bounded scalar scan.

A faster drop-in replacement for [email protected]: the same exports, identical ASTs (keys, key order, values, Node / SourceLocation / Position objects and their sharing), identical errors (class, message, pos, loc, raisedAt) and callbacks, for every ecmaVersion (3 .. latest) and every option.

// package.json
"dependencies": {
  "acorn": "npm:@r1ck404/[email protected]",
  "acorn-jsx": "npm:@r1ck404/[email protected]"   // optional, see below
}

| operation | times faster than acorn 8.18 | |---|---| | parse 1.6KB .. 9MB | 2.5-3.2x | | parse with locations | 2.2-2.9x | | Parser.extend(acornJsx()) | 2.3-2.5x | | subclasses that only override parseFunctionBody | 2.0-2.6x | | parseExpressionAt | 3.2x | | tokenizer() | 2.2-2.6x | | other plugins (acorn's own parser code) | 1.5x (after a one-time ~5 ms load in Node) |

Times and inputs: benchmark results.

How

  • src/parser.mts: a parser that mirrors acorn function by function (same checks in the same order, same token-context rules, the same errors at the same points) on different machinery: integer token types with flag tables, an ASCII fast path in the tokenizer, one constructor per node type (monomorphic shapes, acorn's key order), set-backed scopes, lazily created token end positions. It handles everything acorn does: all ecmaVersions, sourceType script / module / commonjs, every option (onToken, onComment, onInsertedSemicolon, onTrailingComma, program, startLocation, preserveParens, ...), parseExpressionAt, tokenizer() and every error. acorn's regular expression validator is included (src/regexp.mjs, generated from acorn).
  • Parser.extend():
    • acorn-jsx runs on a native JSX mode when the class is the genuine acorn-jsx 5.3.2 plugin (recognised by its source text, structure and probe calls, which also give its options) or was made by @r1ck404/fast-acorn-jsx (registered by identity, so this also works in minified bundles, where the genuine plugin's source text no longer matches).

    • Subclasses that only override parseFunctionBody (e.g. Nodepod's topLevelParser, which skips function bodies) pass a whitelist analysis of their method's source and then run that method against a facade over the fast parser (src/override.mts). This works after minification too.

    • Empty subclasses of those behave like their parent.

    • Anything else (other plugins, subclasses with their own methods, new Parser(...), a patched Parser.prototype) runs acorn's own parser code, generic.cjs (generated from acorn), with the same tokTypes, TokenType, tokContexts, Node, Position, ... objects as the rest of the package. It is not part of the main module: Parser.prototype inherits acorn's methods from a prototype that receives them on first use. In Node that happens on demand, synchronously (a require that bundlers do not follow). In browsers and bundles, import it once:

      import "@r1ck404/fast-acorn/full";   // or "acorn/full" when installed as acorn

      Without it, such a parse throws an Error that says so.

  • index.mjs is src/ bundled into one minified module (build.mjs): importing it costs about what importing acorn does (one module; the node constructors and other tables are made by the first parse).

Differences from acorn

Each is pinned by a test (test/differences.mjs unless noted):

  • Unrecognised plugins, subclasses with methods of their own, new Parser(...), a patched Parser.prototype, a parseExpressionAt position that is not a number, and the genuine acorn-jsx after minification need @r1ck404/fast-acorn/full outside Node (see above; test/bundle.mjs).
  • Parser.prototype has no own methods (they are inherited, see above), and Parser has two symbol-keyed hooks, for @r1ck404/fast-acorn-jsx and /full.
  • A method put on Parser.prototype with Object.defineProperty before anything has read a method from Parser.prototype is not noticed; the fast parser keeps running. (Assignments, and defineProperty after such a read, switch to acorn's code exactly like acorn: test/plugins.mjs.)
  • The token types' and contexts' behaviour is built in: replacing tokTypes.x.updateContext or a TokContext's override affects only parses that run acorn's code.
  • tokenizer() returns an object with acorn's token API and state (getToken, iteration, next, nextToken, type, value, start, end, pos, curLine, lineStart, exprAllowed, context, ...; writable where acorn-loose writes them), an instanceof Parser, but not a whole parser: no scope stack, labels or parse methods.
  • Nesting too deep for the stack throws acorn's "Not enough stack space to parse input" in both, at a different depth.
  • Error stack traces show this package's functions.

Development

npm run build             # index.mjs from src/ (after node tools/ts-build.mjs)
npm test                  # quick: build check, API, options, corpus sample, versions, plugins
npm run test:full         # everything (incl. Nodepod's pnpm store), see package.json
npm run gen               # regenerate src/ident-data.mts, src/regexp.mjs,
                          # src/jsx-data.mts and generic.cjs from acorn / acorn-jsx

The JSX tests use verify/jsx-corpus (generate it with node verify/make-jsx-corpus.mjs).