mrkeyoor.com_
Tue 22 Sept 18:51 UTC
npmCLI & Toolingupdated 22 Sept 2026

nearley review

nearley 2.20.1 is an Earley parser generator for JavaScript. You write a grammar in a .ne file, compile it to JavaScript with nearleyc, feed text to a Parser, and inspect every valid parse. Earley parsing accepts left recursion and ambiguous context-free grammars that narrower generators may reject. The package also provides commands for parser tests, random valid-input generation, and railroad diagrams, while Moo supplies the recommended token layer. The current npm version has not changed since December 2020, and the repository's last push was in November 2024, so there is no recent release behavior to add.

Verdict

nearley 2.20.1 installed in 1.3 seconds, used 1 MB on disk, and bundled to 2.9 KB gzipped in our sandbox with 0 audit findings. Choose it for left-recursive or intentionally ambiguous grammars; deterministic new parsers should compare the more active Peggy and Chevrotain projects.

We installed it

Lab card: what happened when we installed nearleyScreenshot of nearley documentation
Install✓ · 1.3s7 packages on disk · 1 MB
ImportESM import works · require() works · CommonJS package
Browser2.9 KBgzipped (7.8 KB minified), bundled with esbuild
Typesno TypeScript types found
Known vulns00 critical · 0 high · 0 moderate · 0 low (npm audit)

Answers from our run

Does nearley install cleanly?

Yes. In a fresh container with an empty cache, npm install nearley finished in 1 seconds, leaving 7 packages and 1 MB on disk. npm audit reported no known vulnerabilities.

How much does nearley add to a browser bundle?

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

Does nearley work with both ESM and CommonJS?

Yes. Both import 'nearley' and require('nearley') worked in Node 22 in our run. The package is published as CommonJS.

Does nearley include TypeScript types?

No type declarations were found in our install, so TypeScript users need their own declarations.

nearley or peggy: which should you use?

peggy: Use it for an actively maintained PEG generator with ordered, deterministic choices. nearley 2.20.1 installed in 1.3 seconds, used 1 MB on disk, and bundled to 2.9 KB gzipped in our sandbox with 0 audit findings.

When should you not use nearley?

A new parser needs active releases and prompt fixes. npm remains on 2.20.1 from 2020, while GitHub lists 199 open issues and pull requests.

API stability4/5For years, the workflow has remained: compile a .ne file, call Grammar.fromCompiled, construct Parser, feed input, and inspect results. Postprocessors, lexer attachment, includes, and the four command names are also settled. The lack of releases reduces upgrade churn, yet it leaves current ESM and TypeScript packaging unresolved. Treat generated-module imports and parser-result cardinality as contracts in your own tests.
Docs4/5nearley.js.org explains grammar syntax, postprocessors, EBNF modifiers, parser feeds, ambiguity, Moo integration, TypeScript preprocessing, test commands, unparse, and railroad output. It says plainly that reject can be slow and a syntax error cannot be repaired by another feed. Examples and packaging guidance reflect an older Node ecosystem, so developers must supply the modern build and module details themselves.
Maintenance2/5npm 2.20.1 was published in December 2020, and GitHub records the last repository push on November 14, 2024. The repository is unarchived and has 3,742 stars, but its 199 open issues and pull requests sit against a long release gap. The mature implementation may keep working on tested runtimes. Teams adopting it now should expect to own compatibility diagnosis and local patches when newer tooling exposes a problem.
Ecosystem3/5npm recorded 7,848,112 downloads in the latest completed week. The package includes compiler, test, unparse, and railroad commands, and the documentation recommends Moo for tokenization. Generated parsers can run in Node or a browser. The surrounding editor and build integrations are older, no TypeScript declarations ship in the package, and newer parser toolkits offer more current language-service and recovery features.

Use it if

  • Your grammar is left recursive or intentionally ambiguous, and receiving every valid parse is useful.
  • Input arrives in chunks and the application can continue feeding the same parser until a complete result exists.
  • A .ne grammar plus JavaScript postprocessors is easier for the team to review than a hand-written parser.
  • Random grammar expansion and railroad diagrams will help test or explain a small language or file format.
Skip it if

Setup reality

We installed nearley 2.20.1 in a clean Node 22 Bookworm container. npm finished in 1.3 seconds, left 7 packages on disk, and used 1 MB. The package declares 4 direct dependencies and no peer dependencies, with 140 KB unpacked. npm audit found no known vulnerabilities. It is CommonJS with no exports map; require and ESM import worked in our lab. No TypeScript declarations were found. Our browser bundle measured 7.8 KB minified and 2.9 KB gzipped.

Production use normally adds a grammar source, a nearleyc build command, and a generated JavaScript module. Decide whether the generated file is committed or rebuilt in every package and deployment job. A stale artifact is easy to ship when the .ne source changes without the compile step. Postprocessors shape nested grammar values into the AST and may execute arbitrary JavaScript, so grammar files are application code.

