shared: source de vérité unique pour les énums d'API

- API_STATUSES inclut 'NO_YAML' (était manquant alors que le type et le
  code l'utilisent)
- ApiType/ApiStatus/ApiConvention dérivés des constantes (typeof X[number])
  -> plus de double maintenance type <-> tableau
- DTO back réutilisent API_CONVENTIONS/API_TYPES dans @IsIn (fin de la
  triple duplication des valeurs)
- front: déclare la dépendance @datacat/shared (workspace:*)
- shared: exports map + métadonnées + README (double build front/back)

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
z3n
2026-06-26 11:54:27 +00:00
parent 1a8bd0b7b4
commit 558bf763e7
7 changed files with 57 additions and 9 deletions

View File

@@ -1,9 +1,9 @@
import { IsString, IsNotEmpty, IsIn, IsOptional, IsUUID, IsInt, Min, IsEmail } from 'class-validator'; import { IsString, IsNotEmpty, IsIn, IsOptional, IsUUID, IsInt, Min, IsEmail } from 'class-validator';
import { Type } from 'class-transformer'; import { Type } from 'class-transformer';
import { ApiType, ApiConvention } from '@datacat/shared'; import { ApiType, ApiConvention, API_CONVENTIONS, API_TYPES } from '@datacat/shared';
export class CreateApiEntryDto { export class CreateApiEntryDto {
@IsIn(['CONSULTER', 'ENREGISTRER', 'ETRE_NOTIFIE']) @IsIn([...API_CONVENTIONS])
convention!: ApiConvention; convention!: ApiConvention;
@IsString() @IsString()
@@ -33,7 +33,7 @@ export class CreateApiEntryDto {
@IsOptional() @IsOptional()
description?: string; description?: string;
@IsIn(['ASYNCAPI', 'OPENAPI']) @IsIn([...API_TYPES])
type!: ApiType; type!: ApiType;
@IsString() @IsString()

View File

@@ -1,9 +1,9 @@
import { IsString, IsOptional, IsUUID, IsIn, IsInt, Min, IsEmail } from 'class-validator'; import { IsString, IsOptional, IsUUID, IsIn, IsInt, Min, IsEmail } from 'class-validator';
import { Type } from 'class-transformer'; import { Type } from 'class-transformer';
import { ApiConvention } from '@datacat/shared'; import { ApiConvention, API_CONVENTIONS } from '@datacat/shared';
export class UpdateApiEntryDto { export class UpdateApiEntryDto {
@IsIn(['CONSULTER', 'ENREGISTRER', 'ETRE_NOTIFIE']) @IsIn([...API_CONVENTIONS])
@IsOptional() @IsOptional()
convention?: ApiConvention; convention?: ApiConvention;

View File

@@ -10,6 +10,7 @@
"lint": "ng lint" "lint": "ng lint"
}, },
"dependencies": { "dependencies": {
"@datacat/shared": "workspace:*",
"@angular/animations": "^19.0.0", "@angular/animations": "^19.0.0",
"@angular/common": "^19.0.0", "@angular/common": "^19.0.0",
"@angular/compiler": "^19.0.0", "@angular/compiler": "^19.0.0",

31
shared/README.md Normal file
View File

@@ -0,0 +1,31 @@
# @datacat/shared
Types et constantes partagés entre le **back** (NestJS) et le **front** (Angular).
## Contenu
- `src/types/` — interfaces et types (`ApiEntry`, `Category`, réponses d'API…).
- `src/schemas/api-entry.schema.ts`**source de vérité** des énumérations
(`API_TYPES`, `API_STATUSES`, `API_CONVENTIONS`). Les types `ApiType` /
`ApiStatus` / `ApiConvention` en sont **dérivés** (`typeof X[number]`), et la
validation back (`@IsIn`) réutilise ces mêmes constantes. Ajouter une valeur
dans le tableau suffit donc à propager type + validation.
## Double build (piège récurrent)
Ce paquet est consommé de **deux façons différentes** :
| Consommateur | Mécanisme | Config |
|--------------|-----------|--------|
| **front** (Angular) | alias TypeScript vers la **source** | `tsconfig.json` (ES2022) + `paths` dans `front-public/tsconfig.json` |
| **back** (NestJS) | paquet **compilé** (`dist/`) en CommonJS | `tsconfig.build.json` (CommonJS) → `dist/` |
⚠️ Le back lit `dist/`, pas la source. Après toute modification de `shared`, il
faut **rebuild** avant que le back voie le changement :
```sh
pnpm --filter @datacat/shared build
# (le docker-compose le fait déjà : voir infra/docker-compose.yml, étape tsc)
```
Le front, lui, voit la source directement (pas de rebuild nécessaire).

View File

@@ -1,9 +1,17 @@
{ {
"name": "@datacat/shared", "name": "@datacat/shared",
"version": "0.1.0", "version": "0.1.0",
"description": "Types et constantes partagés entre le back (NestJS) et le front (Angular) de Datacat.",
"license": "UNLICENSED",
"private": true, "private": true,
"main": "dist/index.js", "main": "dist/index.js",
"types": "dist/index.d.ts", "types": "dist/index.d.ts",
"exports": {
".": {
"types": "./dist/index.d.ts",
"default": "./dist/index.js"
}
},
"scripts": { "scripts": {
"build": "tsc --project tsconfig.build.json" "build": "tsc --project tsconfig.build.json"
} }

View File

@@ -1,3 +1,7 @@
// Source de vérité unique pour les énumérations d'API.
// Les types (`ApiType`, `ApiStatus`, `ApiConvention`) sont dérivés de ces
// constantes dans `../types/api-entry.types.ts`, et la validation back
// (class-validator `@IsIn`) les réutilise — pas de duplication.
export const API_TYPES = ['ASYNCAPI', 'OPENAPI'] as const; export const API_TYPES = ['ASYNCAPI', 'OPENAPI'] as const;
export const API_STATUSES = ['PENDING', 'GENERATED', 'ERROR'] as const; export const API_STATUSES = ['PENDING', 'GENERATED', 'ERROR', 'NO_YAML'] as const;
export const API_CONVENTIONS = ['CONSULTER', 'ENREGISTRER', 'ETRE_NOTIFIE'] as const; export const API_CONVENTIONS = ['CONSULTER', 'ENREGISTRER', 'ETRE_NOTIFIE'] as const;

View File

@@ -1,8 +1,12 @@
export type ApiType = 'ASYNCAPI' | 'OPENAPI'; import { API_TYPES, API_STATUSES, API_CONVENTIONS } from '../schemas/api-entry.schema';
export type ApiStatus = 'PENDING' | 'GENERATED' | 'ERROR' | 'NO_YAML'; // Types dérivés des constantes (source de vérité dans api-entry.schema.ts) :
// ajouter une valeur dans le tableau suffit à mettre à jour le type.
export type ApiType = (typeof API_TYPES)[number];
export type ApiConvention = 'CONSULTER' | 'ENREGISTRER' | 'ETRE_NOTIFIE'; export type ApiStatus = (typeof API_STATUSES)[number];
export type ApiConvention = (typeof API_CONVENTIONS)[number];
export const API_CONVENTION_LABELS: Record<ApiConvention, string> = { export const API_CONVENTION_LABELS: Record<ApiConvention, string> = {
CONSULTER: 'Consulter', CONSULTER: 'Consulter',