246 lines
12 KiB
JavaScript
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',
|
|
},
|
|
},
|
|
]
|