Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Speaker Deck
PRO
Sign in
Sign up for free
ESLintの独自ルール作成にチャレンジした話
meijin
January 19, 2022
Technology
2
180
ESLintの独自ルール作成にチャレンジした話
https://rakus.connpass.com/event/232039
meijin
January 19, 2022
Tweet
Share
More Decks by meijin
See All by meijin
初めてエンジニアインターンの育成に取り組んで考えたこと
texmeijin
0
760
シード期スタートアップで 2年半カイゼンしてきたこと
texmeijin
1
120
一部上場企業からベンチャー転職のBefore/After
texmeijin
0
280
次世代フロントエンドツールVite入門会
texmeijin
0
430
microCMSを使った ビジネスサイドとの コミュニケーション
texmeijin
2
550
国産OSS_aspida_の_公認エバンジェリストに_任命してもらった話.pdf
texmeijin
1
180
React Native×Firebaseで オンライン指導用の チャットアプリを開発している話
texmeijin
0
1.6k
管理画面付きAPIが簡単に作れるmicroCMSとの向き合い方まとめ
texmeijin
1
900
docker-compose × Firebase Emulator でローカル環境構築
texmeijin
0
4k
Other Decks in Technology
See All in Technology
事業の成長と共に歩む、ABEMA SRE探求の歴史 / SRE-Next 2022
nagaa052
0
460
TypeScript 4.7と型レベルプログラミング
uhyo
6
3.5k
SRENEXT2022 組織にSREを実装していくまでの道のり
marnie0301
1
720
成長を続ける組織でのSRE戦略:プレモーテムによる信頼性の認識共有 SRE Next 2022
niwatakeru
7
2.9k
LIFF Deep Dive 2022
line_developers
PRO
1
740
[AKIBA.AWS] それ、t2.micro選んで大丈夫?
tsukuboshi
0
370
プロダクトの理想と現実はなぜ乖離しがち?プロダクト作りに潜む問題を考える
suzukentaro
0
210
長年運用されてきたモノリシックアプリケーションをコンテナ化しようとするとどんな問題に遭遇するか? / SRE NEXT 2022
nulabinc
PRO
15
8k
Server-side Kotlin in LINE Messaging API
line_developers
PRO
0
150
ドキュメントの翻訳に必要なこと
mayukosawai
0
180
New Features in C# 10/11
chack411
0
1k
[SRE NEXT 2022]メルカリグループにおけるSREs
srenext
0
470
Featured
See All Featured
Designing the Hi-DPI Web
ddemaree
272
32k
The Cult of Friendly URLs
andyhume
68
4.7k
The Most Common Mistakes in Cover Letters
jrick
PRO
4
24k
Designing on Purpose - Digital PM Summit 2013
jponch
106
5.6k
RailsConf & Balkan Ruby 2019: The Past, Present, and Future of Rails at GitHub
eileencodes
119
28k
How To Stay Up To Date on Web Technology
chriscoyier
780
250k
Design and Strategy: How to Deal with People Who Don’t "Get" Design
morganepeng
103
16k
Faster Mobile Websites
deanohume
294
28k
How STYLIGHT went responsive
nonsquared
85
3.9k
jQuery: Nuts, Bolts and Bling
dougneiner
56
6.4k
Music & Morning Musume
bryan
35
4.2k
Art Directing for the Web. Five minutes with CSS Template Areas
malarkey
196
9.4k
Transcript
ESLint の独自ルール作成に チャレンジした話 株式会社 NoSchool meijin
目次 独自ルールを作ろうと思ったきっかけ 作って適用する手順 独自ルールの作りかた テストの書きかた 補足① TypeScript 対応 補足② 運用手段の候補
余談 勉強会の主催 まとめ
自己紹介 ニックネームは「名人」 Twitter: @Meijin_garden Web エンジニア6 年目 株式会社NoSchool CTO オンライン家庭教師マナリンク
-> https://manalink.jp 好きな分野はWeb フロントエンド 最近はWYSIWYG ライブラリのSlate.js に感動した 趣味は将棋(アマチュア二段くらい)
独自ルールを作ろうと思ったきっかけ ESLint って気軽にコードの品質を統一できて便利やな〜 業務上で、「今後はこのライブラリは使わないで欲しい」とか「この便利関数作ったからみんな使ってね」とい ったローカルルールを、レビューではなくLint で縛れたらいいな〜 でも、ESLint のルールって字句解析の知識とかないと作るの大変そう… → ちょっと作ってみるか!
独自ルールの大まかな手順 今回は以下の手順で独自ルールを動作させることができた。 独自ルールを記述したJavaScript(or TS) ファイルを作成して、 rules ディレクトリに置く npm scripts で
"lint": "eslint --rulesdir rules" のように記述して実行 ※ --rulesdir オプションはDeprecated なので、他の方法が有力(後述) https://eslint.org/docs/user-guide/command-line-interface
独自ルールの記述方法
本家のドキュメント 「Working with Rules 」 https://eslint.org/docs/developer-guide/working-with-rules 英語かつものすごく長く、(個人的には)理解に時間がかかるので、日本語の文献や巷のライブラリのコードを読み つつ進めるのが良いと思う。ある程度理解すると、公式ドキュメントが割と手にとるようにわかる(当社比)。 以後、これを分かっていれば公式ドキュメントの言っていることがなんとなくわかると思う知識をザッと書いていき ます。
ルールを記述する JS ファイルの構造 meta と create から構成される大きなオブジェクトをexport する 1 module.exports
= { 2 meta: { 3 type: "suggestion", 4 // ... 5 }, 6 7 create(context) { 8 return { 9 VariableDeclaration(node) { 10 // ... 11 } 12 }; 13 14 } 15 };
meta その名の通りルールのメタ情報(fix できる?suggest はある?) を表現するオブジェクト ESLint v8 から必要となるプロパティが追加されたみたいなので、昔の日本語記事など一部参考にならないものがあ るかも。要注意。 https://eslint.org/docs/user-guide/migrating-to-8.0.0#rules-require-metahassuggestions-to-provide-
suggestions 1 module.exports = { 2 meta: { 3 hasSuggestions: true 4 }, 5 create(context) { 6 // your rule 7 } 8 };
create create は context を受け取る関数で、AST のノードに対応してLint ルールを実装したオブジェクトを返す プログラム中のこの種類のノードに対しては、このチェックをする!という考えで実装する なのでLint に関係ないノードについては実装しなくてよい
ここで疑問に思ったことが2 つ AST ってなに?AST のノードってなに? どうやってLint ルールを実装するか?
AST とはなにか ( 広義には) 文字列で表現されたプログラムから演算子や変数など、文法的に意味のある情報のみを取り出して、 木構造で表現したもの プログラムは、【プログラム全体-> 複数のクラス-> 複数の関数-> 複数の変数宣言や代入など】といったように木構造で表現できる
分解した各部品のことをノードという プログラムを木構造で表現すると、プログラムから扱いやすくなる ESLint などの「プログラムを意味的に解釈して何らかの動作をするもの」を実装しやすくなる( 他にもbabel とか、Prettier とか、 esbuild とかも多分そう)
AST を覗いてみる https://astexplorer.net/ で簡単な式のAST 表現を見てみると、文字列のコードが巨大なJSON として表現される ことがわかる。超絶雑に図解すると以下の感じ
create に Lint ルールを実装する 引数 context に含まれる、エラーや警告をレポートする report() 関数や、node から変数名を取得できる
getDeclaredVariables() 関数を活用して、便利にルールを実装できる 1 // 変数名が _ から始まっていたらエラーになる独自ルールの例 2 create(context) { 3 return { 4 VariableDeclaration(node) { 5 context.getDeclaredVariables(node).forEach(variable => { 6 const name = variable.name; 7 if (name.charAt(0) === "_") { 8 context.report({ 9 node, 10 messageId: "unexpected", 11 data: { name } 12 }); 13 } 14 }); 15 } 16 }; 17 } VariableDeclaration が変数宣言ノードの種類名. context.getDeclaredVariables() で変数名を全取得. context.report() でLint 結果をレポート.
リファレンス リファレンスがあるので丸暗記をしなくてもOK context の仕様 https://eslint.org/docs/developer-guide/working-with-rules#the-context-object VariableDeclaration などのAST のノードの種類名 ESTree https://github.com/estree/estree/blob/master/es5.md
@types/eslint https://github.com/DefinitelyTyped/DefinitelyTyped/blob/master/types/eslint/index.d.ts#L438
テストの書きかた 1 const rule = require("../no-underscore-prefix"), 2 RuleTester = require("eslint").RuleTester;
3 const ruleTester = new RuleTester(); 4 ruleTester.run("no-underscore-prefix", rule, { 5 valid: [ 6 "'hoge'", 7 // ... 8 { code: "const obj = { _name: 'hoge' };", env: { es6: true } }, 9 ], 10 invalid: [ 11 { 12 code: "var _hoge = 'hoge';", 13 errors: [{ messageId: "unexpected", data: { name: "_hoge" }, type: "VariableDeclaration", 14 }, 15 // ... 16 { code: "let x,_y = 'hoge';", env: { es6: true }, errors: [{ messageId: "unexpected", data: { 17 // ... 18 ] 19 }); RuleTester を使ってテストを実装. valid / invalid キーで正常系と異常系を書く. RuleTester のコンストラクタでオプションも色々 設定できるらしい.
補足① TypeScript 対応 @types/eslint を使う 以下の記事が詳しい(厳密にはESLint7 時代の記事なので少しだけ注意が必要) https://blog.sa2taka.com/post/custom-eslint-rule-with-typescript ESLint 自体はts
を読み込んでくれないので、コンパイルフェーズを自前で組むことに注意
補足② 運用手段 冒頭で示した --rulesdir オプションはDeprecated あくまで外部プラグインとして、ローカルフォルダを読み込めるプラグインとしてのアプローチがいくつかある eslint-plugin-rulesdir https://github.com/not-an-aardvark/eslint-plugin-rulesdir eslintrc.js を使っている前提だが最も最新か?
https://github.com/cletusw/eslint-plugin-local-rules 使い方の癖があるように見えるが、任意のeslintrc の形式で対応できそう
余談 勉強会の主催 今回ESLint の独自ルールを調べるにあたって、勉強会を企画してみました https://connpass.com/event/232064/ 2021/12/13 に開催し、共催の RyoKawamata さんと2 時間作業してなんとか形にできた(ありがとうございました)
勉強会駆動開発(Meetup Driven Development, MDD ?)よさそう 勉強会企画したい方、一緒に主催できるので声かけてくださいw
まとめ ESLint の独自ルールを書くために難しい知識は必要ない ドキュメントは丁寧だが、概念をつかむまで少々大変なのと、 @types/eslint などを見たほうが理解が早く 進むところがあるので、手を動かして学ぶのが一番早そう 簡単なルールだったら業務でも作れそうな気がした(まだ作ってない) 勉強会駆動開発おすすめ
告知
Twitter フォローしてね @Meijin_garden だいたいWeb 開発の話か将棋の話してます 絶賛エンジニア採用中です! オンライン家庭教師のスタートアップです! 2020 年リリースで、これから塾や家庭教師や通信教育 を置き換える教育スタイルを広げていきます
少しでも興味があればカジュアル面談歓迎なので、DM やMeety でお声がけください!!
ご清聴ありがとうございました