Slide 1

Slide 1 text

@unvalley_ Biomeの裏側 Parser / Linter 1

Slide 2

Slide 2 text

About me - unvalley - A core contributor of Biome - TypeScript / Rust / Scala @unvalley_ unvalley 2

Slide 3

Slide 3 text

Biome - One toolchain for your web project - パフォーマンスに優れたRust製のWebツールチェーン - Analyzer / Linter / Formatterを提供(CLI, LSP, WASMで利用可能) - Prettierと約97%の互換性(対象はJS, TS, JSX のフォーマット) - 190以上のLintルールを実装(ESLintなどからの移植や固有のもの) - Sponsored by: 時雨堂, トヨクモ, 要, nanabit, GitHub sponsors 3 Rome Biome

Slide 4

Slide 4 text

4 Astro.build Ben’s impression! https://x.com/BHolmesDev/status/1733622553925869976?s=20

Slide 5

Slide 5 text

5 Roadmap 2024

Slide 6

Slide 6 text

Roadmap 2024 - Help users to move to Biome - Expand Biome’s language support so Biome tools can span more of the web ecosystem - Deepen Biome’s existing capabilities to offer more functionalities - Plugins - Transformations - Community and content https://biomejs.dev/blog/roadmap-2024/ 6

Slide 7

Slide 7 text

Biomeを試す 7 - npm, yarn, pnpm, deno, bunで利用できます - Homebrewでもインストール可能:brew install biome - 業務で使ってるプロジェクトやOSSなどで試してみてください - Docs : https://biomejs.dev - Playground : https://biomejs.dev/playground npx @biomejs/biome check --apply . // format and lint with npx

Slide 8

Slide 8 text

1. Parser 8

Slide 9

Slide 9 text

処理の簡単な流れ 9 Lexing Parse Analyze / Lint / Format Tree Source Code Result

Slide 10

Slide 10 text

処理の簡単な流れ 10 Lexing Parse Analyze / Lint / Format Tree Source Code Result

Slide 11

Slide 11 text

Biome Parser (crates/biome_parser) - BiomeのParserの基盤 - biome_{js/json/css}_parser から利用して、それぞれのparse処理を実装している - lex処理もbiome_parser crate内に実装されている - Green and Red Treeを利用する - Parseプロセスで、Green Tree(コードに忠実で不変なデータ構造)と Red Tree (Green Treeから構築される親子関係の情報を持つ可変な データ構造)を生成する手法 - Lossless: コードが不正な場合でも、Parserはツリーを正確に表現する - Resillient: コードが不正な場合でも、Parserは入力に含まれる構文の断 片を可能な限り見ようとする 11

Slide 12

Slide 12 text

Rowan (rust-analyzer/rowan) - Rust AnalyzerチームによるGreen/Red Treeを実装したライブラリ - Biomeでは、biome_rowan crateを利用して、Green and Red Treeを作成し ている 12 解説:https://github.com/rust-lang/rust-analyzer/blob/master/docs/dev/syntax.md

Slide 13

Slide 13 text

Green Tree (CST) - コード内のトリビア* を含むすべて の情報を持つ、不変なデータ構造 - SyntaxKindとテキスト長を持つ - コードが変更されたら、部分的に再 構築して既存のツリーと統合する - Biomeのコード上、直接アクセスは できない *スペース・タブ・コメントなど 13

Slide 14

Slide 14 text

Red Tree - Green Treeから計算される可変な データ構造 - Green Treeから、Red Tree (SyntaxNodes)を生成し、それ を型定義されたAST Nodesに変換 - Lint Rule実装などにおいては、 AST Nodesに対して、クエリを行 い、処理する - 親子関係の走査も可能 (SyntaxNodesのメソッド参照) 14 Red Treeから変換して生成されるAST Node

Slide 15

Slide 15 text

15 Input: function} - tokenなどが欠落(missing) した状態でもTreeを構築 - JsBogusStatementで 不正なNodeとして処理 Error Resilient

