@diagramers/cli 1.0.23 → 1.0.24

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (64) hide show
  1. package/dist/services/template-updater.d.ts +2 -0
  2. package/dist/services/template-updater.d.ts.map +1 -1
  3. package/dist/services/template-updater.js +66 -14
  4. package/dist/services/template-updater.js.map +1 -1
  5. package/package.json +5 -1
  6. package/templates/api/certs/auth-app-cert.json +13 -0
  7. package/templates/api/main.ts +10 -0
  8. package/templates/api/package.json +70 -0
  9. package/templates/api/src/assets/css/email-template.css +8 -0
  10. package/templates/api/src/assets/images/logo_large.png +0 -0
  11. package/templates/api/src/assets/keys/certificate.pem +22 -0
  12. package/templates/api/src/assets/keys/private-key.pem +28 -0
  13. package/templates/api/src/config/config-interface.ts +191 -0
  14. package/templates/api/src/config/development.ts +145 -0
  15. package/templates/api/src/config/index.ts +59 -0
  16. package/templates/api/src/config/production.ts +145 -0
  17. package/templates/api/src/config/staging.ts +144 -0
  18. package/templates/api/src/config/uat.ts +144 -0
  19. package/templates/api/src/controllers/account-controller.ts +162 -0
  20. package/templates/api/src/entities/audit.ts +12 -0
  21. package/templates/api/src/entities/base-entity.ts +10 -0
  22. package/templates/api/src/entities/user.ts +71 -0
  23. package/templates/api/src/helpers/FrameworkHelper.ts +157 -0
  24. package/templates/api/src/helpers/auth.ts +971 -0
  25. package/templates/api/src/helpers/cronHelper.ts +170 -0
  26. package/templates/api/src/helpers/dbcontext.ts +83 -0
  27. package/templates/api/src/helpers/encryptionHelper.ts +76 -0
  28. package/templates/api/src/helpers/enums.ts +258 -0
  29. package/templates/api/src/helpers/handle-response.ts +49 -0
  30. package/templates/api/src/helpers/httpHelper.ts +75 -0
  31. package/templates/api/src/helpers/mailer.ts +152 -0
  32. package/templates/api/src/helpers/result.ts +47 -0
  33. package/templates/api/src/helpers/string-helper.ts +27 -0
  34. package/templates/api/src/routes/account-routes.ts +37 -0
  35. package/templates/api/src/routes/auth-routes.ts +286 -0
  36. package/templates/api/src/routes/index.ts +92 -0
  37. package/templates/api/src/schemas/audit.ts +36 -0
  38. package/templates/api/src/schemas/otp.ts +52 -0
  39. package/templates/api/src/schemas/session.ts +57 -0
  40. package/templates/api/src/schemas/user.ts +125 -0
  41. package/templates/api/src/server/index.ts +86 -0
  42. package/templates/api/src/server/socket-server-provider.ts +209 -0
  43. package/templates/api/src/services/account-service.ts +243 -0
  44. package/templates/api/src/services/audit-service.ts +56 -0
  45. package/templates/api/tsconfig.json +16 -0
  46. package/templates/api/webpack.config.js +66 -0
  47. package/scripts/publish.sh +0 -58
  48. package/scripts/setup.sh +0 -38
  49. package/scripts/version.sh +0 -80
  50. package/src/commands/api.ts +0 -76
  51. package/src/commands/extend.ts +0 -35
  52. package/src/commands/init.ts +0 -32
  53. package/src/commands/update.ts +0 -25
  54. package/src/config/template-config.ts +0 -111
  55. package/src/index.ts +0 -41
  56. package/src/services/api-generator.ts +0 -378
  57. package/src/services/project-extender.ts +0 -330
  58. package/src/services/project-initializer.ts +0 -335
  59. package/src/services/project-updater.ts +0 -117
  60. package/src/services/relation-generator.ts +0 -203
  61. package/src/services/table-generator.ts +0 -114
  62. package/src/services/template-processor.ts +0 -166
  63. package/src/services/template-updater.ts +0 -184
  64. package/tsconfig.json +0 -19
