create-backlist 7.3.0 → 7.4.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.
Files changed (45) hide show
  1. package/bin/index.js +483 -470
  2. package/bin/qa.js +103 -0
  3. package/package.json +7 -3
  4. package/src/analyzer.js +221 -21
  5. package/src/env-resolver.js +70 -0
  6. package/src/generators/dotnet.js +134 -134
  7. package/src/generators/java.js +248 -248
  8. package/src/generators/js.js +345 -345
  9. package/src/generators/nestjs.js +277 -277
  10. package/src/generators/python.js +86 -86
  11. package/src/project-detector.js +131 -0
  12. package/src/qa/qa-engine.js +909 -0
  13. package/src/templates/dotnet/partials/Dockerfile.ejs +27 -27
  14. package/src/templates/dotnet/partials/docker-compose.yml.ejs +33 -33
  15. package/src/templates/js-express/base/server.js +59 -59
  16. package/src/templates/js-express/partials/Dockerfile.ejs +12 -12
  17. package/src/templates/js-express/partials/auth.controller.js.ejs +66 -66
  18. package/src/templates/js-express/partials/auth.middleware.js.ejs +19 -19
  19. package/src/templates/js-express/partials/auth.routes.js.ejs +9 -9
  20. package/src/templates/js-express/partials/controller.js.ejs +53 -53
  21. package/src/templates/js-express/partials/db.js.ejs +19 -19
  22. package/src/templates/js-express/partials/docker-compose.yml.ejs +46 -46
  23. package/src/templates/js-express/partials/model.js.ejs +18 -18
  24. package/src/templates/js-express/partials/package.json.ejs +17 -17
  25. package/src/templates/js-express/partials/prisma.schema.ejs +21 -21
  26. package/src/templates/js-express/partials/routes.js.ejs +19 -19
  27. package/src/templates/js-express/partials/seeder.js.ejs +103 -103
  28. package/src/templates/js-express/partials/service.js.ejs +51 -51
  29. package/src/templates/js-express/partials/swagger.js.ejs +30 -30
  30. package/src/templates/js-express/partials/test.js.ejs +46 -46
  31. package/src/templates/nestjs/base/app.module.ts +9 -9
  32. package/src/templates/nestjs/base/main.ts +23 -23
  33. package/src/templates/nestjs/base/tsconfig.json +21 -21
  34. package/src/templates/nestjs/partials/auth.controller.ts.ejs +17 -17
  35. package/src/templates/nestjs/partials/auth.module.ts.ejs +17 -17
  36. package/src/templates/nestjs/partials/auth.service.ts.ejs +70 -70
  37. package/src/templates/nestjs/partials/controller.ts.ejs +34 -34
  38. package/src/templates/nestjs/partials/create-dto.ts.ejs +22 -22
  39. package/src/templates/nestjs/partials/jwt-guard.ts.ejs +24 -24
  40. package/src/templates/nestjs/partials/module.ts.ejs +10 -10
  41. package/src/templates/nestjs/partials/package.json.ejs +27 -27
  42. package/src/templates/nestjs/partials/prisma.service.ts.ejs +13 -13
  43. package/src/templates/nestjs/partials/schema.ts.ejs +19 -19
  44. package/src/templates/nestjs/partials/service.ts.ejs +67 -67
  45. package/src/templates/nestjs/partials/update-dto.ts.ejs +4 -4
