Espree is an Esprima-compatible JavaScript parser built on top of Acorn. It serves as the primary parser for ESLint and provides comprehensive ECMAScript support up to ES2023 with partial ES2024 features. Espree produces Abstract Syntax Trees (AST) that conform to the ESTree specification with JSX extensions.
npm install espreeimport * as espree from "espree";For CommonJS:
const espree = require("espree");import * as espree from "espree";
// Parse JavaScript code into an AST
const ast = espree.parse('let foo = "bar";', { ecmaVersion: 2023 });
// Tokenize JavaScript code
const tokens = espree.tokenize('let foo = "bar";', { ecmaVersion: 2023 });
// Access metadata
console.log(espree.version); // Current version
console.log(espree.latestEcmaVersion); // Latest supported ECMAScript version
console.log(espree.supportedEcmaVersions); // Array of all supported versionsEspree is built around several key components:
Parses JavaScript code into Abstract Syntax Trees (AST) conforming to the ESTree specification.
/**
* Parses JavaScript code into an Abstract Syntax Tree
* @param code - The JavaScript code to parse
* @param options - Parser configuration options
* @returns Program AST node representing the parsed code
* @throws SyntaxError if the input code is invalid
*/
function parse(code: string, options?: ParseOptions): Program;Usage Examples:
import * as espree from "espree";
// Basic parsing
const ast = espree.parse('var x = 42;');
// With options
const ast = espree.parse('let foo = "bar";', {
ecmaVersion: 2023,
sourceType: "module",
range: true,
loc: true
});
// JSX parsing
const jsxAst = espree.parse('<div>Hello</div>', {
ecmaVersion: 2023,
ecmaFeatures: { jsx: true }
});Tokenizes JavaScript code into an array of tokens for lexical analysis.
/**
* Tokenizes JavaScript code into an array of tokens
* @param code - The JavaScript code to tokenize
* @param options - Tokenizer configuration options
* @returns Array of tokens representing the lexical elements
* @throws SyntaxError if the input code is invalid
*/
function tokenize(code: string, options?: ParseOptions): Token[];Usage Examples:
import * as espree from "espree";
// Basic tokenization
const tokens = espree.tokenize('let foo = "bar";', { ecmaVersion: 6 });
// With location information
const tokens = espree.tokenize('const x = 42;', {
ecmaVersion: 2023,
loc: true,
range: true
});Access to package version and supported ECMAScript versions.
/** Current espree package version */
const version: string;
/** Package name constant */
const name: string;
/** Latest ECMAScript version supported by espree */
const latestEcmaVersion: number;
/** Array of all supported ECMAScript versions */
const supportedEcmaVersions: number[];Utilities for traversing and analyzing Abstract Syntax Trees.
/**
* Visitor keys for traversing AST nodes from eslint-visitor-keys
* Maps node types to arrays of child property names
*/
const VisitorKeys: {
[nodeType: string]: string[];
};
/**
* AST node type constants derived from VisitorKeys
* Provides constants for all ESTree node types
*/
const Syntax: {
[nodeType: string]: string;
};Usage Examples:
import * as espree from "espree";
// Use VisitorKeys for traversal
function traverse(node, visitor) {
const keys = espree.VisitorKeys[node.type] || [];
keys.forEach(key => {
const child = node[key];
if (Array.isArray(child)) {
child.forEach(item => item && traverse(item, visitor));
} else if (child) {
traverse(child, visitor);
}
});
if (visitor[node.type]) {
visitor[node.type](node);
}
}
// Use Syntax constants
const ast = espree.parse('function foo() {}');
if (ast.body[0].type === espree.Syntax.FunctionDeclaration) {
console.log('Found function declaration');
}interface ParseOptions {
/** ECMAScript version (3, 5, 6-15, 2015-2024, or "latest") */
ecmaVersion?: number | "latest";
/** Source type: "script", "module", or "commonjs" */
sourceType?: "script" | "module" | "commonjs";
/** Include range information [start, end] on nodes */
range?: boolean;
/** Include line/column location information */
loc?: boolean;
/** Collect comments in top-level comments array */
comment?: boolean;
/** Collect tokens in top-level tokens array */
tokens?: boolean;
/** Allow reserved words as identifiers (ECMAScript 3 only) */
allowReserved?: boolean;
/** ECMAScript feature flags */
ecmaFeatures?: EcmaFeatures;
}
interface EcmaFeatures {
/** Enable JSX parsing */
jsx?: boolean;
/** Allow return in global scope */
globalReturn?: boolean;
/** Enable implied strict mode */
impliedStrict?: boolean;
}interface Program {
type: "Program";
body: Statement[];
sourceType: "script" | "module" | "commonjs";
start?: number;
end?: number;
range?: [number, number];
loc?: SourceLocation;
comments?: Comment[];
tokens?: Token[];
}
interface SourceLocation {
start: Position;
end: Position;
}
interface Position {
line: number; // 1-based
column: number; // 0-based
}interface Token {
type: TokenType;
value: string;
start: number;
end: number;
range?: [number, number];
loc?: SourceLocation;
}
type TokenType =
| "Boolean"
| "Identifier"
| "PrivateIdentifier"
| "Keyword"
| "Null"
| "Numeric"
| "Punctuator"
| "String"
| "RegularExpression"
| "Template"
| "JSXIdentifier"
| "JSXText";interface Comment {
type: "Line" | "Block" | "Hashbang";
value: string;
start?: number;
end?: number;
range?: [number, number];
loc?: SourceLocation;
}interface SyntaxError extends Error {
/** Character position where error occurred */
index: number;
/** Line number of error (1-based) */
lineNumber: number;
/** Column number of error (1-based) */
column: number;
}When ecmaFeatures.jsx is enabled:
Espree throws SyntaxError objects for invalid JavaScript code:
try {
espree.parse('let x = ;'); // Invalid syntax
} catch (error) {
console.log(error.message); // Error description
console.log(error.index); // Character position
console.log(error.lineNumber); // Line number (1-based)
console.log(error.column); // Column number (1-based)
}