diff --git a/frontend/.eslintrc.js b/frontend/.eslintrc.js index ee284ea235..86a1ca3fd9 100644 --- a/frontend/.eslintrc.js +++ b/frontend/.eslintrc.js @@ -1,3 +1,6 @@ +/** + * ESLint Configuration for SigNoz Frontend + */ module.exports = { ignorePatterns: ['src/parser/*.ts', 'scripts/update-registry.js'], env: { @@ -10,11 +13,9 @@ module.exports = { 'eslint:recommended', 'plugin:react/recommended', 'plugin:@typescript-eslint/recommended', - 'plugin:@typescript-eslint/eslint-recommended', + 'plugin:react-hooks/recommended', 'plugin:prettier/recommended', 'plugin:sonarjs/recommended', - 'plugin:import/errors', - 'plugin:import/warnings', 'plugin:react/jsx-runtime', ], parser: '@typescript-eslint/parser', @@ -23,17 +24,21 @@ module.exports = { ecmaFeatures: { jsx: true, }, - ecmaVersion: 12, + ecmaVersion: 2021, sourceType: 'module', }, plugins: [ - 'react', - '@typescript-eslint', - 'simple-import-sort', - 'react-hooks', - 'prettier', - 'jest', - 'jsx-a11y', + 'react', // React-specific rules + '@typescript-eslint', // TypeScript linting + 'simple-import-sort', // Auto-sort imports + 'react-hooks', // React Hooks rules + 'prettier', // Code formatting + 'jest', // Jest test rules + 'jsx-a11y', // Accessibility rules + 'import', // Import/export linting + 'sonarjs', // Code quality/complexity + // TODO: Uncomment after running: yarn add -D eslint-plugin-spellcheck + // 'spellcheck', ], settings: { react: { @@ -47,82 +52,94 @@ module.exports = { }, }, rules: { + // Code quality rules + 'prefer-const': 'error', // Enforces const for variables never reassigned + 'no-var': 'error', // Disallows var, enforces let/const + // TODO: Enable after fixing ~50 violations (auto-fixable) + // 'no-else-return': ['error', { allowElseIf: false }], // Reduces nesting by disallowing else after return + 'no-cond-assign': 'error', // Prevents accidental assignment in conditions (if (x = 1) instead of if (x === 1)) + 'no-debugger': 'error', // Disallows debugger statements in production code + // curly: 'error', // Requires curly braces for all control statements + eqeqeq: ['error', 'always', { null: 'ignore' }], // Enforces === and !== (allows == null for null/undefined check) + // TODO: Enable after fixing ~15 console.log statements + // 'no-console': ['error', { allow: ['warn', 'error'] }], // Warns on console.log, allows console.warn/error + + // TypeScript rules + '@typescript-eslint/explicit-function-return-type': 'error', // Requires explicit return types on functions + '@typescript-eslint/no-unused-vars': 'off', + '@typescript-eslint/no-explicit-any': 'warn', // Warns when using 'any' type (consider upgrading to error) + // TODO: Change to 'error' after fixing ~80 empty function placeholders in providers/contexts + '@typescript-eslint/no-empty-function': 'off', // Disallows empty function bodies + '@typescript-eslint/no-var-requires': 'error', // Disallows require() in TypeScript (use import instead) + '@typescript-eslint/ban-ts-comment': 'off', // Allows @ts-ignore comments (sometimes needed for third-party libs) + 'no-empty-function': 'off', // Disabled in favor of TypeScript version above + + // React rules 'react/jsx-filename-extension': [ 'error', { - extensions: ['.tsx', '.js', '.jsx'], + extensions: ['.tsx', '.jsx'], // Warns if JSX is used in non-.jsx/.tsx files }, ], - 'react/prop-types': 'off', - '@typescript-eslint/explicit-function-return-type': 'error', - '@typescript-eslint/no-var-requires': 'error', - 'react/no-array-index-key': 'error', - 'linebreak-style': [ - 'error', - process.env.platform === 'win32' ? 'windows' : 'unix', - ], - '@typescript-eslint/default-param-last': 'off', + 'react/prop-types': 'off', // Disabled - using TypeScript instead + 'react/jsx-props-no-spreading': 'off', // Allows {...props} spreading (common in HOCs, forms, wrappers) + 'react/no-array-index-key': 'error', // Prevents using array index as key (causes bugs when list changes) - // simple sort error - 'simple-import-sort/imports': 'error', - 'simple-import-sort/exports': 'error', - - // hooks - 'react-hooks/rules-of-hooks': 'error', - 'react-hooks/exhaustive-deps': 'error', - - 'import/prefer-default-export': 'off', - 'import/extensions': [ - 'error', - 'ignorePackages', - { - js: 'never', - jsx: 'never', - ts: 'never', - tsx: 'never', - }, - ], - 'import/no-extraneous-dependencies': ['error', { devDependencies: true }], - // Disabled because TypeScript already handles this check more accurately, - // and the rule has false positives with type-only imports (e.g., TooltipProps from antd) - 'import/named': 'off', - 'no-plusplus': 'off', + // Accessibility rules 'jsx-a11y/label-has-associated-control': [ 'error', { required: { - some: ['nesting', 'id'], + some: ['nesting', 'id'], // Labels must either wrap inputs or use htmlFor/id }, }, ], - 'jsx-a11y/label-has-for': [ - 'error', - { - required: { - some: ['nesting', 'id'], - }, - }, - ], - // Allow empty functions for mocks, default context values, and noop callbacks - '@typescript-eslint/no-empty-function': 'off', - // Allow underscore prefix for intentionally unused variables (e.g., const { id: _id, ...rest } = props) - '@typescript-eslint/no-unused-vars': 'warn', - 'func-style': ['error', 'declaration', { allowArrowFunctions: true }], - 'arrow-body-style': ['error', 'as-needed'], - // eslint rules need to remove - '@typescript-eslint/no-shadow': 'off', - 'import/no-cycle': 'off', - // https://typescript-eslint.io/rules/consistent-return/ check the warning for details - 'consistent-return': 'off', + // React Hooks rules + 'react-hooks/rules-of-hooks': 'error', // Enforces Rules of Hooks (only call at top level) + 'react-hooks/exhaustive-deps': 'warn', // Warns about missing dependencies in useEffect/useMemo/useCallback + + // Import/export rules + 'import/extensions': [ + 'error', + 'ignorePackages', + { + js: 'never', // Disallows .js extension in imports + jsx: 'never', // Disallows .jsx extension in imports + ts: 'never', // Disallows .ts extension in imports + tsx: 'never', // Disallows .tsx extension in imports + }, + ], + 'import/no-extraneous-dependencies': ['error', { devDependencies: true }], // Prevents importing packages not in package.json + // 'import/no-cycle': 'warn', // TODO: Enable later to detect circular dependencies + + // TODO: Enable in separate PR with auto fixes + // // Import sorting rules + // 'simple-import-sort/imports': [ + // 'error', + // { + // groups: [ + // ['^react', '^@?\\w'], // React first, then external packages + // ['^@/'], // Absolute imports with @ alias + // ['^\\u0000'], // Side effect imports (import './file') + // ['^\\.'], // Relative imports + // ['^.+\\.s?css$'], // Style imports + // ], + // }, + // ], + // 'simple-import-sort/exports': 'error', // Auto-sorts exports + + // Prettier - code formatting 'prettier/prettier': [ 'error', {}, { - usePrettierrc: true, + usePrettierrc: true, // Uses .prettierrc.json for formatting rules }, ], - 'react/jsx-props-no-spreading': 'off', + + // SonarJS - code quality and complexity + 'sonarjs/no-duplicate-string': 'off', // Disabled - can be noisy (enable periodically to check) }, overrides: [ { diff --git a/frontend/.prettierrc.json b/frontend/.prettierrc.json index e350d92369..88402cbf7f 100644 --- a/frontend/.prettierrc.json +++ b/frontend/.prettierrc.json @@ -7,7 +7,7 @@ "semi": true, "printWidth": 80, "bracketSpacing": true, - "bracketSameLine": false, + "jsxBracketSameLine": false, "arrowParens": "always", "endOfLine": "lf", "quoteProps": "as-needed",