From df717bd247ffb184030740af4b9dda359f323d97 Mon Sep 17 00:00:00 2001 From: azu Date: Mon, 31 Aug 2015 19:47:06 +0900 Subject: [PATCH 01/11] =?UTF-8?q?feat(ESLint):=20ESLint=E3=81=AE=E3=82=B7?= =?UTF-8?q?=E3=83=B3=E3=83=97=E3=83=AB=E3=81=AA=E5=AE=9F=E8=A3=85=E3=82=92?= =?UTF-8?q?=E8=BF=BD=E5=8A=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- package.json | 2 ++ src/ESLint/MyLint.js | 41 ++++++++++++++++++++++++++++++++++++++ src/ESLint/no-console.js | 10 ++++++++++ test/ESLint/MyLint-test.js | 15 ++++++++++++++ 4 files changed, 68 insertions(+) create mode 100644 src/ESLint/MyLint.js create mode 100644 src/ESLint/no-console.js create mode 100644 test/ESLint/MyLint-test.js diff --git a/package.json b/package.json index 3a35dae..883b17a 100644 --- a/package.json +++ b/package.json @@ -34,6 +34,8 @@ "eslint": "^1.3.0", "eslint-plugin-markdown": "git://github.com/eslint/eslint-plugin-markdown.git", "espower-babel": "^3.3.0", + "esprima": "^2.5.0", + "estraverse": "^4.1.0", "gitbook-cli": "^0.3.4", "gitbook-plugin-richquotes": "0.0.5", "gitbook-summary-to-path": "^1.0.1", diff --git a/src/ESLint/MyLint.js b/src/ESLint/MyLint.js new file mode 100644 index 0000000..909796e --- /dev/null +++ b/src/ESLint/MyLint.js @@ -0,0 +1,41 @@ +// LICENSE : MIT +"use strict"; +import {parse} from "esprima"; +import {traverse} from "estraverse"; +import {EventEmitter} from "events"; +class RuleContext extends EventEmitter { + report(node, message) { + this.emit("report", message); + } +} +export default class MyLint extends EventEmitter { + constructor() { + super(); + this._emitter = new EventEmitter(); + this._ruleContext = new RuleContext(); + this._ruleContext.on("report", (message) => { + this.emit("report", message); + }); + } + + loadPlugin(plugin) { + var rule = plugin(this._ruleContext); + // on(nodeType, nodeTypeCallback); + Object.keys(rule).forEach(nodeType => { + this._emitter.on(nodeType, rule[nodeType]); + }); + } + + + lint(code) { + var ast = parse(code); + traverse(ast, { + enter: (node) => { + this._emitter.emit(node.type, node); + }, + leave: (node) => { + this._emitter.emit(`${node.type}:exit`, node); + } + }); + } +} \ No newline at end of file diff --git a/src/ESLint/no-console.js b/src/ESLint/no-console.js new file mode 100644 index 0000000..495680c --- /dev/null +++ b/src/ESLint/no-console.js @@ -0,0 +1,10 @@ +"use strict"; +module.exports = function (context) { + return { + "MemberExpression": function (node) { + if (node.object.name === "console") { + context.report(node, "Unexpected console statement."); + } + } + }; +}; \ No newline at end of file diff --git a/test/ESLint/MyLint-test.js b/test/ESLint/MyLint-test.js new file mode 100644 index 0000000..46e39c9 --- /dev/null +++ b/test/ESLint/MyLint-test.js @@ -0,0 +1,15 @@ +// LICENSE : MIT +"use strict"; +import assert from "power-assert"; +import MyLint from "../../src/ESLint/MyLint"; +import noConsole from "../../src/ESLint/no-console"; +describe("MyLint", function () { + it("should load and lint", function () { + let lint = new MyLint(); + lint.loadPlugin(noConsole); + lint.on("report", (message)=> { + assert.equal(message, "Unexpected console statement."); + }); + lint.lint(`console.log("test")`); + }); +}); From 42052363d0260cec85596fac3c02a026eea3a7b8 Mon Sep 17 00:00:00 2001 From: azu Date: Mon, 31 Aug 2015 23:48:30 +0900 Subject: [PATCH 02/11] chore(ESLint) rename MyLint to MyLinter --- src/ESLint/MyLinter-example.js | 9 +++++++++ src/ESLint/{MyLint.js => MyLinter.js} | 14 ++++++++------ test/ESLint/MyLint-test.js | 15 --------------- test/ESLint/MyLinter-test.js | 14 ++++++++++++++ 4 files changed, 31 insertions(+), 21 deletions(-) create mode 100644 src/ESLint/MyLinter-example.js rename src/ESLint/{MyLint.js => MyLinter.js} (75%) delete mode 100644 test/ESLint/MyLint-test.js create mode 100644 test/ESLint/MyLinter-test.js diff --git a/src/ESLint/MyLinter-example.js b/src/ESLint/MyLinter-example.js new file mode 100644 index 0000000..faff6f4 --- /dev/null +++ b/src/ESLint/MyLinter-example.js @@ -0,0 +1,9 @@ +"use strict"; +import assert from "assert"; +import MyLinter from "./MyLinter"; +import noConsole from "./noConsole"; +let linter = new MyLinter(); +linter.loadPlugin(noConsole); +var results = linter.lint(`console.log("test")`); +assert(results.length > 0); +assert.equal(results[0], "Unexpected console statement."); \ No newline at end of file diff --git a/src/ESLint/MyLint.js b/src/ESLint/MyLinter.js similarity index 75% rename from src/ESLint/MyLint.js rename to src/ESLint/MyLinter.js index 909796e..2b97f80 100644 --- a/src/ESLint/MyLint.js +++ b/src/ESLint/MyLinter.js @@ -1,4 +1,3 @@ -// LICENSE : MIT "use strict"; import {parse} from "esprima"; import {traverse} from "estraverse"; @@ -8,14 +7,10 @@ class RuleContext extends EventEmitter { this.emit("report", message); } } -export default class MyLint extends EventEmitter { +export default class MyLint { constructor() { - super(); this._emitter = new EventEmitter(); this._ruleContext = new RuleContext(); - this._ruleContext.on("report", (message) => { - this.emit("report", message); - }); } loadPlugin(plugin) { @@ -28,6 +23,11 @@ export default class MyLint extends EventEmitter { lint(code) { + var messages = []; + var addMessage = (message)=> { + messages.push(message); + }; + this._ruleContext.on("report", addMessage); var ast = parse(code); traverse(ast, { enter: (node) => { @@ -37,5 +37,7 @@ export default class MyLint extends EventEmitter { this._emitter.emit(`${node.type}:exit`, node); } }); + this._ruleContext.removeListener("report", addMessage); + return messages; } } \ No newline at end of file diff --git a/test/ESLint/MyLint-test.js b/test/ESLint/MyLint-test.js deleted file mode 100644 index 46e39c9..0000000 --- a/test/ESLint/MyLint-test.js +++ /dev/null @@ -1,15 +0,0 @@ -// LICENSE : MIT -"use strict"; -import assert from "power-assert"; -import MyLint from "../../src/ESLint/MyLint"; -import noConsole from "../../src/ESLint/no-console"; -describe("MyLint", function () { - it("should load and lint", function () { - let lint = new MyLint(); - lint.loadPlugin(noConsole); - lint.on("report", (message)=> { - assert.equal(message, "Unexpected console statement."); - }); - lint.lint(`console.log("test")`); - }); -}); diff --git a/test/ESLint/MyLinter-test.js b/test/ESLint/MyLinter-test.js new file mode 100644 index 0000000..24a358e --- /dev/null +++ b/test/ESLint/MyLinter-test.js @@ -0,0 +1,14 @@ +// LICENSE : MIT +"use strict"; +import assert from "power-assert"; +import MyLinter from "../../src/ESLint/MyLinter"; +import noConsole from "../../src/ESLint/no-console"; +describe("MyLint", function () { + it("should load and lint", function () { + let linter = new MyLinter(); + linter.loadPlugin(noConsole); + var results = linter.lint(`console.log("test")`); + assert(results.length > 0); + assert.equal(results[0], "Unexpected console statement."); + }); +}); From 174470833e967ffd4d62adc2a9a0adfdbd9d782b Mon Sep 17 00:00:00 2001 From: azu Date: Mon, 31 Aug 2015 23:52:43 +0900 Subject: [PATCH 03/11] test(example): test to run *-example.js --- package.json | 3 ++- src/ESLint/MyLinter-example.js | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/package.json b/package.json index 883b17a..e98c066 100644 --- a/package.json +++ b/package.json @@ -24,7 +24,8 @@ "eslint": "eslint src/**/*.js", "eslint:md": "eslint -c .md.eslintrc --ext .md ja/**/*.md", "textlint": "summary-to-path | xargs textlint --rule spellcheck-tech-word", - "test": "mocha --recursive && npm run textlint && npm run eslint:md && npm run eslint && npm run build" + "test:example": "find ./src -name '*-example.js' | xargs babel-node", + "test": "mocha --recursive && npm run test:example && npm run textlint && npm run eslint:md && npm run eslint && npm run build" }, "keywords": [ "plugin", diff --git a/src/ESLint/MyLinter-example.js b/src/ESLint/MyLinter-example.js index faff6f4..73871e6 100644 --- a/src/ESLint/MyLinter-example.js +++ b/src/ESLint/MyLinter-example.js @@ -1,7 +1,8 @@ "use strict"; import assert from "assert"; import MyLinter from "./MyLinter"; -import noConsole from "./noConsole"; +import noConsole from "./no-console"; + let linter = new MyLinter(); linter.loadPlugin(noConsole); var results = linter.lint(`console.log("test")`); From a2444cdb49fe739432bf6eb1d18adc66def52721 Mon Sep 17 00:00:00 2001 From: azu Date: Mon, 31 Aug 2015 23:53:42 +0900 Subject: [PATCH 04/11] refactor(test): move `--recursive` to mocha.opts --- package.json | 2 +- test/mocha.opts | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/package.json b/package.json index e98c066..42dfe8d 100644 --- a/package.json +++ b/package.json @@ -25,7 +25,7 @@ "eslint:md": "eslint -c .md.eslintrc --ext .md ja/**/*.md", "textlint": "summary-to-path | xargs textlint --rule spellcheck-tech-word", "test:example": "find ./src -name '*-example.js' | xargs babel-node", - "test": "mocha --recursive && npm run test:example && npm run textlint && npm run eslint:md && npm run eslint && npm run build" + "test": "mocha && npm run test:example && npm run textlint && npm run eslint:md && npm run eslint && npm run build" }, "keywords": [ "plugin", diff --git a/test/mocha.opts b/test/mocha.opts index 8d0282d..f83e8df 100644 --- a/test/mocha.opts +++ b/test/mocha.opts @@ -1 +1,2 @@ +--recursive --compilers js:espower-babel/guess \ No newline at end of file From cb5b318474aad7ea982cd44c624bc4e603d8b8cc Mon Sep 17 00:00:00 2001 From: azu Date: Mon, 31 Aug 2015 23:57:54 +0900 Subject: [PATCH 05/11] chore(npm): add babel --- package.json | 1 + 1 file changed, 1 insertion(+) diff --git a/package.json b/package.json index 42dfe8d..d1670fb 100644 --- a/package.json +++ b/package.json @@ -32,6 +32,7 @@ "extension" ], "devDependencies": { + "babel": "^5.8.23", "eslint": "^1.3.0", "eslint-plugin-markdown": "git://github.com/eslint/eslint-plugin-markdown.git", "espower-babel": "^3.3.0", From a1780123a3dbc4df6ce4995dee2abf2cb2398a6e Mon Sep 17 00:00:00 2001 From: azu Date: Mon, 31 Aug 2015 23:59:04 +0900 Subject: [PATCH 06/11] refactor(npm): move to modules relates with MyLinter tot dependencies --- package.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/package.json b/package.json index d1670fb..3dcf308 100644 --- a/package.json +++ b/package.json @@ -36,8 +36,6 @@ "eslint": "^1.3.0", "eslint-plugin-markdown": "git://github.com/eslint/eslint-plugin-markdown.git", "espower-babel": "^3.3.0", - "esprima": "^2.5.0", - "estraverse": "^4.1.0", "gitbook-cli": "^0.3.4", "gitbook-plugin-richquotes": "0.0.5", "gitbook-summary-to-path": "^1.0.1", @@ -48,6 +46,8 @@ "textlint-rule-spellcheck-tech-word": "^4.0.1" }, "dependencies": { + "esprima": "^2.5.0", + "estraverse": "^4.1.0", "jquery": "^2.1.4" } } From b001c431165ff733e3646b9cd51a55c38c4bf27e Mon Sep 17 00:00:00 2001 From: azu Date: Tue, 1 Sep 2015 22:24:25 +0900 Subject: [PATCH 07/11] =?UTF-8?q?feat(ESLint):=20=E5=AE=9F=E8=A3=85?= =?UTF-8?q?=E3=81=AB=E3=81=A4=E3=81=84=E3=81=A6=E3=82=92=E8=BF=BD=E5=8A=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- SUMMARY.md | 1 + ja/ESLint/README.md | 70 ++++++++++++++++++++++++++++++++++ src/ESLint/MyLinter-example.js | 11 +++++- src/ESLint/MyLinter.js | 10 ++--- test/ESLint/MyLinter-test.js | 2 +- 5 files changed, 86 insertions(+), 8 deletions(-) create mode 100644 ja/ESLint/README.md diff --git a/SUMMARY.md b/SUMMARY.md index 6920d4b..e3a599e 100644 --- a/SUMMARY.md +++ b/SUMMARY.md @@ -3,4 +3,5 @@ * [README](README.md) * [Introduction](ja/introduction/README.md) * [jQuery](ja/jQuery/README.md) +* [ESLint](ja/ESLint/README.md) diff --git a/ja/ESLint/README.md b/ja/ESLint/README.md new file mode 100644 index 0000000..d54ba4b --- /dev/null +++ b/ja/ESLint/README.md @@ -0,0 +1,70 @@ +# ESLint + +[ESLint](http://eslint.org/ "ESLint")はJavaScriptのコードをJavaScriptで書かれたルールによって検証するLintツールです。 + +大まかな動作としては、検証したいJavaScriptのコードをパースしてできたAST(抽象構文木)を、ルールで検証し、エラーや警告を出力します。 + +このルールがプラグインとして書けるようになっていて、ESLintの全てのルールがプラグインとして実装されています。 + +> The pluggable linting utility for JavaScript and JSX + +ESLintサイト上には、上記のように書かれていることからもわかりますが、プラグインに重きを置いた設計となっているので、 +今回はESLintのプラグインアーキテクチャについてを見て行きましょう + +## どう書ける? + +[import, no-console.js](../../src/ESLint/no-console.js) + +## どういう仕組み? +## どういう用途に向いている? +## どういう用途に向いていない? +## この仕組みを使ってるもの +## 実装してみよう + +今回は、ESLintのルールを解釈できるシンプルなLintの処理を書いてみます。 + +利用するルールは先ほども出てきた[no-console.js](#no-console.js)をそのまま使い、 +このルールを使って同じようにJavaScriptのコードを検証できる`MyLinter`を書いてみます。 + +### MyLinter + +MyLinterは単純で以下の2つのメソッドを持つクラスとして実装しました。 + +- `MyLinter#loadRule(rule): void` + - 利用するルールを登録する処理 + - `rule`は[no-console.js](#no-console.js)がexportしたもの +- `MyLinter#lint(code): string[]` + - `code`を受け取りルールによってLintした結果を返す + - Lint結果はエラーメッセージの配列とする + +実際に実装したものが以下のようになっています。 + +[import, src/ESLint/MyLinter.js](../../src/ESLint/MyLinter.js) + +MyLinterで[no-console.js](#no-console.js)を読み込ませて、 + +```js +function add(x, y){{ + console.log(x, y); + return x + y; +} +add(1, 3); +``` + +というコードをLintしてみます。 + +[import, src/ESLint/MyLinter-example.js](../../src/ESLint/MyLinter-example.js) + +コードには`console`というオブジェクトが含まれているので_"Unexpected console statement."_というエラーメッセージが取得出来ました。 + +### RuleContext + +もう一度、[MyLinter.js](#MyLinter.js)を見てみると、`RuleContext`というシンプルなクラスがあることに気づくと思います。 + +この`RuleContext`はいわゆるルールから使えるユーティリティメソッドをまとめたもので、 +今回は`RuleContext#report`というエラーメッセージをルールからMyLinterへ通知するものだけを実装しています。 + +ESLintのプラグインアーキテクチャの特徴でもありますが、プラグインが本体の実装がについては知らなくて、 +Contextという本体から与えられたものだけを使うので、ルールが行える事を制御しやすい作りといえます。 + +## エコシステム \ No newline at end of file diff --git a/src/ESLint/MyLinter-example.js b/src/ESLint/MyLinter-example.js index 73871e6..d5c08a9 100644 --- a/src/ESLint/MyLinter-example.js +++ b/src/ESLint/MyLinter-example.js @@ -4,7 +4,14 @@ import MyLinter from "./MyLinter"; import noConsole from "./no-console"; let linter = new MyLinter(); -linter.loadPlugin(noConsole); -var results = linter.lint(`console.log("test")`); +linter.loadRule(noConsole); +var code = ` +function add(x, y){{ + console.log(x, y); + return x + y; +} +add(1, 3); +`; +var results = linter.lint(code); assert(results.length > 0); assert.equal(results[0], "Unexpected console statement."); \ No newline at end of file diff --git a/src/ESLint/MyLinter.js b/src/ESLint/MyLinter.js index 2b97f80..92587a8 100644 --- a/src/ESLint/MyLinter.js +++ b/src/ESLint/MyLinter.js @@ -7,17 +7,17 @@ class RuleContext extends EventEmitter { this.emit("report", message); } } -export default class MyLint { +export default class MyLinter { constructor() { this._emitter = new EventEmitter(); this._ruleContext = new RuleContext(); } - loadPlugin(plugin) { - var rule = plugin(this._ruleContext); + loadRule(rule) { + var ruleExports = rule(this._ruleContext); // on(nodeType, nodeTypeCallback); - Object.keys(rule).forEach(nodeType => { - this._emitter.on(nodeType, rule[nodeType]); + Object.keys(ruleExports).forEach(nodeType => { + this._emitter.on(nodeType, ruleExports[nodeType]); }); } diff --git a/test/ESLint/MyLinter-test.js b/test/ESLint/MyLinter-test.js index 24a358e..0adee75 100644 --- a/test/ESLint/MyLinter-test.js +++ b/test/ESLint/MyLinter-test.js @@ -6,7 +6,7 @@ import noConsole from "../../src/ESLint/no-console"; describe("MyLint", function () { it("should load and lint", function () { let linter = new MyLinter(); - linter.loadPlugin(noConsole); + linter.loadRule(noConsole); var results = linter.lint(`console.log("test")`); assert(results.length > 0); assert.equal(results[0], "Unexpected console statement."); From 43972753a626619dfa395fa9ba376f7783b0dccb Mon Sep 17 00:00:00 2001 From: azu Date: Tue, 1 Sep 2015 22:30:27 +0900 Subject: [PATCH 08/11] fix(ESLint): fix inline code --- ja/ESLint/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ja/ESLint/README.md b/ja/ESLint/README.md index d54ba4b..f552fed 100644 --- a/ja/ESLint/README.md +++ b/ja/ESLint/README.md @@ -44,7 +44,7 @@ MyLinterは単純で以下の2つのメソッドを持つクラスとして実 MyLinterで[no-console.js](#no-console.js)を読み込ませて、 ```js -function add(x, y){{ +function add(x, y){ console.log(x, y); return x + y; } From ac809c116b5e2753c5919b5edeaba572c6256dbd Mon Sep 17 00:00:00 2001 From: azu Date: Tue, 1 Sep 2015 22:44:17 +0900 Subject: [PATCH 09/11] =?UTF-8?q?refactor(ESLint):=20=E6=96=87=E7=AB=A0?= =?UTF-8?q?=E3=81=AE=E7=B4=B0=E3=81=8B=E3=81=84=E5=86=85=E5=AE=B9=E3=82=92?= =?UTF-8?q?=E4=BF=AE=E6=AD=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ja/ESLint/README.md | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/ja/ESLint/README.md b/ja/ESLint/README.md index f552fed..f935816 100644 --- a/ja/ESLint/README.md +++ b/ja/ESLint/README.md @@ -28,7 +28,7 @@ ESLintサイト上には、上記のように書かれていることからも ### MyLinter -MyLinterは単純で以下の2つのメソッドを持つクラスとして実装しました。 +MyLinterは単純な2つのメソッドを持つクラスとして実装しました。 - `MyLinter#loadRule(rule): void` - 利用するルールを登録する処理 @@ -37,11 +37,11 @@ MyLinterは単純で以下の2つのメソッドを持つクラスとして実 - `code`を受け取りルールによってLintした結果を返す - Lint結果はエラーメッセージの配列とする -実際に実装したものが以下のようになっています。 +実装したものが以下のようになっています。 [import, src/ESLint/MyLinter.js](../../src/ESLint/MyLinter.js) -MyLinterで[no-console.js](#no-console.js)を読み込ませて、 +このMyLinterを使って、`MyLinter#load`で[no-console.js](#no-console.js)を読み込ませて、 ```js function add(x, y){ @@ -55,16 +55,21 @@ add(1, 3); [import, src/ESLint/MyLinter-example.js](../../src/ESLint/MyLinter-example.js) -コードには`console`というオブジェクトが含まれているので_"Unexpected console statement."_というエラーメッセージが取得出来ました。 +コードには`console`という名前のオブジェクトが含まれているので、 _"Unexpected console statement."_ というエラーメッセージが取得出来ました。 ### RuleContext もう一度、[MyLinter.js](#MyLinter.js)を見てみると、`RuleContext`というシンプルなクラスがあることに気づくと思います。 -この`RuleContext`はいわゆるルールから使えるユーティリティメソッドをまとめたもので、 +この`RuleContext`はルールから使えるユーティリティメソッドをまとめたもので、 今回は`RuleContext#report`というエラーメッセージをルールからMyLinterへ通知するものだけを実装しています。 -ESLintのプラグインアーキテクチャの特徴でもありますが、プラグインが本体の実装がについては知らなくて、 -Contextという本体から与えられたものだけを使うので、ルールが行える事を制御しやすい作りといえます。 +ルールの実装の方を見てみると、直接オブジェクトをexportしてる訳ではなく、 +`context` つまり`RuleContext`のインスタンスを受け取っていることが分かると思います。 + +[import, no-console.js](../../src/ESLint/no-console.js) + +このようにして、ルールは `context` という与えられたものだけを使うので、ルールができることを制御しやすくなり、 +ルールがMyLinter本体の実装の詳細を知らなくても良くなります。 ## エコシステム \ No newline at end of file From 0ca956afc9c267ffffcc0fa8de8d65dde10fb758 Mon Sep 17 00:00:00 2001 From: azu Date: Tue, 1 Sep 2015 22:50:39 +0900 Subject: [PATCH 10/11] fix(ESLint): fix example --- src/ESLint/MyLinter-example.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ESLint/MyLinter-example.js b/src/ESLint/MyLinter-example.js index d5c08a9..42754e5 100644 --- a/src/ESLint/MyLinter-example.js +++ b/src/ESLint/MyLinter-example.js @@ -6,7 +6,7 @@ import noConsole from "./no-console"; let linter = new MyLinter(); linter.loadRule(noConsole); var code = ` -function add(x, y){{ +function add(x, y){ console.log(x, y); return x + y; } From c3ec702aa115f2259d808adce9af0df56f813054 Mon Sep 17 00:00:00 2001 From: azu Date: Tue, 1 Sep 2015 22:53:34 +0900 Subject: [PATCH 11/11] fix(ESLint): add no-console to config for Markdown --- .md.eslintrc | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.md.eslintrc b/.md.eslintrc index 1f24738..9589990 100644 --- a/.md.eslintrc +++ b/.md.eslintrc @@ -1,6 +1,7 @@ { "rules": { - "no-undef": 0 + "no-undef": 0, + "no-console": 0 }, "plugins": [ "markdown"