sosukesuzuki.dev

2022年 sosukesuzuki 1人アドベントカレンダー

December, 06 2022

ESTree とは

2022年の sosukesuzuki 1人アドベントカレンダー 6 日目です。

アドベントカレンダー飽きてきて文章が適当になってきている気がする。

概要

ESTree とは JavaScript の AST の仕様です。

https://github.com/estree/estree で Markdown として管理されています。

AST を表現する独自の構文(README では AST Descriptor Syntax として説明されている)を使って、JavaScript の各構文の AST の形を定義しています。

たとえば ArrayExpression (配列リテラル) の定義はこのようになっています。

interface ArrayExpression <: Expression {
    type: "ArrayExpression";
    elements: [ Expression | null ];
}

1 行目の <:implements のような意味です。すなわち ArrayExpressionExpression を実装しているということで、ArrayExpressionExpressionであるということです。

2 行目の type は、単に名前です。ここでは "ArrayExpression" です。

3 行目の elements は配列の要素のことです。ArrayExpressionelements は配列で、その要素は Expression もしくは null です。

配列リテラルの要素が Expression (式) であるというのはすぐわかると思います。

const arr = [1, "foo", bar(), hoge];

Expression | nullnull は、null リテラルのことではなく、empty のことです。

const arr = [, , , , ,];

null リテラルは ESTree においては他のリテラルと一緒に Literal として次のように定義されていて、Expression に属すからです(valuenull のときが null リテラル)。

interface Literal <: Expression {
    type: "Literal";
    value: string | boolean | null | number | RegExp;
}

このような定義が JavaScript のすべての構文に対して、バージョンごとにファイルを分けて定義されています。

何のためにあるのか

この ESTree という仕様は Web 標準ではなく、ガバナンス的には TC39 とはなんの関係もありません。

では何のために維持されているのでしょうか。実は公式に説明はないので維持に携わっている人がどう考えているかはわかりません(公式な説明、あるのか?)。

そこで活動実態やメンバーを見て推測すると、ESLint や Babel などのツールが扱う AST に差異が生じすぎないようにするために維持されているのだと考えられます。

ESLint や Babel や typescript-eslint は、それぞれが別のパーサーを使っています。そこでそれぞれが全く別の AST を吐くようになっていると、それらのツール間を協調して扱うのが難しくなります(Prettier なんかはそれらのパーサーを一貫して扱いたいのでめっちゃ困る)。

ということで、ある程度共通した AST の仕様を共同でメンテして、概ねそれに準拠したパーサーを扱おうという雰囲気があります。

重要なのは ESTree は ECMA-262 のようなちゃんとした仕様ではなく、各ツール間の AST 表現についてのゆるい約束事という感じなので完全に準拠する必要はありません。実際必要に応じて拡張・改変されて使われています。

誰がメンテしているのか

Babel や ESLint、Acorn のメンテナーが ESTree Steering Comittee としてメンテナンスをしています。また、他にも typescript-eslint のメンテナーや Prettier のメンテナーなど、JavaScript(や TypeScript) のパーサーやそのユーザーが関わっています。

経緯

実は筆者は ESTree 誕生の経緯について知らななかったのですが、README によると

Once upon a time, an unsuspecting Mozilla engineer created an API in Firefox that exposed the SpiderMonkey engine's JavaScript parser as a JavaScript API. Said engineer documented the format it produced, and this format caught on as a lingua franca for tools that manipulate JavaScript source code. Meanwhile JavaScript is evolving. This site will serve as a community standard for people involved in building and using these tools to help evolve this format to keep up with the evolution of the JavaScript language.

(estree/estreeの README から引用)

とのことです。

雑に解釈すると、昔々 Mozilla のエンジニアが SpiderMonkey の JavaScript パーサーの API を公開しそのフォーマットをドキュメントとして公開したところ流行ってしまい、それを最近の JavaScript にも対応させつつ進化させているということみたいです。

ESTree (風)を出力するパーサーライブラリ

https://zenn.dev/sosukesuzuki/scraps/fa4d48f9098d66 にまとめてるのでそっちをご覧ください。