Some checks are pending
Go Benchmark / Performance Regression Check (push) Waiting to run
Cerberus Integration / Cerberus Security Stack Integration (push) Waiting to run
Upload Coverage to Codecov / Backend Codecov Upload (push) Waiting to run
Upload Coverage to Codecov / Frontend Codecov Upload (push) Waiting to run
CodeQL - Analyze / CodeQL analysis (go) (push) Waiting to run
CodeQL - Analyze / CodeQL analysis (javascript-typescript) (push) Waiting to run
CrowdSec Integration / CrowdSec Bouncer Integration (push) Waiting to run
Docker Build, Publish & Test / build-and-push (push) Waiting to run
Docker Build, Publish & Test / Security Scan PR Image (push) Blocked by required conditions
Quality Checks / Auth Route Protection Contract (push) Waiting to run
Quality Checks / Codecov Trigger/Comment Parity Guard (push) Waiting to run
Quality Checks / Backend (Go) (push) Waiting to run
Quality Checks / Frontend (React) (push) Waiting to run
Rate Limit integration / Rate Limiting Integration (push) Waiting to run
Security Scan (PR) / Trivy Binary Scan (push) Waiting to run
Supply Chain Verification (PR) / Verify Supply Chain (push) Waiting to run
WAF integration / Coraza WAF Integration (push) Waiting to run
198 lines
6.9 KiB
JavaScript
Executable File
198 lines
6.9 KiB
JavaScript
Executable File
import js from '@eslint/js';
|
|
import tseslint from 'typescript-eslint';
|
|
import reactRefresh from 'eslint-plugin-react-refresh';
|
|
import reactHooks from 'eslint-plugin-react-hooks';
|
|
import jsxA11y from 'eslint-plugin-jsx-a11y';
|
|
import importX from 'eslint-plugin-import-x';
|
|
import unusedImports from 'eslint-plugin-unused-imports';
|
|
import promise from 'eslint-plugin-promise';
|
|
import unicorn from 'eslint-plugin-unicorn';
|
|
import sonarjs from 'eslint-plugin-sonarjs';
|
|
import security from 'eslint-plugin-security';
|
|
import noUnsanitized from 'eslint-plugin-no-unsanitized';
|
|
import reactCompiler from 'eslint-plugin-react-compiler';
|
|
import testingLibrary from 'eslint-plugin-testing-library';
|
|
import vitest from '@vitest/eslint-plugin';
|
|
import css from '@eslint/css';
|
|
import json from '@eslint/json';
|
|
import markdown from '@eslint/markdown';
|
|
|
|
export default tseslint.config(
|
|
{ ignores: ['dist/**', 'node_modules/**', 'coverage/**'] },
|
|
|
|
// ── Base configs (scoped to JS/TS to avoid breaking non-JS parsers) ──
|
|
{ ...js.configs.recommended, files: ['**/*.{ts,tsx,js,jsx,mjs,cjs}'] },
|
|
...tseslint.configs.recommended.map(config => ({
|
|
...config,
|
|
files: config.files ?? ['**/*.{ts,tsx,js,jsx,mjs,cjs}'],
|
|
})),
|
|
|
|
// ── TypeScript + React (main source files) ────────────────────────────
|
|
{
|
|
files: ['**/*.{ts,tsx}'],
|
|
plugins: {
|
|
'react-refresh': reactRefresh,
|
|
'react-hooks': reactHooks,
|
|
'jsx-a11y': jsxA11y,
|
|
'import-x': importX,
|
|
'unused-imports': unusedImports,
|
|
promise,
|
|
unicorn,
|
|
sonarjs,
|
|
security,
|
|
'no-unsanitized': noUnsanitized,
|
|
'react-compiler': reactCompiler,
|
|
},
|
|
settings: {
|
|
'import-x/resolver': {
|
|
typescript: true,
|
|
node: true,
|
|
},
|
|
},
|
|
rules: {
|
|
// ── React ──
|
|
'react-refresh/only-export-components': 'warn',
|
|
'react-hooks/rules-of-hooks': 'error',
|
|
'react-hooks/exhaustive-deps': 'warn',
|
|
'react-compiler/react-compiler': 'warn',
|
|
|
|
// ── TypeScript ──
|
|
'@typescript-eslint/no-explicit-any': 'warn',
|
|
'@typescript-eslint/no-unused-vars': 'off', // handled by unused-imports
|
|
'@typescript-eslint/consistent-type-imports': [
|
|
'warn',
|
|
{ prefer: 'type-imports', fixStyle: 'inline-type-imports' },
|
|
],
|
|
|
|
// ── Unused imports ──
|
|
'unused-imports/no-unused-imports': 'error',
|
|
'unused-imports/no-unused-vars': [
|
|
'warn',
|
|
{
|
|
vars: 'all',
|
|
varsIgnorePattern: '^_',
|
|
args: 'after-used',
|
|
argsIgnorePattern: '^_',
|
|
},
|
|
],
|
|
|
|
// ── Import organization ──
|
|
'import-x/order': [
|
|
'warn',
|
|
{
|
|
groups: [
|
|
'builtin',
|
|
'external',
|
|
'internal',
|
|
['parent', 'sibling', 'index'],
|
|
'type',
|
|
],
|
|
'newlines-between': 'always',
|
|
alphabetize: { order: 'asc', caseInsensitive: true },
|
|
},
|
|
],
|
|
'import-x/no-duplicates': ['warn', { 'prefer-inline': true }],
|
|
'import-x/no-cycle': ['warn', { maxDepth: 4 }],
|
|
'import-x/no-self-import': 'error',
|
|
|
|
// ── Accessibility ──
|
|
...jsxA11y.flatConfigs.recommended.rules,
|
|
'jsx-a11y/label-has-associated-control': 'warn',
|
|
'jsx-a11y/no-static-element-interactions': 'warn',
|
|
'jsx-a11y/click-events-have-key-events': 'warn',
|
|
'jsx-a11y/no-autofocus': 'warn',
|
|
'jsx-a11y/role-has-required-aria-props': 'warn',
|
|
'jsx-a11y/heading-has-content': 'warn',
|
|
|
|
// ── Promises ──
|
|
'promise/always-return': 'warn',
|
|
'promise/no-return-wrap': 'error',
|
|
'promise/catch-or-return': 'warn',
|
|
'promise/no-nesting': 'warn',
|
|
|
|
// ── Unicorn (cherry-picked) ──
|
|
'unicorn/prefer-node-protocol': 'error',
|
|
'unicorn/no-array-for-each': 'warn',
|
|
'unicorn/prefer-array-find': 'warn',
|
|
'unicorn/prefer-array-flat-map': 'warn',
|
|
'unicorn/prefer-array-some': 'warn',
|
|
'unicorn/prefer-includes': 'warn',
|
|
'unicorn/prefer-string-starts-ends-with': 'warn',
|
|
'unicorn/no-useless-spread': 'warn',
|
|
'unicorn/no-useless-undefined': 'warn',
|
|
'unicorn/prefer-optional-catch-binding': 'warn',
|
|
'unicorn/prefer-ternary': ['warn', 'only-single-line'],
|
|
'unicorn/no-lonely-if': 'warn',
|
|
|
|
// ── Sonar (code smells) ──
|
|
'sonarjs/no-identical-functions': 'warn',
|
|
'sonarjs/no-duplicated-branches': 'warn',
|
|
'sonarjs/no-collapsible-if': 'warn',
|
|
'sonarjs/prefer-immediate-return': 'warn',
|
|
|
|
// ── Security ──
|
|
'security/detect-object-injection': 'off', // too noisy for frontend
|
|
'security/detect-non-literal-regexp': 'warn',
|
|
'security/detect-unsafe-regex': 'warn',
|
|
'no-unsanitized/method': 'error',
|
|
'no-unsanitized/property': 'error',
|
|
},
|
|
},
|
|
|
|
// ── Test files ────────────────────────────────────────────────────────
|
|
{
|
|
files: ['**/*.test.{ts,tsx}', '**/*.spec.{ts,tsx}', '**/__tests__/**/*.{ts,tsx}'],
|
|
plugins: {
|
|
'testing-library': testingLibrary,
|
|
vitest,
|
|
},
|
|
rules: {
|
|
...testingLibrary.configs['flat/react'].rules,
|
|
...vitest.configs.recommended.rules,
|
|
// relax rules that are too noisy for the existing test suite
|
|
'@typescript-eslint/no-explicit-any': 'off',
|
|
'sonarjs/no-identical-functions': 'off',
|
|
'testing-library/no-node-access': 'warn',
|
|
'testing-library/prefer-find-by': 'warn',
|
|
'testing-library/no-container': 'warn',
|
|
'testing-library/no-wait-for-multiple-assertions': 'warn',
|
|
'testing-library/no-unnecessary-act': 'warn',
|
|
'testing-library/no-manual-cleanup': 'warn',
|
|
'testing-library/render-result-naming-convention': 'warn',
|
|
'vitest/expect-expect': 'warn',
|
|
},
|
|
},
|
|
|
|
// ── CSS files ─────────────────────────────────────────────────────────
|
|
{
|
|
files: ['**/*.css'],
|
|
language: 'css/css',
|
|
plugins: { css },
|
|
rules: {
|
|
'css/no-duplicate-imports': 'error',
|
|
'css/no-empty-blocks': 'warn',
|
|
},
|
|
},
|
|
|
|
// ── JSON files ────────────────────────────────────────────────────────
|
|
{
|
|
files: ['**/*.json'],
|
|
ignores: ['package-lock.json', 'tsconfig*.json'],
|
|
language: 'json/json',
|
|
plugins: { json },
|
|
rules: {
|
|
'json/no-duplicate-keys': 'error',
|
|
},
|
|
},
|
|
|
|
// ── Markdown files ────────────────────────────────────────────────────
|
|
{
|
|
files: ['**/*.md'],
|
|
plugins: { markdown },
|
|
language: 'markdown/gfm',
|
|
rules: {
|
|
'markdown/no-html': 'off',
|
|
},
|
|
}
|
|
);
|