☰
Esprima 语法树格式(AST)完全指南:ESTree 节点定义与位置信息
2026/9/29 2:35:26 网站建设 项目流程
  • 开发工具

【免费下载链接】esprima

ECMAScript parsing infrastructure for multipurpose analysis

项目地址:https://gitcode.com/gh_mirrors/es/esprima
点击查看免费下载

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

项目地址:https://gitcode.com/gh_mirrors/es/esprima
点击查看免费下载

相关推荐

上一篇:告别Python代码格式混乱:VSCode与PyCharm集成YAPF的超实用方案
下一篇:Snap.svg SVG元素复制终极指南:copy.js完整使用教程

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询