You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@superset.apache.org by ru...@apache.org on 2025/10/01 00:54:09 UTC

(superset) branch flatten-eslint created (now fcd0f3b77b)

This is an automated email from the ASF dual-hosted git repository.

rusackas pushed a change to branch flatten-eslint
in repository https://gitbox.apache.org/repos/asf/superset.git


      at fcd0f3b77b refactor(frontend): Flatten ESLint configuration and remove Airbnb dependency

This branch includes the following new commits:

     new fcd0f3b77b refactor(frontend): Flatten ESLint configuration and remove Airbnb dependency

The 1 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.



(superset) 01/01: refactor(frontend): Flatten ESLint configuration and remove Airbnb dependency

Posted by ru...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

rusackas pushed a commit to branch flatten-eslint
in repository https://gitbox.apache.org/repos/asf/superset.git

commit fcd0f3b77b94229111279d92dbb77a76bb77e44a
Author: Evan Rusackas <ev...@rusackas.com>
AuthorDate: Tue Sep 30 17:53:06 2025 -0700

    refactor(frontend): Flatten ESLint configuration and remove Airbnb dependency
    
    This commit completes the ESLint configuration flattening by extracting all rules
    from eslint-config-airbnb and adding them directly to our config file. This gives
    us full control over our linting rules and reduces external dependencies.
    
    Changes:
    - Extracted and added 426 rules from Airbnb config (251 core + 175 plugin rules)
    - Removed eslint-config-airbnb dependency and 4 related utility packages
    - Added required plugins to the plugins array (import, jsx-a11y, react-hooks)
    - Removed 116 redundant rules (62 off-by-default, 6 deprecated, 48 at defaults)
    - All existing linting behavior is preserved
    
    Benefits:
    - Complete control over all linting rules
    - Easier to modify individual rules
    - Reduced dependency footprint (5 packages removed)
    - More maintainable configuration
    
    🤖 Generated with Claude Code
    
    Co-Authored-By: Claude <no...@anthropic.com>
---
 superset-frontend/.eslintrc.js      | 2939 ++++++++++++++++++++++++++++++++++-
 superset-frontend/package-lock.json |   62 +-
 superset-frontend/package.json      |    1 -
 3 files changed, 2900 insertions(+), 102 deletions(-)

