Navigation Menu

Skip to content

Instantly share code, notes, and snippets.

@bathos
Last active May 18, 2017 22:15
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save bathos/f9dec570b175c6c84b45cd48fa579394 to your computer and use it in GitHub Desktop.
Save bathos/f9dec570b175c6c84b45cd48fa579394 to your computer and use it in GitHub Desktop.
personal eslint config 2017 update
%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