| name | lint-rules |
| description | Règles ESLint + Prettier partagées de la toolbox Soliguide. À utiliser dès qu'un projet veut être linté ou formaté, qu'on crée un nouveau projet TypeScript/Angular/NestJS, ou que l'utilisateur dit "mets en place le lint", "ajoute eslint", "ajoute prettier", "format fix", "aligne sur soliguide", "configure les règles". Documente les conventions héritées du repo `../../soliguide` (api NestJS + frontend Angular) et fournit les templates flat config ESLint 9 + .prettierrc prêts à copier. |
Règles ESLint + Prettier Soliguide
Cette skill documente les conventions ESLint et Prettier utilisées dans tous les projets de la toolbox. Elles sont alignées sur le repo principal ../../soliguide pour qu'un dev qui passe d'un repo à l'autre garde les mêmes garde-fous.
Toujours répondre en français. Tutoyer l'utilisateur.
Séparation des rôles
- Prettier = formatage pur (indentation, quotes, virgules, retours à la ligne). Pas de débat de style.
- ESLint = logique et erreurs (vars unused, types douteux, accessibilité templates Angular…). Pas de formatage.
eslint-config-prettier = désactive les règles ESLint qui entreraient en conflit avec Prettier. À spread EN DERNIER dans le flat config.
Starter pack — checklist "nouveau projet"
Tout nouveau projet dans projects/* (ou nouveau package dans packages/*) doit contenir 6 fichiers de config pour être totalement autonome :
| Fichier | Racine du projet | Rôle |
|---|
eslint.config.mjs | ⚠️ optionnel | Config ESLint locale (seulement si règles spécifiques, ex: Angular). |
.prettierrc.json | ✅ obligatoire | Config Prettier locale (dup du template, valeurs identiques racine). |
.prettierignore | ✅ obligatoire | Prettier ne remonte PAS aux parents pour .prettierignore. |
package.json scripts | ✅ obligatoire | lint, lint:fix, format, format:fix (voir template plus bas). |
Pourquoi dupliquer .prettierrc.json alors que Prettier remonte aux parents ?
Cohérence + auto-découverte. Un dev qui ouvre un projet doit voir tout de suite comment il est formaté sans devoir remonter. Le coût = zéro (5 lignes copiées).
Pourquoi .prettierignore obligatoire par projet ?
Contrairement à .prettierrc.json, Prettier ne remonte PAS au parent pour trouver un .prettierignore. Sans fichier local, un pnpm --filter <projet> format va scanner tout data/ et pnpm-lock.yaml.
Config racine du monorepo — pour les commandes lancées depuis la racine :
/eslint.config.mjs : couvre tous les projets sauf projects/solihub/ (qui a Angular).
/.prettierrc.json + /.prettierignore : idem, tourne depuis la racine.
/lefthook.yml : hooks pre-commit / pre-push (voir section dédiée plus bas).
Vue d'ensemble
Le repo Soliguide a une config ESLint par package (monorepo Lerna). On reprend les deux configs pertinentes pour la toolbox :
| Origine soliguide | Cible toolbox | Stack |
|---|
packages/api/.eslintrc.js | scripts tsx, API NestJS, libs partagées | TypeScript serveur |
packages/frontend/.eslintrc.js | dashboards Angular | TypeScript + templates HTML |
On n'importe pas la config packages/web-app (Svelte + style fonctionnel fp/*) — pas pertinente.
Format : flat config ESLint 9 (eslint.config.mjs), pas le legacy .eslintrc.js.
Règles "soliguide/api" (TypeScript serveur)
S'applique à : NestJS, scripts tsx, libs partagées.
{
'no-unused-vars': 'off',
'@typescript-eslint/no-unused-vars': [
'error',
{ argsIgnorePattern: '^_', varsIgnorePattern: '^_' },
],
'@typescript-eslint/no-explicit-any': 'warn',
'@typescript-eslint/naming-convention': [
'error',
{ selector: 'enumMember', format: ['UPPER_CASE', 'camelCase'] },
],
}
Pourquoi ces règles ?
no-unused-vars : on désactive la version JS pour utiliser celle TS, qui comprend les types. Le pattern ^_ autorise _unused quand on a besoin de déclarer un paramètre sans s'en servir (callbacks).
no-explicit-any en warn : any est un signal, pas une interdiction. Le warn rappelle qu'il faut souvent mieux typer, sans bloquer le commit.
naming-convention enum : convention soliguide. UPPER_CASE pour les constantes-like (Status.ACTIVE), camelCase pour les variantes plus descriptives (Status.notFound).
Règles "soliguide/frontend" (Angular)
S'applique à : dashboards Angular. Deux blocs distincts car le parser HTML est différent du parser TS.
TypeScript Angular
{
files: ['**/*.ts'],
extends: [...angular.configs.tsRecommended],
processor: angular.processInlineTemplates,
rules: {
'@angular-eslint/directive-selector': [
'error',
{ type: 'attribute', prefix: 'app', style: 'camelCase' },
],
'@angular-eslint/component-selector': [
'error',
{ type: 'element', prefix: 'app', style: 'kebab-case' },
],
},
}
Templates HTML
{
files: ['**/*.html'],
extends: [...angular.configs.templateRecommended],
rules: {
'@angular-eslint/template/button-has-type': 'error',
'@angular-eslint/template/no-duplicate-attributes': 'error',
'@angular-eslint/template/no-distracting-elements': 'error',
'@angular-eslint/template/eqeqeq': 'error',
'@angular-eslint/template/click-events-have-key-events': 'warn',
'@angular-eslint/template/no-call-expression': 'warn',
},
}
Pourquoi ces règles ?
- Préfixe
app : convention Angular standard, partagée avec packages/frontend de soliguide. Évite les collisions avec les composants tiers (Material, etc.).
button-has-type : un <button> sans type est submit par défaut → submit involontaire dans un <form>. Bug classique.
eqeqeq (templates) : force === au lieu de == côté template, comme côté TS.
no-call-expression en warn : appeler une fonction dans un binding template ({{ getStuff() }}) la ré-exécute à chaque change detection. Warn pour qu'on s'en aperçoive sans tout bloquer.
click-events-have-key-events en warn : accessibilité. Idéalement error, mais on a des cas légitimes (mobile-first, target tactile).
Template flat config complet
Pour un nouveau projet qui mêle TS serveur + Angular, copier ça dans eslint.config.mjs à la racine du projet :
import js from "@eslint/js";
import tseslint from "typescript-eslint";
import angular from "angular-eslint";
import eslintConfigPrettier from "eslint-config-prettier";
import globals from "globals";
export default tseslint.config(
{ ignores: ["node_modules/**", "**/dist/**", "**/.angular/**", "data/**"] },
{
files: ["**/*.ts"],
extends: [js.configs.recommended, ...tseslint.configs.recommended],
},
{
files: ["apps/api/**/*.ts", "apps/backend/**/*.ts", "libs/**/*.ts"],
languageOptions: { globals: { ...globals.node } },
rules: {
"no-unused-vars": "off",
"@typescript-eslint/no-unused-vars": [
"error",
{ argsIgnorePattern: "^_", varsIgnorePattern: "^_" },
],
"@typescript-eslint/no-explicit-any": "warn",
"@typescript-eslint/naming-convention": [
"error",
{ selector: "enumMember", format: ["UPPER_CASE", "camelCase"] },
],
},
},
{
files: ["apps/dashboard/**/*.ts"],
extends: [...angular.configs.tsRecommended],
processor: angular.processInlineTemplates,
languageOptions: { globals: { ...globals.browser } },
rules: {
"@angular-eslint/directive-selector": [
"error",
{ type: "attribute", prefix: "app", style: "camelCase" },
],
"@angular-eslint/component-selector": [
"error",
{ type: "element", prefix: "app", style: "kebab-case" },
],
"@typescript-eslint/no-explicit-any": "warn",
"@typescript-eslint/no-unused-vars": [
"warn",
{ argsIgnorePattern: "^_", varsIgnorePattern: "^_" },
],
},
},
{
files: ["apps/dashboard/**/*.html"],
extends: [...angular.configs.templateRecommended],
rules: {
"@angular-eslint/template/button-has-type": "error",
"@angular-eslint/template/no-duplicate-attributes": "error",
"@angular-eslint/template/no-distracting-elements": "error",
"@angular-eslint/template/eqeqeq": "error",
"@angular-eslint/template/click-events-have-key-events": "warn",
"@angular-eslint/template/no-call-expression": "warn",
},
},
eslintConfigPrettier,
);
Dépendances à installer
pnpm add -D eslint @eslint/js typescript-eslint globals prettier eslint-config-prettier
Pour Angular en plus :
pnpm add -D angular-eslint
Version : angular-eslint suit le versionnage d'Angular. Pour Angular 20 → angular-eslint@^20.
Scripts package.json
À ajouter dans package.json du projet :
{
"scripts": {
"lint": "eslint .",
"lint:fix": "eslint . --fix",
"format": "prettier --cache -c .",
"format:fix": "prettier --cache -w ."
}
}
pnpm format → vérifie sans modifier (utile en CI / pre-push).
pnpm format:fix → écrit les corrections.
--cache accélère les runs successifs (cache stocké dans node_modules/.cache/prettier/).
Configuration Prettier
.prettierrc.json
À placer à la racine du projet. Alignée sur les defaults Prettier utilisés par soliguide/packages/api et soliguide/packages/frontend (qui n'ont pas de .prettierrc dédié, donc tournent en defaults = double quotes).
{
"useTabs": false,
"singleQuote": false,
"trailingComma": "all",
"printWidth": 100,
"semi": true
}
Pourquoi ces choix ?
singleQuote: false — defaults Prettier = double quotes. C'est ce qui s'applique à packages/api (NestJS) et packages/frontend (Angular) de soliguide. ⚠️ ne pas confondre avec packages/web-app (Svelte) qui surcharge en singleQuote: true — pas pertinent pour notre stack TS/NestJS/Angular.
trailingComma: 'all' — meilleur git diff (la ligne suivante ne s'affiche pas comme "modifiée"), refacto + safe (ajout/suppression d'un élément ne touche pas la ligne d'avant). C'est le default Prettier 3+.
printWidth: 100 — confortable sur écrans modernes sans être trop large, aligné soliguide web-app/design-system.
semi: true — point-virgules explicites (default Prettier, aligne avec le code TS existant).
.prettierignore
⚠️ Un fichier par projet, obligatoire. Prettier ne remonte pas au parent pour le trouver.
Template standard pour un projet de la toolbox :
# Dépendances et builds
node_modules/
dist/
coverage/
# Données pipeline + articles Notion (non committés)
data/
articles/
# Lockfiles (le lock racine est la source de vérité en monorepo pnpm)
pnpm-lock.yaml
package-lock.json
yarn.lock
Cas particuliers :
- Angular (
solihub/apps/dashboard) : ajouter .angular/
- Astro (
regularizate) : ajouter .astro/
- Prisma (
solihub/apps/backend) : ajouter prisma/migrations/ et src/generated/
Hooks git (lefthook)
Les commits/pushes du repo sont protégés par lefthook — voir /lefthook.yml racine. Trois familles de checks :
| Tag | Commande | Rôle |
|---|
security | talisman, secretlint | Bloque les secrets (AWS, GCP, Slack, tokens…) |
lint | eslint --fix (2× : racine + solihub) | Autofix + restage transparent |
format | prettier --cache --write | Reformattage transparent sur les fichiers staged |
Un nouveau projet est couvert automatiquement — le hook eslint racine linte tout ce qui n'est pas dans projects/solihub/**, le hook prettier couvre toutes les extensions supportées.
Bypass ponctuel : LEFTHOOK=0 git commit … ou git commit --no-verify. À ne faire qu'en connaissance de cause.
Allowlist :
- Faux positif secretlint →
.secretlintignore (racine)
- Faux positif talisman →
.talismanrc (racine, format filename + checksum)
Workflow ESLint + Prettier
L'ordre des étapes compte. Si tu lances ESLint avant Prettier, certaines règles ESLint peuvent réécrire du code que Prettier va re-réécrire derrière.
pnpm format:fix
pnpm lint:fix
pnpm typecheck
En CI :
pnpm format && pnpm lint && pnpm typecheck
Workflow recommandé
- Avant de commit :
pnpm lint. Idéalement, brancher sur un hook husky (à venir, voir CLAUDE.md racine).
- Erreurs vs warnings : viser zéro
error, et faire passer les warn un par un quand on touche un fichier.
- Ajouter une nouvelle règle : la mettre ici dans la skill d'abord avec son pourquoi, puis la propager dans les configs des projets.
- Ignorer un fichier ponctuel :
// eslint-disable-next-line <rule> + un commentaire pourquoi. Pas d'eslint-disable global sur un fichier sans raison documentée.
Référence
Configs source soliguide
- API NestJS :
../../soliguide/packages/api/.eslintrc.js
- Frontend Angular :
../../soliguide/packages/frontend/.eslintrc.js
- Prettier :
../../soliguide/packages/web-app/.prettierrc
Implémentation actuelle dans la toolbox
- Racine du monorepo :
- ESLint :
/eslint.config.mjs (couvre tout sauf solihub)
- Prettier :
/.prettierrc.json + /.prettierignore
- Hooks :
/lefthook.yml
- Scanners de secrets :
/.talismanrc + /.secretlintrc.json + /.secretlintignore
- Scripts racine :
pnpm lint, pnpm lint:all (racine + solihub), pnpm format, pnpm format:fix
- Chaque projet (
packages/common, projects/* sauf solihub) :
.prettierrc.json + .prettierignore locaux (voir starter pack)
- Scripts
lint, lint:fix, format, format:fix dans son package.json
- Solihub (cas spécial Angular + NestJS) :
projects/solihub/eslint.config.mjs (config Angular-aware)
projects/solihub/.prettierrc.json + .prettierignore
- Scripts dédiés qui délèguent à backend + dashboard
Documentation officielle