First-class support for project-specific linting rules
See original GitHub issueThis issue is a continuation of #2715. See that issue for more context.
tl;dr: The current proposal is to topLevelOptions
property to a config file only available in the project-level config (not shareable/extended configs). Allow rulesDir to be specified there.
Version
This problem is not solved as of 4.0.0.
The problem
Many projects have their own unique conventions, ESLint and Node included. From comments in the previous issue, Facebook and Taskworld also have project-specific ESLint rules. The --rulesdir
command-line argument and rulePaths
APIs can be used to tell ESLint to look for rules in additional directories. Both Node and ESLint puts this configuration in their Makefiles.
Here comes the problem: Many people use ESLint integration for their text editors (e.g.
Sublime Text, Atom). These plugins don’t read Makefiles; they assumed the project can be linted by running eslint
in the project directory without passing extra command line arguments or API options.
Even if these editor plugins can be configured to add CLI arguments, they will be applied at global level instead of project-specific level. And these configurations are local to each text editor.
This brings the need for standardized way to include project-specific linting rules that will get picked up by all tools that integrate with ESLint.
Existing workarounds
Create an ESLint plugin
This is the approach previously suggested by ESLint maintainers—by creating ESLint plugins and including it in the project. ESLint requires plugins to be in node_modules
folder. There are several drawbacks to this:
- Publishing the plugins to
npm
: It is cumbersome to update the rules in tandem with the codebase. I would have to go to the plugin, test the rule, and publish a new version tonpm
. The main project needs to point the plugin to the new version. Finally, each developer needs to runnpm install
again to make sure their plugin is at the latest version. - Putting the plugin in the project and use
npm link
. This makes it cumbersome for developers to prepare the project for development. They would have to runnpm install
inside the plugin folder in addition to the main project folder, and runnpm link
afterwards. If the plugin’s dependencies are updated, they need to runnpm install
inside the plugin folder again. - Specifying relative folders in
package.json
. This makes it very cumbersome to update plugins, as bothnpm@3
andyarn@0.24
will say “Already up-to-date” when runningyarn
after changing the rules. I need to runrm -rf node_modules/eslint-plugin-proprietary
before runningyarn
again.
Clearly, using ESLint plugin is more suitable for ESLint rules that are maintained separately. But it is unwieldy for rules that are project-specific.
Here’s how a suitable solution must look like:
- The rules are part of the project. The linting rules are version-controlled along with project’s code and is updated in lockstep.
- They work out-of-the-box with the CLI and all text editor integrations.
- They are ready to use after a single
npm install
command on the project directory. - They can updated by
git pull
without requiring any extra step.
Hacking ESLint internals to load extra rules from .eslintrc.js
Accroding to @zertosh, Facebook uses this approach:
// .eslintrc.js
const Rules = require('eslint/lib/rules');
Rules.load(path.join(__dirname, 'resources/eslint-rules'));
Hacking Node’s module resolution system
We at @taskworld put this in .eslintrc
to hack Node’s module resolution system so that require('eslint-plugin-proprietary')
becomes require('./lib/eslint/plugin')
:
// .eslintrc.js
const Module = require('module')
// Hack Node module system to recognize our plugin.
Module._resolveFilename = (original => function (request, requester) {
if (request === 'eslint-plugin-proprietary') {
return require.resolve('./lib/eslint/plugin')
} else {
return original.apply(this, arguments)
}
})(Module._resolveFilename)
Proposed solution
A solution proposed by @not-an-aardvark is to have topLevelOptions
property in a configuration file. This topLevelOptions
is only usable inside a project (cannot be used in shareable/extended configs).
It is a place where we could include the rulesDir
option, and other options which would not make much sense or would have unintended side-effects when placed in shareable configs.
Issue Analytics
- State:
- Created 6 years ago
- Reactions:2
- Comments:12 (12 by maintainers)
@not-an-aardvark I ended up creating
eslint-plugin-local
, heavily inspired byeslint-plugin-local-rules
. The module is one line of code:Since this plugin is intended to be installed at project-level (not in shareable config; in that case, better to create a plugin), we can be sure it will reside at
$PROJECT/node_modules/eslint-plugin-local
. This means the plugin will work regardless of thecwd
.The name
.eslintplugin
is chosen so that the file appears alongside.eslintrc
. Then we can implement our project-specific plugin at:.eslintplugin.js
.eslintplugin/index.js
Would this solve your issue: https://github.com/cletusw/eslint-plugin-local-rules This is a plugin that allows you to configure local rules through eslintrc file.