@diagramers/cli 1.0.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (46) hide show
  1. package/README.md +91 -0
  2. package/dist/commands/extend.d.ts +3 -0
  3. package/dist/commands/extend.d.ts.map +1 -0
  4. package/dist/commands/extend.js +37 -0
  5. package/dist/commands/extend.js.map +1 -0
  6. package/dist/commands/init.d.ts +3 -0
  7. package/dist/commands/init.d.ts.map +1 -0
  8. package/dist/commands/init.js +31 -0
  9. package/dist/commands/init.js.map +1 -0
  10. package/dist/commands/update.d.ts +3 -0
  11. package/dist/commands/update.d.ts.map +1 -0
  12. package/dist/commands/update.js +29 -0
  13. package/dist/commands/update.js.map +1 -0
  14. package/dist/config/template-config.d.ts +21 -0
  15. package/dist/config/template-config.d.ts.map +1 -0
  16. package/dist/config/template-config.js +93 -0
  17. package/dist/config/template-config.js.map +1 -0
  18. package/dist/index.d.ts +3 -0
  19. package/dist/index.d.ts.map +1 -0
  20. package/dist/index.js +30 -0
  21. package/dist/index.js.map +1 -0
  22. package/dist/services/project-extender.d.ts +15 -0
  23. package/dist/services/project-extender.d.ts.map +1 -0
  24. package/dist/services/project-extender.js +207 -0
  25. package/dist/services/project-extender.js.map +1 -0
  26. package/dist/services/project-initializer.d.ts +15 -0
  27. package/dist/services/project-initializer.d.ts.map +1 -0
  28. package/dist/services/project-initializer.js +240 -0
  29. package/dist/services/project-initializer.js.map +1 -0
  30. package/dist/services/project-updater.d.ts +16 -0
  31. package/dist/services/project-updater.d.ts.map +1 -0
  32. package/dist/services/project-updater.js +134 -0
  33. package/dist/services/project-updater.js.map +1 -0
  34. package/package.json +51 -0
  35. package/scripts/publish.sh +58 -0
  36. package/scripts/setup.sh +38 -0
  37. package/scripts/version.sh +80 -0
  38. package/src/commands/extend.ts +35 -0
  39. package/src/commands/init.ts +27 -0
  40. package/src/commands/update.ts +25 -0
  41. package/src/config/template-config.ts +111 -0
  42. package/src/index.ts +35 -0
  43. package/src/services/project-extender.ts +196 -0
  44. package/src/services/project-initializer.ts +224 -0
  45. package/src/services/project-updater.ts +125 -0
  46. package/tsconfig.json +19 -0
