Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Features
Speaker Deck
PRO
Sign in
Sign up for free
Search
Search
ESLintの独自ルール作成にチャレンジした話
Search
meijin
January 19, 2022
Technology
900
2
Share
Embed
Copy iframe code
Copy JS code
Copy link
Start on current slide
ESLintの独自ルール作成にチャレンジした話
https://rakus.connpass.com/event/232039
meijin
January 19, 2022
More Decks by meijin
See All by meijin
Technical Decisions and Reflections on "Test Maker" After Two Years of Development
texmeijin
1
140
弊社の「意識チョット低いアーキテクチャ」10選
texmeijin
5
27k
DDDを志して3年経ったら「DDDの皮を被ったクリーンアーキテクチャ」になった話【デブサミ2024夏】
texmeijin
4
4.5k
サービス黎明期にNuxt.js v2からNext.js移行を決めた理由と進め方
texmeijin
0
540
スタートアップCTOが個人開発で収益化・年13本記事発信・5件登壇を平行するための時間管理
texmeijin
4
1.3k
個人開発がおすすめな理由
texmeijin
3
1.1k
弊社の開発体験の良いところは?メンバーに訊いてみた!
texmeijin
0
500
初めてESLintプラグインにコントリビュートした話
texmeijin
0
280
先生と一緒に プロダクトを良くする アナリティクス機能の開発
texmeijin
0
140
Other Decks in Technology
See All in Technology
猫付きpingコマンドを自作
uyuki234
0
290
会社紹介資料 / Sansan Company Profile
sansan33
PRO
24
430k
Model Studio CLI × Token Plan
maigo999
0
210
ホームラボ紹介
y_sera15
0
230
Head First モブプログラミング / Head First Mobprogramming
takaking22
10
12k
Kiro Crew入門 - 常駐エージェントの仕組みと使いどころ / Intro to Kiro Crew
k_adachi_01
1
790
平文パスワードはログに“残り” ── 肝心の侵入は“痕跡すら残らない”
kuroneko13
0
120
AI時代のアウトプット――変わったこと、変わらないこと / Devsumi 2026 Kansai #devsumi
jnchito
0
510
AI・HPC開発を支えるGPU環境の新しい選択肢 液冷GPUシステム「AquSys」の取り組み
gpuunite_official
0
220
地震情報アプリを作ってみた
yama3133
1
110
内製AIチャットボット開発で学んだ Datadog Agent Observability活用術
mkdev10
0
100
なぜ Temporal の大小比較には compare しかないのか / Why Does Temporal Only Have compare() for Comparisons
kazukihayase
1
200
Featured
See All Featured
Producing Creativity
orderedlist
PRO
348
40k
Organizational Design Perspectives: An Ontology of Organizational Design Elements
kimpetersen
PRO
1
800
Noah Learner - AI + Me: how we built a GSC Bulk Export data pipeline
techseoconnect
PRO
0
400
Measuring & Analyzing Core Web Vitals
bluesmoon
9
970
What does AI have to do with Human Rights?
axbom
PRO
1
2.3k
Winning Ecommerce Organic Search in an AI Era - #searchnstuff2025
aleyda
1
2.1k
AI in Enterprises - Java and Open Source to the Rescue
ivargrimstad
0
1.4k
Applied NLP in the Age of Generative AI
inesmontani
PRO
4
2.4k
The Spectacular Lies of Maps
axbom
PRO
1
940
Dealing with People You Can't Stand - Big Design 2015
cassininazir
367
27k
Making Projects Easy
brettharned
120
6.7k
The Power of CSS Pseudo Elements
geoffreycrofte
82
6.5k
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 でお声がけください!!
ご清聴ありがとうございました