From ae1549ce22c6900e179e7d359e560b2e1efb97e2 Mon Sep 17 00:00:00 2001 From: Matt DuLeone Date: Wed, 8 Aug 2018 17:30:02 -0400 Subject: [PATCH 1/2] Update rules and create rules json (#1) * Update rules and create rules json * Make suggested changes --- README.md | 30 + linters/eslintrc.json | 1709 +++++++++++++++++ package.json | 4 +- .../rules/best-practices.js | 35 +- .../rules/imports.js | 13 +- .../eslint-config-airbnb-base/rules/node.js | 2 +- .../eslint-config-airbnb-base/rules/style.js | 44 +- .../rules/variables.js | 3 +- packages/eslint-config-airbnb/index.js | 10 +- .../eslint-config-airbnb/rules/react-a11y.js | 3 +- packages/eslint-config-airbnb/rules/react.js | 20 +- print.js | 33 + 12 files changed, 1836 insertions(+), 70 deletions(-) create mode 100644 linters/eslintrc.json create mode 100644 print.js diff --git a/README.md b/README.md index c2840b0b6f..e5a88920a6 100644 --- a/README.md +++ b/README.md @@ -3661,4 +3661,34 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. We encourage you to fork this guide and change the rules to fit your team’s style guide. Below, you may list some amendments to the style guide. This allows you to periodically update your style guide without having to deal with merge conflicts. +- Require all control statements to be wrapped in curly braces. AirBnb allows single line ifs, where we prefer the default behavior: every control statement has curlies +- Require all switch statements to have a default case or a comment matching /^no default$/i (case insensitive). AirBnb prefers forcing lower case. +- Require `===` and `!==` always. AirBnb allows `==` and `!=` when comparing against `null`, we prefer to always require `===` or `!==` +- Disallow allowing case statements to fallthrough, unless we comment to explicitly allow it. AirBnb prefers to disallow falling through entirely +- We prefer to enforce a clean global scope, where AirBnb turns off this enforcement +- We allow reassignment of function parameters, where AirBnb disallows it save for some exceptions +- We want to prevent unused expressions, while allowing short circuiting. AirBnb prefers to disallow short circuiting, as well +- Disallow use of undefined variable +- We prefer to use `import` statements to retrieve our module code, restricting usage of `require` to only cases where we specifically want to conditionally or synchronously require a module. An example of this use case can be seen in [SliceLink's router](https://github.com/mypizza/slice_hub/blob/master/src/routes.js#L16-L27). We use `require` specifically to allow both importing and mounting sandbox routes only in development, so they are not included in the production bundle due to dead code elminiation. AirBnb prefers to force require statements be in the top level of modules. +- Enforce line breaks after opening and before closing array brackets +- Enforce line breaks between array elements +- AirBnb prefers to allow single-line blocks. We prefer to disallow them +- We prefer enforcing function declarations and allowing arrow functions +- We prefer to use double quotes in JSX to allow strings to have apostrophes +- AirBnb prefers to enforce spaces between single line class members, while we prefer to allow no lines between single line class members +- AirBnb prefers to limit the max len to 100 characters, while we prefer to make the max len 120 +- Unsure what rule they would set, but we prefer to enforce a multiline if the expression spans multiple lines +- AirBnb disallows `++` and `--`, while we prefer to alllow them. We can safely allow `++` and `--` because we require semicolons, so we are not subject to ASI induced errors +- AirBnb prefers to disallow dangling underscores, while we prefer to allow them as ref-holder- and pseudo-private-members of React Element Classes +- Quote props: AirBnb prefers as-needed, but we prefer consistent-as-needed to allow for consistent props +- We prefer to ensure our imports exist +- We prefer to export default a named entity +- Enforce consistent usage of destructuring assignment of props, state, and context +- AirBnb prefers to forbid the proptypes `any`, `array`, and `object`. We prefer to allow these proptype types +- Prevent using this.state within a this.setState +- Directly mutating this.state is dangerous and can lead to some very bad things. We prefer to disallow it. +- Prevent this from being used in stateless functional components +- AirBnb prefers to enforce only `.jsx` file extension files may contain JSX. We prefer all our files to allow JSX. +- Validate JSX has key prop when in array or iterator + # }; diff --git a/linters/eslintrc.json b/linters/eslintrc.json new file mode 100644 index 0000000000..299d88d80f --- /dev/null +++ b/linters/eslintrc.json @@ -0,0 +1,1709 @@ +{ + "env": { + "es6": true, + "node": true + }, + "parserOptions": { + "ecmaVersion": 6, + "sourceType": "module", + "ecmaFeatures": { + "generators": false, + "objectLiteralDuplicateProperties": false, + "jsx": true + } + }, + "plugins": [ + "import", + "react", + "jsx-a11y" + ], + "settings": { + "import/resolver": { + "node": { + "extensions": [ + ".mjs", + ".js", + ".json", + ".js", + ".jsx", + ".json" + ] + } + }, + "import/extensions": [ + ".js", + ".mjs", + ".jsx" + ], + "import/core-modules": [], + "import/ignore": [ + "node_modules", + "\\.(coffee|scss|css|less|hbs|svg|json)$" + ], + "react": { + "pragma": "React", + "version": "16.0" + }, + "propWrapperFunctions": [ + "forbidExtraProps", + "exact", + "Object.freeze" + ] + }, + "rules": { + "import/no-unresolved": [ + "error", + { + "commonjs": true, + "caseSensitive": true + } + ], + "import/named": "error", + "import/default": "error", + "import/namespace": "error", + "import/export": "error", + "import/no-named-as-default": "error", + "import/no-named-as-default-member": "error", + "import/no-deprecated": "off", + "import/no-extraneous-dependencies": [ + "error", + { + "devDependencies": [ + "test/**", + "tests/**", + "spec/**", + "**/__tests__/**", + "test.{js,jsx}", + "test-*.{js,jsx}", + "**/*.{test,spec}.{js,jsx}", + "**/jest.config.js", + "**/webpack.config.js", + "**/webpack.config.*.js", + "**/rollup.config.js", + "**/rollup.config.*.js", + "**/gulpfile.js", + "**/gulpfile.*.js", + "**/Gruntfile{,.js}", + "**/protractor.conf.js", + "**/protractor.conf.*.js" + ], + "optionalDependencies": false + } + ], + "import/no-mutable-exports": "error", + "import/no-commonjs": "off", + "import/no-amd": "error", + "import/no-nodejs-modules": "off", + "import/first": [ + "error", + "absolute-first" + ], + "import/imports-first": "off", + "import/no-duplicates": "error", + "import/no-namespace": "off", + "import/extensions": [ + "error", + "always", + { + "js": "never", + "mjs": "never", + "jsx": "never" + } + ], + "import/order": [ + "off", + { + "groups": [ + "builtin", + "external", + "internal", + "parent", + "sibling", + "index" + ], + "newlines-between": "never" + } + ], + "import/newline-after-import": "error", + "import/prefer-default-export": "error", + "import/no-restricted-paths": "off", + "import/max-dependencies": [ + "off", + { + "max": 10 + } + ], + "import/no-absolute-path": "error", + "import/no-dynamic-require": "error", + "import/no-internal-modules": [ + "off", + { + "allow": [] + } + ], + "import/unambiguous": "off", + "import/no-webpack-loader-syntax": "error", + "import/no-unassigned-import": "off", + "import/no-named-default": "error", + "import/no-anonymous-default-export": "error", + "import/exports-last": "off", + "accessor-pairs": "off", + "array-callback-return": [ + "error", + { + "allowImplicit": true + } + ], + "block-scoped-var": "error", + "complexity": [ + "off", + 11 + ], + "consistent-return": "error", + "curly": "error", + "default-case": "error", + "dot-notation": [ + "error", + { + "allowKeywords": true + } + ], + "dot-location": [ + "error", + "property" + ], + "eqeqeq": [ + "error", + "always", + { + "null": "always" + } + ], + "guard-for-in": "error", + "no-alert": "warn", + "no-caller": "error", + "no-case-declarations": "error", + "no-div-regex": "off", + "no-else-return": [ + "error", + { + "allowElseIf": false + } + ], + "no-empty-function": [ + "error", + { + "allow": [ + "arrowFunctions", + "functions", + "methods" + ] + } + ], + "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": "[\\s\\w]*fall(through|thru)[\\s\\w]*}" + } + ], + "no-floating-decimal": "error", + "no-global-assign": [ + "error", + { + "exceptions": [] + } + ], + "no-native-reassign": "off", + "no-implicit-coercion": [ + "off", + { + "boolean": false, + "number": true, + "string": true, + "allow": [] + } + ], + "no-implicit-globals": "error", + "no-implied-eval": "error", + "no-invalid-this": "off", + "no-iterator": "error", + "no-labels": [ + "error", + { + "allowLoop": false, + "allowSwitch": false + } + ], + "no-lone-blocks": "error", + "no-loop-func": "error", + "no-magic-numbers": [ + "off", + { + "ignore": [], + "ignoreArrayIndexes": true, + "enforceConst": true, + "detectObjects": false + } + ], + "no-multi-spaces": [ + "error", + { + "ignoreEOLComments": false + } + ], + "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": "off", + "no-proto": "error", + "no-redeclare": "error", + "no-restricted-properties": [ + "error", + { + "object": "arguments", + "property": "callee", + "message": "arguments.callee is deprecated" + }, + { + "object": "global", + "property": "isFinite", + "message": "Please use Number.isFinite instead" + }, + { + "object": "self", + "property": "isFinite", + "message": "Please use Number.isFinite instead" + }, + { + "object": "window", + "property": "isFinite", + "message": "Please use Number.isFinite instead" + }, + { + "object": "global", + "property": "isNaN", + "message": "Please use Number.isNaN instead" + }, + { + "object": "self", + "property": "isNaN", + "message": "Please use Number.isNaN instead" + }, + { + "object": "window", + "property": "isNaN", + "message": "Please use Number.isNaN instead" + }, + { + "property": "__defineGetter__", + "message": "Please use Object.defineProperty instead." + }, + { + "property": "__defineSetter__", + "message": "Please use Object.defineProperty instead." + }, + { + "object": "Math", + "property": "pow", + "message": "Use the exponentiation operator (**) instead." + } + ], + "no-return-assign": [ + "error", + "always" + ], + "no-return-await": "error", + "no-script-url": "error", + "no-self-assign": "error", + "no-self-compare": "error", + "no-sequences": "error", + "no-throw-literal": "error", + "no-unmodified-loop-condition": "off", + "no-unused-expressions": [ + "error", + { + "allowShortCircuit": true, + "allowTernary": false, + "allowTaggedTemplates": false + } + ], + "no-unused-labels": "error", + "no-useless-call": "off", + "no-useless-concat": "error", + "no-useless-escape": "error", + "no-useless-return": "error", + "no-void": "error", + "no-warning-comments": [ + "off", + { + "terms": [ + "todo", + "fixme", + "xxx" + ], + "location": "start" + } + ], + "no-with": "error", + "prefer-promise-reject-errors": [ + "error", + { + "allowEmptyReject": true + } + ], + "radix": "error", + "require-await": "off", + "vars-on-top": "error", + "wrap-iife": [ + "error", + "outside", + { + "functionPrototypeMethods": false + } + ], + "yoda": "error", + "for-direction": "error", + "getter-return": [ + "error", + { + "allowImplicit": true + } + ], + "no-await-in-loop": "error", + "no-compare-neg-zero": "error", + "no-cond-assign": [ + "error", + "always" + ], + "no-console": "warn", + "no-constant-condition": "warn", + "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", + "all", + { + "conditionalAssign": true, + "nestedBinaryExpressions": false, + "returnAssign": false, + "ignoreJSX": "all", + "enforceForArrowConditionals": false + } + ], + "no-extra-semi": "error", + "no-func-assign": "error", + "no-inner-declarations": "error", + "no-invalid-regexp": "error", + "no-irregular-whitespace": "error", + "no-obj-calls": "error", + "no-prototype-builtins": "error", + "no-regex-spaces": "error", + "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", + "no-negated-in-lhs": "off", + "use-isnan": "error", + "valid-jsdoc": "off", + "valid-typeof": [ + "error", + { + "requireStringLiterals": true + } + ], + "callback-return": "off", + "global-require": "off", + "handle-callback-err": "off", + "no-buffer-constructor": "error", + "no-mixed-requires": [ + "off", + false + ], + "no-new-require": "error", + "no-path-concat": "error", + "no-process-env": "off", + "no-process-exit": "off", + "no-restricted-modules": "off", + "no-sync": "off", + "array-bracket-newline": [ + "error", + { + "multiline": true + } + ], + "array-element-newline": [ + "error", + "always" + ], + "array-bracket-spacing": [ + "error", + "never" + ], + "block-spacing": [ + "error", + "always" + ], + "brace-style": [ + "error", + "1tbs", + { + "allowSingleLine": false + } + ], + "camelcase": [ + "error", + { + "properties": "never" + } + ], + "capitalized-comments": [ + "off", + "never", + { + "line": { + "ignorePattern": ".*", + "ignoreInlineComments": true, + "ignoreConsecutiveComments": true + }, + "block": { + "ignorePattern": ".*", + "ignoreInlineComments": true, + "ignoreConsecutiveComments": true + } + } + ], + "comma-dangle": [ + "error", + { + "arrays": "always-multiline", + "objects": "always-multiline", + "imports": "always-multiline", + "exports": "always-multiline", + "functions": "always-multiline" + } + ], + "comma-spacing": [ + "error", + { + "before": false, + "after": true + } + ], + "comma-style": [ + "error", + "last", + { + "exceptions": { + "ArrayExpression": false, + "ArrayPattern": false, + "ArrowFunctionExpression": false, + "CallExpression": false, + "FunctionDeclaration": false, + "FunctionExpression": false, + "ImportDeclaration": false, + "ObjectExpression": false, + "ObjectPattern": false, + "VariableDeclaration": false, + "NewExpression": false + } + } + ], + "computed-property-spacing": [ + "error", + "never" + ], + "consistent-this": "off", + "eol-last": [ + "error", + "always" + ], + "func-call-spacing": [ + "error", + "never" + ], + "func-name-matching": [ + "off", + "always", + { + "includeCommonJSModuleExports": false + } + ], + "func-names": "warn", + "func-style": [ + "error", + "declaration", + { + "allowArrowFunctions": true + } + ], + "function-paren-newline": [ + "error", + "multiline" + ], + "id-blacklist": "off", + "id-length": "off", + "id-match": "off", + "implicit-arrow-linebreak": [ + "error", + "beside" + ], + "indent": [ + "error", + 2, + { + "SwitchCase": 1, + "VariableDeclarator": 1, + "outerIIFEBody": 1, + "FunctionDeclaration": { + "parameters": 1, + "body": 1 + }, + "FunctionExpression": { + "parameters": 1, + "body": 1 + }, + "CallExpression": { + "arguments": 1 + }, + "ArrayExpression": 1, + "ObjectExpression": 1, + "ImportDeclaration": 1, + "flatTernaryExpressions": false, + "ignoredNodes": [ + "JSXElement", + "JSXElement > *", + "JSXAttribute", + "JSXIdentifier", + "JSXNamespacedName", + "JSXMemberExpression", + "JSXSpreadAttribute", + "JSXExpressionContainer", + "JSXOpeningElement", + "JSXClosingElement", + "JSXText", + "JSXEmptyExpression", + "JSXSpreadChild" + ], + "ignoreComments": false + } + ], + "key-spacing": [ + "error", + { + "beforeColon": false, + "afterColon": true + } + ], + "keyword-spacing": [ + "error", + { + "before": true, + "after": true, + "overrides": { + "return": { + "after": true + }, + "throw": { + "after": true + }, + "case": { + "after": true + } + } + } + ], + "line-comment-position": [ + "off", + { + "position": "above", + "ignorePattern": "", + "applyDefaultPatterns": true + } + ], + "linebreak-style": [ + "error", + "unix" + ], + "lines-between-class-members": [ + "error", + "always", + { + "exceptAfterSingleLine": true + } + ], + "lines-around-comment": "off", + "lines-around-directive": "off", + "max-depth": [ + "off", + 4 + ], + "max-len": [ + "error", + 120, + 2, + { + "ignoreUrls": true, + "ignoreComments": false, + "ignoreRegExpLiterals": true, + "ignoreStrings": true, + "ignoreTemplateLiterals": true + } + ], + "max-lines": [ + "off", + { + "max": 300, + "skipBlankLines": true, + "skipComments": true + } + ], + "max-nested-callbacks": "off", + "max-params": [ + "off", + 3 + ], + "max-statements": [ + "off", + 10 + ], + "max-statements-per-line": [ + "off", + { + "max": 1 + } + ], + "multiline-comment-style": [ + "off", + "starred-block" + ], + "multiline-ternary": [ + "error", + "always-multiline" + ], + "new-cap": [ + "error", + { + "newIsCap": true, + "newIsCapExceptions": [], + "capIsNew": false, + "capIsNewExceptions": [ + "Immutable.Map", + "Immutable.Set", + "Immutable.List" + ] + } + ], + "new-parens": "error", + "newline-after-var": "off", + "newline-before-return": "off", + "newline-per-chained-call": [ + "error", + { + "ignoreChainWithDepth": 4 + } + ], + "no-array-constructor": "error", + "no-bitwise": "error", + "no-continue": "error", + "no-inline-comments": "off", + "no-lonely-if": "error", + "no-mixed-operators": [ + "error", + { + "groups": [ + [ + "%", + "**" + ], + [ + "%", + "+" + ], + [ + "%", + "-" + ], + [ + "%", + "*" + ], + [ + "%", + "/" + ], + [ + "**", + "+" + ], + [ + "**", + "-" + ], + [ + "**", + "*" + ], + [ + "**", + "/" + ], + [ + "&", + "|", + "^", + "~", + "<<", + ">>", + ">>>" + ], + [ + "==", + "!=", + "===", + "!==", + ">", + ">=", + "<", + "<=" + ], + [ + "&&", + "||" + ], + [ + "in", + "instanceof" + ] + ], + "allowSamePrecedence": false + } + ], + "no-mixed-spaces-and-tabs": "error", + "no-multi-assign": [ + "error" + ], + "no-multiple-empty-lines": [ + "error", + { + "max": 2, + "maxEOF": 1 + } + ], + "no-negated-condition": "off", + "no-nested-ternary": "error", + "no-new-object": "error", + "no-plusplus": "off", + "no-restricted-syntax": [ + "error", + { + "selector": "ForInStatement", + "message": "for..in loops iterate over the entire prototype chain, which is virtually never what you want. Use Object.{keys,values,entries}, and iterate over the resulting array." + }, + { + "selector": "ForOfStatement", + "message": "iterators/generators require regenerator-runtime, which is too heavyweight for this guide to allow them. Separately, loops should be avoided in favor of array iterations." + }, + { + "selector": "LabeledStatement", + "message": "Labels are a form of GOTO; using them makes code confusing and hard to maintain and understand." + }, + { + "selector": "WithStatement", + "message": "`with` is disallowed in strict mode because it makes code impossible to predict and optimize." + } + ], + "no-spaced-func": "off", + "no-tabs": "error", + "no-ternary": "off", + "no-trailing-spaces": [ + "error", + { + "skipBlankLines": false, + "ignoreComments": false + } + ], + "no-underscore-dangle": "off", + "no-unneeded-ternary": [ + "error", + { + "defaultAssignment": false + } + ], + "no-whitespace-before-property": "error", + "nonblock-statement-body-position": [ + "error", + "beside", + { + "overrides": {} + } + ], + "object-curly-spacing": [ + "error", + "always" + ], + "object-curly-newline": [ + "error", + { + "ObjectExpression": { + "minProperties": 4, + "multiline": true, + "consistent": true + }, + "ObjectPattern": { + "minProperties": 4, + "multiline": true, + "consistent": true + } + } + ], + "object-property-newline": [ + "error", + { + "allowAllPropertiesOnSameLine": true + } + ], + "one-var": [ + "error", + "never" + ], + "one-var-declaration-per-line": [ + "error", + "always" + ], + "operator-assignment": [ + "error", + "always" + ], + "operator-linebreak": [ + "error", + "before", + { + "overrides": { + "=": "none" + } + } + ], + "padded-blocks": [ + "error", + { + "blocks": "never", + "classes": "never", + "switches": "never" + } + ], + "padding-line-between-statements": [ + "error", + { + "blankLine": "always", + "prev": "*", + "next": "directive" + }, + { + "blankLine": "always", + "prev": "directive", + "next": "*" + } + ], + "quote-props": [ + "error", + "consistent-as-needed", + { + "keywords": false, + "unnecessary": false, + "numbers": false + } + ], + "quotes": [ + "error", + "single", + { + "avoidEscape": true + } + ], + "require-jsdoc": "off", + "semi": [ + "error", + "always" + ], + "semi-spacing": [ + "error", + { + "before": false, + "after": true + } + ], + "semi-style": [ + "error", + "last" + ], + "sort-keys": [ + "off", + "asc", + { + "caseSensitive": false, + "natural": true + } + ], + "sort-vars": "off", + "space-before-blocks": "error", + "space-before-function-paren": [ + "error", + { + "anonymous": "always", + "named": "never", + "asyncArrow": "always" + } + ], + "space-in-parens": [ + "error", + "never" + ], + "space-infix-ops": "error", + "space-unary-ops": [ + "error", + { + "words": true, + "nonwords": false, + "overrides": {} + } + ], + "spaced-comment": [ + "error", + "always", + { + "line": { + "exceptions": [ + "-", + "+" + ], + "markers": [ + "=", + "!" + ] + }, + "block": { + "exceptions": [ + "-", + "+" + ], + "markers": [ + "=", + "!" + ], + "balanced": true + } + } + ], + "switch-colon-spacing": [ + "error", + { + "after": true, + "before": false + } + ], + "template-tag-spacing": [ + "error", + "never" + ], + "unicode-bom": [ + "error", + "never" + ], + "wrap-regex": "off", + "init-declarations": "off", + "no-catch-shadow": "off", + "no-delete-var": "error", + "no-label-var": "error", + "no-restricted-globals": [ + "error", + "isFinite", + "isNaN", + "addEventListener", + "blur", + "close", + "closed", + "confirm", + "defaultStatus", + "event", + "external", + "defaultstatus", + "find", + "focus", + "frameElement", + "frames", + "history", + "innerHeight", + "innerWidth", + "length", + "location", + "locationbar", + "menubar", + "moveBy", + "moveTo", + "name", + "onblur", + "onerror", + "onfocus", + "onload", + "onresize", + "onunload", + "open", + "opener", + "opera", + "outerHeight", + "outerWidth", + "pageXOffset", + "pageYOffset", + "parent", + "print", + "removeEventListener", + "resizeBy", + "resizeTo", + "screen", + "screenLeft", + "screenTop", + "screenX", + "screenY", + "scroll", + "scrollbars", + "scrollBy", + "scrollTo", + "scrollX", + "scrollY", + "self", + "status", + "statusbar", + "stop", + "toolbar", + "top" + ], + "no-shadow": "error", + "no-shadow-restricted-names": "error", + "no-undef": "error", + "no-undef-init": "error", + "no-undefined": "error", + "no-unused-vars": [ + "error", + { + "vars": "all", + "args": "after-used", + "ignoreRestSiblings": true + } + ], + "no-use-before-define": [ + "error", + { + "functions": true, + "classes": true, + "variables": true + } + ], + "arrow-body-style": [ + "error", + "as-needed", + { + "requireReturnForObjectLiteral": false + } + ], + "arrow-parens": [ + "error", + "as-needed", + { + "requireForBlockBody": true + } + ], + "arrow-spacing": [ + "error", + { + "before": true, + "after": true + } + ], + "constructor-super": "error", + "generator-star-spacing": [ + "error", + { + "before": false, + "after": true + } + ], + "no-class-assign": "error", + "no-confusing-arrow": [ + "error", + { + "allowParens": true + } + ], + "no-const-assign": "error", + "no-dupe-class-members": "error", + "no-duplicate-imports": "off", + "no-new-symbol": "error", + "no-restricted-imports": [ + "off", + { + "paths": [], + "patterns": [] + } + ], + "no-this-before-super": "error", + "no-useless-computed-key": "error", + "no-useless-constructor": "error", + "no-useless-rename": [ + "error", + { + "ignoreDestructuring": false, + "ignoreImport": false, + "ignoreExport": false + } + ], + "no-var": "error", + "object-shorthand": [ + "error", + "always", + { + "ignoreConstructors": false, + "avoidQuotes": true + } + ], + "prefer-arrow-callback": [ + "error", + { + "allowNamedFunctions": false, + "allowUnboundThis": true + } + ], + "prefer-const": [ + "error", + { + "destructuring": "any", + "ignoreReadBeforeAssign": true + } + ], + "prefer-destructuring": [ + "error", + { + "VariableDeclarator": { + "array": false, + "object": true + }, + "AssignmentExpression": { + "array": true, + "object": true + } + }, + { + "enforceForRenamedProperties": false + } + ], + "prefer-numeric-literals": "error", + "prefer-reflect": "off", + "prefer-rest-params": "error", + "prefer-spread": "error", + "prefer-template": "error", + "require-yield": "error", + "rest-spread-spacing": [ + "error", + "never" + ], + "sort-imports": [ + "off", + { + "ignoreCase": false, + "ignoreMemberSort": false, + "memberSyntaxSortOrder": [ + "none", + "all", + "multiple", + "single" + ] + } + ], + "symbol-description": "error", + "template-curly-spacing": "error", + "yield-star-spacing": [ + "error", + "after" + ], + "strict": [ + "error", + "never" + ], + "jsx-quotes": [ + "error", + "prefer-double" + ], + "class-methods-use-this": [ + "error", + { + "exceptMethods": [ + "render", + "getInitialState", + "getDefaultProps", + "getChildContext", + "componentWillMount", + "componentDidMount", + "componentWillReceiveProps", + "shouldComponentUpdate", + "componentWillUpdate", + "componentDidUpdate", + "componentWillUnmount", + "componentDidCatch" + ] + } + ], + "react/destructuring-assignment": [ + "error", + "always" + ], + "react/display-name": [ + "off", + { + "ignoreTranspilerName": false + } + ], + "react/forbid-prop-types": "off", + "react/jsx-boolean-value": [ + "error", + "never", + { + "always": [] + } + ], + "react/jsx-closing-bracket-location": [ + "error", + "line-aligned" + ], + "react/jsx-closing-tag-location": "error", + "react/jsx-curly-spacing": [ + "error", + "never", + { + "allowMultiline": true + } + ], + "react/jsx-handler-names": [ + "off", + { + "eventHandlerPrefix": "handle", + "eventHandlerPropPrefix": "on" + } + ], + "react/jsx-indent-props": [ + "error", + 2 + ], + "react/jsx-key": "error", + "react/jsx-max-props-per-line": [ + "error", + { + "maximum": 1, + "when": "multiline" + } + ], + "react/jsx-no-bind": [ + "error", + { + "ignoreRefs": true, + "allowArrowFunctions": true, + "allowBind": false + } + ], + "react/jsx-no-duplicate-props": [ + "error", + { + "ignoreCase": true + } + ], + "react/jsx-no-literals": [ + "off", + { + "noStrings": true + } + ], + "react/jsx-no-undef": "error", + "react/jsx-pascal-case": [ + "error", + { + "allowAllCaps": true, + "ignore": [] + } + ], + "react/sort-prop-types": [ + "off", + { + "ignoreCase": true, + "callbacksLast": false, + "requiredFirst": false + } + ], + "react/jsx-sort-prop-types": "off", + "react/jsx-sort-props": [ + "off", + { + "ignoreCase": true, + "callbacksLast": false, + "shorthandFirst": false, + "shorthandLast": false, + "noSortAlphabetically": false, + "reservedFirst": true + } + ], + "react/jsx-uses-react": [ + "error" + ], + "react/jsx-uses-vars": "error", + "react/no-access-state-in-setstate": "error", + "react/no-danger": "warn", + "react/no-deprecated": [ + "error" + ], + "react/no-did-mount-set-state": "off", + "react/no-did-update-set-state": "error", + "react/no-will-update-set-state": "error", + "react/no-direct-mutation-state": "error", + "react/no-is-mounted": "error", + "react/no-multi-comp": [ + "error", + { + "ignoreStateless": true + } + ], + "react/no-set-state": "off", + "react/no-string-refs": "error", + "react/no-this-in-sfc": "error", + "react/no-unknown-property": "error", + "react/prefer-es6-class": [ + "error", + "always" + ], + "react/prefer-stateless-function": [ + "error", + { + "ignorePureComponents": true + } + ], + "react/prop-types": [ + "error", + { + "ignore": [], + "customValidators": [], + "skipUndeclared": false + } + ], + "react/react-in-jsx-scope": "error", + "react/require-render-return": "error", + "react/self-closing-comp": "error", + "react/sort-comp": [ + "error", + { + "order": [ + "static-methods", + "lifecycle", + "/^on.+$/", + "getters", + "setters", + "/^(get|set)(?!(InitialState$|DefaultProps$|ChildContext$)).+$/", + "everything-else", + "/^render.+$/", + "render" + ] + } + ], + "react/jsx-wrap-multilines": [ + "error", + { + "declaration": true, + "assignment": true, + "return": true, + "arrow": true + } + ], + "react/jsx-first-prop-new-line": [ + "error", + "multiline-multiprop" + ], + "react/jsx-equals-spacing": [ + "error", + "never" + ], + "react/jsx-indent": [ + "error", + 2 + ], + "react/jsx-no-target-blank": "error", + "react/jsx-filename-extension": "off", + "react/jsx-no-comment-textnodes": "error", + "react/no-render-return-value": "error", + "react/require-optimization": [ + "off", + { + "allowDecorators": [] + } + ], + "react/no-find-dom-node": "error", + "react/forbid-component-props": [ + "off", + { + "forbid": [] + } + ], + "react/forbid-elements": [ + "off", + { + "forbid": [] + } + ], + "react/no-danger-with-children": "error", + "react/no-unused-prop-types": [ + "error", + { + "customValidators": [], + "skipShapeProps": true + } + ], + "react/style-prop-object": "error", + "react/no-unescaped-entities": "error", + "react/no-children-prop": "error", + "react/jsx-tag-spacing": [ + "error", + { + "closingSlash": "never", + "beforeSelfClosing": "always", + "afterOpening": "never" + } + ], + "react/jsx-space-before-closing": [ + "off", + "always" + ], + "react/no-array-index-key": "error", + "react/require-default-props": "error", + "react/forbid-foreign-prop-types": "off", + "react/void-dom-elements-no-children": "error", + "react/default-props-match-prop-types": [ + "error", + { + "allowRequiredDefaults": false + } + ], + "react/no-redundant-should-component-update": "error", + "react/no-unused-state": "error", + "react/boolean-prop-naming": [ + "off", + { + "propTypeNames": [ + "bool", + "mutuallyExclusiveTrueProps" + ], + "rule": "^(is|has)[A-Z]([A-Za-z0-9]?)+" + } + ], + "react/no-typos": "error", + "react/jsx-curly-brace-presence": [ + "error", + { + "props": "never", + "children": "never" + } + ], + "jsx-a11y/anchor-has-content": [ + "error", + { + "components": [] + } + ], + "jsx-a11y/aria-role": [ + "error", + { + "ignoreNonDom": false + } + ], + "jsx-a11y/aria-props": "error", + "jsx-a11y/aria-proptypes": "error", + "jsx-a11y/aria-unsupported-elements": "error", + "jsx-a11y/alt-text": [ + "error", + { + "elements": [ + "img", + "object", + "area", + "input[type=\"image\"]" + ], + "img": [], + "object": [], + "area": [], + "input[type=\"image\"]": [] + } + ], + "jsx-a11y/img-redundant-alt": "error", + "jsx-a11y/label-has-for": [ + "error", + { + "components": [ + "label" + ] + } + ], + "jsx-a11y/mouse-events-have-key-events": "error", + "jsx-a11y/no-access-key": "error", + "jsx-a11y/no-onchange": "off", + "jsx-a11y/interactive-supports-focus": "error", + "jsx-a11y/role-has-required-aria-props": "error", + "jsx-a11y/role-supports-aria-props": "error", + "jsx-a11y/tabindex-no-positive": "error", + "jsx-a11y/heading-has-content": [ + "error", + { + "components": [ + "" + ] + } + ], + "jsx-a11y/html-has-lang": "error", + "jsx-a11y/lang": "error", + "jsx-a11y/no-distracting-elements": [ + "error", + { + "elements": [ + "marquee", + "blink" + ] + } + ], + "jsx-a11y/scope": "error", + "jsx-a11y/click-events-have-key-events": "error", + "jsx-a11y/no-static-element-interactions": [ + "error", + { + "handlers": [ + "onClick", + "onMouseDown", + "onMouseUp", + "onKeyPress", + "onKeyDown", + "onKeyUp" + ] + } + ], + "jsx-a11y/no-noninteractive-element-interactions": [ + "error", + { + "handlers": [ + "onClick", + "onMouseDown", + "onMouseUp", + "onKeyPress", + "onKeyDown", + "onKeyUp" + ] + } + ], + "jsx-a11y/accessible-emoji": "error", + "jsx-a11y/aria-activedescendant-has-tabindex": "error", + "jsx-a11y/iframe-has-title": "error", + "jsx-a11y/no-autofocus": [ + "error", + { + "ignoreNonDOM": true + } + ], + "jsx-a11y/no-redundant-roles": "error", + "jsx-a11y/media-has-caption": [ + "error", + { + "audio": [], + "video": [], + "track": [] + } + ], + "jsx-a11y/no-interactive-element-to-noninteractive-role": [ + "error", + { + "tr": [ + "none", + "presentation" + ] + } + ], + "jsx-a11y/no-noninteractive-element-to-interactive-role": [ + "error", + { + "ul": [ + "listbox", + "menu", + "menubar", + "radiogroup", + "tablist", + "tree", + "treegrid" + ], + "ol": [ + "listbox", + "menu", + "menubar", + "radiogroup", + "tablist", + "tree", + "treegrid" + ], + "li": [ + "menuitem", + "option", + "row", + "tab", + "treeitem" + ], + "table": [ + "grid" + ], + "td": [ + "gridcell" + ] + } + ], + "jsx-a11y/no-noninteractive-tabindex": [ + "error", + { + "tags": [], + "roles": [ + "tabpanel" + ] + } + ], + "jsx-a11y/anchor-is-valid": [ + "error", + { + "components": [ + "Link" + ], + "specialLink": [ + "to" + ], + "aspects": [ + "noHref", + "invalidHref", + "preferButton" + ] + } + ] + } +} diff --git a/package.json b/package.json index b50dd7a121..018350eef5 100644 --- a/package.json +++ b/package.json @@ -14,7 +14,8 @@ "pretravis": "npm run --silent lint", "travis": "npm run --silent travis:config && npm run --silent travis:config:base", "travis:config": "cd packages/eslint-config-airbnb; npm run travis", - "travis:config:base": "cd packages/eslint-config-airbnb-base; npm run travis" + "travis:config:base": "cd packages/eslint-config-airbnb-base; npm run travis", + "print": "node print > ./linters/eslintrc.json" }, "repository": { "type": "git", @@ -36,6 +37,7 @@ }, "homepage": "https://github.com/airbnb/javascript", "devDependencies": { + "lodash": "^4.17.5", "markdownlint-cli": "^0.3.1" } } diff --git a/packages/eslint-config-airbnb-base/rules/best-practices.js b/packages/eslint-config-airbnb-base/rules/best-practices.js index 978cafc698..1b615f2c34 100644 --- a/packages/eslint-config-airbnb-base/rules/best-practices.js +++ b/packages/eslint-config-airbnb-base/rules/best-practices.js @@ -15,18 +15,19 @@ module.exports = { // enforce that class methods use "this" // https://eslint.org/docs/rules/class-methods-use-this - 'class-methods-use-this': ['error', { - exceptMethods: [], - }], + // Overridden by react rules + // 'class-methods-use-this': ['error', { + // exceptMethods: [], + // }], // require return statements to either always or never specify values 'consistent-return': 'error', // specify curly brace conventions for all control statements - curly: ['error', 'multi-line'], + curly: 'error', // require default case in switch statements - 'default-case': ['error', { commentPattern: '^no default$' }], + 'default-case': 'error', // encourages use of dot notation whenever possible 'dot-notation': ['error', { allowKeywords: true }], @@ -37,7 +38,7 @@ module.exports = { // require the use of === and !== // https://eslint.org/docs/rules/eqeqeq - eqeqeq: ['error', 'always', { null: 'ignore' }], + eqeqeq: ['error', 'always', { null: 'always' }], // make sure for-in loops have an if statement 'guard-for-in': 'error', @@ -75,7 +76,7 @@ module.exports = { 'no-empty-pattern': 'error', // disallow comparisons to null without a type-checking operator - 'no-eq-null': 'off', + 'no-eq-null': 'error', // disallow use of eval() 'no-eval': 'error', @@ -91,7 +92,7 @@ module.exports = { 'no-extra-label': 'error', // disallow fallthrough of case statements - 'no-fallthrough': 'error', + 'no-fallthrough': ['error', { 'commentPattern': '[\\s\\w]*fall(through|thru)[\\s\\w]*}' }], // disallow the use of leading or trailing decimal points in numeric literals 'no-floating-decimal': 'error', @@ -113,7 +114,7 @@ module.exports = { // disallow var and named functions in global scope // https://eslint.org/docs/rules/no-implicit-globals - 'no-implicit-globals': 'off', + 'no-implicit-globals': 'error', // disallow use of eval()-like methods 'no-implied-eval': 'error', @@ -169,19 +170,7 @@ module.exports = { // disallow reassignment of function parameters // disallow parameter object manipulation except for specific exclusions // rule: https://eslint.org/docs/rules/no-param-reassign.html - 'no-param-reassign': ['error', { - props: true, - ignorePropertyModificationsFor: [ - 'acc', // for reduce accumulators - 'e', // for e.returnvalue - 'ctx', // for Koa routing - 'req', // for Express requests - 'request', // for Express requests - 'res', // for Express responses - 'response', // for Express responses - '$scope', // for Angular 1 scopes - ] - }], + 'no-param-reassign': 'off', // disallow usage of __proto__ property 'no-proto': 'error', @@ -259,7 +248,7 @@ module.exports = { // disallow usage of expressions in statement position 'no-unused-expressions': ['error', { - allowShortCircuit: false, + allowShortCircuit: true, allowTernary: false, allowTaggedTemplates: false, }], diff --git a/packages/eslint-config-airbnb-base/rules/imports.js b/packages/eslint-config-airbnb-base/rules/imports.js index 9536e9b4a4..681ac61ca5 100644 --- a/packages/eslint-config-airbnb-base/rules/imports.js +++ b/packages/eslint-config-airbnb-base/rules/imports.js @@ -42,10 +42,10 @@ module.exports = { // ensure default import coupled with default export // https://github.com/benmosher/eslint-plugin-import/blob/master/docs/rules/default.md#when-not-to-use-it - 'import/default': 'off', + 'import/default': 'error', // https://github.com/benmosher/eslint-plugin-import/blob/master/docs/rules/namespace.md - 'import/namespace': 'off', + 'import/namespace': 'error', // Helpful warnings: @@ -198,14 +198,7 @@ module.exports = { // Reports if a module's default export is unnamed // https://github.com/benmosher/eslint-plugin-import/blob/d9b712ac7fd1fddc391f7b234827925c160d956f/docs/rules/no-anonymous-default-export.md - 'import/no-anonymous-default-export': ['off', { - allowArray: false, - allowArrowFunction: false, - allowAnonymousClass: false, - allowAnonymousFunction: false, - allowLiteral: false, - allowObject: false, - }], + 'import/no-anonymous-default-export': 'error', // This rule enforces that all exports are declared at the bottom of the file. // https://github.com/benmosher/eslint-plugin-import/blob/98acd6afd04dcb6920b81330114e146dc8532ea4/docs/rules/exports-last.md diff --git a/packages/eslint-config-airbnb-base/rules/node.js b/packages/eslint-config-airbnb-base/rules/node.js index b178d7f909..55ddf67ef9 100644 --- a/packages/eslint-config-airbnb-base/rules/node.js +++ b/packages/eslint-config-airbnb-base/rules/node.js @@ -9,7 +9,7 @@ module.exports = { // require all requires be top-level // https://eslint.org/docs/rules/global-require - 'global-require': 'error', + 'global-require': 'off', // enforces error handling in callbacks (node environment) 'handle-callback-err': 'off', diff --git a/packages/eslint-config-airbnb-base/rules/style.js b/packages/eslint-config-airbnb-base/rules/style.js index bc5e032e4a..629e1839a7 100644 --- a/packages/eslint-config-airbnb-base/rules/style.js +++ b/packages/eslint-config-airbnb-base/rules/style.js @@ -2,13 +2,11 @@ module.exports = { rules: { // enforce line breaks after opening and before closing array brackets // https://eslint.org/docs/rules/array-bracket-newline - // TODO: enable? semver-major - 'array-bracket-newline': ['off', 'consistent'], // object option alternative: { multiline: true, minItems: 3 } + 'array-bracket-newline': ['error', { multiline: true }], // enforce line breaks between array elements // https://eslint.org/docs/rules/array-element-newline - // TODO: enable? semver-major - 'array-element-newline': ['off', { multiline: true, minItems: 3 }], + 'array-element-newline': ['error', 'always'], // enforce spacing inside array brackets 'array-bracket-spacing': ['error', 'never'], @@ -18,7 +16,7 @@ module.exports = { 'block-spacing': ['error', 'always'], // enforce one true brace style - 'brace-style': ['error', '1tbs', { allowSingleLine: true }], + 'brace-style': ['error', '1tbs', { allowSingleLine: false }], // require camel case names camelcase: ['error', { properties: 'never' }], @@ -93,8 +91,7 @@ module.exports = { // enforces use of function declarations or expressions // https://eslint.org/docs/rules/func-style - // TODO: enable - 'func-style': ['off', 'expression'], + 'func-style': ['error', 'declaration', { allowArrowFunctions: true }], // enforce consistent line breaks inside function parentheses // https://eslint.org/docs/rules/function-paren-newline @@ -144,7 +141,8 @@ module.exports = { // specify whether double or single quotes should be used in JSX attributes // https://eslint.org/docs/rules/jsx-quotes - 'jsx-quotes': ['off', 'prefer-double'], + // Overridden by react rules + // 'jsx-quotes': ['error', 'prefer-double'], // enforces spacing between keys and values in object literal properties 'key-spacing': ['error', { beforeColon: false, afterColon: true }], @@ -175,24 +173,21 @@ module.exports = { // require or disallow an empty line between class members // https://eslint.org/docs/rules/lines-between-class-members - 'lines-between-class-members': ['error', 'always', { exceptAfterSingleLine: false }], + 'lines-between-class-members': ['error', 'always', { exceptAfterSingleLine: true }], // enforces empty lines around comments 'lines-around-comment': 'off', // require or disallow newlines around directives // https://eslint.org/docs/rules/lines-around-directive - 'lines-around-directive': ['error', { - before: 'always', - after: 'always', - }], + 'lines-around-directive': 'off', // specify the maximum depth that blocks can be nested 'max-depth': ['off', 4], // specify the maximum length of a line in your program // https://eslint.org/docs/rules/max-len - 'max-len': ['error', 100, 2, { + 'max-len': ['error', 120, 2, { ignoreUrls: true, ignoreComments: false, ignoreRegExpLiterals: true, @@ -227,8 +222,7 @@ module.exports = { // require multiline ternary // https://eslint.org/docs/rules/multiline-ternary - // TODO: enable? - 'multiline-ternary': ['off', 'never'], + 'multiline-ternary': ['error', 'always-multiline'], // require a capital letter for constructors 'new-cap': ['error', { @@ -316,7 +310,7 @@ module.exports = { // disallow use of unary operators, ++ and -- // https://eslint.org/docs/rules/no-plusplus - 'no-plusplus': 'error', + 'no-plusplus': 'off', // disallow certain syntax forms // https://eslint.org/docs/rules/no-restricted-syntax @@ -341,7 +335,7 @@ module.exports = { ], // disallow space between function identifier and application - 'no-spaced-func': 'error', + 'no-spaced-func': 'off', // disallow tab characters entirely 'no-tabs': 'error', @@ -356,12 +350,7 @@ module.exports = { }], // disallow dangling underscores in identifiers - 'no-underscore-dangle': ['error', { - allow: [], - allowAfterThis: false, - allowAfterSuper: false, - enforceInMethodNames: false, - }], + 'no-underscore-dangle': 'off', // disallow the use of Boolean literals in conditional expressions // also, prefer `a || b` over `a ? a : b` @@ -412,11 +401,14 @@ module.exports = { // Require or disallow padding lines between statements // https://eslint.org/docs/rules/padding-line-between-statements - 'padding-line-between-statements': 'off', + 'padding-line-between-statements': ['error', + { blankLine: 'always', prev: '*', next: 'directive' }, + { blankLine: 'always', prev: 'directive', next: '*' } + ], // require quotes around object literal property names // https://eslint.org/docs/rules/quote-props.html - 'quote-props': ['error', 'as-needed', { keywords: false, unnecessary: true, numbers: false }], + 'quote-props': ['error', 'consistent-as-needed', { keywords: false, unnecessary: false, numbers: false }], // specify whether double or single quotes should be used quotes: ['error', 'single', { avoidEscape: true }], diff --git a/packages/eslint-config-airbnb-base/rules/variables.js b/packages/eslint-config-airbnb-base/rules/variables.js index aeab992320..493cd6408f 100644 --- a/packages/eslint-config-airbnb-base/rules/variables.js +++ b/packages/eslint-config-airbnb-base/rules/variables.js @@ -32,8 +32,7 @@ module.exports = { // disallow use of undefined variable // https://eslint.org/docs/rules/no-undefined - // TODO: enable? - 'no-undefined': 'off', + 'no-undefined': 'error', // disallow declaration of variables that are not used in the code 'no-unused-vars': ['error', { vars: 'all', args: 'after-used', ignoreRestSiblings: true }], diff --git a/packages/eslint-config-airbnb/index.js b/packages/eslint-config-airbnb/index.js index ddd3bfb712..d6c2afc61d 100644 --- a/packages/eslint-config-airbnb/index.js +++ b/packages/eslint-config-airbnb/index.js @@ -1,7 +1,13 @@ module.exports = { extends: [ - 'eslint-config-airbnb-base', - 'eslint-config-airbnb-base/rules/strict', + '../eslint-config-airbnb-base/rules/best-practices', + '../eslint-config-airbnb-base/rules/errors', + '../eslint-config-airbnb-base/rules/node', + '../eslint-config-airbnb-base/rules/style', + '../eslint-config-airbnb-base/rules/variables', + '../eslint-config-airbnb-base/rules/es6', + '../eslint-config-airbnb-base/rules/imports', + '../eslint-config-airbnb-base/rules/strict', './rules/react', './rules/react-a11y', ].map(require.resolve), diff --git a/packages/eslint-config-airbnb/rules/react-a11y.js b/packages/eslint-config-airbnb/rules/react-a11y.js index 3e7f5c970c..c6b5f96ed1 100644 --- a/packages/eslint-config-airbnb/rules/react-a11y.js +++ b/packages/eslint-config-airbnb/rules/react-a11y.js @@ -1,7 +1,8 @@ module.exports = { plugins: [ 'jsx-a11y', - 'react' + // Commenting to de-dupe against react rules + // 'react' ], parserOptions: { diff --git a/packages/eslint-config-airbnb/rules/react.js b/packages/eslint-config-airbnb/rules/react.js index 999d3a1cbb..d46e94e8ec 100644 --- a/packages/eslint-config-airbnb/rules/react.js +++ b/packages/eslint-config-airbnb/rules/react.js @@ -33,13 +33,17 @@ module.exports = { ], }], + // Enforce consistent usage of destructuring assignment of props, state, and context + // https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/destructuring-assignment.md + 'react/destructuring-assignment': ['error', 'always'], + // Prevent missing displayName in a React component definition // https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/display-name.md 'react/display-name': ['off', { ignoreTranspilerName: false }], // Forbid certain propTypes (any, array, object) // https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/forbid-prop-types.md - 'react/forbid-prop-types': ['error', { forbid: ['any', 'array', 'object'] }], + 'react/forbid-prop-types': 'off', // Enforce boolean attributes notation in JSX // https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/jsx-boolean-value.md @@ -70,7 +74,7 @@ module.exports = { // Validate JSX has key prop when in array or iterator // https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/jsx-key.md - 'react/jsx-key': 'off', + 'react/jsx-key': 'error', // Limit maximum of props on a single line in JSX // https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/jsx-max-props-per-line.md @@ -133,6 +137,10 @@ module.exports = { // https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/jsx-uses-vars.md 'react/jsx-uses-vars': 'error', + // Prevent using this.state within a this.setState + // https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/no-access-state-in-setstate.md + 'react/no-access-state-in-setstate': 'error', + // Prevent usage of dangerous JSX properties // https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/no-danger.md 'react/no-danger': 'warn', @@ -156,7 +164,7 @@ module.exports = { // Prevent direct mutation of this.state // https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/no-direct-mutation-state.md - 'react/no-direct-mutation-state': 'off', + 'react/no-direct-mutation-state': 'error', // Prevent usage of isMounted // https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/no-is-mounted.md @@ -174,6 +182,10 @@ module.exports = { // https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/no-string-refs.md 'react/no-string-refs': 'error', + // Prevent this from being used in stateless functional components + // https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/no-this-in-sfc.md + 'react/no-this-in-sfc': 'error', + // Prevent usage of unknown DOM property // https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/no-unknown-property.md 'react/no-unknown-property': 'error', @@ -249,7 +261,7 @@ module.exports = { // only .jsx files may have JSX // https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/jsx-filename-extension.md - 'react/jsx-filename-extension': ['error', { extensions: ['.jsx'] }], + 'react/jsx-filename-extension': 'off', // prevent accidental JS comments from being injected into JSX as text // https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/jsx-no-comment-textnodes.md diff --git a/print.js b/print.js new file mode 100644 index 0000000000..25ee8e1f8d --- /dev/null +++ b/print.js @@ -0,0 +1,33 @@ +const _ = require('lodash'); +const bestPractices = require('./packages/eslint-config-airbnb-base/rules/best-practices'); +const errors = require('./packages/eslint-config-airbnb-base/rules/errors'); +const node = require('./packages/eslint-config-airbnb-base/rules/node'); +const style = require('./packages/eslint-config-airbnb-base/rules/style'); +const variables = require('./packages/eslint-config-airbnb-base/rules/variables'); +const es6 = require('./packages/eslint-config-airbnb-base/rules/es6'); +const imports = require('./packages/eslint-config-airbnb-base/rules/imports'); +const strict = require('./packages/eslint-config-airbnb-base/rules/strict'); +const react = require('./packages/eslint-config-airbnb/rules/react'); +const reactA11y = require('./packages/eslint-config-airbnb/rules/react-a11y'); + +const customizer = (objValue, srcValue) => { + if (_.isArray(objValue)) { + return objValue.concat(srcValue); + } +} + +const rules = _.mergeWith( + imports, + bestPractices, + errors, + node, + style, + variables, + es6, + strict, + react, + reactA11y, + customizer +); + +console.log(JSON.stringify(rules, null, 2)); From 704c386f346b5056c3bb76598874053db30976d0 Mon Sep 17 00:00:00 2001 From: Daniel Chang Date: Wed, 8 Aug 2018 17:50:57 -0400 Subject: [PATCH 2/2] Add **/setupTests.js to import/no-extraneous-dependencies matchers list. --- README.md | 3 +++ linters/eslintrc.json | 3 ++- packages/eslint-config-airbnb-base/rules/imports.js | 1 + 3 files changed, 6 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index e5a88920a6..a7bb03fcfc 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,7 @@ # Airbnb JavaScript Style Guide() { +**See [Amendments Section](#amendments) for our changes** + *A mostly reasonable approach to JavaScript* > **Note**: this guide assumes you are using [Babel](https://babeljs.io), and requires that you use [babel-preset-airbnb](https://npmjs.com/babel-preset-airbnb) or the equivalent. It also assumes you are installing shims/polyfills in your app, with [airbnb-browser-shims](https://npmjs.com/airbnb-browser-shims) or the equivalent. @@ -3690,5 +3692,6 @@ We encourage you to fork this guide and change the rules to fit your team’s st - Prevent this from being used in stateless functional components - AirBnb prefers to enforce only `.jsx` file extension files may contain JSX. We prefer all our files to allow JSX. - Validate JSX has key prop when in array or iterator +- We added `**/setupTests.js` to our list of `import/no-extraneous-dependencies` matchers. # }; diff --git a/linters/eslintrc.json b/linters/eslintrc.json index 299d88d80f..b254fecd2b 100644 --- a/linters/eslintrc.json +++ b/linters/eslintrc.json @@ -85,7 +85,8 @@ "**/gulpfile.*.js", "**/Gruntfile{,.js}", "**/protractor.conf.js", - "**/protractor.conf.*.js" + "**/protractor.conf.*.js", + "**/setupTests.js" ], "optionalDependencies": false } diff --git a/packages/eslint-config-airbnb-base/rules/imports.js b/packages/eslint-config-airbnb-base/rules/imports.js index 681ac61ca5..f416b0f2e9 100644 --- a/packages/eslint-config-airbnb-base/rules/imports.js +++ b/packages/eslint-config-airbnb-base/rules/imports.js @@ -87,6 +87,7 @@ module.exports = { '**/Gruntfile{,.js}', // grunt config '**/protractor.conf.js', // protractor config '**/protractor.conf.*.js', // protractor config + '**/setupTests.js', // test setup file ], optionalDependencies: false, }],