Home

Awesome

eslint-config-ash-nazg

A ruthless--though not arbitrary--degree of control for your kingdom!

One ring to rule them all!

Installation

npm i -D eslint-config-ash-nazg
install-peerdeps -d eslint-config-ash-nazg

The rules

See main.js (and node.js for ash-nazg/node rules) for the rules we explicitly include (and see sauron.js for the even stricter ash-nazg/sauron rules or great-eye (or great-eye-node) for still stricter rules though which are probably best not used).

(See explicitly-unused.js for the core and extended rules we don't include (rationale for non-inclusion below).)

I've focused below on deviations because the original sites tend to already articulate the usefulness of the rules I have incorporated for these plugins/configs. This is for tracking design choices and not disparaging the utility of non-included rules.

Other bundled configs

The ash-nazg/node config expands upon the regular ash-nazg rules to add rules specific to Node environments. Specifically, plugin:node/recommended-module has been adopted for now along with some stylistic choices. However, if you are using more CJS exports, you can override this by adding plugin:node/recommended-script to your extends array (after ash-nazg) or, for Sauron-Node, by using sauron-node-script.

The ash-nazg/node configs also detect minimum Node from engines and set env to use the highest supported ES globals, e.g., ES2021 (and also sets node: true) as well as sets ecmaVersion.

The ash-nazg/sauron config expands upon the regular ash-nazg rules to indicate what are generally best practices but are less likely to be due to an error and may possibly also require a high (and possibly tyrannical) degree of refactoring for existing projects. See below for the rationales for inclusion.

The ash-nazg/great-eye and ash-nazg/great-eye-node configs expands on ash-nazg/sauron (and ash-nazg/sauron-node) to include rules which enforce good practices, but which are so cumbersome and may flag too much legitimate code that I personally won't regularly use them. Still, I like to track them here, including in the event that their config changes to make them less all-encompassing.

The ash-nazg/sauron-node config incorporates both ash-nazg/node and ash-nazg/sauron. It adds specific rules of its own which may be unduly strict for ash-nazg/node.

A few experimental configs have been added as well, though this might be removed or significantly modified in a future version:

Comparison to other "standards"

eslint-config-ash-nazg is a collection of some excellent preexisting rules other projects have created, curated with the intent of attaining productive strictness.

"standard" (config) and eslint:recommended have brought a welcome degree of pseudo-standardization for code styling and error checking.

However, they do not impose as high of a degree of control as one may find desirable to enforce common, sane styling practices, catch bad practices and hard-to-read patterns, or in some cases even catch errors.

Moreover, standard enforces a few styling rules which are contrary to regular JavaScript practice (e.g., its enforced absence of semi-colons).

ash-nazg aims to offer defaults which adhere to norms, build upon productive restrictions, and in a few cases, offer greater latitude where some constraints are unduly confining.

To see which rules from an extended config ended up enabled (we are typically inheriting "recommended" configs), see /inherited-rules/implicitly-included.

To see which rules from the extended config we disabled, see our relevant config(s) (e.g., main.js).

To see which rules from the plugin that each extended config derives from (i.e., the non-recommended rules of a plug-in), see explicitly-unused.js for ones we have consciously not used and see our relevant config(s) (e.g., main.js) for the ones we did add (alongside any recommended).

The unused folder is used to capture any (non-recommended) rules which are not explicitly either enabled or within explicitly-unused.js (as might be found during an update of our config dependencies), but it is currently, and should hopefully remain, empty, as we wish to be consciously aware of all rules from inherited projects and whether we wished to include them. As far as new rules added to recommended, we can see these within diffs of inherited-rules/implicitly-included files (built during development by npm run compare).

Rationales for inclusion of dependent plug-ins

Besides incorporating more from ESLint core, we also add rules from a few other (peer) dependencies.

Deviations

Deviation from eslint:recommended

In comparison to eslint:recommended, ash-nazg only adds restrictions with the exceptions of:

  1. Loosening the ESLint < 6 requirement of no-console into a mere warning and only in the stricter ash-nazg/sauron configuration. This is for the reason that console logging is too useful for debugging (and sometimes for reporting progress) to have to disable it at every turn and to distract one from actual errors.
  2. Change no-empty so that allowEmptyCatch is true. There are enough cases where one legitimately needs to suppress errors.

Rationale for overriding standard rules

  1. semi - Even if not strictly required, semi-colons are conventional in JavaScript and help denote the end of statements (as opposed to the end of a line which may continue).
  2. indent - While it may take some getting used to, 2 spaces does allow more in one's field of vision. However, changed to use outerIIFEBody for avoiding indents with the IIFE body, as this often minimizes indent level for much or all of the whole file.
  3. object-property-newline - Properties on the same line can be very convenient, including stacking for space to avoid max length (though without stacking the height too high).
  4. one-var - While I normally favor enforcing conventions, this one seems to me to be of little consequence. It also prevents grouping like items together. I might favor an option to require separate lines for variable declarations, but for uninitialized ones, adding to the same line is convenient, especially for single-letter variables. I would like a rule to have declarations as close as possible to being just above any used scopes (for let and const).
  5. object-curly-spacing - Not sure why standard switched from the default here.
  6. quotes - avoidEscape is too reasonable to avoid ugliness; allowTemplateLiterals is useful to begin a pattern that may expend to allow other quotes or dynamic variables.
  7. object-curly-newline - Doesn't allow let f = {foo () { dosomething(); }};
  8. lines-between-class-members - Don't feel any need for it
  9. @stylistic/spaced-comment - Adding markers for sake of TS-style /// <reference> comments.

Rationale for changing required rules' configuration away from ESLint defaults

While these are not part of standard or eslint-recommended, I've noted here why we have deviated from the defaults set by ESLint for those applying the rule.

Rationale for not including some rules

The following rules are not included within eslint:recommended or standard, nor have we chosen to include them in any of the ash-nazg rules.

Note: italicized items refer to features I might enable if the described option could become available (or upon further review). I might also tweak some standard rules further which I have not had time to examine (but it would probably be toward the stricter rather than looser as I have been happy with it thus far).

Rationale for disabled import rules

Rationale for disabled Node and Promise rules

no-process-exit (added by Node recommended) - has a version in Unicorn which allows in CLI apps.

node/no-missing-import - Redundant with import/no-unresolved

node/file-extension-in-import - Redundant with import/extensions and has no ignorePackages option currently.

node/prefer-promises/dns and node/prefer-promises/fs are good, but a bit early with Node 12.

node/no-restricted-import - project-specific

node/no-restricted-require - project-specific

promise/no-native is disabled as promises are essential--even, it appears, to Dark Lords.

promise/param-names can be too tyrannical in some cases.

promise/no-nesting - can be useful to nest sometimes

promise/no-promise-in-callback - May be difficult to apply (Note: Is disabled in main.js but enabled in sauron.js)

promise/no-callback-in-promise - May be difficult to apply (Note: Is disabled in main.js but enabled in sauron.js)

promise/avoid-new - Can be useful or even necessary for APIs missing Promise version (Note: Is disabled in main.js but enabled in sauron.js; could use promisify)

promise/no-return-in-finally - (Note: Is disabled in main.js but enabled in sauron.js)

promise/valid-params - (Note: Is disabled in main.js but enabled in sauron.js)

Rationale for suppressing some eslint-plugin-jsdoc rules

Rationale for disabling some unicorn rules

(The following are recommended rules unless otherwise noted.)

Rationale for altering default on Unicorn rules

Rationale for including some Unicorn rules which are disabled in plugin:unicorn/recommended

Rationale for including eslint-comments rules which are not in plugin:eslint-comments/recommended

Rationale for changing eslint-comments rules from default recommended

eslint-comments/disable-enable-pair - If at top, behavior is clear, and no need to reenable within doc

Rationale for not including some eslint-comments rules

Rationale for not including some array-func rules

Rationale for not including some sonarjs rules

(All sonarjs rules are currently "recommended" rules as well except as noted.)

Rationale for including eslint-plugin-jsdoc rules which are not in plugin:jsdoc/recommended

Rationale for only including some rules within ash-nazg/sauron

These are good practices, but cumbersome, not as familiar to developers, prohibitive during ongoing debugging or conversion of existing projects, etc. But perhaps useful for a new project which can pay closer attention to standards without the undue burden of having to refactor lots of code (which may not all be under one's control).

The forceRequireReturn setting was also applied therein as it may be cumbersome to add to all returns or not favored as a requirement in all projects though it does note that a method's return was considered even if undefined.

The preferredTypes setting was enabled here as it can be cumbersome for projects to specify all child types.

Rationale for only including some rules within ash-nazg/great-eye

The preferredTypes setting was enabled here for integer/float as it can be cumbersome for projects to distinguish and because Promise even subclassed doesn't indicate the rejector type.

Rationale for not including some rules in @brettz9/eslint-plugin

Rationale for including rules that might not seem necessary

Rationale for not including some non-recommended eslint rules

Deprecated rule non-inclusion

Deprecated and removed items from ESLint are also naturally not included.

Contributing

While I will admit to being opinionated, and one may need to disable some rules (or possibly add a few ones mentioned in my non-inclusion sections), feel free to file issues if you really feel there are compelling reasons for different defaults. But again, I have to add caution that ring bearers can be picky about giving up their preh-shus...

High-priority to-dos

  1. Restore the following as may become available in flat config:
    1. eslint-plugin-unsanitized
    2. @fintechstudios/eslint-plugin-chai-as-promised (has PR)
    3. eslint-plugin-mocha-cleanup (has PR)

To-dos