Simple, fast, powerful parser toolkit for JavaScript using the Earley parsing algorithm
npx @tessl/cli install tessl/npm-nearley@2.20.0Nearley is a comprehensive JavaScript parsing toolkit that implements the Earley parsing algorithm, enabling developers to parse any context-free grammar including left-recursive ones that challenge other parser generators. It offers a powerful domain-specific language for grammar definition, an efficient streaming parser with comprehensive error handling and ambiguity resolution, and extensive tooling including railroad diagram generation, grammar testing, and fuzzing capabilities.
npm install nearleyconst nearley = require("nearley");
const { Parser, Grammar, Rule } = nearley;For ES6 modules:
import * as nearley from "nearley";
import { Parser, Grammar, Rule } from "nearley";const nearley = require("nearley");
// Use a pre-compiled grammar (generated with nearleyc)
const grammar = nearley.Grammar.fromCompiled(require("./my-grammar.js"));
// Create a parser instance
const parser = new nearley.Parser(grammar);
// Parse input text
try {
parser.feed("your input text here");
console.log("Parse results:", parser.results);
} catch (parseError) {
console.error("Parse error:", parseError.message);
}Nearley is built around several key components:
Parser class implementing the Earley parsing algorithm with streaming supportGrammar and Rule classes for representing compiled grammars and production rules.ne grammar files into executable JavaScriptStreamLexer and external lexers like mooMain parsing functionality using the Earley algorithm for parsing any context-free grammar. Supports streaming input, error recovery, and ambiguous grammars.
class Parser {
constructor(rules, start, options);
constructor(grammar, options);
feed(chunk: string): Parser;
save(): Column;
restore(column: Column): void;
finish(): any[];
}
static Parser.fail: object;Grammar representation and compilation system for working with context-free grammars and production rules.
class Grammar {
constructor(rules: Rule[], start?: string);
static fromCompiled(rules: object, start?: string): Grammar;
}
class Rule {
constructor(name: string, symbols: any[], postprocess?: Function);
toString(withCursorAt?: number): string;
}Node.js stream integration for parsing large inputs or continuous data streams.
class StreamWrapper extends Writable {
constructor(parser: Parser);
}Random text generation from grammars for testing, fuzzing, and example generation.
function Unparse(grammar: Grammar, start: string, depth?: number): string;Command-line tools for grammar compilation, testing, railroad diagram generation, and text generation.
nearleyc - Compile .ne grammar files to JavaScriptnearley-test - Test compiled grammars with inputnearley-railroad - Generate railroad diagrams from grammarsnearley-unparse - Generate random text from grammarsclass StreamLexer {
constructor();
reset(data: string, state?: object): void;
next(): {value: string} | undefined;
save(): {line: number, col: number};
formatError(token: object, message: string): string;
}Nearley includes several built-in grammar modules that can be included in your own grammars:
builtin/number.ne - Number parsing patterns (unsigned_int, int, decimal, percentage, jsonfloat)builtin/string.ne - String parsing patterns with escape sequencesbuiltin/whitespace.ne - Whitespace handling patternsbuiltin/postprocessors.ne - Common postprocessing functions (id, nuller, joiner, etc.)builtin/cow.ne - Simple example grammar for matching "MOO", "MOOO", etc.Usage in Grammar Files:
@include "builtin/number.ne"
@include "builtin/whitespace.ne"
# Your grammar rules can now use built-in rules
expr -> number _:* "+" _:* number {%
function(d) { return d[0] + d[4]; }
%}Importing in JavaScript:
// Built-in grammars are typically included at compile time
// For runtime access to compiled built-ins, they must be pre-compiled:
const numberGrammar = require("nearley/builtin/number.js"); // if compiledinterface ParserOptions {
keepHistory?: boolean;
lexer?: object;
}
interface State {
rule: Rule;
dot: number;
reference: number;
data: any[];
wantedBy: State[];
isComplete: boolean;
}
interface Column {
grammar: Grammar;
index: number;
states: State[];
wants: object;
scannable: State[];
completed: object;
}