diff --git a/superset-frontend/.eslintrc.js b/superset-frontend/.eslintrc.js
index bd87c8c6a4..4a7b6872e0 100644
--- a/superset-frontend/.eslintrc.js
+++ b/superset-frontend/.eslintrc.js
@@ -77,7 +77,6 @@ const restrictedImportsRules = {
 
 module.exports = {
   extends: [
-    'airbnb',
     'prettier',
     'prettier/react',
     'plugin:react-hooks/recommended',
@@ -116,7 +115,10 @@ module.exports = {
     },
   },
   plugins: [
+    'import',
     'react',
+    'jsx-a11y',
+    'react-hooks',
     'file-progress',
     'lodash',
     'theme-colors',
@@ -128,6 +130,1447 @@ module.exports = {
   // Add this TS ESlint rule in separate `rules` section to avoid breakages with JS/TS files in /cypress-base.
   // TODO(hainenber): merge it to below `rules` section.
   rules: {
+    // === Core Airbnb ESLint rules (extracted from eslint-config-airbnb) ===
+    // Plugin rules (react/*, import/*, jsx-a11y/*) remain in the 'extends: ["airbnb"]' config
+
+    'array-callback-return': [
+      'error',
+      {
+        allowImplicit: true,
+      },
+    ],
+    'block-scoped-var': 'error',
+    complexity: ['off', 20],
+    'consistent-return': 'error',
+    'default-case': [
+      'error',
+      {
+        commentPattern: '^no default$',
+      },
+    ],
+    'dot-notation': [
+      'error',
+      {
+        allowKeywords: true,
+      },
+    ],
+    'dot-location': ['error', 'property'],
+    eqeqeq: [
+      'error',
+      'always',
+      {
+        null: 'ignore',
+      },
+    ],
+    'grouped-accessor-pairs': 'error',
+    'no-alert': 'warn',
+    'no-caller': 'error',
+
+    'no-constructor-return': 'error',
+
+    'no-else-return': [
+      'error',
+      {
+        allowElseIf: false,
+      },
+    ],
+    'no-empty-function': [
+      'error',
+      {
+        allow: ['arrowFunctions', 'functions', 'methods'],
+      },
+    ],
+
+    'no-eval': 'error',
+    'no-extend-native': 'error',
+    'no-extra-bind': 'error',
+    'no-extra-label': 'error',
+
+    'no-floating-decimal': 'error',
+    'no-global-assign': [
+      'error',
+      {
+        exceptions: [],
+      },
+    ],
+
+    'no-implicit-coercion': [
+      'off',
+      {
+        boolean: false,
+        number: true,
+        string: true,
+        allow: [],
+      },
+    ],
+
+    'no-implied-eval': 'error',
+
+    '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-str': 'error',
+    'no-new': 'error',
+    'no-new-func': 'error',
+    'no-new-wrappers': 'error',
+
+    'no-octal-escape': 'error',
+    'no-param-reassign': [
+      'error',
+      {
+        props: true,
+        ignorePropertyModificationsFor: [
+          'acc',
+          'accumulator',
+          'e',
+          'ctx',
+          'context',
+          'req',
+          'request',
+          'res',
+          'response',
+          '$scope',
+          'staticContext',
+        ],
+      },
+    ],
+    'no-proto': 'error',
+
+    'no-return-assign': ['error', 'always'],
+    'no-return-await': 'error',
+    'no-script-url': 'error',
+    'no-self-assign': [
+      'error',
+      {
+        props: true,
+      },
+    ],
+    'no-self-compare': 'error',
+    'no-sequences': 'error',
+    'no-throw-literal': 'error',
+
+    'no-unused-expressions': [
+      'error',
+      {
+        allowShortCircuit: false,
+        allowTernary: false,
+        allowTaggedTemplates: false,
+      },
+    ],
+
+    'no-useless-concat': 'error',
+
+    'no-useless-return': 'error',
+    'no-void': 'error',
+    'no-warning-comments': [
+      'off',
+      {
+        terms: ['todo', 'fixme', 'xxx'],
+        location: 'start',
+      },
+    ],
+
+    'prefer-promise-reject-errors': [
+      'error',
+      {
+        allowEmptyReject: true,
+      },
+    ],
+
+    radix: 'error',
+
+    'vars-on-top': 'error',
+    'wrap-iife': [
+      'error',
+      'outside',
+      {
+        functionPrototypeMethods: false,
+      },
+    ],
+    yoda: 'error',
+
+    'getter-return': [
+      'error',
+      {
+        allowImplicit: true,
+      },
+    ],
+
+    'no-await-in-loop': 'error',
+
+    'no-cond-assign': ['error', 'always'],
+    'no-console': 'warn',
+    'no-constant-condition': 'warn',
+
+    'no-extra-parens': [
+      'off',
+      'all',
+      {
+        conditionalAssign: true,
+        nestedBinaryExpressions: false,
+        returnAssign: false,
+        ignoreJSX: 'all',
+        enforceForArrowConditionals: false,
+      },
+    ],
+    'no-extra-semi': 'error',
+
+    'no-template-curly-in-string': 'error',
+
+    'no-unreachable-loop': [
+      'error',
+      {
+        ignore: [],
+      },
+    ],
+
+    'valid-typeof': [
+      'error',
+      {
+        requireStringLiterals: true,
+      },
+    ],
+
+    'no-mixed-requires': ['off', false],
+
+    'array-bracket-newline': ['off', 'consistent'],
+    'array-element-newline': [
+      'off',
+      {
+        multiline: true,
+        minItems: 3,
+      },
+    ],
+    'array-bracket-spacing': ['error', 'never'],
+    'block-spacing': ['error', 'always'],
+    'brace-style': [
+      'error',
+      '1tbs',
+      {
+        allowSingleLine: true,
+      },
+    ],
+    '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'],
+
+    'eol-last': ['error', 'always'],
+    'function-call-argument-newline': ['error', 'consistent'],
+    'func-call-spacing': ['error', 'never'],
+    'func-name-matching': [
+      'off',
+      'always',
+      {
+        includeCommonJSModuleExports: false,
+        considerPropertyDescriptor: true,
+      },
+    ],
+    'func-style': ['off', 'expression'],
+    'function-paren-newline': ['error', 'multiline-arguments'],
+
+    'implicit-arrow-linebreak': ['error', 'beside'],
+    'jsx-quotes': ['error', 'prefer-double'],
+    '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: false,
+      },
+    ],
+    'max-depth': ['off', 4],
+    'max-len': [
+      'error',
+      100,
+      2,
+      {
+        ignoreUrls: true,
+        ignoreComments: false,
+        ignoreRegExpLiterals: true,
+        ignoreStrings: true,
+        ignoreTemplateLiterals: true,
+      },
+    ],
+    'max-lines': [
+      'off',
+      {
+        max: 300,
+        skipBlankLines: true,
+        skipComments: true,
+      },
+    ],
+    'max-lines-per-function': [
+      'off',
+      {
+        max: 50,
+        skipBlankLines: true,
+        skipComments: true,
+        IIFEs: true,
+      },
+    ],
+
+    'max-params': ['off', 3],
+    'max-statements': ['off', 10],
+    'max-statements-per-line': [
+      'off',
+      {
+        max: 1,
+      },
+    ],
+    'multiline-comment-style': ['off', 'starred-block'],
+    'multiline-ternary': ['off', 'never'],
+    'new-parens': 'error',
+
+    'newline-per-chained-call': [
+      'error',
+      {
+        ignoreChainWithDepth: 4,
+      },
+    ],
+    'no-array-constructor': 'error',
+
+    'no-lonely-if': 'error',
+    'no-mixed-spaces-and-tabs': 'error',
+    'no-multiple-empty-lines': [
+      'error',
+      {
+        max: 1,
+        maxBOF: 0,
+        maxEOF: 0,
+      },
+    ],
+
+    'no-new-object': 'error',
+    'no-plusplus': 'error',
+
+    'no-tabs': 'error',
+
+    'no-trailing-spaces': [
+      'error',
+      {
+        skipBlankLines: false,
+        ignoreComments: false,
+      },
+    ],
+    'no-underscore-dangle': [
+      'error',
+      {
+        allow: ['__REDUX_DEVTOOLS_EXTENSION_COMPOSE__'],
+        allowAfterThis: false,
+        allowAfterSuper: false,
+        enforceInMethodNames: true,
+      },
+    ],
+    '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,
+        },
+        ImportDeclaration: {
+          minProperties: 4,
+          multiline: true,
+          consistent: true,
+        },
+        ExportDeclaration: {
+          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',
+        },
+      },
+    ],
+
+    'quote-props': [
+      'error',
+      'as-needed',
+      {
+        keywords: false,
+        unnecessary: true,
+        numbers: false,
+      },
+    ],
+    quotes: [
+      'error',
+      'single',
+      {
+        avoidEscape: true,
+      },
+    ],
+
+    semi: ['error', 'always'],
+    'semi-spacing': [
+      'error',
+      {
+        before: false,
+        after: true,
+      },
+    ],
+    'semi-style': ['error', 'last'],
+    'sort-keys': [
+      'off',
+      'asc',
+      {
+        caseSensitive: false,
+        natural: true,
+      },
+    ],
+
+    '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'],
+
+    'no-label-var': 'error',
+    'no-restricted-globals': [
+      'error',
+      {
+        name: 'isFinite',
+        message:
+          'Use Number.isFinite instead https://github.com/airbnb/javascript#standard-library--isfinite',
+      },
+      {
+        name: 'isNaN',
+        message:
+          'Use Number.isNaN instead https://github.com/airbnb/javascript#standard-library--isnan',
+      },
+      '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-shadow-restricted-names': 'error',
+
+    'no-undef-init': 'error',
+
+    'no-unused-vars': [
+      'error',
+      {
+        vars: 'all',
+        args: 'after-used',
+        ignoreRestSiblings: true,
+      },
+    ],
+    'arrow-body-style': [
+      'error',
+      'as-needed',
+      {
+        requireReturnForObjectLiteral: false,
+      },
+    ],
+    'arrow-parens': ['error', 'always'],
+    'arrow-spacing': [
+      'error',
+      {
+        before: true,
+        after: true,
+      },
+    ],
+
+    'generator-star-spacing': [
+      'error',
+      {
+        before: false,
+        after: true,
+      },
+    ],
+
+    'no-confusing-arrow': [
+      'error',
+      {
+        allowParens: true,
+      },
+    ],
+
+    '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-const': [
+      'error',
+      {
+        destructuring: 'any',
+        ignoreReadBeforeAssign: true,
+      },
+    ],
+    'prefer-numeric-literals': 'error',
+
+    'prefer-rest-params': 'error',
+    'prefer-spread': 'error',
+    'prefer-template': 'error',
+
+    'rest-spread-spacing': ['error', 'never'],
+    'sort-imports': [
+      'off',
+      {
+        ignoreCase: false,
+        ignoreDeclarationSort: false,
+        ignoreMemberSort: false,
+        memberSyntaxSortOrder: ['none', 'all', 'multiple', 'single'],
+      },
+    ],
+    'symbol-description': 'error',
+    'template-curly-spacing': 'error',
+    'yield-star-spacing': ['error', 'after'],
+    strict: ['error', 'never'],
+    // === End of core Airbnb rules ===
+
+    // === Plugin rules from Airbnb (previously in eslint-config-airbnb) ===
+
+    // Import plugin rules (43 rules)
+    'import/no-unresolved': [
+      'error',
+      {
+        commonjs: true,
+        caseSensitive: true,
+      },
+    ],
+    'import/named': 'error',
+    'import/default': 'off',
+    'import/namespace': 'off',
+    '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__/**',
+          '**/__mocks__/**',
+          'test.{js,jsx}',
+          'test-*.{js,jsx}',
+          '**/*{.,_}{test,spec}.{js,jsx}',
+          '**/jest.config.js',
+          '**/jest.setup.js',
+          '**/vue.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',
+          '**/karma.conf.js',
+          '**/.eslintrc.js',
+        ],
+        optionalDependencies: false,
+      },
+    ],
+    'import/no-mutable-exports': 'error',
+    'import/no-commonjs': 'off',
+    'import/no-amd': 'error',
+    'import/no-nodejs-modules': 'off',
+    'import/first': 'error',
+    'import/imports-first': 'off',
+    'import/no-duplicates': 'error',
+    'import/no-namespace': 'off',
+    'import/extensions': [
+      'error',
+      'ignorePackages',
+      {
+        js: 'never',
+        mjs: 'never',
+        jsx: 'never',
+      },
+    ],
+    'import/order': [
+      'error',
+      {
+        groups: [['builtin', 'external', 'internal']],
+      },
+    ],
+    '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': [
+      'off',
+      {
+        allowArray: false,
+        allowArrowFunction: false,
+        allowAnonymousClass: false,
+        allowAnonymousFunction: false,
+        allowLiteral: false,
+        allowObject: false,
+      },
+    ],
+    'import/exports-last': 'off',
+    'import/group-exports': 'off',
+    'import/no-default-export': 'off',
+    'import/no-named-export': 'off',
+    'import/no-self-import': 'error',
+    'import/no-cycle': [
+      'error',
+      {
+        maxDepth: '∞',
+      },
+    ],
+    'import/no-useless-path-segments': [
+      'error',
+      {
+        commonjs: true,
+      },
+    ],
+    'import/dynamic-import-chunkname': [
+      'off',
+      {
+        importFunctions: [],
+        webpackChunknameFormat: '[0-9a-zA-Z-_/.]+',
+      },
+    ],
+    'import/no-relative-parent-imports': 'off',
+    'import/no-unused-modules': [
+      'off',
+      {
+        ignoreExports: [],
+        missingExports: true,
+        unusedExports: true,
+      },
+    ],
+    'import/no-import-module-exports': [
+      'error',
+      {
+        exceptions: [],
+      },
+    ],
+    'import/no-relative-packages': 'error',
+
+    // React plugin rules (94 rules)
+    'react/display-name': [
+      'off',
+      {
+        ignoreTranspilerName: false,
+      },
+    ],
+    'react/forbid-prop-types': [
+      'error',
+      {
+        forbid: ['any', 'array', 'object'],
+        checkContextTypes: true,
+        checkChildContextTypes: true,
+      },
+    ],
+    'react/forbid-dom-props': [
+      'off',
+      {
+        forbid: [],
+      },
+    ],
+    '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': 'off',
+    'react/jsx-max-props-per-line': [
+      'error',
+      {
+        maximum: 1,
+        when: 'multiline',
+      },
+    ],
+    'react/jsx-no-bind': [
+      'error',
+      {
+        ignoreRefs: true,
+        allowArrowFunctions: true,
+        allowFunctions: false,
+        allowBind: false,
+        ignoreDOMComponents: true,
+      },
+    ],
+    '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,
+        sortShapeProp: true,
+      },
+    ],
+    '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-sort-default-props': [
+      'off',
+      {
+        ignoreCase: true,
+      },
+    ],
+    'react/jsx-uses-vars': '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': 'off',
+    'react/no-is-mounted': 'error',
+    'react/no-multi-comp': 'off',
+    'react/no-set-state': 'off',
+    'react/no-string-refs': '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/require-render-return': 'error',
+    'react/self-closing-comp': 'error',
+    'react/sort-comp': [
+      'error',
+      {
+        order: [
+          'static-variables',
+          'static-methods',
+          'instance-variables',
+          'lifecycle',
+          '/^handle.+$/',
+          '/^on.+$/',
+          'getters',
+          'setters',
+          '/^(get|set)(?!(InitialState$|DefaultProps$|ChildContext$)).+$/',
+          'instance-methods',
+          'everything-else',
+          'rendering',
+        ],
+        groups: {
+          lifecycle: [
+            'displayName',
+            'propTypes',
+            'contextTypes',
+            'childContextTypes',
+            'mixins',
+            'statics',
+            'defaultProps',
+            'constructor',
+            'getDefaultProps',
+            'getInitialState',
+            'state',
+            'getChildContext',
+            'getDerivedStateFromProps',
+            'componentWillMount',
+            'UNSAFE_componentWillMount',
+            'componentDidMount',
+            'componentWillReceiveProps',
+            'UNSAFE_componentWillReceiveProps',
+            'shouldComponentUpdate',
+            'componentWillUpdate',
+            'UNSAFE_componentWillUpdate',
+            'getSnapshotBeforeUpdate',
+            'componentDidUpdate',
+            'componentDidCatch',
+            'componentWillUnmount',
+          ],
+          rendering: ['/^render.+$/', 'render'],
+        },
+      },
+    ],
+    'react/jsx-wrap-multilines': [
+      'error',
+      {
+        declaration: 'parens-new-line',
+        assignment: 'parens-new-line',
+        return: 'parens-new-line',
+        arrow: 'parens-new-line',
+        condition: 'parens-new-line',
+        logical: 'parens-new-line',
+        prop: 'parens-new-line',
+      },
+    ],
+    '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',
+      {
+        enforceDynamicLinks: 'always',
+      },
+    ],
+    'react/jsx-filename-extension': [
+      'error',
+      {
+        extensions: ['.jsx'],
+      },
+    ],
+    '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',
+        beforeClosing: 'never',
+      },
+    ],
+    'react/jsx-space-before-closing': ['off', 'always'],
+    'react/no-array-index-key': 'error',
+    'react/require-default-props': [
+      'error',
+      {
+        forbidDefaultForRequired: true,
+      },
+    ],
+    'react/forbid-foreign-prop-types': [
+      'warn',
+      {
+        allowInPropTypes: true,
+      },
+    ],
+    '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]?)+',
+        message: '',
+      },
+    ],
+    'react/no-typos': 'error',
+    'react/jsx-curly-brace-presence': [
+      'error',
+      {
+        props: 'never',
+        children: 'never',
+      },
+    ],
+    'react/jsx-one-expression-per-line': [
+      'error',
+      {
+        allow: 'single-child',
+      },
+    ],
+    'react/destructuring-assignment': ['error', 'always'],
+    'react/no-access-state-in-setstate': 'error',
+    'react/button-has-type': [
+      'error',
+      {
+        button: true,
+        submit: true,
+        reset: false,
+      },
+    ],
+    'react/jsx-child-element-spacing': 'off',
+    'react/no-this-in-sfc': 'error',
+    'react/jsx-max-depth': 'off',
+    'react/jsx-props-no-multi-spaces': 'error',
+    'react/no-unsafe': 'off',
+    'react/jsx-fragments': ['error', 'syntax'],
+    'react/jsx-curly-newline': [
+      'error',
+      {
+        multiline: 'consistent',
+        singleline: 'consistent',
+      },
+    ],
+    'react/state-in-constructor': ['error', 'always'],
+    'react/static-property-placement': ['error', 'property assignment'],
+    'react/jsx-props-no-spreading': [
+      'error',
+      {
+        html: 'enforce',
+        custom: 'enforce',
+        explicitSpread: 'ignore',
+        exceptions: [],
+      },
+    ],
+    'react/prefer-read-only-props': 'off',
+    'react/jsx-no-script-url': [
+      'error',
+      [
+        {
+          name: 'Link',
+          props: ['to'],
+        },
+      ],
+    ],
+    'react/jsx-no-useless-fragment': 'error',
+    'react/no-adjacent-inline-elements': 'off',
+    'react/function-component-definition': [
+      'error',
+      {
+        namedComponents: ['function-declaration', 'function-expression'],
+        unnamedComponents: 'function-expression',
+      },
+    ],
+    'react/jsx-newline': 'off',
+    'react/jsx-no-constructed-context-values': 'error',
+    'react/no-unstable-nested-components': 'error',
+    'react/no-namespace': 'error',
+    'react/prefer-exact-props': 'error',
+    'react/no-arrow-function-lifecycle': 'error',
+    'react/no-invalid-html-attribute': 'error',
+    'react/no-unused-class-component-methods': 'error',
+
+    // JSX-a11y plugin rules (36 rules)
+    'jsx-a11y/accessible-emoji': 'off',
+    'jsx-a11y/alt-text': [
+      'error',
+      {
+        elements: ['img', 'object', 'area', 'input[type="image"]'],
+        img: [],
+        object: [],
+        area: [],
+        'input[type="image"]': [],
+      },
+    ],
+    'jsx-a11y/anchor-has-content': [
+      'error',
+      {
+        components: [],
+      },
+    ],
+    'jsx-a11y/anchor-is-valid': [
+      'error',
+      {
+        components: ['Link'],
+        specialLink: ['to'],
+        aspects: ['noHref', 'invalidHref', 'preferButton'],
+      },
+    ],
+    'jsx-a11y/aria-activedescendant-has-tabindex': 'error',
+    'jsx-a11y/aria-props': 'error',
+    'jsx-a11y/aria-proptypes': 'error',
+    'jsx-a11y/aria-role': [
+      'error',
+      {
+        ignoreNonDOM: false,
+      },
+    ],
+    'jsx-a11y/aria-unsupported-elements': 'error',
+    'jsx-a11y/autocomplete-valid': [
+      'off',
+      {
+        inputComponents: [],
+      },
+    ],
+    'jsx-a11y/click-events-have-key-events': 'error',
+    'jsx-a11y/control-has-associated-label': [
+      'error',
+      {
+        labelAttributes: ['label'],
+        controlComponents: [],
+        ignoreElements: [
+          'audio',
+          'canvas',
+          'embed',
+          'input',
+          'textarea',
+          'tr',
+          'video',
+        ],
+        ignoreRoles: [
+          'grid',
+          'listbox',
+          'menu',
+          'menubar',
+          'radiogroup',
+          'row',
+          'tablist',
+          'toolbar',
+          'tree',
+          'treegrid',
+        ],
+        depth: 5,
+      },
+    ],
+    'jsx-a11y/heading-has-content': [
+      'error',
+      {
+        components: [''],
+      },
+    ],
+    'jsx-a11y/html-has-lang': 'error',
+    'jsx-a11y/iframe-has-title': 'error',
+    'jsx-a11y/img-redundant-alt': 'error',
+    'jsx-a11y/interactive-supports-focus': 'error',
+    'jsx-a11y/label-has-associated-control': [
+      'error',
+      {
+        labelComponents: [],
+        labelAttributes: [],
+        controlComponents: [],
+        assert: 'both',
+        depth: 25,
+      },
+    ],
+    'jsx-a11y/lang': 'error',
+    'jsx-a11y/media-has-caption': [
+      'error',
+      {
+        audio: [],
+        video: [],
+        track: [],
+      },
+    ],
+    'jsx-a11y/mouse-events-have-key-events': 'error',
+    'jsx-a11y/no-access-key': 'error',
+    'jsx-a11y/no-autofocus': [
+      'error',
+      {
+        ignoreNonDOM: true,
+      },
+    ],
+    'jsx-a11y/no-distracting-elements': [
+      'error',
+      {
+        elements: ['marquee', 'blink'],
+      },
+    ],
+    'jsx-a11y/no-interactive-element-to-noninteractive-role': [
+      'error',
+      {
+        tr: ['none', 'presentation'],
+      },
+    ],
+    'jsx-a11y/no-noninteractive-element-interactions': [
+      'error',
+      {
+        handlers: [
+          'onClick',
+          'onMouseDown',
+          'onMouseUp',
+          'onKeyPress',
+          'onKeyDown',
+          'onKeyUp',
+        ],
+      },
+    ],
+    '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/no-onchange': 'off',
+    'jsx-a11y/no-redundant-roles': 'error',
+    'jsx-a11y/no-static-element-interactions': [
+      'error',
+      {
+        handlers: [
+          'onClick',
+          'onMouseDown',
+          'onMouseUp',
+          'onKeyPress',
+          'onKeyDown',
+          'onKeyUp',
+        ],
+      },
+    ],
+    'jsx-a11y/role-has-required-aria-props': 'error',
+    'jsx-a11y/role-supports-aria-props': 'error',
+    'jsx-a11y/scope': 'error',
+    'jsx-a11y/tabindex-no-positive': 'error',
+    'jsx-a11y/label-has-for': [
+      'off',
+      {
+        components: [],
+        required: {
+          every: ['nesting', 'id'],
+        },
+        allowChildren: false,
+      },
+    ],
+
+    // React-hooks plugin rules (2 rules)
+    'react-hooks/rules-of-hooks': 'error',
+    'react-hooks/exhaustive-deps': 'error',
+
+    // === End of plugin rules from Airbnb ===
+
+    // === Custom rules ===
     '@typescript-eslint/prefer-optional-chain': 'error',
   },
   overrides: [
@@ -135,7 +1578,6 @@ module.exports = {
       files: ['*.ts', '*.tsx'],
       parser: '@typescript-eslint/parser',
       extends: [
-        'airbnb',
         'plugin:@typescript-eslint/recommended',
         'prettier',
         'prettier/@typescript-eslint',
@@ -143,6 +1585,1447 @@ module.exports = {
       ],
       plugins: ['@typescript-eslint/eslint-plugin', 'react', 'prettier'],
       rules: {
+        // === Core Airbnb ESLint rules (extracted from eslint-config-airbnb) ===
+
+        'array-callback-return': [
+          'error',
+          {
+            allowImplicit: true,
+          },
+        ],
+        'block-scoped-var': 'error',
+        complexity: ['off', 20],
+        'consistent-return': 'error',
+        'default-case': [
+          'error',
+          {
+            commentPattern: '^no default$',
+          },
+        ],
+        'dot-notation': [
+          'error',
+          {
+            allowKeywords: true,
+          },
+        ],
+        'dot-location': ['error', 'property'],
+        eqeqeq: [
+          'error',
+          'always',
+          {
+            null: 'ignore',
+          },
+        ],
+        'grouped-accessor-pairs': 'error',
+        'no-alert': 'warn',
+        'no-caller': 'error',
+
+        'no-constructor-return': 'error',
+
+        'no-else-return': [
+          'error',
+          {
+            allowElseIf: false,
+          },
+        ],
+        'no-empty-function': [
+          'error',
+          {
+            allow: ['arrowFunctions', 'functions', 'methods'],
+          },
+        ],
+
+        'no-eval': 'error',
+        'no-extend-native': 'error',
+        'no-extra-bind': 'error',
+        'no-extra-label': 'error',
+
+        'no-floating-decimal': 'error',
+        'no-global-assign': [
+          'error',
+          {
+            exceptions: [],
+          },
+        ],
+
+        'no-implicit-coercion': [
+          'off',
+          {
+            boolean: false,
+            number: true,
+            string: true,
+            allow: [],
+          },
+        ],
+
+        'no-implied-eval': 'error',
+
+        '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-str': 'error',
+        'no-new': 'error',
+        'no-new-func': 'error',
+        'no-new-wrappers': 'error',
+
+        'no-octal-escape': 'error',
+        'no-param-reassign': [
+          'error',
+          {
+            props: true,
+            ignorePropertyModificationsFor: [
+              'acc',
+              'accumulator',
+              'e',
+              'ctx',
+              'context',
+              'req',
+              'request',
+              'res',
+              'response',
+              '$scope',
+              'staticContext',
+            ],
+          },
+        ],
+        'no-proto': 'error',
+
+        'no-return-assign': ['error', 'always'],
+        'no-return-await': 'error',
+        'no-script-url': 'error',
+        'no-self-assign': [
+          'error',
+          {
+            props: true,
+          },
+        ],
+        'no-self-compare': 'error',
+        'no-sequences': 'error',
+        'no-throw-literal': 'error',
+
+        'no-unused-expressions': [
+          'error',
+          {
+            allowShortCircuit: false,
+            allowTernary: false,
+            allowTaggedTemplates: false,
+          },
+        ],
+
+        'no-useless-concat': 'error',
+
+        'no-useless-return': 'error',
+        'no-void': 'error',
+        'no-warning-comments': [
+          'off',
+          {
+            terms: ['todo', 'fixme', 'xxx'],
+            location: 'start',
+          },
+        ],
+
+        'prefer-promise-reject-errors': [
+          'error',
+          {
+            allowEmptyReject: true,
+          },
+        ],
+
+        radix: 'error',
+
+        'vars-on-top': 'error',
+        'wrap-iife': [
+          'error',
+          'outside',
+          {
+            functionPrototypeMethods: false,
+          },
+        ],
+        yoda: 'error',
+
+        'getter-return': [
+          'error',
+          {
+            allowImplicit: true,
+          },
+        ],
+
+        'no-await-in-loop': 'error',
+
+        'no-cond-assign': ['error', 'always'],
+        'no-console': 'warn',
+        'no-constant-condition': 'warn',
+
+        'no-extra-parens': [
+          'off',
+          'all',
+          {
+            conditionalAssign: true,
+            nestedBinaryExpressions: false,
+            returnAssign: false,
+            ignoreJSX: 'all',
+            enforceForArrowConditionals: false,
+          },
+        ],
+        'no-extra-semi': 'error',
+
+        'no-template-curly-in-string': 'error',
+
+        'no-unreachable-loop': [
+          'error',
+          {
+            ignore: [],
+          },
+        ],
+
+        'valid-typeof': [
+          'error',
+          {
+            requireStringLiterals: true,
+          },
+        ],
+
+        'no-mixed-requires': ['off', false],
+
+        'array-bracket-newline': ['off', 'consistent'],
+        'array-element-newline': [
+          'off',
+          {
+            multiline: true,
+            minItems: 3,
+          },
+        ],
+        'array-bracket-spacing': ['error', 'never'],
+        'block-spacing': ['error', 'always'],
+        'brace-style': [
+          'error',
+          '1tbs',
+          {
+            allowSingleLine: true,
+          },
+        ],
+        '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'],
+
+        'eol-last': ['error', 'always'],
+        'function-call-argument-newline': ['error', 'consistent'],
+        'func-call-spacing': ['error', 'never'],
+        'func-name-matching': [
+          'off',
+          'always',
+          {
+            includeCommonJSModuleExports: false,
+            considerPropertyDescriptor: true,
+          },
+        ],
+        'func-style': ['off', 'expression'],
+        'function-paren-newline': ['error', 'multiline-arguments'],
+
+        'implicit-arrow-linebreak': ['error', 'beside'],
+        'jsx-quotes': ['error', 'prefer-double'],
+        '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: false,
+          },
+        ],
+        'max-depth': ['off', 4],
+        'max-len': [
+          'error',
+          100,
+          2,
+          {
+            ignoreUrls: true,
+            ignoreComments: false,
+            ignoreRegExpLiterals: true,
+            ignoreStrings: true,
+            ignoreTemplateLiterals: true,
+          },
+        ],
+        'max-lines': [
+          'off',
+          {
+            max: 300,
+            skipBlankLines: true,
+            skipComments: true,
+          },
+        ],
+        'max-lines-per-function': [
+          'off',
+          {
+            max: 50,
+            skipBlankLines: true,
+            skipComments: true,
+            IIFEs: true,
+          },
+        ],
+
+        'max-params': ['off', 3],
+        'max-statements': ['off', 10],
+        'max-statements-per-line': [
+          'off',
+          {
+            max: 1,
+          },
+        ],
+        'multiline-comment-style': ['off', 'starred-block'],
+        'multiline-ternary': ['off', 'never'],
+        'new-parens': 'error',
+
+        'newline-per-chained-call': [
+          'error',
+          {
+            ignoreChainWithDepth: 4,
+          },
+        ],
+        'no-array-constructor': 'error',
+
+        'no-lonely-if': 'error',
+        'no-mixed-spaces-and-tabs': 'error',
+        'no-multiple-empty-lines': [
+          'error',
+          {
+            max: 1,
+            maxBOF: 0,
+            maxEOF: 0,
+          },
+        ],
+
+        'no-new-object': 'error',
+        'no-plusplus': 'error',
+
+        'no-tabs': 'error',
+
+        'no-trailing-spaces': [
+          'error',
+          {
+            skipBlankLines: false,
+            ignoreComments: false,
+          },
+        ],
+        'no-underscore-dangle': [
+          'error',
+          {
+            allow: ['__REDUX_DEVTOOLS_EXTENSION_COMPOSE__'],
+            allowAfterThis: false,
+            allowAfterSuper: false,
+            enforceInMethodNames: true,
+          },
+        ],
+        '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,
+            },
+            ImportDeclaration: {
+              minProperties: 4,
+              multiline: true,
+              consistent: true,
+            },
+            ExportDeclaration: {
+              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',
+            },
+          },
+        ],
+
+        'quote-props': [
+          'error',
+          'as-needed',
+          {
+            keywords: false,
+            unnecessary: true,
+            numbers: false,
+          },
+        ],
+        quotes: [
+          'error',
+          'single',
+          {
+            avoidEscape: true,
+          },
+        ],
+
+        semi: ['error', 'always'],
+        'semi-spacing': [
+          'error',
+          {
+            before: false,
+            after: true,
+          },
+        ],
+        'semi-style': ['error', 'last'],
+        'sort-keys': [
+          'off',
+          'asc',
+          {
+            caseSensitive: false,
+            natural: true,
+          },
+        ],
+
+        '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'],
+
+        'no-label-var': 'error',
+        'no-restricted-globals': [
+          'error',
+          {
+            name: 'isFinite',
+            message:
+              'Use Number.isFinite instead https://github.com/airbnb/javascript#standard-library--isfinite',
+          },
+          {
+            name: 'isNaN',
+            message:
+              'Use Number.isNaN instead https://github.com/airbnb/javascript#standard-library--isnan',
+          },
+          '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-shadow-restricted-names': 'error',
+
+        'no-undef-init': 'error',
+
+        'no-unused-vars': [
+          'error',
+          {
+            vars: 'all',
+            args: 'after-used',
+            ignoreRestSiblings: true,
+          },
+        ],
+        'arrow-body-style': [
+          'error',
+          'as-needed',
+          {
+            requireReturnForObjectLiteral: false,
+          },
+        ],
+        'arrow-parens': ['error', 'always'],
+        'arrow-spacing': [
+          'error',
+          {
+            before: true,
+            after: true,
+          },
+        ],
+
+        'generator-star-spacing': [
+          'error',
+          {
+            before: false,
+            after: true,
+          },
+        ],
+
+        'no-confusing-arrow': [
+          'error',
+          {
+            allowParens: true,
+          },
+        ],
+
+        '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-const': [
+          'error',
+          {
+            destructuring: 'any',
+            ignoreReadBeforeAssign: true,
+          },
+        ],
+        'prefer-numeric-literals': 'error',
+
+        'prefer-rest-params': 'error',
+        'prefer-spread': 'error',
+        'prefer-template': 'error',
+
+        'rest-spread-spacing': ['error', 'never'],
+        'sort-imports': [
+          'off',
+          {
+            ignoreCase: false,
+            ignoreDeclarationSort: false,
+            ignoreMemberSort: false,
+            memberSyntaxSortOrder: ['none', 'all', 'multiple', 'single'],
+          },
+        ],
+        'symbol-description': 'error',
+        'template-curly-spacing': 'error',
+        'yield-star-spacing': ['error', 'after'],
+        strict: ['error', 'never'],
+        // === End of core Airbnb rules ===
+
+        // === Plugin rules from Airbnb (previously in eslint-config-airbnb) ===
+
+        // Import plugin rules (43 rules)
+        'import/no-unresolved': [
+          'error',
+          {
+            commonjs: true,
+            caseSensitive: true,
+          },
+        ],
+        'import/named': 'error',
+        'import/default': 'off',
+        'import/namespace': 'off',
+        '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__/**',
+              '**/__mocks__/**',
+              'test.{js,jsx}',
+              'test-*.{js,jsx}',
+              '**/*{.,_}{test,spec}.{js,jsx}',
+              '**/jest.config.js',
+              '**/jest.setup.js',
+              '**/vue.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',
+              '**/karma.conf.js',
+              '**/.eslintrc.js',
+            ],
+            optionalDependencies: false,
+          },
+        ],
+        'import/no-mutable-exports': 'error',
+        'import/no-commonjs': 'off',
+        'import/no-amd': 'error',
+        'import/no-nodejs-modules': 'off',
+        'import/first': 'error',
+        'import/imports-first': 'off',
+        'import/no-duplicates': 'error',
+        'import/no-namespace': 'off',
+        'import/extensions': [
+          'error',
+          'ignorePackages',
+          {
+            js: 'never',
+            mjs: 'never',
+            jsx: 'never',
+          },
+        ],
+        'import/order': [
+          'error',
+          {
+            groups: [['builtin', 'external', 'internal']],
+          },
+        ],
+        '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': [
+          'off',
+          {
+            allowArray: false,
+            allowArrowFunction: false,
+            allowAnonymousClass: false,
+            allowAnonymousFunction: false,
+            allowLiteral: false,
+            allowObject: false,
+          },
+        ],
+        'import/exports-last': 'off',
+        'import/group-exports': 'off',
+        'import/no-default-export': 'off',
+        'import/no-named-export': 'off',
+        'import/no-self-import': 'error',
+        'import/no-cycle': [
+          'error',
+          {
+            maxDepth: '∞',
+          },
+        ],
+        'import/no-useless-path-segments': [
+          'error',
+          {
+            commonjs: true,
+          },
+        ],
+        'import/dynamic-import-chunkname': [
+          'off',
+          {
+            importFunctions: [],
+            webpackChunknameFormat: '[0-9a-zA-Z-_/.]+',
+          },
+        ],
+        'import/no-relative-parent-imports': 'off',
+        'import/no-unused-modules': [
+          'off',
+          {
+            ignoreExports: [],
+            missingExports: true,
+            unusedExports: true,
+          },
+        ],
+        'import/no-import-module-exports': [
+          'error',
+          {
+            exceptions: [],
+          },
+        ],
+        'import/no-relative-packages': 'error',
+
+        // React plugin rules (94 rules)
+        'react/display-name': [
+          'off',
+          {
+            ignoreTranspilerName: false,
+          },
+        ],
+        'react/forbid-prop-types': [
+          'error',
+          {
+            forbid: ['any', 'array', 'object'],
+            checkContextTypes: true,
+            checkChildContextTypes: true,
+          },
+        ],
+        'react/forbid-dom-props': [
+          'off',
+          {
+            forbid: [],
+          },
+        ],
+        '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': 'off',
+        'react/jsx-max-props-per-line': [
+          'error',
+          {
+            maximum: 1,
+            when: 'multiline',
+          },
+        ],
+        'react/jsx-no-bind': [
+          'error',
+          {
+            ignoreRefs: true,
+            allowArrowFunctions: true,
+            allowFunctions: false,
+            allowBind: false,
+            ignoreDOMComponents: true,
+          },
+        ],
+        '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,
+            sortShapeProp: true,
+          },
+        ],
+        '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-sort-default-props': [
+          'off',
+          {
+            ignoreCase: true,
+          },
+        ],
+        'react/jsx-uses-vars': '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': 'off',
+        'react/no-is-mounted': 'error',
+        'react/no-multi-comp': 'off',
+        'react/no-set-state': 'off',
+        'react/no-string-refs': '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/require-render-return': 'error',
+        'react/self-closing-comp': 'error',
+        'react/sort-comp': [
+          'error',
+          {
+            order: [
+              'static-variables',
+              'static-methods',
+              'instance-variables',
+              'lifecycle',
+              '/^handle.+$/',
+              '/^on.+$/',
+              'getters',
+              'setters',
+              '/^(get|set)(?!(InitialState$|DefaultProps$|ChildContext$)).+$/',
+              'instance-methods',
+              'everything-else',
+              'rendering',
+            ],
+            groups: {
+              lifecycle: [
+                'displayName',
+                'propTypes',
+                'contextTypes',
+                'childContextTypes',
+                'mixins',
+                'statics',
+                'defaultProps',
+                'constructor',
+                'getDefaultProps',
+                'getInitialState',
+                'state',
+                'getChildContext',
+                'getDerivedStateFromProps',
+                'componentWillMount',
+                'UNSAFE_componentWillMount',
+                'componentDidMount',
+                'componentWillReceiveProps',
+                'UNSAFE_componentWillReceiveProps',
+                'shouldComponentUpdate',
+                'componentWillUpdate',
+                'UNSAFE_componentWillUpdate',
+                'getSnapshotBeforeUpdate',
+                'componentDidUpdate',
+                'componentDidCatch',
+                'componentWillUnmount',
+              ],
+              rendering: ['/^render.+$/', 'render'],
+            },
+          },
+        ],
+        'react/jsx-wrap-multilines': [
+          'error',
+          {
+            declaration: 'parens-new-line',
+            assignment: 'parens-new-line',
+            return: 'parens-new-line',
+            arrow: 'parens-new-line',
+            condition: 'parens-new-line',
+            logical: 'parens-new-line',
+            prop: 'parens-new-line',
+          },
+        ],
+        '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',
+          {
+            enforceDynamicLinks: 'always',
+          },
+        ],
+        'react/jsx-filename-extension': [
+          'error',
+          {
+            extensions: ['.jsx'],
+          },
+        ],
+        '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',
+            beforeClosing: 'never',
+          },
+        ],
+        'react/jsx-space-before-closing': ['off', 'always'],
+        'react/no-array-index-key': 'error',
+        'react/require-default-props': [
+          'error',
+          {
+            forbidDefaultForRequired: true,
+          },
+        ],
+        'react/forbid-foreign-prop-types': [
+          'warn',
+          {
+            allowInPropTypes: true,
+          },
+        ],
+        '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]?)+',
+            message: '',
+          },
+        ],
+        'react/no-typos': 'error',
+        'react/jsx-curly-brace-presence': [
+          'error',
+          {
+            props: 'never',
+            children: 'never',
+          },
+        ],
+        'react/jsx-one-expression-per-line': [
+          'error',
+          {
+            allow: 'single-child',
+          },
+        ],
+        'react/destructuring-assignment': ['error', 'always'],
+        'react/no-access-state-in-setstate': 'error',
+        'react/button-has-type': [
+          'error',
+          {
+            button: true,
+            submit: true,
+            reset: false,
+          },
+        ],
+        'react/jsx-child-element-spacing': 'off',
+        'react/no-this-in-sfc': 'error',
+        'react/jsx-max-depth': 'off',
+        'react/jsx-props-no-multi-spaces': 'error',
+        'react/no-unsafe': 'off',
+        'react/jsx-fragments': ['error', 'syntax'],
+        'react/jsx-curly-newline': [
+          'error',
+          {
+            multiline: 'consistent',
+            singleline: 'consistent',
+          },
+        ],
+        'react/state-in-constructor': ['error', 'always'],
+        'react/static-property-placement': ['error', 'property assignment'],
+        'react/jsx-props-no-spreading': [
+          'error',
+          {
+            html: 'enforce',
+            custom: 'enforce',
+            explicitSpread: 'ignore',
+            exceptions: [],
+          },
+        ],
+        'react/prefer-read-only-props': 'off',
+        'react/jsx-no-script-url': [
+          'error',
+          [
+            {
+              name: 'Link',
+              props: ['to'],
+            },
+          ],
+        ],
+        'react/jsx-no-useless-fragment': 'error',
+        'react/no-adjacent-inline-elements': 'off',
+        'react/function-component-definition': [
+          'error',
+          {
+            namedComponents: ['function-declaration', 'function-expression'],
+            unnamedComponents: 'function-expression',
+          },
+        ],
+        'react/jsx-newline': 'off',
+        'react/jsx-no-constructed-context-values': 'error',
+        'react/no-unstable-nested-components': 'error',
+        'react/no-namespace': 'error',
+        'react/prefer-exact-props': 'error',
+        'react/no-arrow-function-lifecycle': 'error',
+        'react/no-invalid-html-attribute': 'error',
+        'react/no-unused-class-component-methods': 'error',
+
+        // JSX-a11y plugin rules (36 rules)
+        'jsx-a11y/accessible-emoji': 'off',
+        'jsx-a11y/alt-text': [
+          'error',
+          {
+            elements: ['img', 'object', 'area', 'input[type="image"]'],
+            img: [],
+            object: [],
+            area: [],
+            'input[type="image"]': [],
+          },
+        ],
+        'jsx-a11y/anchor-has-content': [
+          'error',
+          {
+            components: [],
+          },
+        ],
+        'jsx-a11y/anchor-is-valid': [
+          'error',
+          {
+            components: ['Link'],
+            specialLink: ['to'],
+            aspects: ['noHref', 'invalidHref', 'preferButton'],
+          },
+        ],
+        'jsx-a11y/aria-activedescendant-has-tabindex': 'error',
+        'jsx-a11y/aria-props': 'error',
+        'jsx-a11y/aria-proptypes': 'error',
+        'jsx-a11y/aria-role': [
+          'error',
+          {
+            ignoreNonDOM: false,
+          },
+        ],
+        'jsx-a11y/aria-unsupported-elements': 'error',
+        'jsx-a11y/autocomplete-valid': [
+          'off',
+          {
+            inputComponents: [],
+          },
+        ],
+        'jsx-a11y/click-events-have-key-events': 'error',
+        'jsx-a11y/control-has-associated-label': [
+          'error',
+          {
+            labelAttributes: ['label'],
+            controlComponents: [],
+            ignoreElements: [
+              'audio',
+              'canvas',
+              'embed',
+              'input',
+              'textarea',
+              'tr',
+              'video',
+            ],
+            ignoreRoles: [
+              'grid',
+              'listbox',
+              'menu',
+              'menubar',
+              'radiogroup',
+              'row',
+              'tablist',
+              'toolbar',
+              'tree',
+              'treegrid',
+            ],
+            depth: 5,
+          },
+        ],
+        'jsx-a11y/heading-has-content': [
+          'error',
+          {
+            components: [''],
+          },
+        ],
+        'jsx-a11y/html-has-lang': 'error',
+        'jsx-a11y/iframe-has-title': 'error',
+        'jsx-a11y/img-redundant-alt': 'error',
+        'jsx-a11y/interactive-supports-focus': 'error',
+        'jsx-a11y/label-has-associated-control': [
+          'error',
+          {
+            labelComponents: [],
+            labelAttributes: [],
+            controlComponents: [],
+            assert: 'both',
+            depth: 25,
+          },
+        ],
+        'jsx-a11y/lang': 'error',
+        'jsx-a11y/media-has-caption': [
+          'error',
+          {
+            audio: [],
+            video: [],
+            track: [],
+          },
+        ],
+        'jsx-a11y/mouse-events-have-key-events': 'error',
+        'jsx-a11y/no-access-key': 'error',
+        'jsx-a11y/no-autofocus': [
+          'error',
+          {
+            ignoreNonDOM: true,
+          },
+        ],
+        'jsx-a11y/no-distracting-elements': [
+          'error',
+          {
+            elements: ['marquee', 'blink'],
+          },
+        ],
+        'jsx-a11y/no-interactive-element-to-noninteractive-role': [
+          'error',
+          {
+            tr: ['none', 'presentation'],
+          },
+        ],
+        'jsx-a11y/no-noninteractive-element-interactions': [
+          'error',
+          {
+            handlers: [
+              'onClick',
+              'onMouseDown',
+              'onMouseUp',
+              'onKeyPress',
+              'onKeyDown',
+              'onKeyUp',
+            ],
+          },
+        ],
+        '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/no-onchange': 'off',
+        'jsx-a11y/no-redundant-roles': 'error',
+        'jsx-a11y/no-static-element-interactions': [
+          'error',
+          {
+            handlers: [
+              'onClick',
+              'onMouseDown',
+              'onMouseUp',
+              'onKeyPress',
+              'onKeyDown',
+              'onKeyUp',
+            ],
+          },
+        ],
+        'jsx-a11y/role-has-required-aria-props': 'error',
+        'jsx-a11y/role-supports-aria-props': 'error',
+        'jsx-a11y/scope': 'error',
+        'jsx-a11y/tabindex-no-positive': 'error',
+        'jsx-a11y/label-has-for': [
+          'off',
+          {
+            components: [],
+            required: {
+              every: ['nesting', 'id'],
+            },
+            allowChildren: false,
+          },
+        ],
+
+        // React-hooks plugin rules (2 rules)
+        'react-hooks/rules-of-hooks': 'error',
+        'react-hooks/exhaustive-deps': 'error',
+
+        // === End of plugin rules from Airbnb ===
+
+        // === Custom rules ===
+
         '@typescript-eslint/ban-ts-ignore': 0,
         '@typescript-eslint/ban-ts-comment': 0, // disabled temporarily
         '@typescript-eslint/ban-types': 0, // disabled temporarily
