JavaScript
ESLint
逆噴射聡一郎

ESLintのルールを全部手動で設定するのは大変だからやめておけ

よく来たな。
お前がこの記事を見ているとゆうことは、やめておけとゆわれたことをあえてやろうとする真の男たらんとするものだろう。
軟弱な男たちがスマッホの予測変換に骨抜きにされている間にお前は反骨もあらわにここに来た。
おまえのそうゆう負けん気は実際大事だ。強くなければお前はメキシコで野垂れ死ぬだろう。
だが真の男と無謀は違う。
ときにお前は知の高速道路をもうダッシュするひつようがある。
つまり今がそのときとゆうことだ。

ESLintを入れろ

お前のJavaScriptがぐちゃぐちゃなことをおれはしっている。
なぜならおまえはESLintを使っていないからだ。
お前はコードの荒野を踏破できるタフな男を気取っているが、それにも限界が来るだろう。
今のままではお前が倒れ目を伏せるのはベイブの隣ではなく混沌としたコードの掃き溜めだ。

まずはESLintを入れろ。
簡単だ。
お前のその目の前の板の黒い部分に
npm install eslint
と入れろ。

そろそろ書くのが辛くなってきたからこいつらを見ろ。

見たな? 入れたな? 入れておけ。
入れたお前はコロナを飲んでいい。ESLintにはそれだけの価値がある。

ルールを設定しようとするな

お前は2つの記事でこう書かれていることを目ざとく見つけろ。

ESLint のルールの数は本当に多いです。組込みルールだけでも 200 以上。その上でプラグインが 200 以上公開されています。とてもではないけれど把握しきれません。
そこで、Shareable Config (共有設定) を使うと楽ができます。


ESLintにはルールが200以上あるためひとつずつ設定するのは大変です。
extendsプロパティを使うことでESLintおすすめのルールを読み込むことができます。

お前は寝返りが打てないくらい反骨のそうがある。お前のインストールはいつもカスンタムインストールだ。人のおすすめを頑として受けいれない。だがゲーム・オブ・スローンズは見ておけ。それが真の男だ。

ESLintのルールはここにある。
List of available rules - ESLint - Pluggable JavaScript linter
お前はこの程度コロナビールを飲みながらでも設定できると思い込む。
ルールの詳細を開き、GoodとBadのコードを読み、オプションを理解し好きな値を決めて理想のベイブをつくっていく。
お前はにっほん語とスペイン語しか解さない蛮人ゆえにときによくわからないルールが出る。
その度にお前はGoogleをくししてなんとか理解しようとする。

しばらくルールを設定していき、お前は気づく。「終わらない」。
あのリストで油断したお前は知らない。ルールの難解さとオプションの複雑さとをだ。
さらにお前はメキシコの荒野のような無秩序なコードの中で育ってきたタフな男だ。だがそれゆえにお前はお前のベストなルールをもはっきりと知らない。
お前はやがてドリトスを食っても拭いきれぬ疲労にみまわれるだろう。
だがやめることはできない。やめればここまでのルールは無駄になるし、真の男からも遠のく。
お前は引き返すこともできずに山のようなルールとコードとオプションを死んだ目でみてルールを作っていく。そして死ぬ。

おまえのルールは無効だ

おまえはおれの忠告を無視してすべてのルールを手動で設定した。そして生き残った。
おまえは真の男かもしれないが、おまえのあゆみはとまらない。
ESLintを入れただけでは今までのおまえのコードは何一つ綺麗にならない。おまえはメキシコの夕日よりも赤いコードを見ることになるだろう。
真の男ならばそこでeslint --fixではなくPrettierを入れる。

Prettierを知らないやつは

を見ろ。見たな。
おまえは記事でこう書かれていることを目ざとく見つけろ。

eslint-config-prettier(ESLintのフォーマット関連のルールを全て無効にする、ようはPrettierが整形した箇所に関してエラーを出さなくなる)

