Closed5
no-restricted-syntax でお手軽にカスタムルールを追加する
TL; DR
ここに書いてあるので、AST 操作をしたことある人はこれと公式 Docs を読めば OK
ここからは AST 操作したことない人向け
そもそも AST とは?
AST = Abstract Syntax Tree、抽象構文木
文字列であるソースコードを解析して、 ツリー状に表現したもの。プログラムに本質的に関係のないコメントとかスペースとかはなくなることが多い。
(brn さんのスライドは大変素晴らしいので読んでみると良いよ)
ソースコードの AST を確認したいときは AST explorer を使う
no-restricted-syntax
AST に対する query とエラー文言を定義すると、query にマッチしたものに error を報告するというルール。
見てもらったほうが速そうなので、早速今回実装したものを見せる
- スタイルの確認は VRT でしたいので、toHaveCSS 系のメソッドを使わないようにしたい
- lib/date.ts に日付操作用の関数を集約しているので、Intl.DateFormat を使えわないようにしたい
'no-restricted-syntax': [
'error',
{
selector: 'MemberExpression[property.name=/toHaveCSS|toHaveStyle/]',
message: '見た目を確認するには、CSS のチェックではなく VRT などを検討してください。',
},
{
selector: "MemberExpression[object.name='Intl'][property.name='DateTimeFormat']",
message:
'日付操作を行う場合は、基本的に date-fns を使用してください。src/lib に日付操作の関数も定義されています。',
},
],
AST に慣れてないと selector の定義見ても、こんな感じになるよね

selector の実装方法
禁止したい構文の ASTをチェックする
test('test', async ({ page }) => {
// これを禁止したい
await expect(page.locator('....')).toHaveCSS('font-size', '16px');
});
↑のコードを AST explorer に貼り付ける

AST explorer を見るときのポイント
- parser の設定は確認しよう
- ESLint のルールを書くときは ESLint 系の parser を選ぼう
- チェックしたい箇所をダブルクリックすると便利だよ
- ダブルクリックした箇所に対する AST にフォーカスが移動するよ
構文に対するクエリを書いてみる
AST を見てわかったこと
- "toHaveCSS" が格納されているノードは MemberExpression になっている
- ノードはただの object だと思って貰えればよい
- "toHaveCSS" が格納されているフィールドは "property" になっている
- "toHaveCSS" は Identifier というノードの name フィールドに格納されている
これを query に変換すると次のようになる
MemberExpression[property.name=/toHaveCSS|toHaveStyle/]
クエリの詳細の仕様は、次のドキュメントにかかれている。基本的になんでもできる。
クエリがうまくいくかどうかは次の playground でも確認できる
練習
- Intl.DateFormat の利用を禁止する
- グローバル空間での定数宣言は必ず大文字 or undescore で定義されることを強制する
-
const AAA_BBB = 1みたいなこと
-
2つ目の解答
以下のクエリで大文字 or undescore 以外を使った場合にマッチできる
Program > VariableDeclaration > VariableDeclarator[id.name=/^[^A-Z_]+$/][init.type="Literal"]
以下だとグローバル空間でないのも拾ってしまうのでだめ
VariableDeclaration > VariableDeclarator[id.name=/^[^A-Z_]+$/][init.type="Literal"]
以下だと Literal 以外の arrow 関数とかも拾ってしまうのでだめ
Program > VariableDeclaration > VariableDeclarator[id.name=/^[^A-Z_]+$/]
このスクラップは2024/02/26にクローズされました