@@ -165,9 +3048,7 @@ module.exports = {
         '@typescript-eslint/explicit-module-boundary-types': 0, // re-enable up for discussion
         '@typescript-eslint/no-unused-vars': 'warn', // downgrade to Warning severity for Jest v30 upgrade
         camelcase: 0,
-        'class-methods-use-this': 0,
-        'func-names': 0,
-        'guard-for-in': 0,
+
         'import/no-cycle': 0, // re-enable up for discussion, might require some major refactors
         'import/extensions': [
           'error',
@@ -183,20 +3064,9 @@ module.exports = {
         'jsx-a11y/anchor-is-valid': 2,
         'jsx-a11y/click-events-have-key-events': 0, // re-enable up for discussion
         'jsx-a11y/mouse-events-have-key-events': 0, // re-enable up for discussion
-        'max-classes-per-file': 0,
-        'new-cap': 0,
-        'no-bitwise': 0,
-        'no-continue': 0,
-        'no-mixed-operators': 0,
-        'no-multi-assign': 0,
-        'no-multi-spaces': 0,
-        'no-nested-ternary': 0,
+
         'no-prototype-builtins': 0,
-        'no-restricted-properties': 0,
-        'no-shadow': 0, // re-enable up for discussion
-        'no-use-before-define': 0, // disabled temporarily
-        'padded-blocks': 0,
-        'prefer-arrow-callback': 0,
+
         'prefer-destructuring': ['error', { object: true, array: false }],
         'react/destructuring-assignment': 0, // re-enable up for discussion
         'react/forbid-prop-types': 0,
@@ -222,20 +3092,20 @@ module.exports = {
             namedComponents: 'arrow-function',
           },
         ],
-        'default-param-last': 0,
+
         'react/no-unstable-nested-components': 0,
         'react/jsx-no-useless-fragment': 0,
         'react/no-unknown-property': 0,
-        'no-restricted-exports': 0,
+
         'react/default-props-match-prop-types': 0,
         'no-unsafe-optional-chaining': 0,
         'react/state-in-constructor': 0,
         'import/no-import-module-exports': 0,
         'no-promise-executor-return': 0,
-        'prefer-regex-literals': 0,
+
         'react/no-unused-class-component-methods': 0,
         'import/no-relative-packages': 0,
-        'prefer-exponentiation-operator': 0,
+
         'react/react-in-jsx-scope': 0,
         'no-restricted-syntax': [
           'error',
@@ -347,8 +3217,7 @@ module.exports = {
           },
         ],
         'no-only-tests/no-only-tests': 'error',
-        'max-classes-per-file': 0,
-        // temporary rules to help with migration - please re-enable!
+
         'testing-library/await-async-queries': 0,
         'testing-library/await-async-utils': 0,
         'testing-library/no-await-sync-events': 0,
@@ -410,10 +3279,9 @@ module.exports = {
         properties: 'never',
       },
     ],
-    'class-methods-use-this': 0,
+
     curly: 2,
-    'func-names': 0,
-    'guard-for-in': 0,
+
     'import/extensions': [
       'error',
       {
@@ -431,18 +3299,9 @@ module.exports = {
     'jsx-a11y/click-events-have-key-events': 0, // re-enable up for discussion
     'jsx-a11y/mouse-events-have-key-events': 0, // re-enable up for discussion
     'lodash/import-scope': [2, 'member'],
-    'new-cap': 0,
-    'no-bitwise': 0,
-    'no-continue': 0,
-    'no-mixed-operators': 0,
-    'no-multi-assign': 0,
-    'no-multi-spaces': 0,
-    'no-nested-ternary': 0,
+
     'no-prototype-builtins': 0,
-    'no-restricted-properties': 0,
-    'no-shadow': 0, // re-enable up for discussion
-    'padded-blocks': 0,
-    'prefer-arrow-callback': 0,
+
     'prefer-object-spread': 1,
     'prefer-destructuring': ['error', { object: true, array: false }],
     'react/destructuring-assignment': 0, // re-enable up for discussion
@@ -473,10 +3332,10 @@ module.exports = {
     ],
     'react/no-unstable-nested-components': 0,
     'react/jsx-no-useless-fragment': 0,
-    'default-param-last': 0,
+
     'no-import-assign': 0,
     'import/no-relative-packages': 0,
-    'default-case-last': 0,
+
     'no-promise-executor-return': 0,
     'react/no-unused-class-component-methods': 0,
     'react/react-in-jsx-scope': 0,
diff --git a/superset-frontend/package-lock.json b/superset-frontend/package-lock.json
index ad6ac17411..8018b73de1 100644
--- a/superset-frontend/package-lock.json
+++ b/superset-frontend/package-lock.json
@@ -214,7 +214,6 @@
         "css-loader": "^7.1.2",
         "css-minimizer-webpack-plugin": "^7.0.2",
         "eslint": "^8.56.0",
-        "eslint-config-airbnb": "^19.0.4",
         "eslint-config-prettier": "^7.2.0",
         "eslint-import-resolver-alias": "^1.1.2",
         "eslint-import-resolver-typescript": "^3.7.0",
@@ -21934,13 +21933,6 @@
       "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==",
       "license": "ISC"
     },
-    "node_modules/confusing-browser-globals": {
-      "version": "1.0.11",
-      "resolved": "https://registry.npmjs.org/confusing-browser-globals/-/confusing-browser-globals-1.0.11.tgz",
-      "integrity": "sha512-JsPKdmh8ZkmnHxDk55FZ1TqVLvEQTvoByJZRN9jzI0UjxK/QgAmsphz7PGtqgPieQZ/CQcHWXCR7ATDNhGe+YA==",
-      "dev": true,
-      "license": "MIT"
-    },
     "node_modules/connect-history-api-fallback": {
       "version": "2.0.0",
       "resolved": "https://registry.npmjs.org/connect-history-api-fallback/-/connect-history-api-fallback-2.0.0.tgz",
@@ -25385,58 +25377,6 @@
         "url": "https://opencollective.com/eslint"
       }
     },
-    "node_modules/eslint-config-airbnb": {
-      "version": "19.0.4",
-      "resolved": "https://registry.npmjs.org/eslint-config-airbnb/-/eslint-config-airbnb-19.0.4.tgz",
-      "integrity": "sha512-T75QYQVQX57jiNgpF9r1KegMICE94VYwoFQyMGhrvc+lB8YF2E/M/PYDaQe1AJcWaEgqLE+ErXV1Og/+6Vyzew==",
-      "dev": true,
-      "license": "MIT",
-      "dependencies": {
-        "eslint-config-airbnb-base": "^15.0.0",
-        "object.assign": "^4.1.2",
-        "object.entries": "^1.1.5"
-      },
-      "engines": {
-        "node": "^10.12.0 || ^12.22.0 || ^14.17.0 || >=16.0.0"
-      },
-      "peerDependencies": {
-        "eslint": "^7.32.0 || ^8.2.0",
-        "eslint-plugin-import": "^2.25.3",
-        "eslint-plugin-jsx-a11y": "^6.5.1",
-        "eslint-plugin-react": "^7.28.0",
-        "eslint-plugin-react-hooks": "^4.3.0"
-      }
-    },
-    "node_modules/eslint-config-airbnb-base": {
-      "version": "15.0.0",
-      "resolved": "https://registry.npmjs.org/eslint-config-airbnb-base/-/eslint-config-airbnb-base-15.0.0.tgz",
-      "integrity": "sha512-xaX3z4ZZIcFLvh2oUNvcX5oEofXda7giYmuplVxoOg5A7EXJMrUyqRgR+mhDhPK8LZ4PttFOBvCYDbX3sUoUig==",
-      "dev": true,
-      "license": "MIT",
-      "dependencies": {
-        "confusing-browser-globals": "^1.0.10",
-        "object.assign": "^4.1.2",
-        "object.entries": "^1.1.5",
-        "semver": "^6.3.0"
-      },
-      "engines": {
-        "node": "^10.12.0 || >=12.0.0"
-      },
-      "peerDependencies": {
-        "eslint": "^7.32.0 || ^8.2.0",
-        "eslint-plugin-import": "^2.25.2"
-      }
-    },
-    "node_modules/eslint-config-airbnb-base/node_modules/semver": {
-      "version": "6.3.1",
-      "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz",
-      "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==",
-      "dev": true,
-      "license": "ISC",
-      "bin": {
-        "semver": "bin/semver.js"
-      }
-    },
     "node_modules/eslint-config-prettier": {
       "version": "7.2.0",
       "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-7.2.0.tgz",
@@ -61644,7 +61584,7 @@
         "@storybook/types": "8.4.7",
         "@types/react-loadable": "^5.5.11",
         "core-js": "3.40.0",
-        "gh-pages": "^6.2.0",
+        "gh-pages": "^6.3.0",
         "jquery": "^3.7.1",
         "memoize-one": "^5.2.1",
         "react": "^17.0.2",
diff --git a/superset-frontend/package.json b/superset-frontend/package.json
index 3523d013e1..067fcad307 100644
--- a/superset-frontend/package.json
+++ b/superset-frontend/package.json
@@ -282,7 +282,6 @@
     "css-loader": "^7.1.2",
     "css-minimizer-webpack-plugin": "^7.0.2",
     "eslint": "^8.56.0",
-    "eslint-config-airbnb": "^19.0.4",
     "eslint-config-prettier": "^7.2.0",
     "eslint-import-resolver-alias": "^1.1.2",
     "eslint-import-resolver-typescript": "^3.7.0",