🧊

sveltejs/esrap のコードを読む

ClaudeCodeにしろ、DeepWikiにしろ、便利ではあるけどやっぱりなんか物足りなくて、結局自分で読んじゃうのよな・・・。

esrapとは

sveltejs/esrap: Parse in reverse https://github.com/sveltejs/esrap/

Svelteコンパイラの中でも使われてるライブラリで、

  • sveltejs/acorn-typescriptでパースしたASTを
  • Rich-Harris/zimmerframewalkして更新してから
  • sveltejs/esrapでコード文字列に戻す

この最後の、AST-to-stringのステップを担うパーツ。

https://github.com/sveltejs/svelte/blob/2342c8719a555783ba1d6d4a6dec3c2e30dca8e0/packages/svelte/src/compiler/phases/3-transform/index.js#L37

できること・できないこと

acornでパースしたJSのASTを文字列化することはできる。おそらくacornじゃなくても、ESTree ASTなら対応してる。

ただし、acorn-jsxのような拡張は考慮していないようで、JSXXxxなノードが現れるとエラーになってしまう。まぁ.svelteでJSXを書くことはないからな・・・。

TSについては、sveltejs/acorn-typescriptでパースしたTSのASTの文字列化もできると書いてある。

が、コードを追ってみるとサポートは完全ではないようで、目grepする限り、結構いろんな型がサポートされてないように見える。

@typescript-eslint/typescript-estreeでは、79種類のTSXxxノードが定義されてるけど、40ちょいくらいしかサポートされてなさそう・・・? (というかそもそも、acorn-typescriptのSpecが見当たらないし、typescript-estreeと同一の構造というわけでもなさそうだった)

そもそも、Svelteコンパイラのユースケースでは、ASTから型のノードを消し去ってからesrapに投げてそうだった・・・。

https://github.com/sveltejs/svelte/blob/2342c8719a555783ba1d6d4a6dec3c2e30dca8e0/packages/svelte/src/compiler/phases/1-parse/remove_typescript_nodes.js#L23

ソースマップには対応してて、いわゆるリレーもできるようになってる。

あとはコメントの出力にも対応してる。 が、ASTノードの任意の位置にleadingCommentstrailingCommentsというプロパティを事前に差し込んでおく必要がある。

いわゆるattachComments()的な実装は含まれておらず、テストコードに簡易な実装だけあった。

https://github.com/sveltejs/esrap/blob/31e5a4096adb533a1ed2dbe970dab7a7d9488bad/test/common.js#L14

実装

端的に言うと、軽量なPrettierだった。ASTをまずはIRにして、それを文字列にしてる。 (ただし絶対的な違いとして、たった2ファイルしか実装がない!読みやすい!)

以上。

感想

実装としてはシンプルで、特に気になるところはなかった。

しかしTSの型サポートが中途半端なのは、優先度の問題なのかポリシーの問題なのかが気になるところ。まぁJSXと同じで、Svelteコンパイラとして必要ないからサポートされてない気がする。

どこまでPrettyに文字列化するかは厳密ではなく、テストケースも70パターンくらいしかなかった。

コメントに関しては、Prettierと比べるとそもそもdanglingCommentsの扱いがなかったりと、思い切った割り切りを感じる。まあ仕方ない。うん、だって、仕方ないあれは。

同じような役割のライブラリとしては、astringもある。

davidbonnet/astring: 🌳 Tiny and fast JavaScript code generator from an ESTree-compliant AST. https://github.com/davidbonnet/astring

こっちは、IRを持たないより簡素な実装になっていつつ、ハンドラは外部から拡張できるようになってる。

JSXとTSのサポートは、それぞれ本家ではない野良プラグインがあるという感じ。