Skip to content

Commit c977902

Browse files
committed
feat(ESLint): ESLintの仕組みについてを追加
1 parent 2f48d4f commit c977902

File tree

2 files changed

+63
-8
lines changed

2 files changed

+63
-8
lines changed

.md.eslintrc

+1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
{
22
"rules": {
33
"no-undef": 0,
4+
"no-unused-vars": 0,
45
"no-console": 0
56
},
67
"plugins": [

ja/ESLint/README.md

+62-8
Original file line numberDiff line numberDiff line change
@@ -124,19 +124,68 @@ debug("Hello");
124124
## どういう仕組み?
125125

126126
ESLintはコードをパースしてASTにして、そのASTをJavaScriptで書いたルールでチェックしてレポートする
127-
というおおまかな仕組みは分かりました
127+
という大まかな仕組みは分かりました
128128

129-
では、このルールをプラグインとする仕組みがどのようにして動いているのか見て行きましょう。
129+
次に、このルールをプラグインとする仕組みがどのようにして動いているのか見て行きましょう。
130130

131131
ESLintのLintは次のような3つの手順で行われています。
132132

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+
もう少し具体的にするため、実装して動かせるようなものを作ってこの仕組みについて見ていきます。
136188

137-
## どういう用途に向いている?
138-
## どういう用途に向いていない?
139-
## この仕組みを使ってるもの
140189
## 実装してみよう
141190

142191
今回は、ESLintのルールを解釈できるシンプルなLintの処理を書いてみます。
@@ -190,4 +239,9 @@ add(1, 3);
190239
このようにして、ルールは `context` という与えられたものだけを使うので、ルールができることを制御しやすくなり、
191240
ルールがMyLinter本体の実装の詳細を知らなくても良くなります。
192241

242+
243+
## どういう用途に向いている?
244+
## どういう用途に向いていない?
245+
## この仕組みを使ってるもの
246+
193247
## エコシステム

0 commit comments

Comments
 (0)