Skip to content

Commit 67acf2a

Browse files
committed
feat: Add detailed JSDoc comments to ExtensionsModule and service setup for improved documentation
1 parent 1e047a5 commit 67acf2a

File tree

2 files changed

+168
-13
lines changed

2 files changed

+168
-13
lines changed

apps/api/src/extensions/extensions.module.ts

Lines changed: 84 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,26 +1,97 @@
1-
import { DynamicModule, Logger, Module, OnModuleInit } from '@nestjs/common'
1+
import { DynamicModule, Logger, Module, OnApplicationBootstrap, OnModuleInit } from '@nestjs/common'
22
import { RouterModule } from '@nestjs/core'
3-
import { isConsoleEntrypoint } from '~/_common/functions/is-cli'
43
import serviceSetup from '~/extensions/extensions.service.setup'
54

5+
/**
6+
* Module de gestion et de chargement des extensions.
7+
*
8+
* Ce module gère le système de plugins/extensions de l'application, permettant
9+
* de charger dynamiquement des modules personnalisés qui enrichissent les
10+
* fonctionnalités sans modifier le code source principal. Les extensions sont
11+
* chargées au démarrage selon la configuration définie dans list.yml.
12+
*
13+
* @module ExtensionsModule
14+
* @implements {OnModuleInit}
15+
* @implements {OnApplicationBootstrap}
16+
*
17+
* @description
18+
* Fonctionnalités du système d'extensions :
19+
* - Chargement dynamique des modules d'extension au démarrage
20+
* - Isolation des extensions dans leurs propres modules
21+
* - Configuration centralisée via list.yml et extension.yml
22+
* - Support des extensions côté service (backend) et application (frontend)
23+
* - Activation/désactivation des extensions sans suppression
24+
* - Routage automatique sous le préfixe '/extensions'
25+
*
26+
* Comportement selon le contexte :
27+
* - **Mode service** : Charge toutes les extensions activées depuis list.yml
28+
* - **Mode console** : Ignore le chargement des extensions pour optimiser les performances
29+
*
30+
* Processus de chargement :
31+
* 1. Lecture du fichier list.yml
32+
* 2. Filtrage des extensions activées
33+
* 3. Chargement de chaque extension.yml
34+
* 4. Import dynamique des modules définis
35+
* 5. Enregistrement des routes sous '/extensions'
36+
*/
637
@Module({
738
imports: [],
839
})
9-
export class ExtensionsModule implements OnModuleInit {
40+
export class ExtensionsModule implements OnModuleInit, OnApplicationBootstrap {
41+
/**
42+
* Hook de cycle de vie appelé après l'initialisation du module.
43+
*
44+
* Enregistre un message de log confirmant que toutes les extensions
45+
* ont été initialisées avec succès.
46+
*
47+
* @async
48+
* @returns {Promise<void>}
49+
*/
1050
public async onModuleInit(): Promise<void> {
11-
Logger.log('All extensions is initialized', 'ExtensionsModule')
51+
Logger.log('All extensions is initialized', ExtensionsModule.name)
1252
}
1353

14-
public static async register(): Promise<DynamicModule> {
15-
if (isConsoleEntrypoint) {
16-
Logger.verbose('Console entrypoint detected, skipping extensions registration', 'ExtensionsModule')
17-
return {
18-
module: this,
19-
imports: [],
20-
}
21-
}
54+
/**
55+
* Hook de cycle de vie appelé après le démarrage complet de l'application.
56+
*
57+
* Enregistre un message de log confirmant que toutes les extensions
58+
* ont été enregistrées et sont prêtes à être utilisées.
59+
*
60+
* @async
61+
* @returns {Promise<void>}
62+
*/
63+
public async onApplicationBootstrap(): Promise<void> {
64+
Logger.log('Extensions registered !', ExtensionsModule.name)
65+
}
2266

23-
Logger.debug('Registering extensions', 'ExtensionsModule')
67+
/**
68+
* Enregistre le module Extensions en mode dynamique avec chargement des extensions.
69+
*
70+
* Cette méthode asynchrone charge dynamiquement toutes les extensions activées
71+
* depuis le fichier de configuration list.yml et configure le routage automatique.
72+
*
73+
* @static
74+
* @async
75+
* @returns {Promise<DynamicModule>} Le module configuré avec les extensions chargées
76+
*
77+
* @description
78+
* Processus détaillé :
79+
* 1. Vérifie si l'application est lancée en mode console
80+
* - Si oui : Ignore le chargement des extensions (retour module vide)
81+
* - Si non : Continue le chargement
82+
* 2. Appelle serviceSetup() qui :
83+
* - Lit le fichier list.yml
84+
* - Charge chaque extension activée
85+
* - Import dynamiquement les modules
86+
* 3. Configure le RouterModule pour préfixer toutes les routes par '/extensions'
87+
* 4. Retourne le module dynamique avec toutes les extensions importées
88+
*
89+
* Logging :
90+
* - Mode console : Log verbose indiquant que les extensions sont ignorées
91+
* - Mode service : Log debug au début du chargement
92+
* - Fin d'initialisation : Log info via onModuleInit()
93+
*/
94+
public static async register(): Promise<DynamicModule> {
2495
const modules = await serviceSetup()
2596

2697
return {

apps/api/src/extensions/extensions.service.setup.ts

Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,11 +8,42 @@ import { validateOrReject } from 'class-validator'
88
import * as process from 'process'
99
import { DynamicModule, Logger } from '@nestjs/common'
1010

11+
/**
12+
* Liste des modules d'extension chargés dynamiquement.
13+
* @type {DynamicModule[]}
14+
*/
1115
const serviceList: DynamicModule[] = []
1216

17+
/**
18+
* Nom du fichier de configuration d'une extension.
19+
* @constant {string}
20+
*/
1321
export const EXTENSION_FILE_INFO = 'extension.yml'
22+
23+
/**
24+
* Chemin vers le fichier de liste des extensions.
25+
* @constant {string}
26+
*/
1427
export const EXTENSIONS_FILE_PATH = join(process.cwd(), '/extensions/list.yml')
1528

29+
/**
30+
* Parse et valide le fichier de liste des extensions.
31+
*
32+
* Lit le fichier list.yml, le valide selon le schéma ExtensionsFileV1
33+
* et retourne la liste des extensions configurées.
34+
*
35+
* @async
36+
* @returns {Promise<ExtensionsListV1[]>} Liste des extensions avec leur configuration
37+
* @throws {Error} Si le fichier est invalide ou ne respecte pas le schéma
38+
*
39+
* @description
40+
* Processus de validation :
41+
* 1. Lecture du fichier list.yml
42+
* 2. Parsing YAML en objet JavaScript
43+
* 3. Transformation en instance de classe avec class-transformer
44+
* 4. Validation du schéma avec class-validator
45+
* 5. Retour de la liste des extensions si valide
46+
*/
1647
export async function parseExtensionsList(): Promise<ExtensionsListV1[]> {
1748
const data = readFileSync(EXTENSIONS_FILE_PATH, 'utf8')
1849
const yml = parse(data)
@@ -30,13 +61,66 @@ export async function parseExtensionsList(): Promise<ExtensionsListV1[]> {
3061
return yml.list
3162
}
3263

64+
/**
65+
* Parse et valide le fichier de configuration d'une extension.
66+
*
67+
* Lit le fichier extension.yml d'une extension spécifique et le valide
68+
* selon le schéma ExtensionFileV1.
69+
*
70+
* @async
71+
* @param {string} path - Chemin vers le répertoire de l'extension
72+
* @returns {Promise<ExtensionFileV1>} Configuration complète de l'extension
73+
* @throws {Error} Si le fichier n'existe pas ou est invalide
74+
*
75+
* @description
76+
* Cette fonction :
77+
* 1. Lit le fichier extension.yml dans le répertoire spécifié
78+
* 2. Parse le contenu YAML
79+
* 3. Transforme en instance ExtensionFileV1
80+
* 4. Retourne la configuration validée
81+
*/
3382
export async function extensionParseFile(path: string): Promise<ExtensionFileV1> {
3483
Logger.log('Extension file found, validating...', 'extensionParseFile')
3584
const data = readFileSync(`${path}/${EXTENSION_FILE_INFO}`, 'utf8')
3685
const yml = parse(data)
3786
return plainToInstance(ExtensionFileV1, yml)
3887
}
3988

89+
/**
90+
* Fonction principale de configuration et chargement des extensions.
91+
*
92+
* Cette fonction asynchrone charge toutes les extensions activées depuis
93+
* le fichier list.yml et retourne les modules prêts à être importés par NestJS.
94+
*
95+
* @async
96+
* @default
97+
* @returns {Promise<DynamicModule[]>} Liste des modules d'extension chargés
98+
*
99+
* @description
100+
* Processus de chargement complet :
101+
* 1. Vérifie l'existence du fichier list.yml
102+
* 2. Parse et valide la liste des extensions
103+
* 3. Pour chaque extension activée :
104+
* a. Lit et valide son fichier extension.yml
105+
* b. Vérifie qu'elle a une cible service définie
106+
* c. Import dynamiquement le module depuis le chemin spécifié
107+
* d. Récupère le module principal (par défaut 'ExtensionModule')
108+
* e. Ajoute le module à la liste
109+
* 4. Retourne tous les modules chargés
110+
*
111+
* Gestion des erreurs :
112+
* - Extension désactivée : Log et skip
113+
* - Pas de cible service : Warning et skip
114+
* - Module principal introuvable : Warning et skip
115+
* - Erreur de chargement : Error log avec trace
116+
* - Erreur critique : Exit du processus avec code 1
117+
*
118+
* Logging détaillé :
119+
* - Info : Fichier trouvé, validation en cours
120+
* - Info : Extension activée avec succès
121+
* - Warning : Extension désactivée ou configuration incomplète
122+
* - Error : Échec de chargement avec stack trace
123+
*/
40124
export default async function (): Promise<DynamicModule[]> {
41125
try {
42126
if (existsSync(EXTENSIONS_FILE_PATH)) {

0 commit comments

Comments
 (0)