ECMAScript parser ecosystem including main parser, error-tolerant parser, and AST walker utilities
npx @tessl/cli install tessl/npm-acorn@8.12.0Acorn is a comprehensive ECMAScript parser ecosystem written entirely in JavaScript. It provides a fast, tiny JavaScript parser with a complete toolchain for parsing, analyzing, and walking ECMAScript (JavaScript) syntax trees. The ecosystem consists of three complementary packages that work together to provide robust JavaScript parsing capabilities.
npm install acornnpm install acorn-loosenpm install acorn-walkimport { parse, parseExpressionAt, tokenizer, Parser } from "acorn";For CommonJS:
const { parse, parseExpressionAt, tokenizer, Parser } = require("acorn");import { parse, LooseParser, isDummy } from "acorn-loose";import { simple, ancestor, recursive, full, findNodeAt, base } from "acorn-walk";import { parse } from "acorn";
import { simple } from "acorn-walk";
// Parse JavaScript code into AST
const code = "let x = 10; function foo() { return x + 1; }";
const ast = parse(code, { ecmaVersion: 2020 });
// Walk the AST to find function declarations
simple(ast, {
FunctionDeclaration(node) {
console.log(`Found function: ${node.id.name}`);
}
});
// For error-tolerant parsing with acorn-loose
import { parse as looseParse } from "acorn-loose";
const brokenCode = "let x = ; function incomplete() { // missing closing brace";
const looseAst = looseParse(brokenCode);Acorn is designed as a modular parser ecosystem with three main components:
acorn): Fast, standards-compliant ECMAScript parser with plugin supportacorn-loose): Error-tolerant parser for handling malformed JavaScript codeacorn-walk): Comprehensive tree traversal utilities for analyzing parsed codeFast, standards-compliant parsing of ECMAScript code with full ES2025 support and plugin extensibility.
function parse(input: string, options: Options): Program;
function parseExpressionAt(input: string, pos: number, options: Options): Expression;
function tokenizer(input: string, options: Options): {
getToken(): Token;
[Symbol.iterator](): Iterator<Token>;
};Fault-tolerant parsing that attempts to recover from syntax errors and produce usable ASTs from malformed code.
function parse(input: string, options: Options): Program;
const LooseParser: typeof Parser;
function isDummy(node: Node): boolean;Comprehensive tree traversal utilities with multiple algorithms for visiting, finding, and analyzing AST nodes.
function simple<TState>(
node: Node,
visitors: SimpleVisitors<TState>,
base?: RecursiveVisitors<TState>,
state?: TState
): void;
function findNodeAt<TState>(
node: Node,
start: number | undefined,
end?: number | undefined,
type?: FindPredicate | string,
base?: RecursiveVisitors<TState>,
state?: TState
): Found<TState> | undefined;Extensible parser architecture for adding custom syntax support and parser behaviors.
class Parser {
static extend(...plugins: ((BaseParser: typeof Parser) => typeof Parser)[]): typeof Parser;
}Plugins can extend the parser to support additional JavaScript dialects like JSX, TypeScript syntax, or experimental language features.
import { parse } from "acorn";
import { simple } from "acorn-walk";
const code = `
function calculateSum(a, b) {
return a + b;
}
const result = calculateSum(5, 3);
console.log(result);
`;
const ast = parse(code, { ecmaVersion: 2020 });
// Collect all identifiers
const identifiers = [];
simple(ast, {
Identifier(node) {
identifiers.push(node.name);
}
});
console.log("Found identifiers:", identifiers);import { parse as looseParse } from "acorn-loose";
import { simple } from "acorn-walk";
const brokenCode = `
function incomplete() {
let x =
return x
// missing closing brace
`;
const ast = looseParse(brokenCode);
// Still able to walk the recovered AST
simple(ast, {
FunctionDeclaration(node) {
console.log("Found function despite syntax errors");
}
});import { Parser } from "acorn";
// Example plugin that adds support for a custom operator
function customOperatorPlugin(Parser) {
return class extends Parser {
parseExprAtom() {
if (this.type === tt.name && this.value === "customOp") {
const node = this.startNode();
this.next();
return this.finishNode(node, "CustomOperator");
}
return super.parseExprAtom();
}
};
}
const ExtendedParser = Parser.extend(customOperatorPlugin);
const ast = ExtendedParser.parse("let x = customOp;");interface Options {
ecmaVersion: ecmaVersion;
sourceType?: "script" | "module";
allowReserved?: boolean | "never";
allowReturnOutsideFunction?: boolean;
allowImportExportEverywhere?: boolean;
allowAwaitOutsideFunction?: boolean;
allowSuperOutsideMethod?: boolean;
allowHashBang?: boolean;
checkPrivateFields?: boolean;
locations?: boolean;
onToken?: ((token: Token) => void) | Token[];
onComment?: ((
isBlock: boolean, text: string, start: number, end: number, startLoc?: Position,
endLoc?: Position
) => void) | Comment[];
ranges?: boolean;
program?: Node;
sourceFile?: string;
directSourceFile?: string;
preserveParens?: boolean;
}
interface Node {
start: number;
end: number;
type: string;
range?: [number, number];
loc?: SourceLocation | null;
}
interface Program extends Node {
type: "Program";
body: Array<Statement | ModuleDeclaration>;
sourceType: "script" | "module";
}
class Parser {
options: Options;
input: string;
static parse(input: string, options: Options): Program;
static parseExpressionAt(input: string, pos: number, options: Options): Expression;
static tokenizer(input: string, options: Options): {
getToken(): Token;
[Symbol.iterator](): Iterator<Token>;
};
static extend(...plugins: ((BaseParser: typeof Parser) => typeof Parser)[]): typeof Parser;
}
class Token {
type: TokenType;
start: number;
end: number;
loc?: SourceLocation;
range?: [number, number];
}