Slide 16

Slide 16 text

16

Slide 17

Slide 17 text

2. Linter (Analyzer) 17

Slide 18

Slide 18 text

処理の簡単な流れ 18 Lexing Parse Analyze / Lint / Format Tree Source Code Result

Slide 19

Slide 19 text

Analyzer関連crateの依存 19 biome_service biome_json_analyze biome_analyze biome_js_analyze biome_css_analyze biome_cli biome_lsp

Slide 20

Slide 20 text

Analyzer関連crateの依存 20 biome_service biome_json_analyze biome_analyze biome_js_analyze biome_css_analyze biome_cli biome_lsp

Slide 21

Slide 21 text

biome_js_analyze と biome_analyze の構造 21 biome_json_analyze biome_analyze biome_js_analyze biome_css_analyze 1. biome_js_analyze には、各種Ruleが実 装されている(n>=190) 2. biome_js_analyze で、 biome_analyze::Analyzer を用意し、 Analyzer::run を実行 3. 各種Lint Ruleの診断結果とコードアク ションを収集 (Analyzer::emit_signal) Lint Rule Lint Rule Lint Rule

Slide 22

Slide 22 text

22 起点となる構造体 : biome_analyze::Analyzer

Slide 23

Slide 23 text

biome_analyze::Analyzer の処理 1. biome_js_analyze から biome_analyze::Analyzer instance を作成 2. Analyzer::run メソッドでanalyzeを開始 - biome_analyze::PhaseRunner が、各Phaseにおいて Visitor にAstNodeに対する 特定のanalyzeタスクを実行させ、診断結果・コードアクションなどを生成 - Suppression Comment (// biome-ignore) の解析と適用 23

Slide 24

Slide 24 text

24

Slide 25

Slide 25 text

biome_js_analyze と biome_analyze の構造 25 biome_json_analyze biome_analyze biome_js_analyze biome_css_analyze 1. biome_js_analyze には、各種Ruleが実 装されている(n>=190) 2. biome_js_analyze で、 biome_analyze::Analyzer を用意し、 Analyzer::run を実行 3. 各種Lint Ruleの診断結果とコードアク ションを収集 (Analyzer::emit_signal) Lint Rule Lint Rule Lint Rule

Slide 26

Slide 26 text

26 起点 : biome_js_analyze::analyze (analyze_with_inspect_matcher)

Slide 27

Slide 27 text

JS用Analyzerのsetup : biome_js_analyze::analyze 1. 解析に必要なデータを引数で受け取る - root: AnalyzeするJavaScriptコードのルートノード - filter: Analyzeを制限するためのフィルター(特定のルールやソース範囲を指定) - options: Analyzeオプション(biome.jsonの設定) - source_type: Analyzeするソースコード種類(例:JSX、モジュールなど) - emit_signal: Lint Ruleが診断やアクションを発行した際に呼ばれる関数 2. biome_analyze::RuleRegistry (ActiveなLint Ruleの管理者) の構築 3. biome_analyze::Analyzer の初期化 4. 解析Phaseごとのbiome_analyze::Visitor の追加 5. biome_analyze::AnalyzerContextに、引数で得たデータを渡して、Analyzer::run を 実行 27

Slide 28

Slide 28 text

28 起点 : biome_js_analyze::analyze (analyze_with_inspect_matcher) 1. 解析に必要なデータを引数で受け取る

Slide 29

Slide 29 text

29 起点 : biome_js_analyze::analyze (analyze_with_inspect_matcher) 2. biome_analyze::RuleRegistryの構築

Slide 30

Slide 30 text

30 起点 : biome_js_analyze::analyze (analyze_with_inspect_matcher) 3. biome_analyze::Analyzer の初期化

Slide 31

Slide 31 text

31 起点 : biome_js_analyze::analyze (analyze_with_inspect_matcher) 4. 解析Phaseごとのbiome_analyze::Visitorの追加

Slide 32

Slide 32 text

32 起点 : biome_js_analyze::analyze (analyze_with_inspect_matcher) 5. biome_analyze::AnalyzerContextに、引数で得たデータを渡して、 Analyzer::run を実行

Slide 33

Slide 33 text

33 起点 : biome_js_analyze::analyze (analyze_with_inspect_matcher)

Slide 34

Slide 34 text

biome_js_analyze と biome_analyze の構造 34 biome_json_analyze biome_analyze biome_js_analyze biome_css_analyze 1. biome_js_analyze には、各種Ruleが実 装されている(n>=190) 2. biome_js_analyze で、 biome_analyze::Analyzer を用意し、 Analyzer::run を実行 3. 各種Lint Ruleの診断結果とコードアク ションを収集 (Analyzer::emit_signal) Lint Rule Lint Rule Lint Rule

Slide 35

Slide 35 text

35 Lint Rule: NoUselessTernary Disallow ternary operators when simpler alternatives exist. (単純な代替が存在する場合に、三項演算子を許可しない)

Slide 36

Slide 36 text

36 var a = x ? true : true; をどうやってLintする? Parser処理後に構築されたAST Node: JsConditionalExpressionに Queryすれば、三項演算子をチェックできる

Slide 37

Slide 37 text

37 Lint Rule: NoUselessTernary (簡略版)

Slide 38

Slide 38 text

処理のまとめ 38 Lexing Parse Analyze / Lint / Format Tree Source Code Result biome_parserでError ResillientなParseを行い、 biome_rowanでGreen and Red Treeを構築する

Slide 39

Slide 39 text

処理のまとめ 39 Lexing Parse Analyze / Lint / Format Tree Source Code Result Analyzerのコアであるbiome_analyzeを基盤として、Tree を元に、biome_js_analyzeなどで実装したLint Ruleを適用 して、診断結果やコードアクションを生成する

Slide 40

Slide 40 text

処理のまとめ 40 Lexing Parse Analyze / Lint / Format Tree Source Code Result biome_parserでError ResillientなParseを行い、 biome_rowanでGreen and Red Treeを構築する Analyzerのコアであるbiome_analyzeを基盤として、Tree を元に、biome_js_analyzeなどで実装したLint Ruleを適用 して、診断結果やコードアクションを生成する

Slide 41

Slide 41 text

41

Slide 42

Slide 42 text

Biome Community - X: https://x.com/biomejs (@biomejs) - GitHub: https://github.com/biomejs/biome (@biomejs) - Discord: https://discord.com/invite/BypW39g6Yc 42

Slide 43

Slide 43 text

余談:個人的に好きなLintルール - noExcessiveCognitiveComplexity: (v1.0.0) - 認知複雑度の高いコードを禁止するlint - useFilenamingConvention (v1.5.0) - ファイル名を一貫したものにするlint - useImportRestrictions (v1.0.0) - privateなpackageからのimportを禁止するlint - uhyoさんのeslint-plugin-import-accessにinspireされている 43

Slide 44

Slide 44 text

参考資料 - biomejs.dev (https://biomejs.dev) - Deep Dive into Biome (https://speakerdeck.com/nissydev/deep-dive-into-biome-in-jsconf-2023) - Rust Dublin October 2023 - Biome (https://youtu.be/stxiUYmHn0s?si=VyLdx33ZbK3Kq2iX) - Persistence, Facades and Roslyn's Red-Green Trees (https://learn.microsoft.com/en-us/archive/blogs/ericlippert/persistence-facades-and-roslyns-red-green-trees) - Syntax in rust-analyzer (https://github.com/rust-lang/rust-analyzer/blob/master/docs/dev/syntax.md) - LintオタクによるLint解説(https://speakerdeck.com/orgachem/lintotakuniyorulintjie-shuo) 44