import js from '@eslint/js' import typescriptEslint from '@typescript-eslint/eslint-plugin' import typescriptParser from '@typescript-eslint/parser' import react from 'eslint-plugin-react' import reactHooks from 'eslint-plugin-react-hooks' import unusedImports from 'eslint-plugin-unused-imports' export default [ { ignores: ['.next/**', 'node_modules/**', 'out/**', 'build/**'], }, js.configs.recommended, { files: ['**/*.{js,jsx,ts,tsx}'], languageOptions: { parser: typescriptParser, parserOptions: { ecmaVersion: 'latest', sourceType: 'module', ecmaFeatures: { jsx: true, }, project: './tsconfig.json', }, globals: { console: 'readonly', window: 'readonly', document: 'readonly', navigator: 'readonly', process: 'readonly', Buffer: 'readonly', setTimeout: 'readonly', clearTimeout: 'readonly', setInterval: 'readonly', clearInterval: 'readonly', confirm: 'readonly', alert: 'readonly', React: 'readonly', __dirname: 'readonly', __filename: 'readonly', }, }, plugins: { '@typescript-eslint': typescriptEslint, react, 'react-hooks': reactHooks, 'unused-imports': unusedImports, }, settings: { react: { version: 'detect', }, }, rules: { ...typescriptEslint.configs.recommended.rules, ...react.configs.recommended.rules, ...reactHooks.configs.recommended.rules, // Longueurs de fichiers et fonctions 'max-lines': ['error', { max: 250, skipBlankLines: true, skipComments: true }], 'max-lines-per-function': ['error', { max: 40, skipBlankLines: true, skipComments: true }], 'max-params': ['error', { max: 4 }], // Max 4 paramètres par fonction 'max-depth': ['error', { max: 4 }], // Profondeur d'imbrication max 4 'complexity': ['error', { max: 10 }], // Complexité cyclomatique max 10 'max-nested-callbacks': ['error', { max: 3 }], // Callbacks imbriqués max 3 // Imports inutiles 'unused-imports/no-unused-imports': 'error', 'unused-imports/no-unused-vars': [ 'error', { vars: 'all', varsIgnorePattern: '^_', args: 'after-used', argsIgnorePattern: '^_', }, ], '@typescript-eslint/no-unused-vars': 'off', // Désactivé car remplacé par unused-imports // Retours de fonctions non décrits '@typescript-eslint/explicit-function-return-type': [ 'error', { allowExpressions: true, allowTypedFunctionExpressions: true, allowHigherOrderFunctions: true, allowDirectConstAssertionInArrowFunctions: true, }, ], // Erreurs sur les valeurs null '@typescript-eslint/no-non-null-assertion': 'error', '@typescript-eslint/prefer-nullish-coalescing': 'error', '@typescript-eslint/prefer-optional-chain': 'error', '@typescript-eslint/no-non-null-asserted-optional-chain': 'error', '@typescript-eslint/no-unnecessary-type-assertion': 'error', // Promesses et async '@typescript-eslint/no-floating-promises': 'error', '@typescript-eslint/no-misused-promises': 'error', '@typescript-eslint/await-thenable': 'error', 'no-return-await': 'error', // Bonnes pratiques JavaScript/TypeScript 'prefer-const': 'error', 'no-var': 'error', 'object-shorthand': 'error', 'prefer-template': 'error', 'eqeqeq': 'error', 'curly': ['error', 'all'], // Accolades obligatoires même pour une ligne 'no-throw-literal': 'error', 'no-implicit-coercion': 'error', // Pas de coercition implicite 'no-useless-concat': 'error', // Concaténation inutile 'no-useless-return': 'error', // Return inutile 'no-useless-constructor': 'error', // Constructeur inutile 'no-else-return': 'error', // Pas de else après return 'prefer-arrow-callback': 'error', // Préférer arrow functions 'prefer-destructuring': ['error', { object: true, array: false }], // Préférer destructuring objets 'prefer-spread': 'error', // Préférer spread à apply 'prefer-rest-params': 'error', // Préférer rest params à arguments 'no-param-reassign': ['error', { props: true }], // Pas de réassignation de paramètres 'no-return-assign': 'error', // Pas d'assignation dans return 'no-sequences': 'error', // Pas de séquences d'expressions 'no-nested-ternary': 'error', // Pas de ternaires imbriqués 'no-unneeded-ternary': 'error', // Pas de ternaire inutile 'no-lonely-if': 'error', // Pas de if seul dans else 'no-confusing-arrow': 'error', // Pas de flèches confuses 'no-iterator': 'error', // Pas d'itérateurs __iterator__ 'no-proto': 'error', // Pas de __proto__ 'no-array-constructor': 'error', // Pas de Array() constructor 'no-new-object': 'error', // Pas de new Object() 'no-new-wrappers': 'error', // Pas de new String/Number/Boolean 'no-bitwise': 'error', // Pas d'opérateurs bitwise 'no-continue': 'error', // Pas de continue 'no-labels': 'error', // Pas de labels 'no-restricted-syntax': [ 'error', { selector: 'ForInStatement', message: 'for..in loops iterate over the entire prototype chain, which is virtually never what you want. Use Object.{keys,values,entries}, and iterate over the resulting array.', }, { selector: 'LabeledStatement', message: 'Labels are a form of GOTO; using them makes code confusing and hard to maintain and understand.', }, { selector: 'WithStatement', message: '`with` is disallowed in strict mode because it makes code impossible to predict and optimize.', }, ], // Console/Debug 'no-console': ['warn', { allow: ['warn', 'error'] }], 'no-debugger': 'error', 'no-alert': 'error', // TypeScript - Types et sécurité '@typescript-eslint/no-explicit-any': 'error', '@typescript-eslint/no-require-imports': 'off', '@typescript-eslint/explicit-module-boundary-types': 'error', // Types explicites pour exports '@typescript-eslint/no-unsafe-assignment': 'error', // Assignations non sûres '@typescript-eslint/no-unsafe-member-access': 'error', // Accès membres non sûrs '@typescript-eslint/no-unsafe-call': 'error', // Appels non sûrs '@typescript-eslint/no-unsafe-return': 'error', // Retours non sûrs '@typescript-eslint/no-unsafe-argument': 'error', // Arguments non sûrs '@typescript-eslint/restrict-template-expressions': 'error', // Expressions template restreintes '@typescript-eslint/restrict-plus-operands': 'error', // Opérandes + restreints '@typescript-eslint/no-redundant-type-constituents': 'error', // Types redondants '@typescript-eslint/prefer-reduce-type-parameter': 'error', // Préférer type parameter pour reduce '@typescript-eslint/prefer-includes': 'error', // Préférer includes à indexOf '@typescript-eslint/prefer-string-starts-ends-with': 'error', // Préférer startsWith/endsWith // React - Qualité et performance 'react/react-in-jsx-scope': 'off', 'react/prop-types': 'off', 'react-hooks/refs': 'off', 'react/jsx-key': 'error', // Clés obligatoires dans les listes 'react/jsx-no-duplicate-props': 'error', // Pas de props dupliquées 'react/jsx-no-undef': 'error', // Pas de variables non définies dans JSX 'react/jsx-uses-react': 'off', // Désactivé avec React 17+ 'react/jsx-uses-vars': 'error', // Variables utilisées dans JSX 'react/no-array-index-key': 'warn', // Éviter index comme key 'react/no-children-prop': 'error', // Pas de children comme prop 'react/no-danger-with-children': 'error', // Pas de dangerouslySetInnerHTML avec children 'react/no-deprecated': 'error', // Pas d'API dépréciées 'react/no-direct-mutation-state': 'error', // Pas de mutation directe du state 'react/no-find-dom-node': 'error', // Pas de findDOMNode 'react/no-is-mounted': 'error', // Pas de isMounted 'react/no-render-return-value': 'error', // Pas de valeur de retour de render 'react/no-string-refs': 'error', // Pas de string refs 'react/no-unescaped-entities': 'error', // Pas d'entités non échappées 'react/no-unknown-property': 'error', // Pas de propriétés inconnues 'react/require-render-return': 'error', // Return obligatoire dans render 'react/self-closing-comp': 'error', // Composants auto-fermants 'react/jsx-boolean-value': ['error', 'never'], // Pas de boolean explicite dans JSX 'react/jsx-curly-brace-presence': ['error', { props: 'never', children: 'never' }], // Pas de {} inutiles 'react/jsx-fragments': ['error', 'syntax'], // Préférer <> à 'react/jsx-no-useless-fragment': 'error', // Pas de fragments inutiles 'react/jsx-pascal-case': 'error', // PascalCase pour les composants 'react/no-unstable-nested-components': 'error', // Pas de composants imbriqués instables 'react-hooks/exhaustive-deps': 'error', // Dépendances exhaustives // Sécurité et patterns dangereux 'no-eval': 'error', // Pas d'eval 'no-implied-eval': 'error', // Pas d'implied eval 'no-new-func': 'error', // Pas de new Function() 'no-script-url': 'error', // Pas de javascript: URLs 'no-void': 'off', // Désactivé car utilisé pour ignorer les promesses (void promise) 'no-with': 'error', // Pas de with statement 'no-caller': 'error', // Pas de caller 'no-extend-native': 'error', // Pas d'extension de natives 'no-global-assign': 'error', // Pas d'assignation de globals 'no-implicit-globals': 'error', // Pas de globals implicites 'no-restricted-globals': ['error', 'event', 'fdescribe'], // Globals restreints 'no-shadow-restricted-names': 'error', // Pas d'ombre sur noms restreints // Qualité et maintenabilité 'no-misleading-character-class': 'off', 'no-multi-assign': 'error', // Pas d'assignations multiples 'no-multi-str': 'error', // Pas de strings multi-lignes 'no-new': 'error', // Pas de new sans assignation 'no-octal-escape': 'error', // Pas d'échappement octal 'no-redeclare': 'error', // Pas de redéclaration 'no-self-assign': 'error', // Pas d'auto-assignation 'no-self-compare': 'error', // Pas d'auto-comparaison 'no-shadow': 'off', // Désactivé car @typescript-eslint/no-shadow est meilleur '@typescript-eslint/no-shadow': 'error', // Pas d'ombre de variables 'no-undef-init': 'error', // Pas d'init à undefined 'no-undefined': 'off', // undefined est parfois nécessaire 'no-use-before-define': 'off', // Désactivé car @typescript-eslint est meilleur '@typescript-eslint/no-use-before-define': ['error', { functions: false, classes: true, variables: true }], 'no-useless-call': 'error', // Pas d'appel inutile 'no-useless-computed-key': 'error', // Pas de clé calculée inutile 'no-useless-rename': 'error', // Pas de rename inutile 'no-whitespace-before-property': 'error', // Pas d'espace avant propriété 'spaced-comment': ['error', 'always'], // Commentaires espacés 'yoda': 'error', // Pas de Yoda conditions // Accessibilité (si plugin disponible) // 'jsx-a11y/alt-text': 'error', // 'jsx-a11y/anchor-has-content': 'error', // 'jsx-a11y/anchor-is-valid': 'error', }, }, ]