Espree is an Esprima-compatible JavaScript parser built on Acorn that parses JavaScript code into Abstract Syntax Trees (AST) following the ESTree specification. It provides parsing and tokenization capabilities with support for modern ECMAScript features through ECMAScript 2025 and partial ECMAScript 2026 support.
import * as espree from "espree";For CommonJS:
const espree = require("espree");Named imports (ESM):
import { parse, tokenize, version, VisitorKeys, Syntax, latestEcmaVersion, supportedEcmaVersions } from "espree";import * as espree from "espree";
// Parse JavaScript code into AST
const ast = espree.parse('let foo = "bar"', {
ecmaVersion: 2022,
sourceType: "module"
});
// Tokenize JavaScript code
const tokens = espree.tokenize('let foo = "bar"', {
ecmaVersion: 2022
});
// Check supported ECMAScript versions
console.log(espree.supportedEcmaVersions); // [3, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17]
console.log(espree.latestEcmaVersion); // 17Parses JavaScript code and returns an Abstract Syntax Tree (AST).
/**
* Parses JavaScript code and returns an Abstract Syntax Tree (AST)
* @param {string} code - The JavaScript code to parse
* @param {ParserOptions} options - Parser configuration options
* @returns {Program} The "Program" AST node
* @throws {SyntaxError} If the input code is invalid
*/
function parse(code, options);Tokenizes JavaScript code and returns an array of tokens.
/**
* Tokenizes JavaScript code and returns an array of tokens
* @param {string} code - The JavaScript code to tokenize
* @param {ParserOptions} options - Parser configuration options (tokens forced to true)
* @returns {Token[]} Array of token objects
* @throws {SyntaxError} If the input code is invalid
*/
function tokenize(code, options);Constants providing information about supported ECMAScript versions.
/**
* Latest ECMAScript version supported by espree
* @type {number} Latest supported ECMAScript version (17 for ES2026)
*/
const latestEcmaVersion: number;
/**
* Array of all supported ECMAScript versions
* @type {number[]} Array of supported versions: [3, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17]
*/
const supportedEcmaVersions: number[];Package version and identification constants.
/** Current espree version string */
const version: string;
/** Package name ("espree") */
const name: string;Utilities for working with Abstract Syntax Trees.
/**
* AST visitor keys from eslint-visitor-keys for tree traversal
* Contains property names that hold child nodes for each AST node type
*/
const VisitorKeys: object;
/**
* AST node type constants derived from VisitorKeys
* Object with AST node type names as both keys and values
*/
const Syntax: object;interface ParserOptions {
/** ECMAScript version: 3, 5, 6-17, 2015-2026, or "latest" */
ecmaVersion?: number | "latest";
/** Source type: "script", "module", or "commonjs" */
sourceType?: "script" | "module" | "commonjs";
/** Attach range information to each node */
range?: boolean;
/** Attach line/column location information to each node */
loc?: boolean;
/** Create a top-level comments array containing all comments */
comment?: boolean;
/** Create a top-level tokens array containing all tokens */
tokens?: boolean;
/** Allow reserved words (only allowed when ecmaVersion is 3) */
allowReserved?: boolean;
/** Additional language features */
ecmaFeatures?: ECMAFeatures;
}
interface ECMAFeatures {
/** Enable JSX parsing */
jsx?: boolean;
/** Allow return statement in global scope (automatically true for sourceType "commonjs") */
globalReturn?: boolean;
/** Enable implied strict mode (if ecmaVersion >= 5) */
impliedStrict?: boolean;
}interface Program {
type: "Program";
body: Statement[];
sourceType: "script" | "module";
start?: number;
end?: number;
range?: [number, number];
loc?: SourceLocation;
comments?: Comment[];
tokens?: Token[];
}
interface Token {
type: string; // "Keyword", "Identifier", "Punctuator", "String", "Numeric", etc.
value: string;
start: number;
end: number;
range?: [number, number];
loc?: SourceLocation;
}
interface SourceLocation {
start: Position;
end: Position;
}
interface Position {
line: number; // 1-based
column: number; // 0-based
}
interface Comment {
type: "Line" | "Block";
value: string;
start: number;
end: number;
range?: [number, number];
loc?: SourceLocation;
}Parsing with different ECMAScript versions:
import * as espree from "espree";
// ES5 parsing
const es5Ast = espree.parse("var x = 5;", { ecmaVersion: 5 });
// ES2020 parsing with optional chaining
const es2020Ast = espree.parse("obj?.prop?.method?.()", { ecmaVersion: 11 });
// Latest ECMAScript features
const latestAst = espree.parse("const x = 5;", { ecmaVersion: "latest" });Module vs Script parsing:
// Parse as ES module
const moduleAst = espree.parse("import { foo } from 'bar';", {
ecmaVersion: 2022,
sourceType: "module"
});
// Parse as script
const scriptAst = espree.parse("var foo = require('bar');", {
ecmaVersion: 2022,
sourceType: "script"
});
// Parse as CommonJS
const commonjsAst = espree.parse("return module.exports;", {
ecmaVersion: 2022,
sourceType: "commonjs"
});JSX parsing:
const jsxAst = espree.parse("const element = <div>Hello</div>;", {
ecmaVersion: 2022,
sourceType: "module",
ecmaFeatures: {
jsx: true
}
});Tokenization with location information:
const tokens = espree.tokenize('let x = "hello";', {
ecmaVersion: 2022,
loc: true,
range: true
});
console.log(tokens);
// [
// { type: 'Keyword', value: 'let', start: 0, end: 3, loc: {...} },
// { type: 'Identifier', value: 'x', start: 4, end: 5, loc: {...} },
// { type: 'Punctuator', value: '=', start: 6, end: 7, loc: {...} },
// { type: 'String', value: '"hello"', start: 8, end: 15, loc: {...} }
// ]Parsing with comments and tokens:
const ast = espree.parse(`
// This is a comment
let x = 42; /* Another comment */
`, {
ecmaVersion: 2022,
comment: true,
tokens: true,
loc: true
});
console.log(ast.comments.length); // 2
console.log(ast.tokens.length); // 4 (let, x, =, 42)Error handling:
try {
const ast = espree.parse("let x = ;", { ecmaVersion: 2022 });
} catch (error) {
if (error instanceof SyntaxError) {
console.log("Parsing error:", error.message);
console.log("Line:", error.lineNumber);
console.log("Column:", error.column);
console.log("Index:", error.index);
}
}Working with visitor keys and syntax:
import * as espree from "espree";
const ast = espree.parse("function test() { return 42; }", { ecmaVersion: 2022 });
// Access visitor keys
console.log(espree.VisitorKeys.FunctionDeclaration); // ["id", "params", "body"]
// Use syntax constants
console.log(espree.Syntax.FunctionDeclaration); // "FunctionDeclaration"
// Traverse AST using visitor keys
function traverse(node, visitor) {
if (typeof visitor[node.type] === "function") {
visitor[node.type](node);
}
const keys = espree.VisitorKeys[node.type] || [];
for (const key of keys) {
const child = node[key];
if (Array.isArray(child)) {
for (const item of child) {
if (item && typeof item === "object") {
traverse(item, visitor);
}
}
} else if (child && typeof child === "object") {
traverse(child, visitor);
}
}
}
traverse(ast, {
FunctionDeclaration(node) {
console.log(`Found function: ${node.id.name}`);
}
});ecmaFeatures.jsx is enabled"latest" for the most recent supported versionES6/ES2015 (version 6):
ES2017 (version 8):
ES2018 (version 9):
ES2019 (version 10):
ES2020 (version 11):
?.), nullish coalescing (??), BigInt, dynamic importsES2021 (version 12):
||=, &&=, ??=), numeric separatorsES2022 (version 13):
ES2023 (version 14):
ES2024 (version 15):
ES2025 (version 16):
ES2026 (version 17) - Partial:
using, await using)Espree throws SyntaxError for invalid JavaScript code with detailed error information:
// Enhanced SyntaxError properties
interface EspreeSyntaxError extends SyntaxError {
message: string; // Descriptive error message
lineNumber: number; // 1-based line number
column: number; // 0-based column number
index: number; // 0-based character index
}Common validation errors:
ecmaVersion valuessourceType valuesecmaFeatures combinationssourceType: "module" with ecmaVersion < 6allowReserved used with ecmaVersion !== 3Error handling examples:
// Invalid syntax
try {
espree.parse("let x = ;", { ecmaVersion: 2022 });
} catch (error) {
console.log(error.message); // "Unexpected token ;"
console.log(error.lineNumber); // 1
console.log(error.column); // 8
}
// Invalid options
try {
espree.parse("const x = 1;", {
ecmaVersion: 5, // const not supported in ES5
sourceType: "script"
});
} catch (error) {
console.log(error.message); // "Unexpected token const"
}
// Module syntax with wrong sourceType
try {
espree.parse("import x from 'y';", {
ecmaVersion: 2022,
sourceType: "script" // Should be "module"
});
} catch (error) {
console.log(error.message); // "'import' and 'export' may appear only with 'sourceType: module'"
}tokens: true when needed, as it increases memory usageloc and range options add overhead but are useful for error reportingcomment: true and attachComments: true add processing overheadEspree integrates seamlessly with JavaScript tooling:
ESLint integration:
// ESLint uses espree as its default parser
module.exports = {
parser: "espree", // Default parser
parserOptions: {
ecmaVersion: 2022,
sourceType: "module",
ecmaFeatures: {
jsx: true
}
}
};Custom AST processing:
import * as espree from "espree";
class CodeAnalyzer {
analyze(code, options = {}) {
const ast = espree.parse(code, {
ecmaVersion: "latest",
sourceType: "module",
loc: true,
...options
});
return this.processAST(ast);
}
processAST(ast) {
// Custom analysis logic
return {
functions: this.findFunctions(ast),
variables: this.findVariables(ast),
imports: this.findImports(ast)
};
}
}