- 文档
- 编程语言
【免费下载链接】estree
The ESTree Spec
导读
本文基于 ESTree 仓库中的 experimental/import-reflection.md,系统讲解 JavaScript 的 Import Reflection 提案在 ESTree AST 中的节点定义:静态导入节点新增的module: boolean标志、动态导入节点新增的attributes: Expression | null反射属性,以及它们各自的约束规则。同时结合 stage3/source-phase-imports.md、es2015.md、es2020.md 与 es2025.md,厘清该提案与 Import Attributes、Source Phase Imports 之间的继承与演进关系,帮助 AST 工具链开发者正确识别、校验并序列化这一类"以模块源码为导入目标"的新语法结构。
一、文档定位:一个已被取代的实验性提案
experimental/import-reflection.md位于 ESTree 仓库的experimental/目录下。按 experimental/README.md 的说明,该目录存放的是对应 ECMAScript 提案处于Stage 0、1、2 或 2.7的 AST 扩展,其特点是"可能随时变更,不应视为稳定"。
import-reflection.md 在文档开头就以 Warning 形式明确声明:
Warning:本提案已被 Source Phase Imports 取代。
需要说明的是,仓库中实际存放 Source Phase Imports 文档的位置是 stage3/source-phase-imports.md(该提案已进入 Stage 3),而非原文档中引用的 experimental 路径。因此,研究 Import Reflection 的 AST 形态,既要看本文件对旧语法的完整定义,也要对照 Stage 3 文档中取而代之的phase字段设计,理解其演进脉络。
Import Reflection 提案的初衷,是允许 JavaScript 代码在不执行模块副作用的前提下,把某个模块的源码(source)作为一等公民导入并加工处理——典型场景如import(wasmModuleName, { reflect: "module" })中先把 WebAssembly 模块以源码形式取回,再交给编译管线处理。后来 TC39 将该方向收敛为更简洁的 Source Phase Imports 语法(import source X from "X"),因此本文件中的 AST 扩展被宣告作废。即便如此,它仍是理解 ESTree 如何处理"导入附加选项"这一设计空间的重要史料。
二、AST 描述语法回顾:extend interface的语义
在深入节点定义之前,先回顾 ESTree 仓库描述 AST 的专用语法(见 README.md 中的 "AST Descriptor Syntax" 一节)。仓库用extend interface表示对既有核心接口的增量扩展,例如 es2015.md 中对Program的描述:
extend interface Program { sourceType: "script" | "module"; body: [ Statement | ImportOrExportDeclaration ]; }这意味着extend关键字之后的字段是在基础接口之上新增的属性,而非重写整个接口。import-reflection.md 中的两处extend interface(ImportDeclaration与ImportExpression)同样遵循这一约定:要还原节点全貌,必须将其与对应基础文档中的核心定义合并阅读。
三、静态导入扩展:ImportDeclaration新增module标志
import-reflection.md 对静态导入声明的扩展定义如下:
extend interface ImportDeclaration { module: boolean; }ImportDeclaration的基础形态定义在 es2015.md 的 Modules 一节:
interface ImportDeclaration <: ImportOrExportDeclaration { type: "ImportDeclaration"; specifiers: [ ImportSpecifier | ImportDefaultSpecifier | ImportNamespaceSpecifier ]; source: Literal; }合并后,在启用 Import Reflection 语法的解析器中,ImportDeclaration的完整字段为:type、specifiers、source,外加本提案新增的module: boolean。
约束规则:module: true时的强约束
文档对该标志给出了明确的合法性约束:
当
module为true时,specifiers必须是一个长度为 1 的数组,且其中只能是ImportDefaultSpecifier;同时assertions必须是空数组。
逐条拆解:
specifiers长度必须为 1:也就是说,"反射导入"只能以默认导入的形态出现,不允许同时携带具名导入(ImportSpecifier)或命名空间导入(ImportNamespaceSpecifier)。唯一的 specifier 必须是
ImportDefaultSpecifier:ImportDefaultSpecifier的基础定义见 es2015.md:interface ImportDefaultSpecifier <: ModuleSpecifier { type: "ImportDefaultSpecifier"; }它表示
import foo from "mod.js"中的foo这类默认导入绑定。assertions必须为空数组:即反射导入不允许附带任何 import assertions(当时提案使用的旧名词,后文会说明其与现代 Import Attributes 的关系)。
合法与非法 AST 对比
以下两个示例(示意形态,依据上述接口定义与约束推演):
// 合法:反射导入仅带一个默认说明符 { "type": "ImportDeclaration", "specifiers": [ { "type": "ImportDefaultSpecifier", "local": { "type": "Identifier", "name": "wasmSource" } } ], "source": { "type": "Literal", "value": "./module.wasm", "raw": "\"./module.wasm\"" }, "module": true, "assertions": [] } // 非法:module 为 true 时 specifiers 长度超过 1,或携带非默认说明符 { "type": "ImportDeclaration", "specifiers": [ { "type": "ImportDefaultSpecifier", "local": { "type": "Identifier", "name": "a" } }, { "type": "ImportSpecifier", "imported": { "type": "Identifier", "name": "b" }, "local": { "type": "Identifier", "name": "b" } } ], "source": { "type": "Literal", "value": "./module.wasm", "raw": "\"./module.wasm\"" }, "module": true }对于实现该语法的解析器来说,module: true的存在即意味着整个声明以"源码获取"为目标,后续工具(如打包器、转译器)应据此跳过正常的模块实例化流程。
四、动态导入扩展:ImportExpression新增attributes属性
除静态导入外,Import Reflection 还允许通过动态导入携带反射指令。文档的扩展定义如下:
extend interface ImportExpression { attributes: Expression | null; }ImportExpression的基础形态定义在 es2020.md 的 Expressions 一节:
interface ImportExpression <: Expression { type: "ImportExpression"; source: Expression; }基础定义中source可以是任意表达式节点(而不像ImportDeclaration的source那样必须是Literal)。合并后,ImportExpression增加attributes: Expression | null字段。
语义:attributes何时非空
文档给出的语义是:
当 import attributes 存在时,
attributes属性中包含一个Expression,例如import(wasmModuleName, { reflect: "module" })中的{ reflect: "module" }。
也就是说,动态反射导入的 AST 表现为:
{ "type": "ImportExpression", "source": { "type": "Identifier", "name": "wasmModuleName" }, "attributes": { "type": "ObjectExpression", "properties": [ { "type": "Property", "method": false, "shorthand": false, "computed": false, "key": { "type": "Identifier", "name": "reflect" }, "value": { "type": "Literal", "value": "module", "raw": "\"module\"" }, "kind": "init" } ] } }这里的{ reflect: "module" }即以普通对象表达式(ObjectExpression)的形态存入attributes。attributes为null时表示该动态导入未携带任何反射选项,对应普通import(specifier)写法。
与 Import Assertions 文档的关系
文档末尾特别说明:
该
ImportExpression扩展同样定义在 Import assertions 文档中;当该提案进入 Stage 4 后,本文件中的相关内容将被移除。
这体现了 ESTree 的单一事实来源原则:同一 AST 字段如果被多个提案共享,就会在相应文档间同步维护。在当前的仓库快照中,Import Attributes(即旧称 import assertions 的演进形态)已经标准化于 es2025.md:
extend interface ImportExpression { options: Expression | null; }注意此处字段名已从提案期的attributes演变为 ES2025 标准中的options,承载的对象也由{ reflect: "module" }变为{ with: { type: "json" } }形态。这一演变说明:Import Reflection 文档所定义的attributes字段只是特定历史阶段的设计,不应在实现中直接与标准化的options混用。
五、演进对照:从 Import Reflection 到 Source Phase Imports
文档在开头即声明该提案已被 Source Phase Imports 取代,其 AST 新形态完整定义于 stage3/source-phase-imports.md。两代设计对同一语法空间的解决方案对比如下:
| 语法维度 | Import Reflection(本文件,已废弃) | Source Phase Imports(Stage 3) |
|---|---|---|
| 静态导入形态 | ImportDeclaration.module: true(默认说明符 + 空 assertions) | ImportDeclaration.phase: "source" |
| 动态导入形态 | import(spec, { reflect: "module" })→ImportExpression.attributes | import.source(spec)→ImportExpression.phase: "source" |
| 标志语义 | 布尔标志区分是否反射导入 | 枚举值"source" | null区分是否源码阶段导入 |
| 附加选项承载 | attributes: Expression | null | 不再需要附加对象(语法本身携带语义) |
Stage 3 文档中的完整定义:
extend interface ImportDeclaration { phase: "source" | null; }phase为"source"时表示import source X from "X"形式的源码阶段导入;同样约束specifiers必须是长度为 1、仅含ImportDefaultSpecifier的数组:
extend interface ImportExpression { phase: "source" | null; }phase为"source"时表示import.source("X")形式的动态源码阶段导入。
从对比可见,Source Phase Imports 把"反射导入"从附加选项({ reflect: "module" })收敛为语法关键字(source),使 AST 形态更简洁、可校验性更强。phase字段同时出现在ImportDeclaration与ImportExpression上,保持了静态导入与动态导入在 AST 表达上的一致性设计原则。按 stage3/README.md 的说明,Stage 3 的 AST 形状已达成共识、基本稳定,可供实现者参考。
六、对解析器与工具链的落地建议
结合 ESTree 仓库的哲学(见 README.md 的 "Philosophy" 一节:向后兼容、无上下文依赖、信息不重复、易于扩展),若需在工具链中处理 Import Reflection 语法,建议遵循以下几点:
- 严格校验约束:
module: true与phase: "source"下,specifiers必须为长度 1 且仅含ImportDefaultSpecifier;不符合即视为语法错误。Import Reflection 额外要求assertions为空数组。 - 区分新旧字段:
ImportExpression上存在三套不同时期的字段——本文件的attributes(已废弃)、ES2025 标准的options(见 es2025.md)、Stage 3 的phase(见 stage3/source-phase-imports.md)。实现时应按目标 ECMAScript 版本选择对应字段,切勿混用。 - 向后兼容:所有扩展均以
extend形式叠加在既有核心接口之上(基础定义见 es2015.md 与 es2020.md),普通导入节点(module缺省为false、phase为null、attributes/options为null)的既有 AST 形态不受影响,旧工具仍可解析新增字段。 - 按实验特性处理:Import Reflection 属于 experimental 目录(对应 TC39 Stage 0–2.7),形态随时可能变动;生产实现应以 stage3/source-phase-imports.md 的稳定形态为基准。
七、总结与延伸阅读
experimental/import-reflection.md虽然篇幅精炼,却完整定义了 Import Reflection 提案在 ESTree AST 中的两个关键扩展:静态导入的module: boolean标志(及其"单默认说明符 + 空 assertions"约束)和动态导入的attributes: Expression | null属性(用于承载{ reflect: "module" }反射指令)。该提案已被 Source Phase Imports 取代,其位置由phase: "source"字段与import source X from "X"、import.source("X")语法承接。
建议按以下路径深入阅读仓库相关文档:
- es2015.md:
ImportDeclaration、ImportDefaultSpecifier等模块导入基础节点定义; - es2020.md:
ImportExpression动态导入基础节点定义; - es2025.md:Import Attributes 标准化后的
attributes/options字段形态; - stage3/source-phase-imports.md:取代本提案的 Stage 3 稳定 AST 定义;
- experimental/README.md 与 stage3/README.md:experimental 与 Stage 3 两档文档的稳定性约定。
- 文档
- 编程语言
【免费下载链接】estree
The ESTree Spec
相关推荐
理解 ESTree 中的 defer-import-eval 扩展:模块求值延迟的 AST 表示
理解 ESTree 中的 defer import eval 扩展:模块求值延迟的 AST 表示 导读 本文聚焦 ESTree 规范仓库中 stage3/def
文档编程语言ESTree Module Declarations 规范解析:内嵌模块声明(ModuleDeclaration / ModuleBlock)的 AST 节点扩展
ESTree Module Declarations 规范解析:内嵌模块声明(ModuleDeclaration / ModuleBlock)的 AST 节点扩
文档编程语言ESTree 规范详解:JavaScript 工具链通用 AST 标准的设计与演进
ESTree 规范详解:JavaScript 工具链通用 AST 标准的设计与演进 ESTree 是 JavaScript 抽象语法树(AST)事实上的社区标准
文档编程语言
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考