591 lines · 17.7 KB · JavaScript
RawDownload
import { defineConfig, globalIgnores } from 'eslint/config';import js from '@eslint/js';import tseslint from 'typescript-eslint';import reactPlugin from 'eslint-plugin-react';import reactHooks from 'eslint-plugin-react-hooks';import reactRefresh from 'eslint-plugin-react-refresh';import jsxA11y from 'eslint-plugin-jsx-a11y';import tailwindcss from 'eslint-plugin-tailwindcss';import sonarjs from 'eslint-plugin-sonarjs';import simpleImportSort from 'eslint-plugin-simple-import-sort';import importPlugin from 'eslint-plugin-import';import security from 'eslint-plugin-security';import boundaries from 'eslint-plugin-boundaries';import eslintComments from '@eslint-community/eslint-plugin-eslint-comments';import eslintConfigPrettier from 'eslint-config-prettier/flat';import globals from 'globals'; export default defineConfig([  // Global ignores  globalIgnores([    'dist/**',    'dist-electron/**',    'build/**',    'node_modules/**',    '*.config.js',    '*.config.cjs',    '*.config.ts',    'out/**',  ]),   // Base ESLint recommended rules  js.configs.recommended,   // TypeScript-ESLint recommended with type checking + stylistic  // Using recommended (not strict) for a balanced approach  ...tseslint.configs.recommendedTypeChecked,  ...tseslint.configs.stylisticTypeChecked,   // SonarJS - Code quality and bug detection rules  sonarjs.configs.recommended,   // Security - Catch common security mistakes in AI-generated code  security.configs.recommended,   // TypeScript parser options for type-aware linting  {    name: 'typescript-parser-options',    languageOptions: {      parserOptions: {        projectService: true,        tsconfigRootDir: import.meta.dirname,      },    },  },   // Import plugin configuration - Main/Preload (uses tsconfig.node.json)  {    name: 'import-plugin-main',    files: ['src/main/**/*.ts', 'src/preload/**/*.ts'],    plugins: {      import: importPlugin,    },    settings: {      'import/resolver': {        typescript: {          alwaysTryTypes: true,          project: './tsconfig.node.json',        },      },    },    rules: {      'import/no-cycle': ['error', { maxDepth: 3, ignoreExternal: true }],      'import/no-unresolved': 'error',      'import/no-default-export': 'warn',    },  },   // Import plugin configuration - Renderer (uses tsconfig.json)  {    name: 'import-plugin-renderer',    files: ['src/renderer/**/*.{ts,tsx}'],    plugins: {      import: importPlugin,    },    settings: {      'import/resolver': {        typescript: {          alwaysTryTypes: true,          project: './tsconfig.json',        },      },    },    rules: {      'import/no-cycle': ['error', { maxDepth: 3, ignoreExternal: true }],      'import/no-unresolved': 'error',      'import/no-default-export': 'warn',    },  },   // Module boundaries - Enforce Electron three-process architecture  {    name: 'module-boundaries',    files: ['src/**/*.{js,jsx,ts,tsx}'],    plugins: {      boundaries: boundaries,    },    settings: {      'boundaries/elements': [        { type: 'main', pattern: 'src/main/**', mode: 'folder' },        { type: 'preload', pattern: 'src/preload/**', mode: 'folder' },        { type: 'renderer', pattern: 'src/renderer/**', mode: 'folder' },        { type: 'shared', pattern: 'src/shared/**', mode: 'folder' },      ],      'boundaries/ignore': ['**/*.test.ts', '**/*.spec.ts'],    },    rules: {      // Enforce strict module boundaries for Electron architecture      'boundaries/element-types': [        'error',        {          default: 'disallow',          rules: [            // Renderer can only import from renderer and shared            { from: 'renderer', allow: ['renderer', 'shared'] },            // Main process can only import from main and shared            { from: 'main', allow: ['main', 'shared'] },            // Preload can only import from preload and shared            { from: 'preload', allow: ['preload', 'shared'] },            // Shared can import from shared and main (for type re-exports)            { from: 'shared', allow: ['shared', 'main'] },          ],        },      ],      // Prevent importing private modules      'boundaries/no-private': 'error',    },  },   // ESLint Comments  {    name: 'eslint-comments',    files: ['src/**/*.{js,jsx,ts,tsx}'],    plugins: {      '@eslint-community/eslint-comments': eslintComments,    },    rules: {      // Prevents blanket-disabling rules      '@eslint-community/eslint-comments/no-unlimited-disable': 'error',      // Require description for disable comments      '@eslint-community/eslint-comments/require-description': [        'error',        { ignore: [] },      ],      // Re-enable rules after disabling      '@eslint-community/eslint-comments/disable-enable-pair': 'error',      // No duplicate disable comments      '@eslint-community/eslint-comments/no-duplicate-disable': 'error',      // Unused disable comments      '@eslint-community/eslint-comments/no-unused-disable': 'error',    },  },   // Import sorting for all JS/TS files  {    name: 'import-sorting',    files: ['src/**/*.{js,jsx,ts,tsx}'],    plugins: {      'simple-import-sort': simpleImportSort,    },    rules: {      'simple-import-sort/imports': [        'error',        {          groups: [            // Side effect imports (e.g., import './styles.css')            ['^\\u0000'],            // Node.js builtins (fs, path, etc.)            ['^node:'],            // React and related packages            ['^react', '^react-dom'],            // External packages from node_modules            ['^@?\\w'],            // Internal aliases (@/ paths)            ['^@/'],            // Parent imports (../)            ['^\\.\\.(?!/?$)', '^\\.\\./?$'],            // Same-folder imports (./)            ['^\\./(?=.*/)(?!/?$)', '^\\.(?!/?$)', '^\\./?$'],            // Type imports            ['^.+\\u0000$'],          ],        },      ],      'simple-import-sort/exports': 'error',    },  },   // Main process (Electron Node.js)  {    name: 'electron-main',    files: ['src/main/**/*.ts'],    languageOptions: {      globals: {        ...globals.node,      },    },    rules: {      // Allow console in main process for logging      'no-console': 'off',    },  },   // Preload script (Electron bridge)  {    name: 'electron-preload',    files: ['src/preload/**/*.ts'],    languageOptions: {      globals: {        ...globals.node,        ...globals.browser,      },    },  },   // Renderer process (React + A11y + Tailwind)  {    name: 'renderer-react',    files: ['src/renderer/**/*.{ts,tsx}'],    languageOptions: {      globals: {        ...globals.browser,      },    },    plugins: {      react: reactPlugin,      'react-hooks': reactHooks,      'react-refresh': reactRefresh,      'jsx-a11y': jsxA11y,      tailwindcss: tailwindcss,    },    settings: {      react: {        version: 'detect',      },      tailwindcss: {        // Tailwind config path (relative to cwd)        config: 'tailwind.config.js',        // Allow custom classnames (e.g., from CSS modules)        callees: ['classnames', 'clsx', 'cn'],      },    },    rules: {      // React recommended rules      ...reactPlugin.configs.recommended.rules,      // JSX runtime (React 17+) - no need to import React      ...reactPlugin.configs['jsx-runtime'].rules,      // React Hooks rules      ...reactHooks.configs.recommended.rules,      // Accessibility rules (recommended)      ...jsxA11y.configs.recommended.rules,      // Tailwind CSS rules      ...tailwindcss.configs.recommended.rules,       // React Refresh for HMR      'react-refresh/only-export-components': [        'warn',        { allowConstantExport: true },      ],      // Disable prop-types since we use TypeScript      'react/prop-types': 'off',       // A11y rule adjustments for this project      // Allow click handlers on divs when keyboard handlers also present      'jsx-a11y/click-events-have-key-events': 'warn',      'jsx-a11y/no-static-element-interactions': 'warn',      // Allow autofocus for search inputs in desktop apps      'jsx-a11y/no-autofocus': 'off',       // Tailwind CSS rule adjustments      // Warn on class order (Prettier plugin handles sorting)      'tailwindcss/classnames-order': 'off', // Prettier plugin handles this      // Warn on conflicting classes      'tailwindcss/no-contradicting-classname': 'error',      // Warn on custom classnames that don't exist      'tailwindcss/no-custom-classname': 'warn',       // === React-Specific Rules ===      // Consistent component definition      'react/function-component-definition': [        'error',        {          namedComponents: 'arrow-function',          unnamedComponents: 'arrow-function',        },      ],       // Strengthen exhaustive-deps      'react-hooks/exhaustive-deps': 'error',       // Prevent prop spreading      'react/jsx-props-no-spreading': [        'warn',        {          exceptions: ['input', 'button', 'Input', 'Button', 'textarea', 'select'],        },      ],       // Ensure key props      'react/jsx-key': [        'error',        {          checkFragmentShorthand: true,          checkKeyMustBeforeSpread: true,        },      ],       // Prevent unnecessary fragments      'react/jsx-no-useless-fragment': 'warn',       // Self-closing components for consistency      'react/self-closing-comp': [        'error',        {          component: true,          html: true,        },      ],    },  },   // Test files  {    name: 'test-files',    files: ['test/**/*.ts', '**/*.test.ts', '**/*.spec.ts'],    languageOptions: {      globals: {        ...globals.node,      },      parserOptions: {        projectService: false,        project: './tsconfig.test.json',      },    },    rules: {      // Relax TypeScript strict rules for tests      '@typescript-eslint/no-explicit-any': 'off',      '@typescript-eslint/no-non-null-assertion': 'off',      '@typescript-eslint/no-unsafe-assignment': 'off',      '@typescript-eslint/no-unsafe-member-access': 'off',      '@typescript-eslint/no-unsafe-call': 'off',      '@typescript-eslint/no-unsafe-argument': 'off',      '@typescript-eslint/no-unsafe-return': 'off',      '@typescript-eslint/unbound-method': 'off',       // Relax function/export rules for tests      '@typescript-eslint/explicit-function-return-type': 'off',      '@typescript-eslint/explicit-module-boundary-types': 'off',       // Relax naming conventions for tests (allow describe, it, expect patterns)      '@typescript-eslint/naming-convention': 'off',       // Allow magic numbers in tests      'sonarjs/no-hardcoded-ip': 'off',       // Allow floating promises in tests (common with async test helpers)      '@typescript-eslint/no-floating-promises': 'off',    },  },   // Custom rule overrides for all TypeScript files  {    name: 'custom-rules',    files: ['src/**/*.{ts,tsx}'],    rules: {      // === Core JavaScript rules ===      'prefer-const': 'error',      'no-var': 'error',      eqeqeq: ['error', 'always', { null: 'ignore' }],       // === TypeScript Import/Export rules ===      '@typescript-eslint/consistent-type-imports': [        'error',        {          prefer: 'type-imports',          fixStyle: 'inline-type-imports',        },      ],      '@typescript-eslint/consistent-type-exports': [        'error',        { fixMixedExportsWithInlineTypeSpecifier: true },      ],       // === Unused variables ===      '@typescript-eslint/no-unused-vars': [        'error',        {          argsIgnorePattern: '^_',          varsIgnorePattern: '^_',          caughtErrorsIgnorePattern: '^_',        },      ],       // === Relaxed strict rules for practical use ===      // Allow empty functions (useful for callbacks and stubs)      '@typescript-eslint/no-empty-function': 'off',       // Allow numbers/booleans in template literals (common pattern)      '@typescript-eslint/restrict-template-expressions': [        'error',        {          allowNumber: true,          allowBoolean: true,          allowNullish: false,        },      ],       // Allow async functions without await (IPC handlers often need this)      '@typescript-eslint/require-await': 'off',       // Allow floating promises in event handlers (common in Electron)      '@typescript-eslint/no-floating-promises': [        'error',        {          ignoreVoid: true,          ignoreIIFE: true,        },      ],       // Allow promises in places that don't expect them (event handlers)      '@typescript-eslint/no-misused-promises': [        'error',        {          checksVoidReturn: {            attributes: false,            arguments: false,          },        },      ],       // Allow void expression in arrow functions shorthand      '@typescript-eslint/no-confusing-void-expression': [        'error',        {          ignoreArrowShorthand: true,          ignoreVoidOperator: true,        },      ],       // Prefer nullish coalescing but don't error on logical or      '@typescript-eslint/prefer-nullish-coalescing': 'off',       // Allow inferrable types (style preference)      '@typescript-eslint/no-inferrable-types': 'off',       // === Anti-Hallucination Rules ===      // Explicit return types      '@typescript-eslint/explicit-function-return-type': [        'warn',        {          allowExpressions: true,          allowTypedFunctionExpressions: true,          allowHigherOrderFunctions: true,          allowDirectConstAssertionInArrowFunctions: true,        },      ],       // Explicit types for exported functions (minimum requirement)      '@typescript-eslint/explicit-module-boundary-types': 'warn',       // Prevent variable shadowing      '@typescript-eslint/no-shadow': 'error',       // === Naming Conventions ===      '@typescript-eslint/naming-convention': [        'warn',        // Imports can be camelCase or PascalCase (React, ReactDOM, App, etc.)        {          selector: 'import',          format: ['camelCase', 'PascalCase'],        },        // Default: variables and parameters in camelCase        {          selector: 'default',          format: ['camelCase'],          leadingUnderscore: 'allow',        },        // Static readonly class properties can be UPPER_CASE        {          selector: 'classProperty',          modifiers: ['static', 'readonly'],          format: ['camelCase', 'UPPER_CASE'],        },        // Variables: camelCase or UPPER_CASE for constants        {          selector: 'variable',          format: ['camelCase', 'UPPER_CASE', 'PascalCase'],          leadingUnderscore: 'allow',        },        // Functions: camelCase (includes type guards like isXxx, builders like buildXxx)        {

Lines 1–500 of 591.