@diagramers/cli 1.0.13 → 1.0.14

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.
@@ -0,0 +1,3 @@
1
+ import { Command } from 'commander';
2
+ export declare function apiCommand(program: Command): Command;
3
+ //# sourceMappingURL=api.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"api.d.ts","sourceRoot":"","sources":["../../src/commands/api.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAKpC,wBAAgB,UAAU,CAAC,OAAO,EAAE,OAAO,WAoC1C"}
@@ -0,0 +1,46 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.apiCommand = apiCommand;
7
+ const api_generator_1 = require("../services/api-generator");
8
+ const template_processor_1 = require("../services/template-processor");
9
+ const chalk_1 = __importDefault(require("chalk"));
10
+ function apiCommand(program) {
11
+ const api = program
12
+ .command('api')
13
+ .description('API-specific commands for diagramers projects');
14
+ // Generate module command
15
+ api
16
+ .command('generate:module <name>')
17
+ .description('Generate a new module with entity, schema, service, controller, and routes')
18
+ .action(async (name) => {
19
+ try {
20
+ console.log(chalk_1.default.blue(`🚀 Generating module: ${name}`));
21
+ await (0, api_generator_1.generateModule)(name);
22
+ console.log(chalk_1.default.green(`✅ Module '${name}' generated successfully!`));
23
+ }
24
+ catch (error) {
25
+ console.error(chalk_1.default.red(`❌ Error generating module: ${error.message}`));
26
+ process.exit(1);
27
+ }
28
+ });
29
+ // Process template command
30
+ api
31
+ .command('process:template <name>')
32
+ .description('Process template files for a new project')
33
+ .action(async (name) => {
34
+ try {
35
+ console.log(chalk_1.default.blue(`🔧 Processing template for project: ${name}`));
36
+ await (0, template_processor_1.processTemplate)(name);
37
+ console.log(chalk_1.default.green(`✅ Template processing completed for '${name}'!`));
38
+ }
39
+ catch (error) {
40
+ console.error(chalk_1.default.red(`❌ Error processing template: ${error.message}`));
41
+ process.exit(1);
42
+ }
43
+ });
44
+ return api;
45
+ }
46
+ //# sourceMappingURL=api.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"api.js","sourceRoot":"","sources":["../../src/commands/api.ts"],"names":[],"mappings":";;;;;AAKA,gCAoCC;AAxCD,6DAA2D;AAC3D,uEAAiE;AACjE,kDAA0B;AAE1B,SAAgB,UAAU,CAAC,OAAgB;IACzC,MAAM,GAAG,GAAG,OAAO;SAChB,OAAO,CAAC,KAAK,CAAC;SACd,WAAW,CAAC,+CAA+C,CAAC,CAAC;IAEhE,0BAA0B;IAC1B,GAAG;SACA,OAAO,CAAC,wBAAwB,CAAC;SACjC,WAAW,CAAC,4EAA4E,CAAC;SACzF,MAAM,CAAC,KAAK,EAAE,IAAY,EAAE,EAAE;QAC7B,IAAI,CAAC;YACH,OAAO,CAAC,GAAG,CAAC,eAAK,CAAC,IAAI,CAAC,yBAAyB,IAAI,EAAE,CAAC,CAAC,CAAC;YACzD,MAAM,IAAA,8BAAc,EAAC,IAAI,CAAC,CAAC;YAC3B,OAAO,CAAC,GAAG,CAAC,eAAK,CAAC,KAAK,CAAC,aAAa,IAAI,2BAA2B,CAAC,CAAC,CAAC;QACzE,CAAC;QAAC,OAAO,KAAU,EAAE,CAAC;YACpB,OAAO,CAAC,KAAK,CAAC,eAAK,CAAC,GAAG,CAAC,8BAA8B,KAAK,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC;YACxE,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAClB,CAAC;IACH,CAAC,CAAC,CAAC;IAEL,2BAA2B;IAC3B,GAAG;SACA,OAAO,CAAC,yBAAyB,CAAC;SAClC,WAAW,CAAC,0CAA0C,CAAC;SACvD,MAAM,CAAC,KAAK,EAAE,IAAY,EAAE,EAAE;QAC7B,IAAI,CAAC;YACH,OAAO,CAAC,GAAG,CAAC,eAAK,CAAC,IAAI,CAAC,uCAAuC,IAAI,EAAE,CAAC,CAAC,CAAC;YACvE,MAAM,IAAA,oCAAe,EAAC,IAAI,CAAC,CAAC;YAC5B,OAAO,CAAC,GAAG,CAAC,eAAK,CAAC,KAAK,CAAC,wCAAwC,IAAI,IAAI,CAAC,CAAC,CAAC;QAC7E,CAAC;QAAC,OAAO,KAAU,EAAE,CAAC;YACpB,OAAO,CAAC,KAAK,CAAC,eAAK,CAAC,GAAG,CAAC,gCAAgC,KAAK,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC;YAC1E,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAClB,CAAC;IACH,CAAC,CAAC,CAAC;IAEL,OAAO,GAAG,CAAC;AACb,CAAC"}
package/dist/index.js CHANGED
@@ -5,6 +5,7 @@ const commander_1 = require("commander");
5
5
  const init_1 = require("./commands/init");
6
6
  const update_1 = require("./commands/update");
7
7
  const extend_1 = require("./commands/extend");
8
+ const api_1 = require("./commands/api");
8
9
  const program = new commander_1.Command();
9
10
  program
10
11
  .name('diagramers')
@@ -14,6 +15,7 @@ program
14
15
  (0, init_1.initCommand)(program);
15
16
  (0, update_1.updateCommand)(program);
16
17
  (0, extend_1.extendCommand)(program);
18
+ (0, api_1.apiCommand)(program);
17
19
  // Add help text
18
20
  program.addHelpText('after', `
19
21
  Examples:
@@ -21,6 +23,8 @@ Examples:
21
23
  $ diagramers init admin my-admin-dashboard
22
24
  $ diagramers update
23
25
  $ diagramers extend --feature auth
26
+ $ diagramers api generate:module product
27
+ $ diagramers api process:template my-api-project
24
28
  `);
25
29
  program.parse();
