Skip to content

Unified API (createParser)

createParser from @lanexio/parser wraps any grammar pack in a uniform, never-throwing parser handle. Use it when you want string inputs, incremental reparse, streaming, or the ability to swap grammars (including future WASM grammar packs) without changing call sites. If you only ever parse bytes with one grammar, calling parseHtml/parseMarkdown/etc. directly is equally correct.

Package: @lanexio/parser Layer: 4 (Host). Depends on @lanexio/parser-core and @lanexio/parser-wasm. Runtime: Universal.

import { createParser, LanexioParserError, LanexioParserErrorCode } from '@lanexio/parser';
import type { LanexioParser } from '@lanexio/parser';

Pass any grammar descriptor. Every grammar package exports one:

import { createParser } from '@lanexio/parser';
import { htmlGrammar } from '@lanexio/parser-grammar-html';
const parser = await createParser(htmlGrammar);
console.log(parser.grammar); // "@lanexio/parser-grammar-html"
console.log(parser.protocolVersion); // shared buffer protocol version (1)
Grammar descriptorPackage
htmlGrammar@lanexio/parser-grammar-html
markdownGrammar@lanexio/parser-grammar-markdown
jsonGrammar@lanexio/parser-grammar-json
yamlGrammar@lanexio/parser-grammar-yaml
cssGrammar@lanexio/parser-grammar-css
toyGrammar@lanexio/parser-wasm (demo grammar used in examples and tests)
type LanexioParser = {
readonly grammar: string; // stable npm package name of the loaded grammar
readonly protocolVersion: number; // frozen shared-buffer protocol version
readonly parse: (input: string | Uint8Array) => LexTree;
readonly reparse: (previousTree: LexTree, edit: LexEdit) => LexTree;
readonly createStream: () => LexParseStream;
};

Unlike the raw grammar functions (which take Uint8Array only), the handle’s parse accepts a string and UTF-8-encodes it for you:

const tree = parser.parse('<p>Hello <b>world</b></p>');
console.log(tree.nodeCount);

parse never throws — for any input, malformed or not, it returns a valid LexTree. If the underlying grammar ever violated that contract, the handle catches the exception and returns a single-node error tree instead.

reparse — apply an edit, get a fresh tree

Section titled “reparse — apply an edit, get a fresh tree”
const tree = parser.parse('<p>Hello</p>');
const edited = parser.reparse(tree, {
start: 3, // byte offset in the previous source
end: 8, // half-open: replaces bytes [3, 8)
replacement: new TextEncoder().encode('Goodbye'),
});

The result is guaranteed byte-identical to parse(applyEdit(tree.source, edit)). See Incremental Parsing for edit semantics and error behavior.

const stream = parser.createStream();
stream.push('<html><head>');
stream.push('<body>hello</body></html>');
stream.end();
for await (const tree of stream) {
console.log(tree.source.byteLength);
}

Each push yields one tree covering all bytes accumulated so far. See Streaming for the full contract.

Construction errors are loud; parse errors are data

Section titled “Construction errors are loud; parse errors are data”

createParser itself may throw — deliberately. A grammar that cannot load or that targets the wrong protocol version is a deployment problem, and deployment problems should fail loudly at startup:

import { createParser, LanexioParserError, LanexioParserErrorCode } from '@lanexio/parser';
import { htmlGrammar } from '@lanexio/parser-grammar-html';
let parser;
try {
parser = await createParser(htmlGrammar);
} catch (err) {
if (err instanceof LanexioParserError) {
// Stable machine-readable codes:
// LanexioParserErrorCode.GrammarLoadFailed — WASM bytes unreachable / instantiation failure
// LanexioParserErrorCode.ProtocolMismatch — grammar targets a different protocol version
console.error(err.code, err.message, err.cause);
}
throw err;
}
// From here on, nothing on the handle throws.
const tree = parser.parse(untrustedInput);
Error codeMeaning
grammar_load_failedThe grammar’s WASM source could not be resolved or instantiated. The original cause is attached as err.cause.
protocol_mismatchThe grammar (or its WASM bridge) reports a different shared-buffer protocol version than this host expects.

Pure-TypeScript grammars (all five shipped grammars) can only fail with protocol_mismatch; grammar_load_failed applies to WASM grammar packs.

createParser also accepts WASM-backed grammars conforming to the LanexioParserGrammar contract (a source to fetch plus an instantiate function). The bundled toyGrammar demonstrates the shape; see the parser-wasm reference for authoring details, including browser loading via fetch.

import { createParser, toyGrammar } from '@lanexio/parser';
const toy = await createParser(toyGrammar);
const tree = toy.parse('(a + b)');
ExportTypeDescription
createParser(grammar) => Promise<LanexioParser>Build a never-throwing handle from a pure or WASM grammar.
LanexioParsertypeThe handle shape (see above).
LanexioParserError / LanexioParserErrorCodeclass / const objectConstruction-time errors with stable codes.
createParseStream(grammar: string, parseFn) => LexParseStreamStandalone stream factory (re-exported from core).
applyEdit(source, edit) => Uint8ArrayPure edit application. Throws LexEditError on malformed ranges.
LexEditError / LexEditErrorCodeclass / const objectEdit validation errors (range_out_of_bounds, range_inverted).
toyParse(bytes: Uint8Array) => LexTreeThe toy demo grammar’s parse function (for examples and tests — not a real-format parser).
toyGrammar / TOY_GRAMMAR_NAMEgrammar / stringBundled WASM demo grammar.
defineLanexioParserGrammaridentity helperType-checked construction of WASM grammar descriptors.
LexTree, LexNode, LexCursor, PROTOCOL_VERSION, …re-exportsCore types so simple hosts need only this one dependency.