Parser.results can contain zero, one, or several values. Zero after the final input means the parse did not complete; several values reveal ambiguity. Always assert the intended cardinality instead of taking index zero. Repeated feed calls support chunked input, but a thrown syntax error ends useful work for that parser. Create a new Parser for another attempt.

Character rules are fine for small grammars. For a serious language, the docs recommend Moo tokens for speed and clearer errors. Install Moo separately, declare @lexer, and reference token names with percent syntax. Avoid reject as a normal semantic filter. Use nearley-unparse to generate accepted strings, then assert the produced AST and semantics in your test runner because valid syntax alone proves little.

Patterns

Generate a parser module compile-grammar

npx nearleyc src/expression.ne -o src/expression.js

Add this to the build or commit the generated artifact. The runtime does not compile the .ne file by itself.

Require one complete parse parse-once

const nearley = require('nearley')
const grammar = require('./expression.js')

const parser = new nearley.Parser(nearley.Grammar.fromCompiled(grammar))
parser.feed('2 + 3')
if (parser.results.length !== 1) {
  throw new Error(`expected one parse, got ${parser.results.length}`)
}
const ast = parser.results[0]

Zero results means incomplete or invalid final input. More than one result means the grammar is ambiguous for this text.

Shape values in a postprocessor build-ast

@{%
function add(data) {
  return { type: 'add', left: data[0], right: data[2] }
}
%}

expression -> number _ "+" _ number {% add %}
number -> [0-9]:+ {% d => Number(d[0].join('')) %}
_ -> [\s]:*

Postprocessors receive each production value in an array. Convert the generated nesting to a stable AST here.

Collect a comma-separated list repeat-rule

word -> [a-z]:+ {% d => d[0].join('') %}
words -> word ("," _ word):* {%
  d => [d[0], ...d[1].map((part) => part[2])]
%}
_ -> [\s]:*

EBNF repetition produces nested arrays. Flatten them before the structure leaves the grammar.

Parse chunked input feed-chunks

const parser = new nearley.Parser(nearley.Grammar.fromCompiled(grammar))
parser.feed('if (ready) {')
parser.feed('run()')
parser.feed('}')

if (parser.results.length === 1) console.log(parser.results[0])

Chunked feeds do not provide syntax recovery. Discard the parser after feed throws on an invalid token.

Attach a Moo lexer tokenize-with-moo

@{%
const moo = require('moo')
const lexer = moo.compile({
  ws: { match: /\s+/, lineBreaks: true },
  number: /0|[1-9][0-9]*/,
  plus: '+',
})
%}
@lexer lexer

sum -> %number %ws:? %plus %ws:? %number {%
  d => Number(d[0].value) + Number(d[4].value)
%}

Install Moo separately. Lexer tokens expose value, line, column, and offset information for errors and AST locations.

Reuse another grammar file include-rules

@include "./number.ne"

main -> number _ "items" {% d => ({ count: d[0] }) %}
_ -> [\s]:*

nearleyc expands includes at compile time. Keep rule names unique across included files.

Inspect a compiled grammar test-parser-cli

npx nearleyc src/expression.ne -o build/expression.js
npx nearley-test build/expression.js -i '2 + 3'

The command is useful for inspection. Keep expected ASTs and ambiguity checks in automated tests.

Produce random accepted strings generate-inputs

npx nearley-unparse -s expression build/expression.js -n 25

Generated input exercises grammar reachability. Parse it again and test the AST because accepted syntax may still have wrong semantics.

Write railroad diagrams draw-grammar

npx nearley-railroad src/expression.ne -o docs/expression-grammar.html

Regenerate the HTML whenever the grammar changes; it is documentation output rather than an executable parser.

Save a parser checkpoint save-parser-state

const checkpoint = parser.save()
parser.feed(candidate)

// Restore and try a different continuation.
parser.restore(checkpoint)
parser.feed(alternative)

A checkpoint supports controlled branching before an error. It does not repair a parser after invalid input has already been consumed.

Fail a test on several parses inspect-ambiguity

const parser = new nearley.Parser(nearley.Grammar.fromCompiled(grammar))
parser.feed(source)
expect(parser.results).toHaveLength(1)
expect(parser.results[0]).toEqual(expectedAst)

Cardinality assertions catch ambiguity that a results[0] shortcut would hide.

Alternatives

PackageRegistryPick it when
peggynpmUse it for an actively maintained PEG generator with ordered, deterministic choices.
chevrotainnpmUse it for a code-defined parser with explicit tokens, TypeScript tooling, and error recovery.
ohm-jsnpmUse it when grammar rules should stay separate from reusable semantic operations.

More cli & tooling guides

chalk · commander · typescript · esbuild · yargs · click · 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.