An expansion and tweaking of the "standard" config style for ESLint
MIT License
A ruthless--though not arbitrary--degree of control for your kingdom!
One ring to rule them all!
npm i -D eslint-config-ash-nazg
install-peerdeps -d eslint-config-ash-nazg
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).)
eslint-recommended.js
of @eslint/js
) for the eslint:recommended
rules we inherit (though see below for our two modifications to these).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.
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:
+script-node.js
: Applies script source type with Node; used bysauron-node-script
+script.js
: Applies script source type for non-Node; used bysauron-script
sauron-node-overrides.js
: sauron-node
with rc
and mocha
sauron-node-script-overrides.js
): sauron-node-script
with rc
andmocha
sauron-overrides.js
: sauron
with rc
and mocha
sauron-script.js
: sauron
with +script.js
filesauron-script-overrides.js
: sauron-script
with rc
and mocha
+babel.js
: Wraps a module to support equivalent babel/eslint-parser rulesmocha.js
: Sets up Mocha (and chai
global) on test directoriesmocha-plus.js
: Strict but reasonable rules for checking Mocha/Chai (notcypress.js
: Strict but reasonable rules for checking Cypressoverrides.js
: Config for overrides to give browser directories,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
).
Besides incorporating more from ESLint core, we also add rules from a few other (peer) dependencies.
eslint-plugin-compat
- Though its list of browsers to support is noteslint-plugin-import
- Besides being peer dependencies of standard
,eslint-plugin-jsdoc
- provides a number of helpful rules for catchingjsdoc/require-jsdoc
except as a warning in ash-nazg/sauron
mode, soeslint-plugin-jsdoc
rules should only apply when JSDoc iseslint-plugin-jsdoc
stricter checking@eslint/markdown
- Another basic use case is ensuring codeoverrides
helpful for tweaking rules for Markdown (andoverrides
, for the eslint-plugin-jsdoc
check-examples
if you wish to lint your JSDoc examples according--ext
flag, e.g., --ext js,md
to get thisoverrides[].files
(though it does seem tomd
if you do use --ext
).eslint-plugin-html
- One basic use case is ensuring HTMLoverrides
for HTML-specific rules or enable the plugin's--ext
flag, e.g., --ext js,html
to get thisoverrides[].files
(though it does seem tomd
if you do use --ext
). (The HTML plugin lackseslint-plugin-promise
- Besides being peer dependencies of standard
,eslint:recommended
In comparison to eslint:recommended
, ash-nazg only adds restrictions with
the exceptions of:
no-console
into a mere warningash-nazg/sauron
configuration. This is for theno-empty
so that allowEmptyCatch
is true
. There are enoughstandard
rulessemi
- Even if not strictly required, semi-colons are conventional inindent
- While it may take some getting used to, 2 spaces does allow moreouterIIFEBody
forobject-property-newline
- Properties on the same line can be veryone-var
- While I normally favor enforcing conventions, this one seemslet
and const
).object-curly-spacing
- Not sure why standard
switched from the defaultquotes
- avoidEscape
is too reasonable to avoid ugliness;allowTemplateLiterals
is useful to begin a pattern that may expend toobject-curly-newline
- Doesn't allow let f = {foo () { dosomething(); }};
lines-between-class-members
- Don't feel any need for it@stylistic/spaced-comment
- Adding markers
for sake of TS-style /// <reference>
comments.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.
array-bracket-newline
- Switched to "consistent" over "always" asfunction-paren-newline
- The default multiline can get too long whereasmultiline-ternary
- Inline ternary can be very readable when notno-empty
- Empty catches occur frequently enough to justifyallowEmptyCatch
no-mixed-requires
- Grouping is more organized, while calls areno-warning-comments
- As per great-eye
discussion of this rule,terms
fixme
and xxx
so we reject these other forms of todo
. Totodo
, see great-eye
.no-restricted-globals
- Use example defaults for event
(andfdescribe
) as convenientno-restricted-properties
- Use example default of restricting__defineGetter__
in favor of Object.defineProperty
as convenientno-restricted-syntax
- Set to eliminate any use of instanceof
Symbol.hasInstance
)no-shadow
- It is better practice not to confuse by using globals! I"parent"
, "top"
, "open"
, "close"
, "stop"
, "blur"
,"status"
, "name"
, "closed"
, and "start"
to allow
as frequentstart
for QUnit env).object-shorthand
- Enabling avoidExplicitReturnArrows
as methodsthis
that this rule grabs (which have their own meaning withthis
refers to thethis
). The optionavoidExplicitReturnArrows
does not avoid if the functions havethis
(though this isn't currently documented); this is probablythis
may signal an error if within a methodprefer-destructuring
- Did not set array to true due to its problemsquote-props
- Changed to "as-needed" as properties more verbose andradix
- We're only dealing with ES5+ environments, so the radix isimport/order
- Enforcing "builtin", "external", "internal" and thenimport/no-unresolved
- fs/promises
should be allowed by default as a@uce/reactive
is just a virtual package (as used byuce-template
.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).
array-element-newline
- While the "consistent" option would be nice,[\n a, b, \n c, d\n]
arrow-body-style
- With as-needed
and requireReturnForObjectLiteral
,func-names
- Too prohibitive, though if applied to methods only, it mayfunc-style
- Declarations are simpler so appealing also. If enabling,allowArrowFunctions
.id-blacklist
- Can be helpful but a little tyrannicalid-length
- Can be helpful (especially a minimum) but a little tyrannicalid-match
- Too project-specificinit-declarations
- Nice with "always" and ignoreForLoopInit
, butline-comment-position
- Too inflexible to enforce either waylines-around-comment
- Irksome to memax-classes-per-file
- A bit tyrannicalmax-depth
- Sounds good but tyrannicalmax-lines-per-function
- A bit tyrannicalmax-lines
- A bit tyrannicalmax-params
- Can be troublesome when one is forced to abide by some APImultiline-comment-style
- Would be nice if allowed multilinenewline-after-var
- Not very flexible (deprecated)newline-before-return
- Not very flexible (deprecated)newline-per-chained-call
- Not flexible in practiceno-continue
- Can be convenientno-inline-comments
- Can be faster and more succintno-invalid-this
- Sounds good but not useful for element eventno-multi-assign
- Sounds good, but can be burdensomeno-negated-condition
- Is generally simpler, but it can be annoyingno-nested-ternary
- Nested ternaries can be helpful to avoid clutter ofno-param-reassign
- Can be helpful, but not convenient, including whenundefined
(e.g., null
)no-restricted-imports
- Project-specificno-restricted-modules
- Project-specificno-ternary
- Not usefulno-undefined
- undefined
is ok for ES6 modules and strict code, so usingno-global-assign
and no-shadow-restricted-names
insteadno-underscore-dangle
- Too restrictiveno-useless-concat
- Too restrictive when one has certain formatting oneone-var-declaration-per-line
- Sounds good, but too cumbersome for smallpadding-line-between-statements
- Might revisitprefer-arrow-callback
- Not compellingprefer-template
- Sounds good, but too cumbersome in practicerequire-atomic-updates
- Many false positivessort-imports
- Would be useful with "warn" if could sort bysort-keys
- Too cumbersomesort-vars
- Too cumbersomeimport/no-restricted-paths
- Project-specificimport/no-internal-modules
- Useful but have to specify, soimport/no-import-module-exports
- Seems redundant for normal CJSimport/no-cycle
- Don't see a problem with cyclic imports in ESMimport/no-nodejs-modules
- Useful for some projects, but not allallow
option)import/no-relative-packages
- Not needed for general environmentsimport/exports-last
- Has some reason for being, but nicer to seeimport/no-namespace
- While can be more efficient to import only whatimport/prefer-default-export
- Could even be a bad practice asimport/no-default-export
- Has some basis, but defaults are admittedlyimport/no-named-export
- Could even be a bad practice asimport/no-relative-parent-imports
- Appealing in some ways, but too rigidimport/dynamic-import-chunkname
- Might revisit for warnings, butimport/max-dependencies
- Too constrainingimport/no-unassigned-import
- Could be useful with allow
option,import/group-exports
- Too rigid as with exports-last
.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
)
eslint-plugin-jsdoc
rulesjsdoc/no-blank-blocks
- Too useful to progressively build docs with blank onesjsdoc/check-line-alignment
- More desirable default not yet implementedjsdoc/informative-docs
- Too troublesome to deal with descriptions as it isjsdoc/no-blank-block-descriptions
- Bad for debuggingjsdoc/no-types
- Types have utility in jsdoc unless using TypeScriptjsdoc/newline-after-description
(recommended) - I can see its draw,jsdoc/no-defaults
- Haven't transitioned to TypeScriptjsdoc/no-undefined-types
(recommended) - I'd like something like this,@typedef
s, etc., it is too restrictive for me at thisjsdoc/require-description-complete-sentence
seems like a good idea, asjsdoc/match-description
with a specialjsdoc/require-hyphen-before-param-description
- I can see its draw,jsdoc/sort-tags
- A bit oppressive (and probably a bit unstable stilljsdoc/no-missing-syntax
- Nothing currently wish to enforcejsdoc/no-restricted-syntax
- Nothing currently wish to enforceunicorn
rules(The following are recommended rules unless otherwise noted.)
catch-error-name
- It can actually be useful to use differentconsistent-destructuring
- In practice can be cumbersomeconsistent-function-scoping
- Though this can be useful, and itempty-brace-spaces
- Easier to build on and cleaner if allowing newlinesexplicit-length-check
- Seems wasteful.filename-case
- Looks potentially useful with camelCase
.import-index
- While understandable, seems may cause more trouble inindex
.import-style
- Using eslint-plugin-import
insteadno-array-reduce
- Though I can see some appeal to this (and reduce
alsojoin
withno-array-for-each
- Writing code for forEach
allows later refactoring,no-await-expression-member
- A bit confining for convenience for only ano-instanceof-array
- Covered by our blocking of all instanceof
no-keyword-prefix
- See no need.no-lonely-if
- Nested ifs can be useful to catch and ignore.no-negated-condition
- Good but cumbersomeno-nested-ternary
- As with eslint's no-nested-ternary
no-null
- A good idea, but besides use of null
in JSON, and semanticno-typeof-undefined
- Ok but cumbersome, especially if global situationno-unreadable-array-destructuring
- Better to use this than multiple linesno-unused-properties
- While no doubt useful, it won't catch all cases,no-useless-switch-case
- Still useful for flagging a viable value orno-useless-undefined
- I don't like the consequence of changingarray-callback-return
to allowImplicit
, and it can make clear thatundefined
is deliberate.prefer-array-flat
- Present in array-func
prefer-array-flat-map
- Present in array-func
prefer-at
- Not widely availableprefer-exponentiation
- Now present in eslint coreprefer-export-from
- Understandable but cumbersome when importing anywaysprefer-json-parse-buffer
- Not recommended now and may be less performantprefer-module
- Handling by different configs insteadprefer-node-protocol
- Might revisit later if practice becomes adoptedprefer-object-from-entries
- Too many false positives (e.g., non-simpleprefer-optional-catch-binding
- Understandable rule, but extra work ifprefer-prototype-methods
- Sometimes a bit cumbersomeprefer-string-slice
- Added to Sauron but can be cumbersome to change forprefer-string-replace-all
- Good but not available yet in Node (even 14)prefer-top-level-await
- Good requires Babel currentlyregex-shorthand
- Was renamed to better-regex
.string-content
- Don't want the trouble of requiring formatted apostrophes (not recommended anyways).switch-case-braces
- Reasonable but burdensome as may not need bracestemplate-indent
- Although attractive, requires tooling to be reliable.throw-new-error
- Potentially confining.better-regex
- Character classes can be arranged for readability.plugin:unicorn/recommended
unicorn/custom-error-definition
- Does not seem confining.unicorn/no-unsafe-regex
- Seems like something to watch for, thoughunicorn/require-post-message-target-origin
- Useful for common casesplugin:eslint-comments/recommended
eslint-comments/no-unused-disable
- Might be indicative of an erroreslint-comments/disable-enable-pair
- If at top, behavior is clear, and
no need to reenable within doc
eslint-comments
ruleseslint-comments/no-restricted-disable
- See no needeslint-comments/no-use
- See no needarray-func
rulesarray-func/prefer-array-from
- While it may benefit performance, it issonarjs
rules(All sonarjs rules are currently "recommended" rules as well except as noted.)
elseif-without-else
- Good rationale but burdensome (not recommended)no-nested-switch
- Arbitrary and not helpful for cleaner codeno-nested-template-literals
- Somewhat reasonable, but also arbitrarymax-switch-cases
- Sounds too arbitrary.no-collapsible-if
- Sometimes more logically clear or made in preparationno-commented-code
- Overly oppressiveno-duplicate-string
- Often used in test files and repeated in fairlyno-identical-functions
- Often used in test files and repeated by fairlyno-lonely-if
- Oppressiveno-nested-conditional
- Not neededno-nested-functions
- Good idea but restrictiveno-primitive-wrappers
- Handling elsewhereno-regex-complexity
- Oppressiveno-self-compare
- Handling elsewhereslow-regex
- Oppressiveno-small-switch
- Too useful to start a pattern to which one intends to add later.prefer-default-last
- Handling elsewhereprefer-immediate-return
- Can be useful for documenting even if method nametodo-tag
- Use expiring to-dos, etc. insteadplugin:jsdoc/recommended
check-examples
- If examples are present, they ought to follow one's standards,.md
extension) by default and excludes any example beginning with acheck-syntax
- Following typescript, not Closure syntaximports-as-dependencies
- Usefulmatch-description
- Cleaner to see complete sentences which its default allows.no-bad-blocks
- Useful to catch blocks likely intended as jsdocrequire-returns-check
- If the return value doesn't match, there may be a problem.require-file-overview
- Don't need @file
in every file.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).
class-methods-use-this
- Good for new code (though even here may needconsistent-this
- A good practice, but sometimes, especially with jQuerythat
is in reference to, this
may be more clearlydefault-case
- Refactoring code to know whether to throw or silentlyno-implicit-globals
with lexicalBindings
to true
- Light browsermax-len
- May require a lot of refactoring.no-alert
- No quick easy replacement yet with poor dialog
support.no-console
- Useful for debugging (and sometimes for reporting progress)no-empty-function
- Cumbersome to add comments within every no-op.no-shadow
- Can catch errors, but also some work to refactor (See alsoprefer-numeric-literals
- Good but some work.require-unicode-regexp
- Good, but some work to fix all.vars-on-top
- Not needed for let
/const
, and if overriding, this isimport/unambiguous
- A good practice, and one which overrides
canpromise/prefer-await-to-callbacks
- Sometimes useful, but callbacksunicorn/no-array-callback-reference
- May be cumbersome though doesunicorn/prefer-number-properties
- Good but some refactoring needed (and notjsdoc/require-returns
(recommended) - Put in ash-nazg/sauron
asforceRequireReturn
void
/undefined
contexts: ['any']
so it checks virtual functions@implements
).jsdoc/require-jsdoc
(recommended) - Imposes a heavy burden ongreat-eye.js
);ClassDeclaration
,ClassExpression
, and MethodDefinition
in addition toFunctionDeclaration
. This may still FunctionExpression
andArrowFunctionExpression
, and these may admittedly be used on such asjsdoc/require-param-name
(recommended): Expanded this tocontexts: ['any']
; see description for jsdoc/require-jsdoc
.jsdoc/require-param-type
(recommended): Expanded this tocontexts: ['any']
; see description for jsdoc/require-jsdoc
.jsdoc/require-returns-type
(recommended): Expanded this tocontexts: ['any']
; see description for jsdoc/require-jsdoc
.jsdoc/implements-on-classes
- Added with contexts: ['any']
;jsdoc/require-jsdoc
. Better to beThe 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.
ash-nazg/great-eye
capitalized-comments
- May be very prevalent; reports with commentedcomplexity
- A generally good practice, but can be work to refactor,no-shadow
with hoist: 'all'
- A person should generally be able to trackmax-statements-per-line
- Tyrannical when prohibiting single-lineif (...) { continue; }
; might revisit if allowed for control statementsmax-statements
- A bit tyrannical even if good for clear codeno-magic-numbers
- Very helpful for clear code, but cumbersome,no-plusplus
- Would be nice if there were an option to allow if notno-warning-comments
(with default value on terms
option blockingimport/no-unused-modules
- Useful (for missingExports
at least),jsdoc/check-alignment
(recommended) - A pretty good practice, but notjsdoc/check-indentation
- A pretty good practice, but that that important.jsdoc/require-description
- Though a very good practices, this isash-nazg/sauron
, though if you feeljsdoc/require-param-description
(recommended) - Seejsdoc/require-description
.jsdoc/require-returns-description
(recommended) - Seejsdoc/require-description
.jsdoc/require-property-description
(recommended) - Seejsdoc/require-description
.jsdoc/require-example
- See jsdoc/require-description
.sonarjs/cognitive-complexity
- As with complexity
perhaps (though mayunicorn/numeric-separators-style
- Good but may involve many changes.unicorn/prevent-abbreviations
- Very cumbersome for frequent conventions suche
for event
unicorn/prefer-set-has
- Very good, but troublesome to refactor.unicorn/prefer-object-has-own
- Good but only available by polyfillThe 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.
@brettz9/for-of
- Iterating functions can be easier to refactorno-implicit-globals
- Included despite not applying to modules, instrict
- Included despite not being needed for modules, inno-return-await
- As per this issue,require-await
which effectivelyasync
on such functions either).prefer-object-has-own
- Not yet supported in all NodeDeprecated and removed items from ESLint are also naturally not included.
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...
no-new-object
; now no-object-constructorno-process-env
this
(to use class
)? Might adapt https://github.com/matijs/eslint-plugin-this?/{/u
and /(/
too)eslint-plugin-privileges
for plugins/config to add for security/transparencyyo
also)eslint --print-config file
for getting at applied config for a file