ESLint のルールを TypeScript で実装してみる

eslint-plugin-vue-scoped-cssが TypeScript(以下 TS)で書かれていたので、気になったので、TS で ESLint のルールを作成し、プラグインとして公開するまでの手順を紹介する。

実装した repo はこちら

TS で作る環境を整える

  • typescript
  • eslint
  • @types/eslint
  • @types/estree
    を使う
    ts-node は、test のときにあると便利。

TS の module は、ESLint が commonjs でのプラグインを許容してるので、合わせて
"module": "commonjs" とする。

ルールを作る

@types/eslintでは、namespace でRuleが export されているので、ルール作るときはこれを使う。
型がある程度実装されているので、そこからは JS で書くように普通に実装していく。
ハマったところとしては、

type NodeListener = { [T in NodeTypes]?: (node: ESTree.Node) => void };

となっていて、

import { Rule, RuleTester } from "eslint";

const rule: Rule.RuleModule = {
  meta: {...},
  create(context) {
    return {
      Identifier(node) {
        if (node.type !== "Identifier") {
          return;
        }
      },
    };
  },
};

export = rule;

というように、node.typeでタイプガードしないと型が効かないというところだけだった。

テストを書く

mocha を使うので、ts-node に書いてあるように require オプションに ts-node/register を指定してテストを実行する
GitHub - TypeStrong/ts-node: TypeScript execution and REPL for node.js

@types/eslintでは、class でRuleTesterが export されているのでそれを使っていつもどおりテストを書いていく。

build、release する

eslint plugin として公開するときには js にビルドしておかないとダメなので、CI とか手元とかでビルドして npm release する。
以上で終わり。

終わりに

意外と簡単だったが、vue-eslint-parser なんかと組み合わせたらたぶん沼になっていくんだろうなぁという感じ。
TS で ESLint プラグインを作る情報全然見当たらないし知らないので、これから作っていく人はどんどん TS で作って、情報を共有してくれ!!

おまけ

@typescript-eslint/experimental-utils

typescript-eslint がルールを作る際に使用している @typescript-eslint/experimental-utilsは、うまく型を独自で定義してあるっぽかった。
@types/eslintのかわりにこっちを使っても良さそう。

eslint-ast

ESLint コアメンバーの mysticatea さんの mysticatea/eslint-astでは、AST の型を定義している。

今後に期待できそう。