そうだ。おまえがひっしに書いてきた珠玉のルールは無効化される。おまえの苦難の道での歩みは否定される。
じっさいeslint-config-prettierが無効化するルールはそう多くはない。だがそんなことはおまえには関係がない。
おまえはただそのじじつに打ちひしがれなにもかもに無力感を覚えスマッホンの予測変換へすべてをゆだね・・・やがて老いて死ぬ。

おまえは生き残れる

お前は死ぬしかなかったのか? そんなことはない。おまえが真摯に人のゆうことを聞き

{
    "extends": "eslint:recommended",
}

と入れるだけでお前は凱旋を果たせる。
おすすめが気に入らないならその部分だけを書き換えることもできる。
他のチームがつくったプリセットをつかうこともできる。方法はおまえで探せ。おまえが腰抜けでなければかんたんだ。
いっけんおれはさきの記事と同じことをゆうようにみえるが、おれはすべてのルールを手動で設定した。そのおれがおまえにゆうのだ。そうゆうことだ。

それでもおまえは荒野をめざす

おれの話をきいた上でおまえたちの中には手動設定にこだわる男もいるだろう。
そんなおまえたちにおれが見てきた記事を紹介するときに真の男は何の躊躇もしない。

まずは

を見ろ。すこし古いがおおくのルールが解説されている。
ここにないル0ルがあれば

@mysticatea の記事をみろ。
かれはESLint の中の人でESLintの更新をちくいちQiitaに報告してくれる男の中の男だ。
あたらしいルールが出きたときはかれがかんたんな日本語とともに解説をしてくれている。
かれの記事はここからさがせ。

ESLint ルール 一覧 (日本語) - galife
もいい。一行でルールを解説してくれている。

あれら以外のものをおれはみていない。さがす時間があるならばルールを書け。もたもたしていると書ききる前におまえは虚無にのまれて死ぬだろう。


最後におれがかいたJSONを貼り付ける。
お前ももうわかっていると思うが、ここはおれのブログだ。
だからおまえに何の役にも立たないものを載せるときもある。

ル0ルの行すうだけでおよそ280ある。
みてのとおりPrettierも入れきれていない。
おれはこのコードをみるたびに虚脱感に襲われる。なぜrecommendedをそのまま使わなかったのか。そしてなぜ序盤に諦めなかったのかだ。
ESLintは進化を続ける。あたらしいルールは今後も増えていくだろう。そしておれはこのJSONを拡張していくのだろう。
おれはおまえたちにおれとおなじ過ちを犯してほしくない。おれがいいたいことはそれだけだ。

