Skip to content

Commit

Permalink
Merge pull request #311 from ljharb/eslint_6
Browse files Browse the repository at this point in the history
feat: add eslint 6 support
  • Loading branch information
ljharb committed Aug 9, 2019
2 parents eeae519 + 57951cf commit 4f71be5
Show file tree
Hide file tree
Showing 4 changed files with 81 additions and 11 deletions.
17 changes: 12 additions & 5 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,29 +3,36 @@ language: node_js
notifications:
email: false
node_js:
- '12'
- '10'
- '8'
- '6'
- '4'
before_install:
- nvm install-latest-npm
before_script:
- 'if [ -n "${ESLINT-}" ]; then npm install --no-save "eslint@${ESLINT}"; fi'
- 'if [ -n "${AJV-}" ]; then npm install --no-save "ajv@${AJV}"; fi'
- npm ls > /dev/null
- npm prune > /dev/null && npm ls > /dev/null
script:
- 'if [ -n "${LINTONLY-}" ]; then npm run lint; else npm run cover && npm run check-coverage; fi'
after_success:
- npm run travis-after-all
env:
matrix:
- ESLINT=6
- ESLINT=5 AJV=6
- ESLINT=4 AJV=5
- ESLINT=3
matrix:
include:
- node_js: "node"
env: LINTONLY=true
exclude:
- node_js: "6"
env: ESLINT=5 AJV=5
- node_js: "6"
env: ESLINT=4 AJV=5
- node_js: "6"
env: ESLINT=3
- node_js: "4"
env: ESLINT=5 AJV=6
env: ESLINT=4 AJV=5
- node_js: "4"
env: ESLINT=3
7 changes: 4 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
"description": "Find built-in ESLint rules you don't have in your custom config.",
"main": "dist/lib/rule-finder.js",
"scripts": {
"cover": "nyc --reporter=lcov --reporter=text npm test",
"cover": "nyc --reporter=lcov --reporter=text --reporter=html npm test",
"lint": "eslint --ext .js,.json .",
"test": "mocha --recursive",
"update-contributors": "all-contributors generate",
Expand Down Expand Up @@ -32,6 +32,7 @@
"dependencies": {
"cliui": "^3.2.0",
"eslint-rule-documentation": "^1.0.0",
"glob": "^7.1.4",
"path-is-absolute": "^1.0.1",
"which": "^1.2.8",
"window-size": "0.3.0",
Expand All @@ -46,7 +47,7 @@
"codecov": "^2.2.0",
"commitizen": "^2.9.6",
"cz-conventional-changelog": "^2.0.0",
"eslint": "^3.12.0 || ^4 || ^5",
"eslint": "^3.12.0 || ^4 || ^5 || ^6",
"eslint-plugin-json": "^1.4.0",
"ghooks": "^2.0.0",
"mocha": "^3.0.1",
Expand All @@ -60,7 +61,7 @@
"validate-commit-msg": "^2.12.2"
},
"peerDependencies": {
"eslint": "^3.12.0 || ^4 || ^5"
"eslint": "^3.12.0 || ^4 || ^5 || ^6"
},
"nyc": {
"exclude": [
Expand Down
17 changes: 14 additions & 3 deletions src/lib/rule-finder.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
const path = require('path');

const eslint = require('eslint');
const glob = require('glob');
const isAbsolute = require('path-is-absolute');
const difference = require('./array-diff');
const getSortedRules = require('./sort-rules');
Expand All @@ -16,14 +17,22 @@ function _getConfigFile(specifiedFile) {
return require(path.join(process.cwd(), 'package.json')).main; // eslint-disable-line import/no-dynamic-require
}

function _getConfig(configFile) {
function _getConfigs(configFile, files) {
const cliEngine = new eslint.CLIEngine({
// Ignore any config applicable depending on the location on the filesystem
useEslintrc: false,
// Point to the particular config
configFile
});
return cliEngine.getConfigForFile();
return new Set(files
.map(filePath => cliEngine.isPathIgnored(filePath) ? false : cliEngine.getConfigForFile(filePath))
.filter(Boolean));
}

function _getConfig(configFile, files) {
return Array.from(_getConfigs(configFile, files)).reduce((prev, item) => {
return Object.assign(prev, item, {rules: Object.assign({}, prev.rules, item.rules)});
}, {});
}

function _getCurrentNamesRules(config) {
Expand Down Expand Up @@ -69,6 +78,7 @@ function _notDeprecated(rule) {
function _getPluginRules(config) {
const pluginRules = new Map();
const plugins = config.plugins;
/* istanbul ignore else */
if (plugins) {
plugins.forEach(plugin => {
const normalized = _normalizePluginName(plugin);
Expand Down Expand Up @@ -98,7 +108,8 @@ function _isNotCore(rule) {
function RuleFinder(specifiedFile, options) {
const {omitCore, includeDeprecated} = options;
const configFile = _getConfigFile(specifiedFile);
const config = _getConfig(configFile);
const files = glob.sync('**/*.js', {dot: true, matchBase: true});
const config = _getConfig(configFile, files);
let currentRuleNames = _getCurrentNamesRules(config);
if (omitCore) {
currentRuleNames = currentRuleNames.filter(_isNotCore);
Expand Down
51 changes: 51 additions & 0 deletions test/lib/rule-finder.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,21 @@ const path = require('path');
const assert = require('assert');
const proxyquire = require('proxyquire');

let ModuleResolver;
try {
// eslint 6 and over: load the actual module
// eslint-disable-next-line import/no-unresolved
ModuleResolver = require('eslint/lib/shared/relative-module-resolver');
} catch (err) {
if (err.code !== 'MODULE_NOT_FOUND') {
throw err;
}
// eslint < 6: ModuleResolver is `undefined`, which is okay. The proxyquire
// override for ../shared/relative-module-resolver won't be used because
// eslint < 6 does not have that module and so does not try to load it.
ModuleResolver = undefined;
}

const processCwd = process.cwd;

const eslintVersion = process.env.ESLINT === '3' || process.env.ESLINT === '4' ? '<v5' : 'v5+';
Expand All @@ -19,6 +34,31 @@ const getRuleFinder = proxyquire('../../src/lib/rule-finder', {
}
}
},
//
// This following module override is needed for eslint v6 and over. The module
// path that we pass here is literally the one used in eslint (specifially in
// eslint/lib/cli-engine/config-array-factory.js)
//
// The stock `resolve` method attempts to resolve to a file path the module
// name passed in `name` relative to the path in `relative`. We have to
// override that function, otherwise eslint fails to "load" our plugins.
//
'../shared/relative-module-resolver': {
resolve(name, relative) {
// The strategy is simple: if called with one of our plugins, just return
// the module name, as-is. This is a lie because what we return is not a
// path, but it is simple, and works. Otherwise, we just call the original
// `resolve` from the stock module.
return ['eslint-plugin-plugin',
'eslint-plugin-no-rules',
'@scope/eslint-plugin-scoped-plugin',
'@scope/eslint-plugin'].includes(name) ?
name :
ModuleResolver.resolve(name, relative);
},
'@global': true,
'@noCallThru': true
},
'eslint-plugin-plugin': {
rules: {
'foo-rule': {},
Expand Down Expand Up @@ -83,6 +123,17 @@ const getRuleFinderForDedupeTests = proxyquire('../../src/lib/rule-finder', {
}
}
},
// See the long comment in `getRuleFinder` above to learn what the point of
// this override is.
'../shared/relative-module-resolver': {
resolve(name, relative) {
return name === 'eslint-plugin-plugin' ?
name :
ModuleResolver.resolve(name, relative);
},
'@global': true,
'@noCallThru': true
},
'eslint-plugin-plugin': {
rules: {
'duplicate-foo-rule': {},
Expand Down

0 comments on commit 4f71be5

Please sign in to comment.