Migration between minor versions follows the same steps:
-
Update
@perfective/eslint-config-react
and its peer dependencies. -
Disable all new rules.
-
Gradually enable the new rules:
-
remove one or more rules from the list;
-
fix errors or check auto-fixes of warnings;
-
check for the regressions.
-
-
Replace customized
eslint-plugin-node
rules (if any) witheslint-plugin-n
:-
Replace customized
node/
rules withn/
. -
Replace
node/shebang
rule withn/hashbang
. -
Disable
n/no-hide-core-modules
as deprecated. -
Change
n/exports-style
severity towarn
.
-
-
Update customizations (if any) for the deprecated
@typescript-eslint
rules:-
Replace
@typescript-eslint/no-throw-literal
with@typescript-eslint/only-throw-error
. -
Replace
@typescript-eslint/no-useless-template-literals
with@typescript-eslint/no-unnecessary-template-expression
. -
Disabled deprecated
@typescript-eslint/prefer-ts-expect-error
.
-
-
Add
@jest/globals
to thedevDependencies
for thejest/prefer-importing-jest-globals
rule. -
Disable and gradually enable new rules in the
.eslintrc.js
.module.exports = { extends: [ '@perfective/eslint-config', ], overrides: [ { files: ['*.[jt]s?(x)'], rules: { '@stylistic/js/line-comment-position': 'off', '@stylistic/js/multiline-comment-style': 'off', // Auto-fixable '@stylistic/jsx/jsx-function-call-newline': 'off', // Auto-fixable '@typescript-eslint/consistent-return': 'off', '@typescript-eslint/use-unknown-in-catch-callback-variable': 'off', 'cypress/no-async-before': 'off', 'jest/prefer-importing-jest-globals': 'off', // Auto-fixable 'jest/prefer-jest-mocked': 'off', // Auto-fixable 'unicorn/consistent-empty-array-spread': 'off', // Auto-fixable 'unicorn/no-anonymous-default-export': 'off', 'unicorn/no-await-in-promise-methods': 'off', 'unicorn/no-invalid-fetch-options': 'off', 'unicorn/no-magic-array-flat-depth': 'off', 'unicorn/no-single-promise-in-promise-methods': 'off', // Auto-fixable }, }, ], };
-
Check customizations of the
eslint
and@typescript-eslint
rules replaced by the ESLint Stylistic rules. Replace the name of the customized rules with the new rules. See Stylistic migration documentation for details. -
Disable and gradually enable new rules in the
.eslintrc.js
.module.exports = { extends: [ '@perfective/eslint-config-react', ], overrides: [ { files: ['*.[jt]s?(x)'], rules: { '@typescript-eslint/no-array-delete': 'off', '@typescript-eslint/prefer-find': 'off', '@typescript-eslint/prefer-promise-reject-errors': 'off', 'react/checked-requires-onchange-or-readonly': 'off', }, }, ], };
-
Disable and gradually enable new rules in the
.eslintrc.js
.module.exports = { extends: [ '@perfective/eslint-config-react', ], overrides: [ { files: ['*.[jt]s?(x)'], rules: { '@typescript-eslint/no-useless-template-literals': 'off', '@typescript-eslint/no-unsafe-unary-minus': 'off', 'jest/no-confusing-set-timeout': 'off', 'no-object-constructor': 'off', 'testing-library/prefer-implicit-assert': 'off', }, }, ], };
-
If you do not use
jest
, removeeslint-plugin-jest
,eslint-plugin-jest-formatting
,eslint-plugin-jest-dom
, andeslint-plugin-testing-library
fromdevDependencies
. -
If you do not use
@testing-library/jest-dom
, removeeslint-plugin-jest-dom
fromdevDependencies
. -
If you do not use
@testing-library
, removeeslint-plugin-testing-library
fromdevDependencies
. -
If you do not use
cypress
, removeeslint-plugin-cypress
fromdevDependencies
. -
If you do not use
rxjs
, removeeslint-plugin-rxjs
fromdevDependencies
.
Note
|
After removing optional peer dependencies, you may need to regenerate your |
-
If you use
eslint-plugin-testing-library
, update rules:-
Replace
testing-library/await-async-query
withtesting-library/await-async-queries
. -
Replace
testing-library/await-fire-event
withtesting-library/await-async-events
. -
Replace
testing-library/no-await-sync-query
withtesting-library/no-await-sync-queries
. -
Replace
testing-library/no-render-in-setup
withtesting-library/no-render-in-lifecycle
.
-
-
Remove the
jsdoc/newline-after-description
rule customizations, if you have any. -
Disable new rules in the
.eslintrc.js
.module.exports = { extends: [ '@perfective/eslint-config-react', ], overrides: [ { files: ['*.[jt]s?(x)'], rules: { '@typescript-eslint/block-spacing': 'off', // auto-fixable '@typescript-eslint/no-duplicate-type-constituents': 'off', '@typescript-eslint/no-unsafe-enum-comparison': 'off', 'jsdoc/imports-as-dependencies': 'off', 'jsdoc/no-blank-blocks': 'off', // auto-fixable 'jsdoc/tag-lines': 'off', // auto-fixable 'unicorn/prefer-blob-reading-methods': 'off', }, }, ], };
.eslintrc.js
module.exports = {
extends: [
'@perfective/eslint-config-react',
],
overrides: [
{
files: ['*.[jt]s?(x)'],
rules: {
'@typescript-eslint/key-spacing': 'off', // auto-fixable
'@typescript-eslint/no-import-type-side-effects': 'off', // auto-fixable
'@typescript-eslint/no-mixed-enums': 'off',
'import/consistent-type-specifier-style': 'off', // auto-fixable
'import/no-empty-named-blocks': 'off', // auto-fixable
'jest/no-untyped-mock-factory': 'off', // auto-fixable
'jsx-a11y/no-aria-hidden-on-focusable': 'off',
'jsx-a11y/prefer-tag-over-role': 'off',
'react/no-object-type-as-default-prop': 'off',
'react/sort-default-props': 'off',
'unicorn/no-negated-condition': 'off', // auto-fixable
'unicorn/no-typeof-undefined': 'off', // auto-fixable
'unicorn/refer-set-size': 'off', // auto-fixable
},
},
],
};
.eslintrc.js
module.exports = {
extends: [
'@perfective/eslint-config-react',
],
overrides: [
{
files: ['*.[jt]s?(x)'],
rules: {
'logical-assignment-operators': 'off', // auto-fixable
'no-empty-static-block': 'off',
'no-new-native-nonconstructor': 'off',
'@typescript-eslint/no-unsafe-declaration-merging': 'off',
'jest/prefer-each': 'off',
'jest/prefer-mock-promise-shorthand': 'off', // auto-fixable
'promise/no-multiple-resolved': 'off',
'unicorn/no-unnecessary-await': 'off', // auto-fixable
},
},
],
};
.eslintrc.js
module.exports = {
extends: [
'@perfective/eslint-config-react',
],
overrides: [
{
files: ['*.[jt]s?(x)'],
rules: {
'react/hook-use-state': 'off',
'react/iframe-missing-sandbox': 'off',
'react/jsx-no-leaked-render': 'off',
'no-constant-binary-expression': 'off',
'@typescript-eslint/consistent-generic-constructors': 'off', // auto-fixable
'@typescript-eslint/no-duplicate-enum-values': 'off',
'@typescript-eslint/no-redundant-type-constituents': 'off',
'@typescript-eslint/no-useless-empty-export': 'off', // auto-fixable
'@typescript-eslint/parameter-properties': 'off',
'jest/max-expects': 'off',
'jest/prefer-hooks-in-order': 'off',
'testing-library/no-global-regexp-flag-in-query': 'off', // auto-fixable
'unicorn/no-unreadable-iife': 'off',
'unicorn/no-useless-switch-case': 'off',
'unicorn/prefer-event-target': 'off',
'unicorn/prefer-logical-operator-over-ternary': 'off',
'unicorn/prefer-modern-math-apis': 'off', // auto-fixable
'unicorn/prefer-native-coercion-functions': 'off', // auto-fixable
},
},
],
};
.eslintrc.js
module.exports = {
extends: [
'@perfective/eslint-config-react',
],
overrides: [
{
files: ['*.[jt]s?(x)'],
rules: {
'no-unused-private-class-members': 'off',
'jest/no-conditional-in-test': 'off',
// Deprecated; turn off when `jest/no-conditional-in-test` is enabled
'jest/no-if': 'error',
'jest/prefer-comparison-matcher': 'off',
'jest/prefer-equality-matcher': 'off',
'jest/prefer-snapshot-hint': 'off',
'jsdoc/sort-tags': 'off',
'unicorn/no-thenable': 'off',
'unicorn/no-useless-promise-resolve-reject': 'off',
'unicorn/prefer-json-parse-buffer': 'off',
'unicorn/relative-url-style': 'off',
'unicorn/text-encoding-identifier-case': 'off',
},
},
],
};
If you have customization of the renamed rules, update the rules' names:
-
jest/valid-describe
intojest/valid-describe-callback
; -
jest/lowercase-name
intojest/prefer-lowercase-title
; -
testing-library/no-debug
intotesting-library/no-debugging-utils
.eslintrc.js
module.exports = {
extends: [
'@perfective/eslint-config-react',
],
overrides: [
{
files: ['*.[jt]s?(x)'],
rules: {
'@typescript-eslint/no-meaningless-void-operator': 'off',
'@typescript-eslint/no-non-null-asserted-nullish-coalescing': 'off',
'@typescript-eslint/prefer-return-this-type': 'off',
'cypress/no-pause': 'off',
'jest/max-nested-describe': 'off',
'jest/prefer-expect-resolves': 'off',
'jest/prefer-to-be': 'off',
'jest/require-hook': 'off',
'jest/valid-expect-in-promise': 'off',
'react/no-arrow-function-lifecycle': 'off',
'react/no-invalid-html-attribute': 'off',
'react/no-namespace': 'off',
'sonarjs/no-empty-collection': 'off',
'sonarjs/no-gratuitous-expressions': 'off',
'sonarjs/no-ignored-return': 'off',
'sonarjs/no-inverted-boolean-check': 'off',
'sonarjs/no-nested-switch': 'off',
'sonarjs/no-nested-template-literals': 'off',
'sonarjs/non-existent-operator': 'off',
'testing-library/prefer-query-by-disappearance': 'off',
'unicorn/no-await-expression-member': 'off',
'unicorn/no-empty-file': 'off',
'unicorn/no-invalid-remove-event-listener': 'off',
'unicorn/no-useless-fallback-in-spread': 'off',
'unicorn/no-useless-length-check': 'off',
'unicorn/no-useless-spread': 'off',
'unicorn/prefer-code-point': 'off',
'unicorn/prefer-export-from': 'off',
'unicorn/template-indent': 'off',
},
},
],
};