9 个版本 (4 个重大更改)

0.5.7 2024年3月12日
0.5.6 2024年3月12日
0.4.0 2024年1月9日
0.3.1 2023年11月26日
0.0.2 2023年9月28日

#497 in 网页编程

Download history 104/week @ 2024-04-08 76/week @ 2024-04-15 42/week @ 2024-04-22 56/week @ 2024-04-29 43/week @ 2024-05-06 116/week @ 2024-05-13 222/week @ 2024-05-20 247/week @ 2024-05-27 301/week @ 2024-06-03 75/week @ 2024-06-10 59/week @ 2024-06-17 63/week @ 2024-06-24 37/week @ 2024-07-01 45/week @ 2024-07-08 178/week @ 2024-07-15 2454/week @ 2024-07-22

2,728 下载/每月
3 crates 中使用

MIT/Apache

4.5MB
108K SLoC

Biome - Toolchain of the web

Discord chat cargo version

biome_js_parser

Biome 的 JavaScript 解析器实现。请参考 文档


lib.rs:

极快、无损且容错的 JavaScript 解析器。

解析器使用对非空白标记的抽象。这允许我们无损或带损地解析代码,而无需显式处理空白。解析器产生事件,而不是 AST,这些事件被解析为未类型化的语法节点,然后可以将其转换为类型化的 AST。

解析器能够从任何源代码生成有效的 AST。错误生成被包装在 ERROR 语法节点中,原始源代码在最终的语法节点中完全表示。

除非您想要解析 JavaScript 源代码片段或创建自己的生成,否则通常不需要使用解析器结构。相反,使用诸如 [parse_script]、[parse_module] 等函数,这些函数提供了抽象化的解析版本。

为了更精细的控制,请使用 parse 或 [parse_js_with_cache]。

解析器的显著特性包括

  • 通过极快的词法分析器实现极快的解析和词法分析。
  • 能够根据需要执行带损或无损解析,无需显式处理空白。
  • 可定制,能够根据您的意愿解析任何 JS 代码片段。
  • 完全容错,能够从任何源代码生成 AST。
  • 将未类型化节点转换为类型化 AST 时无需开销。
  • 能够轻松地以几乎零成本从AST到SyntaxNodes、SyntaxTokens再到源代码以及反向转换。
  • 通过SyntaxNode轻松进行树遍历。
  • 带有多个标签和注释的描述性错误。
  • 克隆成本极低,克隆AST节点或语法节点相当于向Rc添加一个引用的成本。
  • 便宜的改变文本的增量重新解析。

该包还包括以下实用工具

  • 通过lexer对节点或文本进行ANSI语法高亮。

它受到rust analyzer解析器的启发,但适用于JavaScript。

语法节点与AST节点对比

该包依赖于无类型的biome_js_syntax::JsSyntaxNode与有类型的biome_rowan::AstNode的概念。语法节点以无类型的方式表示语法树。它们使用两个指针表示不可变树中的位置。语法树由biome_js_syntax::JsSyntaxNodebiome_js_syntax::JsSyntaxToken以嵌套树结构组成。每个节点可以有父节点、兄弟节点、子节点、后代节点等。

biome_rowan::AstNode代表语法节点的有类型版本。它们与语法节点有相同的表示形式,因此两者之间的转换没有运行时成本。AST节点中的每个数据项都是可选的,这是由于解析器完全容错。

每种表示方法都有其优点

SyntaxNodes

  • 通过它们上的函数轻松遍历语法树。
  • 可以轻松地将它们转换为底层的文本、范围或标记。
  • 包含与底层生成相关联的所有空白(在无损解析的情况下)。
  • 可以以零成本轻松转换为其有类型表示。
  • 可以使用fmt debug转换为美观的表示。

AST Nodes

  • 可以轻松访问底层生成属性。
  • 转换为语法节点没有成本。

总之,使用这两种表示方法意味着我们不受限于通过有类型节点进行操作。这使得遍历变得困难,并且你经常不得不求助于自动生成的访问者模式。AST节点是简单访问语法节点子属性的一种方式。

解析器测试

解析器测试是以testtest_err开始的注释,后跟测试名称,然后是单独一行上的代码。

// test js feature_name
// let a = { new_feature : "" }
// let b = { new_feature : "" }
fn parse_new_feature(p: &mut Parser) -> ParsedSyntax {}
  • test:测试有效程序。不应产生任何诊断信息或缺失节点。
  • test_err:测试有语法错误的程序。必须产生诊断信息。

默认情况下,测试作为JavaScript模块运行。您可以通过指定文件类型来自定义源类型,文件类型位于testtest_err之后。

// test ts typescript_test
// console.log("a");
if a {
    // ..
}

支持以下源类型

  • js
  • jsx
  • ts
  • tsx
  • d.ts

要启用脚本模式,请在代码中添加一个// script注释。

要提取测试用例,运行cargo codegen test。在添加、更改或删除内联测试时,运行codegen是必需的。

要更新测试输出,请运行

Linux/MacOs:

env UPDATE_EXPECT=1 cargo test

Windows

set UPDATE_EXPECT=1 & cargo test

依赖项

~9–19MB
~240K SLoC