- 开发工具
【免费下载链接】esprima
ECMAScript parsing infrastructure for multipurpose analysis
Esprima 是 ECMAScript 解析基础设施,其输出的语法树(Abstract Syntax Tree, AST)格式继承自 Mozilla Parser API,并经 ESTree 规范正式化与扩展。本文以 docs/syntax-tree-format.md 为骨架,结合仓库src/nodes.ts、src/syntax.ts、src/parser.ts等源码实现,系统梳理每一个 AST 节点的 TypeScript 接口定义、字段含义与真实输出形态,帮助你在编写代码分析工具、转换器、linter 或自定义编译器时准确消费 Esprima 的解析结果。
从 Mozilla Parser API 到 ESTree:语法树的来源
Esprima 的语法树格式并非凭空发明,而是派生自 Mozilla Parser API 的原始版本,随后被正式化并扩展为 ESTree 规范。因此,任何基于 ESTree 的工具链(如 Babel、ESLint 的解析器生态)都能与 Esprima 的输出保持结构兼容。在后续小节中,接口统一使用 TypeScript interface 语法描述。
节点基座:每个 AST 节点都是普通 JavaScript 对象
Esprima 输出的 AST 中,每个节点都是一个普通 JavaScript 对象,实现如下基础接口:
interface Node { type: string; }type属性是包含节点变体类型名称的字符串,例如Program、VariableDeclaration、CallExpression。类型名称常量集中定义在 src/syntax.ts 的Syntax对象中,并在 src/nodes.ts 的各类构造函数中被引用(如this.type = Syntax.ArrayExpression),保证type值在整个仓库中完全一致。
当节点被标注位置信息(见 syntactic-analysis.md 对应的loc/range选项)时,接口扩展为:
interface Node { type: string; range?: [number, number]; loc?: SourceLocation; }其中源位置定义如下:
interface Position { line: number; column: number; } interface SourceLocation { start: Position; end: Position; source?: string | null; }从实现上看,src/parser.ts 中Parser构造函数会把options.range、options.loc、options.tokens、options.comment、options.tolerant等布尔选项读入config;当config.loc为真且提供了options.source字符串时,node.loc.source会携带该来源标识(见 src/parser.ts 的finalize方法)。range是[起始偏移, 结束偏移]的 UTF-16 码元索引对,loc则记录行列号(行从 1 计,列从 0 计)。测试夹具中的真实输出(如 test/fixtures/JSX/simple-expression-container.tree.json)展示了range与loc同时存在时的完整形态。
Expressions and Patterns:表达式与绑定模式
绑定模式(binding pattern,用于解构语境)只能是以下之一:
type BindingPattern = ArrayPattern | ObjectPattern;表达式(expression)则可以是以下任意一种:
type Expression = ThisExpression | Identifier | Literal | ArrayExpression | ObjectExpression | FunctionExpression | ArrowFunctionExpression | ClassExpression | TaggedTemplateExpression | MemberExpression | Super | MetaProperty | NewExpression | CallExpression | UpdateExpression | AwaitExpression | UnaryExpression | BinaryExpression | LogicalExpression | ConditionalExpression | YieldExpression | AssignmentExpression | SequenceExpression;仓库中 src/nodes.ts 的类型联合(union)在此基础上还补充了ChainExpression、RegexLiteral、ComputedMemberExpression、StaticMemberExpression与异步函数变体,说明 Esprima 对 ESTree 的实现在细节上略超前于本文档的基础集合。
Array Pattern(数组绑定模式)
interface ArrayPattern { type: 'ArrayPattern'; elements: ArrayPatternElement[]; }其中
type ArrayPatternElement = AssignmentPattern | Identifier | BindingPattern | RestElement | null; interface RestElement { type: 'RestElement'; argument: Identifier | BindingPattern; }null元素对应数组解构中的洞(hole),如const [, a] = arr;中逗号间的空位;RestElement对应...rest剩余元素(src/nodes.ts)。
Assignment Pattern(带默认值的绑定模式)
interface AssignmentPattern { type: 'AssignmentPattern'; left: Identifier | BindingPattern; right: Expression; }用于function f(a = 1)或解构默认值{a = 1}。实现见 src/nodes.ts。
Object Pattern(对象绑定模式)
interface ObjectPattern { type: 'ObjectPattern'; properties: Property[]; }仓库实现 src/nodes.ts 中,properties实际为Property | RestElement,即还支持{...rest}的对象剩余属性(ES2018 rest-property,见 test/fixtures/es2018/rest-property)。
This Expression、Identifier 与 Literal
interface ThisExpression { type: 'ThisExpression'; } interface Identifier { type: 'Identifier'; name: string; } interface Literal { type: 'Literal'; value: boolean | number | string | RegExp | null; raw: string; regex?: { pattern: string, flags: string }; }要点:
Literal.value是运行时求值后的值(如42、"foo"、null、true);raw保留源码中的原始文本(如0xFF的 raw 为"0xFF",value 为255);regex属性仅适用于正则表达式字面量,携带pattern与flags。仓库中该场景由独立的 RegexLiteral 类生成,其type仍为'Literal'。
Array Expression 与 Object Expression
interface ArrayExpression { type: 'ArrayExpression'; elements: ArrayExpressionElement[]; }其中type ArrayExpressionElement = Expression | SpreadElement;(仓库中还允许null表示稀疏数组空洞,见 src/nodes.ts)。
interface ObjectExpression { type: 'ObjectExpression'; properties: Property[]; }其中Property定义如下:
interface Property { type: 'Property'; key: Expression; computed: boolean; value: Expression | null; kind: 'get' | 'set' | 'init'; method: false; shorthand: boolean; }字段语义:
computed:true表示[key]计算属性;kind:get/set为访问器属性,init为普通属性;method:文档中固定为false(方法属性在 Esprima 中同样以Property+FunctionExpression值表达,仓库实现见 src/nodes.ts);shorthand:true表示{a}形式的简写属性(ES6 object-literal-property-value-shorthand)。
Function Expression、Arrow Function Expression 与 Class Expression
interface FunctionExpression { type: 'FunctionExpression'; id: Identifier | null; params: FunctionParameter[]; body: BlockStatement; generator: boolean; async: boolean; expression: boolean; }FunctionParameter定义为AssignmentPattern | Identifier | BindingPattern。generator为true表示生成器函数表达式。expression恒为false(Esprima 用body字段区分函数体与表达式体,箭头函数除外)。
interface ArrowFunctionExpression { type: 'ArrowFunctionExpression'; id: Identifier | null; params: FunctionParameter[]; body: BlockStatement | Expression; generator: boolean; async: boolean; expression: false; }箭头函数的body可以是BlockStatement(() => {})或Expression(() => 1),id恒为null。实现中expression布尔值由构造函数第三个参数传入(src/nodes.ts),async恒为false;异步箭头函数由AsyncArrowFunctionExpression生成,但其type同样写为ArrowFunctionExpression(src/nodes.ts),async为true。
interface ClassExpression { type: 'ClassExpression'; id: Identifier | null; superClass: Identifier | null; body: ClassBody; }ClassBody与MethodDefinition如下:
interface ClassBody { type: 'ClassBody'; body: MethodDefinition[]; } interface MethodDefinition { type: 'MethodDefinition'; key: Expression | null; computed: boolean; value: FunctionExpression | null; kind: 'method' | 'constructor'; static: boolean; }注意:ClassExpression.id、superClass在接口中标注为Identifier | null,但 ES2015 的superClass实际可以是任意表达式(class A extends mixin(B) {});仓库实现 src/nodes.ts 中其类型为Expression | null,阅读输出时需兼容这一差异。
Tagged Template Expression
interface TaggedTemplateExpression { type: 'TaggedTemplateExpression'; readonly tag: Expression; readonly quasi: TemplateLiteral; }模板相关节点:
interface TemplateElement { type: 'TemplateElement'; value: { cooked: string; raw: string }; tail: boolean; } interface TemplateLiteral { type: 'TemplateLiteral'; quasis: TemplateElement[]; expressions: Expression[]; }quasis为静态文本片段的TemplateElement数组,expressions为插入表达式数组,二者一一交错(quasis 数量 = expressions 数量 + 1)。仓库中TemplateElement.value.cooked的类型为string | null(src/nodes.ts),tail标记是否为最后一个 quasi。
Member Expression、Super 与 MetaProperty
interface MemberExpression { type: 'MemberExpression'; computed: boolean; object: Expression; property: Expression; } interface Super { type: 'Super'; } interface MetaProperty { type: 'MetaProperty'; meta: Identifier; property: Identifier; }MemberExpression.computed:a.b为false,a[b]为true。实现中由StaticMemberExpression(computed=false)与ComputedMemberExpression(computed=true)两个类共同产出MemberExpression(src/nodes.ts、src/nodes.ts);MetaProperty对应new.target(meta为new,property为target),fixture 见 test/fixtures/ES6/meta-property。
Call / New Expressions、Import 与 SpreadElement
interface CallExpression { type: 'CallExpression'; callee: Expression | Import; arguments: ArgumentListElement[]; } interface NewExpression { type: 'NewExpression'; callee: Expression; arguments: ArgumentListElement[]; }辅助类型:
interface Import { type: 'Import'; } type ArgumentListElement = Expression | SpreadElement; interface SpreadElement { type: 'SpreadElement'; argument: Expression; }Import节点对应动态import()(ES2020 dynamic-import,fixture 见 test/fixtures/es2018/dynamic-import);SpreadElement对应展开参数f(...args)或数组展开[...a]。
Update、Await、Unary、Binary、Logical、Conditional、Yield、Assignment、Sequence 表达式
interface UpdateExpression { type: 'UpdateExpression'; operator: '++' | '--'; argument: Expression; prefix: boolean; } interface AwaitExpression { type: 'AwaitExpression'; argument: Expression; } interface UnaryExpression { type: 'UnaryExpression'; operator: '+' | '-' | '~' | '!' | 'delete' | 'void' | 'typeof'; argument: Expression; prefix: true; } interface BinaryExpression { type: 'BinaryExpression'; operator: 'instanceof' | 'in' | '+' | '-' | '*' | '/' | '%' | '**' | '|' | '^' | '&' | '==' | '!=' | '===' | '!==' | '<' | '>' | '<=' | '<<' | '>>' | '>>>'; left: Expression; right: Expression; } interface LogicalExpression { type: 'LogicalExpression'; operator: '||' | '&&'; left: Expression; right: Expression; } interface ConditionalExpression { type: 'ConditionalExpression'; test: Expression; consequent: Expression; alternate: Expression; } interface YieldExpression { type: 'YieldExpression'; argument: Expression | null; delegate: boolean; } interface AssignmentExpression { type: 'AssignmentExpression'; operator: '=' | '*=' | '**=' | '/=' | '%=' | '+=' | '-=' | '<<=' | '>>=' | '>>>=' | '&=' | '^=' | '|='; left: Expression; right: Expression; } interface SequenceExpression { type: 'SequenceExpression'; expressions: Expression[]; }关键语义与实现要点:
UpdateExpression.prefix区分++x(true)与x++(false);UnaryExpression.prefix恒为true;- 仓库对二元运算的归类值得注意:
BinaryExpression构造函数在运算符为||、&&(以及??)时会将type置为LogicalExpression(src/nodes.ts),与文档中LogicalExpression单独成类的约定一致;ES2020 空值合并??同样输出为LogicalExpression; YieldExpression.delegate为true表示yield*委托生成(fixture 见 test/fixtures/ES6/yield);AwaitExpression与ForOfStatement.await(for await...of)覆盖 ES2017 异步特性(fixture 见 test/fixtures/es2017/async)。
Statements and Declarations:语句与声明
语句(statement)可以是以下任意一种:
type Statement = BlockStatement | BreakStatement | ContinueStatement | DebuggerStatement | DoWhileStatement | EmptyStatement | ExpressionStatement | ForStatement | ForInStatement | ForOfStatement | FunctionDeclaration | IfStatement | LabeledStatement | ReturnStatement | SwitchStatement | ThrowStatement | TryStatement | VariableDeclaration | WhileStatement | WithStatement;声明(declaration)只能是:
type Declaration = ClassDeclaration | FunctionDeclaration | VariableDeclaration;语句列表项(statement list item)则两者皆可:
type StatementListItem = Declaration | Statement;仓库中 src/nodes.ts 将Declaration扩展为包含AsyncFunctionDeclaration、ExportDeclaration、ImportDeclaration,Statement亦包含AsyncFunctionDeclaration与Directive子类型,这是对模块语法的直接支撑。
Block、Break、Continue、Debugger、Do-While、Empty 语句
interface BlockStatement { type: 'BlockStatement'; body: StatementListItem[]; } interface BreakStatement { type: 'BreakStatement'; label: Identifier | null; } interface ContinueStatement { type: 'ContinueStatement'; label: Identifier | null; } interface DebuggerStatement { type: 'DebuggerStatement'; } interface DoWhileStatement { type: 'DoWhileStatement'; body: Statement; test: Expression; } interface EmptyStatement { type: 'EmptyStatement'; }BreakStatement/ContinueStatement的label在无标签跳转时为null。
Class Declaration、Expression Statement 与指令序言
interface ClassDeclaration { type: 'ClassDeclaration'; id: Identifier | null; superClass: Identifier | null; body: ClassBody; } interface ExpressionStatement { type: 'ExpressionStatement'; expression: Expression; directive?: string; }指令(directive)语义:当表达式语句表示一条指令(如"use strict")时,directive属性会包含指令字符串。仓库中 Directive 类生成该节点(type仍为ExpressionStatement),parser 在parseDirective路径处理(相关 fixture 见 test/fixtures/directive-prolog 与 ES2016 strict-directive)。脚本开头的指令序列即“指令序言”(directive prologue)。
For、For-In、For-Of 语句
interface ForStatement { type: 'ForStatement'; init: Expression | VariableDeclaration | null; test: Expression | null; update: Expression | null; body: Statement; } interface ForInStatement { type: 'ForInStatement'; left: Expression | VariableDeclaration; right: Expression; body: Statement; each: false; } interface ForOfStatement { type: 'ForOfStatement'; await: boolean; left: Expression | VariableDeclaration; right: Expression; body: Statement; }ForStatement.init/test/update在缺省时均为null;ForInStatement.each恒为false(历史遗留字段,保留兼容);ForOfStatement.await为true表示for await (x of y)(ES2018,fixture 见 test/fixtures/es2018/for-await-of)。实现见 src/nodes.ts。
Function Declaration、If、Labeled、Return、Switch 语句
interface FunctionDeclaration { type: 'FunctionDeclaration'; id: Identifier | null; params: FunctionParameter[]; body: BlockStatement; generator: boolean; async: boolean; expression: false; } interface IfStatement { type: 'IfStatement'; test: Expression; consequent: Statement; alternate?: Statement; } interface LabeledStatement { type: 'LabeledStatement'; label: Identifier; body: Statement; } interface ReturnStatement { type: 'ReturnStatement'; argument: Expression | null; } interface SwitchStatement { type: 'SwitchStatement'; discriminant: Expression; cases: SwitchCase[]; }SwitchCase辅助类型:
interface SwitchCase { type: 'SwitchCase'; test: Expression | null; consequent: Statement[]; }注意:IfStatement.alternate与SwitchCase.test(default分支)在缺省时为null或省略。
Throw、Try 与 Catch
interface ThrowStatement { type: 'ThrowStatement'; argument: Expression; } interface TryStatement { type: 'TryStatement'; block: BlockStatement; handler: CatchClause | null; finalizer: BlockStatement | null; } interface CatchClause { type: 'CatchClause'; param: Identifier | BindingPattern; body: BlockStatement; }ES2019 的可选 catch 绑定(try {} catch {})对应handler.param为null,fixture 见 test/fixtures/es2019/optional-catch-binding;仓库实现 src/nodes.ts 中param类型已允许null。
Variable Declaration
interface VariableDeclaration { type: 'VariableDeclaration'; declarations: VariableDeclarator[]; kind: 'var' | 'const' | 'let'; } interface VariableDeclarator { type: 'VariableDeclarator'; id: Identifier | BindingPattern; init: Expression | null; }kind只能是var/const/let;VariableDeclarator.init在var a;这类无初始化器声明时为null。实现见 src/nodes.ts。
While 与 With 语句
interface WhileStatement { type: 'WhileStatement'; test: Expression; body: Statement; } interface WithStatement { type: 'WithStatement'; object: Expression; body: Statement; }Scripts and Modules:脚本与模块
程序(Program)要么是脚本,要么是模块:
interface Program { type: 'Program'; sourceType: 'script'; body: StatementListItem[]; } interface Program { type: 'Program'; sourceType: 'module'; body: ModuleItem[]; }辅助类型:
type StatementListItem = Declaration | Statement; type ModuleItem = ImportDeclaration | ExportDeclaration | StatementListItem;仓库中 Script 与 Module 两个类分别产出sourceType为script/module的Program节点。入口 src/esprima.ts 通过options.sourceType决定调用parseModule()还是parseScript(),并暴露了parseModule/parseScript便捷函数;parse()在收集注释、token 或容错模式下还会向Program追加comments、tokens、errors数组(src/esprima.ts)。
Import Declaration(导入声明)
type ImportDeclaration { type: 'ImportDeclaration'; specifiers: ImportSpecifier[]; source: Literal; }interface ImportSpecifier { type: 'ImportSpecifier' | 'ImportDefaultSpecifier' | 'ImportNamespaceSpecifier'; local: Identifier; imported?: Identifier; }三种 specifier 形态:
ImportSpecifier:具名导入import { a as b } from 'm',local为本地名,imported为源模块导出名;ImportDefaultSpecifier:默认导入import a from 'm',仅含local;ImportNamespaceSpecifier:命名空间导入import * as ns from 'm',仅含local。
实现分别见 src/nodes.ts,fixture 见 test/fixtures/ES6/import-declaration。
Export Declaration(导出声明)
导出声明可以是批量(batch)、默认(default)或具名(named)三种形式:
type ExportDeclaration = ExportAllDeclaration | ExportDefaultDeclaration | ExportNamedDeclaration;interface ExportAllDeclaration { type: 'ExportAllDeclaration'; source: Literal; } interface ExportDefaultDeclaration { type: 'ExportDefaultDeclaration'; declaration: Identifier | BindingPattern | ClassDeclaration | Expression | FunctionDeclaration; } interface ExportNamedDeclaration { type: 'ExportNamedDeclaration'; declaration: ClassDeclaration | FunctionDeclaration | VariableDeclaration; specifiers: ExportSpecifier[]; source: Literal; }interface ExportSpecifier { type: 'ExportSpecifier'; exported: Identifier; local: Identifier; };ExportAllDeclaration:export * from 'm',仅含source;ExportDefaultDeclaration:export default ...,declaration可以是表达式、标识符、类/函数声明或绑定模式;ExportNamedDeclaration:export { a as b }(含specifiers)或export const x = 1(含declaration);配合source即为export { a } from 'm'的重导出。仓库实现 src/nodes.ts 中ExportNamedDeclaration.declaration与source的类型允许为null,而ExportSpecifier.exported为导出名、local为本地名。
对应测试覆盖见 test/fixtures/ES6/export-declaration。
实战:从源码验证语法树格式
要在本地观察 Esprima 的输出,可结合 getting-started.md 运行:
# 在仓库根目录执行,输出带 range/loc 的完整 AST node -e " const esprima = require('./dist/esprima'); const ast = esprima.parseScript('const answer = 42;', { range: true, loc: true }); console.log(JSON.stringify(ast, null, 2)); "输出顶层结构为Program,sourceType为'script',body中包含VariableDeclaration(kind: 'const')与VariableDeclarator,其init为Literal(value: 42),与本文各节接口完全对应。
需要定位的验证依据速查:
| 关注点 | 仓库证据 |
|---|---|
| 节点类型常量 | src/syntax.ts |
| 全部节点类实现 | src/nodes.ts |
| 位置信息(range/loc)注入 | src/parser.ts |
| 解析入口与选项处理 | src/esprima.ts |
| 真实 AST 输出样例 | test/fixtures/JSX/simple-expression-container.tree.json |
小结
Esprima 的语法树格式以 ESTree 为规范骨架,通过type字段区分节点变体,以可选range/loc携带精确位置信息。本文完整梳理了表达式、语句/声明、脚本/模块三大类约 40 种节点接口:掌握Literal的raw与value分离、Property.kind/computed/shorthand语义、Directive与ExpressionStatement的关系、Program.sourceType区分脚本与模块,以及Import/Export系列声明结构,即可从容解析 Esprima 的任意输出,并在此基础上构建自己的静态分析、代码转换或格式化工具。
- 开发工具
【免费下载链接】esprima
ECMAScript parsing infrastructure for multipurpose analysis
相关推荐
如何用Get Shit Done解决AI编程的上下文衰退难题:架构深度解析与工程实践
如何用Get Shit Done解决AI编程的上下文衰退难题:架构深度解析与工程实践 在AI编程工具日益普及的今天,开发者面临着一个普遍却致命的问题:上下文衰退
人工智能AI 应用提示工程开发工具工作流自动化AI AgentMaLiang API完全指南:掌握iOS Metal绘图的核心类与最佳实践
MaLiang API完全指南:掌握iOS Metal绘图的核心类与最佳实践 MaLiang是一款基于Metal的iOS绘图库,为开发者提供了高效、灵活的涂鸦和
create-guten-block核心功能揭秘:为什么它是WordPress开发者的必备工具
create guten block核心功能揭秘:为什么它是WordPress开发者的必备工具 在WordPress Gutenberg编辑器时代,开发自定义区
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考