26
30
  // If no command is provided, show help
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;AAEA,yCAAoC;AACpC,0CAA8C;AAC9C,8CAAkD;AAClD,8CAAkD;AAGlD,MAAM,OAAO,GAAG,IAAI,mBAAO,EAAE,CAAC;AAE9B,OAAO;KACJ,IAAI,CAAC,YAAY,CAAC;KAClB,WAAW,CAAC,2CAA2C,CAAC;KACxD,OAAO,CAAC,OAAO,CAAC,CAAC;AAEpB,eAAe;AACf,IAAA,kBAAW,EAAC,OAAO,CAAC,CAAC;AACrB,IAAA,sBAAa,EAAC,OAAO,CAAC,CAAC;AACvB,IAAA,sBAAa,EAAC,OAAO,CAAC,CAAC;AAEvB,gBAAgB;AAChB,OAAO,CAAC,WAAW,CAAC,OAAO,EAAE;;;;;;CAM5B,CAAC,CAAC;AAEH,OAAO,CAAC,KAAK,EAAE,CAAC;AAEhB,uCAAuC;AACvC,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC;IAClC,OAAO,CAAC,UAAU,EAAE,CAAC;AACvB,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;AAEA,yCAAoC;AACpC,0CAA8C;AAC9C,8CAAkD;AAClD,8CAAkD;AAClD,wCAA4C;AAG5C,MAAM,OAAO,GAAG,IAAI,mBAAO,EAAE,CAAC;AAE9B,OAAO;KACJ,IAAI,CAAC,YAAY,CAAC;KAClB,WAAW,CAAC,2CAA2C,CAAC;KACxD,OAAO,CAAC,OAAO,CAAC,CAAC;AAEpB,eAAe;AACf,IAAA,kBAAW,EAAC,OAAO,CAAC,CAAC;AACrB,IAAA,sBAAa,EAAC,OAAO,CAAC,CAAC;AACvB,IAAA,sBAAa,EAAC,OAAO,CAAC,CAAC;AACvB,IAAA,gBAAU,EAAC,OAAO,CAAC,CAAC;AAEpB,gBAAgB;AAChB,OAAO,CAAC,WAAW,CAAC,OAAO,EAAE;;;;;;;;CAQ5B,CAAC,CAAC;AAEH,OAAO,CAAC,KAAK,EAAE,CAAC;AAEhB,uCAAuC;AACvC,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC;IAClC,OAAO,CAAC,UAAU,EAAE,CAAC;AACvB,CAAC"}
@@ -0,0 +1,2 @@
1
+ export declare function generateModule(moduleName: string): Promise<void>;
2
+ //# sourceMappingURL=api-generator.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"api-generator.d.ts","sourceRoot":"","sources":["../../src/services/api-generator.ts"],"names":[],"mappings":"AAGA,wBAAsB,cAAc,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CA6CtE"}
@@ -0,0 +1,387 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.generateModule = generateModule;
37
+ const fs = __importStar(require("fs"));
38
+ const path = __importStar(require("path"));
39
+ async function generateModule(moduleName) {
40
+ // Validate module name
41
+ if (!moduleName || !/^[a-zA-Z][a-zA-Z0-9_-]*$/.test(moduleName)) {
42
+ throw new Error('Invalid module name. Use only letters, numbers, hyphens, and underscores. Must start with a letter.');
43
+ }
44
+ const moduleNameCapitalized = moduleName.charAt(0).toUpperCase() + moduleName.slice(1);
45
+ const currentDir = process.cwd();
46
+ // Check if we're in a diagramers API project
47
+ const packageJsonPath = path.join(currentDir, 'package.json');
48
+ if (!fs.existsSync(packageJsonPath)) {
49
+ throw new Error('package.json not found. Please run this command from a diagramers API project root.');
50
+ }
51
+ const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, 'utf8'));
52
+ if (!packageJson.name?.includes('diagramers') && !packageJson.name?.includes('api')) {
53
+ throw new Error('This command should be run from a diagramers API project.');
54
+ }
55
+ console.log('📝 Creating entity...');
56
+ const entityContent = generateEntityContent(moduleName, moduleNameCapitalized);
57
+ fs.writeFileSync(path.join(currentDir, 'src/entities', `${moduleName}.ts`), entityContent);
58
+ console.log('📋 Creating schema...');
59
+ const schemaContent = generateSchemaContent(moduleName, moduleNameCapitalized);
60
+ fs.writeFileSync(path.join(currentDir, 'src/schemas', `${moduleName}.ts`), schemaContent);
61
+ console.log('🔧 Creating service...');
62
+ const serviceContent = generateServiceContent(moduleName, moduleNameCapitalized);
63
+ fs.writeFileSync(path.join(currentDir, 'src/services', `${moduleName}-service.ts`), serviceContent);
64
+ console.log('🎮 Creating controller...');
65
+ const controllerContent = generateControllerContent(moduleName, moduleNameCapitalized);
66
+ fs.writeFileSync(path.join(currentDir, 'src/controllers', `${moduleName}-controller.ts`), controllerContent);
67
+ console.log('🛣️ Creating routes...');
68
+ const routesContent = generateRoutesContent(moduleName, moduleNameCapitalized);
69
+ fs.writeFileSync(path.join(currentDir, 'src/routes', `${moduleName}-routes.ts`), routesContent);
70
+ // Update dbcontext to include the new entity
71
+ updateDbContext(currentDir, moduleName, moduleNameCapitalized);
72
+ // Update routes index to include the new routes
73
+ updateRoutesIndex(currentDir, moduleName);
74
+ }
75
+ function generateEntityContent(moduleName, moduleNameCapitalized) {
76
+ return `import * as mongoose from 'mongoose';
77
+ import { ObjectId } from "bson";
78
+
79
+ export interface I${moduleNameCapitalized} extends mongoose.Document {
80
+ _id: ObjectId,
81
+ name: string,
82
+ description?: string,
83
+ status: number,
84
+ createdAt: Date,
85
+ updatedAt: Date
86
+ }`;
87
+ }
88
+ function generateSchemaContent(moduleName, moduleNameCapitalized) {
89
+ return `import * as mongoose from 'mongoose';
90
+ import { I${moduleNameCapitalized} } from '../entities/${moduleName}';
91
+
92
+ export const ${moduleName}Schema = new mongoose.Schema(
93
+ {
94
+ name: {
95
+ type: mongoose.SchemaTypes.String,
96
+ required: true,
97
+ },
98
+ description: {
99
+ type: mongoose.SchemaTypes.String,
100
+ required: false,
101
+ },
102
+ status: {
103
+ type: mongoose.SchemaTypes.Number,
104
+ default: 1,
105
+ }
106
+ },
107
+ { timestamps: true, suppressReservedKeysWarning: true },
108
+ );
109
+
110
+ export const ${moduleNameCapitalized}Entity = mongoose.model<I${moduleNameCapitalized}>('${moduleName}', ${moduleName}Schema);`;
111
+ }
112
+ function generateServiceContent(moduleName, moduleNameCapitalized) {
113
+ return `import { ObjectId } from "bson";
114
+ import dbcontext from "../helpers/dbcontext";
115
+ import { ResponseCode } from "../helpers/enums";
116
+ import { Result } from "../helpers/result";
117
+ import { ${moduleNameCapitalized}Entity } from "../schemas/${moduleName}";
118
+
119
+ export class ${moduleNameCapitalized}Service {
120
+ result: Result;
121
+ className = '${moduleNameCapitalized}Service';
122
+
123
+ constructor(result: Result) {
124
+ this.result = result;
125
+ }
126
+
127
+ async getAll(): Promise<Result> {
128
+ try {
129
+ const ${moduleName}s = await dbcontext.${moduleNameCapitalized}Entity.find({ status: 1 });
130
+ this.result.Data = ${moduleName}s;
131
+ this.result.Status = ResponseCode.Ok;
132
+ return this.result;
133
+ } catch (ex) {
134
+ this.result.addException(this.className, 'GetAll', ex);
135
+ return this.result;
136
+ }
137
+ }
138
+
139
+ async getById(id: string): Promise<Result> {
140
+ try {
141
+ const ${moduleName} = await dbcontext.${moduleNameCapitalized}Entity.findById(id);
142
+ if (${moduleName}) {
143
+ this.result.Data = ${moduleName};
144
+ this.result.Status = ResponseCode.Ok;
145
+ } else {
146
+ this.result.Status = ResponseCode.NotExist;
147
+ }
148
+ return this.result;
149
+ } catch (ex) {
150
+ this.result.addException(this.className, 'GetById', ex);
151
+ return this.result;
152
+ }
153
+ }
154
+
155
+ async create(${moduleName}Data: any): Promise<Result> {
156
+ try {
157
+ const ${moduleName}Entity = new ${moduleNameCapitalized}Entity({
158
+ _id: new ObjectId(),
159
+ ...${moduleName}Data,
160
+ status: 1
161
+ });
162
+ const created${moduleNameCapitalized} = await dbcontext.${moduleNameCapitalized}Entity.create(${moduleName}Entity);
163
+ if (created${moduleNameCapitalized}) {
164
+ this.result.Data = created${moduleNameCapitalized};
165
+ this.result.Status = ResponseCode.Ok;
166
+ } else {
167
+ this.result.Status = ResponseCode.Error;
168
+ this.result.Errors.push('Failed to create ${moduleName}');
169
+ }
170
+ return this.result;
171
+ } catch (ex) {
172
+ this.result.addException(this.className, 'Create', ex);
173
+ return this.result;
174
+ }
175
+ }
176
+
177
+ async update(id: string, ${moduleName}Data: any): Promise<Result> {
178
+ try {
179
+ const updated${moduleNameCapitalized} = await dbcontext.${moduleNameCapitalized}Entity.findByIdAndUpdate(
180
+ id,
181
+ { ...${moduleName}Data },
182
+ { new: true }
183
+ );
184
+ if (updated${moduleNameCapitalized}) {
185
+ this.result.Data = updated${moduleNameCapitalized};
186
+ this.result.Status = ResponseCode.Ok;
187
+ } else {
188
+ this.result.Status = ResponseCode.NotExist;
189
+ }
190
+ return this.result;
191
+ } catch (ex) {
192
+ this.result.addException(this.className, 'Update', ex);
193
+ return this.result;
194
+ }
195
+ }
196
+
197
+ async delete(id: string): Promise<Result> {
198
+ try {
199
+ const deleted${moduleNameCapitalized} = await dbcontext.${moduleNameCapitalized}Entity.findByIdAndUpdate(
200
+ id,
201
+ { status: 0 },
202
+ { new: true }
203
+ );
204
+ if (deleted${moduleNameCapitalized}) {
205
+ this.result.Data = deleted${moduleNameCapitalized};
206
+ this.result.Status = ResponseCode.Ok;
207
+ } else {
208
+ this.result.Status = ResponseCode.NotExist;
209
+ }
210
+ return this.result;
211
+ } catch (ex) {
212
+ this.result.addException(this.className, 'Delete', ex);
213
+ return this.result;
214
+ }
215
+ }
216
+ }`;
217
+ }
218
+ function generateControllerContent(moduleName, moduleNameCapitalized) {
219
+ return `import { AuditMessageType, ResponseCode } from "../helpers/enums";
220
+ import handleResponse from "../helpers/handle-response";
221
+ import { Result } from "../helpers/result";
222
+ import { ${moduleNameCapitalized}Service } from "../services/${moduleName}-service";
223
+
224
+ export default class ${moduleNameCapitalized}Controller {
225
+
226
+ async getAll(req, res) {
227
+ const result = res.locals.result;
228
+ try {
229
+ result.addMessage(AuditMessageType.info, req.baseUrl, 'getAll', 'Started');
230
+ const ${moduleName}Service = new ${moduleNameCapitalized}Service(result);
231
+ const serviceResult = await ${moduleName}Service.getAll();
232
+ result.addMessage(AuditMessageType.info, req.baseUrl, 'getAll', 'Finished');
233
+ return handleResponse(req, res, serviceResult);
234
+ } catch (ex) {
235
+ result.addException(req.baseUrl, 'getAll', ex);
236
+ return handleResponse(req, res, result);
237
+ }
238
+ }
239
+
240
+ async getById(req, res) {
241
+ const result = res.locals.result;
242
+ try {
243
+ result.addMessage(AuditMessageType.info, req.baseUrl, 'getById', 'Started');
244
+ const ${moduleName}Service = new ${moduleNameCapitalized}Service(result);
245
+ const serviceResult = await ${moduleName}Service.getById(req.params.id);
246
+ result.addMessage(AuditMessageType.info, req.baseUrl, 'getById', 'Finished');
247
+ return handleResponse(req, res, serviceResult);
248
+ } catch (ex) {
249
+ result.addException(req.baseUrl, 'getById', ex);
250
+ return handleResponse(req, res, result);
251
+ }
252
+ }
253
+
254
+ async create(req, res) {
255
+ const result = res.locals.result;
256
+ try {
257
+ result.addMessage(AuditMessageType.info, req.baseUrl, 'create', 'Started');
258
+ const ${moduleName}Service = new ${moduleNameCapitalized}Service(result);
259
+ const serviceResult = await ${moduleName}Service.create(req.body);
260
+ result.addMessage(AuditMessageType.info, req.baseUrl, 'create', 'Finished');
261
+ return handleResponse(req, res, serviceResult);
262
+ } catch (ex) {
263
+ result.addException(req.baseUrl, 'create', ex);
264
+ return handleResponse(req, res, result);
265
+ }
266
+ }
267
+
268
+ async update(req, res) {
269
+ const result = res.locals.result;
270
+ try {
271
+ result.addMessage(AuditMessageType.info, req.baseUrl, 'update', 'Started');
272
+ const ${moduleName}Service = new ${moduleNameCapitalized}Service(result);
273
+ const serviceResult = await ${moduleName}Service.update(req.params.id, req.body);
274
+ result.addMessage(AuditMessageType.info, req.baseUrl, 'update', 'Finished');
275
+ return handleResponse(req, res, serviceResult);
276
+ } catch (ex) {
277
+ result.addException(req.baseUrl, 'update', ex);
278
+ return handleResponse(req, res, result);
279
+ }
280
+ }
281
+
282
+ async delete(req, res) {
283
+ const result = res.locals.result;
284
+ try {
285
+ result.addMessage(AuditMessageType.info, req.baseUrl, 'delete', 'Started');
286
+ const ${moduleName}Service = new ${moduleNameCapitalized}Service(result);
287
+ const serviceResult = await ${moduleName}Service.delete(req.params.id);
288
+ result.addMessage(AuditMessageType.info, req.baseUrl, 'delete', 'Finished');
289
+ return handleResponse(req, res, serviceResult);
290
+ } catch (ex) {
291
+ result.addException(req.baseUrl, 'delete', ex);
292
+ return handleResponse(req, res, result);
293
+ }
294
+ }
295
+ }`;
296
+ }
297
+ function generateRoutesContent(moduleName, moduleNameCapitalized) {
298
+ return `import express from 'express';
299
+ import ${moduleNameCapitalized}Controller from '../controllers/${moduleName}-controller';
300
+
301
+ const router = express.Router();
302
+ const ${moduleName}Controller = new ${moduleNameCapitalized}Controller();
303
+
304
+ // GET /api/${moduleName}s
305
+ router.get('/', ${moduleName}Controller.getAll.bind(${moduleName}Controller));
306
+
307
+ // GET /api/${moduleName}s/:id
308
+ router.get('/:id', ${moduleName}Controller.getById.bind(${moduleName}Controller));
309
+
310
+ // POST /api/${moduleName}s
311
+ router.post('/', ${moduleName}Controller.create.bind(${moduleName}Controller));
312
+
313
+ // PUT /api/${moduleName}s/:id
314
+ router.put('/:id', ${moduleName}Controller.update.bind(${moduleName}Controller));
315
+
316
+ // DELETE /api/${moduleName}s/:id
317
+ router.delete('/:id', ${moduleName}Controller.delete.bind(${moduleName}Controller));
318
+
319
+ export default router;`;
320
+ }
321
+ function updateDbContext(currentDir, moduleName, moduleNameCapitalized) {
322
+ const dbcontextPath = path.join(currentDir, 'src/helpers/dbcontext.ts');
323
+ if (!fs.existsSync(dbcontextPath)) {
324
+ console.log('⚠️ dbcontext.ts not found, skipping dbcontext update');
325
+ return;
326
+ }
327
+ let dbcontextContent = fs.readFileSync(dbcontextPath, 'utf8');
328
+ // Add import
329
+ const importStatement = `import { ${moduleNameCapitalized}Entity } from '../schemas/${moduleName}';`;
330
+ if (!dbcontextContent.includes(importStatement)) {
331
+ // Find the last import statement and add after it
332
+ const importRegex = /import.*from.*['"];?\s*$/gm;
333
+ const matches = [...dbcontextContent.matchAll(importRegex)];
334
+ if (matches.length > 0) {
335
+ const lastImport = matches[matches.length - 1];
336
+ const insertIndex = lastImport.index + lastImport[0].length;
337
+ dbcontextContent = dbcontextContent.slice(0, insertIndex) + '\n' + importStatement + dbcontextContent.slice(insertIndex);
338
+ }
339
+ }
340
+ // Add to dbcontext object
341
+ const dbcontextObjectRegex = /export\s+default\s*\{([^}]*)\}/s;
342
+ const match = dbcontextContent.match(dbcontextObjectRegex);
343
+ if (match) {
344
+ const objectContent = match[1];
345
+ if (!objectContent.includes(`${moduleNameCapitalized}Entity`)) {
346
+ const newObjectContent = objectContent.trim() + `,\n ${moduleNameCapitalized}Entity`;
347
+ dbcontextContent = dbcontextContent.replace(dbcontextObjectRegex, `export default {$1${newObjectContent}\n}`);
348
+ }
349
+ }
350
+ fs.writeFileSync(dbcontextPath, dbcontextContent);
351
+ console.log('📊 Updated dbcontext.ts');
352
+ }
353
+ function updateRoutesIndex(currentDir, moduleName) {
354
+ const routesIndexPath = path.join(currentDir, 'src/routes/index.ts');
355
+ if (!fs.existsSync(routesIndexPath)) {
356
+ console.log('⚠️ routes/index.ts not found, skipping routes index update');
357
+ return;
358
+ }
359
+ let routesContent = fs.readFileSync(routesIndexPath, 'utf8');
360
+ // Add import
361
+ const importStatement = `import ${moduleName}Routes from './${moduleName}-routes';`;
362
+ if (!routesContent.includes(importStatement)) {
363
+ // Find the last import statement and add after it
364
+ const importRegex = /import.*from.*['"];?\s*$/gm;
365
+ const matches = [...routesContent.matchAll(importRegex)];
366
+ if (matches.length > 0) {
367
+ const lastImport = matches[matches.length - 1];
368
+ const insertIndex = lastImport.index + lastImport[0].length;
369
+ routesContent = routesContent.slice(0, insertIndex) + '\n' + importStatement + routesContent.slice(insertIndex);
370
+ }
371
+ }
372
+ // Add route registration
373
+ const routeRegistration = `app.use('/api/${moduleName}s', ${moduleName}Routes);`;
374
+ if (!routesContent.includes(routeRegistration)) {
375
+ // Find where routes are registered (usually after imports)
376
+ const routeRegex = /app\.use\('\/api\/.*',.*\);?\s*$/gm;
377
+ const matches = [...routesContent.matchAll(routeRegex)];
378
+ if (matches.length > 0) {
379
+ const lastRoute = matches[matches.length - 1];
380
+ const insertIndex = lastRoute.index + lastRoute[0].length;
381
+ routesContent = routesContent.slice(0, insertIndex) + '\n' + routeRegistration + routesContent.slice(insertIndex);
382
+ }
383
+ }
384
+ fs.writeFileSync(routesIndexPath, routesContent);
385
+ console.log('🛣️ Updated routes/index.ts');
386
+ }
387
+ //# sourceMappingURL=api-generator.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"api-generator.js","sourceRoot":"","sources":["../../src/services/api-generator.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export declare function processTemplate(projectName: string): Promise<void>;
2
+ //# sourceMappingURL=template-processor.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"template-processor.d.ts","sourceRoot":"","sources":["../../src/services/template-processor.ts"],"names":[],"mappings":"AAGA,wBAAsB,eAAe,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAkHxE"}
@@ -0,0 +1,162 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.processTemplate = processTemplate;
37
+ const fs = __importStar(require("fs"));
38
+ const path = __importStar(require("path"));
39
+ async function processTemplate(projectName) {
40
+ if (!projectName) {
41
+ throw new Error('Project name is required');
42
+ }
43
+ const currentDir = process.cwd();
44
+ // Check if we're in a diagramers API project
45
+ const packageJsonPath = path.join(currentDir, 'package.json');
46
+ if (!fs.existsSync(packageJsonPath)) {
47
+ throw new Error('package.json not found. Please run this command from a diagramers API project root.');
48
+ }
49
+ const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, 'utf8'));
50
+ if (!packageJson.name?.includes('diagramers') && !packageJson.name?.includes('api')) {
51
+ throw new Error('This command should be run from a diagramers API project.');
52
+ }
53
+ // Convert project name to database-friendly format
54
+ const dbName = projectName
55
+ .toLowerCase()
56
+ .replace(/[^a-zA-Z0-9]/g, '_')
57
+ .replace(/_+/g, '_')
58
+ .replace(/^_|_$/g, '');
59
+ console.log(`🗄️ Database name will be: ${dbName}`);
60
+ // Process configuration files
61
+ console.log('📝 Updating configuration files...');
62
+ // Update development config
63
+ const devConfigPath = path.join(currentDir, 'src/config/development.ts');
64
+ if (fs.existsSync(devConfigPath)) {
65
+ let devConfig = fs.readFileSync(devConfigPath, 'utf8');
66
+ devConfig = devConfig.replace(/mongodb:\/\/127\.0\.0\.1:27017\/[^,\s]+/g, `mongodb://127.0.0.1:27017/${dbName}-development`);
67
+ fs.writeFileSync(devConfigPath, devConfig);
68
+ console.log(' ✅ Updated development.ts');
69
+ }
70
+ // Update staging config
71
+ const stagingConfigPath = path.join(currentDir, 'src/config/staging.ts');
72
+ if (fs.existsSync(stagingConfigPath)) {
73
+ let stagingConfig = fs.readFileSync(stagingConfigPath, 'utf8');
74
+ stagingConfig = stagingConfig.replace(/sendifier-staging/g, `${dbName}-staging`);
75
+ fs.writeFileSync(stagingConfigPath, stagingConfig);
76
+ console.log(' ✅ Updated staging.ts');
77
+ }
78
+ // Update production config
79
+ const prodConfigPath = path.join(currentDir, 'src/config/production.ts');
80
+ if (fs.existsSync(prodConfigPath)) {
81
+ let prodConfig = fs.readFileSync(prodConfigPath, 'utf8');
82
+ prodConfig = prodConfig.replace(/sendifier-production/g, `${dbName}-production`);
83
+ fs.writeFileSync(prodConfigPath, prodConfig);
84
+ console.log(' ✅ Updated production.ts');
85
+ }
86
+ // Update package.json
87
+ let packageJsonContent = fs.readFileSync(packageJsonPath, 'utf8');
88
+ packageJsonContent = packageJsonContent.replace(/"name":\s*"@diagramers\/api"/g, `"name": "${projectName}"`);
89
+ packageJsonContent = packageJsonContent.replace(/"description":\s*"Diagramers API - A comprehensive Node\.js API template with TypeScript, Firebase Functions, and Socket\.io"/g, `"description": "${projectName} - API project"`);
90
+ fs.writeFileSync(packageJsonPath, packageJsonContent);
91
+ console.log(' ✅ Updated package.json');
92
+ // Update README.md
93
+ const readmePath = path.join(currentDir, 'README.md');
94
+ if (fs.existsSync(readmePath)) {
95
+ let readmeContent = fs.readFileSync(readmePath, 'utf8');
96
+ readmeContent = readmeContent.replace(/# @diagramers\/api/g, `# ${projectName}`);
97
+ readmeContent = readmeContent.replace(/A comprehensive Node\.js API template with TypeScript, Firebase Functions, and Socket\.io\./g, `${projectName} - API project.`);
98
+ fs.writeFileSync(readmePath, readmeContent);
99
+ console.log(' ✅ Updated README.md');
100
+ }
101
+ // Create .env file template
102
+ console.log('📄 Creating .env template...');
103
+ const envTemplate = generateEnvTemplate(dbName);
104
+ fs.writeFileSync(path.join(currentDir, '.env.example'), envTemplate);
105
+ console.log('✅ Template processing completed!');
106
+ console.log('');
107
+ console.log('📋 Summary:');
108
+ console.log(` Project Name: ${projectName}`);
109
+ console.log(` Database Name: ${dbName}`);
110
+ console.log(` Development DB: ${dbName}-development`);
111
+ console.log(` Staging DB: ${dbName}-staging`);
112
+ console.log(` Production DB: ${dbName}-production`);
113
+ console.log('');
114
+ console.log('🚀 Next steps:');
115
+ console.log(' 1. Copy .env.example to .env and configure your environment variables');
116
+ console.log(' 2. Install dependencies: npm install');
117
+ console.log(' 3. Build the project: npm run build:dev');
118
+ console.log(' 4. Start the server: npm run serve');
119
+ }
120
+ function generateEnvTemplate(dbName) {
121
+ return `# Environment Configuration
122
+ NODE_ENV=development
123
+
124
+ # Server Configuration
125
+ PORT=4000
126
+ HOST=localhost
127
+
128
+ # Database Configuration
129
+ MONGODB_URI=mongodb://127.0.0.1:27017/${dbName}-development
130
+
131
+ # Firebase Configuration
132
+ FIREBASE_API_KEY=your-api-key
133
+ FIREBASE_AUTH_DOMAIN=your-project.firebaseapp.com
134
+ FIREBASE_PROJECT_ID=your-project-id
135
+ FIREBASE_STORAGE_BUCKET=your-project.appspot.com
136
+ FIREBASE_MESSAGING_SENDER_ID=your-sender-id
137
+ FIREBASE_APP_ID=your-app-id
138
+
139
+ # JWT Configuration
140
+ JWT_SECRET=your-jwt-secret-key
141
+
142
+ # Twilio Configuration (for SMS)
143
+ TWILIO_ACCOUNT_SID=your-account-sid
144
+ TWILIO_AUTH_TOKEN=your-auth-token
145
+
146
+ # Email Configuration
147
+ SMTP_HOST=smtp.gmail.com
148
+ SMTP_PORT=587
149
+ SMTP_USER=your-email@gmail.com
150
+ SMTP_PASS=your-app-password
151
+
152
+ # Internal API Configuration
153
+ INTERNAL_REQUEST_HEADER_VALUE=your-secret-header-value
154
+
155
+ # Optional Configuration
156
+ BASE_SITE_URL=http://localhost:3000
157
+ LOCAL_API_TUNNEL_URL=https://your-ngrok-url.ngrok-free.app
158
+ LOCAL_UI_TUNNEL_URL=https://your-ui-ngrok-url.ngrok-free.app
159
+ BACKUP_DATABASES_FOLDER_PATH=/path/to/backup/folder
160
+ EXTERNAL_HTTP_REQUEST_TIMEOUT=5000`;
161
+ }
162
+ //# sourceMappingURL=template-processor.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"template-processor.js","sourceRoot":"","sources":["../../src/services/template-processor.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@diagramers/cli",
3
- "version": "1.0.13",
3
+ "version": "1.0.14",
4
4
  "description": "Diagramers CLI - Command-line tools for managing Diagramers projects",