@@ -0,0 +1,27 @@
1
+ import { Command } from 'commander';
2
+ import { ProjectInitializer } from '../services/project-initializer';
3
+ import chalk from 'chalk';
4
+
5
+ export function initCommand(program: Command) {
6
+ program
7
+ .command('init <project-name>')
8
+ .description('Initialize a new project from the template')
9
+ .option('-t, --template <template>', 'Template version to use', 'latest')
10
+ .option('-y, --yes', 'Skip prompts and use defaults')
11
+ .action(async (projectName: string, options: any) => {
12
+ try {
13
+ console.log(chalk.blue(`🚀 Initializing new project: ${projectName}`));
14
+
15
+ const initializer = new ProjectInitializer();
16
+ await initializer.initialize(projectName, options);
17
+
18
+ console.log(chalk.green(`✅ Project ${projectName} initialized successfully!`));
19
+ console.log(chalk.yellow(`📁 Navigate to the project: cd ${projectName}`));
20
+ console.log(chalk.yellow(`🔧 Install dependencies: npm install`));
21
+ console.log(chalk.yellow(`🚀 Start development: npm run serve`));
22
+ } catch (error: any) {
23
+ console.error(chalk.red(`❌ Failed to initialize project: ${error.message}`));
24
+ process.exit(1);
25
+ }
26
+ });
27
+ }
@@ -0,0 +1,25 @@
1
+ import { Command } from 'commander';
2
+ import { ProjectUpdater } from '../services/project-updater';
3
+ import chalk from 'chalk';
4
+
5
+ export function updateCommand(program: Command) {
6
+ program
7
+ .command('update')
8
+ .description('Update existing project with latest template features')
9
+ .option('-f, --force', 'Force update even if conflicts detected')
10
+ .option('-b, --backup', 'Create backup before updating')
11
+ .action(async (options: any) => {
12
+ try {
13
+ console.log(chalk.blue('🔄 Checking for template updates...'));
14
+
15
+ const updater = new ProjectUpdater();
16
+ await updater.update(options);
17
+
18
+ console.log(chalk.green('✅ Project updated successfully!'));
19
+ console.log(chalk.yellow('📝 Review the changes and test your application'));
20
+ } catch (error: any) {
21
+ console.error(chalk.red(`❌ Failed to update project: ${error.message}`));
22
+ process.exit(1);
23
+ }
24
+ });
25
+ }
@@ -0,0 +1,111 @@
1
+ export interface TemplateConfig {
2
+ name: string;
3
+ version: string;
4
+ description: string;
5
+ files: {
6
+ include: string[];
7
+ exclude: string[];
8
+ updateable: string[];
9
+ customizable: string[];
10
+ };
11
+ features: {
12
+ [key: string]: {
13
+ name: string;
14
+ description: string;
15
+ dependencies: string[];
16
+ files: string[];
17
+ };
18
+ };
19
+ }
20
+
21
+ export const templateConfig: TemplateConfig = {
22
+ name: 'diagrammers-api-template',
23
+ version: '1.0.0',
24
+ description: 'Node.js API template with TypeScript, Firebase Functions, and Socket.io',
25
+
26
+ files: {
27
+ include: [
28
+ 'src/**/*',
29
+ 'package.json',
30
+ 'tsconfig.json',
31
+ 'webpack.config.js',
32
+ 'main.ts',
33
+ 'certs/**/*'
34
+ ],
35
+ exclude: [
36
+ 'node_modules/**',
37
+ 'dist/**',
38
+ 'cli/**',
39
+ '.git/**',
40
+ 'backup-*/**',
41
+ '*.log',
42
+ '.env*'
43
+ ],
44
+ updateable: [
45
+ 'src/helpers/**/*',
46
+ 'src/config/**/*',
47
+ 'src/server/**/*',
48
+ 'webpack.config.js',
49
+ 'tsconfig.json'
50
+ ],
51
+ customizable: [
52
+ 'src/controllers/**/*',
53
+ 'src/entities/**/*',
54
+ 'src/routes/**/*',
55
+ 'src/services/**/*',
56
+ 'src/schemas/**/*',
57
+ 'main.ts'
58
+ ]
59
+ },
60
+
61
+ features: {
62
+ auth: {
63
+ name: 'Authentication',
64
+ description: 'JWT-based authentication system',
65
+ dependencies: ['jsonwebtoken', 'bcryptjs', '@types/jsonwebtoken', '@types/bcryptjs'],
66
+ files: [
67
+ 'src/features/auth/**/*',
68
+ 'src/helpers/auth.ts'
69
+ ]
70
+ },
71
+ email: {
72
+ name: 'Email System',
73
+ description: 'Email notification system with templates',
74
+ dependencies: ['nodemailer', 'handlebars', '@types/nodemailer'],
75
+ files: [
76
+ 'src/features/email/**/*',
77
+ 'src/helpers/mailer.ts',
78
+ 'src/assets/css/email-template.css'
79
+ ]
80
+ },
81
+ socket: {
82
+ name: 'WebSocket',
83
+ description: 'Real-time communication with Socket.io',
84
+ dependencies: ['socket.io', '@types/socket.io'],
85
+ files: [
86
+ 'src/features/socket/**/*',
87
+ 'src/server/socket-server-provider.ts'
88
+ ]
89
+ },
90
+ cron: {
91
+ name: 'Scheduled Tasks',
92
+ description: 'Cron job system for scheduled tasks',
93
+ dependencies: ['node-cron', '@types/node-cron'],
94
+ files: [
95
+ 'src/features/cron/**/*',
96
+ 'src/helpers/cronHelper.ts'
97
+ ]
98
+ },
99
+ audit: {
100
+ name: 'Audit Logging',
101
+ description: 'Comprehensive audit logging system',
102
+ dependencies: [],
103
+ files: [
104
+ 'src/features/audit/**/*',
105
+ 'src/entities/audit.ts',
106
+ 'src/schemas/audit.ts',
107
+ 'src/services/audit-service.ts'
108
+ ]
109
+ }
110
+ }
111
+ };
package/src/index.ts ADDED
@@ -0,0 +1,35 @@
1
+ #!/usr/bin/env node
2
+
3
+ import { Command } from 'commander';
4
+ import { initCommand } from './commands/init';
5
+ import { updateCommand } from './commands/update';
6
+ import { extendCommand } from './commands/extend';
7
+ import chalk from 'chalk';
8
+
9
+ const program = new Command();
10
+
11
+ program
12
+ .name('diagrammers')
13
+ .description('CLI tool for managing Diagrammers projects')
14
+ .version('1.0.0');
15
+
16
+ // Add commands
17
+ initCommand(program);
18
+ updateCommand(program);
19
+ extendCommand(program);
20
+
21
+ // Add help text
22
+ program.addHelpText('after', `
23
+ Examples:
24
+ $ diagrammers init api my-new-project
25
+ $ diagrammers init admin my-admin-dashboard
26
+ $ diagrammers update
27
+ $ diagrammers extend --feature auth
28
+ `);
29
+
30
+ program.parse();
31
+
32
+ // If no command is provided, show help
33
+ if (!process.argv.slice(2).length) {
34
+ program.outputHelp();
35
+ }
@@ -0,0 +1,196 @@
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
+ console.log(chalk.green(`✅ Feature '${featureName}' added successfully!`));
83
+ }
84
+
85
+ private async createFeatureStructure(projectPath: string, feature: Feature): Promise<void> {
86
+ const featurePath = path.join(projectPath, 'src', 'features', feature.name);
87
+
88
+ // Create basic feature structure
89
+ const structure = {
90
+ 'controllers': 'Feature controllers',
91
+ 'services': 'Feature business logic',
92
+ 'schemas': 'Feature validation schemas',
93
+ 'routes': 'Feature API routes',
94
+ 'types': 'Feature TypeScript types'
95
+ };
96
+
97
+ for (const [dir, description] of Object.entries(structure)) {
98
+ const dirPath = path.join(featurePath, dir);
99
+ await fs.ensureDir(dirPath);
100
+
101
+ // Create index file
102
+ const indexContent = `// ${description} for ${feature.name} feature
103
+ export * from './${feature.name}-${dir.slice(0, -1)}';
104
+ `;
105
+ await fs.writeFile(path.join(dirPath, 'index.ts'), indexContent);
106
+ }
107
+
108
+ // Create main feature file
109
+ const mainFeatureContent = `import { Router } from 'express';
110
+ import { ${feature.name}Controller } from './controllers';
111
+ import { ${feature.name}Service } from './services';
112
+
113
+ export class ${this.capitalizeFirst(feature.name)}Feature {
114
+ private router: Router;
115
+ private controller: ${feature.name}Controller;
116
+ private service: ${feature.name}Service;
117
+
118
+ constructor() {
119
+ this.router = Router();
120
+ this.service = new ${feature.name}Service();
121
+ this.controller = new ${feature.name}Controller(this.service);
122
+ this.setupRoutes();
123
+ }
124
+
125
+ private setupRoutes(): void {
126
+ // Define your routes here
127
+ // this.router.get('/', this.controller.index.bind(this.controller));
128
+ }
129
+
130
+ public getRouter(): Router {
131
+ return this.router;
132
+ }
133
+ }
134
+ `;
135
+
136
+ await fs.writeFile(path.join(featurePath, `${feature.name}.ts`), mainFeatureContent);
137
+
138
+ // Create controller
139
+ const controllerContent = `import { Request, Response } from 'express';
140
+ import { ${feature.name}Service } from '../services';
141
+
142
+ export class ${feature.name}Controller {
143
+ constructor(private service: ${feature.name}Service) {}
144
+
145
+ // Add your controller methods here
146
+ // async index(req: Request, res: Response): Promise<void> {
147
+ // try {
148
+ // const result = await this.service.someMethod();
149
+ // res.json(result);
150
+ // } catch (error) {
151
+ // res.status(500).json({ error: error.message });
152
+ // }
153
+ // }
154
+ }
155
+ `;
156
+
157
+ await fs.writeFile(path.join(featurePath, 'controllers', `${feature.name}-controller.ts`), controllerContent);
158
+
159
+ // Create service
160
+ const serviceContent = `export class ${feature.name}Service {
161
+ // Add your service methods here
162
+ // async someMethod(): Promise<any> {
163
+ // // Implementation
164
+ // }
165
+ }
166
+ `;
167
+
168
+ await fs.writeFile(path.join(featurePath, 'services', `${feature.name}-service.ts`), serviceContent);
169
+
170
+ // Create types
171
+ const typesContent = `// TypeScript types for ${feature.name} feature
172
+ export interface ${this.capitalizeFirst(feature.name)}Config {
173
+ // Add configuration interface
174
+ }
175
+
176
+ export interface ${this.capitalizeFirst(feature.name)}Data {
177
+ // Add data interface
178
+ }
179
+ `;
180
+
181
+ await fs.writeFile(path.join(featurePath, 'types', `${feature.name}-types.ts`), typesContent);
182
+ }
183
+
184
+ private async addDependencies(dependencies: string[]): Promise<void> {
185
+ console.log(chalk.blue('📦 Installing dependencies...'));
186
+
187
+ // This would typically run npm install with the dependencies
188
+ // For now, we'll just log what would be installed
189
+ console.log(chalk.yellow(`Would install: ${dependencies.join(', ')}`));
190
+ console.log(chalk.gray('Run: npm install ' + dependencies.join(' ') + ' to install dependencies'));
191
+ }
192
+
193
+ private capitalizeFirst(str: string): string {
194
+ return str.charAt(0).toUpperCase() + str.slice(1);
195
+ }
196
+ }
@@ -0,0 +1,224 @@
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
+
6
+ export interface InitOptions {
7
+ template?: string;
8
+ yes?: boolean;
9
+ }
10
+
11
+ export class ProjectInitializer {
12
+ private templatePath: string;
13
+ private templateFiles: string[] = [
14
+ 'src/**/*',
15
+ 'package.json',
16
+ 'tsconfig.json',
17
+ 'webpack.config.js',
18
+ 'main.ts',
19
+ 'certs/**/*'
20
+ ];
21
+
22
+ constructor() {
23
+ // Get the path to the template (parent directory of CLI)
24
+ this.templatePath = path.resolve(__dirname, '../../..');
25
+ }
26
+
27
+ async initialize(projectName: string, options: InitOptions): Promise<void> {
28
+ const projectPath = path.resolve(process.cwd(), projectName);
29
+
30
+ // Check if project directory already exists
31
+ if (await fs.pathExists(projectPath)) {
32
+ throw new Error(`Project directory ${projectName} already exists`);
33
+ }
34
+
35
+ // Create project directory
36
+ await fs.ensureDir(projectPath);
37
+
38
+ // Copy template files
39
+ await this.copyTemplateFiles(projectPath);
40
+
41
+ // Update package.json with project name
42
+ await this.updatePackageJson(projectPath, projectName);
43
+
44
+ // Create .gitignore
45
+ await this.createGitignore(projectPath);
46
+
47
+ // Create README
48
+ await this.createReadme(projectPath, projectName);
49
+
50
+ console.log(chalk.green(`✅ Project structure created successfully`));
51
+ }
52
+
53
+ private async copyTemplateFiles(projectPath: string): Promise<void> {
54
+ for (const pattern of this.templateFiles) {
55
+ try {
56
+ const files = glob.sync(pattern, {
57
+ cwd: this.templatePath,
58
+ ignore: ['node_modules/**', 'dist/**', 'cli/**', '.git/**'],
59
+ nodir: false
60
+ });
61
+
62
+ for (const file of files) {
63
+ const sourcePath = path.join(this.templatePath, file);
64
+ const destPath = path.join(projectPath, file);
65
+
66
+ if (await fs.pathExists(sourcePath)) {
67
+ const stat = await fs.stat(sourcePath);
68
+
69
+ if (stat.isDirectory()) {
70
+ // Copy directory
71
+ await fs.ensureDir(destPath);
72
+ await fs.copy(sourcePath, destPath);
73
+ } else {
74
+ // Copy file
75
+ await fs.ensureDir(path.dirname(destPath));
76
+ await fs.copy(sourcePath, destPath);
77
+ }
78
+ }
79
+ }
80
+ } catch (error: any) {
81
+ // Log warning but continue with other files
82
+ console.log(chalk.yellow(`⚠️ Warning: Could not copy pattern '${pattern}': ${error.message}`));
83
+ }
84
+ }
85
+ }
86
+
87
+ private async updatePackageJson(projectPath: string, projectName: string): Promise<void> {
88
+ const packageJsonPath = path.join(projectPath, 'package.json');
89
+
90
+ if (await fs.pathExists(packageJsonPath)) {
91
+ const packageJson = await fs.readJson(packageJsonPath);
92
+ packageJson.name = projectName;
93
+ packageJson.description = `API project: ${projectName}`;
94
+
95
+ await fs.writeJson(packageJsonPath, packageJson, { spaces: 2 });
96
+ }
97
+ }
98
+
99
+ private async createGitignore(projectPath: string): Promise<void> {
100
+ const gitignoreContent = `
101
+ # Dependencies
102
+ node_modules/
103
+ npm-debug.log*
104
+ yarn-debug.log*
105
+ yarn-error.log*
106
+
107
+ # Build outputs
108
+ dist/
109
+ build/
110
+ *.tsbuildinfo
111
+
112
+ # Environment variables
113
+ .env
114
+ .env.local
115
+ .env.development.local
116
+ .env.test.local
117
+ .env.production.local
118
+
119
+ # IDE
120
+ .vscode/
121
+ .idea/
122
+ *.swp
123
+ *.swo
124
+
125
+ # OS
126
+ .DS_Store
127
+ Thumbs.db
128
+
129
+ # Logs
130
+ logs
131
+ *.log
132
+
133
+ # Runtime data
134
+ pids
135
+ *.pid
136
+ *.seed
137
+ *.pid.lock
138
+
139
+ # Coverage directory used by tools like istanbul
140
+ coverage/
141
+
142
+ # Firebase
143
+ .firebase/
144
+ firebase-debug.log
145
+ firestore-debug.log
146
+ ui-debug.log
147
+
148
+ # Temporary folders
149
+ tmp/
150
+ temp/
151
+ `.trim();
152
+
153
+ await fs.writeFile(path.join(projectPath, '.gitignore'), gitignoreContent);
154
+ }
155
+
156
+ private async createReadme(projectPath: string, projectName: string): Promise<void> {
157
+ const readmeContent = `# ${projectName}
158
+
159
+ A Node.js API project built with TypeScript and Firebase Functions.
160
+
161
+ ## Features
162
+
163
+ - Express.js server with TypeScript
164
+ - Firebase Functions integration
165
+ - Socket.io for real-time communication
166
+ - MongoDB with Mongoose
167
+ - Authentication system
168
+ - Email notifications
169
+ - Cron jobs
170
+ - Audit logging
171
+
172
+ ## Getting Started
173
+
174
+ 1. Install dependencies:
175
+ \`\`\`bash
176
+ npm install
177
+ \`\`\`
178
+
179
+ 2. Set up environment variables:
180
+ - Copy \`.env.example\` to \`.env\`
181
+ - Update the values according to your configuration
182
+
183
+ 3. Start development server:
184
+ \`\`\`bash
185
+ npm run serve
186
+ \`\`\`
187
+
188
+ ## Available Scripts
189
+
190
+ - \`npm run serve\` - Start development server
191
+ - \`npm run build:dev\` - Build for development
192
+ - \`npm run build:prod\` - Build for production
193
+ - \`npm run deploy\` - Deploy to Firebase
194
+
195
+ ## Project Structure
196
+
197
+ \`\`\`
198
+ src/
199
+ ├── config/ # Configuration files
200
+ ├── controllers/ # Route controllers
201
+ ├── entities/ # Database entities
202
+ ├── helpers/ # Utility functions
203
+ ├── routes/ # API routes
204
+ ├── schemas/ # Validation schemas
205
+ ├── server/ # Server setup
206
+ └── services/ # Business logic
207
+ \`\`\`
208
+
209
+ ## Contributing
210
+
211
+ 1. Fork the repository
212
+ 2. Create a feature branch
213
+ 3. Make your changes
214
+ 4. Test thoroughly
215
+ 5. Submit a pull request
216
+
217
+ ## License
218
+
219
+ MIT
220
+ `;
221
+
222
+ await fs.writeFile(path.join(projectPath, 'README.md'), readmeContent);
223
+ }
224
+ }