Skip to content

Commit

Permalink
Do not raise error on unsupported plugins (#204)
Browse files Browse the repository at this point in the history
* Fix #192 

* Decouple docs from eslint patch

* Prevent error on not supported modules (plugins/extensions)
Given an .eslintrc.yml:
```yaml
env:
    es6: true
    node: true
parserOptions:
    sourceType: module
plugins:
    - node
    - not_supported
extends:
    - not_valid
    - 'plugin:invalidplugin/recommended'
    - 'eslint:recommended'
    - 'plugin:node/recommended'
rules:
    invalidplugin/rule: 1
    node/exports-style: [error, module.exports]
    indent: [error, 4]
    linebreak-style: [error, unix]
    quotes: [error, double]
    semi: [error, always]
    no-console: off
```
When `CODECLIMATE_DEBUG=true codeclimate analyze` runs
Then the output is like:
```
...
Module not supported: eslint-plugin-not_supported
Module not supported: eslint-plugin-invalidplugin
Module not supported: eslint-config-not_valid
...
Analyzing: app1.js
...

== app1.js (1 issue) ==
1: Definition for rule 'invalidplugin/rule' was not found [eslint]
```
  • Loading branch information
filipesperandio authored Mar 14, 2017
1 parent dfef9a0 commit a856436
Show file tree
Hide file tree
Showing 7 changed files with 189 additions and 60 deletions.
5 changes: 3 additions & 2 deletions bin/eslint.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,11 @@ process.chdir(CODE_DIR);
var stdout = console.log;
console.log = console.error;

var eslint = require('../lib/eslint-patch')(require('eslint'));

var eslint = require('../lib/eslint-patch')();

var CLIEngine = eslint.CLIEngine;
var docs = eslint.docs;
var docs = require('../lib/docs')();
var fs = require("fs");
var glob = require("glob");
var options = { extensions: [".js"], ignore: true, reset: false, useEslintrc: true };
Expand Down
30 changes: 11 additions & 19 deletions lib/docs.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,14 @@
var fs = require('fs')
, path = require('path');

//------------------------------------------------------------------------------
// Privates
//------------------------------------------------------------------------------
function Docs() {

var docs = Object.create(null);
var docs = Object.create(null);

function get(ruleId) {
return docs[ruleId];
}

function load() {
var docsDir = path.join(__dirname, '/docs/rules');

fs.readdirSync(docsDir).forEach(function(file) {
Expand All @@ -22,19 +23,10 @@ function load() {
// Remove the .md extension from the filename
docs[file.slice(0, -3)] = content;
});
}

//------------------------------------------------------------------------------
// Public Interface
//------------------------------------------------------------------------------

exports.get = function(ruleId) {
return docs[ruleId];
};

//------------------------------------------------------------------------------
// Initialization
//------------------------------------------------------------------------------
return {
get: get
};
}

// loads existing docs
load();
module.exports = Docs;
6 changes: 6 additions & 0 deletions lib/empty-plugin.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
module.exports = {
rules: {},
configs: {
recommended: {}
}
};
81 changes: 48 additions & 33 deletions lib/eslint-patch.js
Original file line number Diff line number Diff line change
@@ -1,33 +1,50 @@
'use strict';
var meld = require('meld');
var docs = require('./docs');
var Config = require("eslint/lib/config");
var ConfigUpgrader = require('./config_upgrader');

var supportedPlugins = ['react', 'babel'];

module.exports = function patcher(eslint) {

meld.around(eslint.CLIEngine, 'loadPlugins', function(joinPoint) {
var pluginNames = joinPoint.args[0];
var filteredPluginNames = pluginNames.filter(function(pluginName) {
return supportedPlugins.indexOf(pluginName) >= 0;
});
return joinPoint.proceed(filteredPluginNames);
});

meld.around(eslint.CLIEngine, 'addPlugin', function() {
return;
});

// meld.around(eslint.CLIEngine.Config, 'loadPackage', function(joinPoint) {
// var filePath = joinPoint.args[0];
// if (filePath.match(/^eslint-config-airbnb.*/)) {
// return joinPoint.proceed();
// } else {
// return {};
// }
// });
"use strict";

const Plugins = require("eslint/lib/config/plugins");
const ModuleResolver = require("eslint/lib/util/module-resolver");

const ConfigFile = require("eslint/lib/config/config-file");

const Config = require("eslint/lib/config");
const ConfigUpgrader = require("./config_upgrader");

module.exports = function patch() {

const skippedModules = [];
function warnModuleNotSupported(name) {
if(skippedModules.indexOf(name) < 0) {
skippedModules.push(name);
console.error(`Module not supported: ${name}`);
}
}

const resolve = ModuleResolver.prototype.resolve;
ModuleResolver.prototype.resolve = function(name, path) {
try {
return resolve.apply(this, [name, path]);
} catch(e) {
warnModuleNotSupported(name);
return `${__dirname}/empty-plugin.js`;
}
};

Plugins.loadAll = function(pluginNames) {
const loadedPlugins = Object.keys(Plugins.getAll());
if(loadedPlugins.length > 0) {
return;
}

for(const index in pluginNames) {
const name = pluginNames[index];
try {

Plugins.load(name);

} catch(e) {
warnModuleNotSupported(`eslint-plugin-${name}`);
}
}
};

const originalGetConfig = Config.prototype.getConfig;
Config.prototype.getConfig = function(filePath) {
Expand All @@ -37,7 +54,5 @@ module.exports = function patcher(eslint) {
return configUpgrader.upgrade(originalConfig);
};

eslint.docs = docs;

return eslint;
return require('eslint');
};
4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -55,12 +55,12 @@
"eslint-plugin-standard": "^2.1.1",
"eslint-plugin-vue": "^2.0.1",
"eslint-plugin-xogroup": "^1.1.0",
"glob": "^7.0.6",
"meld": "^1.3.2"
"glob": "^7.0.6"
},
"devDependencies": {
"chai": "^3.5.0",
"mocha": "^2.5.3",
"sinon": "^1.17.7",
"temp": "^0.8.3"
},
"scripts": {
Expand Down
86 changes: 86 additions & 0 deletions test/eslint-patch_test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
const expect = require("chai").expect;
const sinon = require("sinon");

const Plugins = require("eslint/lib/config/plugins");
const ModuleResolver = require("eslint/lib/util/module-resolver");
const eslintPatch = require("../lib/eslint-patch");

describe("eslint-patch", function() {
let loadAll;

before(function() {
loadAll = Plugins.loadAll;
});

after(function() {
Plugins.loadAll = loadAll;
});

it("intercepts plugins", function() {
eslintPatch();
expect(loadAll).to.not.equal(Plugins.loadAll, "Plugins.loadAll is not patched");
});

describe("Plugins.loadAll", function() {
before(function() {
eslintPatch();
});

it("delegates each plugin to be loaded", function () {
Plugins.getAll = sinon.stub().returns([]);
Plugins.load = sinon.spy();

Plugins.loadAll([ "jasmine", "mocha" ]);

expect(Plugins.load.calledWith("jasmine")).to.be.true;
expect(Plugins.load.calledWith("mocha")).to.be.true;
});

it("only load plugins once", function () {
Plugins.getAll = sinon.stub().returns([ "node" ]);
Plugins.load = sinon.spy();

Plugins.loadAll([ "node" ]);

expect(Plugins.load.called).to.be.false;
});

it("does not raise exception for unsupported plugins", function() {
Plugins.getAll = sinon.stub().returns([]);
Plugins.load = sinon.stub().throws();

function loadPlugin() {
Plugins.loadAll([ "unsupported-plugin" ]);
}

expect(loadPlugin).to.not.throw();
});
});

describe("loading extends configuration", function() {
it("patches module resolver", function() {
const resolve = ModuleResolver.prototype.resolve;

eslintPatch();
expect(ModuleResolver.prototype.resolve).to.not.eql(resolve);
});

it("returns fake config for skipped modules", function() {
eslintPatch();
Plugins.loadAll(['invalidplugin']);
expect(new ModuleResolver().resolve('eslint-plugin-invalidplugin')).to.match(/.+empty-plugin.js/);
});

it("does not warn user repeatedly about not supported modules", function() {
console.error = sinon.spy();
eslintPatch();

for(var i=0; i<3; i++) {
new ModuleResolver().resolve('eslint-plugin-bogus');
}

expect(console.error.callCount).to.eql(1);
});
});

});
37 changes: 33 additions & 4 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -978,6 +978,12 @@ foreach@^2.0.5:
version "2.0.5"
resolved "https://registry.yarnpkg.com/foreach/-/foreach-2.0.5.tgz#0bee005018aeb260d0a3af3ae658dd0136ec1b99"

[email protected]:
version "1.1.1"
resolved "https://registry.yarnpkg.com/formatio/-/formatio-1.1.1.tgz#5ed3ccd636551097383465d996199100e86161e9"
dependencies:
samsam "~1.1"

fs.realpath@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f"
Expand Down Expand Up @@ -1109,6 +1115,10 @@ inherits@2, inherits@^2.0.1, inherits@~2.0.1:
version "2.0.3"
resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de"

[email protected]:
version "2.0.1"
resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.1.tgz#b17d08d326b4423e568eff719f91b0b1cbdf69f1"

inquirer@^0.12.0:
version "0.12.0"
resolved "https://registry.yarnpkg.com/inquirer/-/inquirer-0.12.0.tgz#1ef2bfd63504df0bc75785fff8c2c41df12f077e"
Expand Down Expand Up @@ -1320,6 +1330,10 @@ lodash@^4.0.0, lodash@^4.11.1, lodash@^4.13.1, lodash@^4.15.0, lodash@^4.2.0, lo
version "4.17.2"
resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.2.tgz#34a3055babe04ce42467b607d700072c7ff6bf42"

[email protected]:
version "1.3.2"
resolved "https://registry.yarnpkg.com/lolex/-/lolex-1.3.2.tgz#7c3da62ffcb30f0f5a80a2566ca24e45d8a01f31"

loose-envify@^1.0.0:
version "1.3.0"
resolved "https://registry.yarnpkg.com/loose-envify/-/loose-envify-1.3.0.tgz#6b26248c42f6d4fa4b0d8542f78edfcde35642a8"
Expand All @@ -1330,10 +1344,6 @@ lru-cache@2:
version "2.7.3"
resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-2.7.3.tgz#6d4524e8b955f95d4f5b58851ce21dd72fb4e952"

meld@^1.3.2:
version "1.3.2"
resolved "https://registry.yarnpkg.com/meld/-/meld-1.3.2.tgz#8c3235fb5001b8796f8768818e9e4563b0de8066"

[email protected]:
version "0.3.0"
resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-0.3.0.tgz#275d8edaac4f1bb3326472089e7949c8394699dd"
Expand Down Expand Up @@ -1606,6 +1616,10 @@ safe-regex@^1.1.0:
dependencies:
ret "~0.1.10"

[email protected], samsam@~1.1:
version "1.1.2"
resolved "https://registry.yarnpkg.com/samsam/-/samsam-1.1.2.tgz#bec11fdc83a9fda063401210e40176c3024d1567"

[email protected]:
version "5.3.0"
resolved "https://registry.yarnpkg.com/semver/-/semver-5.3.0.tgz#9b2ce5d3de02d17c6012ad326aa6b4d0cf54f94f"
Expand All @@ -1622,6 +1636,15 @@ sigmund@~1.0.0:
version "1.0.1"
resolved "https://registry.yarnpkg.com/sigmund/-/sigmund-1.0.1.tgz#3ff21f198cad2175f9f3b781853fd94d0d19b590"

sinon@^1.17.7:
version "1.17.7"
resolved "https://registry.yarnpkg.com/sinon/-/sinon-1.17.7.tgz#4542a4f49ba0c45c05eb2e9dd9d203e2b8efe0bf"
dependencies:
formatio "1.1.1"
lolex "1.3.2"
samsam "1.1.2"
util ">=0.10.3 <1"

slash@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/slash/-/slash-1.0.0.tgz#c41f2f6c39fc16d1cd17ad4b5d896114ae470d55"
Expand Down Expand Up @@ -1759,6 +1782,12 @@ util-deprecate@~1.0.1:
version "1.0.2"
resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf"

"util@>=0.10.3 <1":
version "0.10.3"
resolved "https://registry.yarnpkg.com/util/-/util-0.10.3.tgz#7afb1afe50805246489e3db7fe0ed379336ac0f9"
dependencies:
inherits "2.0.1"

wordwrap@~1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/wordwrap/-/wordwrap-1.0.0.tgz#27584810891456a4171c8d0226441ade90cbcaeb"
Expand Down

0 comments on commit a856436

Please sign in to comment.