story-research-zapwall/eslint.config.mjs

246 lines
12 KiB
JavaScript

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.Fragment>
'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',
},
},
]