.eslintrc.json
{
    "env": {
        "browser"  : true,
        "node"     : true,
        "commonjs" : true,
        "es6"      : true
    },
    "extends": [
        "eslint:recommended",
        "plugin:eslint-comments/recommended"
    ],
    "parserOptions": {
        "ecmaVersion" : 2018,
        "ecmaFeatures": {
            "jsx": true
        },
        "sourceType"  : "module"
    },
    "plugins": [
        "eslint-comments",
        "react"
    ],
    "rules": {
        // Possible Errors
        "for-direction"               : "error",
        "getter-return"               : ["warn"],
        "no-await-in-loop"            : "warn",
        "no-compare-neg-zero"         : "error",
        "no-cond-assign"              : ["warn", "always"],
        "no-console"                  : ["warn"],
        "no-constant-condition"       : "error",
        "no-control-regex"            : "error",
        "no-debugger"                 : "error",
        "no-dupe-args"                : "error",
        "no-dupe-keys"                : "error",
        "no-duplicate-case"           : "error",
        "no-empty"                    : ["error"],
        "no-empty-character-class"    : "error",
        "no-ex-assign"                : "error",
        "no-extra-boolean-cast"       : "error",
        "no-extra-parens"             : ["off"],
        "no-extra-semi"               : "error",
        "no-func-assign"              : "error",
        "no-inner-declarations"       : ["error", "both"],
        "no-invalid-regexp"           : ["error"],
        "no-irregular-whitespace"     : ["error"], // 文字列もチェックしたほうが安全かなあ
        "no-obj-calls"                : "error",
        "no-prototype-builtins"       : "error",
        "no-regex-spaces"             : "warn",
        "no-sparse-arrays"            : "error",
        "no-template-curly-in-string" : "error",
        "no-unexpected-multiline"     : "error",
        "no-unreachable"              : "error",
        "no-unsafe-finally"           : "error",
        "no-unsafe-negation"          : "error",
        "use-isnan"                   : "error",
        "valid-jsdoc"                 : ["warn"],
        "valid-typeof"                : ["error"],

        // Best Practices
        "accessor-pairs"               : ["warn"],
        "array-callback-return"        : ["warn", { "allowImplicit": true }],
        "block-scoped-var"             : "warn",
        "class-methods-use-this"       : ["warn"],
        "complexity"                   : ["warn", {"max" : 20}],
        "consistent-return"            : ["error"],
        "curly"                        : ["error"],
        "default-case"                 : ["error"],
        "dot-location"                 : ["error", "property"],
        "dot-notation"                 : ["error"],
        "eqeqeq"                       : ["error", "smart"],
        "guard-for-in"                 : "off",
        "no-alert"                     : "warn",
        "no-caller"                    : "error",
        "no-case-declarations"         : "warn",
        "no-div-regex"                 : "error",
        "no-else-return"               : ["error", {"allowElseIf": false }],
        "no-empty-function"            : ["warn"],
        "no-empty-pattern"             : "error",
        "no-eq-null"                   : "error",
        "no-eval"                      : ["error"],
        "no-extend-native"             : ["error"],
        "no-extra-bind"                : "error",
        "no-extra-label"               : "error",
        "no-fallthrough"               : ["error", {"commentPattern": "break[\\s\\w]*omitted | no\\s?break"}],
        "no-floating-decimal"          : "error",
        "no-global-assign"             : ["error"],
        "no-implicit-coercion"         : ["off"],
        "no-implicit-globals"          : ["off"],
        "no-implied-eval"              : ["error"],
        "no-invalid-this"              : "error",
        "no-iterator"                  : "error",
        "no-labels"                    : "error",
        "no-lone-blocks"               : "error",
        "no-loop-func"                 : "error",
        "no-magic-numbers"             : ["warn", {"ignoreArrayIndexes": true}],
        "no-multi-spaces"              : ["warn", {
            "exceptions": 
            {
                "Property"           : true,
                "VariableDeclarator" : true,
                "ImportDeclaration"  : true
            }}],
        "no-multi-str"                 : "error",
        "no-new"                       : "error",
        "no-new-func"                  : "error",
        "no-new-wrappers"              : "error",
        "no-octal"                     : "error",
        "no-octal-escape"              : "error",
        "no-param-reassign"            : ["warn"],
        "no-proto"                     : "error",
        "no-redeclare"                 : ["error"],
        "no-restricted-properties"     : "off",
        "no-return-assign"             : "error",
        "no-return-await"              : "warn",
        "no-script-url"                : "error",
        "no-self-assign"               : ["error"],
        "no-self-compare"              : "error",
        "no-sequences"                 : ["warn"],
        "no-throw-literal"             : "error",
        "no-unmodified-loop-condition" : "error",
        "no-unused-expressions"        : ["error"],
        "no-unused-labels"             : "error",
        "no-useless-call"              : "error",
        "no-useless-concat"            : "error",
        "no-useless-escape"            : "error",
        "no-useless-return"            : "error",
        "no-void"                      : "error",
        "no-warning-comments"          : "warn",
        "no-with"                      : "error",
        "prefer-promise-reject-errors" : ["error", {"allowEmptyReject" : true}],
        "radix"                        : "error",
        "require-await"                : "warn",
        "vars-on-top"                  : "warn",
        "wrap-iife"                    : ["warn", "inside"],
        "yoda"                         : ["error", "never", {"exceptRange": true }],

        // Strict Mode
        "strict" : ["off"], // 保留

        // Variables
        "init-declarations"          : ["error"],
        "no-catch-shadow"            : "error",
        "no-delete-var"              : "error",
        "no-label-var"               : "error",
        "no-restricted-globals"      : ["warn"],
        "no-shadow"                  : ["warn"],
        "no-shadow-restricted-names" : "error",
        "no-undef"                   : ["error"],
        "no-undef-init"              : "error",
        "no-undefined"               : "error",
        "no-unused-vars"             : ["error"],
        "no-use-before-define"       : ["error"],

        // Node.js and CommonJS
        "callback-return"       : ["error"],
        "global-require"        : "error",
        "handle-callback-err"   : ["warn"],
        "no-buffer-constructor" : "warn",
        "no-mixed-requires"     : ["warn"],
        "no-new-require"        : "warn",
        "no-path-concat"        : "error",
        "no-process-env"        : "warn",
        "no-process-exit"       : "warn",
        "no-restricted-modules" : ["warn"],
        "no-sync"               : ["warn"],

        // Stylistic Issues
        "array-bracket-newline"       : ["error", {"multiline": true}],
        "array-bracket-spacing"       : ["error", "never"],
        "array-element-newline"       : ["error", {"multiline": true}],
        "block-spacing"               : ["error", "always"],
        "brace-style"                 : ["error", "1tbs", {"allowSingleLine": false}],
        "camelcase"                   : ["warn", {"properties": "always"}],
        "capitalized-comments"        : ["error"],
        "comma-dangle"                : ["error", "only-multiline", {
            "functions" : "never",
            "imports"   : "never",
            "exports"   : "never"
        }],
        "comma-spacing"               : ["error", {"before": false, "after": true}],
        "comma-style"                 : ["error", "last"],
        "computed-property-spacing"   : ["error", "never"],
        "consistent-this"             : ["warn"],
        "eol-last"                    : ["error", "always"],
        "func-call-spacing"           : ["error", "never"],
        "func-name-matching"          : ["warn"],
        "func-names"                  : ["off"],
        "func-style"                  : ["error", "expression"],
        "function-paren-newline"      : ["error", "multiline"],
        "id-blacklist"                : ["warn"],
        "id-length"                   : ["off"],
        "id-match"                    : ["off"],
        "implicit-arrow-linebreak"    : ["error", "beside"],
        "indent"                      : ["error", 4],
        "jsx-quotes"                  : ["error"],
        "key-spacing"                 : ["error", {
            "beforeColon" : true,
            "afterColon"  : true,
            "mode"        : "minimum",
            "align"       : "colon"
        }],
        "keyword-spacing"                  : ["error"],
        "line-comment-position"            : ["off"],
        "linebreak-style"                  : ["error", "unix"],
        "lines-around-comment"             : ["off"],
        "lines-between-class-members"      : ["error", "always"],
        "max-depth"                        : ["warn", {"max": 4}],
        "max-len"                          : ["off"],
        "max-lines"                        : ["off"],
        "max-nested-callbacks"             : ["error"],
        "max-params"                       : ["warn", {"max": 5}],
        "max-statements"                   : ["warn", {"max": 30}, {"ignoreTopLevelFunctions"       : true}],
        "max-statements-per-line"          : ["warn", {"max": 2}],
        "multiline-comment-style"          : ["warn", "starred-block"],
        "multiline-ternary"                : ["error", "always-multiline"],
        "new-cap"                          : ["error"],
        "new-parens"                       : ["error"],
        "newline-per-chained-call"         : ["error"],
        "no-array-constructor"             : ["error"],
        "no-bitwise"                       : ["error"],
        "no-continue"                      : "off",
        "no-inline-comments"               : "off",
        "no-lonely-if"                     : "error",
        "no-mixed-operators"               : ["error"],
        "no-mixed-spaces-and-tabs"         : ["error"],
        "no-multi-assign"                  : "error",
        "no-multiple-empty-lines"          : ["error"],
        "no-negated-condition"             : "error",
        "no-nested-ternary"                : "error",
        "no-new-object"                    : "error",
        "no-plusplus"                      : ["off"],
        "no-restricted-syntax"             : ["off"],
        "no-tabs"                          : "error",
        "no-ternary"                       : "off",
        "no-trailing-spaces"               : ["error"],
        "no-underscore-dangle"             : ["error"],
        "no-unneeded-ternary"              : ["error"],
        "no-whitespace-before-property"    : "error",
        "nonblock-statement-body-position" : ["off"], // そもそもnonblockを許さない
        "object-curly-newline"             : ["error", {"consistent": true}],
        "object-curly-spacing"             : ["error", "never"],
        "object-property-newline"          : ["error", {"allowAllPropertiesOnSameLine": true}],
        "one-var"                          : ["off"],
        "one-var-declaration-per-line"     : ["off"],
        "operator-assignment"              : ["warn"],
        "operator-linebreak"               : ["error", "before"],
        "padded-blocks"                    : ["error", "never"],
        "padding-line-between-statements"  : ["off"], // 保留
        "quote-props"                      : ["error", "as-needed"], // consistent-as-neededと悩み中
        "quotes"                           : ["error", "single", {"avoidEscape": true}],
        "require-jsdoc"                    : ["warn"],
        "semi"                             : ["error", "never"], // 無い方が好きだけどさー。他所のコードがねー?
        "semi-spacing"                     : ["error", {"before": false, "after": false}],
        "semi-style"                       : "error",
        "sort-keys"                        : ["off"],
        "sort-vars"                        : ["off"],
        "space-before-blocks"              : ["error", "always"],
        "space-before-function-paren"      : ["error", {
            "anonymous"  :"never",
            "named"      :"never",
            "asyncArrow" : "always"
        }],
        "space-in-parens"                  : ["error", "never"],
        "space-infix-ops"                  : ["error"],
        "space-unary-ops"                  : ["error", {
            "words"    : true,
            "nonwords" : false
        }],
        "spaced-comment"                   : ["error", "always"],
        "switch-colon-spacing"             : ["error"],
        "template-tag-spacing"             : ["error"], // タグ使わないので保留
        "unicode-bom"                      : ["error", "never"],
        "wrap-regex"                       : "off",

        // ECMAScript 6
        "arrow-body-style"        : ["error", "as-needed"],
        "arrow-parens"            : ["error", "as-needed"],
        "arrow-spacing"           : ["error"],
        "constructor-super"       : "error",
        "generator-star-spacing"  : ["error", {
            "before" : false,
            "after"  : true
        }],
        "no-class-assign"         : "error",
        "no-confusing-arrow"      : ["off"], // 簡単な三項演算子は使いたいかもしれないので、保留
        "no-const-assign"         : "error",
        "no-dupe-class-members"   : "error",
        "no-duplicate-imports"    : ["error"],
        "no-new-symbol"           : "error",
        "no-restricted-imports"   : ["warn"],
        "no-this-before-super"    : "error",
        "no-useless-computed-key" : "error",
        "no-useless-constructor"  : "error",
        "no-useless-rename"       : ["error"],
        "no-var"                  : "error",
        "object-shorthand"        : ["error"],
        "prefer-arrow-callback"   : ["error"],
        "prefer-const"            : ["error"],
        "prefer-destructuring"    : ["warn"],
        "prefer-numeric-literals" : ["off"],
        "prefer-rest-params"      : "error",
        "prefer-spread"           : "error",
        "prefer-template"         : "warn",
        "require-yield"           : "error",
        "rest-spread-spacing"     : ["error", "never"],
        "sort-imports" : ["off"],
        "symbol-description" : "error",
        "template-curly-spacing" : ["error", "never"],
        "yield-star-spacing" : ["error", {
            "before" : false,
            "after"  : true
        }]
    }
}