opticore-feature-component 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md ADDED
@@ -0,0 +1,697 @@
1
+ # opticore-feature-component
2
+
3
+ OptiCore Feature component est un package qui permet via l'interaction d'une CLI de générer des features dans un projet **OptiCoreJs**.
4
+ Trois modes de scaffolding sont proposés : Simple Component, Clean Architecture pas à pas, et Full Clean Architecture.
5
+
6
+ [![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](https://opensource.org/licenses/MIT)
7
+ [![npm version](https://img.shields.io/npm/v/opticore-feature-component.svg)](https://www.npmjs.com/package/opticore-feature-component)
8
+
9
+ ---
10
+
11
+ ## Table des matières
12
+
13
+ - [Prérequis](#prérequis)
14
+ - [Installation](#installation)
15
+ - [Lancer le CLI](#lancer-le-cli)
16
+ - [Flux interactif global](#flux-interactif-global)
17
+ - [Option 1 — Simple Component](#option-1--simple-component)
18
+ - [Option 2 — CLEAN Architecture by step](#option-2--clean-architecture-by-step)
19
+ - [Option 3 — Full CLEAN Architecture component](#option-3--full-clean-architecture-component)
20
+ - [Règles de nommage](#règles-de-nommage)
21
+ - [Enregistrement automatique du router](#enregistrement-automatique-du-router)
22
+ - [Contribuer](#contribuer)
23
+
24
+ ---
25
+
26
+ ## Prérequis
27
+
28
+ - **Node.js** ≥ 18
29
+ - **TypeScript** ≥ 5
30
+ - Un projet qui expose le répertoire `src/features/` à la racine (le CLI y crée les features)
31
+
32
+ ```
33
+ mon-projet > src > app > router > register.router.ts
34
+ ```
35
+
36
+ Le fichier `register.router.ts` se met automatiquement à jour lors de la création du router de la feature
37
+
38
+ > Si le dossier `features` est absent au lancement du server, le CLI affiche une erreur et s'arrête.
39
+
40
+ ---
41
+
42
+ ## Installation
43
+
44
+ ### En tant que dépendance de développement (recommandé)
45
+
46
+ ```bash
47
+ npm install --save-dev opticore-feature-component
48
+ # ou
49
+ yarn add -D opticore-feature-component
50
+ ```
51
+
52
+ ### Globalement
53
+
54
+ ```bash
55
+ npm install -g opticore-feature-component
56
+ ```
57
+
58
+ ### Depuis les sources (monorepo)
59
+
60
+ ```bash
61
+ # depuis la racine du package
62
+ npm install
63
+ npm run build
64
+ ```
65
+
66
+ ---
67
+
68
+ ## Lancer le CLI
69
+
70
+ ### Avec `npx` ou `npm` (sans installation globale)
71
+
72
+ ```bash
73
+ npx opticore-feature-component
74
+ ```
75
+ ```bash
76
+ npm exec opticore-feature-component
77
+ ```
78
+
79
+ ### Via le script `package.json` du projet (recommandé)
80
+
81
+ Ajoutez un script dans le `package.json` de votre projet :
82
+
83
+ ```json
84
+ {
85
+ "scripts": {
86
+ "feature": "opticore-feature-component"
87
+ }
88
+ }
89
+ ```
90
+
91
+ Puis lancez :
92
+
93
+ ```bash
94
+ npm run feature
95
+ # ou
96
+ yarn feature
97
+ ```
98
+
99
+ ### Installation globale
100
+
101
+ ```bash
102
+ opticore-feature-component
103
+ ```
104
+
105
+ ---
106
+
107
+ ## Flux interactif global
108
+
109
+ À chaque lancement, le CLI suit toujours ce flux en 3 étapes avant de proposer les options :
110
+
111
+ ```
112
+ ╭────────────────────────────────────────────────────╮
113
+ │ │
114
+ │ Welcome to Feature Component CLI │
115
+ │ │
116
+ ╰────────────────────────────────────────────────────╯
117
+
118
+ ◆ Please choose the creation principle for your feature :
119
+ │ ● OptiCoreJs CLEAN Module (recommended)
120
+ │ ○ Custom feature
121
+
122
+
123
+ ◆ Enter feature's name :
124
+ │ login
125
+
126
+
127
+ ◆ Choose a type of component :
128
+ │ ○ Simple component
129
+ │ ○ CLEAN Architecture component by step
130
+ │ ● Full CLEAN Architecture component (default)
131
+
132
+ ```
133
+
134
+ **Étape 1 — Principe de création**
135
+
136
+ | Choix | Comportement |
137
+ |---|---|
138
+ | `OptiCoreJs CLEAN Module` | Active le scaffolding automatisé — continue vers l'étape 2 |
139
+ | `Custom feature` | Affiche un message d'information et quitte (création manuelle) |
140
+
141
+ **Étape 2 — Nom de la feature**
142
+
143
+ Le nom doit respecter la règle : `^[a-z][A-Za-z]+$`
144
+ → camelCase, commence par une minuscule, minimum 2 caractères.
145
+
146
+ ```
147
+ ✅ userProfile
148
+ ✅ productOrder
149
+ ✅ authToken
150
+ ❌ UserProfile (commence par une majuscule)
151
+ ❌ user_profile (underscore interdit)
152
+ ❌ user (1 seul caractère après la première lettre)
153
+ ```
154
+
155
+ **Étape 3 — Type de composant** → voir les sections suivantes.
156
+
157
+ > Appuyer sur **Ctrl+C** à n'importe quelle étape annule l'opération et supprime
158
+ > les répertoires éventuellement créés.
159
+
160
+ ---
161
+
162
+ ## Option 1 — Simple Component
163
+
164
+ Structure plate et pragmatique. Idéal pour des features légères sans couche de domaine.
165
+
166
+ ### Ce qui est généré
167
+
168
+ ```
169
+ src/features/<featureName>/
170
+ ├── models/
171
+ │ └── <featureName>.model.ts
172
+ ├── repositories/
173
+ │ └── <featureName>.repository.ts
174
+ ├── services/
175
+ │ └── <featureName>.service.ts
176
+ ├── controllers/
177
+ │ └── <featureName>.controller.ts
178
+ └── routes/
179
+ ├── <featureName>.router.handler.ts
180
+ └── <featureName>.router.ts
181
+ ```
182
+
183
+ ### Exemple — feature `order`
184
+
185
+ ```
186
+ src/features/order/
187
+ ├── models/
188
+ │ └── order.model.ts
189
+ ├── repositories/
190
+ │ └── order.repository.ts
191
+ ├── services/
192
+ │ └── order.service.ts
193
+ ├── controllers/
194
+ │ └── order.controller.ts
195
+ └── routes/
196
+ ├── order.router.handler.ts
197
+ └── order.router.ts
198
+ ```
199
+
200
+ Le CLI demande si vous souhaitez des méthodes dans le controller :
201
+
202
+ ```
203
+ ◆ Do you want to add methods to the controller?
204
+ │ ● Yes ○ No
205
+
206
+
207
+ ◆ Enter the method names (comma separated):
208
+ │ create, findAll, findById, update, delete
209
+
210
+ ```
211
+
212
+ ### Contenu généré — `order.service.ts`
213
+
214
+ ```typescript
215
+ import { OrderRepository } from "../repositories/order.repository";
216
+ import { OrderModel } from "../models/order.model";
217
+
218
+ export class OrderService {
219
+ private readonly repository: OrderRepository;
220
+
221
+ constructor() {
222
+ this.repository = new OrderRepository();
223
+ }
224
+
225
+ async findAll(): Promise<OrderModel[]> {
226
+ return this.repository.findAll();
227
+ }
228
+
229
+ async findById(id: string): Promise<OrderModel | null> {
230
+ return this.repository.findById(id);
231
+ }
232
+
233
+ async create(data: Record<string, unknown>): Promise<OrderModel> {
234
+ const model = new OrderModel(String(Date.now()));
235
+ // TODO: Map data fields onto model
236
+ return this.repository.create(model);
237
+ }
238
+
239
+ async update(id: string, data: Record<string, unknown>): Promise<OrderModel | null> {
240
+ const existing = await this.repository.findById(id);
241
+ if (!existing) return null;
242
+ // TODO: Apply data fields onto existing model
243
+ return this.repository.update(existing);
244
+ }
245
+
246
+ async delete(id: string): Promise<boolean> {
247
+ return this.repository.delete(id);
248
+ }
249
+ }
250
+ ```
251
+
252
+ ### Contenu généré — `order.controller.ts` (méthodes `create, findAll`)
253
+
254
+ ```typescript
255
+ import { Request, Response } from "express";
256
+ import { ResponseHandler, HttpStatusCode, IResponseHandlerSuccessData } from "opticore-http-response";
257
+ import { OrderService } from "../services/order.service";
258
+
259
+ export class OrderController {
260
+ private static buildService(): OrderService {
261
+ return new OrderService();
262
+ }
263
+
264
+ static async create(req: Request, res: Response): Promise<IResponseHandlerSuccessData | ReturnType<typeof ResponseHandler.error>> {
265
+ try {
266
+ const service = OrderController.buildService();
267
+ const result = await service.create(req.body);
268
+ return ResponseHandler.success(result, "created", HttpStatusCode.CREATED);
269
+ } catch (error) {
270
+ return OrderController.handleError(error);
271
+ }
272
+ }
273
+
274
+ static async findAll(req: Request, res: Response): Promise<IResponseHandlerSuccessData | ReturnType<typeof ResponseHandler.error>> {
275
+ try {
276
+ const service = OrderController.buildService();
277
+ const results = await service.findAll();
278
+ return ResponseHandler.success(results, "success", HttpStatusCode.OK);
279
+ } catch (error) {
280
+ return OrderController.handleError(error);
281
+ }
282
+ }
283
+
284
+ private static handleError(error: unknown) {
285
+ const message = error instanceof Error ? error.message : "Internal server error";
286
+ return ResponseHandler.error(message, HttpStatusCode.INTERNAL_SERVER_ERROR);
287
+ }
288
+ }
289
+ ```
290
+
291
+ ### Mapping HTTP automatique des méthodes
292
+
293
+ Le CLI déduit le verbe et le chemin HTTP à partir du nom de méthode :
294
+
295
+ | Nom de méthode (exemples) | Verbe | Chemin |
296
+ |---|---|---|
297
+ | `findAll`, `getAll` | `GET` | `/<featureName>` |
298
+ | `findById`, `getById`, `getOne` | `GET` | `/<featureName>/:id` |
299
+ | `create`, `add` | `POST` | `/<featureName>` |
300
+ | `update`, `edit` | `PUT` | `/<featureName>/:id` |
301
+ | `delete`, `remove` | `DELETE` | `/<featureName>/:id` |
302
+ | tout autre nom | `GET` | `/<featureName>/<methodName>` |
303
+
304
+ ---
305
+
306
+ ## Option 2 — CLEAN Architecture by step
307
+
308
+ Mode interactif file-par-file. Le CLI propose chaque composant un à un et ne crée que ceux que vous confirmez. **Tous les fichiers créés sont vides** — aucun template n'est injecté.
309
+
310
+ ### Déroulement
311
+
312
+ ```
313
+ ── Domain ──────────────────────────────────────────────────────
314
+
315
+ ◆ Entity → payment.entity.ts
316
+ │ ○ Yes ● No
317
+
318
+
319
+ ◆ Event → payment.event.ts
320
+ │ ● Yes ○ No
321
+
322
+ ✅ Created: src/features/payment/domain/events/payment.event.ts
323
+
324
+ ◆ Exception → payment.exception.ts
325
+ │ ○ Yes ● No
326
+
327
+
328
+ ── Application ─────────────────────────────────────────────────
329
+
330
+ ◆ Repo Interface → payment.repository.interface.ts
331
+ │ ● Yes ○ No
332
+
333
+ ✅ Created: src/features/payment/application/ports/repositories/payment.repository.interface.ts
334
+
335
+ ◆ Presenter Port → payment.presenter.interface.ts
336
+ │ ○ Yes ● No
337
+
338
+
339
+ ◆ Service Port → payment.service.ts
340
+ │ ○ Yes ● No
341
+
342
+
343
+ ◆ DTO → payment.dto.ts
344
+ │ ● Yes ○ No
345
+
346
+ ✅ Created: src/features/payment/application/dtos/payment.dto.ts
347
+
348
+ ◆ Use Case → payment.usecase.ts
349
+ │ ● Yes ○ No
350
+
351
+ ✅ Created: src/features/payment/application/use-cases/payment.usecase.ts
352
+
353
+ ── Infrastructure ──────────────────────────────────────────────
354
+
355
+ ◆ Repo Impl → payment.repository.ts
356
+ │ ● Yes ○ No
357
+
358
+ ✅ Created: src/features/payment/infrastructure/adapters/repositories/payment.repository.ts
359
+
360
+ ◆ Presenter Impl → payment.presenter.ts
361
+ │ ○ Yes ● No
362
+
363
+
364
+ ◆ Controller → payment.controller.ts
365
+ │ ● Yes ○ No
366
+
367
+ ✅ Created: src/features/payment/infrastructure/adapters/controllers/payment.controller.ts
368
+
369
+ ◆ Router Handler → payment.router.handler.ts
370
+ │ ○ Yes ● No
371
+
372
+
373
+ ◆ Router → payment.router.ts
374
+ │ ○ Yes ● No
375
+
376
+
377
+ 🎉 Feature "payment" — 5 file(s) created step by step.
378
+ ```
379
+
380
+ ### Résultat pour l'exemple ci-dessus
381
+
382
+ ```
383
+ src/features/payment/
384
+ ├── application/
385
+ │ ├── dtos/
386
+ │ │ └── payment.dto.ts ← vide
387
+ │ ├── ports/
388
+ │ │ └── repositories/
389
+ │ │ └── payment.repository.interface.ts ← vide
390
+ │ └── use-cases/
391
+ │ └── payment.usecase.ts ← vide
392
+ └── infrastructure/
393
+ └── adapters/
394
+ ├── controllers/
395
+ │ └── payment.controller.ts ← vide
396
+ └── repositories/
397
+ └── payment.repository.ts ← vide
398
+ ```
399
+
400
+ > **Les répertoires ne sont créés que pour les fichiers confirmés.**
401
+ > Si aucun fichier n'est sélectionné, rien n'est créé sur le disque.
402
+
403
+ ### Composants disponibles
404
+
405
+ | Groupe | Label affiché | Fichier créé | Répertoire |
406
+ |---|---|---|---|
407
+ | Domain | Entity | `<n>.entity.ts` | `domain/entities/` |
408
+ | Domain | Event | `<n>.event.ts` | `domain/events/` |
409
+ | Domain | Exception | `<n>.exception.ts` | `domain/exceptions/` |
410
+ | Application | Repo Interface | `<n>.repository.interface.ts` | `application/ports/repositories/` |
411
+ | Application | Presenter Port | `<n>.presenter.interface.ts` | `application/ports/presenters/` |
412
+ | Application | Service Port | `<n>.service.ts` | `application/ports/services/` |
413
+ | Application | DTO | `<n>.dto.ts` | `application/dtos/` |
414
+ | Application | Use Case | `<n>.usecase.ts` | `application/use-cases/` |
415
+ | Infrastructure | Repo Impl | `<n>.repository.ts` | `infrastructure/adapters/repositories/` |
416
+ | Infrastructure | Presenter Impl | `<n>.presenter.ts` | `infrastructure/adapters/presenters/` |
417
+ | Infrastructure | Controller | `<n>.controller.ts` | `infrastructure/adapters/controllers/` |
418
+ | Infrastructure | Router Handler | `<n>.router.handler.ts` | `infrastructure/routes/` |
419
+ | Infrastructure | Router | `<n>.router.ts` | `infrastructure/routes/` |
420
+
421
+ ---
422
+
423
+ ## Option 3 — Full CLEAN Architecture component
424
+
425
+ Génère l'intégralité de la structure Clean Architecture en une seule commande. Chaque fichier est pré-rempli avec un template TypeScript fonctionnel et prêt à être adapté.
426
+
427
+ ### Ce qui est généré
428
+
429
+ ```
430
+ src/features/<featureName>/
431
+ ├── domain/
432
+ │ ├── entities/
433
+ │ │ └── <featureName>.entity.ts
434
+ │ ├── events/
435
+ │ │ └── <featureName>.event.ts
436
+ │ └── exceptions/
437
+ │ └── <featureName>.exception.ts
438
+ ├── application/
439
+ │ ├── dtos/
440
+ │ │ └── <featureName>.dto.ts
441
+ │ ├── ports/
442
+ │ │ ├── repositories/
443
+ │ │ │ └── <featureName>.repository.interface.ts
444
+ │ │ ├── presenters/
445
+ │ │ │ └── <featureName>.presenter.interface.ts
446
+ │ │ └── services/
447
+ │ │ └── <featureName>.service.ts
448
+ │ └── use-cases/
449
+ │ └── <featureName>.usecase.ts
450
+ └── infrastructure/
451
+ ├── adapters/
452
+ │ ├── controllers/
453
+ │ │ └── <featureName>.controller.ts
454
+ │ ├── repositories/
455
+ │ │ └── <featureName>.repository.ts
456
+ │ └── presenters/
457
+ │ └── <featureName>.presenter.ts
458
+ └── routes/
459
+ ├── <featureName>.router.handler.ts
460
+ └── <featureName>.router.ts
461
+ ```
462
+
463
+ 13 fichiers, 12 répertoires — générés en une seule interaction.
464
+
465
+ ### Exemple — feature `invoice`
466
+
467
+ Seule question posée pendant la génération : les méthodes du controller.
468
+
469
+ ```
470
+ ◆ Do you want to add methods to the controller?
471
+ │ ● Yes ○ No
472
+
473
+
474
+ ◆ Enter the method names (comma separated):
475
+ │ create, findAll, findById, update, delete
476
+
477
+
478
+ ✅ Entity created: src/features/invoice/domain/entities/invoice.entity.ts
479
+ ✅ Event created: src/features/invoice/domain/events/invoice.event.ts
480
+ ✅ Exception created: src/features/invoice/domain/exceptions/invoice.exception.ts
481
+ ✅ Repository interface created: src/features/invoice/application/ports/repositories/invoice.repository.interface.ts
482
+ ✅ Presenter interface created: src/features/invoice/application/ports/presenters/invoice.presenter.interface.ts
483
+ ✅ Service interface created: src/features/invoice/application/ports/services/invoice.service.ts
484
+ ✅ DTO created: src/features/invoice/application/dtos/invoice.dto.ts
485
+ ✅ UseCase created: src/features/invoice/application/use-cases/invoice.usecase.ts
486
+ ✅ Repository implementation: src/features/invoice/infrastructure/adapters/repositories/invoice.repository.ts
487
+ ✅ Presenter implementation: src/features/invoice/infrastructure/adapters/presenters/invoice.presenter.ts
488
+ ✅ Controller created: src/features/invoice/infrastructure/adapters/controllers/invoice.controller.ts
489
+ ✅ Router Handler created: src/features/invoice/infrastructure/routes/invoice.router.handler.ts
490
+ ✅ Router created: src/features/invoice/infrastructure/routes/invoice.router.ts
491
+ ✅ register.router.ts updated with InvoiceRouter.
492
+
493
+ 🎉 Feature "invoice" scaffolded with Clean Architecture!
494
+ ```
495
+
496
+ ### Contenu généré — `invoice.entity.ts`
497
+
498
+ ```typescript
499
+ /**
500
+ * InvoiceEntity — Domain Entity
501
+ * Represents the core business object for the "invoice" feature.
502
+ * No framework dependency, pure business logic only.
503
+ */
504
+ export class InvoiceEntity {
505
+ private readonly _id: string;
506
+ private _createdAt: Date;
507
+ private _updatedAt: Date;
508
+
509
+ constructor(
510
+ id: string,
511
+ // TODO: Add your business properties here
512
+ createdAt?: Date,
513
+ updatedAt?: Date,
514
+ ) {
515
+ this._id = id;
516
+ this._createdAt = createdAt ?? new Date();
517
+ this._updatedAt = updatedAt ?? new Date();
518
+ this.validate();
519
+ }
520
+
521
+ get id(): string { return this._id; }
522
+ get createdAt(): Date { return this._createdAt; }
523
+ get updatedAt(): Date { return this._updatedAt; }
524
+
525
+ public touch(): void {
526
+ this._updatedAt = new Date();
527
+ }
528
+
529
+ public toSnapshot(): Record<string, unknown> {
530
+ return { id: this._id, createdAt: this._createdAt, updatedAt: this._updatedAt };
531
+ }
532
+
533
+ private validate(): void {
534
+ if (!this._id || this._id.trim().length === 0) {
535
+ throw new Error(`[InvoiceEntity] id must not be empty.`);
536
+ }
537
+ // TODO: Add your domain invariant checks here
538
+ }
539
+ }
540
+ ```
541
+
542
+ ### Contenu généré — `invoice.usecase.ts`
543
+
544
+ ```typescript
545
+ import { IInvoiceRepository } from "../ports/repositories/invoice.repository.interface";
546
+ import { InvoiceEntity } from "../../domain/entities/invoice.entity";
547
+ import {
548
+ CreateInvoiceDto,
549
+ UpdateInvoiceDto,
550
+ InvoiceResponseDto,
551
+ InvoiceDtoMapper,
552
+ } from "../dtos/invoice.dto";
553
+
554
+ /**
555
+ * InvoiceUseCase — Application Use Case
556
+ *
557
+ * Orchestrates business operations for the "invoice" feature.
558
+ * Depends only on the repository port (interface), never on a concrete implementation.
559
+ */
560
+ export class InvoiceUseCase {
561
+ constructor(private readonly repository: IInvoiceRepository) {}
562
+
563
+ async findAll(): Promise<InvoiceResponseDto[]> {
564
+ const entities = await this.repository.findAll();
565
+ return InvoiceDtoMapper.toResponseList(entities);
566
+ }
567
+
568
+ async findById(id: string): Promise<InvoiceResponseDto | null> {
569
+ const entity = await this.repository.findById(id);
570
+ if (!entity) return null;
571
+ return InvoiceDtoMapper.toResponse(entity);
572
+ }
573
+
574
+ async create(dto: CreateInvoiceDto): Promise<InvoiceResponseDto> {
575
+ const id = crypto.randomUUID();
576
+ const entity = new InvoiceEntity(id /* TODO: pass dto fields */);
577
+ const saved = await this.repository.create(entity);
578
+ return InvoiceDtoMapper.toResponse(saved);
579
+ }
580
+
581
+ async update(dto: UpdateInvoiceDto): Promise<InvoiceResponseDto | null> {
582
+ const existing = await this.repository.findById(dto.id);
583
+ if (!existing) return null;
584
+ existing.touch();
585
+ const updated = await this.repository.update(existing);
586
+ if (!updated) return null;
587
+ return InvoiceDtoMapper.toResponse(updated);
588
+ }
589
+
590
+ async delete(id: string): Promise<boolean> {
591
+ return this.repository.delete(id);
592
+ }
593
+ }
594
+ ```
595
+
596
+ ### Contenu généré — `invoice.router.handler.ts` (méthodes `create, findAll, findById`)
597
+
598
+ ```typescript
599
+ import { OpticoreRouting, ICustomContext, IMultipleRouteDefinition } from "opticore-router";
600
+ import { InvoiceController } from "../adapters/controllers/invoice.controller";
601
+
602
+ export const InvoiceHandlerRouter: () => IMultipleRouteDefinition = () => {
603
+ return OpticoreRouting.routes(
604
+ InvoiceController,
605
+ [
606
+ {
607
+ path: `/invoice`,
608
+ method: "post",
609
+ middlewares: [],
610
+ handler: async (ctx: ICustomContext) => await InvoiceController.create(ctx.req, ctx.res)
611
+ },
612
+ {
613
+ path: `/invoice`,
614
+ method: "get",
615
+ middlewares: [],
616
+ handler: async (ctx: ICustomContext) => await InvoiceController.findAll(ctx.req, ctx.res)
617
+ },
618
+ {
619
+ path: `/invoice/:id`,
620
+ method: "get",
621
+ middlewares: [],
622
+ handler: async (ctx: ICustomContext) => await InvoiceController.findById(ctx.req, ctx.res)
623
+ }
624
+ ]
625
+ );
626
+ };
627
+ ```
628
+
629
+ ---
630
+
631
+ ## Règles de nommage
632
+
633
+ Le nom de la feature est soumis à validation stricte :
634
+
635
+ | Règle | Détail |
636
+ |---|---|
637
+ | Format | camelCase — `^[a-z][A-Za-z]+$` |
638
+ | Premier caractère | Minuscule obligatoire |
639
+ | Longueur minimale | 2 caractères |
640
+ | Caractères autorisés | Lettres uniquement (a-z, A-Z) |
641
+ | Caractères interdits | Chiffres, underscore, tiret, espaces |
642
+
643
+ Le CLI rejette le nom si la feature existe déjà dans `src/features/`.
644
+
645
+ ---
646
+
647
+ ## Enregistrement automatique du router
648
+
649
+ Lors de la génération des options **Simple Component** et **Full CLEAN Architecture**, le router de la feature est automatiquement enregistré dans `src/app/router/register.router.ts`.
650
+
651
+ **Avant** :
652
+
653
+ ```typescript
654
+ export const registerRouter: () => TFeatureRoutes[] = (): TFeatureRoutes[] => {
655
+ return new OpticoreRegisterRouter().registered([
656
+ AuthenticationRouter,
657
+ ]);
658
+ }
659
+ ```
660
+
661
+ **Après** (ajout de `InvoiceRouter`) :
662
+
663
+ ```typescript
664
+ import { InvoiceRouter } from "../../features/invoice/infrastructure/routes/invoice.router";
665
+
666
+ export const registerRouter: () => TFeatureRoutes[] = (): TFeatureRoutes[] => {
667
+ return new OpticoreRegisterRouter().registered([
668
+ AuthenticationRouter,
669
+ InvoiceRouter,
670
+ ]);
671
+ }
672
+ ```
673
+
674
+ > Si `register.router.ts` est introuvable, un avertissement est affiché mais la génération continue normalement.
675
+ > En mode **CLEAN by step**, l'enregistrement automatique n'est pas effectué car les fichiers sont vides.
676
+
677
+ ---
678
+
679
+ ## Récapitulatif des options
680
+
681
+ | Option | Fichiers créés | Contenu | Interaction |
682
+ |---|---|---|---|
683
+ | Simple Component | 6 | Avec template | Nom des méthodes du controller |
684
+ | CLEAN by step | 0 à 13 au choix | **Vides** | Confirmation pour chaque fichier |
685
+ | Full CLEAN Architecture | 13 | Avec template | Nom des méthodes du controller |
686
+
687
+ ---
688
+
689
+ ## Contribuer
690
+
691
+ `opticore-feature-component` est open source.
692
+ Pour contribuer : clonez le dépôt et ouvrez une pull request.
693
+
694
+ - **Repository** : [github.com/guyzoum77/opticore-feature-cli](https://github.com/guyzoum77/opticore-feature-cli)
695
+ - **Issues** : [github.com/guyzoum77/opticore-feature-cli/issues](https://github.com/guyzoum77/opticore-feature-cli/issues)
696
+
697
+ **Auteur** : Guy-serge Kouacou — Licence MIT