UNPKG

@aleph/eslint-config

Version:

Aleph's ESLint configuration for JavaScript and TypeScript projects - ESLint 9 flat config

951 lines (935 loc) 32 kB
/** * Aleph ESLint Configuration - ESLint 9 Flat Config * * This configuration is maintained as part of our documentation system. * For detailed explanation of rules and rationale, see: * https://docs.aleph.inc/docs/resources/4devs/standards/code-style-standards * * Based on Airbnb style guide but with minimal external dependencies. * Compatible with ESLint 9+ flat config format. */ const js = require('@eslint/js'); const stylistic = require('@stylistic/eslint-plugin'); const importPlugin = require('eslint-plugin-import'); const reactPlugin = require('eslint-plugin-react'); const reactHooksPlugin = require('eslint-plugin-react-hooks'); const jsxA11yPlugin = require('eslint-plugin-jsx-a11y'); const globals = require('globals'); module.exports = [ // Base JavaScript configuration js.configs.recommended, // Global settings { languageOptions: { ecmaVersion: 'latest', sourceType: 'module', globals: { ...globals.browser, ...globals.node, ...globals.es2022, }, parserOptions: { ecmaFeatures: { jsx: true, }, }, }, plugins: { '@stylistic': stylistic, 'import': importPlugin, 'react': reactPlugin, 'react-hooks': reactHooksPlugin, 'jsx-a11y': jsxA11yPlugin, }, settings: { 'react': { version: 'detect', }, 'import/resolver': { node: { extensions: ['.js', '.jsx', '.ts', '.tsx'], }, }, }, rules: { // === Core JavaScript Rules (Airbnb-based) === // Possible Errors 'no-await-in-loop': 'error', 'no-console': 'warn', 'no-constant-condition': 'error', 'no-constructor-return': 'error', 'no-duplicate-case': 'error', 'no-duplicate-imports': 'error', 'no-empty-character-class': 'error', 'no-ex-assign': 'error', 'no-extra-boolean-cast': 'error', 'no-inner-declarations': 'error', 'no-invalid-regexp': 'error', 'no-irregular-whitespace': 'error', 'no-loss-of-precision': 'error', 'no-misleading-character-class': 'error', 'no-new-symbol': 'error', 'no-obj-calls': 'error', 'no-promise-executor-return': 'error', 'no-prototype-builtins': 'error', 'no-self-assign': 'error', 'no-self-compare': 'error', 'no-setter-return': 'error', 'no-sparse-arrays': 'error', 'no-template-curly-in-string': 'error', 'no-this-before-super': 'error', 'no-undef': 'error', 'no-unexpected-multiline': 'error', 'no-unmodified-loop-condition': 'error', 'no-unreachable': 'error', 'no-unreachable-loop': 'error', 'no-unsafe-finally': 'error', 'no-unsafe-negation': 'error', 'no-unsafe-optional-chaining': 'error', 'no-unused-private-class-members': 'error', 'no-unused-vars': ['error', { argsIgnorePattern: '^_', varsIgnorePattern: '^_', ignoreRestSiblings: true, }], 'no-use-before-define': ['error', { functions: false, classes: true, variables: true, }], 'no-useless-backreference': 'error', 'require-atomic-updates': 'off', 'use-isnan': 'error', 'valid-typeof': 'error', // Best Practices 'accessor-pairs': 'off', 'array-callback-return': ['error', { allowImplicit: true }], 'block-scoped-var': 'error', 'class-methods-use-this': ['error', { exceptMethods: [], }], 'complexity': ['off', 20], 'consistent-return': 'error', 'curly': ['error', 'multi-line'], 'default-case': ['error', { commentPattern: '^no default$' }], 'default-case-last': 'error', 'default-param-last': 'error', 'dot-notation': ['error', { allowKeywords: true }], 'eqeqeq': ['error', 'always', { null: 'ignore' }], 'grouped-accessor-pairs': 'error', 'guard-for-in': 'error', 'max-classes-per-file': ['error', 1], 'no-alert': 'warn', 'no-caller': 'error', 'no-case-declarations': 'error', 'no-constructor-return': 'error', 'no-div-regex': 'off', 'no-else-return': ['error', { allowElseIf: false }], 'no-empty-function': ['error', { allow: [ 'arrowFunctions', 'functions', 'methods', ] }], 'no-empty-pattern': 'error', 'no-eq-null': 'off', 'no-eval': 'error', 'no-extend-native': 'error', 'no-extra-bind': 'error', 'no-extra-label': 'error', 'no-fallthrough': 'error', 'no-floating-decimal': 'error', 'no-global-assign': ['error', { exceptions: [] }], 'no-implicit-coercion': ['off', { boolean: false, number: true, string: true, allow: [], }], 'no-implicit-globals': 'off', 'no-implied-eval': 'error', 'no-invalid-this': 'off', 'no-iterator': 'error', 'no-labels': ['error', { allowLoop: false, allowSwitch: false }], 'no-lone-blocks': 'error', 'no-loop-func': 'error', 'no-magic-numbers': ['off', { ignore: [], ignoreArrayIndexes: true, enforceConst: true, detectObjects: false, }], 'no-multi-spaces': ['error', { ignoreEOLComments: false, }], 'no-multi-str': 'error', 'no-new': 'error', 'no-new-func': 'error', 'no-new-wrappers': 'error', 'no-nonoctal-decimal-escape': 'error', 'no-octal': 'error', 'no-octal-escape': 'error', 'no-param-reassign': ['error', { props: true, ignorePropertyModificationsFor: [ 'acc', // for reduce accumulators 'accumulator', // for reduce accumulators 'e', // for e.returnvalue 'ctx', // for Koa routing 'context', // for Koa routing 'req', // for Express requests 'request', // for Express requests 'res', // for Express responses 'response', // for Express responses '$scope', // for Angular 1 scopes 'staticContext', // for ReactRouter context ] }], 'no-proto': 'error', 'no-redeclare': 'error', 'no-restricted-properties': ['error', { object: 'arguments', property: 'callee', message: 'arguments.callee is deprecated', }, { object: 'global', property: 'isFinite', message: 'Please use Number.isFinite instead', }, { object: 'self', property: 'isFinite', message: 'Please use Number.isFinite instead', }, { object: 'window', property: 'isFinite', message: 'Please use Number.isFinite instead', }, { object: 'global', property: 'isNaN', message: 'Please use Number.isNaN instead', }, { object: 'self', property: 'isNaN', message: 'Please use Number.isNaN instead', }, { object: 'window', property: 'isNaN', message: 'Please use Number.isNaN instead', }, { property: '__defineGetter__', message: 'Please use Object.defineProperty instead.', }, { property: '__defineSetter__', message: 'Please use Object.defineProperty instead.', }, { object: 'Math', property: 'pow', message: 'Use the exponentiation operator (**) instead.', }], 'no-return-assign': ['error', 'always'], 'no-return-await': 'error', 'no-script-url': 'error', 'no-self-compare': 'error', 'no-sequences': 'error', 'no-throw-literal': 'error', 'no-unmodified-loop-condition': 'off', 'no-unused-expressions': ['error', { allowShortCircuit: false, allowTernary: false, allowTaggedTemplates: false, }], 'no-unused-labels': 'error', 'no-useless-call': 'off', 'no-useless-catch': 'error', 'no-useless-concat': 'error', 'no-useless-escape': 'error', 'no-useless-return': 'error', 'no-void': 'error', 'no-warning-comments': ['off', { terms: ['todo', 'fixme', 'xxx'], location: 'start' }], 'no-with': 'error', 'prefer-promise-reject-errors': ['error', { allowEmptyReject: true }], 'prefer-regex-literals': ['error', { disallowRedundantWrapping: true, }], 'radix': 'error', 'require-await': 'off', 'require-unicode-regexp': 'off', 'vars-on-top': 'error', 'wrap-iife': ['error', 'outside', { functionPrototypeMethods: false }], 'yoda': 'error', // Variables 'init-declarations': 'off', 'no-delete-var': 'error', 'no-label-var': 'error', 'no-restricted-globals': [ 'error', { name: 'isFinite', message: 'Use Number.isFinite instead', }, { name: 'isNaN', message: 'Use Number.isNaN instead', }, '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': 'error', 'no-shadow-restricted-names': 'error', 'no-undef-init': 'error', 'no-undefined': 'off', 'no-unused-vars': ['error', { vars: 'all', args: 'after-used', ignoreRestSiblings: true }], // ES6 'arrow-body-style': ['error', 'as-needed', { requireReturnForObjectLiteral: false, }], 'arrow-parens': ['error', 'always'], 'arrow-spacing': ['error', { before: true, after: true }], 'constructor-super': 'error', 'generator-star-spacing': ['error', { before: false, after: true }], 'no-class-assign': 'error', 'no-confusing-arrow': ['error', { allowParens: true, }], 'no-const-assign': 'error', 'no-dupe-class-members': 'error', 'no-duplicate-imports': 'off', // replaced by import/no-duplicates 'no-new-symbol': 'error', 'no-restricted-exports': ['error', { restrictedNamedExports: [ 'default', // use `export default` to provide a default export 'then', // this will cause tons of confusion when your module is dynamically `import()`ed, and will break in most node ESM versions ] }], 'no-restricted-imports': ['off', { paths: [], patterns: [] }], 'no-this-before-super': 'error', 'no-useless-computed-key': 'error', 'no-useless-constructor': 'error', 'no-useless-rename': ['error', { ignoreDestructuring: false, ignoreImport: false, ignoreExport: false, }], 'no-var': 'error', 'object-shorthand': ['error', 'always', { ignoreConstructors: false, avoidQuotes: true, }], 'prefer-arrow-callback': ['error', { allowNamedFunctions: false, allowUnboundThis: true, }], 'prefer-const': ['error', { destructuring: 'any', ignoreReadBeforeAssign: true, }], 'prefer-destructuring': ['error', { VariableDeclarator: { array: false, object: true, }, AssignmentExpression: { array: true, object: false, }, }, { enforceForRenamedProperties: false, }], 'prefer-numeric-literals': 'error', 'prefer-rest-params': 'error', 'prefer-spread': 'error', 'prefer-template': 'error', 'require-yield': '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'], // === Stylistic Rules === '@stylistic/array-bracket-newline': ['off', 'consistent'], '@stylistic/array-bracket-spacing': ['error', 'never'], '@stylistic/array-element-newline': ['off', { multiline: true, minItems: 3 }], '@stylistic/block-spacing': ['error', 'always'], '@stylistic/brace-style': ['error', '1tbs', { allowSingleLine: true }], '@stylistic/comma-dangle': ['error', { arrays: 'always-multiline', objects: 'always-multiline', imports: 'always-multiline', exports: 'always-multiline', functions: 'always-multiline', }], '@stylistic/comma-spacing': ['error', { before: false, after: true }], '@stylistic/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, } }], '@stylistic/computed-property-spacing': ['error', 'never'], '@stylistic/eol-last': ['error', 'always'], '@stylistic/func-call-spacing': ['error', 'never'], '@stylistic/function-call-argument-newline': ['off', 'consistent'], '@stylistic/function-paren-newline': ['error', 'consistent'], '@stylistic/implicit-arrow-linebreak': ['error', 'beside'], '@stylistic/indent': ['error', 2, { SwitchCase: 1, VariableDeclarator: 1, outerIIFEBody: 1, FunctionDeclaration: { parameters: 1, body: 1 }, FunctionExpression: { parameters: 1, body: 1 }, CallExpression: { arguments: 1 }, ArrayExpression: 1, ObjectExpression: 1, ImportDeclaration: 1, flatTernaryExpressions: false, ignoredNodes: ['JSXElement', 'JSXElement > *', 'JSXAttribute', 'JSXIdentifier', 'JSXNamespacedName', 'JSXMemberExpression', 'JSXSpreadAttribute', 'JSXExpressionContainer', 'JSXOpeningElement', 'JSXClosingElement', 'JSXFragment', 'JSXOpeningFragment', 'JSXClosingFragment', 'JSXText', 'JSXEmptyExpression', 'JSXSpreadChild'], ignoreComments: false }], '@stylistic/jsx-quotes': ['off', 'prefer-double'], '@stylistic/key-spacing': ['error', { beforeColon: false, afterColon: true }], '@stylistic/keyword-spacing': ['error', { before: true, after: true, overrides: { return: { after: true }, throw: { after: true }, case: { after: true } } }], '@stylistic/line-comment-position': ['off', { position: 'above', ignorePattern: '', applyDefaultPatterns: true, }], '@stylistic/linebreak-style': ['error', 'unix'], '@stylistic/lines-between-class-members': ['error', 'always', { exceptAfterSingleLine: false }], '@stylistic/lines-around-comment': ['off'], '@stylistic/max-len': ['error', 100, 2, { ignoreUrls: true, ignoreComments: false, ignoreRegExpLiterals: true, ignoreStrings: true, ignoreTemplateLiterals: true, }], '@stylistic/max-statements-per-line': ['off', { max: 1 }], '@stylistic/multiline-comment-style': ['off', 'starred-block'], '@stylistic/multiline-ternary': ['off', 'never'], '@stylistic/new-parens': 'error', '@stylistic/newline-per-chained-call': ['error', { ignoreChainWithDepth: 4 }], '@stylistic/no-confusing-arrow': ['error', { allowParens: true, }], '@stylistic/no-extra-parens': ['off', 'all', { conditionalAssign: true, nestedBinaryExpressions: false, returnAssign: false, ignoreJSX: 'all', enforceForArrowConditionals: false, }], '@stylistic/no-extra-semi': 'error', '@stylistic/no-floating-decimal': 'error', '@stylistic/no-mixed-operators': ['error', { groups: [ ['%', '**'], ['%', '+'], ['%', '-'], ['%', '*'], ['%', '/'], ['/', '*'], ['&', '|', '<<', '>>', '>>>'], ['==', '!=', '===', '!=='], ['&&', '||'], ], allowSamePrecedence: false }], '@stylistic/no-mixed-spaces-and-tabs': 'error', '@stylistic/no-multi-spaces': ['error', { ignoreEOLComments: false, }], '@stylistic/no-multiple-empty-lines': ['error', { max: 1, maxBOF: 0, maxEOF: 0 }], '@stylistic/no-tabs': 'error', '@stylistic/no-trailing-spaces': ['error', { skipBlankLines: false, ignoreComments: false, }], '@stylistic/no-whitespace-before-property': 'error', '@stylistic/nonblock-statement-body-position': ['error', 'beside', { overrides: {} }], '@stylistic/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 }, }], '@stylistic/object-curly-spacing': ['error', 'always'], '@stylistic/object-property-newline': ['error', { allowAllPropertiesOnSameLine: true, }], '@stylistic/one-var-declaration-per-line': ['error', 'always'], '@stylistic/operator-linebreak': ['error', 'before', { overrides: { '=': 'none' } }], '@stylistic/padded-blocks': ['error', { blocks: 'never', classes: 'never', switches: 'never' }, { allowSingleLineBlocks: true }], '@stylistic/padding-line-between-statements': ['off'], '@stylistic/quote-props': ['error', 'as-needed', { keywords: false, unnecessary: true, numbers: false }], '@stylistic/quotes': ['error', 'single', { avoidEscape: true }], '@stylistic/rest-spread-spacing': ['error', 'never'], '@stylistic/semi': ['error', 'always'], '@stylistic/semi-spacing': ['error', { before: false, after: true }], '@stylistic/semi-style': ['error', 'last'], '@stylistic/space-before-blocks': 'error', '@stylistic/space-before-function-paren': ['error', { anonymous: 'always', named: 'never', asyncArrow: 'always' }], '@stylistic/space-in-parens': ['error', 'never'], '@stylistic/space-infix-ops': 'error', '@stylistic/space-unary-ops': ['error', { words: true, nonwords: false, overrides: { }, }], '@stylistic/spaced-comment': ['error', 'always', { line: { exceptions: ['-', '+'], markers: ['=', '!', '/'], }, block: { exceptions: ['-', '+'], markers: ['=', '!', ':', '::'], balanced: true, } }], '@stylistic/switch-colon-spacing': ['error', { after: true, before: false }], '@stylistic/template-curly-spacing': 'error', '@stylistic/template-tag-spacing': ['error', 'never'], '@stylistic/wrap-iife': ['error', 'outside', { functionPrototypeMethods: false }], '@stylistic/wrap-regex': 'off', '@stylistic/yield-star-spacing': ['error', 'after'], // === Import Rules === 'import/export': 'error', 'import/no-duplicates': 'error', 'import/no-named-as-default': 'error', 'import/no-named-as-default-member': 'error', 'import/no-unresolved': ['error', { commonjs: true, caseSensitive: true }], 'import/named': 'error', 'import/namespace': 'off', 'import/default': 'off', 'import/no-restricted-paths': 'off', 'import/no-absolute-path': 'error', 'import/no-dynamic-require': 'error', 'import/no-internal-modules': ['off', { allow: [], }], 'import/no-webpack-loader-syntax': 'error', 'import/no-self-import': 'error', 'import/no-cycle': ['error', { maxDepth: '∞' }], 'import/no-useless-path-segments': ['error', { commonjs: true }], 'import/no-relative-parent-imports': 'off', 'import/no-unused-modules': ['off', { ignoreExports: [], missingExports: true, unusedExports: true, }], 'import/first': 'error', 'import/exports-last': 'off', 'import/no-duplicates': 'error', 'import/no-namespace': 'off', 'import/extensions': ['error', 'ignorePackages', { js: 'never', mjs: 'never', jsx: 'never', ts: 'never', tsx: 'never', }], 'import/order': ['error', { groups: [['builtin', 'external', 'internal']], 'newlines-between': 'always', }], 'import/newline-after-import': 'error', 'import/prefer-default-export': 'error', 'import/max-dependencies': ['off', { max: 10 }], 'import/no-unassigned-import': 'off', 'import/no-named-default': 'error', 'import/no-default-export': 'off', 'import/no-named-export': 'off', 'import/no-anonymous-default-export': ['off', { allowArray: false, allowArrowFunction: false, allowAnonymousClass: false, allowAnonymousFunction: false, allowCallExpression: true, allowNew: false, allowLiteral: false, allowObject: false, }], 'import/group-exports': 'off', 'import/dynamic-import-chunkname': ['off', { importFunctions: [], webpackChunknameFormat: '[0-9a-zA-Z-_/.]+', }], }, }, // React-specific configuration { files: ['**/*.{js,jsx,ts,tsx}'], rules: { // === React Rules === 'react/boolean-prop-naming': ['off', { propTypeNames: ['bool', 'mutuallyExclusiveTrueProps'], rule: '^(is|has)[A-Z]([A-Za-z0-9]?)+', message: '', }], 'react/button-has-type': ['error', { button: true, submit: true, reset: false, }], 'react/default-props-match-prop-types': ['error', { allowRequiredDefaults: false, }], 'react/destructuring-assignment': ['error', 'always'], 'react/display-name': ['off', { ignoreTranspilerName: false }], 'react/forbid-component-props': ['off', { forbid: [] }], 'react/forbid-dom-props': ['off', { forbid: [] }], 'react/forbid-elements': ['off', { forbid: [] }], 'react/forbid-foreign-prop-types': ['warn', { allowInPropTypes: true }], 'react/forbid-prop-types': ['error', { forbid: ['any', 'array', 'object'], checkContextTypes: true, checkChildContextTypes: true, }], 'react/function-component-definition': ['error', { namedComponents: 'function-declaration', unnamedComponents: 'function-expression', }], 'react/no-access-state-in-setstate': 'error', 'react/no-array-index-key': 'error', 'react/no-children-prop': 'error', 'react/no-danger': 'warn', 'react/no-danger-with-children': 'error', 'react/no-deprecated': ['error'], 'react/no-did-mount-set-state': 'off', 'react/no-did-update-set-state': 'error', 'react/no-direct-mutation-state': 'off', 'react/no-find-dom-node': 'error', 'react/no-is-mounted': 'error', 'react/no-multi-comp': 'off', 'react/no-redundant-should-component-update': 'error', 'react/no-render-return-value': 'error', 'react/no-set-state': 'off', 'react/no-typos': 'error', 'react/no-string-refs': 'error', 'react/no-this-in-sfc': 'error', 'react/no-unescaped-entities': 'error', 'react/no-unknown-property': 'error', 'react/no-unsafe': 'off', 'react/no-unused-prop-types': ['error', { customValidators: [], skipShapeProps: true, }], 'react/no-unused-state': 'error', 'react/no-will-update-set-state': 'error', 'react/prefer-es6-class': ['error', 'always'], 'react/prefer-read-only-props': 'off', 'react/prefer-stateless-function': ['error', { ignorePureComponents: true }], 'react/prop-types': ['error', { ignore: [], customValidators: [], skipUndeclared: false, }], 'react/react-in-jsx-scope': 'error', 'react/require-default-props': ['error', { forbidDefaultForRequired: true, }], 'react/require-optimization': ['off', { allowDecorators: [] }], '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/sort-prop-types': ['off', { ignoreCase: true, callbacksLast: false, requiredFirst: false, sortShapeProp: true, }], 'react/state-in-constructor': ['error', 'always'], 'react/static-property-placement': ['error', 'property assignment'], 'react/style-prop-object': 'error', 'react/void-dom-elements-no-children': 'error', // === React Hooks Rules === 'react-hooks/rules-of-hooks': 'error', 'react-hooks/exhaustive-deps': 'warn', // === JSX A11y Rules === 'jsx-a11y/accessible-emoji': 'off', 'jsx-a11y/alt-text': 'error', 'jsx-a11y/anchor-has-content': 'error', 'jsx-a11y/anchor-is-valid': ['error', { components: ['Link'], specialLink: ['hrefLeft', 'hrefRight'], 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/click-events-have-key-events': 'error', 'jsx-a11y/control-has-associated-label': ['off', { 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', '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': ['off', { 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', ], allowExpressionValues: true, }], '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', }, }, // TypeScript-specific overrides { files: ['**/*.{ts,tsx}'], languageOptions: { parser: require('@typescript-eslint/parser'), parserOptions: { ecmaVersion: 'latest', sourceType: 'module', ecmaFeatures: { jsx: true, }, }, }, plugins: { '@typescript-eslint': require('@typescript-eslint/eslint-plugin'), }, rules: { // TypeScript-specific rule overrides 'no-unused-vars': 'off', '@typescript-eslint/no-unused-vars': ['error', { argsIgnorePattern: '^_', varsIgnorePattern: '^_', ignoreRestSiblings: true, }], 'no-use-before-define': 'off', '@typescript-eslint/no-use-before-define': ['error', { functions: false, classes: true, variables: true, }], 'no-shadow': 'off', '@typescript-eslint/no-shadow': 'error', 'no-redeclare': 'off', '@typescript-eslint/no-redeclare': 'error', }, }, ];