eslint-plugin-commonjs-require-name v1.2.0
eslint-plugin-commonjs-require-name
Contents
Install
- Ensure that
eslintis installed already. Install the plugin:
$ npm install --save-dev eslint-plugin-commonjs-require-nameConfigure the plugin...
The recommended way, with default settings:
{ "extends": [ "plugin:commonjs-require-name/recommended" ] }Or override the configuration options as needed:
{ "plugins": ["commonjs-require-name"], "rules": { "commonjs-require-name/rule": ["warn", {"strict": {"size": true}}, {"order": "any"}] } }
Summary
This plugin contains a single rule, commonjs-require-name/rule, that enforces a naming convention for require module assignments.
The rule checks that the name of the module assignment matches the module name that is required.
require Types
Any given require is categorized into one of two buckets:
- A local module
require. - A node module
require.
A local module require refers to files that exist only within the project.
Generally this is a require string that is a relative filepath.
For example, a project that has this structure:
$ tree
.
├── index.js
└── app
└── models
├── data.json
├── index.js
└── user.jsCould have these local requires:
const models = require("./app/models"); // a local index file
const user = require("./app/models/user"); // a local file
const data = require("./app/models/data.json"); // a local json fileA node module require refers to builtin modules or those that were installed in node_modules/, such as:
const fs = require("fs"); // a node module that is builtin
const request = require("request"); // a node module installed in node_modules/Naming conventions for each type of require can be configured independently since it is common for projects to use different conventions depending on the type of module being required.
See options for more information.
Token Types
When the require string argument is parsed it is tokenized such that each token is categorized as either a namespace token or a name token.
The name tokens are usually the last token(s) to appear and are preceeded by a variable number of namespace tokens.
Here are some examples of how module names are parsed:
// index.js
require("lodash/findBy"); // [lodash, find, by]
// ^^^^^^ ^^^^ ^^
// | | |
// | name name
// namespace
require("@babel/types"); // [babel, types]
// ^^^^^ ^^^^^
// | |
// | name
// namespace
require("./app/models"); // [app, models]
// ^^ ^^^^^^
// | |
// | name
// namespace
require("./app/models/user"); // [app, models, user]
// ^^ ^^^^^^ ^^^^
// | | |
// | | name
// | namespace
// namespace
// app/controllers/user.js
require("../models/user"); // [models, user]
// ^^^^^^ ^^^^
// | |
// | name
// namespace
require("../models"); // [models]
// ^^^^^^
// |
// name
require("./"); // [controllers]
// ^^^
// |
// name
require("../"); // [app]
// ^^^
// |
// nameAlthough there are other optional behaviors that depend on the type of token, the only non-configurable behavior is that a module assignment must always include the name token(s) parsed from the module name. These examples conform to this behavior and would not be reported (although they could still be reported depending on how the other options are configured).
const childProcess = require("child_process");
const has = require("lodash/has");
const traverse = require("@babel/traverse")
const data = require("./app/models/data.json");
const user = require("./app/models/user");These examples, meanwhile, would be reported for this rule:
const child = require("child_process");
const babel = require("@babel/traverse");
const key = require("lodash/has");
const models = require("./app/models/data.json");
const usr = require("./app/models/user");Options
Three options arguments are accepted:
"commonjs-require-name/rule": [
"error", // the eslint error level
{"order": "any"}, // options object for local requires
{"order": "left-to-right"} // options object for node requires
]The options for local and node requires use the same schema, which is the following:
null- the rule will not be enforced for the type ofrequire.- An object with the following optional keys:
disable- a list of regex strings that, if matched against the module name, the rule will not run.namespace- an object with the following optional keys:canonicalize- whentrue, will attempt to matchnamespacetokens in either their singular or plural form.separators- a list of strings that, if found in a module name, will be recognized as separators betweennamespacetokens.
order- the order in which module name tokens must appear.strict- an object with the following optional keys:size- whentrue, the module assignment must use the same number of tokens as the module name.tokens- whentrue, the module assignment must use every token that appears in the module name.
strip- a list of regex strings that, if matched, will be stripped from the module name.
disable
- Default for
local:[] - Default for
node:["^bluebird$", "^jquery$", "^lodash$", "^underscore$"]
This option is useful for projects that typically use modules with assignment names that deliberately don't follow the enforced rules but are still common enough that they can't be disabled individually every time they are used.
This is typical for node require types where module names such as jquery, lodash, or underscore are assigned to variables like $ and _.
Instead of having to add an eslint-disable directive every time these appear, they can be globally disabled in the node configuration object, like so:
"commonjs-require-name/rule": ["error", null, {"disable": ["^bluebird$", "^jquery$", "^lodash$"]}]Projects with local modules that have a similar issue, meanwhile, can be disabled in the local configuration object with a flexible regex.
"commonjs-require-name/rule": ["error", {"disable": ["vendor/(bluebird|jquery|lodash)/dist"]}, null]This can be useful for projects that use vendored dependencies.
namespace
These options configure how matches against the namespace tokens of a module name behave.
namespace.canonicalize
- Default for
local:true - Default for
node:false
This option is useful for projects that group related files into plural namespaces, but still use the singular form in code at module assignment. For example, a project that uses this directory structure:
$ tree
.
└── app
├── controllers
│ └── user.js
├── index.js
├── models
│ └── user.js
└── views
└── user.jsMight have a file that requires each of the user.js modules like so:
// in app/index.js
const controllerUser = require("./controllers/user");
const modelUser = require("./models/user");
const viewUser = require("./views/user");Without any configuration, the rule would compare the singular token (controller, model, or view) against the corresponding plural token (controllers, models, or views) and report the mismatch.
With this option enabled in the local configuration options, though, the rule will attempt to match the singular token from the module assignment with the corresponding token from the module name in either a singular or plural form.
This means that controller on the left would be matched with either controllers or controller on the right, which will succeed.
To enable this rule for local requires:
"commonjs-require-name/rule": ["error", {"namespace": {"canonicalize": true}}, null]Note, however, that this option only affects namespace tokens.
Even with this option enabled, these will still be reported:
const otherThing = require("other-things"); // reported
const thing = require("./things"); // reportedThis is because things is parsed as a name token since it is the name of the module, whereas controllers, models, and views are parsed as namespace tokens.
namespace.separators
- Default for
local:[] - Default for
node:["."]
This option is useful for parsing namespace tokens that otherwise would be indistinguishable from name tokens.
This is typical for node modules that use a . to differentiate between a project name and the module name.
For example:
const get = require("lodash.get"); // reportedThis would be reported since the rule would not be able to differentiate that lodash is a namespace token instead of a name token.
With this option in the node configuration options, however, it would not be reported since lodash would be properly categorized as a namespace token.
"commonjs-require-name/rule": ["error", null, {"namespace": {"separators": ["."]}}]order
- Valid values:
"any","left-to-right","right-to-left" - Default for
local:"any" - Default for
node:"left-to-right"
This option specifies the order in which module assignment tokens should appear relative to the module name. Tokens can be omitted and extraneous tokens can be added but the main requirement is that the tokens that the module assignment and the module name have in common must match in the configured order.
Here are some examples:
// "commonjs-require-name/rule": ["error", null, {"order": "left-to-right"}]
const childProcess = require("child_process"); // ok
const get = require("lodash/fp/get"); // ok
const intersectionByFP = require("lodash/fp/intersectionBy"); // reported
// "commonjs-require-name/rule": ["error", {"order": "right-to-left"}, null]
const userControllers = require("./app/controllers/user"); // ok
const userModelsV2 = require("./app/models/user"); // ok
const viewsUser = require("./app/views/user"); // reported
// "commonjs-require-name/rule": ["error", {"order": "any"}, null]
const follower = require("./app/models/follower"); // ok
const userAppModelsV3 = require("./app/models/user"); // ok
const noMatch = require("./app/models"); // reportedstrict
These options configure how strictly module assignments are compared to module names.
strict.size
- Default for
local:false - Default for
node:false
Enabling this option specifies that the module assignment must use the same number of tokens that were parsed in the module name.
Here are some examples:
// "commonjs-require-name/rule": ["error", null, {"strict": {"size": true}}]
const babelTraverse = require("@babel/traverse"); // ok
const types = require("@babel/types"); // reported
// "commonjs-require-name/rule": ["error", {"strict": {"size": true}}, null]
const followerAppModels = require("./app/models/follower"); // ok
const user = require("./app/models/user"); // reportedstrict.tokens
- Default for
local:true - Default for
node:true
Enabling this option specifies that the module assignment must not use any additional tokens than those that appear in the module name.
Here are some examples:
// "commonjs-require-name/rule": ["error", null, {"strict": {"tokens": true}}]
const traverse = require("@babel/traverse"); // ok
const babbleTypes = require("@babel/types"); // reported
// "commonjs-require-name/rule": ["error", {"strict": {"tokens": true}}, null]
const followerModels = require("./app/models/follower"); // ok
const userModelsV2 = require("./app/models/user"); // reportedstrip
- Default for
local:[] - Default for
node:[".js", ".css", ".com", ".org", ".io"]
This option can be used to strip unwanted text out of module names before they are parsed. This is typically useful for module names that include file extensions or top-level domains that, if not included, would be a name that is otherwise already taken on the NPM registry.
Here are some examples:
// "commonjs-require-name/rule": ["error", null, {"strip": [".js", ".io"]}]
const decimal = require("decimal.js"); // ok
const socket = require("socket.io"); // ok
const normalize = require("normalize.css"); // reportedNote that file extensions are not parsed and do not need to be stripped.
// "commonjs-require-name/rule": ["error", {"strip": [".js"]}, {"strip": [".js"]}]
const get = require("lodash/get.js"); // ok
const user = require("./user.js"); // ok
const decimal = require("decimal.js"); // ok
// "commonjs-require-name/rule": ["error", {"strip": []}, {"strip": []}]
const get = require("lodash/get.js"); // ok
const user = require("./user.js"); // ok
const decimal = require("decimal.js"); // reported