@diagramers/cli 1.0.25 → 1.0.27
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +239 -388
- package/dist/commands/extend.d.ts.map +1 -1
- package/dist/commands/extend.js +49 -10
- package/dist/commands/extend.js.map +1 -1
- package/dist/commands/init.js +1 -1
- package/dist/commands/init.js.map +1 -1
- package/dist/services/project-extender.d.ts +17 -0
- package/dist/services/project-extender.d.ts.map +1 -1
- package/dist/services/project-extender.js +677 -1
- package/dist/services/project-extender.js.map +1 -1
- package/dist/services/project-initializer.d.ts.map +1 -1
- package/dist/services/project-initializer.js +4 -3
- package/dist/services/project-initializer.js.map +1 -1
- package/dist/services/template-processor.js +1 -1
- package/dist/services/template-processor.js.map +1 -1
- package/package.json +1 -1
@@ -75,8 +75,9 @@ class ProjectExtender {
|
|
75
75
|
];
|
76
76
|
}
|
77
77
|
async listFeatures() {
|
78
|
-
console.log(chalk_1.default.blue('
|
78
|
+
console.log(chalk_1.default.blue('�� Available features and templates:'));
|
79
79
|
console.log('');
|
80
|
+
console.log(chalk_1.default.green('🔧 Features:'));
|
80
81
|
this.features.forEach(feature => {
|
81
82
|
console.log(chalk_1.default.green(` ${feature.name}`));
|
82
83
|
console.log(chalk_1.default.gray(` ${feature.description}`));
|
@@ -85,6 +86,18 @@ class ProjectExtender {
|
|
85
86
|
}
|
86
87
|
console.log('');
|
87
88
|
});
|
89
|
+
console.log(chalk_1.default.blue('📦 Module Templates:'));
|
90
|
+
console.log(chalk_1.default.green(' --module <name> --crud --fields field1,field2'));
|
91
|
+
console.log(chalk_1.default.gray(' Generate complete module with CRUD operations'));
|
92
|
+
console.log('');
|
93
|
+
console.log(chalk_1.default.blue('🗄️ Database Templates:'));
|
94
|
+
console.log(chalk_1.default.green(' --table <name> --fields field1,field2 --type mongodb'));
|
95
|
+
console.log(chalk_1.default.gray(' Generate database table/collection schema'));
|
96
|
+
console.log('');
|
97
|
+
console.log(chalk_1.default.blue('🔗 Relation Templates:'));
|
98
|
+
console.log(chalk_1.default.green(' --relation <name> --type mongodb'));
|
99
|
+
console.log(chalk_1.default.gray(' Generate database relations and references'));
|
100
|
+
console.log('');
|
88
101
|
}
|
89
102
|
async addFeature(featureName) {
|
90
103
|
const feature = this.features.find(f => f.name === featureName);
|
@@ -108,6 +121,38 @@ class ProjectExtender {
|
|
108
121
|
console.log(chalk_1.default.green(`✅ Feature '${featureName}' added successfully!`));
|
109
122
|
console.log(chalk_1.default.blue(`📝 Main configuration updated to include ${featureName} feature`));
|
110
123
|
}
|
124
|
+
async generateModule(moduleName, options = {}) {
|
125
|
+
const projectPath = process.cwd();
|
126
|
+
// Check if module already exists
|
127
|
+
const modulePath = path.join(projectPath, 'src', 'modules', moduleName);
|
128
|
+
if (await fs.pathExists(modulePath)) {
|
129
|
+
throw new Error(`Module '${moduleName}' already exists in this project.`);
|
130
|
+
}
|
131
|
+
console.log(chalk_1.default.blue(`📁 Creating module structure for: ${moduleName}`));
|
132
|
+
// Create module directory structure
|
133
|
+
await this.createModuleStructure(projectPath, moduleName, options);
|
134
|
+
// Generate CRUD operations if requested
|
135
|
+
if (options.crud) {
|
136
|
+
await this.generateCRUDOperations(projectPath, moduleName, options);
|
137
|
+
}
|
138
|
+
// Update main application to include the module
|
139
|
+
await this.registerModule(projectPath, moduleName);
|
140
|
+
console.log(chalk_1.default.green(`✅ Module '${moduleName}' generated successfully!`));
|
141
|
+
}
|
142
|
+
async generateTable(tableName, options = {}) {
|
143
|
+
const projectPath = process.cwd();
|
144
|
+
console.log(chalk_1.default.blue(`🗄️ Generating table schema for: ${tableName}`));
|
145
|
+
// Create table schema based on database type
|
146
|
+
await this.createTableSchema(projectPath, tableName, options);
|
147
|
+
console.log(chalk_1.default.green(`✅ Table '${tableName}' generated successfully!`));
|
148
|
+
}
|
149
|
+
async generateRelations(relationName, options = {}) {
|
150
|
+
const projectPath = process.cwd();
|
151
|
+
console.log(chalk_1.default.blue(`🔗 Generating relations for: ${relationName}`));
|
152
|
+
// Create relation definitions
|
153
|
+
await this.createRelations(projectPath, relationName, options);
|
154
|
+
console.log(chalk_1.default.green(`✅ Relations '${relationName}' generated successfully!`));
|
155
|
+
}
|
111
156
|
async createFeatureStructure(projectPath, feature) {
|
112
157
|
const featurePath = path.join(projectPath, 'src', 'features', feature.name);
|
113
158
|
// Create basic feature structure
|
@@ -195,6 +240,637 @@ export interface ${this.capitalizeFirst(feature.name)}Data {
|
|
195
240
|
`;
|
196
241
|
await fs.writeFile(path.join(featurePath, 'types', `${feature.name}-types.ts`), typesContent);
|
197
242
|
}
|
243
|
+
async createModuleStructure(projectPath, moduleName, options) {
|
244
|
+
const modulePath = path.join(projectPath, 'src', 'modules', moduleName);
|
245
|
+
// Create module directory structure
|
246
|
+
const structure = {
|
247
|
+
'entities': 'Data models and interfaces',
|
248
|
+
'schemas': 'Database schemas and validation',
|
249
|
+
'services': 'Business logic and data access',
|
250
|
+
'controllers': 'HTTP request handlers',
|
251
|
+
'routes': 'API route definitions'
|
252
|
+
};
|
253
|
+
for (const [dir, description] of Object.entries(structure)) {
|
254
|
+
const dirPath = path.join(modulePath, dir);
|
255
|
+
await fs.ensureDir(dirPath);
|
256
|
+
// Create index file
|
257
|
+
const indexContent = `// ${description} for ${moduleName} module
|
258
|
+
export * from './${moduleName}.${dir.slice(0, -1)}';
|
259
|
+
`;
|
260
|
+
await fs.writeFile(path.join(dirPath, 'index.ts'), indexContent);
|
261
|
+
}
|
262
|
+
// Create main entity
|
263
|
+
await this.createEntity(modulePath, moduleName, options);
|
264
|
+
// Create schema
|
265
|
+
await this.createSchema(modulePath, moduleName, options);
|
266
|
+
// Create service
|
267
|
+
await this.createService(modulePath, moduleName, options);
|
268
|
+
// Create controller
|
269
|
+
await this.createController(modulePath, moduleName, options);
|
270
|
+
// Create routes
|
271
|
+
await this.createRoutes(modulePath, moduleName, options);
|
272
|
+
}
|
273
|
+
async createEntity(modulePath, moduleName, options) {
|
274
|
+
const entityName = this.capitalizeFirst(moduleName);
|
275
|
+
const fields = options.fields || ['name', 'description'];
|
276
|
+
const entityContent = `import { BaseEntity } from '../../../shared/types/base-entity';
|
277
|
+
|
278
|
+
export interface I${entityName} extends BaseEntity {
|
279
|
+
${fields.map((field) => ` ${field}: string;`).join('\n')}
|
280
|
+
}
|
281
|
+
|
282
|
+
export interface I${entityName}Create {
|
283
|
+
${fields.map((field) => ` ${field}: string;`).join('\n')}
|
284
|
+
}
|
285
|
+
|
286
|
+
export interface I${entityName}Update {
|
287
|
+
${fields.map((field) => ` ${field}?: string;`).join('\n')}
|
288
|
+
}
|
289
|
+
`;
|
290
|
+
await fs.writeFile(path.join(modulePath, 'entities', `${moduleName}.entity.ts`), entityContent);
|
291
|
+
}
|
292
|
+
async createSchema(modulePath, moduleName, options) {
|
293
|
+
const entityName = this.capitalizeFirst(moduleName);
|
294
|
+
const fields = options.fields || ['name', 'description'];
|
295
|
+
const schemaContent = `import mongoose, { Schema, Document } from 'mongoose';
|
296
|
+
import { I${entityName} } from '../entities/${moduleName}.entity';
|
297
|
+
|
298
|
+
export interface I${entityName}Document extends Omit<I${entityName}, '_id'>, Document {}
|
299
|
+
|
300
|
+
const ${moduleName}Schema = new Schema({
|
301
|
+
${fields.map((field) => ` ${field}: {
|
302
|
+
type: String,
|
303
|
+
required: true,
|
304
|
+
trim: true
|
305
|
+
}`).join(',\n')}
|
306
|
+
}, {
|
307
|
+
timestamps: true,
|
308
|
+
toJSON: {
|
309
|
+
transform: function(doc, ret) {
|
310
|
+
return ret;
|
311
|
+
}
|
312
|
+
}
|
313
|
+
});
|
314
|
+
|
315
|
+
// Indexes
|
316
|
+
${fields.map((field) => `${moduleName}Schema.index({ ${field}: 1 });`).join('\n')}
|
317
|
+
|
318
|
+
export const ${entityName}Model = mongoose.model<I${entityName}Document>('${entityName}', ${moduleName}Schema);
|
319
|
+
`;
|
320
|
+
await fs.writeFile(path.join(modulePath, 'schemas', `${moduleName}.schema.ts`), schemaContent);
|
321
|
+
}
|
322
|
+
async createService(modulePath, moduleName, options) {
|
323
|
+
const entityName = this.capitalizeFirst(moduleName);
|
324
|
+
const serviceContent = `import { Result } from '../../../shared/types/result';
|
325
|
+
import { ${entityName}Model, I${entityName}Document } from '../schemas/${moduleName}.schema';
|
326
|
+
import { I${entityName}, I${entityName}Create, I${entityName}Update } from '../entities/${moduleName}.entity';
|
327
|
+
|
328
|
+
export class ${entityName}Service {
|
329
|
+
/**
|
330
|
+
* Get all ${moduleName}s
|
331
|
+
*/
|
332
|
+
async getAll(): Promise<Result<I${entityName}[]>> {
|
333
|
+
try {
|
334
|
+
const ${moduleName}s = await ${entityName}Model.find({ status: 1 }).lean();
|
335
|
+
const converted${entityName}s = ${moduleName}s.map(${moduleName} => ({
|
336
|
+
...${moduleName},
|
337
|
+
_id: ${moduleName}._id?.toString() || ''
|
338
|
+
})) as I${entityName}[];
|
339
|
+
return Result.success(converted${entityName}s);
|
340
|
+
} catch (error: any) {
|
341
|
+
return Result.error('Failed to fetch ${moduleName}s', error.message);
|
342
|
+
}
|
343
|
+
}
|
344
|
+
|
345
|
+
/**
|
346
|
+
* Get ${moduleName} by ID
|
347
|
+
*/
|
348
|
+
async getById(id: string): Promise<Result<I${entityName} | null>> {
|
349
|
+
try {
|
350
|
+
const ${moduleName} = await ${entityName}Model.findOne({ _id: id, status: 1 });
|
351
|
+
if (!${moduleName}) {
|
352
|
+
return Result.error('${entityName} not found', '${entityName} with the specified ID does not exist');
|
353
|
+
}
|
354
|
+
const ${moduleName}Obj = ${moduleName}.toObject();
|
355
|
+
const converted${entityName} = {
|
356
|
+
...${moduleName}Obj,
|
357
|
+
_id: ${moduleName}Obj._id?.toString() || ''
|
358
|
+
} as I${entityName};
|
359
|
+
return Result.success(converted${entityName});
|
360
|
+
} catch (error: any) {
|
361
|
+
return Result.error('Failed to fetch ${moduleName}', error.message);
|
362
|
+
}
|
363
|
+
}
|
364
|
+
|
365
|
+
/**
|
366
|
+
* Create new ${moduleName}
|
367
|
+
*/
|
368
|
+
async create(${moduleName}Data: I${entityName}Create): Promise<Result<I${entityName}>> {
|
369
|
+
try {
|
370
|
+
const ${moduleName} = new ${entityName}Model({
|
371
|
+
...${moduleName}Data,
|
372
|
+
status: 1
|
373
|
+
});
|
374
|
+
|
375
|
+
const saved${entityName} = await ${moduleName}.save();
|
376
|
+
const ${moduleName}Obj = saved${entityName}.toObject();
|
377
|
+
|
378
|
+
const converted${entityName} = {
|
379
|
+
...${moduleName}Obj,
|
380
|
+
_id: ${moduleName}Obj._id?.toString() || ''
|
381
|
+
} as I${entityName};
|
382
|
+
|
383
|
+
return Result.success(converted${entityName});
|
384
|
+
} catch (error: any) {
|
385
|
+
return Result.error('Failed to create ${moduleName}', error.message);
|
386
|
+
}
|
387
|
+
}
|
388
|
+
|
389
|
+
/**
|
390
|
+
* Update ${moduleName}
|
391
|
+
*/
|
392
|
+
async update(id: string, ${moduleName}Data: I${entityName}Update): Promise<Result<I${entityName} | null>> {
|
393
|
+
try {
|
394
|
+
const ${moduleName} = await ${entityName}Model.findOne({ _id: id, status: 1 });
|
395
|
+
if (!${moduleName}) {
|
396
|
+
return Result.error('${entityName} not found', '${entityName} with the specified ID does not exist');
|
397
|
+
}
|
398
|
+
|
399
|
+
Object.assign(${moduleName}, ${moduleName}Data);
|
400
|
+
const updated${entityName} = await ${moduleName}.save();
|
401
|
+
|
402
|
+
const ${moduleName}Obj = updated${entityName}.toObject();
|
403
|
+
|
404
|
+
const converted${entityName} = {
|
405
|
+
...${moduleName}Obj,
|
406
|
+
_id: ${moduleName}Obj._id?.toString() || ''
|
407
|
+
} as I${entityName};
|
408
|
+
|
409
|
+
return Result.success(converted${entityName});
|
410
|
+
} catch (error: any) {
|
411
|
+
return Result.error('Failed to update ${moduleName}', error.message);
|
412
|
+
}
|
413
|
+
}
|
414
|
+
|
415
|
+
/**
|
416
|
+
* Delete ${moduleName} (soft delete)
|
417
|
+
*/
|
418
|
+
async delete(id: string): Promise<Result<boolean>> {
|
419
|
+
try {
|
420
|
+
const ${moduleName} = await ${entityName}Model.findOne({ _id: id, status: 1 });
|
421
|
+
if (!${moduleName}) {
|
422
|
+
return Result.error('${entityName} not found', '${entityName} with the specified ID does not exist');
|
423
|
+
}
|
424
|
+
|
425
|
+
${moduleName}.status = 0;
|
426
|
+
await ${moduleName}.save();
|
427
|
+
|
428
|
+
return Result.success(true);
|
429
|
+
} catch (error: any) {
|
430
|
+
return Result.error('Failed to delete ${moduleName}', error.message);
|
431
|
+
}
|
432
|
+
}
|
433
|
+
}
|
434
|
+
`;
|
435
|
+
await fs.writeFile(path.join(modulePath, 'services', `${moduleName}.service.ts`), serviceContent);
|
436
|
+
}
|
437
|
+
async createController(modulePath, moduleName, options) {
|
438
|
+
const entityName = this.capitalizeFirst(moduleName);
|
439
|
+
const controllerContent = `import { Request, Response } from 'express';
|
440
|
+
import { ${entityName}Service } from '../services/${moduleName}.service';
|
441
|
+
import { I${entityName}Create, I${entityName}Update } from '../entities/${moduleName}.entity';
|
442
|
+
|
443
|
+
/**
|
444
|
+
* @swagger
|
445
|
+
* components:
|
446
|
+
* schemas:
|
447
|
+
* ${entityName}:
|
448
|
+
* type: object
|
449
|
+
* properties:
|
450
|
+
* _id:
|
451
|
+
* type: string
|
452
|
+
* name:
|
453
|
+
* type: string
|
454
|
+
* description:
|
455
|
+
* type: string
|
456
|
+
* createdAt:
|
457
|
+
* type: string
|
458
|
+
* format: date-time
|
459
|
+
* updatedAt:
|
460
|
+
* type: string
|
461
|
+
* format: date-time
|
462
|
+
*/
|
463
|
+
|
464
|
+
export class ${entityName}Controller {
|
465
|
+
constructor(private service: ${entityName}Service) {}
|
466
|
+
|
467
|
+
/**
|
468
|
+
* @swagger
|
469
|
+
* /api/${moduleName}s:
|
470
|
+
* get:
|
471
|
+
* summary: Get all ${moduleName}s
|
472
|
+
* tags: [${entityName}s]
|
473
|
+
* responses:
|
474
|
+
* 200:
|
475
|
+
* description: List of ${moduleName}s
|
476
|
+
* content:
|
477
|
+
* application/json:
|
478
|
+
* schema:
|
479
|
+
* type: object
|
480
|
+
* properties:
|
481
|
+
* Data:
|
482
|
+
* type: array
|
483
|
+
* items:
|
484
|
+
* $ref: '#/components/schemas/${entityName}'
|
485
|
+
* StatusCode:
|
486
|
+
* type: number
|
487
|
+
* Message:
|
488
|
+
* type: string
|
489
|
+
*/
|
490
|
+
async getAll(req: Request, res: Response): Promise<void> {
|
491
|
+
try {
|
492
|
+
const result = await this.service.getAll();
|
493
|
+
res.status(result.StatusCode === 1000 ? 200 : 400).json(result);
|
494
|
+
} catch (error: any) {
|
495
|
+
res.status(500).json({ error: error.message });
|
496
|
+
}
|
497
|
+
}
|
498
|
+
|
499
|
+
/**
|
500
|
+
* @swagger
|
501
|
+
* /api/${moduleName}s/{id}:
|
502
|
+
* get:
|
503
|
+
* summary: Get ${moduleName} by ID
|
504
|
+
* tags: [${entityName}s]
|
505
|
+
* parameters:
|
506
|
+
* - in: path
|
507
|
+
* name: id
|
508
|
+
* required: true
|
509
|
+
* schema:
|
510
|
+
* type: string
|
511
|
+
* responses:
|
512
|
+
* 200:
|
513
|
+
* description: ${entityName} details
|
514
|
+
* content:
|
515
|
+
* application/json:
|
516
|
+
* schema:
|
517
|
+
* type: object
|
518
|
+
* properties:
|
519
|
+
* Data:
|
520
|
+
* $ref: '#/components/schemas/${entityName}'
|
521
|
+
* StatusCode:
|
522
|
+
* type: number
|
523
|
+
* Message:
|
524
|
+
* type: string
|
525
|
+
*/
|
526
|
+
async getById(req: Request, res: Response): Promise<void> {
|
527
|
+
try {
|
528
|
+
const { id } = req.params;
|
529
|
+
const result = await this.service.getById(id);
|
530
|
+
res.status(result.StatusCode === 1000 ? 200 : 400).json(result);
|
531
|
+
} catch (error: any) {
|
532
|
+
res.status(500).json({ error: error.message });
|
533
|
+
}
|
534
|
+
}
|
535
|
+
|
536
|
+
/**
|
537
|
+
* @swagger
|
538
|
+
* /api/${moduleName}s:
|
539
|
+
* post:
|
540
|
+
* summary: Create new ${moduleName}
|
541
|
+
* tags: [${entityName}s]
|
542
|
+
* requestBody:
|
543
|
+
* required: true
|
544
|
+
* content:
|
545
|
+
* application/json:
|
546
|
+
* schema:
|
547
|
+
* type: object
|
548
|
+
* properties:
|
549
|
+
* name:
|
550
|
+
* type: string
|
551
|
+
* description:
|
552
|
+
* type: string
|
553
|
+
* responses:
|
554
|
+
* 201:
|
555
|
+
* description: ${entityName} created successfully
|
556
|
+
* content:
|
557
|
+
* application/json:
|
558
|
+
* schema:
|
559
|
+
* type: object
|
560
|
+
* properties:
|
561
|
+
* Data:
|
562
|
+
* $ref: '#/components/schemas/${entityName}'
|
563
|
+
* StatusCode:
|
564
|
+
* type: number
|
565
|
+
* Message:
|
566
|
+
* type: string
|
567
|
+
*/
|
568
|
+
async create(req: Request, res: Response): Promise<void> {
|
569
|
+
try {
|
570
|
+
const ${moduleName}Data: I${entityName}Create = req.body;
|
571
|
+
const result = await this.service.create(${moduleName}Data);
|
572
|
+
res.status(result.StatusCode === 1000 ? 201 : 400).json(result);
|
573
|
+
} catch (error: any) {
|
574
|
+
res.status(500).json({ error: error.message });
|
575
|
+
}
|
576
|
+
}
|
577
|
+
|
578
|
+
/**
|
579
|
+
* @swagger
|
580
|
+
* /api/${moduleName}s/{id}:
|
581
|
+
* put:
|
582
|
+
* summary: Update ${moduleName}
|
583
|
+
* tags: [${entityName}s]
|
584
|
+
* parameters:
|
585
|
+
* - in: path
|
586
|
+
* name: id
|
587
|
+
* required: true
|
588
|
+
* schema:
|
589
|
+
* type: string
|
590
|
+
* requestBody:
|
591
|
+
* required: true
|
592
|
+
* content:
|
593
|
+
* application/json:
|
594
|
+
* schema:
|
595
|
+
* type: object
|
596
|
+
* properties:
|
597
|
+
* name:
|
598
|
+
* type: string
|
599
|
+
* description:
|
600
|
+
* type: string
|
601
|
+
* responses:
|
602
|
+
* 200:
|
603
|
+
* description: ${entityName} updated successfully
|
604
|
+
* content:
|
605
|
+
* application/json:
|
606
|
+
* schema:
|
607
|
+
* type: object
|
608
|
+
* properties:
|
609
|
+
* Data:
|
610
|
+
* $ref: '#/components/schemas/${entityName}'
|
611
|
+
* StatusCode:
|
612
|
+
* type: number
|
613
|
+
* Message:
|
614
|
+
* type: string
|
615
|
+
*/
|
616
|
+
async update(req: Request, res: Response): Promise<void> {
|
617
|
+
try {
|
618
|
+
const { id } = req.params;
|
619
|
+
const ${moduleName}Data: I${entityName}Update = req.body;
|
620
|
+
const result = await this.service.update(id, ${moduleName}Data);
|
621
|
+
res.status(result.StatusCode === 1000 ? 200 : 400).json(result);
|
622
|
+
} catch (error: any) {
|
623
|
+
res.status(500).json({ error: error.message });
|
624
|
+
}
|
625
|
+
}
|
626
|
+
|
627
|
+
/**
|
628
|
+
* @swagger
|
629
|
+
* /api/${moduleName}s/{id}:
|
630
|
+
* delete:
|
631
|
+
* summary: Delete ${moduleName}
|
632
|
+
* tags: [${entityName}s]
|
633
|
+
* parameters:
|
634
|
+
* - in: path
|
635
|
+
* name: id
|
636
|
+
* required: true
|
637
|
+
* schema:
|
638
|
+
* type: string
|
639
|
+
* responses:
|
640
|
+
* 200:
|
641
|
+
* description: ${entityName} deleted successfully
|
642
|
+
* content:
|
643
|
+
* application/json:
|
644
|
+
* schema:
|
645
|
+
* type: object
|
646
|
+
* properties:
|
647
|
+
* Data:
|
648
|
+
* type: boolean
|
649
|
+
* StatusCode:
|
650
|
+
* type: number
|
651
|
+
* Message:
|
652
|
+
* type: string
|
653
|
+
*/
|
654
|
+
async delete(req: Request, res: Response): Promise<void> {
|
655
|
+
try {
|
656
|
+
const { id } = req.params;
|
657
|
+
const result = await this.service.delete(id);
|
658
|
+
res.status(result.StatusCode === 1000 ? 200 : 400).json(result);
|
659
|
+
} catch (error: any) {
|
660
|
+
res.status(500).json({ error: error.message });
|
661
|
+
}
|
662
|
+
}
|
663
|
+
}
|
664
|
+
`;
|
665
|
+
await fs.writeFile(path.join(modulePath, 'controllers', `${moduleName}.controller.ts`), controllerContent);
|
666
|
+
}
|
667
|
+
async createRoutes(modulePath, moduleName, options) {
|
668
|
+
const entityName = this.capitalizeFirst(moduleName);
|
669
|
+
const routesContent = `import { Router } from 'express';
|
670
|
+
import { ${entityName}Controller } from '../controllers/${moduleName}.controller';
|
671
|
+
import { ${entityName}Service } from '../services/${moduleName}.service';
|
672
|
+
|
673
|
+
const router = Router();
|
674
|
+
const service = new ${entityName}Service();
|
675
|
+
const controller = new ${entityName}Controller(service);
|
676
|
+
|
677
|
+
// ${entityName} routes
|
678
|
+
router.get('/', controller.getAll.bind(controller));
|
679
|
+
router.get('/:id', controller.getById.bind(controller));
|
680
|
+
router.post('/', controller.create.bind(controller));
|
681
|
+
router.put('/:id', controller.update.bind(controller));
|
682
|
+
router.delete('/:id', controller.delete.bind(controller));
|
683
|
+
|
684
|
+
export default router;
|
685
|
+
`;
|
686
|
+
await fs.writeFile(path.join(modulePath, 'routes', `${moduleName}.routes.ts`), routesContent);
|
687
|
+
}
|
688
|
+
async generateCRUDOperations(projectPath, moduleName, options) {
|
689
|
+
console.log(chalk_1.default.blue(`🔄 Generating CRUD operations for ${moduleName}...`));
|
690
|
+
// CRUD operations are already included in the service and controller generation
|
691
|
+
}
|
692
|
+
async registerModule(projectPath, moduleName) {
|
693
|
+
console.log(chalk_1.default.blue(`📝 Registering ${moduleName} module in main application...`));
|
694
|
+
// Update main routes index to include the new module
|
695
|
+
const routesIndexPath = path.join(projectPath, 'src', 'modules', 'index.ts');
|
696
|
+
if (await fs.pathExists(routesIndexPath)) {
|
697
|
+
let content = await fs.readFile(routesIndexPath, 'utf8');
|
698
|
+
// Add import for the new module
|
699
|
+
const importStatement = `import ${moduleName}Routes from './${moduleName}/routes/${moduleName}.routes';`;
|
700
|
+
if (!content.includes(importStatement)) {
|
701
|
+
// Find the last import statement and add after it
|
702
|
+
const importRegex = /import.*from.*['"];?\s*$/gm;
|
703
|
+
const matches = [...content.matchAll(importRegex)];
|
704
|
+
if (matches.length > 0) {
|
705
|
+
const lastImport = matches[matches.length - 1];
|
706
|
+
const insertIndex = lastImport.index + lastImport[0].length;
|
707
|
+
content = content.slice(0, insertIndex) + '\n' + importStatement + content.slice(insertIndex);
|
708
|
+
}
|
709
|
+
}
|
710
|
+
// Add route registration
|
711
|
+
const routeRegistration = `app.use('/api/${moduleName}s', ${moduleName}Routes);`;
|
712
|
+
if (!content.includes(routeRegistration)) {
|
713
|
+
// Find where routes are registered and add after
|
714
|
+
const routeRegex = /app\.use\(.*\);?\s*$/gm;
|
715
|
+
const matches = [...content.matchAll(routeRegex)];
|
716
|
+
if (matches.length > 0) {
|
717
|
+
const lastRoute = matches[matches.length - 1];
|
718
|
+
const insertIndex = lastRoute.index + lastRoute[0].length;
|
719
|
+
content = content.slice(0, insertIndex) + '\n' + routeRegistration + content.slice(insertIndex);
|
720
|
+
}
|
721
|
+
}
|
722
|
+
await fs.writeFile(routesIndexPath, content);
|
723
|
+
}
|
724
|
+
}
|
725
|
+
async createTableSchema(projectPath, tableName, options) {
|
726
|
+
const entityName = this.capitalizeFirst(tableName);
|
727
|
+
const fields = options.fields || ['name', 'description'];
|
728
|
+
const dbType = options.type || 'mongodb';
|
729
|
+
if (dbType === 'mongodb') {
|
730
|
+
await this.createMongoDBSchema(projectPath, tableName, fields);
|
731
|
+
}
|
732
|
+
else {
|
733
|
+
await this.createSQLSchema(projectPath, tableName, fields, dbType);
|
734
|
+
}
|
735
|
+
}
|
736
|
+
async createMongoDBSchema(projectPath, tableName, fields) {
|
737
|
+
const schemaPath = path.join(projectPath, 'src', 'schemas', `${tableName}.schema.ts`);
|
738
|
+
await fs.ensureDir(path.dirname(schemaPath));
|
739
|
+
const entityName = this.capitalizeFirst(tableName);
|
740
|
+
const schemaContent = `import mongoose, { Schema, Document } from 'mongoose';
|
741
|
+
|
742
|
+
export interface I${entityName}Document extends Document {
|
743
|
+
${fields.map(field => ` ${field}: string;`).join('\n')}
|
744
|
+
createdAt: Date;
|
745
|
+
updatedAt: Date;
|
746
|
+
}
|
747
|
+
|
748
|
+
const ${tableName}Schema = new Schema({
|
749
|
+
${fields.map(field => ` ${field}: {
|
750
|
+
type: String,
|
751
|
+
required: true,
|
752
|
+
trim: true
|
753
|
+
}`).join(',\n')}
|
754
|
+
}, {
|
755
|
+
timestamps: true
|
756
|
+
});
|
757
|
+
|
758
|
+
// Indexes
|
759
|
+
${fields.map(field => `${tableName}Schema.index({ ${field}: 1 });`).join('\n')}
|
760
|
+
|
761
|
+
export const ${entityName}Model = mongoose.model<I${entityName}Document>('${entityName}', ${tableName}Schema);
|
762
|
+
`;
|
763
|
+
await fs.writeFile(schemaPath, schemaContent);
|
764
|
+
}
|
765
|
+
async createSQLSchema(projectPath, tableName, fields, dbType) {
|
766
|
+
const schemaPath = path.join(projectPath, 'src', 'schemas', `${tableName}.sql`);
|
767
|
+
await fs.ensureDir(path.dirname(schemaPath));
|
768
|
+
const entityName = this.capitalizeFirst(tableName);
|
769
|
+
const schemaContent = `-- ${entityName} table schema for ${dbType.toUpperCase()}
|
770
|
+
CREATE TABLE ${tableName}s (
|
771
|
+
id ${dbType === 'postgres' ? 'SERIAL' : 'INT AUTO_INCREMENT'} PRIMARY KEY,
|
772
|
+
${fields.map(field => ` ${field} VARCHAR(255) NOT NULL,`).join('\n')}
|
773
|
+
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
774
|
+
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
|
775
|
+
);
|
776
|
+
|
777
|
+
-- Indexes
|
778
|
+
${fields.map(field => `CREATE INDEX idx_${tableName}_${field} ON ${tableName}s(${field});`).join('\n')}
|
779
|
+
`;
|
780
|
+
await fs.writeFile(schemaPath, schemaContent);
|
781
|
+
}
|
782
|
+
async createRelations(projectPath, relationName, options) {
|
783
|
+
const dbType = options.type || 'mongodb';
|
784
|
+
const relationPath = path.join(projectPath, 'src', 'schemas', 'relations', `${relationName}.relations.ts`);
|
785
|
+
await fs.ensureDir(path.dirname(relationPath));
|
786
|
+
if (dbType === 'mongodb') {
|
787
|
+
await this.createMongoDBRelations(relationPath, relationName);
|
788
|
+
}
|
789
|
+
else {
|
790
|
+
await this.createSQLRelations(relationPath, relationName, dbType);
|
791
|
+
}
|
792
|
+
}
|
793
|
+
async createMongoDBRelations(relationPath, relationName) {
|
794
|
+
const relationContent = `// MongoDB relations for ${relationName}
|
795
|
+
import mongoose from 'mongoose';
|
796
|
+
|
797
|
+
// Example: One-to-Many relationship
|
798
|
+
// const userSchema = new mongoose.Schema({
|
799
|
+
// name: String,
|
800
|
+
// email: String,
|
801
|
+
// posts: [{ type: mongoose.Schema.Types.ObjectId, ref: 'Post' }]
|
802
|
+
// });
|
803
|
+
|
804
|
+
// const postSchema = new mongoose.Schema({
|
805
|
+
// title: String,
|
806
|
+
// content: String,
|
807
|
+
// author: { type: mongoose.Schema.Types.ObjectId, ref: 'User' }
|
808
|
+
// });
|
809
|
+
|
810
|
+
// Example: Many-to-Many relationship
|
811
|
+
// const categorySchema = new mongoose.Schema({
|
812
|
+
// name: String,
|
813
|
+
// products: [{ type: mongoose.Schema.Types.ObjectId, ref: 'Product' }]
|
814
|
+
// });
|
815
|
+
|
816
|
+
// const productSchema = new mongoose.Schema({
|
817
|
+
// name: String,
|
818
|
+
// price: Number,
|
819
|
+
// categories: [{ type: mongoose.Schema.Types.ObjectId, ref: 'Category' }]
|
820
|
+
// });
|
821
|
+
|
822
|
+
export const ${relationName}Relations = {
|
823
|
+
// Define your relations here
|
824
|
+
// User: userSchema,
|
825
|
+
// Post: postSchema,
|
826
|
+
// Category: categorySchema,
|
827
|
+
// Product: productSchema
|
828
|
+
};
|
829
|
+
`;
|
830
|
+
await fs.writeFile(relationPath, relationContent);
|
831
|
+
}
|
832
|
+
async createSQLRelations(relationPath, relationName, dbType) {
|
833
|
+
const relationContent = `-- SQL relations for ${relationName} (${dbType.toUpperCase()})
|
834
|
+
|
835
|
+
-- Example: One-to-Many relationship
|
836
|
+
-- CREATE TABLE users (
|
837
|
+
-- id ${dbType === 'postgres' ? 'SERIAL' : 'INT AUTO_INCREMENT'} PRIMARY KEY,
|
838
|
+
-- name VARCHAR(255) NOT NULL,
|
839
|
+
-- email VARCHAR(255) UNIQUE NOT NULL
|
840
|
+
-- );
|
841
|
+
|
842
|
+
-- CREATE TABLE posts (
|
843
|
+
-- id ${dbType === 'postgres' ? 'SERIAL' : 'INT AUTO_INCREMENT'} PRIMARY KEY,
|
844
|
+
-- title VARCHAR(255) NOT NULL,
|
845
|
+
-- content TEXT,
|
846
|
+
-- user_id INT,
|
847
|
+
-- FOREIGN KEY (user_id) REFERENCES users(id)
|
848
|
+
-- );
|
849
|
+
|
850
|
+
-- Example: Many-to-Many relationship
|
851
|
+
-- CREATE TABLE categories (
|
852
|
+
-- id ${dbType === 'postgres' ? 'SERIAL' : 'INT AUTO_INCREMENT'} PRIMARY KEY,
|
853
|
+
-- name VARCHAR(255) NOT NULL
|
854
|
+
-- );
|
855
|
+
|
856
|
+
-- CREATE TABLE products (
|
857
|
+
-- id ${dbType === 'postgres' ? 'SERIAL' : 'INT AUTO_INCREMENT'} PRIMARY KEY,
|
858
|
+
-- name VARCHAR(255) NOT NULL,
|
859
|
+
-- price DECIMAL(10,2)
|
860
|
+
-- );
|
861
|
+
|
862
|
+
-- CREATE TABLE product_categories (
|
863
|
+
-- product_id INT,
|
864
|
+
-- category_id INT,
|
865
|
+
-- PRIMARY KEY (product_id, category_id),
|
866
|
+
-- FOREIGN KEY (product_id) REFERENCES products(id),
|
867
|
+
-- FOREIGN KEY (category_id) REFERENCES categories(id)
|
868
|
+
-- );
|
869
|
+
|
870
|
+
-- Add your relations here
|
871
|
+
`;
|
872
|
+
await fs.writeFile(relationPath, relationContent);
|
873
|
+
}
|
198
874
|
async addDependencies(dependencies) {
|
199
875
|
console.log(chalk_1.default.blue('📦 Installing dependencies...'));
|
200
876
|
// This would typically run npm install with the dependencies
|