`sourceType: "unambiguous"` 不一致地处理顶层 await 表单
作者: magic-akari创建于 2026年8月23日更新于 2026年9月11日
问题描述
- 您是否想要修复此问题?
- 如何使用 Babel?
- 程序化 API(
babel.transform、babel.parse) - 输入代码
import { parse } from "@babel/parser";
const cases = {
"await value": "await value;",
"await + 0": "await + 0;",
"for await": "for await (const value of values) {}",
"await using": "await using resource = acquire();",
};
for (const [name, code] of Object.entries(cases)) {
const ast = parse(code, {
sourceType: "unambiguous",
plugins: ["explicitResourceManagement"],
});
console.log(`${name}: ${ast.program.sourceType}`);
}- 配置文件名:babel.config.json
- 配置
{
"sourceType": "unambiguous",
"plugins": ["explicitResourceManagement"]
}- 当前行为和预期行为
- 当前结果如下:
| 输入 | program.sourceType |
|---|---|
await value; |
module |
await + 0; |
script |
for await (const value of values) {} |
script |
await using resource = acquire(); |
script |
这里存在两种不同的不一致性。首先,不同形式的顶级 await 会被不同对待,这表明文件是模块的证据:
- 一个明确的顶级 await 表达式,例如
await value,会产生一个模块。 - 一个同时具有有效脚本解释的表达式,例如
await + 0,会产生一个脚本和不同的 AST 形状。 for await (...)和await using ...会产生一个脚本。- 其次,即使 AST 标记为脚本,但在明确指定了
sourceType: "script"时,Babel 会拒绝此语法:
parse("for await (const value of values) {}", {
sourceType: "script",
}); // throws
parse("await using resource = acquire();", {
sourceType: "script",
plugins: ["explicitResourceManagement"],
}); // throws这意味着使用 sourceType: "unambiguous" 进行解析的结果无法通过使用已解析的 program.sourceType 来重现。后续工具如果保留并再次使用已解析的源类型,则可能会在 Babel 最初接受的源上失败。
- 我希望
sourceType: "unambiguous"遵循一致的策略。以下两种情况都是可以理解的:
选项 1:不要使用顶级 await 进行源类型检测
仅明确的导入/导出族语法才会导致不含歧义的源类型解析为模块。无论顶级 await 以何种形式出现,例如 await value、await + 0、for await (...) 或 await using ...,都不会被视为模块证据。
这是一种保守的策略:源类型检测仍然基于明确的模块语法,而对仅包含 TLA 的输入的接受和 AST 表示可以单独指定。
选项 2:将每个顶级 await 形式都视为模块证据
如果顶级 await 参与源类型检测,则其所有语法形式都应参与。特别是,顶级 for await (...)
…
内容来源: babel/babel