Skip to content

Commit

Permalink
Absorb rules from defunct eslint-config-react-app
Browse files Browse the repository at this point in the history
Our extension of the eslint-config-react-app has always caused problems:

1. Conflicts between versions of plugins
2. Unnecessary ESLint plugins being installed eg. jest and flowtype

We have worked around 1. with solutions such as Yarn resolutions and moving to
pnpm with auto-install-peers=true:

#110

Since create-react-app is going away, eslint-config-react-app will likely not be
maintained any longer (it has not received any updates for 2 years).

This commit absorbs the contents of eslint-config-react-app into our own config,
where we will maintain it from now on.
  • Loading branch information
karlhorky committed May 5, 2023
1 parent 4951214 commit 1880496
Show file tree
Hide file tree
Showing 2 changed files with 274 additions and 6 deletions.
277 changes: 274 additions & 3 deletions index.cjs
Original file line number Diff line number Diff line change
Expand Up @@ -137,13 +137,248 @@ https://github.com/reactjs/reactjs.org/issues/4626#issuecomment-1117535930`,
},
];

/**
* Copied contents from the defunct project eslint-config-react-app
*
* https://github.com/facebook/create-react-app/blob/main/packages/eslint-config-react-app/index.js
* https://github.com/facebook/create-react-app/blob/main/packages/eslint-config-react-app/base.js
*
* @type {import('@typescript-eslint/utils').TSESLint.Linter.Config['rules']}
*/
const eslintConfigReactAppRules = {
'array-callback-return': 'warn',
'default-case': ['warn', { commentPattern: '^no default$' }],
'dot-location': ['warn', 'property'],
eqeqeq: ['warn', 'smart'],
'new-parens': 'warn',
'no-caller': 'warn',
'no-cond-assign': ['warn', 'except-parens'],
'no-const-assign': 'warn',
'no-control-regex': 'warn',
'no-delete-var': 'warn',
'no-dupe-args': 'warn',
'no-dupe-class-members': 'warn',
'no-dupe-keys': 'warn',
'no-duplicate-case': 'warn',
'no-empty-character-class': 'warn',
'no-empty-pattern': 'warn',
'no-eval': 'warn',
'no-ex-assign': 'warn',
'no-extend-native': 'warn',
'no-extra-bind': 'warn',
'no-extra-label': 'warn',
'no-fallthrough': 'warn',
'no-func-assign': 'warn',
'no-implied-eval': 'warn',
'no-invalid-regexp': 'warn',
'no-iterator': 'warn',
'no-label-var': 'warn',
'no-labels': ['warn', { allowLoop: true, allowSwitch: false }],
'no-lone-blocks': 'warn',
'no-loop-func': 'warn',
'no-mixed-operators': [
'warn',
{
groups: [
['&', '|', '^', '~', '<<', '>>', '>>>'],
['==', '!=', '===', '!==', '>', '>=', '<', '<='],
['&&', '||'],
['in', 'instanceof'],
],
allowSamePrecedence: false,
},
],
'no-multi-str': 'warn',
'no-global-assign': 'warn',
'no-unsafe-negation': 'warn',
'no-new-func': 'warn',
'no-new-object': 'warn',
'no-new-symbol': 'warn',
'no-new-wrappers': 'warn',
'no-obj-calls': 'warn',
'no-octal': 'warn',
'no-octal-escape': 'warn',
'no-regex-spaces': 'warn',
'no-script-url': 'warn',
'no-self-assign': 'warn',
'no-self-compare': 'warn',
'no-sequences': 'warn',
'no-shadow-restricted-names': 'warn',
'no-sparse-arrays': 'warn',
'no-template-curly-in-string': 'warn',
'no-this-before-super': 'warn',
'no-throw-literal': 'warn',
'no-undef': 'error',
'no-restricted-globals': [
'error',
// Confusing browser globals (copied from create-react-app)
//
// The ESLint browser environment defines all browser globals as valid,
// even though most people don't know some of them exist (e.g. `name` or `status`).
// This is dangerous as it hides accidentally undefined variables.
// We blacklist the globals that we deem potentially confusing.
// To use them, explicitly reference them, e.g. `window.name` or `window.status`.
//
// https://github.com/facebook/create-react-app/blob/main/packages/confusing-browser-globals/index.js
'addEventListener',
'blur',
'close',
'closed',
'confirm',
'defaultStatus',
'defaultstatus',
'event',
'external',
'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-unreachable': 'warn',
'no-unused-labels': 'warn',
'no-useless-computed-key': 'warn',
'no-useless-concat': 'warn',
'no-useless-escape': 'warn',
'no-useless-rename': [
'warn',
{
ignoreDestructuring: false,
ignoreImport: false,
ignoreExport: false,
},
],
'no-with': 'warn',
'no-whitespace-before-property': 'warn',
'react-hooks/exhaustive-deps': 'warn',
'require-yield': 'warn',
'rest-spread-spacing': ['warn', 'never'],
strict: ['warn', 'never'],
'unicode-bom': ['warn', 'never'],
'use-isnan': 'warn',
'valid-typeof': 'warn',
'no-restricted-properties': [
'error',
{
object: 'require',
property: 'ensure',
message:
'Please use import() instead. More info: https://facebook.github.io/create-react-app/docs/code-splitting',
},
{
object: 'System',
property: 'import',
message:
'Please use import() instead. More info: https://facebook.github.io/create-react-app/docs/code-splitting',
},
],
'getter-return': 'warn',

// https://github.com/benmosher/eslint-plugin-import/tree/master/docs/rules
'import/first': 'error',
'import/no-amd': 'error',
'import/no-anonymous-default-export': 'warn',
'import/no-webpack-loader-syntax': 'error',

// https://github.com/yannickcr/eslint-plugin-react/tree/master/docs/rules
'react/forbid-foreign-prop-types': ['warn', { allowInPropTypes: true }],
'react/jsx-no-comment-textnodes': 'warn',
'react/jsx-no-duplicate-props': 'warn',
'react/jsx-no-target-blank': 'warn',
'react/jsx-no-undef': 'error',
'react/jsx-pascal-case': [
'warn',
{
allowAllCaps: true,
ignore: [],
},
],
'react/no-danger-with-children': 'warn',
// Disabled because of undesirable warnings
// See https://github.com/facebook/create-react-app/issues/5204 for
// blockers until its re-enabled
// 'react/no-deprecated': 'warn',
'react/no-direct-mutation-state': 'warn',
'react/no-is-mounted': 'warn',
'react/no-typos': 'error',
'react/require-render-return': 'error',
'react/style-prop-object': 'warn',

// https://github.com/evcohen/eslint-plugin-jsx-a11y/tree/master/docs/rules
'jsx-a11y/alt-text': 'warn',
'jsx-a11y/anchor-has-content': 'warn',
'jsx-a11y/aria-activedescendant-has-tabindex': 'warn',
'jsx-a11y/aria-props': 'warn',
'jsx-a11y/aria-proptypes': 'warn',
'jsx-a11y/aria-role': ['warn', { ignoreNonDOM: true }],
'jsx-a11y/aria-unsupported-elements': 'warn',
'jsx-a11y/heading-has-content': 'warn',
'jsx-a11y/iframe-has-title': 'warn',
'jsx-a11y/img-redundant-alt': 'warn',
'jsx-a11y/no-access-key': 'warn',
'jsx-a11y/no-distracting-elements': 'warn',
'jsx-a11y/no-redundant-roles': 'warn',
'jsx-a11y/role-has-required-aria-props': 'warn',
'jsx-a11y/role-supports-aria-props': 'warn',
'jsx-a11y/scope': 'warn',

// https://github.com/facebook/react/tree/main/packages/eslint-plugin-react-hooks
'react-hooks/rules-of-hooks': 'error',
};

/** @type {import('@typescript-eslint/utils').TSESLint.Linter.Config} */
const config = {
parser: '@typescript-eslint/parser',
parserOptions: {
project: './tsconfig.json',
// typescript-eslint specific options
warnOnUnsupportedTypeScriptVersion: true,
},
extends: ['react-app', 'plugin:jsx-a11y/recommended'],
extends: ['plugin:jsx-a11y/recommended'],
plugins: [
'@next/next',
'@typescript-eslint',
Expand All @@ -158,7 +393,10 @@ const config = {
'upleveled',
],
env: {
browser: true,
commonjs: true,
es2020: true,
node: true,
},
settings: {
'import/resolver': {
Expand All @@ -168,8 +406,13 @@ const config = {
alwaysTryTypes: true,
},
},
react: {
version: 'detect',
},
},
rules: {
...eslintConfigReactAppRules,

// Error about importing next/document in a page other than pages/_document.js
// https://github.com/vercel/next.js/blob/canary/errors/no-document-import-in-page.md
'@next/next/no-document-import-in-page': 'error',
Expand All @@ -191,6 +434,9 @@ const config = {
// - Object and {}
// https://github.com/typescript-eslint/typescript-eslint/blob/main/packages/eslint-plugin/docs/rules/ban-types.md
'@typescript-eslint/ban-types': ['error'],
// Warn on usage of angle brackets for type assertions (eg. `<Type>x`)
// https://typescript-eslint.io/rules/consistent-type-assertions/
'@typescript-eslint/consistent-type-assertions': 'warn',
// Warn on variables not following naming convention
// https://github.com/typescript-eslint/typescript-eslint/blob/main/packages/eslint-plugin/docs/rules/naming-convention.md
'@typescript-eslint/naming-convention': [
Expand Down Expand Up @@ -235,8 +481,16 @@ const config = {
format: ['camelCase', 'snake_case', 'PascalCase'],
},
],
// Warn on usage of array constructor (eg. Array(0, 1), new Array(0, 1))
// https://typescript-eslint.io/rules/no-array-constructor/
'no-array-constructor': 'off',
'@typescript-eslint/no-array-constructor': 'warn',
// Warn on dangling promises without await
'@typescript-eslint/no-floating-promises': ['warn', { ignoreVoid: false }],
// Warn on redeclare of variables
// https://typescript-eslint.io/rules/no-redeclare/
'no-redeclare': 'off',
'@typescript-eslint/no-redeclare': 'warn',
// Warn about variable shadowing
// https://github.com/typescript-eslint/typescript-eslint/blob/main/packages/eslint-plugin/docs/rules/no-shadow.md
'@typescript-eslint/no-shadow': 'warn',
Expand All @@ -251,14 +505,24 @@ const config = {
// Prevent unnecessary type assertions
// https://github.com/typescript-eslint/typescript-eslint/blob/master/packages/eslint-plugin/docs/rules/no-unnecessary-type-assertion.md
'@typescript-eslint/no-unnecessary-type-assertion': 'warn',
// Warn on unused expressions
// https://typescript-eslint.io/rules/no-unused-expression
'no-unused-expressions': 'off',
'@typescript-eslint/no-unused-expressions': [
'warn',
{
allowShortCircuit: true,
allowTernary: true,
allowTaggedTemplates: true,
},
],
// Disable built-in ESLint no-unused-vars
// to use the more powerful @typescript-eslint/no-unused-vars
// https://github.com/typescript-eslint/typescript-eslint/blob/master/packages/eslint-plugin/docs/rules/no-unused-vars.md
// https://eslint.org/docs/rules/no-unused-vars
'no-unused-vars': 'off',
// No need for this, @typescript-eslint/parser fully understands JSX semantics
// https://github.com/typescript-eslint/typescript-eslint/issues/2985#issuecomment-771771967
'react/jsx-uses-vars': 'off',
'@typescript-eslint/no-unused-vars': [
'warn',
{
Expand All @@ -271,9 +535,13 @@ const config = {
// @typescript-eslint plugin
'no-use-before-define': 'off',
'@typescript-eslint/no-use-before-define': 'error',
// Warn on useless constructor in class
// https://typescript-eslint.io/rules/no-useless-constructor/
'no-useless-constructor': 'off',
'@typescript-eslint/no-useless-constructor': 'warn',
// Allow leaving out curlies only with single-line condition blocks
// https://github.com/eslint/eslint/blob/master/docs/rules/curly.md#multi-line
curly: ['error', 'multi-line', 'consistent'],
curly: ['warn', 'multi-line', 'consistent'],
// Error out on imports that don't match
// the underlying file system
// https://github.com/benmosher/eslint-plugin-import/blob/master/docs/rules/no-unresolved.md
Expand Down Expand Up @@ -336,6 +604,9 @@ const config = {
],
// Error on useless React fragments
'react/jsx-no-useless-fragment': 'warn',
// Disallow React being marked as unused
// https://github.com/jsx-eslint/eslint-plugin-react/blob/master/docs/rules/jsx-uses-react.md
'react/jsx-uses-react': 'warn',
// Warn if a `key` is set to an `index`
// https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/no-array-index-key.md
'react/no-array-index-key': ['error'],
Expand Down
3 changes: 0 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -49,11 +49,8 @@
"@typescript-eslint/eslint-plugin": "^5.59.2",
"@typescript-eslint/parser": "^5.59.2",
"eslint": "^8.39.0",
"eslint-config-react-app": "^7.0.1",
"eslint-import-resolver-typescript": "^3.5.5",
"eslint-plugin-flowtype": "^8.0.3",
"eslint-plugin-import": "^2.27.5",
"eslint-plugin-jest": "^27.2.1",
"eslint-plugin-jsx-a11y": "^6.7.1",
"eslint-plugin-jsx-expressions": "^1.3.1",
"eslint-plugin-react": "^7.32.2",
Expand Down

0 comments on commit 1880496

Please sign in to comment.