@@ -1,278 +1,278 @@
1
- import chalk from 'chalk';
2
- import { execa } from 'execa';
3
- import fs from 'fs-extra';
4
- import path from 'node:path';
5
- import ejs from 'ejs';
6
- import { analyzeFrontend } from '../analyzer.js';
7
- import { renderAndWrite, getTemplatePath } from './template.js';
8
-
9
- function safePascalName(name) {
10
- const cleaned = String(name || 'Default')
11
- .split('?')[0]
12
- .replace(/[^a-zA-Z0-9]/g, '');
13
- if (!cleaned) return 'Default';
14
- return cleaned.charAt(0).toUpperCase() + cleaned.slice(1);
15
- }
16
-
17
- function sanitizeEndpoints(endpoints) {
18
- if (!Array.isArray(endpoints)) return [];
19
- return endpoints.map((ep) => {
20
- const rawPath = String(ep.path || ep.route || '/').split('?')[0];
21
- const parts = rawPath.split('/').filter(Boolean).filter((p) => p !== 'api' && !/^v\d+$/i.test(p));
22
- const resource = parts[0] || 'Default';
23
- const controllerName = safePascalName(resource);
24
- return { ...ep, path: rawPath, controllerName };
25
- });
26
- }
27
-
28
- export async function generateNestProject(options) {
29
- const {
30
- projectDir,
31
- projectName,
32
- frontendSrcDir,
33
- dbType,
34
- addAuth,
35
- addSeeder,
36
- extraFeatures = [],
37
- } = options;
38
-
39
- try {
40
- console.log(chalk.blue(' -> Analyzing frontend for NestJS backend...'));
41
- let endpoints = await analyzeFrontend(frontendSrcDir);
42
-
43
- if (Array.isArray(endpoints) && endpoints.length > 0) {
44
- console.log(chalk.green(` -> Found ${endpoints.length} endpoints.`));
45
- endpoints = sanitizeEndpoints(endpoints);
46
- } else {
47
- endpoints = [];
48
- console.log(chalk.yellow(' -> No API endpoints found. A basic project will be created.'));
49
- }
50
-
51
- // --- Identify Models ---
52
- const modelsToGenerate = new Map();
53
- endpoints.forEach((ep) => {
54
- if (!ep) return;
55
- const ctrl = safePascalName(ep.controllerName);
56
- if (ctrl === 'Default' || ctrl === 'Auth') return;
57
- if (!modelsToGenerate.has(ctrl)) {
58
- let fields = [];
59
- if (ep.schemaFields) {
60
- fields = Object.entries(ep.schemaFields).map(([key, type]) => ({
61
- name: key,
62
- type,
63
- isUnique: key === 'email',
64
- }));
65
- }
66
- modelsToGenerate.set(ctrl, { name: ctrl, fields });
67
- }
68
- });
69
-
70
- if (addAuth && !modelsToGenerate.has('User')) {
71
- modelsToGenerate.set('User', {
72
- name: 'User',
73
- fields: [
74
- { name: 'name', type: 'String' },
75
- { name: 'email', type: 'String', isUnique: true },
76
- { name: 'password', type: 'String' },
77
- ],
78
- });
79
- }
80
-
81
- // --- Base Scaffolding ---
82
- console.log(chalk.blue(' -> Scaffolding NestJS project...'));
83
- const srcDir = path.join(projectDir, 'src');
84
- await fs.ensureDir(srcDir);
85
-
86
- await fs.copy(getTemplatePath('nestjs/base/main.ts'), path.join(srcDir, 'main.ts'));
87
- await fs.copy(getTemplatePath('nestjs/base/app.module.ts'), path.join(srcDir, 'app.module.ts'));
88
- await fs.copy(getTemplatePath('nestjs/base/tsconfig.json'), path.join(projectDir, 'tsconfig.json'));
89
-
90
- // --- package.json ---
91
- const pkgTpl = await fs.readFile(getTemplatePath('nestjs/partials/package.json.ejs'), 'utf-8');
92
- const packageJsonContent = JSON.parse(ejs.render(pkgTpl, { projectName }));
93
-
94
- if (dbType === 'mongoose') {
95
- packageJsonContent.dependencies['@nestjs/mongoose'] = '^10.0.2';
96
- packageJsonContent.dependencies.mongoose = '^7.6.3';
97
- }
98
- if (dbType === 'prisma') {
99
- packageJsonContent.dependencies['@prisma/client'] = '^5.6.0';
100
- packageJsonContent.devDependencies.prisma = '^5.6.0';
101
- }
102
- if (addAuth) {
103
- packageJsonContent.dependencies['@nestjs/jwt'] = '^10.2.0';
104
- packageJsonContent.dependencies.bcryptjs = '^2.4.3';
105
- packageJsonContent.devDependencies['@types/bcryptjs'] = '^2.4.6';
106
- }
107
- if (addSeeder) {
108
- packageJsonContent.devDependencies['@faker-js/faker'] = '^8.3.1';
109
- packageJsonContent.scripts.seed = 'ts-node scripts/seeder.ts';
110
- }
111
-
112
- await fs.writeJson(path.join(projectDir, 'package.json'), packageJsonContent, { spaces: 2 });
113
-
114
- // --- nest-cli.json ---
115
- await fs.writeJson(path.join(projectDir, 'nest-cli.json'), {
116
- "$schema": "https://json.schemastore.org/nest-cli",
117
- "collection": "@nestjs/schematics",
118
- "sourceRoot": "src",
119
- "compilerOptions": { "deleteOutDir": true }
120
- }, { spaces: 2 });
121
-
122
- // --- Generate Modules ---
123
- const moduleImports = [];
124
- const moduleNames = [];
125
-
126
- if (modelsToGenerate.size > 0) {
127
- console.log(chalk.blue(' -> Generating NestJS modules (Controller, Service, DTO)...'));
128
-
129
- for (const [modelName, modelData] of modelsToGenerate.entries()) {
130
- if (modelName === 'Auth') continue;
131
-
132
- const moduleDir = path.join(srcDir, modelName.toLowerCase());
133
- const dtoDir = path.join(moduleDir, 'dto');
134
- await fs.ensureDir(dtoDir);
135
-
136
- const tplData = { modelName, dbType, fields: modelData.fields || [] };
137
-
138
- await renderAndWrite(
139
- getTemplatePath('nestjs/partials/module.ts.ejs'),
140
- path.join(moduleDir, `${modelName.toLowerCase()}.module.ts`),
141
- tplData
142
- );
143
- await renderAndWrite(
144
- getTemplatePath('nestjs/partials/controller.ts.ejs'),
145
- path.join(moduleDir, `${modelName.toLowerCase()}.controller.ts`),
146
- tplData
147
- );
148
- await renderAndWrite(
149
- getTemplatePath('nestjs/partials/service.ts.ejs'),
150
- path.join(moduleDir, `${modelName.toLowerCase()}.service.ts`),
151
- tplData
152
- );
153
- await renderAndWrite(
154
- getTemplatePath('nestjs/partials/create-dto.ts.ejs'),
155
- path.join(dtoDir, `create-${modelName.toLowerCase()}.dto.ts`),
156
- tplData
157
- );
158
- await renderAndWrite(
159
- getTemplatePath('nestjs/partials/update-dto.ts.ejs'),
160
- path.join(dtoDir, `update-${modelName.toLowerCase()}.dto.ts`),
161
- tplData
162
- );
163
-
164
- if (dbType === 'mongoose') {
165
- await renderAndWrite(
166
- getTemplatePath('nestjs/partials/schema.ts.ejs'),
167
- path.join(moduleDir, `${modelName.toLowerCase()}.schema.ts`),
168
- tplData
169
- );
170
- }
171
-
172
- moduleImports.push(`import { ${modelName}Module } from './${modelName.toLowerCase()}/${modelName.toLowerCase()}.module';`);
173
- moduleNames.push(`${modelName}Module`);
174
- }
175
- }
176
-
177
- // --- Prisma module ---
178
- if (dbType === 'prisma') {
179
- const prismaDir = path.join(srcDir, 'prisma');
180
- await fs.ensureDir(prismaDir);
181
- await renderAndWrite(
182
- getTemplatePath('nestjs/partials/prisma.service.ts.ejs'),
183
- path.join(prismaDir, 'prisma.service.ts'),
184
- {}
185
- );
186
- const prismaModuleContent = `import { Global, Module } from '@nestjs/common';
187
- import { PrismaService } from './prisma.service';
188
-
189
- @Global()
190
- @Module({
191
- providers: [PrismaService],
192
- exports: [PrismaService],
193
- })
194
- export class PrismaModule {}
195
- `;
196
- await fs.writeFile(path.join(prismaDir, 'prisma.module.ts'), prismaModuleContent);
197
- moduleImports.unshift("import { PrismaModule } from './prisma/prisma.module';");
198
- moduleNames.unshift('PrismaModule');
199
-
200
- await fs.ensureDir(path.join(projectDir, 'prisma'));
201
- await renderAndWrite(
202
- getTemplatePath('js-express/partials/prisma.schema.ejs'),
203
- path.join(projectDir, 'prisma', 'schema.prisma'),
204
- { models: Array.from(modelsToGenerate.values()) }
205
- );
206
- }
207
-
208
- // --- Mongoose config in AppModule ---
209
- if (dbType === 'mongoose') {
210
- moduleImports.unshift("import { MongooseModule } from '@nestjs/mongoose';");
211
- moduleNames.unshift(`MongooseModule.forRoot(process.env.MONGO_URI || 'mongodb://127.0.0.1:27017/${projectName}')`);
212
- }
213
-
214
- // --- Auth Module ---
215
- if (addAuth) {
216
- console.log(chalk.blue(' -> Generating Auth module...'));
217
- const authDir = path.join(srcDir, 'auth');
218
- await fs.ensureDir(authDir);
219
-
220
- await renderAndWrite(
221
- getTemplatePath('nestjs/partials/auth.module.ts.ejs'),
222
- path.join(authDir, 'auth.module.ts'),
223
- { dbType }
224
- );
225
- await renderAndWrite(
226
- getTemplatePath('nestjs/partials/auth.controller.ts.ejs'),
227
- path.join(authDir, 'auth.controller.ts'),
228
- { dbType }
229
- );
230
- await renderAndWrite(
231
- getTemplatePath('nestjs/partials/auth.service.ts.ejs'),
232
- path.join(authDir, 'auth.service.ts'),
233
- { dbType }
234
- );
235
- await renderAndWrite(
236
- getTemplatePath('nestjs/partials/jwt-guard.ts.ejs'),
237
- path.join(authDir, 'jwt-auth.guard.ts'),
238
- {}
239
- );
240
-
241
- moduleImports.push("import { AuthModule } from './auth/auth.module';");
242
- moduleNames.push('AuthModule');
243
- }
244
-
245
- // --- Inject into app.module.ts ---
246
- let appModuleContent = await fs.readFile(path.join(srcDir, 'app.module.ts'), 'utf-8');
247
- appModuleContent = appModuleContent.replace(
248
- '// INJECT:IMPORTS',
249
- moduleImports.join('\n')
250
- );
251
- appModuleContent = appModuleContent.replace(
252
- '// INJECT:MODULES',
253
- moduleNames.join(',\n ')
254
- );
255
- await fs.writeFile(path.join(srcDir, 'app.module.ts'), appModuleContent);
256
-
257
- // --- Install deps ---
258
- console.log(chalk.magenta(' -> Installing dependencies... This may take a moment.'));
259
- await execa('npm', ['install'], { cwd: projectDir });
260
-
261
- if (dbType === 'prisma') {
262
- console.log(chalk.blue(' -> Running `prisma generate`...'));
263
- await execa('npx', ['prisma', 'generate'], { cwd: projectDir });
264
- }
265
-
266
- // --- .env.example ---
267
- let envContent = `PORT=8000\n`;
268
- if (dbType === 'mongoose') envContent += `MONGO_URI=mongodb://127.0.0.1:27017/${projectName}\n`;
269
- if (dbType === 'prisma') envContent += `DATABASE_URL="postgresql://user:password@localhost:5432/${projectName}?schema=public"\n`;
270
- if (addAuth) envContent += 'JWT_SECRET=your_super_secret_jwt_key_12345\nJWT_EXPIRES_IN=5h\n';
271
-
272
- await fs.writeFile(path.join(projectDir, '.env.example'), envContent);
273
-
274
- console.log(chalk.green(' -> NestJS backend generation complete.'));
275
- } catch (error) {
276
- throw error;
277
- }
1
+ import chalk from 'chalk';
2
+ import { execa } from 'execa';
3
+ import fs from 'fs-extra';
4
+ import path from 'node:path';
5
+ import ejs from 'ejs';
6
+ import { analyzeFrontend } from '../analyzer.js';
7
+ import { renderAndWrite, getTemplatePath } from './template.js';
8
+
9
+ function safePascalName(name) {
10
+ const cleaned = String(name || 'Default')
11
+ .split('?')[0]
12
+ .replace(/[^a-zA-Z0-9]/g, '');
13
+ if (!cleaned) return 'Default';
14
+ return cleaned.charAt(0).toUpperCase() + cleaned.slice(1);
15
+ }
16
+
17
+ function sanitizeEndpoints(endpoints) {
18
+ if (!Array.isArray(endpoints)) return [];
19
+ return endpoints.map((ep) => {
20
+ const rawPath = String(ep.path || ep.route || '/').split('?')[0];
21
+ const parts = rawPath.split('/').filter(Boolean).filter((p) => p !== 'api' && !/^v\d+$/i.test(p));
22
+ const resource = parts[0] || 'Default';
23
+ const controllerName = safePascalName(resource);
24
+ return { ...ep, path: rawPath, controllerName };
25
+ });
26
+ }
27
+
28
+ export async function generateNestProject(options) {
29
+ const {
30
+ projectDir,
31
+ projectName,
32
+ frontendSrcDir,
33
+ dbType,
34
+ addAuth,
35
+ addSeeder,
36
+ extraFeatures = [],
37
+ } = options;
38
+
39
+ try {
40
+ console.log(chalk.blue(' -> Analyzing frontend for NestJS backend...'));
41
+ let endpoints = await analyzeFrontend(frontendSrcDir);
42
+
43
+ if (Array.isArray(endpoints) && endpoints.length > 0) {
44
+ console.log(chalk.green(` -> Found ${endpoints.length} endpoints.`));
45
+ endpoints = sanitizeEndpoints(endpoints);
46
+ } else {
47
+ endpoints = [];
48
+ console.log(chalk.yellow(' -> No API endpoints found. A basic project will be created.'));
49
+ }
50
+
51
+ // --- Identify Models ---
52
+ const modelsToGenerate = new Map();
53
+ endpoints.forEach((ep) => {
54
+ if (!ep) return;
55
+ const ctrl = safePascalName(ep.controllerName);
56
+ if (ctrl === 'Default' || ctrl === 'Auth') return;
57
+ if (!modelsToGenerate.has(ctrl)) {
58
+ let fields = [];
59
+ if (ep.schemaFields) {
60
+ fields = Object.entries(ep.schemaFields).map(([key, type]) => ({
61
+ name: key,
62
+ type,
63
+ isUnique: key === 'email',
64
+ }));
65
+ }
66
+ modelsToGenerate.set(ctrl, { name: ctrl, fields });
67
+ }
68
+ });
69
+
70
+ if (addAuth && !modelsToGenerate.has('User')) {
71
+ modelsToGenerate.set('User', {
72
+ name: 'User',
73
+ fields: [
74
+ { name: 'name', type: 'String' },
75
+ { name: 'email', type: 'String', isUnique: true },
76
+ { name: 'password', type: 'String' },
77
+ ],
78
+ });
79
+ }
80
+
81
+ // --- Base Scaffolding ---
82
+ console.log(chalk.blue(' -> Scaffolding NestJS project...'));
83
+ const srcDir = path.join(projectDir, 'src');
84
+ await fs.ensureDir(srcDir);
85
+
86
+ await fs.copy(getTemplatePath('nestjs/base/main.ts'), path.join(srcDir, 'main.ts'));
87
+ await fs.copy(getTemplatePath('nestjs/base/app.module.ts'), path.join(srcDir, 'app.module.ts'));
88
+ await fs.copy(getTemplatePath('nestjs/base/tsconfig.json'), path.join(projectDir, 'tsconfig.json'));
89
+
90
+ // --- package.json ---
91
+ const pkgTpl = await fs.readFile(getTemplatePath('nestjs/partials/package.json.ejs'), 'utf-8');
92
+ const packageJsonContent = JSON.parse(ejs.render(pkgTpl, { projectName }));
93
+
94
+ if (dbType === 'mongoose') {
95
+ packageJsonContent.dependencies['@nestjs/mongoose'] = '^10.0.2';
96
+ packageJsonContent.dependencies.mongoose = '^7.6.3';
97
+ }
98
+ if (dbType === 'prisma') {
99
+ packageJsonContent.dependencies['@prisma/client'] = '^5.6.0';
100
+ packageJsonContent.devDependencies.prisma = '^5.6.0';
101
+ }
102
+ if (addAuth) {
103
+ packageJsonContent.dependencies['@nestjs/jwt'] = '^10.2.0';
104
+ packageJsonContent.dependencies.bcryptjs = '^2.4.3';
105
+ packageJsonContent.devDependencies['@types/bcryptjs'] = '^2.4.6';
106
+ }
107
+ if (addSeeder) {
108
+ packageJsonContent.devDependencies['@faker-js/faker'] = '^8.3.1';
109
+ packageJsonContent.scripts.seed = 'ts-node scripts/seeder.ts';
110
+ }
111
+
112
+ await fs.writeJson(path.join(projectDir, 'package.json'), packageJsonContent, { spaces: 2 });
113
+
114
+ // --- nest-cli.json ---
115
+ await fs.writeJson(path.join(projectDir, 'nest-cli.json'), {
116
+ "$schema": "https://json.schemastore.org/nest-cli",
117
+ "collection": "@nestjs/schematics",
118
+ "sourceRoot": "src",
119
+ "compilerOptions": { "deleteOutDir": true }
120
+ }, { spaces: 2 });
121
+
122
+ // --- Generate Modules ---
123
+ const moduleImports = [];
124
+ const moduleNames = [];
125
+
126
+ if (modelsToGenerate.size > 0) {
127
+ console.log(chalk.blue(' -> Generating NestJS modules (Controller, Service, DTO)...'));
128
+
129
+ for (const [modelName, modelData] of modelsToGenerate.entries()) {
130
+ if (modelName === 'Auth') continue;
131
+
132
+ const moduleDir = path.join(srcDir, modelName.toLowerCase());
133
+ const dtoDir = path.join(moduleDir, 'dto');
134
+ await fs.ensureDir(dtoDir);
135
+
136
+ const tplData = { modelName, dbType, fields: modelData.fields || [] };
137
+
138
+ await renderAndWrite(
139
+ getTemplatePath('nestjs/partials/module.ts.ejs'),
140
+ path.join(moduleDir, `${modelName.toLowerCase()}.module.ts`),
141
+ tplData
142
+ );
143
+ await renderAndWrite(
144
+ getTemplatePath('nestjs/partials/controller.ts.ejs'),
145
+ path.join(moduleDir, `${modelName.toLowerCase()}.controller.ts`),
146
+ tplData
147
+ );
148
+ await renderAndWrite(
149
+ getTemplatePath('nestjs/partials/service.ts.ejs'),
150
+ path.join(moduleDir, `${modelName.toLowerCase()}.service.ts`),
151
+ tplData
152
+ );
153
+ await renderAndWrite(
154
+ getTemplatePath('nestjs/partials/create-dto.ts.ejs'),
155
+ path.join(dtoDir, `create-${modelName.toLowerCase()}.dto.ts`),
156
+ tplData
157
+ );
158
+ await renderAndWrite(
159
+ getTemplatePath('nestjs/partials/update-dto.ts.ejs'),
160
+ path.join(dtoDir, `update-${modelName.toLowerCase()}.dto.ts`),
161
+ tplData
162
+ );
163
+
164
+ if (dbType === 'mongoose') {
165
+ await renderAndWrite(
166
+ getTemplatePath('nestjs/partials/schema.ts.ejs'),
167
+ path.join(moduleDir, `${modelName.toLowerCase()}.schema.ts`),
168
+ tplData
169
+ );
170
+ }
171
+
172
+ moduleImports.push(`import { ${modelName}Module } from './${modelName.toLowerCase()}/${modelName.toLowerCase()}.module';`);
173
+ moduleNames.push(`${modelName}Module`);
174
+ }
175
+ }
176
+
177
+ // --- Prisma module ---
178
+ if (dbType === 'prisma') {
179
+ const prismaDir = path.join(srcDir, 'prisma');
180
+ await fs.ensureDir(prismaDir);
181
+ await renderAndWrite(
182
+ getTemplatePath('nestjs/partials/prisma.service.ts.ejs'),
183
+ path.join(prismaDir, 'prisma.service.ts'),
184
+ {}
185
+ );
186
+ const prismaModuleContent = `import { Global, Module } from '@nestjs/common';
187
+ import { PrismaService } from './prisma.service';
188
+
189
+ @Global()
190
+ @Module({
191
+ providers: [PrismaService],
192
+ exports: [PrismaService],
193
+ })
194
+ export class PrismaModule {}
195
+ `;
196
+ await fs.writeFile(path.join(prismaDir, 'prisma.module.ts'), prismaModuleContent);
197
+ moduleImports.unshift("import { PrismaModule } from './prisma/prisma.module';");
198
+ moduleNames.unshift('PrismaModule');
199
+
200
+ await fs.ensureDir(path.join(projectDir, 'prisma'));
201
+ await renderAndWrite(
202
+ getTemplatePath('js-express/partials/prisma.schema.ejs'),
203
+ path.join(projectDir, 'prisma', 'schema.prisma'),
204
+ { models: Array.from(modelsToGenerate.values()) }
205
+ );
206
+ }
207
+
208
+ // --- Mongoose config in AppModule ---
209
+ if (dbType === 'mongoose') {
210
+ moduleImports.unshift("import { MongooseModule } from '@nestjs/mongoose';");
211
+ moduleNames.unshift(`MongooseModule.forRoot(process.env.MONGO_URI || 'mongodb://127.0.0.1:27017/${projectName}')`);
212
+ }
213
+
214
+ // --- Auth Module ---
215
+ if (addAuth) {
216
+ console.log(chalk.blue(' -> Generating Auth module...'));
217
+ const authDir = path.join(srcDir, 'auth');
218
+ await fs.ensureDir(authDir);
219
+
220
+ await renderAndWrite(
221
+ getTemplatePath('nestjs/partials/auth.module.ts.ejs'),
222
+ path.join(authDir, 'auth.module.ts'),
223
+ { dbType }
224
+ );
225
+ await renderAndWrite(
226
+ getTemplatePath('nestjs/partials/auth.controller.ts.ejs'),
227
+ path.join(authDir, 'auth.controller.ts'),
228
+ { dbType }
229
+ );
230
+ await renderAndWrite(
231
+ getTemplatePath('nestjs/partials/auth.service.ts.ejs'),
232
+ path.join(authDir, 'auth.service.ts'),
233
+ { dbType }
234
+ );
235
+ await renderAndWrite(
236
+ getTemplatePath('nestjs/partials/jwt-guard.ts.ejs'),
237
+ path.join(authDir, 'jwt-auth.guard.ts'),
238
+ {}
239
+ );
240
+
241
+ moduleImports.push("import { AuthModule } from './auth/auth.module';");
242
+ moduleNames.push('AuthModule');
243
+ }
244
+
245
+ // --- Inject into app.module.ts ---
246
+ let appModuleContent = await fs.readFile(path.join(srcDir, 'app.module.ts'), 'utf-8');
247
+ appModuleContent = appModuleContent.replace(
248
+ '// INJECT:IMPORTS',
249
+ moduleImports.join('\n')
250
+ );
251
+ appModuleContent = appModuleContent.replace(
252
+ '// INJECT:MODULES',
253
+ moduleNames.join(',\n ')
254
+ );
255
+ await fs.writeFile(path.join(srcDir, 'app.module.ts'), appModuleContent);
256
+
257
+ // --- Install deps ---
258
+ console.log(chalk.magenta(' -> Installing dependencies... This may take a moment.'));
259
+ await execa('npm', ['install'], { cwd: projectDir });
260
+
261
+ if (dbType === 'prisma') {
262
+ console.log(chalk.blue(' -> Running `prisma generate`...'));
263
+ await execa('npx', ['prisma', 'generate'], { cwd: projectDir });
264
+ }
265
+
266
+ // --- .env.example ---
267
+ let envContent = `PORT=8000\n`;
268
+ if (dbType === 'mongoose') envContent += `MONGO_URI=mongodb://127.0.0.1:27017/${projectName}\n`;
269
+ if (dbType === 'prisma') envContent += `DATABASE_URL="postgresql://user:password@localhost:5432/${projectName}?schema=public"\n`;
270
+ if (addAuth) envContent += 'JWT_SECRET=your_super_secret_jwt_key_12345\nJWT_EXPIRES_IN=5h\n';
271
+
272
+ await fs.writeFile(path.join(projectDir, '.env.example'), envContent);
273
+
274
+ console.log(chalk.green(' -> NestJS backend generation complete.'));
275
+ } catch (error) {
276
+ throw error;
277
+ }
278
278
  }