@@ -124,19 +124,68 @@ debug("Hello");
124
124
## どういう仕組み?
125
125
126
126
ESLintはコードをパースしてASTにして、そのASTをJavaScriptで書いたルールでチェックしてレポートする
127
- というおおまかな仕組みは分かりました 。
127
+ という大まかな仕組みは分かりました 。
128
128
129
- では 、このルールをプラグインとする仕組みがどのようにして動いているのか見て行きましょう。
129
+ 次に 、このルールをプラグインとする仕組みがどのようにして動いているのか見て行きましょう。
130
130
131
131
ESLintのLintは次のような3つの手順で行われています。
132
132
133
- 1 . ルール毎に使っているNodeTypeをイベント登録する
134
- 2 . ASTをtraverseしながら、NodeTypeのイベントを発火する
135
- 3 . ルールから` context.report ` された内容を集めて表示する
133
+ 1 . ルール毎に使っている` Node.type ` をイベント登録する
134
+ 2 . ASTをtraverseしながら、` Node.type ` のイベントを発火する
135
+ 3 . ルールから` context.report() ` された内容を集めて表示する
136
+
137
+ このイベントの登録と発火にはEventEmitterを使っていて、
138
+ ESLint本体に対してルールは複数あるので、典型的なPub/Subパターンとなっています。
139
+
140
+ 擬似的なコードで表現すると以下のような流れでLintの処理が行われています。
141
+
142
+ ``` js
143
+ import {parse } from " esprima" ;
144
+ import {traverse } from " estraverse" ;
145
+ import {EventEmitter } from " events" ;
146
+
147
+ function lint (code ){
148
+ // コードをパースしてASTにする
149
+ var ast = parse (code);
150
+ // イベントの登録場所
151
+ var emitter = new EventEmitter ();
152
+ var results = [];
153
+ emitter .on (" report" , message => {
154
+ // 3. のためのreportされた内容を集める
155
+ results .push (message);
156
+ });
157
+ // 利用するルール一覧
158
+ var ruleList = getAllRules ();
159
+ // 1. ルール毎に使っている`Node.type`をイベント登録する
160
+ ruleList .forEach (rule => {
161
+ // それぞれのルールに定義されているメソッド一覧を取得
162
+ // e.g) MemberExpression(node){}
163
+ // => {"MemberExpression" : function(node){}, ... } というオブジェクト
164
+ var methodObject = getDefinedMethod (rule);
165
+ Object .keys (methodObject).forEach (nodeType => {
166
+ emitter .on (nodeType, methodList[nodeType]);
167
+ });
168
+ });
169
+ // 2. ASTをtraverseしながら、`Node.type`のイベントを発火する
170
+ traverse (ast, {
171
+ // 1.で登録したNode.typeがあるならここで呼ばれる
172
+ enter : (node ) => {
173
+ emitter .emit (node .type , node);
174
+ },
175
+ leave : (node ) => {
176
+ emitter .emit (` ${ node .type } :exit` , node);
177
+ }
178
+ });
179
+ // 3. ルールから`context.report()`された内容を集めて表示する
180
+ console .log (results .join (" \n " ));
181
+ }
182
+ ```
183
+
184
+ Pub/Subパターンを上手く使うことで、ASTをtraverseするのが一巡のみでそれぞれのルールに対して
185
+ どういうコードであるかという情報が` emit ` で通知できていることがわかります。
186
+
187
+ もう少し具体的にするため、実装して動かせるようなものを作ってこの仕組みについて見ていきます。
136
188
137
- ## どういう用途に向いている?
138
- ## どういう用途に向いていない?
139
- ## この仕組みを使ってるもの
140
189
## 実装してみよう
141
190
142
191
今回は、ESLintのルールを解釈できるシンプルなLintの処理を書いてみます。
@@ -190,4 +239,9 @@ add(1, 3);
190
239
このようにして、ルールは ` context ` という与えられたものだけを使うので、ルールができることを制御しやすくなり、
191
240
ルールがMyLinter本体の実装の詳細を知らなくても良くなります。
192
241
242
+
243
+ ## どういう用途に向いている?
244
+ ## どういう用途に向いていない?
245
+ ## この仕組みを使ってるもの
246
+
193
247
## エコシステム
0 commit comments