nestcraftx 0.2.4 β 0.2.6
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/.gitattributes +6 -0
- package/.github/ISSUE_TEMPLATE/bug_report.md +33 -0
- package/.github/ISSUE_TEMPLATE/feature_request.md +19 -0
- package/.github/ISSUE_TEMPLATE/pull_request_template.md +24 -0
- package/CHANGELOG.fr.md +97 -97
- package/CHANGELOG.md +98 -98
- package/CLI_USAGE.fr.md +331 -331
- package/CLI_USAGE.md +364 -364
- package/DEMO.fr.md +292 -292
- package/DEMO.md +294 -294
- package/LICENSE +21 -21
- package/MIGRATION_GUIDE.fr.md +127 -127
- package/MIGRATION_GUIDE.md +124 -124
- package/QUICK_START.fr.md +152 -152
- package/QUICK_START.md +169 -169
- package/README.fr.md +653 -659
- package/SECURITY.md +10 -0
- package/bin/nestcraft.js +84 -64
- package/commands/demo.js +333 -330
- package/commands/generate.js +93 -0
- package/commands/generateConf.js +91 -0
- package/commands/help.js +78 -78
- package/commands/info.js +48 -48
- package/commands/new.js +338 -335
- package/commands/start.js +19 -19
- package/commands/test.js +7 -7
- package/package.json +41 -41
- package/readme.md +638 -643
- package/utils/cliParser.js +133 -76
- package/utils/colors.js +62 -62
- package/utils/configs/configureDocker.js +120 -120
- package/utils/configs/setupCleanArchitecture.js +563 -557
- package/utils/configs/setupLightArchitecture.js +701 -660
- package/utils/envGenerator.js +122 -122
- package/utils/file-utils/packageJsonUtils.js +49 -55
- package/utils/file-utils/saveProjectConfig.js +36 -0
- package/utils/fullModeInput.js +607 -607
- package/utils/generators/application/dtoUpdater.js +54 -0
- package/utils/generators/cleanModuleGenerator.js +475 -0
- package/utils/generators/database/setupDatabase.js +31 -0
- package/utils/generators/domain/entityUpdater.js +78 -0
- package/utils/generators/infrastructure/mapperUpdater.js +65 -0
- package/utils/generators/lightModuleGenerator.js +131 -0
- package/utils/generators/relation/relation.engine.js +64 -0
- package/utils/interactive/askEntityInputs.js +165 -0
- package/utils/lightModeInput.js +460 -460
- package/utils/loggers/logError.js +7 -7
- package/utils/loggers/logInfo.js +7 -7
- package/utils/loggers/logSuccess.js +7 -7
- package/utils/loggers/logWarning.js +7 -7
- package/utils/setups/orms/typeOrmSetup.js +630 -630
- package/utils/setups/projectSetup.js +46 -46
- package/utils/setups/setupAuth.js +973 -926
- package/utils/setups/setupDatabase.js +75 -75
- package/utils/setups/setupLogger.js +69 -59
- package/utils/setups/setupMongoose.js +377 -432
- package/utils/setups/setupPrisma.js +802 -630
- package/utils/setups/setupSwagger.js +97 -88
- package/utils/shell.js +32 -32
- package/utils/spinner.js +57 -57
- package/utils/systemCheck.js +124 -124
- package/utils/userInput.js +421 -421
- package/utils/utils.js +2197 -1762
|
@@ -1,432 +1,377 @@
|
|
|
1
|
-
const { runCommand } = require("../shell");
|
|
2
|
-
const path = require("path");
|
|
3
|
-
const {
|
|
4
|
-
createFile,
|
|
5
|
-
updateFile,
|
|
6
|
-
createDirectory,
|
|
7
|
-
capitalize,
|
|
8
|
-
} = require("../userInput");
|
|
9
|
-
const { logSuccess } = require("../loggers/logSuccess");
|
|
10
|
-
const { logInfo } = require("../loggers/logInfo");
|
|
11
|
-
const { updatePackageJson } = require("../file-utils/packageJsonUtils");
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
)
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
}
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
path
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
}
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
.
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
console.log('β
${entity.name} data inserted');
|
|
379
|
-
`;
|
|
380
|
-
})
|
|
381
|
-
.join("\n")}
|
|
382
|
-
|
|
383
|
-
console.log('π Seeding finished successfully.');
|
|
384
|
-
await mongoose.disconnect();
|
|
385
|
-
} catch (err) {
|
|
386
|
-
console.error('β Error during seeding:', err);
|
|
387
|
-
process.exit(1);
|
|
388
|
-
}
|
|
389
|
-
}
|
|
390
|
-
|
|
391
|
-
seed();
|
|
392
|
-
`;
|
|
393
|
-
}
|
|
394
|
-
|
|
395
|
-
/**
|
|
396
|
-
* Generates sample data for each entity, handling advanced types.
|
|
397
|
-
*/
|
|
398
|
-
function generateSampleData(entity) {
|
|
399
|
-
const fields = entity.fields || [];
|
|
400
|
-
const sampleObj = fields
|
|
401
|
-
.map((f) => {
|
|
402
|
-
// For 'string[]', 'number[]', 'Date[]', etc. types
|
|
403
|
-
if (f.type.endsWith("[]")) {
|
|
404
|
-
const baseType = f.type.slice(0, -2);
|
|
405
|
-
if (baseType === "string" || baseType === "text")
|
|
406
|
-
return `${f.name}: ['${f.name}_item_1', '${f.name}_item_2']`;
|
|
407
|
-
if (baseType === "number" || baseType === "decimal")
|
|
408
|
-
return `${f.name}: [10, 20]`;
|
|
409
|
-
if (baseType === "Date") return `${f.name}: [new Date(), new Date()]`;
|
|
410
|
-
return `${f.name}: []`;
|
|
411
|
-
}
|
|
412
|
-
|
|
413
|
-
if (f.name.toLowerCase().includes("password")) {
|
|
414
|
-
return `${f.name}: await bcrypt.hash('password123', 10)`;
|
|
415
|
-
}
|
|
416
|
-
if (["string", "text", "uuid"].includes(f.type.toLowerCase()))
|
|
417
|
-
return `${f.name}: '${f.name}_example'`;
|
|
418
|
-
if (["number", "decimal", "int"].includes(f.type.toLowerCase()))
|
|
419
|
-
return `${f.name}: ${Math.floor(Math.random() * 100)}`;
|
|
420
|
-
if (f.type === "boolean") return `${f.name}: true`;
|
|
421
|
-
if (f.type === "date") return `${f.name}: new Date()`;
|
|
422
|
-
if (["json", "object"].includes(f.type.toLowerCase()))
|
|
423
|
-
return `${f.name}: { key: 'value', count: 42 }`;
|
|
424
|
-
|
|
425
|
-
return `${f.name}: null`;
|
|
426
|
-
})
|
|
427
|
-
.join(",\n ");
|
|
428
|
-
|
|
429
|
-
return `{ ${sampleObj} }`;
|
|
430
|
-
}
|
|
431
|
-
|
|
432
|
-
module.exports = { setupMongoose };
|
|
1
|
+
const { runCommand } = require("../shell");
|
|
2
|
+
const path = require("path");
|
|
3
|
+
const {
|
|
4
|
+
createFile,
|
|
5
|
+
updateFile,
|
|
6
|
+
createDirectory,
|
|
7
|
+
capitalize,
|
|
8
|
+
} = require("../userInput");
|
|
9
|
+
const { logSuccess } = require("../loggers/logSuccess");
|
|
10
|
+
const { logInfo } = require("../loggers/logInfo");
|
|
11
|
+
const { updatePackageJson } = require("../file-utils/packageJsonUtils");
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Maps generic entity types to Mongoose schema types.
|
|
15
|
+
* @param {string} type - Generic type (e.g., 'string', 'number', 'Date', 'string[]', 'MonEnum')
|
|
16
|
+
* @returns {string} The corresponding Mongoose type.
|
|
17
|
+
*/
|
|
18
|
+
function mapTypeToMongoose(type) {
|
|
19
|
+
// Handles the case of arrays (e.g., 'string[]')
|
|
20
|
+
if (type.endsWith("[]")) {
|
|
21
|
+
const innerType = type.slice(0, -2);
|
|
22
|
+
const innerMapping = mapTypeToMongoose(innerType); // Recursive // Returns the type enclosed in brackets, Mongoose understands this // Note: Remove "mongoose.Schema.Types." for the array of Mixed
|
|
23
|
+
return innerMapping.replace("mongoose.Schema.Types.", "") === "Mixed"
|
|
24
|
+
? "[mongoose.Schema.Types.Mixed]"
|
|
25
|
+
: `[${innerMapping}]`;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
const typeLower = type.toLowerCase();
|
|
29
|
+
|
|
30
|
+
switch (typeLower) {
|
|
31
|
+
case "string":
|
|
32
|
+
case "text":
|
|
33
|
+
case "uuid":
|
|
34
|
+
return "String";
|
|
35
|
+
|
|
36
|
+
case "number":
|
|
37
|
+
case "decimal":
|
|
38
|
+
case "int":
|
|
39
|
+
return "Number";
|
|
40
|
+
|
|
41
|
+
case "boolean":
|
|
42
|
+
return "Boolean";
|
|
43
|
+
|
|
44
|
+
case "date":
|
|
45
|
+
return "Date";
|
|
46
|
+
|
|
47
|
+
case "json":
|
|
48
|
+
case "object": // Uses Mixed for unstructured JSON objects
|
|
49
|
+
return "mongoose.Schema.Types.Mixed";
|
|
50
|
+
|
|
51
|
+
default: // Case of a custom Enum type (e.g., 'StatusEnum')
|
|
52
|
+
return "String";
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
async function setupMongoose(inputs) {
|
|
57
|
+
/* logWarning(
|
|
58
|
+
`Mongoose integration is currently in Beta (v0.2.x). \nSome manual import fixes and corrections might be required in the generated files.`
|
|
59
|
+
); */
|
|
60
|
+
|
|
61
|
+
const isFull = inputs.mode === "full";
|
|
62
|
+
|
|
63
|
+
logInfo("π¦ Installing Mongoose and @nestjs/mongoose...");
|
|
64
|
+
|
|
65
|
+
await runCommand(
|
|
66
|
+
`${inputs.packageManager} install @nestjs/mongoose mongoose`,
|
|
67
|
+
"Mongoose and its dependencies successfully installed!"
|
|
68
|
+
);
|
|
69
|
+
|
|
70
|
+
// --- Base Configuration (app.module.ts and .env) --- // Generating the .env file
|
|
71
|
+
const envContent = `
|
|
72
|
+
MONGO_URI=${inputs.dbConfig.MONGO_URI}
|
|
73
|
+
MONGO_DB=${inputs.dbConfig.MONGO_DB}
|
|
74
|
+
`.trim();
|
|
75
|
+
await createFile({ path: ".env", contente: envContent });
|
|
76
|
+
|
|
77
|
+
const appModulePath = path.join("src", "app.module.ts");
|
|
78
|
+
const mongooseImport = `import { MongooseModule } from '@nestjs/mongoose';`;
|
|
79
|
+
const mongooseForRoot = `
|
|
80
|
+
MongooseModule.forRoot(process.env.MONGO_URI || "mongodb://localhost/test", {
|
|
81
|
+
dbName: process.env.MONGO_DB,
|
|
82
|
+
}),`;
|
|
83
|
+
|
|
84
|
+
// 1. Adding MongooseModule import
|
|
85
|
+
await updateFile({
|
|
86
|
+
path: appModulePath,
|
|
87
|
+
pattern: /import {[\s\S]*?} from '@nestjs\/config';/,
|
|
88
|
+
replacement: (match) => `${match}\n${mongooseImport}`,
|
|
89
|
+
});
|
|
90
|
+
|
|
91
|
+
// 2. Adding MongooseModule.forRoot() configuration
|
|
92
|
+
const importsPattern =
|
|
93
|
+
/imports:\s*\[[\s\S]*?ConfigModule\.forRoot\([\s\S]*?\),/;
|
|
94
|
+
await updateFile({
|
|
95
|
+
path: appModulePath,
|
|
96
|
+
pattern: importsPattern,
|
|
97
|
+
replacement: (match) => `${match}${mongooseForRoot}`,
|
|
98
|
+
});
|
|
99
|
+
|
|
100
|
+
// --- Generating Mongoose Entities (Schemas) ---
|
|
101
|
+
logInfo("π Generating Mongoose schemas (src/schemas)...");
|
|
102
|
+
|
|
103
|
+
let forFeatureImports = [];
|
|
104
|
+
|
|
105
|
+
for (const entity of inputs.entitiesData.entities) {
|
|
106
|
+
const entityName = capitalize(entity.name);
|
|
107
|
+
const entityNameLower = entity.name.toLowerCase();
|
|
108
|
+
const schemaName = `${entityName}Schema`;
|
|
109
|
+
const interfaceName = `${entityName}Document`;
|
|
110
|
+
|
|
111
|
+
let fieldsContent = "";
|
|
112
|
+
let extraImports = "";
|
|
113
|
+
// On commence avec mongoose dΓ©jΓ importΓ© pour Γ©viter les erreurs "namespace not found"
|
|
114
|
+
let mongooseImportCode =
|
|
115
|
+
"import { Prop, Schema, SchemaFactory } from '@nestjs/mongoose';\nimport * as mongoose from 'mongoose';\n";
|
|
116
|
+
|
|
117
|
+
// --- Gestion du Role (Γviter le doublon) ---
|
|
118
|
+
// --- Gestion du Role (Γviter le doublon) ---
|
|
119
|
+
if (entityNameLower === "user") {
|
|
120
|
+
extraImports += isFull
|
|
121
|
+
? `import { Role } from 'src/user/domain/enums/role.enum';\n`
|
|
122
|
+
: `import { Role } from 'src/common/enums/role.enum';\n`;
|
|
123
|
+
|
|
124
|
+
fieldsContent += `
|
|
125
|
+
@Prop({ type: String, enum: Role, default: Role.USER })
|
|
126
|
+
role: Role;
|
|
127
|
+
`;
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
for (const field of entity.fields) {
|
|
131
|
+
// π‘οΈ CORRECTION : On saute le champ s'il a dΓ©jΓ Γ©tΓ© traitΓ© manuellement (ex: role)
|
|
132
|
+
if (entityNameLower === "user" && field.name.toLowerCase() === "role")
|
|
133
|
+
continue;
|
|
134
|
+
|
|
135
|
+
// π‘οΈ CORRECTION : On Γ©vite de gΓ©nΓ©rer les champs de relations ici car ils sont gΓ©rΓ©s plus bas
|
|
136
|
+
// Si le champ se termine par 'Id' ou s'il a le mΓͺme nom qu'une entitΓ© connue
|
|
137
|
+
const isRelationField = inputs.entitiesData.entities.some(
|
|
138
|
+
(e) =>
|
|
139
|
+
field.name.toLowerCase() === e.name.toLowerCase() ||
|
|
140
|
+
field.name.toLowerCase() === e.name.toLowerCase() + "id"
|
|
141
|
+
);
|
|
142
|
+
if (isRelationField) continue;
|
|
143
|
+
|
|
144
|
+
const mongooseType = mapTypeToMongoose(field.type);
|
|
145
|
+
const tsType = field.type;
|
|
146
|
+
|
|
147
|
+
const isRequired =
|
|
148
|
+
field.name.toLowerCase() !== "isactive" &&
|
|
149
|
+
field.name.toLowerCase() !== "password";
|
|
150
|
+
const requiredOption = isRequired ? ", required: true" : "";
|
|
151
|
+
|
|
152
|
+
// Import des enums partagΓ©s si nΓ©cessaire
|
|
153
|
+
if (
|
|
154
|
+
mongooseType === "String" &&
|
|
155
|
+
tsType.charAt(0) === tsType.charAt(0).toUpperCase() &&
|
|
156
|
+
tsType !== "Role"
|
|
157
|
+
) {
|
|
158
|
+
extraImports += `import { ${tsType} } from '../shared/enums/${tsType.toLowerCase()}.enum';\n`;
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
fieldsContent += `
|
|
162
|
+
@Prop({ type: ${mongooseType}${requiredOption} })
|
|
163
|
+
${field.name}: ${tsType};
|
|
164
|
+
`;
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
// --- Final Generation ---
|
|
168
|
+
const content = `${mongooseImportCode}${extraImports}
|
|
169
|
+
export type ${interfaceName} = ${entityName} & mongoose.Document;
|
|
170
|
+
|
|
171
|
+
@Schema({ timestamps: true })
|
|
172
|
+
export class ${entityName} {
|
|
173
|
+
${fieldsContent}
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
export const ${schemaName} = SchemaFactory.createForClass(${entityName});
|
|
177
|
+
`;
|
|
178
|
+
|
|
179
|
+
forFeatureImports.push(
|
|
180
|
+
`{ name: ${entityName}.name, schema: ${schemaName} }`
|
|
181
|
+
);
|
|
182
|
+
}
|
|
183
|
+
// --- Final Update of app.module.ts --- //
|
|
184
|
+
// 3. Adding MongooseModule.forFeature([...])
|
|
185
|
+
const forFeatureBlock = `MongooseModule.forFeature([${forFeatureImports.join(
|
|
186
|
+
", "
|
|
187
|
+
)}]),`;
|
|
188
|
+
|
|
189
|
+
await updateFile({
|
|
190
|
+
path: appModulePath,
|
|
191
|
+
pattern: new RegExp(mongooseForRoot.trim().replace(/[\n\r]/g, "\\s*"), "g"),
|
|
192
|
+
replacement: (match) => `${match}\n\t${forFeatureBlock}`,
|
|
193
|
+
});
|
|
194
|
+
|
|
195
|
+
if (inputs.isDemo) {
|
|
196
|
+
// The generateSampleData function must be adapted for 'new Date()' usage and Mongoose types
|
|
197
|
+
await setupMongooseSeeding(inputs);
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
logSuccess(
|
|
201
|
+
"Mongoose configuration complete. Schemas are generated in src/schemas!"
|
|
202
|
+
);
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
async function setupMongooseSeeding(inputs) {
|
|
206
|
+
logInfo("βοΈ Configuring seeding for Mongoose..."); // --- Dependencies ---
|
|
207
|
+
|
|
208
|
+
const mongooseDevDeps = ["ts-node", "@types/node", "@types/bcrypt"];
|
|
209
|
+
await runCommand(
|
|
210
|
+
`${inputs.packageManager} add -D ${mongooseDevDeps.join(" ")}`,
|
|
211
|
+
"β Failed to install Mongoose seeding dependencies"
|
|
212
|
+
);
|
|
213
|
+
await runCommand(
|
|
214
|
+
`${inputs.packageManager} install bcrypt`,
|
|
215
|
+
"β Failed to install bcrypt"
|
|
216
|
+
);
|
|
217
|
+
|
|
218
|
+
// --- Scripts in package.json ---
|
|
219
|
+
const mongooseScripts = {
|
|
220
|
+
seed: "ts-node src/database/seed.ts",
|
|
221
|
+
};
|
|
222
|
+
await updatePackageJson(inputs, mongooseScripts);
|
|
223
|
+
|
|
224
|
+
// --- Creating seed.ts file ---
|
|
225
|
+
await createDirectory("src/database");
|
|
226
|
+
const seedTsContent = await generateMongooseSeedContent(
|
|
227
|
+
inputs.entitiesData.entities,
|
|
228
|
+
inputs.mode
|
|
229
|
+
);
|
|
230
|
+
|
|
231
|
+
await createFile({
|
|
232
|
+
path: `src/database/seed.ts`,
|
|
233
|
+
contente: seedTsContent,
|
|
234
|
+
});
|
|
235
|
+
|
|
236
|
+
logSuccess("Mongoose seeding configured.");
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
async function generateMongooseSeedContent(entities, mode) {
|
|
240
|
+
const hasUser = entities.some((e) => e.name.toLowerCase() === "user");
|
|
241
|
+
const hasPost = entities.some((e) => e.name.toLowerCase() === "post");
|
|
242
|
+
const hasComment = entities.some((e) => e.name.toLowerCase() === "comment");
|
|
243
|
+
|
|
244
|
+
return `
|
|
245
|
+
import mongoose from 'mongoose';
|
|
246
|
+
import * as bcrypt from 'bcrypt';
|
|
247
|
+
import * as dotenv from 'dotenv';
|
|
248
|
+
dotenv.config();
|
|
249
|
+
|
|
250
|
+
${entities
|
|
251
|
+
.map((e) => {
|
|
252
|
+
const name = capitalize(e.name);
|
|
253
|
+
const lowName = e.name.toLowerCase();
|
|
254
|
+
let path;
|
|
255
|
+
|
|
256
|
+
if (lowName === "session") {
|
|
257
|
+
path =
|
|
258
|
+
mode === "full"
|
|
259
|
+
? `../auth/infrastructure/persistence/mongoose/${lowName}.schema`
|
|
260
|
+
: `../auth/persistence/${lowName}.schema`;
|
|
261
|
+
} else {
|
|
262
|
+
path =
|
|
263
|
+
mode === "full"
|
|
264
|
+
? `../${lowName}/infrastructure/persistence/mongoose/${lowName}.schema`
|
|
265
|
+
: `../${lowName}/entities/${lowName}.schema`;
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
return `import { ${name}Schema } from '${path}';`;
|
|
269
|
+
})
|
|
270
|
+
.join("\n")}
|
|
271
|
+
|
|
272
|
+
async function seed() {
|
|
273
|
+
const MONGO_URI = process.env.MONGO_URI || 'mongodb://localhost:27017/nestcraft_db';
|
|
274
|
+
|
|
275
|
+
try {
|
|
276
|
+
await mongoose.connect(MONGO_URI);
|
|
277
|
+
console.log('π± Starting Mongoose seeding...');
|
|
278
|
+
|
|
279
|
+
// --- MODELS ---
|
|
280
|
+
${entities
|
|
281
|
+
.map(
|
|
282
|
+
(e) =>
|
|
283
|
+
`const ${capitalize(e.name)}Model = mongoose.model('${capitalize(
|
|
284
|
+
e.name
|
|
285
|
+
)}', ${capitalize(e.name)}Schema);`
|
|
286
|
+
)
|
|
287
|
+
.join("\n ")}
|
|
288
|
+
|
|
289
|
+
// --- CLEANUP ---
|
|
290
|
+
await Promise.all([${entities
|
|
291
|
+
.map((e) => `${capitalize(e.name)}Model.deleteMany({})`)
|
|
292
|
+
.join(", ")}]);
|
|
293
|
+
|
|
294
|
+
// --- 1. ADMIN & DEMO USERS ---
|
|
295
|
+
const salt = await bcrypt.genSalt(10);
|
|
296
|
+
const hashedPassword = await bcrypt.hash('password123', salt);
|
|
297
|
+
|
|
298
|
+
const users = await ${hasUser ? "UserModel" : "null"}.insertMany([
|
|
299
|
+
{ email: 'admin@nestcraft.com', password: hashedPassword, username: 'NestCraftAdmin', role: 'SUPER_ADMIN', isActive: true },
|
|
300
|
+
{ email: 'emma.jones@demo.com', password: hashedPassword, username: 'EmmaJones', isActive: true },
|
|
301
|
+
{ email: 'lucas.martin@demo.com', password: hashedPassword, username: 'LucasMartin', isActive: true },
|
|
302
|
+
{ email: 'sophia.bernard@demo.com', password: hashedPassword, username: 'SophiaBernard', isActive: true },
|
|
303
|
+
{ email: 'alexandre.dubois@demo.com', password: hashedPassword, username: 'AlexandreDubois', isActive: true },
|
|
304
|
+
{ email: 'chloe.moreau@demo.com', password: hashedPassword, username: 'ChloeMoreau', isActive: true },
|
|
305
|
+
]);
|
|
306
|
+
console.log(\`π₯ \${users.length} users created\`);
|
|
307
|
+
|
|
308
|
+
${
|
|
309
|
+
hasPost
|
|
310
|
+
? `
|
|
311
|
+
// --- 2. BLOG POSTS ---
|
|
312
|
+
const posts = await PostModel.insertMany([
|
|
313
|
+
{
|
|
314
|
+
title: 'The Basics of NestJS for Modern Developers',
|
|
315
|
+
content: 'Discover how to build a robust and maintainable API with NestJS...',
|
|
316
|
+
published: true,
|
|
317
|
+
userId: users[1]._id,
|
|
318
|
+
},
|
|
319
|
+
{
|
|
320
|
+
title: 'How to Secure Your API with JWT',
|
|
321
|
+
content: 'JWT authentication is a standard for securing APIs...',
|
|
322
|
+
published: true,
|
|
323
|
+
userId: users[2]._id,
|
|
324
|
+
},
|
|
325
|
+
{
|
|
326
|
+
title: 'Optimizing Node.js API Performance',
|
|
327
|
+
content: 'Discover best practices for improving performance...',
|
|
328
|
+
published: true,
|
|
329
|
+
userId: users[3]._id,
|
|
330
|
+
},
|
|
331
|
+
{
|
|
332
|
+
title: 'Introduction to Prisma ORM',
|
|
333
|
+
content: 'Prisma is a modern ORM that simplifies interactions with the database...',
|
|
334
|
+
published: true,
|
|
335
|
+
userId: users[4]._id,
|
|
336
|
+
},
|
|
337
|
+
{
|
|
338
|
+
title: 'Understanding Clean Architecture',
|
|
339
|
+
content: 'Clean Architecture helps separate business logic from the rest of the code...',
|
|
340
|
+
published: false,
|
|
341
|
+
userId: users[0]._id,
|
|
342
|
+
},
|
|
343
|
+
]);
|
|
344
|
+
console.log('π 5 Articles created');
|
|
345
|
+
`
|
|
346
|
+
: ""
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
${
|
|
350
|
+
hasComment && hasPost
|
|
351
|
+
? `
|
|
352
|
+
// --- 3. DEMO COMMENTS ---
|
|
353
|
+
await CommentModel.insertMany([
|
|
354
|
+
{ content: 'Excellent article! I was able to apply these tips directly to my NestJS project.', postId: posts[0]._id, userId: users[2]._id },
|
|
355
|
+
{ content: 'Very clear and well explained, thank you for sharing about Prisma π', postId: posts[3]._id, userId: users[0]._id },
|
|
356
|
+
{ content: "I didn't know about JWT before this article, it's a real revelation.", postId: posts[1]._id, userId: users[4]._id },
|
|
357
|
+
{ content: 'Clean Architecture always seemed blurry to me, this article finally enlightened me.', postId: posts[4]._id, userId: users[1]._id },
|
|
358
|
+
{ content: 'Thanks for the content! I would like to see a complete tutorial with NestJS + Prisma.', postId: posts[2]._id, userId: users[3]._id },
|
|
359
|
+
]);
|
|
360
|
+
console.log('π¬ 5 Comments created');
|
|
361
|
+
`
|
|
362
|
+
: ""
|
|
363
|
+
}
|
|
364
|
+
|
|
365
|
+
console.log('β
Mongoose seeding finished successfully! π');
|
|
366
|
+
} catch (err) {
|
|
367
|
+
console.error('β Seeding error:', err);
|
|
368
|
+
} finally {
|
|
369
|
+
await mongoose.disconnect();
|
|
370
|
+
}
|
|
371
|
+
}
|
|
372
|
+
|
|
373
|
+
seed();
|
|
374
|
+
`;
|
|
375
|
+
}
|
|
376
|
+
|
|
377
|
+
module.exports = { setupMongoose };
|