@babel/parser
Babel 解析器(以前称为 Babylon)是 Babel 中使用的 JavaScript 解析器。
- 默认情况下启用的最新 ECMAScript 版本 (ES2020)。
- 注释附件。
- 支持 JSX、Flow 和 Typescript。
- 支持实验性语言提案(接受任何至少处于 stage-0 阶段的 PR)。
致谢
很大程度上基于 acorn 和 acorn-jsx,感谢 @RReverser 和 @marijnh 的出色工作。
API
babelParser.parse(code, [options])
babelParser.parseExpression(code, [options])
parse()
将提供的 code
解析为完整的 ECMAScript 程序,而 parseExpression()
尝试解析单个表达式以提高性能。如有疑问,请使用 .parse()
。
选项
历史记录
版本 | 更改 |
---|---|
v7.23.0 | 添加了 createImportExpressions |
v7.21.0 | 添加了 allowNewTargetOutsideFunction 和 annexb |
v7.16.0 | 添加了 startColumn |
v7.15.0 | 添加了 attachComment |
v7.7.0 | 添加了 errorRecovery |
v7.5.0 | 添加了 allowUndeclaredExports |
v7.2.0 | 添加了 createParenthesizedExpressions |
-
allowImportExportEverywhere:默认情况下,
import
和export
声明只能出现在程序的顶层。将此选项设置为true
允许它们出现在允许使用语句的任何位置。 -
allowAwaitOutsideFunction:默认情况下,仅允许在异步函数内部使用
await
,或者在启用了topLevelAwait
插件的情况下,在模块的顶层作用域中使用。将其设置为true
也可以在脚本的顶层作用域中接受它。不建议使用此选项,而建议使用topLevelAwait
插件。 -
allowNewTargetOutsideFunction:默认情况下,不允许在函数或类之外使用
new.target
。将其设置为true
以接受此类代码。 -
allowReturnOutsideFunction:默认情况下,顶层的 return 语句会引发错误。将其设置为
true
以接受此类代码。 -
allowSuperOutsideMethod:默认情况下,不允许在类和对象方法之外使用
super
。将其设置为true
以接受此类代码。 -
allowUndeclaredExports:默认情况下,导出当前模块作用域中未声明的标识符将引发错误。虽然 ECMAScript 模块规范要求这种行为,但 Babel 的解析器无法预料插件管道中稍后可能会插入适当声明的转换,因此有时将此选项设置为
true
以防止解析器过早地抱怨稍后将添加的未声明导出非常重要。 -
attachComment:默认情况下,Babel 将注释附加到相邻的 AST 节点。当此选项设置为
false
时,不会附加注释。当输入代码有*很多*注释时,它可以提供高达 30% 的性能提升。@babel/eslint-parser
将为您设置它。不建议将attachComment: false
与 Babel 转换一起使用,因为这样做会删除输出代码中的所有注释,并使/* istanbul ignore next */
等注释失效。 -
annexb:默认情况下,Babel 根据 ECMAScript 的附件 B“*Web 浏览器附加的 ECMAScript 功能*” 语法解析 JavaScript。当此选项设置为
false
时,Babel 将解析语法,而不使用特定于附件 B 的扩展。 -
createImportExpressions:默认情况下,解析器将动态导入
import()
解析为调用表达式节点。当此选项设置为true
时,将改为创建ImportExpression
AST 节点。在 Babel 8 中,此选项将默认为true
。 -
createParenthesizedExpressions:默认情况下,解析器在表达式节点上设置
extra.parenthesized
。当此选项设置为true
时,将改为创建ParenthesizedExpression
AST 节点。 -
errorRecovery:默认情况下,当 Babel 发现一些无效代码时,它总是会抛出一个错误。当此选项设置为
true
时,它将存储解析错误并尝试继续解析无效的输入文件。生成的 AST 将具有一个errors
属性,表示所有解析错误的数组。请注意,即使启用了此选项,@babel/parser
也可能针对不可恢复的错误抛出异常。 -
plugins:包含要启用的插件的数组。
-
sourceType:指示代码应解析的模式。可以是
"script"
、"module"
或"unambiguous"
之一。默认为"script"
。"unambiguous"
将使 @babel/parser 尝试根据是否存在 ES6import
或export
语句来*猜测*。包含 ES6import
和export
的文件被视为"module"
,否则为"script"
。 -
sourceFilename:将输出 AST 节点与其源文件名相关联。在从多个输入文件的 AST 生成代码和源映射时很有用。
-
startColumn:默认情况下,解析后的代码将被视为从第 1 行第 0 列开始。您可以提供一个列号来选择性地开始。与其他源代码工具集成时很有用。
-
startLine:默认情况下,解析后的代码将被视为从第 1 行第 0 列开始。您可以提供一个行号来选择性地开始。与其他源代码工具集成时很有用。
-
strictMode:默认情况下,仅当存在
"use strict";
指令或解析后的文件是 ECMAScript 模块时,ECMAScript 代码才会被解析为严格模式。将此选项设置为true
以始终在严格模式下解析文件。 -
ranges:为每个节点添加一个
range
属性:[node.start, node.end]
-
tokens:将所有解析后的标记添加到
File
节点上的tokens
属性中
输出
Babel 解析器根据 Babel AST 格式 生成 AST。它基于 ESTree 规范,并具有以下偏差
- Literal 标记替换为 StringLiteral、NumericLiteral、BigIntLiteral、BooleanLiteral、NullLiteral、RegExpLiteral
- Property 标记替换为 ObjectProperty 和 ObjectMethod
- MethodDefinition 替换为 ClassMethod 和 ClassPrivateMethod
- PropertyDefinition 替换为 ClassProperty 和 ClassPrivateProperty
- PrivateIdentifier 替换为 PrivateName
- Program 和 BlockStatement 包含附加的
directives
字段,其中包含 Directive 和 DirectiveLiteral - ClassMethod、ClassPrivateMethod、ObjectProperty 和 ObjectMethod 值属性的属性在 FunctionExpression 中被强制/带入主方法节点。
- ChainExpression 替换为 OptionalMemberExpression 和 OptionalCallExpression
- ImportExpression 替换为 CallExpression,其
callee
是一个 Import 节点。
现在有一个 estree
插件可以还原这些偏差
JSX 代码的 AST 基于 Facebook JSX AST。
语义化版本
Babel 解析器在大多数情况下都遵循语义化版本。唯一需要注意的是,一些规范兼容性错误修复可能会在补丁版本中发布。
例如:我们推送了一个修复程序,用于修复类似 #107 的早期错误 - 每个文件有多个默认导出。这将被视为错误修复,即使它会导致构建失败。
示例
require("@babel/parser").parse("code", {
// parse in strict mode and allow module declarations
sourceType: "module",
plugins: [
// enable jsx and flow syntax
"jsx",
"flow",
],
});
插件
杂项
名称 | 代码示例 |
---|---|
estree (仓库) | 不适用 |
语言扩展
历史记录
版本 | 更改 |
---|---|
v7.6.0 | 添加了 v8intrinsic |
名称 | 代码示例 |
---|---|
flow (仓库) | var a: string = ""; |
flowComments (文档) | /*:: type Foo = {...}; */ |
jsx (仓库) | <a attr="b">{s}</a> |
typescript (仓库) | var a: string = ""; |
v8intrinsic | %DebugPrint(foo); |
ECMAScript 提案
历史记录
版本 | 更改 |
---|---|
v7.23.0 | 添加了 sourcePhaseImports 、deferredImportEvaluation 、optionalChainingAssign |
v7.22.0 | 默认启用 regexpUnicodeSets ,添加了 importAttributes |
v7.20.0 | 添加了 explicitResourceManagement 、importReflection |
v7.17.0 | 添加了 regexpUnicodeSets 、destructuringPrivate 、decoratorAutoAccessors |
v7.15.0 | 在 pipelineOperator 的 proposal 选项中添加了 hack 。将 topLevelAwait 、privateIn 移至最新的 ECMAScript 功能 |
v7.14.0 | 添加了 asyncDoExpressions 。将 classProperties 、classPrivateProperties 、classPrivateMethods 、moduleStringNames 移至最新的 ECMAScript 功能 |
v7.13.0 | 添加了 moduleBlocks |
v7.12.0 | 添加了 classStaticBlock 、moduleStringNames |
v7.11.0 | 添加了 decimal |
v7.10.0 | 添加了 privateIn |
v7.9.0 | 添加了 recordAndTuple |
v7.7.0 | 添加了 topLevelAwait |
v7.4.0 | 添加了 partialApplication |
v7.2.0 | 添加了 classPrivateMethods |
名称 | 代码示例 |
---|---|
asyncDoExpressions (提案) | async do { await requestAPI().json() } |
decimal (提案) | 0.3m |
decorators (提案)decorators-legacy | @a class A {} |
decoratorAutoAccessors (提案) | class Example { @reactive accessor myBool = false; } |
deferredImportEvaluation (提案) | import defer * as ns from "dep"; |
destructuringPrivate (提案) | class Example { #x = 1; method() { const { #x: x } = this; } } |
doExpressions (提案) | var a = do { if (true) { 'hi'; } }; |
explicitResourceManagement (提案) | using reader = getReader() |
exportDefaultFrom (提案) | export v from "mod" |
functionBind (提案) | a::b , ::console.log |
functionSent (提案) | function.sent |
importAttributes (提案)importAssertions (⚠️ 已弃用) | import json from "./foo.json" with { type: "json" }; |
importReflection (提案) | import module foo from "./foo.wasm"; |
moduleBlocks (提案) | let m = module { export let y = 1; }; |
optionalChainingAssign (提案) | x?.prop = 2 |
partialApplication (提案) | f(?, a) |
pipelineOperator (提案) | a |> b |
recordAndTuple (提案) | #{x: 1} , #[1, 2] |
sourcePhaseImports (提案) | import source x from "./x" |
throwExpressions (提案) | () => throw new Error("") |
最新的 ECMAScript 功能
以下功能已在最新版本的 @babel/parser
中启用,并且无法禁用,因为它们是语言的一部分。仅当您使用的是旧版本时,才应启用这些功能。
名称 | 代码示例 |
---|---|
asyncGenerators (提案) | async function*() {} , for await (let a of b) {} |
bigInt (提案) | 100n |
classProperties (提案) | class A { b = 1; } |
classPrivateProperties (提案) | class A { #b = 1; } |
classPrivateMethods (提案) | class A { #c() {} } |
classStaticBlock (提案) | class A { static {} } |
dynamicImport (提案) | import('./guy').then(a) |
exportNamespaceFrom (提案) | export * as ns from "mod" |
logicalAssignment (提案) | a &&= b |
moduleStringNames (提案) | import { "😄" as smile } from "emoji"; |
nullishCoalescingOperator (提案) | a ?? b |
numericSeparator (提案) | 1_000_000 |
objectRestSpread (提案) | var a = { b, ...c }; |
optionalCatchBinding (提案) | try {throw 0;} catch{do();} |
optionalChaining (提案) | a?.b |
privateIn (提案) | #p in obj |
regexpUnicodeSets (提案) | /[\p{Decimal_Number}--[0-9]]/v; |
topLevelAwait (提案) | 模块中的 await promise |
插件选项
历史记录
版本 | 更改 |
---|---|
7.21.0 | decorators 的 decoratorsBeforeExport 选项的默认行为是允许在 export 关键字之前或之后使用装饰器。 |
7.19.0 | recordAndTuple 插件的 syntaxType 选项默认为 hash ;为 decorators 插件添加了 allowCallParenthesized 选项。 |
7.17.0 | 在 hack 管道运算符的 topicToken 选项中添加了 @@ 和 ^^ |
7.16.0 | 为 typescript 插件添加了 disallowAmbiguousJSXLike 。在 hack 管道运算符的 topicToken 选项中添加了 ^ |
7.14.0 | 为 typescript 插件添加了 dts |
当多次指定一个插件时,只考虑第一个选项。
-
importAttributes
:-
deprecatedAssertSyntax
(boolean
, 默认为false
)当为
true
时,允许使用 已弃用 的assert
关键字解析导入属性。这与importAssertions
解析器插件最初支持的语法相匹配。
-
-
decorators
:-
allowCallParenthesized
(boolean
, 默认为true
)当为
false
时,不允许使用@(...)()
形式的装饰器,而应使用@(...())
。第 3 阶段装饰器提案使用allowCallParenthesized: false
。 -
decoratorsBeforeExport
(boolean
)默认情况下,导出类上的装饰器可以放在
export
关键字之前或之后。设置此选项后,将只允许在指定位置使用装饰器。JavaScript// decoratorsBeforeExport: true
@dec
export class C {}
// decoratorsBeforeExport: false
export @dec class C {}注意
-
此选项已弃用,将在未来版本中删除。当此选项显式设置为 true
或 false
时有效的代码,在此选项未设置时也有效。::
-
optionalChainingAssign
:version
(必填,可接受的值:2023-07
) 此提案仍处于第 1 阶段,因此很可能会受到重大更改的影响。您必须指定您正在使用的提案版本,以确保 Babel 将继续以兼容的方式解析您的代码。
-
pipelineOperator
:-
proposal
(必填,可接受的值:minimal
、fsharp
、hack
、(已弃用)) 管道运算符有几种不同的提案。此选项选择使用哪个提案。有关更多信息,包括比较其行为的表格,请参阅 plugin-proposal-pipeline-operator。smart
-
topicToken
(当proposal
为hack
时必填,可接受的值:%
、#
、^
、@@
、^^
)hack
提案在其管道中使用“主题”占位符。此主题占位符有两种不同的选择。此选项选择使用哪个标记来引用主题。topicToken: "#"
与syntaxType: "hash"
的recordAndTuple
不兼容。有关更多信息,请参阅 plugin-proposal-pipeline-operator。
-
-
recordAndTuple
:syntaxType
(hash
或bar
,默认为hash
)recordAndTuple
有两种语法变体。它们共享完全相同的运行时语义。语法类型 记录示例 元组示例 “hash”
#{ a: 1 }
#[1, 2]
“bar”
{| a: 1 |}
[|1, 2|]
有关更多信息,请参阅 #{}
/#[]
的人体工程学。
-
flow
:all
(boolean
,默认值:false
)某些代码在 Flow 和普通 JavaScript 中具有不同的含义。例如,foo<T>(x)
在 Flow 中被解析为带有类型参数的调用表达式,但在 ECMAScript 规范中被解析为比较(foo < T > x
)。默认情况下,仅当文件以// @flow
编译指示开头时,babel-parser
才会将这些不明确的结构解析为 Flow 类型。将此选项设置为true
以始终将文件解析为好像指定了// @flow
。
-
typescript
dts
(boolean
,默认值false
)此选项将启用在 TypeScript 环境上下文中进行解析,其中某些语法具有不同的规则(例如.d.ts
文件和declare module
块内部)。有关环境上下文的更多信息,请参阅https://typescript.net.cn/docs/handbook/declaration-files/introduction.html 和https://basarat.gitbook.io/typescript/type-system/intro。disallowAmbiguousJSXLike
(boolean
,默认值false
)即使未启用jsx
插件,此选项也不允许使用与 JSX 不明确的语法(<X> y
类型断言和<X>() => {}
类型参数)。它与解析.mts
和.mjs
文件时tsc
的行为相匹配。
错误代码
历史记录
版本 | 更改 |
---|---|
v7.14.0 | 添加的错误代码 |
错误代码对于处理 @babel/parser
引发的错误很有用。
有两个错误代码,code
和 reasonCode
。
code
- 错误的粗略分类(例如
BABEL_PARSER_SYNTAX_ERROR
、BABEL_PARSER_SOURCETYPE_MODULE_REQUIRED
)。
- 错误的粗略分类(例如
reasonCode
- 错误的详细分类(例如
MissingSemicolon
、VarRedeclaration
)。
- 错误的详细分类(例如
将错误代码与 errorRecovery
一起使用的示例
const { parse } = require("@babel/parser");
const ast = parse(`a b`, { errorRecovery: true });
console.log(ast.errors[0].code); // BABEL_PARSER_SYNTAX_ERROR
console.log(ast.errors[0].reasonCode); // MissingSemicolon
常见问题解答
Babel 解析器是否会支持插件系统?
我们目前不愿意承诺支持插件 API 或由此产生的生态系统(维护 Babel 自己的插件系统已经足够多了)。目前尚不清楚如何使该 API 有效,并且它会限制我们重构和优化代码库的能力。
我们目前对那些想要创建自己的自定义语法的人的建议是让用户 fork 解析器。
要使用您的自定义解析器,您可以将插件添加到您的选项中,以通过其 npm 包名称调用解析器,或者如果使用 JavaScript,则 require 它,
const parse = require("custom-fork-of-babel-parser-on-npm-here");
module.exports = {
plugins: [
{
parserOverride(code, opts) {
return parse(code, opts);
},
},
],
};