nestgen-cli 0.0.7

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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 Aristide Kamara
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/nestgen.js ADDED
@@ -0,0 +1,218 @@
1
+ #!/usr/bin/env node
2
+
3
+ import { execSync } from 'child_process';
4
+ import inquirer from 'inquirer';
5
+ import chalk from 'chalk';
6
+ import path from 'path';
7
+ import fs from 'fs';
8
+ import { fileURLToPath } from 'url';
9
+
10
+ // ────── Resolve __dirname compatible ES Modules
11
+ const __filename = fileURLToPath(import.meta.url);
12
+ const __dirname = path.dirname(__filename);
13
+
14
+ // ────── Définition du chemin du générateur
15
+ const ROOT_PATH = process.env.NESTGEN_ROOT || path.resolve(__dirname, './nestjs-generator');
16
+ const GENERATE_SCRIPT = path.join(ROOT_PATH, 'generate_project.sh');
17
+ const ADD_MODULE_SCRIPT = path.join(ROOT_PATH, './features/add_module.sh');
18
+
19
+ // ────── Logo CLI
20
+ function printLogo() {
21
+ console.log(chalk.magentaBright(`
22
+ ███╗ ██╗███████╗███████╗████████╗ ██████╗ ███████╗███╗ ██╗
23
+ ████╗ ██║██╔════╝██╔════╝╚══██╔══╝██╔════╝ ██╔════╝████╗ ██║
24
+ ██╔██╗ ██║█████╗ ███████╗ ██║ ██║ ███╗█████╗ ██╔██╗ ██║
25
+ ██║╚██╗██║██╔══╝ ╚════██║ ██║ ██║ ██║██╔══╝ ██║╚██╗██║
26
+ ██║ ╚████║███████╗███████║ ██║ ╚██████╔╝███████╗██║ ╚████║
27
+ ╚═╝ ╚═══╝╚══════╝╚══════╝ ╚═╝ ╚═════╝ ╚══════╝╚═╝ ╚═══╝
28
+ `));
29
+ console.log(chalk.cyan.bold('✨ NestGen CLI — Générateur modulaire NestJS'));
30
+ }
31
+
32
+ // ────── Helpers
33
+ function isNestProject() {
34
+ return fs.existsSync(path.resolve('./src/app.module.ts'));
35
+ }
36
+
37
+ function parseModuleArgs(args) {
38
+ const moduleName = args[1];
39
+ const ormArg = args.find(arg => arg.startsWith('--orm='));
40
+ const orm = ormArg ? ormArg.split('=')[1] : 'typeorm';
41
+ return { moduleName, orm };
42
+ }
43
+
44
+ // ────── Commande : INIT
45
+ async function askInitQuestions() {
46
+ return await inquirer.prompt([
47
+ {
48
+ type: 'input',
49
+ name: 'projectName',
50
+ message: '📛 Nom du projet :',
51
+ default: 'my-app',
52
+ },
53
+ {
54
+ type: 'input',
55
+ name: 'projectPath',
56
+ message: '📁 Dossier cible :',
57
+ default: './',
58
+ },
59
+ {
60
+ type: 'list',
61
+ name: 'packageManager',
62
+ message: '📦 Package manager :',
63
+ choices: ['pnpm', 'yarn', 'npm'],
64
+ default: 'pnpm',
65
+ },
66
+ {
67
+ type: 'list',
68
+ name: 'orm',
69
+ message: '🧠 ORM :',
70
+ choices: ['typeorm', 'prisma'],
71
+ default: 'typeorm',
72
+ },
73
+ {
74
+ type: 'confirm',
75
+ name: 'withSwagger',
76
+ message: '📚 Activer Swagger ?',
77
+ default: true,
78
+ },
79
+ {
80
+ type: 'confirm',
81
+ name: 'withDocker',
82
+ message: '🐳 Activer Docker ?',
83
+ default: false,
84
+ },
85
+ {
86
+ type: 'confirm',
87
+ name: 'withGit',
88
+ message: '🔃 Initialiser Git ?',
89
+ default: true,
90
+ },
91
+ {
92
+ type: 'input',
93
+ name: 'modules',
94
+ message: '📦 Modules à générer (séparés par des espaces) :',
95
+ default: 'user',
96
+ filter: (input) => input.split(' ').map(s => s.trim()).filter(Boolean),
97
+ }
98
+ ]);
99
+ }
100
+
101
+ async function runInteractiveInit() {
102
+ printLogo();
103
+
104
+ if (!fs.existsSync(GENERATE_SCRIPT)) {
105
+ console.log(chalk.red(`❌ Script introuvable : ${GENERATE_SCRIPT}`));
106
+ process.exit(1);
107
+ }
108
+
109
+ const answers = await askInitQuestions();
110
+ const {
111
+ projectName,
112
+ projectPath,
113
+ packageManager,
114
+ orm,
115
+ withSwagger,
116
+ withDocker,
117
+ withGit,
118
+ modules,
119
+ } = answers;
120
+
121
+ const env = {
122
+ APP_NAME: projectName,
123
+ PROJECT_PATH: path.resolve(projectPath),
124
+ PM: packageManager,
125
+ ORM: orm,
126
+ WITH_SWAGGER: withSwagger ? 'y' : 'n',
127
+ WITH_DOCKER: withDocker ? 'y' : 'n',
128
+ WITH_GIT: withGit ? 'y' : 'n',
129
+ MODULES: modules.join(' '),
130
+ };
131
+
132
+ const envExport = Object.entries(env)
133
+ .map(([key, val]) => `${key}="${val}"`)
134
+ .join(' ');
135
+
136
+ console.log('\n🚀 Lancement de la génération du projet...\n');
137
+ try {
138
+ execSync(`env ${envExport} bash "${GENERATE_SCRIPT}"`, {
139
+ stdio: 'inherit',
140
+ });
141
+ } catch (err) {
142
+ console.error(chalk.red('❌ Une erreur est survenue pendant la génération.'));
143
+ process.exit(1);
144
+ }
145
+ }
146
+
147
+ // ────── Commande : MODULE
148
+ async function runModuleGeneration(args) {
149
+ printLogo();
150
+
151
+ let moduleName, orm;
152
+
153
+ if (args.length > 1) {
154
+ ({ moduleName, orm } = parseModuleArgs(args));
155
+ if (!moduleName) {
156
+ console.log(chalk.red('❌ Tu dois fournir un nom de module.'));
157
+ process.exit(1);
158
+ }
159
+ } else {
160
+ const answers = await inquirer.prompt([
161
+ {
162
+ type: 'input',
163
+ name: 'moduleName',
164
+ message: '📦 Nom du module :',
165
+ validate: input => !!input || 'Le nom du module est requis',
166
+ },
167
+ {
168
+ type: 'list',
169
+ name: 'orm',
170
+ message: '🧠 ORM utilisé :',
171
+ choices: ['typeorm', 'prisma'],
172
+ default: 'typeorm',
173
+ },
174
+ ]);
175
+ moduleName = answers.moduleName;
176
+ orm = answers.orm;
177
+ }
178
+
179
+ if (!isNestProject()) {
180
+ console.log(chalk.red('❌ Aucun projet NestJS détecté dans ce dossier.'));
181
+ console.log('👉 Lance cette commande depuis un projet généré avec `nestgen init`.');
182
+ process.exit(1);
183
+ }
184
+
185
+ try {
186
+ console.log(chalk.cyan(`\n⚙️ Génération du module ${moduleName}...\n`));
187
+ execSync(`bash "${ADD_MODULE_SCRIPT}" "${moduleName}" "${orm}"`, {
188
+ stdio: 'inherit',
189
+ });
190
+ } catch (err) {
191
+ console.error(chalk.red('❌ Une erreur est survenue pendant la génération du module.'));
192
+ process.exit(1);
193
+ }
194
+ }
195
+
196
+ // ────── Entrée CLI
197
+ const args = process.argv.slice(2);
198
+ const command = args[0];
199
+
200
+ switch (command) {
201
+ case 'init':
202
+ await runInteractiveInit();
203
+ break;
204
+
205
+ case 'module':
206
+ await runModuleGeneration(args);
207
+ break;
208
+
209
+ default:
210
+ printLogo();
211
+ console.log(chalk.gray(`
212
+ 📘 Commandes disponibles :
213
+ ▸ nestgen init → Génère un projet complet NestJS (interactive)
214
+ ▸ nestgen module [nom] [--orm=xxx] → Génère un module (interactive ou CLI)
215
+ ▸ nestgen doctor → Diagnostic de l’installation CLI
216
+ `));
217
+ break;
218
+ }
@@ -0,0 +1,234 @@
1
+ #!/bin/bash
2
+
3
+ RAW_NAME=$1
4
+ ORM=$2
5
+
6
+ # ────── Charger les helpers ──────
7
+ FEATURES_PATH="$(dirname "$0")"
8
+ source "$FEATURES_PATH/utils.sh"
9
+ source "$FEATURES_PATH/logger.sh"
10
+
11
+
12
+ if [ -z "$RAW_NAME" ]; then
13
+ echo "❌ Tu dois passer un nom de module."
14
+ exit 1
15
+ fi
16
+
17
+ if [ -z "$ORM" ]; then
18
+ echo "❌ ORM manquant (typeorm ou prisma)."
19
+ exit 1
20
+ fi
21
+
22
+ # ────── Formatage ──────
23
+ NAME=$(echo "$RAW_NAME" | tr '[:upper:]' '[:lower:]')
24
+ PASCAL=$(echo "$NAME" | sed -E 's/(^|[-_])([a-z])/\u\2/g' | sed -E 's/[-_]//g')
25
+
26
+ NAME=$(echo "$RAW_NAME" | tr '[:upper:]' '[:lower:]')
27
+ PASCAL=$(echo "$NAME" | sed -E 's/(^|[-_])([a-z])/\U\2/g' | sed -E 's/[-_]//g')
28
+
29
+ CAMEL=$(echo "$PASCAL" | sed -E 's/^([A-Z])/\L\1/')
30
+
31
+ MODULE_DIR="src/app/$NAME"
32
+ mkdir -p "$MODULE_DIR"/{core/{application/{commands,events,queries},domain/{entities,ports}},infrastructure/{adapters,persistences/repositories},interfaces/{controllers,dtos}}
33
+
34
+ # ────── Entity ──────
35
+ cat > "$MODULE_DIR/core/domain/entities/${NAME}.entity.ts" <<EOF
36
+ export class $PASCAL {
37
+ constructor(
38
+ public readonly id: string,
39
+ public name: string,
40
+ public email: string,
41
+ ) {}
42
+ }
43
+ EOF
44
+
45
+ # ────── Port ──────
46
+ cat > "$MODULE_DIR/core/domain/ports/${NAME}.repository.ts" <<EOF
47
+ import { $PASCAL } from '../entities/${NAME}.entity';
48
+
49
+ export interface ${PASCAL}RepositoryPort {
50
+ save(${CAMEL}: $PASCAL): Promise<$PASCAL>;
51
+ findById(id: string): Promise<$PASCAL | null>;
52
+ }
53
+ EOF
54
+
55
+ # ────── Command ──────
56
+ cat > "$MODULE_DIR/core/application/commands/create-${NAME}.command.ts" <<EOF
57
+ export class Create${PASCAL}Command {
58
+ constructor(public readonly name: string, public readonly email: string) {}
59
+ }
60
+ EOF
61
+
62
+ # ────── Command Handler ──────
63
+ cat > "$MODULE_DIR/core/application/commands/create-${NAME}.handler.ts" <<EOF
64
+ import { CommandHandler, ICommandHandler } from '@nestjs/cqrs';
65
+ import { Create${PASCAL}Command } from './create-${NAME}.command';
66
+ import { $PASCAL } from '../../domain/entities/${NAME}.entity';
67
+ import { ${PASCAL}RepositoryPort } from '../../domain/ports/${NAME}.repository';
68
+
69
+ @CommandHandler(Create${PASCAL}Command)
70
+ export class Create${PASCAL}Handler implements ICommandHandler<Create${PASCAL}Command> {
71
+ constructor(private readonly repo: ${PASCAL}RepositoryPort) {}
72
+
73
+ async execute(command: Create${PASCAL}Command): Promise<string> {
74
+ const $CAMEL = new $PASCAL(Date.now().toString(), command.name, command.email);
75
+ const saved = await this.repo.save($CAMEL);
76
+ return saved.id;
77
+ }
78
+ }
79
+ EOF
80
+
81
+ # ────── DTO ──────
82
+ cat > "$MODULE_DIR/interfaces/dtos/create-${NAME}.dto.ts" <<EOF
83
+ import { IsEmail, IsString } from 'class-validator';
84
+
85
+ export class Create${PASCAL}Dto {
86
+ @IsString()
87
+ name: string;
88
+
89
+ @IsEmail()
90
+ email: string;
91
+ }
92
+ EOF
93
+
94
+ # ────── Controller ──────
95
+ cat > "$MODULE_DIR/interfaces/controllers/${NAME}.controller.ts" <<EOF
96
+ import { Controller, Post, Body } from '@nestjs/common';
97
+ import { CommandBus } from '@nestjs/cqrs';
98
+ import { Create${PASCAL}Command } from '../../core/application/commands/create-${NAME}.command';
99
+ import { Create${PASCAL}Dto } from '../dtos/create-${NAME}.dto';
100
+
101
+ @Controller('${NAME}s')
102
+ export class ${PASCAL}Controller {
103
+ constructor(private readonly commandBus: CommandBus) {}
104
+
105
+ @Post()
106
+ async create(@Body() dto: Create${PASCAL}Dto) {
107
+ const id = await this.commandBus.execute(
108
+ new Create${PASCAL}Command(dto.name, dto.email)
109
+ );
110
+ return { id };
111
+ }
112
+ }
113
+ EOF
114
+
115
+ # ────── Repository ORM ──────
116
+ REPO_CLASS=""
117
+ ENTITY_IMPORT=""
118
+ REPO_PROVIDER=""
119
+
120
+ if [ "$ORM" == "typeorm" ]; then
121
+ cat > "$MODULE_DIR/infrastructure/persistences/repositories/${NAME}.orm.ts" <<EOF
122
+ import { Entity, PrimaryGeneratedColumn, Column } from 'typeorm';
123
+
124
+ @Entity('${NAME}s')
125
+ export class ${PASCAL}Entity {
126
+ @PrimaryGeneratedColumn('uuid')
127
+ id: string;
128
+
129
+ @Column()
130
+ name: string;
131
+
132
+ @Column({ unique: true })
133
+ email: string;
134
+ }
135
+ EOF
136
+
137
+ cat > "$MODULE_DIR/infrastructure/persistences/repositories/${NAME}.typeorm.repository.ts" <<EOF
138
+ import { Injectable } from '@nestjs/common';
139
+ import { InjectRepository } from '@nestjs/typeorm';
140
+ import { Repository } from 'typeorm';
141
+ import { ${PASCAL} } from '../../../core/domain/entities/${NAME}.entity';
142
+ import { ${PASCAL}RepositoryPort } from '../../../core/domain/ports/${NAME}.repository';
143
+ import { ${PASCAL}Entity } from './${NAME}.orm';
144
+
145
+ @Injectable()
146
+ export class ${PASCAL}TypeOrmRepository implements ${PASCAL}RepositoryPort {
147
+ constructor(@InjectRepository(${PASCAL}Entity) private readonly repo: Repository<${PASCAL}Entity>) {}
148
+
149
+ async save(${CAMEL}: $PASCAL): Promise<$PASCAL> {
150
+ const entity = this.repo.create(${CAMEL});
151
+ const saved = await this.repo.save(entity);
152
+ return new $PASCAL(saved.id, saved.name, saved.email);
153
+ }
154
+
155
+ async findById(id: string): Promise<$PASCAL | null> {
156
+ const found = await this.repo.findOneBy({ id });
157
+ return found ? new $PASCAL(found.id, found.name, found.email) : null;
158
+ }
159
+ }
160
+ EOF
161
+
162
+ REPO_CLASS="${PASCAL}TypeOrmRepository"
163
+ ENTITY_IMPORT="TypeOrmModule.forFeature([${PASCAL}Entity])"
164
+ REPO_PROVIDER="{
165
+ provide: '${PASCAL}RepositoryPort',
166
+ useClass: ${PASCAL}TypeOrmRepository,
167
+ }"
168
+
169
+ elif [ "$ORM" == "prisma" ]; then
170
+ cat > "$MODULE_DIR/infrastructure/persistences/repositories/${NAME}.prisma.repository.ts" <<EOF
171
+ import { Injectable } from '@nestjs/common';
172
+ import { PrismaService } from '@/prisma.service';
173
+ import { ${PASCAL} } from '../../../core/domain/entities/${NAME}.entity';
174
+ import { ${PASCAL}RepositoryPort } from '../../../core/domain/ports/${NAME}.repository';
175
+
176
+ @Injectable()
177
+ export class ${PASCAL}PrismaRepository implements ${PASCAL}RepositoryPort {
178
+ constructor(private readonly prisma: PrismaService) {}
179
+
180
+ async save(${CAMEL}: ${PASCAL}): Promise<${PASCAL}> {
181
+ const saved = await this.prisma.${NAME}.create({
182
+ data: {
183
+ id: ${CAMEL}.id,
184
+ name: ${CAMEL}.name,
185
+ email: ${CAMEL}.email,
186
+ },
187
+ });
188
+ return new ${PASCAL}(saved.id, saved.name, saved.email);
189
+ }
190
+
191
+ async findById(id: string): Promise<${PASCAL} | null> {
192
+ const found = await this.prisma.${NAME}.findUnique({ where: { id } });
193
+ return found ? new ${PASCAL}(found.id, found.name, found.email) : null;
194
+ }
195
+ }
196
+ EOF
197
+
198
+ REPO_CLASS="${PASCAL}PrismaRepository"
199
+ ENTITY_IMPORT=""
200
+ REPO_PROVIDER="{
201
+ provide: '${PASCAL}RepositoryPort',
202
+ useClass: ${PASCAL}PrismaRepository,
203
+ }"
204
+ fi
205
+
206
+ # ────── Module.ts ──────
207
+ IMPORTS="import { Module } from '@nestjs/common';
208
+ import { CqrsModule } from '@nestjs/cqrs';
209
+ import { ${PASCAL}Controller } from './interfaces/controllers/${NAME}.controller';
210
+ import { Create${PASCAL}Handler } from './core/application/commands/create-${NAME}.handler';
211
+ import { $REPO_CLASS } from './infrastructure/persistences/repositories/${NAME}.${ORM}.repository';"
212
+
213
+ if [ "$ORM" = "typeorm" ]; then
214
+ IMPORTS="$IMPORTS
215
+ import { TypeOrmModule } from '@nestjs/typeorm';
216
+ import { ${PASCAL}Entity } from './infrastructure/persistences/repositories/${NAME}.orm';"
217
+ fi
218
+
219
+ echo "$IMPORTS
220
+
221
+ @Module({
222
+ imports: [CqrsModule${ENTITY_IMPORT:+, $ENTITY_IMPORT}],
223
+ controllers: [${PASCAL}Controller],
224
+ providers: [
225
+ Create${PASCAL}Handler,
226
+ $REPO_CLASS,
227
+ $REPO_PROVIDER,
228
+ ],
229
+ })
230
+ export class ${PASCAL}Module {}
231
+ " > "$MODULE_DIR/${NAME}.module.ts"
232
+
233
+ bash "$(dirname "$0")/inject_module_to_app.sh" "$NAME" "$ORM"
234
+
@@ -0,0 +1,59 @@
1
+ #!/bin/bash
2
+
3
+
4
+ # ────── Charger les helpers ──────
5
+ FEATURES_PATH="$(dirname "$0")/features"
6
+ source "$FEATURES_PATH/utils.sh"
7
+ source "$FEATURES_PATH/logger.sh"
8
+
9
+
10
+ APP_NAME=$1
11
+
12
+ cat > Dockerfile <<EOF
13
+ FROM node:18-alpine
14
+ WORKDIR /usr/src/app
15
+ COPY package*.json ./
16
+ RUN npm install
17
+ COPY . .
18
+ RUN npm run build
19
+ CMD ["node", "dist/main"]
20
+ EOF
21
+
22
+ cat > docker-compose.yml <<EOF
23
+ version: '3.9'
24
+
25
+ services:
26
+ postgres:
27
+ image: postgres:15
28
+ restart: always
29
+ environment:
30
+ POSTGRES_USER: postgres
31
+ POSTGRES_PASSWORD: postgres
32
+ POSTGRES_DB: appdb
33
+ ports:
34
+ - "5432:5432"
35
+ volumes:
36
+ - pgdata:/var/lib/postgresql/data
37
+
38
+ app:
39
+ build: .
40
+ ports:
41
+ - "3000:3000"
42
+ depends_on:
43
+ - postgres
44
+ env_file:
45
+ - .env
46
+ volumes:
47
+ - .:/usr/src/app
48
+ command: npm run start:dev
49
+
50
+ volumes:
51
+ pgdata:
52
+ EOF
53
+
54
+ cat > .env <<EOF
55
+ DATABASE_URL=postgresql://postgres:postgres@postgres:5432/appdb
56
+ PORT=3000
57
+ EOF
58
+
59
+ echo "✅ Dockerfile, docker-compose et .env générés !"
@@ -0,0 +1,12 @@
1
+ #!/bin/bash
2
+
3
+ # ────── Charger les helpers ──────
4
+ FEATURES_PATH="$(dirname "$0")/features"
5
+ source "$FEATURES_PATH/utils.sh"
6
+ source "$FEATURES_PATH/logger.sh"
7
+
8
+
9
+ git init
10
+ git add .
11
+ git commit -m "🚀 Initial commit (NestJS starter clean architecture)"
12
+ echo "✅ Git initialisé et commité !"
@@ -0,0 +1,99 @@
1
+ #!/bin/bash
2
+
3
+ RAW_NAME=$1
4
+ ORM=$2
5
+ APP_MODULE="src/app.module.ts"
6
+ MODULE_FILE="src/app/${RAW_NAME}/${RAW_NAME}.module.ts"
7
+
8
+ if [ -z "$RAW_NAME" ]; then
9
+ echo "❌ Tu dois fournir un nom de module."
10
+ exit 1
11
+ fi
12
+
13
+ if [ ! -f "$MODULE_FILE" ]; then
14
+ echo "❌ Le fichier $MODULE_FILE est introuvable."
15
+ exit 1
16
+ fi
17
+
18
+ # 🧠 Extraire le vrai nom de la classe exportée
19
+ MODULE_CLASS=$(grep -oE 'export class [A-Za-z0-9_]+' "$MODULE_FILE" | awk '{print $3}')
20
+
21
+ if [ -z "$MODULE_CLASS" ]; then
22
+ echo "❌ Impossible de détecter la classe du module dans $MODULE_FILE"
23
+ exit 1
24
+ fi
25
+
26
+ MODULE_PATH="./app/${RAW_NAME}/${RAW_NAME}.module"
27
+
28
+ # 🔧 Créer app.module.ts s'il n'existe pas
29
+ if [ ! -f "$APP_MODULE" ]; then
30
+ echo "📄 Création de $APP_MODULE"
31
+ mkdir -p src
32
+ cat > "$APP_MODULE" <<EOF
33
+ import { Module } from '@nestjs/common';
34
+
35
+ @Module({
36
+ imports: [],
37
+ })
38
+ export class AppModule {}
39
+ EOF
40
+ fi
41
+
42
+ # 🔌 Ajouter l'import du module s'il est absent
43
+ IMPORT_LINE="import { $MODULE_CLASS } from '${MODULE_PATH}';"
44
+ if ! grep -q "$IMPORT_LINE" "$APP_MODULE"; then
45
+ echo "🔧 Insertion de $MODULE_CLASS dans les imports du haut"
46
+ sed -i '' "1s|^|$IMPORT_LINE\n|" "$APP_MODULE"
47
+ else
48
+ echo "ℹ️ Import $MODULE_CLASS déjà présent"
49
+ fi
50
+
51
+ # ➕ Ajouter dans imports: []
52
+ if grep -q "imports: \[" "$APP_MODULE"; then
53
+ if ! grep -q "$MODULE_CLASS" "$APP_MODULE"; then
54
+ sed -i '' "s|imports: \[|imports: [$MODULE_CLASS, |" "$APP_MODULE"
55
+ echo "✅ $MODULE_CLASS injecté dans imports"
56
+ else
57
+ echo "ℹ️ $MODULE_CLASS déjà dans imports"
58
+ fi
59
+ else
60
+ echo "❌ Aucun bloc imports: [] trouvé dans $APP_MODULE"
61
+ fi
62
+
63
+ # ➕ Ajouter CqrsModule si absent
64
+ if ! grep -q "CqrsModule" "$APP_MODULE"; then
65
+ sed -i '' "1i\\
66
+ import { CqrsModule } from '@nestjs/cqrs';
67
+ " "$APP_MODULE"
68
+ sed -i '' "s|imports: \[|imports: [CqrsModule, |" "$APP_MODULE"
69
+ echo "✅ CqrsModule injecté"
70
+ fi
71
+
72
+ # ➕ Ajouter TypeOrmModule si ORM = typeorm
73
+ if [ "$ORM" = "typeorm" ]; then
74
+ if ! grep -q "TypeOrmModule" "$APP_MODULE"; then
75
+ sed -i '' "1i\\
76
+ import { TypeOrmModule } from '@nestjs/typeorm';
77
+ " "$APP_MODULE"
78
+ echo "✅ Import de TypeOrmModule ajouté"
79
+ fi
80
+
81
+ if ! grep -q "TypeOrmModule.forRoot" "$APP_MODULE"; then
82
+ sed -i '' -E "s|(imports: \[)|\1\
83
+ TypeOrmModule.forRoot({\
84
+ type: 'postgres',\
85
+ host: 'localhost',\
86
+ port: 5432,\
87
+ username: 'postgres',\
88
+ password: 'postgres',\
89
+ database: 'appdb',\
90
+ synchronize: true,\
91
+ autoLoadEntities: true,\
92
+ }), |" "$APP_MODULE"
93
+ echo "✅ TypeOrmModule.forRoot injecté"
94
+ else
95
+ echo "ℹ️ TypeOrmModule.forRoot déjà présent"
96
+ fi
97
+ fi
98
+
99
+ echo "🎯 Module $MODULE_CLASS injecté dans app.module.ts avec succès 🧩"
@@ -0,0 +1,24 @@
1
+ #!/bin/bash
2
+
3
+ # 🎨 Couleurs
4
+ RED='\033[0;31m'
5
+ GREEN='\033[0;32m'
6
+ YELLOW='\033[1;33m'
7
+ BLUE='\033[1;34m'
8
+ NC='\033[0m' # No Color
9
+
10
+ log_info() {
11
+ echo -e "${BLUE}ℹ️ $1${NC}"
12
+ }
13
+
14
+ log_success() {
15
+ echo -e "${GREEN}✅ $1${NC}"
16
+ }
17
+
18
+ log_warn() {
19
+ echo -e "${YELLOW}⚠️ $1${NC}"
20
+ }
21
+
22
+ log_error() {
23
+ echo -e "${RED}❌ $1${NC}"
24
+ }
@@ -0,0 +1,9 @@
1
+ #!/bin/bash
2
+
3
+ get_cli_root() {
4
+ echo "$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
5
+ }
6
+
7
+ get_features_path() {
8
+ echo "$(get_cli_root)/features"
9
+ }
@@ -0,0 +1,33 @@
1
+ #!/bin/bash
2
+
3
+ # ────── Charger les helpers ──────
4
+ FEATURES_PATH="$(dirname "$0")/features"
5
+ source "$FEATURES_PATH/utils.sh"
6
+ source "$FEATURES_PATH/logger.sh"
7
+
8
+
9
+ PM=$1
10
+ APP_NAME=$2
11
+
12
+ $PM install prisma --save-dev
13
+ $PM install @prisma/client
14
+ npx prisma init
15
+
16
+ cat > .env <<EOF
17
+ DATABASE_URL="postgresql://postgres:postgres@localhost:5432/$APP_NAME"
18
+ EOF
19
+
20
+ cat > prisma/schema.prisma <<EOF
21
+ generator client {
22
+ provider = "prisma-client-js"
23
+ }
24
+
25
+ datasource db {
26
+ provider = "postgresql"
27
+ url = env("DATABASE_URL")
28
+ }
29
+ EOF
30
+
31
+ npx prisma generate
32
+
33
+ echo "✅ Prisma initialisé avec succès !"
@@ -0,0 +1,27 @@
1
+ #!/bin/bash
2
+
3
+ # ────── Charger les helpers ──────
4
+ FEATURES_PATH="$(dirname "$0")/features"
5
+ source "$FEATURES_PATH/utils.sh"
6
+ source "$FEATURES_PATH/logger.sh"
7
+
8
+
9
+ PM=$1
10
+
11
+ $PM install @nestjs/swagger swagger-ui-express
12
+
13
+ # Ajout dans main.ts (à faire manuellement ou via automatisation)
14
+ echo ""
15
+ echo "📘 Pour activer Swagger, ajoute ceci dans main.ts :"
16
+ echo ""
17
+ cat <<'DOC'
18
+ import { SwaggerModule, DocumentBuilder } from '@nestjs/swagger';
19
+
20
+ const config = new DocumentBuilder()
21
+ .setTitle('API Docs')
22
+ .setDescription('The API description')
23
+ .setVersion('1.0')
24
+ .build();
25
+ const document = SwaggerModule.createDocument(app, config);
26
+ SwaggerModule.setup('api', app, document);
27
+ DOC
@@ -0,0 +1,19 @@
1
+ #!/bin/bash
2
+
3
+ PM=$1
4
+ APP_NAME=$2
5
+
6
+ # ────── Charger les helpers ──────
7
+ FEATURES_PATH="$(dirname "$0")"
8
+ source "$FEATURES_PATH/utils.sh"
9
+ source "$FEATURES_PATH/logger.sh"
10
+
11
+ INSTALL_CMD=$(get_install_cmd "$PM")
12
+
13
+ log_info "📦 Installation de TypeORM et PostgreSQL..."
14
+
15
+ $PM $INSTALL_CMD @nestjs/typeorm typeorm pg
16
+
17
+ log_success "✅ TypeORM installé avec succès"
18
+
19
+ log_info "💡 TypeORM sera automatiquement configuré dans app.module.ts"
@@ -0,0 +1,26 @@
1
+ #!/bin/bash
2
+
3
+ # ────── Commande d'installation adaptée au package manager ──────
4
+ get_install_cmd() {
5
+ local PM=$1
6
+ case "$PM" in
7
+ yarn) echo "add" ;;
8
+ pnpm|npm) echo "install" ;;
9
+ *) echo "install" ;;
10
+ esac
11
+ }
12
+
13
+ # ────── Vérifie si une commande est installée ──────
14
+ assert_command_exists() {
15
+ local CMD=$1
16
+ if ! command -v "$CMD" &> /dev/null; then
17
+ echo "❌ Commande introuvable : $CMD"
18
+ echo "👉 Installe-la ou vérifie ton PATH"
19
+ exit 1
20
+ fi
21
+ }
22
+
23
+ # ────── Formatage ──────
24
+ to_pascal_case() {
25
+ echo "$1" | sed -E 's/(^|-|_)([a-z])/\U\2/g'
26
+ }
@@ -0,0 +1,143 @@
1
+ #!/bin/bash
2
+
3
+ # ────── INIT ──────
4
+ set -e
5
+
6
+ FEATURES_PATH="$(dirname "$0")/features"
7
+ source "$FEATURES_PATH/utils.sh"
8
+ source "$FEATURES_PATH/logger.sh"
9
+
10
+ # ────── DEBUG MODE ──────
11
+ DEBUG=false
12
+ for arg in "$@"; do
13
+ [[ "$arg" == "--debug" ]] && DEBUG=true
14
+ done
15
+
16
+ debug_log() {
17
+ if [ "$DEBUG" = true ]; then
18
+ echo "🐞 [DEBUG] $1" | tee /dev/tty
19
+ fi
20
+ }
21
+
22
+ debug_log "Script lancé avec les arguments : $*"
23
+ debug_log "Chemin du script courant : $(pwd)"
24
+ debug_log "Features path : $FEATURES_PATH"
25
+
26
+ # ────── INFOS UTILISATEUR ──────
27
+ APP_NAME=${APP_NAME:-$(read -p "📛 Nom du projet : " tmp && echo "$tmp")}
28
+ PROJECT_PATH=${PROJECT_PATH:-$(read -p "📁 Chemin d’installation (vide = ici) : " tmp && echo "${tmp:-$(pwd)}")}
29
+ FULL_PATH="$PROJECT_PATH/$APP_NAME"
30
+ PM=${PM:-$(read -p "📦 Package manager (npm/yarn/pnpm) : " tmp && echo "$tmp")}
31
+ ORM=${ORM:-$(read -p "🧠 ORM ? (typeorm/prisma) : " tmp && echo "$tmp")}
32
+
33
+ INSTALL_CMD=$(get_install_cmd "$PM")
34
+ debug_log "Install command : $PM $INSTALL_CMD"
35
+
36
+ # ────── Vérification de Nest CLI ──────
37
+ if ! command -v nest &> /dev/null; then
38
+ log_warn "Nest CLI non installée. Installation avec npm..."
39
+ npm install -g @nestjs/cli
40
+ fi
41
+
42
+ # ────── Création du projet ──────
43
+ log_info "Création du projet à $FULL_PATH"
44
+ mkdir -p "$FULL_PATH"
45
+ cd "$FULL_PATH" || {
46
+ log_error "Erreur : impossible de se déplacer dans $FULL_PATH"
47
+ exit 1
48
+ }
49
+
50
+ nest new . --package-manager "$PM" --skip-git || {
51
+ log_error "Échec de nest new"
52
+ exit 1
53
+ }
54
+
55
+ log_info "Installation des packages communs..."
56
+ $PM $INSTALL_CMD @nestjs/cqrs class-validator class-transformer @nestjs/config
57
+
58
+ # ────── ORM SETUP ──────
59
+ case "$ORM" in
60
+ typeorm)
61
+ debug_log "Appel de typeorm.sh"
62
+ bash "$FEATURES_PATH/typeorm.sh" "$PM" "$APP_NAME"
63
+ ;;
64
+ prisma)
65
+ debug_log "Appel de prisma.sh"
66
+ bash "$FEATURES_PATH/prisma.sh" "$PM" "$APP_NAME"
67
+ ;;
68
+ *)
69
+ log_error "❌ ORM non reconnu : $ORM"
70
+ exit 1
71
+ ;;
72
+ esac
73
+
74
+ # ────── Docker, Swagger, Git ──────
75
+ WITH_DOCKER=${WITH_DOCKER:-$(read -p "🐳 Activer Docker ? (y/n) : " tmp && echo "$tmp")}
76
+ [ "$WITH_DOCKER" = "y" ] && bash "$FEATURES_PATH/docker.sh" "$APP_NAME"
77
+
78
+ WITH_SWAGGER=${WITH_SWAGGER:-$(read -p "📚 Activer Swagger ? (y/n) : " tmp && echo "$tmp")}
79
+ [ "$WITH_SWAGGER" = "y" ] && bash "$FEATURES_PATH/swagger.sh" "$PM"
80
+
81
+ WITH_GIT=${WITH_GIT:-$(read -p "🔃 Initialiser Git ? (y/n) : " tmp && echo "$tmp")}
82
+ [ "$WITH_GIT" = "y" ] && bash "$FEATURES_PATH/git.sh"
83
+
84
+ # ────── Modules à générer ──────
85
+ MODULES=${MODULES:-$(read -p "👤 Modules à générer (séparés par espaces) : " tmp && echo "$tmp")}
86
+ for MODULE in $MODULES; do
87
+ debug_log "Génération du module $MODULE"
88
+ bash "$FEATURES_PATH/add_module.sh" "$MODULE" "$ORM"
89
+ done
90
+
91
+ # ────── Injection dans app.module.ts ──────
92
+ APP_MODULE="src/app.module.ts"
93
+
94
+ # CqrsModule
95
+ if ! grep -q "CqrsModule" "$APP_MODULE"; then
96
+ sed -i '' "1i\\
97
+ import { CqrsModule } from '@nestjs/cqrs';
98
+ " "$APP_MODULE"
99
+ sed -i '' "s|imports: \[|imports: [CqrsModule, |" "$APP_MODULE"
100
+ echo "✅ CqrsModule injecté"
101
+ fi
102
+
103
+ # TypeOrmModule
104
+ if [ "$ORM" = "typeorm" ]; then
105
+ if ! grep -q "TypeOrmModule" "$APP_MODULE"; then
106
+ sed -i '' "1i\\
107
+ import { TypeOrmModule } from '@nestjs/typeorm';
108
+ " "$APP_MODULE"
109
+ echo "✅ Import de TypeOrmModule ajouté"
110
+ fi
111
+
112
+ if ! grep -q "TypeOrmModule.forRoot" "$APP_MODULE"; then
113
+ sed -i '' -E 's/(imports: \[[^]]*)(])/\1\
114
+ TypeOrmModule.forRoot({\
115
+ type: '\''postgres'\'',\
116
+ host: '\''localhost'\'',\
117
+ port: 5432,\
118
+ username: '\''postgres'\'',\
119
+ password: '\''postgres'\'',\
120
+ database: '\''appdb'\'',\
121
+ synchronize: true,\
122
+ autoLoadEntities: true,\
123
+ }), \2/g' "$APP_MODULE"
124
+ echo "✅ TypeOrmModule.forRoot injecté"
125
+ fi
126
+ fi
127
+
128
+ # Modules générés
129
+ for MODULE in $MODULES; do
130
+ debug_log "Injection de $MODULE dans app.module.ts"
131
+ bash "$FEATURES_PATH/inject_module_to_app.sh" "$MODULE" "$ORM"
132
+ done
133
+
134
+ # ────── Résumé final ──────
135
+ echo ""
136
+ log_success "✅ Projet NestJS \"$APP_NAME\" généré avec succès 🎉"
137
+ echo "📁 Localisation : $FULL_PATH"
138
+ echo "📦 Package manager : $PM"
139
+ echo "🧠 ORM : $ORM"
140
+ [ "$WITH_DOCKER" = "y" ] && echo "🐳 Docker activé"
141
+ [ "$WITH_SWAGGER" = "y" ] && echo "📚 Swagger activé"
142
+ [ "$WITH_GIT" = "y" ] && echo "🔃 Git initialisé"
143
+ [ -n "$MODULES" ] && echo "📦 Modules générés : $MODULES"
package/package.json ADDED
@@ -0,0 +1,33 @@
1
+ {
2
+ "name": "nestgen-cli",
3
+ "version": "0.0.7",
4
+ "description": "NestGen CLI — Générateur modulaire NestJS (DDD, CQRS, Hexagonal)",
5
+ "files": [
6
+ "nestgen.js",
7
+ "nestjs-generator"
8
+ ],
9
+ "bin": {
10
+ "nestgen": "nestgen.js"
11
+ },
12
+ "author": "Aristide kamara bakarykamara52@gmail.com",
13
+ "license": "MIT",
14
+ "keywords": [
15
+ "nestjs",
16
+ "cli",
17
+ "ddd",
18
+ "cqrs",
19
+ "scaffold",
20
+ "generator",
21
+ "hexagonal"
22
+ ],
23
+ "repository": {
24
+ "type": "git",
25
+ "url": "https://github.com/el-hack/nestgen-cli.git"
26
+ },
27
+ "type": "module",
28
+ "licenses": "MIT",
29
+ "dependencies": {
30
+ "chalk": "^5.3.0",
31
+ "inquirer": "^9.0.0"
32
+ }
33
+ }
package/readme.md ADDED
@@ -0,0 +1,175 @@
1
+ # NestGen
2
+
3
+ <div align="center">
4
+ <img src="https://raw.githubusercontent.com/outis25/nestgen-js/main/assets/logo.png" alt="NestGen Logo" width="200" />
5
+ <h3>Générateur modulaire autonome pour projets NestJS</h3>
6
+ <p>Architecture DDD • CQRS • Hexagonal • Prisma/TypeORM • Docker/Swagger</p>
7
+
8
+ ![npm](https://img.shields.io/npm/v/@outis25/nestgen?color=crimson&style=for-the-badge)
9
+ ![nestjs](https://img.shields.io/badge/NestJS-Scaffolded-red?style=for-the-badge&logo=nestjs)
10
+ ![standalone](https://img.shields.io/badge/100%25-Autonome-brightgreen?style=for-the-badge)
11
+ ![license](https://img.shields.io/npm/l/@outis25/nestgen?color=blue&style=for-the-badge)
12
+ ![downloads](https://img.shields.io/npm/dm/@outis25/nestgen?color=green&style=for-the-badge)
13
+ </div>
14
+
15
+ ## 📋 Table des matières
16
+
17
+ - [Introduction](#-introduction)
18
+ - [Fonctionnalités](#-fonctionnalités)
19
+ - [Installation](#-installation)
20
+ - [Guide d'utilisation](#-guide-dutilisation)
21
+ - [Architecture générée](#-architecture-générée)
22
+ - [Roadmap](#-roadmap)
23
+ - [FAQ](#-faq)
24
+ - [Contribuer](#-contribuer)
25
+ - [Licence](#-licence)
26
+
27
+ ## 🚀 Introduction
28
+
29
+ **NestGen** est un générateur de code 100% autonome pour NestJS qui vous permet de créer rapidement des projets et des modules respectant les principes d'architecture avancés. Ce package n'a aucune dépendance externe et embarque tous les templates nécessaires pour générer des applications NestJS suivant les modèles Domain-Driven Design (DDD), Command Query Responsibility Segregation (CQRS) et l'architecture hexagonale.
30
+
31
+ Idéal pour les développeurs qui souhaitent maintenir une architecture propre et évolutive, NestGen accélère la phase de setup et garantit la cohérence structurelle de votre application, le tout sans nécessiter d'installation ou de configuration supplémentaire.
32
+
33
+ ## ✨ Fonctionnalités
34
+
35
+ - **100% autonome** - Aucune dépendance externe, tout est intégré
36
+ - **Zéro configuration** - Fonctionne immédiatement après installation
37
+ - **Génération complète** - Projets et modules prêts à l'emploi en quelques secondes
38
+ - **Architecture avancée** - Support intégré pour DDD, CQRS et architecture hexagonale
39
+ - **Templates embarqués** - Tous les templates sont inclus dans le package
40
+ - **Support multiple d'ORM** - TypeORM et Prisma intégrés nativement
41
+ - **DevOps ready** - Configurations Docker, Swagger et CI/CD incluses
42
+ - **Mode interactif** - Interface CLI intuitive avec prompts pour une configuration guidée
43
+
44
+ ## 📦 Installation
45
+
46
+ ```bash
47
+ npm install -g @outis25/nestgen
48
+ ```
49
+
50
+ C'est tout! Aucune configuration supplémentaire n'est nécessaire. Tous les templates et dépendances sont embarqués dans le package.
51
+
52
+ ## 🔧 Guide d'utilisation
53
+
54
+ ### Initialiser un nouveau projet
55
+
56
+ ```bash
57
+ nestgen init
58
+ ```
59
+
60
+ Cette commande lance un assistant interactif qui vous guidera à travers les étapes de configuration :
61
+ - Nom du projet
62
+ - Répertoire d'installation
63
+ - Sélection de l'ORM (TypeORM ou Prisma)
64
+ - Modules à générer automatiquement
65
+ - Options additionnelles (Git, Swagger, Docker, etc.)
66
+
67
+ ### Générer un nouveau module
68
+
69
+ ```bash
70
+ nestgen module <nom-du-module> [options]
71
+ ```
72
+
73
+ Options disponibles :
74
+ - `--orm=<typeorm|prisma>` - Spécifie l'ORM à utiliser pour ce module
75
+ - `--crud` - Génère les opérations CRUD de base
76
+ - `--path=<chemin>` - Définit un chemin personnalisé pour le module
77
+
78
+ Exemples :
79
+ ```bash
80
+ nestgen module user --orm=typeorm
81
+ nestgen module transaction --orm=prisma --crud
82
+ ```
83
+
84
+ ### Vérifier l'installation
85
+
86
+ ```bash
87
+ nestgen doctor
88
+ ```
89
+
90
+ Cette commande vérifie que :
91
+ - Le package est correctement installé
92
+ - Tous les templates embarqués sont disponibles
93
+ - Aucune dépendance n'est manquante
94
+
95
+ ## 📁 Architecture générée
96
+
97
+ NestGen génère une structure de projet suivant les meilleures pratiques d'architecture :
98
+
99
+ ```
100
+ src/app/<module>/
101
+ ├── core/ # Cœur du domaine métier
102
+ │ ├── application/ # Cas d'utilisation
103
+ │ │ ├── commands/ # Commandes CQRS
104
+ │ │ ├── events/ # Événements domaine
105
+ │ │ └── queries/ # Requêtes CQRS
106
+ │ └── domain/ # Modèle du domaine
107
+ │ ├── entities/ # Entités métier
108
+ │ └── ports/ # Interfaces pour l'hexagonal
109
+ ├── infrastructure/ # Implémentations techniques
110
+ │ ├── adapters/ # Adaptateurs pour l'hexagonal
111
+ │ └── persistences/ # Couche de persistance
112
+ │ └── repositories/ # Implémentations des repos
113
+ └── interfaces/ # Points d'entrée de l'app
114
+ ├── controllers/ # Contrôleurs REST
115
+ └── dtos/ # Objets de transfert
116
+ ```
117
+
118
+ Cette structure facilite :
119
+ - La séparation des préoccupations
120
+ - Les tests unitaires et d'intégration
121
+ - L'évolutivité du code
122
+ - Le remplacement des composants techniques
123
+
124
+ ## 🔮 Roadmap
125
+
126
+ - ✅ Génération de projet complet
127
+ - ✅ Génération de module modulaire (DDD, CQRS, Repo)
128
+ - ✅ Support Prisma et TypeORM
129
+ - ✅ Mode interactif
130
+ - ✅ Docker, Swagger, Git
131
+ - ✅ Templates intégrés
132
+ - ✅ Package 100% autonome
133
+ - ⬜ `nestgen resource <name>` (CRUD complet)
134
+ - ⬜ `nestgen destroy module <name>`
135
+ - ⬜ `nestgen preset ecommerce` (Templates d'applications)
136
+ - ⬜ `nestgen --interactive` (menu CLI avancé)
137
+ - ⬜ Support pour MongoDB et Mongoose
138
+ - ⬜ Génération de tests unitaires et d'intégration
139
+
140
+ ## ❓ FAQ
141
+
142
+ **Q: NestGen nécessite-t-il des dépendances externes ?**
143
+ R: Non, NestGen est 100% autonome. Tous les templates et outils nécessaires sont embarqués dans le package.
144
+
145
+ **Q: Puis-je utiliser NestGen avec un projet NestJS existant ?**
146
+ R: Oui, vous pouvez ajouter des modules générés par NestGen à un projet existant. La structure générée s'intègre parfaitement aux projets NestJS standards.
147
+
148
+ **Q: Comment puis-je personnaliser les templates générés ?**
149
+ R: Par défaut, NestGen utilise ses templates intégrés. Leurs structures sont optimisées pour les meilleures pratiques et ne nécessitent généralement pas de modifications.
150
+
151
+ **Q: NestGen supporte-t-il les microservices ?**
152
+ R: Pas encore nativement, mais c'est prévu dans les prochaines versions. En attendant, vous pouvez adapter manuellement la structure générée.
153
+
154
+ ## 👥 Contribuer
155
+
156
+ Les contributions sont les bienvenues ! Pour contribuer :
157
+
158
+ 1. Forkez le dépôt
159
+ 2. Créez une branche pour votre fonctionnalité (`git checkout -b feature/amazing-feature`)
160
+ 3. Commitez vos changements (`git commit -m 'feat: add amazing feature'`)
161
+ 4. Poussez vers la branche (`git push origin feature/amazing-feature`)
162
+ 5. Ouvrez une Pull Request
163
+
164
+ <!-- Veuillez consulter le fichier `CONTRIBUTING.md` pour plus de détails. -->
165
+
166
+ ## 📄 Licence
167
+
168
+ NestGen est distribué sous licence MIT. Voir le fichier `LICENSE` pour plus d'informations.
169
+
170
+ ---
171
+
172
+ <div align="center">
173
+ <p>Développé avec ❤️ par <a href="https://github.com/el-hack">@el-hack</a></p>
174
+ <p>Si vous trouvez ce projet utile, n'hésitez pas à lui donner une ⭐️ sur GitHub !</p>
175
+ </div>