5
5
  "main": "dist/index.js",
6
6
  "bin": {
@@ -0,0 +1,42 @@
1
+ import { Command } from 'commander';
2
+ import { generateModule } from '../services/api-generator';
3
+ import { processTemplate } from '../services/template-processor';
4
+ import chalk from 'chalk';
5
+
6
+ export function apiCommand(program: Command) {
7
+ const api = program
8
+ .command('api')
9
+ .description('API-specific commands for diagramers projects');
10
+
11
+ // Generate module command
12
+ api
13
+ .command('generate:module <name>')
14
+ .description('Generate a new module with entity, schema, service, controller, and routes')
15
+ .action(async (name: string) => {
16
+ try {
17
+ console.log(chalk.blue(`🚀 Generating module: ${name}`));
18
+ await generateModule(name);
19
+ console.log(chalk.green(`✅ Module '${name}' generated successfully!`));
20
+ } catch (error: any) {
21
+ console.error(chalk.red(`❌ Error generating module: ${error.message}`));
22
+ process.exit(1);
23
+ }
24
+ });
25
+
26
+ // Process template command
27
+ api
28
+ .command('process:template <name>')
29
+ .description('Process template files for a new project')
30
+ .action(async (name: string) => {
31
+ try {
32
+ console.log(chalk.blue(`🔧 Processing template for project: ${name}`));
33
+ await processTemplate(name);
34
+ console.log(chalk.green(`✅ Template processing completed for '${name}'!`));
35
+ } catch (error: any) {
36
+ console.error(chalk.red(`❌ Error processing template: ${error.message}`));
37
+ process.exit(1);
38
+ }
39
+ });
40
+
41
+ return api;
42
+ }
package/src/index.ts CHANGED
@@ -4,6 +4,7 @@ import { Command } from 'commander';
4
4
  import { initCommand } from './commands/init';
5
5
  import { updateCommand } from './commands/update';
6
6
  import { extendCommand } from './commands/extend';
7
+ import { apiCommand } from './commands/api';
7
8
  import chalk from 'chalk';
8
9
 
9
10
  const program = new Command();
@@ -17,6 +18,7 @@ program
17
18
  initCommand(program);
18
19
  updateCommand(program);
19
20
  extendCommand(program);
21
+ apiCommand(program);
20
22
 
21
23
  // Add help text
22
24
  program.addHelpText('after', `
@@ -25,6 +27,8 @@ Examples:
25
27
  $ diagramers init admin my-admin-dashboard
26
28
  $ diagramers update
27
29
  $ diagramers extend --feature auth
30
+ $ diagramers api generate:module product
31
+ $ diagramers api process:template my-api-project
28
32
  `);
29
33
 
30
34
  program.parse();
@@ -0,0 +1,376 @@
1
+ import * as fs from 'fs';
2
+ import * as path from 'path';
3
+
4
+ export async function generateModule(moduleName: string): Promise<void> {
5
+ // Validate module name
6
+ if (!moduleName || !/^[a-zA-Z][a-zA-Z0-9_-]*$/.test(moduleName)) {
7
+ throw new Error('Invalid module name. Use only letters, numbers, hyphens, and underscores. Must start with a letter.');
8
+ }
9
+
10
+ const moduleNameCapitalized = moduleName.charAt(0).toUpperCase() + moduleName.slice(1);
11
+ const currentDir = process.cwd();
12
+
13
+ // Check if we're in a diagramers API project
14
+ const packageJsonPath = path.join(currentDir, 'package.json');
15
+ if (!fs.existsSync(packageJsonPath)) {
16
+ throw new Error('package.json not found. Please run this command from a diagramers API project root.');
17
+ }
18
+
19
+ const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, 'utf8'));
20
+ if (!packageJson.name?.includes('diagramers') && !packageJson.name?.includes('api')) {
21
+ throw new Error('This command should be run from a diagramers API project.');
22
+ }
23
+
24
+ console.log('📝 Creating entity...');
25
+ const entityContent = generateEntityContent(moduleName, moduleNameCapitalized);
26
+ fs.writeFileSync(path.join(currentDir, 'src/entities', `${moduleName}.ts`), entityContent);
27
+
28
+ console.log('📋 Creating schema...');
29
+ const schemaContent = generateSchemaContent(moduleName, moduleNameCapitalized);
30
+ fs.writeFileSync(path.join(currentDir, 'src/schemas', `${moduleName}.ts`), schemaContent);
31
+
32
+ console.log('🔧 Creating service...');
33
+ const serviceContent = generateServiceContent(moduleName, moduleNameCapitalized);
34
+ fs.writeFileSync(path.join(currentDir, 'src/services', `${moduleName}-service.ts`), serviceContent);
35
+
36
+ console.log('🎮 Creating controller...');
37
+ const controllerContent = generateControllerContent(moduleName, moduleNameCapitalized);
38
+ fs.writeFileSync(path.join(currentDir, 'src/controllers', `${moduleName}-controller.ts`), controllerContent);
39
+
40
+ console.log('🛣️ Creating routes...');
41
+ const routesContent = generateRoutesContent(moduleName, moduleNameCapitalized);
42
+ fs.writeFileSync(path.join(currentDir, 'src/routes', `${moduleName}-routes.ts`), routesContent);
43
+
44
+ // Update dbcontext to include the new entity
45
+ updateDbContext(currentDir, moduleName, moduleNameCapitalized);
46
+
47
+ // Update routes index to include the new routes
48
+ updateRoutesIndex(currentDir, moduleName);
49
+ }
50
+
51
+ function generateEntityContent(moduleName: string, moduleNameCapitalized: string): string {
52
+ return `import * as mongoose from 'mongoose';
53
+ import { ObjectId } from "bson";
54
+
55
+ export interface I${moduleNameCapitalized} extends mongoose.Document {
56
+ _id: ObjectId,
57
+ name: string,
58
+ description?: string,
59
+ status: number,
60
+ createdAt: Date,
61
+ updatedAt: Date
62
+ }`;
63
+ }
64
+
65
+ function generateSchemaContent(moduleName: string, moduleNameCapitalized: string): string {
66
+ return `import * as mongoose from 'mongoose';
67
+ import { I${moduleNameCapitalized} } from '../entities/${moduleName}';
68
+
69
+ export const ${moduleName}Schema = new mongoose.Schema(
70
+ {
71
+ name: {
72
+ type: mongoose.SchemaTypes.String,
73
+ required: true,
74
+ },
75
+ description: {
76
+ type: mongoose.SchemaTypes.String,
77
+ required: false,
78
+ },
79
+ status: {
80
+ type: mongoose.SchemaTypes.Number,
81
+ default: 1,
82
+ }
83
+ },
84
+ { timestamps: true, suppressReservedKeysWarning: true },
85
+ );
86
+
87
+ export const ${moduleNameCapitalized}Entity = mongoose.model<I${moduleNameCapitalized}>('${moduleName}', ${moduleName}Schema);`;
88
+ }
89
+
90
+ function generateServiceContent(moduleName: string, moduleNameCapitalized: string): string {
91
+ return `import { ObjectId } from "bson";
92
+ import dbcontext from "../helpers/dbcontext";
93
+ import { ResponseCode } from "../helpers/enums";
94
+ import { Result } from "../helpers/result";
95
+ import { ${moduleNameCapitalized}Entity } from "../schemas/${moduleName}";
96
+
97
+ export class ${moduleNameCapitalized}Service {
98
+ result: Result;
99
+ className = '${moduleNameCapitalized}Service';
100
+
101
+ constructor(result: Result) {
102
+ this.result = result;
103
+ }
104
+
105
+ async getAll(): Promise<Result> {
106
+ try {
107
+ const ${moduleName}s = await dbcontext.${moduleNameCapitalized}Entity.find({ status: 1 });
108
+ this.result.Data = ${moduleName}s;
109
+ this.result.Status = ResponseCode.Ok;
110
+ return this.result;
111
+ } catch (ex) {
112
+ this.result.addException(this.className, 'GetAll', ex);
113
+ return this.result;
114
+ }
115
+ }
116
+
117
+ async getById(id: string): Promise<Result> {
118
+ try {
119
+ const ${moduleName} = await dbcontext.${moduleNameCapitalized}Entity.findById(id);
120
+ if (${moduleName}) {
121
+ this.result.Data = ${moduleName};
122
+ this.result.Status = ResponseCode.Ok;
123
+ } else {
124
+ this.result.Status = ResponseCode.NotExist;
125
+ }
126
+ return this.result;
127
+ } catch (ex) {
128
+ this.result.addException(this.className, 'GetById', ex);
129
+ return this.result;
130
+ }
131
+ }
132
+
133
+ async create(${moduleName}Data: any): Promise<Result> {
134
+ try {
135
+ const ${moduleName}Entity = new ${moduleNameCapitalized}Entity({
136
+ _id: new ObjectId(),
137
+ ...${moduleName}Data,
138
+ status: 1
139
+ });
140
+ const created${moduleNameCapitalized} = await dbcontext.${moduleNameCapitalized}Entity.create(${moduleName}Entity);
141
+ if (created${moduleNameCapitalized}) {
142
+ this.result.Data = created${moduleNameCapitalized};
143
+ this.result.Status = ResponseCode.Ok;
144
+ } else {
145
+ this.result.Status = ResponseCode.Error;
146
+ this.result.Errors.push('Failed to create ${moduleName}');
147
+ }
148
+ return this.result;
149
+ } catch (ex) {
150
+ this.result.addException(this.className, 'Create', ex);
151
+ return this.result;
152
+ }
153
+ }
154
+
155
+ async update(id: string, ${moduleName}Data: any): Promise<Result> {
156
+ try {
157
+ const updated${moduleNameCapitalized} = await dbcontext.${moduleNameCapitalized}Entity.findByIdAndUpdate(
158
+ id,
159
+ { ...${moduleName}Data },
160
+ { new: true }
161
+ );
162
+ if (updated${moduleNameCapitalized}) {
163
+ this.result.Data = updated${moduleNameCapitalized};
164
+ this.result.Status = ResponseCode.Ok;
165
+ } else {
166
+ this.result.Status = ResponseCode.NotExist;
167
+ }
168
+ return this.result;
169
+ } catch (ex) {
170
+ this.result.addException(this.className, 'Update', ex);
171
+ return this.result;
172
+ }
173
+ }
174
+
175
+ async delete(id: string): Promise<Result> {
176
+ try {
177
+ const deleted${moduleNameCapitalized} = await dbcontext.${moduleNameCapitalized}Entity.findByIdAndUpdate(
178
+ id,
179
+ { status: 0 },
180
+ { new: true }
181
+ );
182
+ if (deleted${moduleNameCapitalized}) {
183
+ this.result.Data = deleted${moduleNameCapitalized};
184
+ this.result.Status = ResponseCode.Ok;
185
+ } else {
186
+ this.result.Status = ResponseCode.NotExist;
187
+ }
188
+ return this.result;
189
+ } catch (ex) {
190
+ this.result.addException(this.className, 'Delete', ex);
191
+ return this.result;
192
+ }
193
+ }
194
+ }`;
195
+ }
196
+
197
+ function generateControllerContent(moduleName: string, moduleNameCapitalized: string): string {
198
+ return `import { AuditMessageType, ResponseCode } from "../helpers/enums";
199
+ import handleResponse from "../helpers/handle-response";
200
+ import { Result } from "../helpers/result";
201
+ import { ${moduleNameCapitalized}Service } from "../services/${moduleName}-service";
202
+
203
+ export default class ${moduleNameCapitalized}Controller {
204
+
205
+ async getAll(req, res) {
206
+ const result = res.locals.result;
207
+ try {
208
+ result.addMessage(AuditMessageType.info, req.baseUrl, 'getAll', 'Started');
209
+ const ${moduleName}Service = new ${moduleNameCapitalized}Service(result);
210
+ const serviceResult = await ${moduleName}Service.getAll();
211
+ result.addMessage(AuditMessageType.info, req.baseUrl, 'getAll', 'Finished');
212
+ return handleResponse(req, res, serviceResult);
213
+ } catch (ex) {
214
+ result.addException(req.baseUrl, 'getAll', ex);
215
+ return handleResponse(req, res, result);
216
+ }
217
+ }
218
+
219
+ async getById(req, res) {
220
+ const result = res.locals.result;
221
+ try {
222
+ result.addMessage(AuditMessageType.info, req.baseUrl, 'getById', 'Started');
223
+ const ${moduleName}Service = new ${moduleNameCapitalized}Service(result);
224
+ const serviceResult = await ${moduleName}Service.getById(req.params.id);
225
+ result.addMessage(AuditMessageType.info, req.baseUrl, 'getById', 'Finished');
226
+ return handleResponse(req, res, serviceResult);
227
+ } catch (ex) {
228
+ result.addException(req.baseUrl, 'getById', ex);
229
+ return handleResponse(req, res, result);
230
+ }
231
+ }
232
+
233
+ async create(req, res) {
234
+ const result = res.locals.result;
235
+ try {
236
+ result.addMessage(AuditMessageType.info, req.baseUrl, 'create', 'Started');
237
+ const ${moduleName}Service = new ${moduleNameCapitalized}Service(result);
238
+ const serviceResult = await ${moduleName}Service.create(req.body);
239
+ result.addMessage(AuditMessageType.info, req.baseUrl, 'create', 'Finished');
240
+ return handleResponse(req, res, serviceResult);
241
+ } catch (ex) {
242
+ result.addException(req.baseUrl, 'create', ex);
243
+ return handleResponse(req, res, result);
244
+ }
245
+ }
246
+
247
+ async update(req, res) {
248
+ const result = res.locals.result;
249
+ try {
250
+ result.addMessage(AuditMessageType.info, req.baseUrl, 'update', 'Started');
251
+ const ${moduleName}Service = new ${moduleNameCapitalized}Service(result);
252
+ const serviceResult = await ${moduleName}Service.update(req.params.id, req.body);
253
+ result.addMessage(AuditMessageType.info, req.baseUrl, 'update', 'Finished');
254
+ return handleResponse(req, res, serviceResult);
255
+ } catch (ex) {
256
+ result.addException(req.baseUrl, 'update', ex);
257
+ return handleResponse(req, res, result);
258
+ }
259
+ }
260
+
261
+ async delete(req, res) {
262
+ const result = res.locals.result;
263
+ try {
264
+ result.addMessage(AuditMessageType.info, req.baseUrl, 'delete', 'Started');
265
+ const ${moduleName}Service = new ${moduleNameCapitalized}Service(result);
266
+ const serviceResult = await ${moduleName}Service.delete(req.params.id);
267
+ result.addMessage(AuditMessageType.info, req.baseUrl, 'delete', 'Finished');
268
+ return handleResponse(req, res, serviceResult);
269
+ } catch (ex) {
270
+ result.addException(req.baseUrl, 'delete', ex);
271
+ return handleResponse(req, res, result);
272
+ }
273
+ }
274
+ }`;
275
+ }
276
+
277
+ function generateRoutesContent(moduleName: string, moduleNameCapitalized: string): string {
278
+ return `import express from 'express';
279
+ import ${moduleNameCapitalized}Controller from '../controllers/${moduleName}-controller';
280
+
281
+ const router = express.Router();
282
+ const ${moduleName}Controller = new ${moduleNameCapitalized}Controller();
283
+
284
+ // GET /api/${moduleName}s
285
+ router.get('/', ${moduleName}Controller.getAll.bind(${moduleName}Controller));
286
+
287
+ // GET /api/${moduleName}s/:id
288
+ router.get('/:id', ${moduleName}Controller.getById.bind(${moduleName}Controller));
289
+
290
+ // POST /api/${moduleName}s
291
+ router.post('/', ${moduleName}Controller.create.bind(${moduleName}Controller));
292
+
293
+ // PUT /api/${moduleName}s/:id
294
+ router.put('/:id', ${moduleName}Controller.update.bind(${moduleName}Controller));
295
+
296
+ // DELETE /api/${moduleName}s/:id
297
+ router.delete('/:id', ${moduleName}Controller.delete.bind(${moduleName}Controller));
298
+
299
+ export default router;`;
300
+ }
301
+
302
+ function updateDbContext(currentDir: string, moduleName: string, moduleNameCapitalized: string): void {
303
+ const dbcontextPath = path.join(currentDir, 'src/helpers/dbcontext.ts');
304
+ if (!fs.existsSync(dbcontextPath)) {
305
+ console.log('⚠️ dbcontext.ts not found, skipping dbcontext update');
306
+ return;
307
+ }
308
+
309
+ let dbcontextContent = fs.readFileSync(dbcontextPath, 'utf8');
310
+
311
+ // Add import
312
+ const importStatement = `import { ${moduleNameCapitalized}Entity } from '../schemas/${moduleName}';`;
313
+ if (!dbcontextContent.includes(importStatement)) {
314
+ // Find the last import statement and add after it
315
+ const importRegex = /import.*from.*['"];?\s*$/gm;
316
+ const matches = [...dbcontextContent.matchAll(importRegex)];
317
+ if (matches.length > 0) {
318
+ const lastImport = matches[matches.length - 1];
319
+ const insertIndex = lastImport.index! + lastImport[0].length;
320
+ dbcontextContent = dbcontextContent.slice(0, insertIndex) + '\n' + importStatement + dbcontextContent.slice(insertIndex);
321
+ }
322
+ }
323
+
324
+ // Add to dbcontext object
325
+ const dbcontextObjectRegex = /export\s+default\s*\{([^}]*)\}/s;
326
+ const match = dbcontextContent.match(dbcontextObjectRegex);
327
+ if (match) {
328
+ const objectContent = match[1];
329
+ if (!objectContent.includes(`${moduleNameCapitalized}Entity`)) {
330
+ const newObjectContent = objectContent.trim() + `,\n ${moduleNameCapitalized}Entity`;
331
+ dbcontextContent = dbcontextContent.replace(dbcontextObjectRegex, `export default {$1${newObjectContent}\n}`);
332
+ }
333
+ }
334
+
335
+ fs.writeFileSync(dbcontextPath, dbcontextContent);
336
+ console.log('📊 Updated dbcontext.ts');
337
+ }
338
+
339
+ function updateRoutesIndex(currentDir: string, moduleName: string): void {
340
+ const routesIndexPath = path.join(currentDir, 'src/routes/index.ts');
341
+ if (!fs.existsSync(routesIndexPath)) {
342
+ console.log('⚠️ routes/index.ts not found, skipping routes index update');
343
+ return;
344
+ }
345
+
346
+ let routesContent = fs.readFileSync(routesIndexPath, 'utf8');
347
+
348
+ // Add import
349
+ const importStatement = `import ${moduleName}Routes from './${moduleName}-routes';`;
350
+ if (!routesContent.includes(importStatement)) {
351
+ // Find the last import statement and add after it
352
+ const importRegex = /import.*from.*['"];?\s*$/gm;
353
+ const matches = [...routesContent.matchAll(importRegex)];
354
+ if (matches.length > 0) {
355
+ const lastImport = matches[matches.length - 1];
356
+ const insertIndex = lastImport.index! + lastImport[0].length;
357
+ routesContent = routesContent.slice(0, insertIndex) + '\n' + importStatement + routesContent.slice(insertIndex);
358
+ }
359
+ }
360
+
361
+ // Add route registration
362
+ const routeRegistration = `app.use('/api/${moduleName}s', ${moduleName}Routes);`;
363
+ if (!routesContent.includes(routeRegistration)) {
364
+ // Find where routes are registered (usually after imports)
365
+ const routeRegex = /app\.use\('\/api\/.*',.*\);?\s*$/gm;
366
+ const matches = [...routesContent.matchAll(routeRegex)];
367
+ if (matches.length > 0) {
368
+ const lastRoute = matches[matches.length - 1];
369
+ const insertIndex = lastRoute.index! + lastRoute[0].length;
370
+ routesContent = routesContent.slice(0, insertIndex) + '\n' + routeRegistration + routesContent.slice(insertIndex);
371
+ }
372
+ }
373
+
374
+ fs.writeFileSync(routesIndexPath, routesContent);
375
+ console.log('🛣️ Updated routes/index.ts');
376
+ }
@@ -0,0 +1,161 @@
1
+ import * as fs from 'fs';
2
+ import * as path from 'path';
3
+
4
+ export async function processTemplate(projectName: string): Promise<void> {
5
+ if (!projectName) {
6
+ throw new Error('Project name is required');
7
+ }
8
+
9
+ const currentDir = process.cwd();
10
+
11
+ // Check if we're in a diagramers API project
12
+ const packageJsonPath = path.join(currentDir, 'package.json');
13
+ if (!fs.existsSync(packageJsonPath)) {
14
+ throw new Error('package.json not found. Please run this command from a diagramers API project root.');
15
+ }
16
+
17
+ const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, 'utf8'));
18
+ if (!packageJson.name?.includes('diagramers') && !packageJson.name?.includes('api')) {
19
+ throw new Error('This command should be run from a diagramers API project.');
20
+ }
21
+
22
+ // Convert project name to database-friendly format
23
+ const dbName = projectName
24
+ .toLowerCase()
25
+ .replace(/[^a-zA-Z0-9]/g, '_')
26
+ .replace(/_+/g, '_')
27
+ .replace(/^_|_$/g, '');
28
+
29
+ console.log(`🗄️ Database name will be: ${dbName}`);
30
+
31
+ // Process configuration files
32
+ console.log('📝 Updating configuration files...');
33
+
34
+ // Update development config
35
+ const devConfigPath = path.join(currentDir, 'src/config/development.ts');
36
+ if (fs.existsSync(devConfigPath)) {
37
+ let devConfig = fs.readFileSync(devConfigPath, 'utf8');
38
+ devConfig = devConfig.replace(
39
+ /mongodb:\/\/127\.0\.0\.1:27017\/[^,\s]+/g,
40
+ `mongodb://127.0.0.1:27017/${dbName}-development`
41
+ );
42
+ fs.writeFileSync(devConfigPath, devConfig);
43
+ console.log(' ✅ Updated development.ts');
44
+ }
45
+
46
+ // Update staging config
47
+ const stagingConfigPath = path.join(currentDir, 'src/config/staging.ts');
48
+ if (fs.existsSync(stagingConfigPath)) {
49
+ let stagingConfig = fs.readFileSync(stagingConfigPath, 'utf8');
50
+ stagingConfig = stagingConfig.replace(
51
+ /sendifier-staging/g,
52
+ `${dbName}-staging`
53
+ );
54
+ fs.writeFileSync(stagingConfigPath, stagingConfig);
55
+ console.log(' ✅ Updated staging.ts');
56
+ }
57
+
58
+ // Update production config
59
+ const prodConfigPath = path.join(currentDir, 'src/config/production.ts');
60
+ if (fs.existsSync(prodConfigPath)) {
61
+ let prodConfig = fs.readFileSync(prodConfigPath, 'utf8');
62
+ prodConfig = prodConfig.replace(
63
+ /sendifier-production/g,
64
+ `${dbName}-production`
65
+ );
66
+ fs.writeFileSync(prodConfigPath, prodConfig);
67
+ console.log(' ✅ Updated production.ts');
68
+ }
69
+
70
+ // Update package.json
71
+ let packageJsonContent = fs.readFileSync(packageJsonPath, 'utf8');
72
+ packageJsonContent = packageJsonContent.replace(
73
+ /"name":\s*"@diagramers\/api"/g,
74
+ `"name": "${projectName}"`
75
+ );
76
+ packageJsonContent = packageJsonContent.replace(
77
+ /"description":\s*"Diagramers API - A comprehensive Node\.js API template with TypeScript, Firebase Functions, and Socket\.io"/g,
78
+ `"description": "${projectName} - API project"`
79
+ );
80
+ fs.writeFileSync(packageJsonPath, packageJsonContent);
81
+ console.log(' ✅ Updated package.json');
82
+
83
+ // Update README.md
84
+ const readmePath = path.join(currentDir, 'README.md');
85
+ if (fs.existsSync(readmePath)) {
86
+ let readmeContent = fs.readFileSync(readmePath, 'utf8');
87
+ readmeContent = readmeContent.replace(
88
+ /# @diagramers\/api/g,
89
+ `# ${projectName}`
90
+ );
91
+ readmeContent = readmeContent.replace(
92
+ /A comprehensive Node\.js API template with TypeScript, Firebase Functions, and Socket\.io\./g,
93
+ `${projectName} - API project.`
94
+ );
95
+ fs.writeFileSync(readmePath, readmeContent);
96
+ console.log(' ✅ Updated README.md');
97
+ }
98
+
99
+ // Create .env file template
100
+ console.log('📄 Creating .env template...');
101
+ const envTemplate = generateEnvTemplate(dbName);
102
+ fs.writeFileSync(path.join(currentDir, '.env.example'), envTemplate);
103
+
104
+ console.log('✅ Template processing completed!');
105
+ console.log('');
106
+ console.log('📋 Summary:');
107
+ console.log(` Project Name: ${projectName}`);
108
+ console.log(` Database Name: ${dbName}`);
109
+ console.log(` Development DB: ${dbName}-development`);
110
+ console.log(` Staging DB: ${dbName}-staging`);
111
+ console.log(` Production DB: ${dbName}-production`);
112
+ console.log('');
113
+ console.log('🚀 Next steps:');
114
+ console.log(' 1. Copy .env.example to .env and configure your environment variables');
115
+ console.log(' 2. Install dependencies: npm install');
116
+ console.log(' 3. Build the project: npm run build:dev');
117
+ console.log(' 4. Start the server: npm run serve');
118
+ }
119
+
120
+ function generateEnvTemplate(dbName: string): string {
121
+ return `# Environment Configuration
122
+ NODE_ENV=development
123
+
124
+ # Server Configuration
125
+ PORT=4000
126
+ HOST=localhost
127
+
128
+ # Database Configuration
129
+ MONGODB_URI=mongodb://127.0.0.1:27017/${dbName}-development
130
+
131
+ # Firebase Configuration
132
+ FIREBASE_API_KEY=your-api-key
133
+ FIREBASE_AUTH_DOMAIN=your-project.firebaseapp.com
134
+ FIREBASE_PROJECT_ID=your-project-id
135
+ FIREBASE_STORAGE_BUCKET=your-project.appspot.com
136
+ FIREBASE_MESSAGING_SENDER_ID=your-sender-id
137
+ FIREBASE_APP_ID=your-app-id
138
+
139
+ # JWT Configuration
140
+ JWT_SECRET=your-jwt-secret-key
141
+
142
+ # Twilio Configuration (for SMS)
143
+ TWILIO_ACCOUNT_SID=your-account-sid
144
+ TWILIO_AUTH_TOKEN=your-auth-token
145
+
146
+ # Email Configuration
147
+ SMTP_HOST=smtp.gmail.com
148
+ SMTP_PORT=587
149
+ SMTP_USER=your-email@gmail.com
150
+ SMTP_PASS=your-app-password
151
+
152
+ # Internal API Configuration
153
+ INTERNAL_REQUEST_HEADER_VALUE=your-secret-header-value
154
+
155
+ # Optional Configuration
156
+ BASE_SITE_URL=http://localhost:3000
157
+ LOCAL_API_TUNNEL_URL=https://your-ngrok-url.ngrok-free.app
158
+ LOCAL_UI_TUNNEL_URL=https://your-ui-ngrok-url.ngrok-free.app
159
+ BACKUP_DATABASES_FOLDER_PATH=/path/to/backup/folder
160
+ EXTERNAL_HTTP_REQUEST_TIMEOUT=5000`;
161
+ }