@@ -1,330 +0,0 @@
1
- import * as fs from 'fs-extra';
2
- import * as path from 'path';
3
- import chalk from 'chalk';
4
-
5
- export interface Feature {
6
- name: string;
7
- description: string;
8
- files: string[];
9
- dependencies?: string[];
10
- }
11
-
12
- export class ProjectExtender {
13
- private features: Feature[] = [
14
- {
15
- name: 'auth',
16
- description: 'Authentication system with JWT',
17
- files: ['src/features/auth/**/*'],
18
- dependencies: ['jsonwebtoken', 'bcryptjs']
19
- },
20
- {
21
- name: 'email',
22
- description: 'Email notification system',
23
- files: ['src/features/email/**/*'],
24
- dependencies: ['nodemailer', 'handlebars']
25
- },
26
- {
27
- name: 'socket',
28
- description: 'Real-time WebSocket communication',
29
- files: ['src/features/socket/**/*'],
30
- dependencies: ['socket.io']
31
- },
32
- {
33
- name: 'cron',
34
- description: 'Scheduled task system',
35
- files: ['src/features/cron/**/*'],
36
- dependencies: ['node-cron']
37
- },
38
- {
39
- name: 'audit',
40
- description: 'Audit logging system',
41
- files: ['src/features/audit/**/*']
42
- }
43
- ];
44
-
45
- async listFeatures(): Promise<void> {
46
- console.log(chalk.blue('📋 Available features:'));
47
- console.log('');
48
-
49
- this.features.forEach(feature => {
50
- console.log(chalk.green(` ${feature.name}`));
51
- console.log(chalk.gray(` ${feature.description}`));
52
- if (feature.dependencies && feature.dependencies.length > 0) {
53
- console.log(chalk.yellow(` Dependencies: ${feature.dependencies.join(', ')}`));
54
- }
55
- console.log('');
56
- });
57
- }
58
-
59
- async addFeature(featureName: string): Promise<void> {
60
- const feature = this.features.find(f => f.name === featureName);
61
-
62
- if (!feature) {
63
- throw new Error(`Feature '${featureName}' not found. Use --list to see available features.`);
64
- }
65
-
66
- const projectPath = process.cwd();
67
-
68
- // Check if feature already exists
69
- const featurePath = path.join(projectPath, 'src', 'features', featureName);
70
- if (await fs.pathExists(featurePath)) {
71
- throw new Error(`Feature '${featureName}' already exists in this project.`);
72
- }
73
-
74
- // Create feature directory structure
75
- await this.createFeatureStructure(projectPath, feature);
76
-
77
- // Add dependencies if any
78
- if (feature.dependencies && feature.dependencies.length > 0) {
79
- await this.addDependencies(feature.dependencies);
80
- }
81
-
82
- // Update main configuration to use the extended feature
83
- await this.updateMainConfiguration(projectPath, feature);
84
-
85
- console.log(chalk.green(`✅ Feature '${featureName}' added successfully!`));
86
- console.log(chalk.blue(`📝 Main configuration updated to include ${featureName} feature`));
87
- }
88
-
89
- private async createFeatureStructure(projectPath: string, feature: Feature): Promise<void> {
90
- const featurePath = path.join(projectPath, 'src', 'features', feature.name);
91
-
92
- // Create basic feature structure
93
- const structure = {
94
- 'controllers': 'Feature controllers',
95
- 'services': 'Feature business logic',
96
- 'schemas': 'Feature validation schemas',
97
- 'routes': 'Feature API routes',
98
- 'types': 'Feature TypeScript types'
99
- };
100
-
101
- for (const [dir, description] of Object.entries(structure)) {
102
- const dirPath = path.join(featurePath, dir);
103
- await fs.ensureDir(dirPath);
104
-
105
- // Create index file
106
- const indexContent = `// ${description} for ${feature.name} feature
107
- export * from './${feature.name}-${dir.slice(0, -1)}';
108
- `;
109
- await fs.writeFile(path.join(dirPath, 'index.ts'), indexContent);
110
- }
111
-
112
- // Create main feature file
113
- const mainFeatureContent = `import { Router } from 'express';
114
- import { ${feature.name}Controller } from './controllers';
115
- import { ${feature.name}Service } from './services';
116
-
117
- export class ${this.capitalizeFirst(feature.name)}Feature {
118
- private router: Router;
119
- private controller: ${feature.name}Controller;
120
- private service: ${feature.name}Service;
121
-
122
- constructor() {
123
- this.router = Router();
124
- this.service = new ${feature.name}Service();
125
- this.controller = new ${feature.name}Controller(this.service);
126
- this.setupRoutes();
127
- }
128
-
129
- private setupRoutes(): void {
130
- // Define your routes here
131
- // this.router.get('/', this.controller.index.bind(this.controller));
132
- }
133
-
134
- public getRouter(): Router {
135
- return this.router;
136
- }
137
- }
138
- `;
139
-
140
- await fs.writeFile(path.join(featurePath, `${feature.name}.ts`), mainFeatureContent);
141
-
142
- // Create controller
143
- const controllerContent = `import { Request, Response } from 'express';
144
- import { ${feature.name}Service } from '../services';
145
-
146
- export class ${feature.name}Controller {
147
- constructor(private service: ${feature.name}Service) {}
148
-
149
- // Add your controller methods here
150
- // async index(req: Request, res: Response): Promise<void> {
151
- // try {
152
- // const result = await this.service.someMethod();
153
- // res.json(result);
154
- // } catch (error) {
155
- // res.status(500).json({ error: error.message });
156
- // }
157
- // }
158
- }
159
- `;
160
-
161
- await fs.writeFile(path.join(featurePath, 'controllers', `${feature.name}-controller.ts`), controllerContent);
162
-
163
- // Create service
164
- const serviceContent = `export class ${feature.name}Service {
165
- // Add your service methods here
166
- // async someMethod(): Promise<any> {
167
- // // Implementation
168
- // }
169
- }
170
- `;
171
-
172
- await fs.writeFile(path.join(featurePath, 'services', `${feature.name}-service.ts`), serviceContent);
173
-
174
- // Create types
175
- const typesContent = `// TypeScript types for ${feature.name} feature
176
- export interface ${this.capitalizeFirst(feature.name)}Config {
177
- // Add configuration interface
178
- }
179
-
180
- export interface ${this.capitalizeFirst(feature.name)}Data {
181
- // Add data interface
182
- }
183
- `;
184
-
185
- await fs.writeFile(path.join(featurePath, 'types', `${feature.name}-types.ts`), typesContent);
186
- }
187
-
188
- private async addDependencies(dependencies: string[]): Promise<void> {
189
- console.log(chalk.blue('📦 Installing dependencies...'));
190
-
191
- // This would typically run npm install with the dependencies
192
- // For now, we'll just log what would be installed
193
- console.log(chalk.yellow(`Would install: ${dependencies.join(', ')}`));
194
- console.log(chalk.gray('Run: npm install ' + dependencies.join(' ') + ' to install dependencies'));
195
- }
196
-
197
- private async updateMainConfiguration(projectPath: string, feature: Feature): Promise<void> {
198
- console.log(chalk.blue(`📝 Updating main configuration for ${feature.name} feature...`));
199
-
200
- // Update main server file to include the feature
201
- await this.updateServerFile(projectPath, feature);
202
-
203
- // Update routes index to include feature routes
204
- await this.updateRoutesIndex(projectPath, feature);
205
-
206
- // Update package.json scripts if needed
207
- await this.updatePackageJson(projectPath, feature);
208
-
209
- console.log(chalk.green(`✅ Main configuration updated for ${feature.name} feature`));
210
- }
211
-
212
- private async updateServerFile(projectPath: string, feature: Feature): Promise<void> {
213
- const serverFiles = [
214
- 'src/server/index.ts',
215
- 'main.ts',
216
- 'src/index.ts',
217
- 'lib/main.js'
218
- ];
219
-
220
- for (const serverFile of serverFiles) {
221
- const filePath = path.join(projectPath, serverFile);
222
- if (await fs.pathExists(filePath)) {
223
- let content = await fs.readFile(filePath, 'utf8');
224
-
225
- // Add import for the feature
226
- const importStatement = `import { ${this.capitalizeFirst(feature.name)}Feature } from './features/${feature.name}/${feature.name}';`;
227
-
228
- if (!content.includes(importStatement)) {
229
- // Find the last import statement and add after it
230
- const importRegex = /import.*from.*['"];?\s*$/gm;
231
- const matches = [...content.matchAll(importRegex)];
232
- if (matches.length > 0) {
233
- const lastImport = matches[matches.length - 1];
234
- const insertIndex = lastImport.index! + lastImport[0].length;
235
- content = content.slice(0, insertIndex) + '\n' + importStatement + content.slice(insertIndex);
236
- }
237
- }
238
-
239
- // Add feature initialization
240
- const featureInit = `// Initialize ${feature.name} feature
241
- const ${feature.name}Feature = new ${this.capitalizeFirst(feature.name)}Feature();
242
- app.use('/api/${feature.name}', ${feature.name}Feature.getRouter());`;
243
-
244
- if (!content.includes(featureInit)) {
245
- // Find where routes are registered and add after
246
- const routeRegex = /app\.use\(.*\);?\s*$/gm;
247
- const matches = [...content.matchAll(routeRegex)];
248
- if (matches.length > 0) {
249
- const lastRoute = matches[matches.length - 1];
250
- const insertIndex = lastRoute.index! + lastRoute[0].length;
251
- content = content.slice(0, insertIndex) + '\n' + featureInit + content.slice(insertIndex);
252
- }
253
- }
254
-
255
- await fs.writeFile(filePath, content);
256
- console.log(chalk.green(` ✅ Updated ${serverFile}`));
257
- break; // Only update the first found server file
258
- }
259
- }
260
- }
261
-
262
- private async updateRoutesIndex(projectPath: string, feature: Feature): Promise<void> {
263
- const routesIndexPath = path.join(projectPath, 'src/routes/index.ts');
264
-
265
- if (await fs.pathExists(routesIndexPath)) {
266
- let content = await fs.readFile(routesIndexPath, 'utf8');
267
-
268
- // Add import for feature routes
269
- const importStatement = `import ${feature.name}Routes from '../features/${feature.name}/routes';`;
270
-
271
- if (!content.includes(importStatement)) {
272
- const importRegex = /import.*from.*['"];?\s*$/gm;
273
- const matches = [...content.matchAll(importRegex)];
274
- if (matches.length > 0) {
275
- const lastImport = matches[matches.length - 1];
276
- const insertIndex = lastImport.index! + lastImport[0].length;
277
- content = content.slice(0, insertIndex) + '\n' + importStatement + content.slice(insertIndex);
278
- }
279
- }
280
-
281
- // Add route registration
282
- const routeRegistration = `app.use('/api/${feature.name}', ${feature.name}Routes);`;
283
-
284
- if (!content.includes(routeRegistration)) {
285
- const routeRegex = /app\.use\(.*\);?\s*$/gm;
286
- const matches = [...content.matchAll(routeRegex)];
287
- if (matches.length > 0) {
288
- const lastRoute = matches[matches.length - 1];
289
- const insertIndex = lastRoute.index! + lastRoute[0].length;
290
- content = content.slice(0, insertIndex) + '\n' + routeRegistration + content.slice(insertIndex);
291
- }
292
- }
293
-
294
- await fs.writeFile(routesIndexPath, content);
295
- console.log(chalk.green(` ✅ Updated routes/index.ts`));
296
- }
297
- }
298
-
299
- private async updatePackageJson(projectPath: string, feature: Feature): Promise<void> {
300
- const packageJsonPath = path.join(projectPath, 'package.json');
301
-
302
- if (await fs.pathExists(packageJsonPath)) {
303
- const packageJson = JSON.parse(await fs.readFile(packageJsonPath, 'utf8'));
304
-
305
- // Add feature-specific scripts if needed
306
- if (!packageJson.scripts) {
307
- packageJson.scripts = {};
308
- }
309
-
310
- // Add feature-specific scripts
311
- const featureScripts = {
312
- [`test:${feature.name}`]: `npm test -- --grep "${feature.name}"`,
313
- [`build:${feature.name}`]: `npm run build && echo "Built with ${feature.name} feature"`
314
- };
315
-
316
- for (const [scriptName, scriptCommand] of Object.entries(featureScripts)) {
317
- if (!packageJson.scripts[scriptName]) {
318
- packageJson.scripts[scriptName] = scriptCommand;
319
- }
320
- }
321
-
322
- await fs.writeFile(packageJsonPath, JSON.stringify(packageJson, null, 2));
323
- console.log(chalk.green(` ✅ Updated package.json with ${feature.name} scripts`));
324
- }
325
- }
326
-
327
- private capitalizeFirst(str: string): string {
328
- return str.charAt(0).toUpperCase() + str.slice(1);
329
- }
330
- }
@@ -1,335 +0,0 @@
1
- import * as fs from 'fs-extra';
2
- import * as path from 'path';
3
- import * as glob from 'glob';
4
- import chalk from 'chalk';
5
- import { execSync } from 'child_process';
6
-
7
- export interface InitOptions {
8
- template?: string;
9
- yes?: boolean;
10
- }
11
-
12
- export class ProjectInitializer {
13
- private templateFiles: string[] = [
14
- 'scripts',
15
- 'src/**/*',
16
- 'scripts/**/*',
17
- 'package.json',
18
- 'tsconfig.json',
19
- 'webpack.config.js',
20
- 'main.ts',
21
- 'certs/**/*'
22
- ];
23
-
24
- constructor() {
25
- // No need for template path as we'll use npm package
26
- }
27
-
28
- async initialize(projectName: string, options: InitOptions): Promise<void> {
29
- const projectPath = path.resolve(process.cwd(), projectName);
30
- const templateType = options.template || 'api';
31
-
32
- // Check if project directory already exists
33
- if (await fs.pathExists(projectPath)) {
34
- throw new Error(`Project directory ${projectName} already exists`);
35
- }
36
-
37
- // Create project directory
38
- await fs.ensureDir(projectPath);
39
-
40
- // Install the appropriate template package
41
- await this.installTemplatePackage(projectPath, templateType);
42
-
43
- // Copy template files from the installed package
44
- await this.copyTemplateFiles(projectPath, templateType);
45
-
46
- // Update package.json with project name
47
- await this.updatePackageJson(projectPath, projectName, templateType);
48
-
49
- // Create .gitignore
50
- await this.createGitignore(projectPath);
51
-
52
- // Create README
53
- await this.createReadme(projectPath, projectName, templateType);
54
-
55
- // Make scripts executable
56
- await this.makeScriptsExecutable(projectPath);
57
-
58
- // Process template for project name (update database names, etc.)
59
- await this.processTemplate(projectPath, projectName);
60
-
61
- // Clean up the temporary installation
62
- await this.cleanup(projectPath);
63
-
64
- console.log(chalk.green(`✅ Project structure created successfully`));
65
- }
66
-
67
- private async installTemplatePackage(projectPath: string, templateType: string): Promise<void> {
68
- const packageName = `@diagramers/${templateType}`;
69
- console.log(chalk.blue(`📦 Installing ${packageName} template...`));
70
-
71
- try {
72
- // Install the template package temporarily
73
- execSync(`npm install ${packageName} --no-save`, {
74
- cwd: projectPath,
75
- stdio: 'inherit'
76
- });
77
- } catch (error: any) {
78
- throw new Error(`Failed to install ${packageName} package: ${error.message}`);
79
- }
80
- }
81
-
82
- private async copyTemplateFiles(projectPath: string, templateType: string): Promise<void> {
83
- const nodeModulesPath = path.join(projectPath, 'node_modules', '@diagramers', templateType);
84
-
85
- if (!await fs.pathExists(nodeModulesPath)) {
86
- throw new Error(`@diagramers/${templateType} package not found in node_modules`);
87
- }
88
-
89
- for (const pattern of this.templateFiles) {
90
- try {
91
- const files = glob.sync(pattern, {
92
- cwd: nodeModulesPath,
93
- ignore: ['node_modules/**', 'dist/**', '.git/**'],
94
- nodir: false
95
- });
96
-
97
- for (const file of files) {
98
- const sourcePath = path.join(nodeModulesPath, file);
99
- const destPath = path.join(projectPath, file);
100
-
101
- if (await fs.pathExists(sourcePath)) {
102
- const stat = await fs.stat(sourcePath);
103
-
104
- if (stat.isDirectory()) {
105
- // Copy directory
106
- await fs.ensureDir(destPath);
107
- await fs.copy(sourcePath, destPath);
108
- } else {
109
- // Copy file
110
- await fs.ensureDir(path.dirname(destPath));
111
- await fs.copy(sourcePath, destPath);
112
- }
113
- }
114
- }
115
- } catch (error: any) {
116
- // Log warning but continue with other files
117
- console.log(chalk.yellow(`⚠️ Warning: Could not copy pattern '${pattern}': ${error.message}`));
118
- }
119
- }
120
- }
121
-
122
- private async cleanup(projectPath: string): Promise<void> {
123
- // Remove the temporary node_modules
124
- const nodeModulesPath = path.join(projectPath, 'node_modules');
125
- if (await fs.pathExists(nodeModulesPath)) {
126
- await fs.remove(nodeModulesPath);
127
- }
128
-
129
- // Remove package-lock.json if it exists
130
- const packageLockPath = path.join(projectPath, 'package-lock.json');
131
- if (await fs.pathExists(packageLockPath)) {
132
- await fs.remove(packageLockPath);
133
- }
134
- }
135
-
136
- private async updatePackageJson(projectPath: string, projectName: string, templateType: string): Promise<void> {
137
- const packageJsonPath = path.join(projectPath, 'package.json');
138
-
139
- if (await fs.pathExists(packageJsonPath)) {
140
- const packageJson = await fs.readJson(packageJsonPath);
141
- packageJson.name = projectName;
142
- packageJson.description = `${templateType.toUpperCase()} project: ${projectName}`;
143
-
144
- // Remove the bin field if it exists (this is for CLI packages)
145
- if (packageJson.bin) {
146
- delete packageJson.bin;
147
- }
148
-
149
- // Ensure CLI scripts are included
150
- if (!packageJson.scripts) {
151
- packageJson.scripts = {};
152
- }
153
-
154
- // Add CLI scripts if they don't exist
155
- if (!packageJson.scripts['generate:module']) {
156
- packageJson.scripts['generate:module'] = './scripts/generate-module.sh';
157
- }
158
- if (!packageJson.scripts['cli']) {
159
- packageJson.scripts['cli'] = './scripts/cli-commands.sh';
160
- }
161
-
162
- await fs.writeJson(packageJsonPath, packageJson, { spaces: 2 });
163
- }
164
- }
165
-
166
- private async createGitignore(projectPath: string): Promise<void> {
167
- const gitignoreContent = `
168
- # Dependencies
169
- node_modules/
170
- npm-debug.log*
171
- yarn-debug.log*
172
- yarn-error.log*
173
-
174
- # Build outputs
175
- dist/
176
- build/
177
- *.tsbuildinfo
178
-
179
- # Environment variables
180
- .env
181
- .env.local
182
- .env.development.local
183
- .env.test.local
184
- .env.production.local
185
-
186
- # IDE
187
- .vscode/
188
- .idea/
189
- *.swp
190
- *.swo
191
-
192
- # OS
193
- .DS_Store
194
- Thumbs.db
195
-
196
- # Logs
197
- logs
198
- *.log
199
-
200
- # Runtime data
201
- pids
202
- *.pid
203
- *.seed
204
- *.pid.lock
205
-
206
- # Coverage directory used by tools like istanbul
207
- coverage/
208
-
209
- # Firebase
210
- .firebase/
211
- firebase-debug.log
212
- firestore-debug.log
213
- ui-debug.log
214
-
215
- # Temporary folders
216
- tmp/
217
- temp/
218
- `.trim();
219
-
220
- await fs.writeFile(path.join(projectPath, '.gitignore'), gitignoreContent);
221
- }
222
-
223
- private async createReadme(projectPath: string, projectName: string, templateType: string): Promise<void> {
224
- const templateTitle = templateType.toUpperCase();
225
- const readmeContent = `# ${projectName}
226
-
227
- A Node.js ${templateType} project built with TypeScript and Firebase Functions.
228
-
229
- ## Features
230
-
231
- - Express.js server with TypeScript
232
- - Firebase Functions integration
233
- - Socket.io for real-time communication
234
- - MongoDB with Mongoose
235
- - Authentication system
236
- - Email notifications
237
- - Cron jobs
238
- - Audit logging
239
-
240
- ## Getting Started
241
-
242
- 1. Install dependencies:
243
- \`\`\`bash
244
- npm install
245
- \`\`\`
246
-
247
- 2. Set up environment variables:
248
- - Copy \`.env.example\` to \`.env\`
249
- - Update the values according to your configuration
250
-
251
- 3. Start development server:
252
- \`\`\`bash
253
- npm run serve
254
- \`\`\`
255
-
256
- ## Available Scripts
257
-
258
- - \`npm run serve\` - Start development server
259
- - \`npm run build:dev\` - Build for development
260
- - \`npm run build:prod\` - Build for production
261
- - \`npm run deploy\` - Deploy to Firebase
262
-
263
- ## Project Structure
264
-
265
- \`\`\`
266
- src/
267
- ├── config/ # Configuration files
268
- ├── controllers/ # Route controllers
269
- ├── entities/ # Database entities
270
- ├── helpers/ # Utility functions
271
- ├── routes/ # API routes
272
- ├── schemas/ # Validation schemas
273
- ├── server/ # Server setup
274
- └── services/ # Business logic
275
- \`\`\`
276
-
277
- ## Contributing
278
-
279
- 1. Fork the repository
280
- 2. Create a feature branch
281
- 3. Make your changes
282
- 4. Test thoroughly
283
- 5. Submit a pull request
284
-
285
- ## License
286
-
287
- MIT
288
- `;
289
-
290
- await fs.writeFile(path.join(projectPath, 'README.md'), readmeContent);
291
- }
292
-
293
- private async makeScriptsExecutable(projectPath: string): Promise<void> {
294
- const scriptsDir = path.join(projectPath, 'scripts');
295
-
296
- if (await fs.pathExists(scriptsDir)) {
297
- try {
298
- const scripts = await fs.readdir(scriptsDir);
299
- for (const script of scripts) {
300
- if (script.endsWith('.sh')) {
301
- const scriptPath = path.join(scriptsDir, script);
302
- // Make script executable (chmod 755)
303
- await fs.chmod(scriptPath, 0o755);
304
- console.log(chalk.blue(`🔧 Made executable: ${script}`));
305
- }
306
- }
307
- } catch (error: any) {
308
- console.log(chalk.yellow(`⚠️ Warning: Could not make scripts executable: ${error.message}`));
309
- }
310
- }
311
- }
312
-
313
- private async processTemplate(projectPath: string, projectName: string): Promise<void> {
314
- try {
315
- console.log(chalk.blue(`🔧 Processing template for project: ${projectName}`));
316
-
317
- // Change to project directory
318
- const originalCwd = process.cwd();
319
- process.chdir(projectPath);
320
-
321
- // Run the template processor
322
- execSync(`npm run cli process:template ${projectName}`, {
323
- stdio: 'inherit'
324
- });
325
-
326
- // Change back to original directory
327
- process.chdir(originalCwd);
328
-
329
- console.log(chalk.green(`✅ Template processed successfully`));
330
- } catch (error: any) {
331
- console.log(chalk.yellow(`⚠️ Warning: Could not process template: ${error.message}`));
332
- console.log(chalk.yellow(` You can manually run: npm run cli process:template ${projectName}`));
333
- }
334
- }
335
- }