🧊

`@typescript-eslint/parser`と`@typescript-eslint/typescript-estree`の関係

ちゃんと区別できてなくて、地味に誤解してたことに気付いたのでメモしておく。

それぞれの役割

最初はestreeのほうが表向きのパッケージで、内部的にparserを使ってるのかと思ってたけど、まったくの逆だった。

parserこそがESLintのための表向きのパッケージで、純粋にASTだけ取り出したい場合は、typescript-estreeのほうをそのまま使えばよさそう。

parser側のコード

2つの関数がexportされてる。

で、parseForESLint()のここで、typescript-estreeparseAndGenerateServices()を呼び出すことで、ASTを作ってる。

https://github.com/typescript-eslint/typescript-eslint/blob/e7f5e36ecb65002c1ab1e67359cab1527192c471/packages/parser/src/parser.ts#L143

そもそもparserのほうのパッケージは中身が薄くて、200行くらいしかない。

ASTのパース以外には、scope-managerでスコープ解析したりもしてる。

typescript-estree側のコード

(わかりにくいことに)こっちも2つの関数をexportしてる。

まずparse()だが、こっちはparseWithNodeMapsInternal().astを返すだけで、いたってシンプル。

注意点として、parse()のほうでは、errorOnTypeScriptSyntacticAndSemanticIssuesオプションが使えない。

つまりTSCが拾った構文エラーは検知できるけど、意味論的なエラーは検知できないってこと。これを検知したい場合は、parseAndGenerateServices()のほうを使えっていうエラーになる。

つぎにparseAndGenerateServices()では、parse()で返すASTに加えて、TSのProgramを作ってる。

そのおかげで、意味論的なエラーまでも検知することができてるってわけ。

https://github.com/typescript-eslint/typescript-eslint/blob/e7f5e36ecb65002c1ab1e67359cab1527192c471/packages/typescript-estree/src/parser.ts#L268

まとめ

@typescript-eslintでは、parsertypescript-estreeパッケージから、それぞれ以下4種類のパース関数でASTを取得できる。

typescript-estreeにあるもののほうが、よりプリミティブな用途になってて、

  • typescript-estree/parse()
    • 構文エラーあり、意味論的エラーなし
  • typescript-estree/parseAndGenerateServices()
    • 構文エラーあり、意味論的エラーあり

parserにあるのはtypescript-estreeのラッパーでしかなく、

  • parser/parseForESLint()
    • parseAndGenerateServices()を呼びつつ、スコープ解析なんかもやる
  • parser/parse()
    • parseForESLint().astを返すだけ

という感じ。

ということを、Prettierのtypescriptパーサーが有効にしてるsuppressDeprecatedPropertyWarningsというオプションを追うために調べてた。

ちなみにPrettierのtypescriptパーサーでは、最もプリミティブなtypescript-estree/parse()が使われてる。

https://github.com/prettier/prettier/blob/18cd9a978201cd16eb75ab5549bb6e4a5abf7d27/src/language-js/parse/typescript.js