Last active
May 18, 2017 22:15
-
-
Save bathos/f9dec570b175c6c84b45cd48fa579394 to your computer and use it in GitHub Desktop.
personal eslint config 2017 update
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
%YAML 1.2 | |
--- | |
# This is the client config, but it is also used as the basis of the server | |
# config, which just switches env and appends node-specific rules. | |
# Current as of eslint 3.19.0 | |
parserOptions: | |
ecmaVersion: 2017 | |
sourceType: module | |
env: | |
browser: true | |
# Note, "es6" just means es2015 globals are recognized. It is not implicit in | |
# the ecmaVersion curiously. | |
es6: true | |
rules: | |
# The categorization of rules in eslint’s own docs is strange imo. The | |
# following categorization (of the rules I turn on, anyway) I think makes more | |
# sense. | |
# STRAIGHT UP ERRORS: NO AMBIGUITY ########################################### | |
# | |
# I’m not sure why these rules are configurable since there’s no situation | |
# that would allow violations of them to be valid(?) | |
constructor-super: 2 # not valid ES | |
no-const-assign: 2 # not valid ES | |
no-invalid-regexp: 2 # not valid ES | |
no-new-symbol: 2 # not valid ES | |
no-obj-calls: 2 # means you can’t do "JSON()" etc | |
no-this-before-super: 2 # not valid ES | |
valid-typeof: 2 | |
# STRAIGHT UP ERRORS: DEPRECATED ############################################# | |
# | |
# More of the same, but specifically these are cases that were once valid code | |
# and no longer are, or only are valid outside of modules and strict mode. | |
no-debugger: 2 # invalid in module/strict ES | |
no-dupe-args: 2 # invalid in module/strict ES | |
no-octal: 2 # not part of ES anymore (e.g. "07" — "0o7" is okay) | |
no-octal-escape: 2 # not part of ES anymore (unicode/hex escape is okay) | |
no-undef: 2 # that is, reference errors | |
no-with: 2 # invalid in module/strict ES | |
# STRAIGHT UP ERRORS: NON-STANDARD ########################################### | |
# | |
# These two disallow use of properties which are non-standard extensions from | |
# the browserland chaos years. | |
no-caller: 2 # was never part of ES; now defined but throws in strict/module | |
no-iterator: 2 # was never part of ES | |
# POINTLESS CODE ############################################################# | |
# | |
# These rules disallow constructs which serve no purpose. A few of these | |
# teeter on the fuzzy edge, since stylistic preferences could dictate a | |
# divergence. However most point to likely mistakes, redundancy, or something | |
# silly. | |
no-compare-neg-zero: 2 | |
no-dupe-class-members: 2 | |
no-dupe-keys: 2 | |
no-else-return: 2 | |
no-empty: 2 # Not strictly pointless (catch), but valuable there, too. | |
no-empty-character-class: 2 | |
no-empty-pattern: 2 | |
no-extra-bind: 2 | |
no-extra-boolean-cast: 2 | |
no-extra-label: 2 | |
no-extra-parens: [ 2, all, { nestedBinaryExpressions: false } ] | |
no-extra-semi: 2 | |
no-lone-blocks: 2 | |
no-lonely-if: 2 | |
no-new-object: 2 | |
no-proto: 2 # Valid but annex b only; get/setPrototypeOf is standard | |
no-return-await: 2 # This is smart about catch now! | |
no-self-assign: 2 | |
no-self-compare: 2 # Not strictly pointless (NaN), but precluded by use-isnan | |
no-undef-init: 2 | |
no-unneeded-ternary: 2 | |
no-unreachable: 2 | |
no-unused-labels: 2 | |
no-unused-vars: 2 | |
no-useless-call: 2 | |
no-useless-concat: 2 | |
no-useless-constructor: 2 | |
no-useless-escape: 2 | |
no-useless-rename: 2 | |
no-useless-return: 2 | |
prefer-numeric-literals: 2 | |
prefer-spread: 2 | |
prefer-template: 2 | |
radix: [ 2, as-needed ] | |
require-yield: 2 | |
# GOTCHA CODE ################################################################ | |
# | |
# For my own code, I don’t enable rules that merely ban some construct because | |
# of perceived obscurity. I might make this list longer for shared codebase | |
# projects where that kind of thing is more understandable. What’s left are | |
# rules where the intent is to avoid simple errors that come from typos. | |
no-case-declarations: 2 # just means you need to add a block to case for scope | |
no-class-assign: 2 # class A {}; A = poop; | |
no-constant-condition: [ 2, { checkLoops: false } ] # opt imp. for generators | |
no-duplicate-case: 2 # fallthru is a feature! but dupe too weird even for me | |
no-ex-assign: 2 # fringe thing, suggests bug — catch (err) { err = poop; } | |
no-global-assign: 2 # redefining natives / env globals | |
no-implicit-globals: 2 # might only apply to script targets...? | |
no-label-var: 2 # foo: for (let foo... | |
no-new-wrappers: 2 # new String() | |
no-unexpected-multiline: 2 # linebreaks that make one expression look like two | |
no-unsafe-negation: 2 # e.g. !instanceof Foo | |
# PHILOSOPHICAL ############################################################## | |
# | |
# These are the meaty rules — the ones that dictate something about how we | |
# write in a deeper way. The difference from "gotcha" rules is that the | |
# problems these seek to avoid are less up front and more big picture. On the | |
# other hand, whether they are "wrong" or "right" depends on what you want | |
# that big picture to look like. | |
# For its intention, I really would like to enable class-methods-use-this, but | |
# in practice it’s not strictly true that all prototype methods should: there | |
# are actually three distinct occasions for prototype methods — they should | |
# employ `this` or `super` _or_ should be interface implementations for a | |
# super class (in which case they need not do either). So unfortunately this | |
# rule isn’t rational as -is. | |
# | |
# class-methods-use-this: 2 | |
# I didn’t always use eqeqeq. Way back my personal approach was from the | |
# other direction: use eqeq _except_ when you specifically need strict | |
# equality. But I came around on this one when I settled in to working with | |
# other people. Eqeq does trip some people up, and I found I appreciated the | |
# added clarity of intent provided by an explicit String() coercion or two. | |
# | |
eqeqeq: [ 2, always, { null: ignore } ] | |
# In the past, the one convention that everybody agreed on for ES was that | |
# there are only two places where Pascal case is acceptable: the names of | |
# native namespace objects (e.g. Math) and constructors. It was a golden rule, | |
# so much so that the presence of pascal case identifiers for non-constructor | |
# values was a quick litmus test for whether an author "really" does | |
# JavaScript. Recently the situation has changed. In theory, if you’re doing | |
# pure FP, it makes sense — that is, if you truly author code without `new`, | |
# you can get away with repurposing Pascal case to communicate something | |
# different. Except that’s not where this has been popping up — it seems to be | |
# commonly seen in usage of the latest generation of client frameworks, even | |
# those which make heavy use of constructors. This is, imo, a legit problem. | |
# Though questions of camel vs snake are stylistic, the pascal constructor | |
# constraint was never about style. ES has never provided a mechanism for | |
# introspecting whether a callable object is a constructor, even post class | |
# syntax, which is why this convention remains critical to observe — it is our | |
# only channel for communicating that information in the code. | |
# | |
new-cap: 2 | |
# The exception for extending natives is polyfills, but these are almost | |
# always tucked away in established libs. For the rare occasion that one needs | |
# to author a polyfill in their own code, I’m happy with the eslint-disable | |
# annotation to mark out the special case. | |
# | |
no-extend-native: 2 | |
# I see this as a matter of symmetry with using eqeqeq. It’s not a big deal, | |
# but I think it follows that if you’re gonna have explicit casts for one | |
# such case you probably ought to stick with that pattern elsewhere. Plus it’s | |
# better for FP stuff to prefer function-based casting: arr.filter(Boolean) | |
# | |
no-implicit-coercion: 2 | |
# This one is not contentious — in fact I think most people would agree that | |
# it’s strange that we’re allowed to throw non-Errors at all. Aside from | |
# violating API expectations (by their nature, thrown values are typically | |
# going to end up being part of your API if authoring a lib), one loses | |
# important metadata. | |
# | |
no-throw-literal: 2 | |
# Var statements are not officially but spiritually deprecated. | |
# | |
no-var: 2 | |
# Like class-methods-use-this, prefer-arrow-callback attempts ensuring that | |
# one’s choice to use non-lexical functions is always meaningful, except in | |
# this case there are no caveats to worry about. | |
# | |
prefer-arrow-callback: 2 | |
# An easy win, and again, removes any arbitrariness — there is a "right time" | |
# to use `let`. | |
# | |
prefer-const: 2 | |
# Corollary of no-throw-literal; rejection is just asynchronous throwing. This | |
# is not as widely understood because older userland Promise implementations | |
# did not really emphasize that promises are mainly about error propagration, | |
# since their sexy selling point was ergonomic. Hopefully with the arrival of | |
# async/await more folks will begin to understand that fulfill/reject is not | |
# intended as a tool for representing boolean results. | |
# | |
prefer-promise-reject-errors: 2 | |
# I don’t actually mind the idiomatic a === a NaN check personally, but I | |
# think this goes hand-in-hand with the greater outlook implied by choosing | |
# eqeqeq etc. since it makes it easier for someone less familiar with JS to | |
# understand the intention. | |
# | |
use-isnan: 2 | |
# STYLISTIC ################################################################## | |
# | |
# The remaining rules do nothing much except ensure visual consistency. I used | |
# to believe, at least subconsciously, that they were important. Indeed you | |
# can find a lot of discussion that suggests they are critical to ensuring | |
# maintainability and readability. And because I want code to be pretty, I’d | |
# have agreed. In some cases it’s true — erratic indentation for example does | |
# surely hurt clarity. But I’m no longer convinced on the whole. I’ve now | |
# worked a few times with people who might be considered messy and I can’t | |
# honestly report that their code was any less readable or maintainable than | |
# anybody else’s. So in addition to the following rules being pretty arbitrary | |
# compared to those above, I also think that it’s possible to overdo it and | |
# create work (especially for naturally loose folks) where none needed to | |
# exist. | |
# | |
# Also: I’ve come to avoid turning on hard style rules that have to do with | |
# alignment or property sorting because I think the human writer/reader will | |
# not infrequently know some out-of-band info that cannot be expressed by | |
# linter rules (although they are impressively configurable). When there’s a | |
# strong pattern in data or code that gets a readability boost from special | |
# case formatting, I’d like to be able to do it without needing an | |
# eslint-disable rule, which I prefer to reserve for cases where you actually | |
# want to say "I’m gonna do something weird here, okay?". | |
# | |
# Overall I tend to want spaces inside "things": | |
# | |
# [ { foo: `${ bar }` } ] | |
# | |
# ...which is the main thing here that diverges from eslint defaults. | |
array-bracket-spacing: [ 2, always ] | |
arrow-body-style: 2 | |
arrow-parens: [ 2, as-needed ] | |
arrow-spacing: 2 | |
block-spacing: 2 | |
brace-style: 2 | |
camelcase: 2 | |
comma-dangle: 2 | |
comma-spacing: 2 | |
comma-style: 2 | |
computed-property-spacing: 2 | |
# I waver on "curly". It directly contradicts no-lone-blocks / avoiding | |
# pointless statements. But I got used to this rule from prior teams and tend | |
# to leave it on now. | |
curly: 2 | |
dot-location: [ 2, property ] # very surprised this is not default? | |
dot-notation: [ 2, { allowPattern: "[A-Za-z]_" } ] | |
eol-last: 2 | |
func-call-spacing: 2 | |
func-style: [ 2, expression ] | |
generator-star-spacing: [ 2, { before: true, after: true } ] | |
indent: [ 2, 2, { SwitchCase: 1, MemberExpression: 1 } ] | |
key-spacing: [ 2, { mode: minimum } ] | |
keyword-spacing: 2 | |
linebreak-style: 2 | |
lines-around-directive: 2 | |
max-len: 2 | |
max-statements-per-line: 2 | |
new-parens: 2 | |
no-duplicate-imports: 2 | |
no-floating-decimal: 2 | |
no-irregular-whitespace: 2 | |
no-mixed-operators: | |
- 2 | |
- allowSamePrecedence: true | |
groups: # Allow for arithmetic, since those rules are pretty universal | |
- [ "&", "|", "^", "~", "<<", ">>", ">>>" ] | |
- [ "==", "!=", "===", "!==", ">", ">=", "<", "<=" ] | |
- [ "&&", "||" ] | |
no-multi-str: 2 | |
# Irrational personal peeve: | |
no-multiple-empty-lines: [ 2, { max: 1, maxEOF: 1, maxBOF: 0 } ] | |
no-tabs: 2 | |
no-trailing-spaces: 2 | |
no-whitespace-before-property: 2 | |
# Re-enable this when 4.0.0 lands — currently this rule is a nuisance. | |
# object-curly-newline: | |
# - 2 | |
# - consistent: true | |
# minProperties: 3 | |
# multiline: true | |
object-curly-spacing: [ 2, always ] | |
operator-linebreak: 2 | |
# Double quote is eslint default, surprisingly | |
quotes: [ 2, single, { avoidEscape: false, allowTemplateLiterals: true } ] | |
rest-spread-spacing: 2 | |
semi: 2 | |
semi-spacing: 2 | |
space-before-blocks: 2 | |
space-before-function-paren: | |
- 2 | |
- anonymous: never | |
named: never | |
asyncArrow: always | |
space-in-parens: 2 | |
# I’d turn space-infix-ops on, but it cannot distinguish default assignment | |
# yet. There are some long threads about it on GH so hopefully soon. | |
space-infix-ops: 0 | |
space-unary-ops: [ 2, { words: true, nonwords: false } ] | |
template-curly-spacing: [ 2, always ] | |
template-tag-spacing: 2 | |
yield-star-spacing: [ 2, both ] |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment