@hazeljs/cli 0.2.0-beta.1

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 (76) hide show
  1. package/@template/README.md +61 -0
  2. package/@template/package.json +48 -0
  3. package/@template/src/app.module.ts +7 -0
  4. package/@template/src/hello.controller.ts +9 -0
  5. package/@template/src/index.ts +10 -0
  6. package/README.md +675 -0
  7. package/dist/commands/add.d.ts +2 -0
  8. package/dist/commands/add.js +90 -0
  9. package/dist/commands/build.d.ts +2 -0
  10. package/dist/commands/build.js +52 -0
  11. package/dist/commands/generate-agent.d.ts +2 -0
  12. package/dist/commands/generate-agent.js +56 -0
  13. package/dist/commands/generate-ai-service.d.ts +2 -0
  14. package/dist/commands/generate-ai-service.js +49 -0
  15. package/dist/commands/generate-app.d.ts +2 -0
  16. package/dist/commands/generate-app.js +246 -0
  17. package/dist/commands/generate-controller.d.ts +2 -0
  18. package/dist/commands/generate-controller.js +59 -0
  19. package/dist/commands/generate-crud.d.ts +2 -0
  20. package/dist/commands/generate-crud.js +203 -0
  21. package/dist/commands/generate-dto.d.ts +2 -0
  22. package/dist/commands/generate-dto.js +56 -0
  23. package/dist/commands/generate-exception-filter.d.ts +2 -0
  24. package/dist/commands/generate-exception-filter.js +50 -0
  25. package/dist/commands/generate-guard.d.ts +2 -0
  26. package/dist/commands/generate-guard.js +35 -0
  27. package/dist/commands/generate-interceptor.d.ts +2 -0
  28. package/dist/commands/generate-interceptor.js +37 -0
  29. package/dist/commands/generate-middleware.d.ts +2 -0
  30. package/dist/commands/generate-middleware.js +79 -0
  31. package/dist/commands/generate-module.d.ts +2 -0
  32. package/dist/commands/generate-module.js +96 -0
  33. package/dist/commands/generate-pipe.d.ts +2 -0
  34. package/dist/commands/generate-pipe.js +33 -0
  35. package/dist/commands/generate-repository.d.ts +2 -0
  36. package/dist/commands/generate-repository.js +38 -0
  37. package/dist/commands/generate-serverless-handler.d.ts +2 -0
  38. package/dist/commands/generate-serverless-handler.js +46 -0
  39. package/dist/commands/generate-service.d.ts +2 -0
  40. package/dist/commands/generate-service.js +51 -0
  41. package/dist/commands/generate-websocket-gateway.d.ts +2 -0
  42. package/dist/commands/generate-websocket-gateway.js +47 -0
  43. package/dist/commands/info.d.ts +2 -0
  44. package/dist/commands/info.js +91 -0
  45. package/dist/commands/start.d.ts +2 -0
  46. package/dist/commands/start.js +61 -0
  47. package/dist/commands/test.d.ts +2 -0
  48. package/dist/commands/test.js +63 -0
  49. package/dist/index.d.ts +2 -0
  50. package/dist/index.js +61 -0
  51. package/dist/utils/generator.d.ts +14 -0
  52. package/dist/utils/generator.js +79 -0
  53. package/package.json +67 -0
  54. package/src/commands/add.ts +101 -0
  55. package/src/commands/build.ts +56 -0
  56. package/src/commands/generate-agent.ts +58 -0
  57. package/src/commands/generate-ai-service.ts +52 -0
  58. package/src/commands/generate-app.ts +270 -0
  59. package/src/commands/generate-controller.ts +61 -0
  60. package/src/commands/generate-crud.ts +214 -0
  61. package/src/commands/generate-dto.ts +61 -0
  62. package/src/commands/generate-exception-filter.ts +53 -0
  63. package/src/commands/generate-guard.ts +37 -0
  64. package/src/commands/generate-interceptor.ts +39 -0
  65. package/src/commands/generate-middleware.ts +86 -0
  66. package/src/commands/generate-module.ts +102 -0
  67. package/src/commands/generate-pipe.ts +36 -0
  68. package/src/commands/generate-repository.ts +41 -0
  69. package/src/commands/generate-serverless-handler.ts +53 -0
  70. package/src/commands/generate-service.ts +53 -0
  71. package/src/commands/generate-websocket-gateway.ts +50 -0
  72. package/src/commands/info.ts +106 -0
  73. package/src/commands/start.ts +61 -0
  74. package/src/commands/test.ts +70 -0
  75. package/src/index.ts +68 -0
  76. package/src/utils/generator.ts +93 -0
@@ -0,0 +1,101 @@
1
+ import { Command } from 'commander';
2
+ import { execSync } from 'child_process';
3
+ import chalk from 'chalk';
4
+ import inquirer from 'inquirer';
5
+
6
+ const HAZEL_PACKAGES = {
7
+ ai: '@hazeljs/ai',
8
+ auth: '@hazeljs/auth',
9
+ cache: '@hazeljs/cache',
10
+ config: '@hazeljs/config',
11
+ cron: '@hazeljs/cron',
12
+ prisma: '@hazeljs/prisma',
13
+ rag: '@hazeljs/rag',
14
+ serverless: '@hazeljs/serverless',
15
+ swagger: '@hazeljs/swagger',
16
+ websocket: '@hazeljs/websocket',
17
+ discovery: '@hazeljs/discovery',
18
+ };
19
+
20
+ export function addCommand(program: Command) {
21
+ program
22
+ .command('add [package]')
23
+ .description('Add a HazelJS package to your project')
24
+ .option('--dev', 'Install as dev dependency')
25
+ .action(async (packageName?: string, options?: { dev?: boolean }) => {
26
+ try {
27
+ let selectedPackage = packageName;
28
+
29
+ // If no package specified, show interactive selection
30
+ if (!selectedPackage) {
31
+ const { package: pkg } = await inquirer.prompt([
32
+ {
33
+ type: 'list',
34
+ name: 'package',
35
+ message: 'Which HazelJS package would you like to add?',
36
+ choices: Object.keys(HAZEL_PACKAGES).map((key) => ({
37
+ name: `${key} - ${HAZEL_PACKAGES[key as keyof typeof HAZEL_PACKAGES]}`,
38
+ value: key,
39
+ })),
40
+ },
41
+ ]);
42
+ selectedPackage = pkg;
43
+ }
44
+
45
+ // Get the full package name
46
+ const fullPackageName =
47
+ HAZEL_PACKAGES[selectedPackage as keyof typeof HAZEL_PACKAGES];
48
+
49
+ if (!fullPackageName) {
50
+ console.log(chalk.yellow(`Unknown package: ${selectedPackage}`));
51
+ console.log(chalk.gray('\nAvailable packages:'));
52
+ Object.keys(HAZEL_PACKAGES).forEach((key) => {
53
+ console.log(
54
+ chalk.gray(` - ${key}: ${HAZEL_PACKAGES[key as keyof typeof HAZEL_PACKAGES]}`)
55
+ );
56
+ });
57
+ return;
58
+ }
59
+
60
+ console.log(
61
+ chalk.blue(`\n📦 Installing ${fullPackageName}...`)
62
+ );
63
+
64
+ const devFlag = options?.dev ? '--save-dev' : '';
65
+ const command = `npm install ${fullPackageName} ${devFlag}`.trim();
66
+
67
+ execSync(command, { stdio: 'inherit' });
68
+
69
+ console.log(chalk.green(`\n✓ Successfully installed ${fullPackageName}`));
70
+
71
+ // Show usage hints
72
+ console.log(chalk.gray('\nNext steps:'));
73
+ switch (selectedPackage) {
74
+ case 'ai':
75
+ console.log(chalk.gray(' import { AIModule } from "@hazeljs/ai";'));
76
+ break;
77
+ case 'auth':
78
+ console.log(chalk.gray(' import { AuthModule } from "@hazeljs/auth";'));
79
+ break;
80
+ case 'cache':
81
+ console.log(chalk.gray(' import { CacheModule } from "@hazeljs/cache";'));
82
+ break;
83
+ case 'prisma':
84
+ console.log(chalk.gray(' import { PrismaModule } from "@hazeljs/prisma";'));
85
+ break;
86
+ case 'swagger':
87
+ console.log(chalk.gray(' import { SwaggerModule } from "@hazeljs/swagger";'));
88
+ break;
89
+ case 'websocket':
90
+ console.log(chalk.gray(' import { WebSocketModule } from "@hazeljs/websocket";'));
91
+ break;
92
+ }
93
+ console.log(
94
+ chalk.gray(`\nDocumentation: https://hazeljs.com/docs/packages/${selectedPackage}`)
95
+ );
96
+ } catch (error) {
97
+ console.error(chalk.red('Error installing package:'), error);
98
+ process.exit(1);
99
+ }
100
+ });
101
+ }
@@ -0,0 +1,56 @@
1
+ import { Command } from 'commander';
2
+ import { execSync } from 'child_process';
3
+ import chalk from 'chalk';
4
+ import fs from 'fs';
5
+ import path from 'path';
6
+
7
+ export function buildCommand(program: Command) {
8
+ program
9
+ .command('build')
10
+ .description('Build the HazelJS project')
11
+ .option('-w, --watch', 'Watch mode')
12
+ .option('-p, --production', 'Production build')
13
+ .action((options: { watch?: boolean; production?: boolean }) => {
14
+ try {
15
+ const packageJsonPath = path.join(process.cwd(), 'package.json');
16
+
17
+ if (!fs.existsSync(packageJsonPath)) {
18
+ console.log(chalk.red('✗ No package.json found'));
19
+ console.log(chalk.gray('Run this command from your project root'));
20
+ process.exit(1);
21
+ }
22
+
23
+ const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, 'utf-8'));
24
+
25
+ if (!packageJson.scripts?.build) {
26
+ console.log(chalk.yellow('⚠ No build script found in package.json'));
27
+ console.log(chalk.gray('\nAdd a build script to your package.json:'));
28
+ console.log(chalk.gray(' "scripts": {'));
29
+ console.log(chalk.gray(' "build": "tsc"'));
30
+ console.log(chalk.gray(' }'));
31
+ process.exit(1);
32
+ }
33
+
34
+ console.log(chalk.blue('🔨 Building project...\n'));
35
+
36
+ let command = 'npm run build';
37
+
38
+ if (options.watch) {
39
+ command = 'npm run build -- --watch';
40
+ }
41
+
42
+ if (options.production) {
43
+ process.env.NODE_ENV = 'production';
44
+ }
45
+
46
+ execSync(command, { stdio: 'inherit' });
47
+
48
+ if (!options.watch) {
49
+ console.log(chalk.green('\n✓ Build completed successfully'));
50
+ }
51
+ } catch {
52
+ console.error(chalk.red('\n✗ Build failed'));
53
+ process.exit(1);
54
+ }
55
+ });
56
+ }
@@ -0,0 +1,58 @@
1
+ import { Command } from 'commander';
2
+ import { Generator, GeneratorOptions } from '../utils/generator';
3
+
4
+ const AGENT_TEMPLATE = `import { Agent, Tool } from '@hazeljs/agent';
5
+
6
+ @Agent({
7
+ name: '{{fileName}}',
8
+ description: '{{description}}',
9
+ systemPrompt: 'You are a helpful {{className}} agent.',
10
+ enableMemory: true,
11
+ enableRAG: true,
12
+ })
13
+ export class {{className}}Agent {
14
+ @Tool({
15
+ description: 'Example tool for {{fileName}}',
16
+ parameters: [
17
+ {
18
+ name: 'input',
19
+ type: 'string',
20
+ description: 'Input parameter',
21
+ required: true,
22
+ },
23
+ ],
24
+ })
25
+ async exampleTool(input: { input: string }): Promise<{ result: string }> {
26
+ // Implement your tool logic here
27
+ return {
28
+ result: \`Processed: \${input.input}\`,
29
+ };
30
+ }
31
+ }
32
+ `;
33
+
34
+ class AgentGenerator extends Generator {
35
+ protected getDefaultTemplate(): string {
36
+ return AGENT_TEMPLATE;
37
+ }
38
+ }
39
+
40
+ export function generateAgent(program: Command): void {
41
+ program
42
+ .command('agent <name>')
43
+ .description('Generate a new AI agent with @Agent and @Tool decorators')
44
+ .option('-p, --path <path>', 'Path where the agent should be generated')
45
+ .action(async (name: string, options: { path?: string }) => {
46
+ const generator = new AgentGenerator();
47
+ const generatorOptions: Partial<GeneratorOptions> = {
48
+ name,
49
+ path: options.path,
50
+ data: {
51
+ description: `A ${name} agent`,
52
+ },
53
+ };
54
+
55
+ const finalOptions = await generator.promptForOptions(generatorOptions);
56
+ await generator.generate(finalOptions);
57
+ });
58
+ }
@@ -0,0 +1,52 @@
1
+ import { Command } from 'commander';
2
+ import { Generator, GeneratorOptions } from '../utils/generator';
3
+
4
+ const AI_SERVICE_TEMPLATE = `import { Injectable } from '@hazeljs/core';
5
+ import { AIService } from '@hazeljs/ai';
6
+ import { AIFunction, AIPrompt } from '@hazeljs/ai';
7
+
8
+ @Injectable()
9
+ export class {{className}}AIService {
10
+ constructor(private readonly aiService: AIService) {}
11
+
12
+ @AIFunction({
13
+ provider: 'openai',
14
+ model: 'gpt-4',
15
+ streaming: false,
16
+ })
17
+ async {{fileName}}Task(@AIPrompt() prompt: string): Promise<unknown> {
18
+ const result = await this.aiService.complete({
19
+ provider: 'openai',
20
+ model: 'gpt-4',
21
+ messages: [{ role: 'user', content: prompt }],
22
+ });
23
+
24
+ return result;
25
+ }
26
+ }
27
+ `;
28
+
29
+ class AIServiceGenerator extends Generator {
30
+ protected getDefaultTemplate(): string {
31
+ return AI_SERVICE_TEMPLATE;
32
+ }
33
+ }
34
+
35
+ export function generateAIService(program: Command): void {
36
+ program
37
+ .command('ai-service <name>')
38
+ .description('Generate a new AI service with decorators')
39
+ .alias('ai')
40
+ .option('-p, --path <path>', 'Path where the AI service should be generated')
41
+ .action(async (name: string, options: { path?: string }) => {
42
+ const generator = new AIServiceGenerator();
43
+ const generatorOptions: Partial<GeneratorOptions> = {
44
+ name,
45
+ path: options.path,
46
+ };
47
+
48
+ const finalOptions = await generator.promptForOptions(generatorOptions);
49
+ await generator.generate(finalOptions);
50
+ });
51
+ }
52
+
@@ -0,0 +1,270 @@
1
+ import { Command } from 'commander';
2
+ import fs from 'fs';
3
+ import path from 'path';
4
+ import { execSync } from 'child_process';
5
+ import chalk from 'chalk';
6
+ import inquirer from 'inquirer';
7
+
8
+ function copyRecursiveSync(src: string, dest: string) {
9
+ if (fs.existsSync(src)) {
10
+ fs.mkdirSync(dest, { recursive: true });
11
+ for (const entry of fs.readdirSync(src)) {
12
+ const srcPath = path.join(src, entry);
13
+ const destPath = path.join(dest, entry);
14
+ if (fs.lstatSync(srcPath).isDirectory()) {
15
+ copyRecursiveSync(srcPath, destPath);
16
+ } else {
17
+ fs.copyFileSync(srcPath, destPath);
18
+ }
19
+ }
20
+ }
21
+ }
22
+
23
+ function updatePackageJson(destPath: string, appName: string, description: string) {
24
+ const packageJsonPath = path.join(destPath, 'package.json');
25
+ if (fs.existsSync(packageJsonPath)) {
26
+ const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, 'utf-8'));
27
+ packageJson.name = appName;
28
+ packageJson.description = description;
29
+ packageJson.version = '0.1.0';
30
+ fs.writeFileSync(packageJsonPath, JSON.stringify(packageJson, null, 2));
31
+ }
32
+ }
33
+
34
+ export function generateApp(program: Command) {
35
+ program
36
+ .command('new <appName>')
37
+ .description('Create a new HazelJS application')
38
+ .option('-d, --dest <destPath>', 'Destination path', '.')
39
+ .option('--skip-install', 'Skip npm install')
40
+ .option('--skip-git', 'Skip git initialization')
41
+ .option('-i, --interactive', 'Interactive setup')
42
+ .action(async (appName: string, options: { dest?: string; skipInstall?: boolean; skipGit?: boolean; interactive?: boolean }) => {
43
+ try {
44
+ let projectConfig = {
45
+ name: appName,
46
+ description: `A HazelJS application`,
47
+ author: '',
48
+ license: 'MIT',
49
+ packages: [] as string[],
50
+ };
51
+
52
+ // Interactive setup
53
+ if (options.interactive) {
54
+ console.log(chalk.blue('\n🚀 Welcome to HazelJS project setup!\n'));
55
+
56
+ const answers = await inquirer.prompt([
57
+ {
58
+ type: 'input',
59
+ name: 'description',
60
+ message: 'Project description:',
61
+ default: projectConfig.description,
62
+ },
63
+ {
64
+ type: 'input',
65
+ name: 'author',
66
+ message: 'Author:',
67
+ },
68
+ {
69
+ type: 'list',
70
+ name: 'license',
71
+ message: 'License:',
72
+ choices: ['MIT', 'Apache-2.0', 'GPL-3.0', 'BSD-3-Clause', 'ISC'],
73
+ default: 'MIT',
74
+ },
75
+ {
76
+ type: 'checkbox',
77
+ name: 'packages',
78
+ message: 'Select additional HazelJS packages to install:',
79
+ choices: [
80
+ { name: 'AI Integration (@hazeljs/ai)', value: '@hazeljs/ai' },
81
+ { name: 'Authentication (@hazeljs/auth)', value: '@hazeljs/auth' },
82
+ { name: 'Caching (@hazeljs/cache)', value: '@hazeljs/cache' },
83
+ { name: 'Configuration (@hazeljs/config)', value: '@hazeljs/config' },
84
+ { name: 'Cron Jobs (@hazeljs/cron)', value: '@hazeljs/cron' },
85
+ { name: 'Prisma ORM (@hazeljs/prisma)', value: '@hazeljs/prisma' },
86
+ { name: 'RAG/Vector Search (@hazeljs/rag)', value: '@hazeljs/rag' },
87
+ { name: 'Serverless (@hazeljs/serverless)', value: '@hazeljs/serverless' },
88
+ { name: 'Swagger/OpenAPI (@hazeljs/swagger)', value: '@hazeljs/swagger' },
89
+ { name: 'WebSocket (@hazeljs/websocket)', value: '@hazeljs/websocket' },
90
+ ],
91
+ },
92
+ ]);
93
+
94
+ projectConfig = { ...projectConfig, ...answers };
95
+ }
96
+
97
+ const destPath = path.join(process.cwd(), options.dest || '.', appName);
98
+
99
+ console.log(chalk.blue('\n📦 Creating new HazelJS project...\n'));
100
+ console.log(chalk.gray(`Project: ${projectConfig.name}`));
101
+ console.log(chalk.gray(`Location: ${destPath}\n`));
102
+
103
+ // Check if destination exists
104
+ if (fs.existsSync(destPath)) {
105
+ console.error(chalk.red(`✗ Destination already exists: ${destPath}`));
106
+ process.exit(1);
107
+ }
108
+
109
+ // Use local template
110
+ const templatePath = path.join(__dirname, '../../@template');
111
+
112
+ if (fs.existsSync(templatePath)) {
113
+ console.log(chalk.blue('📋 Copying template files...'));
114
+ copyRecursiveSync(templatePath, destPath);
115
+
116
+ // Update package.json
117
+ updatePackageJson(destPath, projectConfig.name, projectConfig.description);
118
+
119
+ console.log(chalk.green('✓ Template files copied'));
120
+ } else {
121
+ console.log(chalk.yellow('⚠ Local template not found, creating basic structure...'));
122
+
123
+ // Create basic structure
124
+ fs.mkdirSync(destPath, { recursive: true });
125
+ fs.mkdirSync(path.join(destPath, 'src'), { recursive: true });
126
+
127
+ // Create package.json
128
+ const packageJson = {
129
+ name: projectConfig.name,
130
+ version: '0.1.0',
131
+ description: projectConfig.description,
132
+ main: 'dist/index.js',
133
+ scripts: {
134
+ build: 'tsc',
135
+ start: 'node dist/index.js',
136
+ dev: 'ts-node-dev --respawn --transpile-only src/index.ts',
137
+ test: 'jest',
138
+ lint: 'eslint "src/**/*.ts"',
139
+ },
140
+ dependencies: {
141
+ '@hazeljs/core': '^0.2.0',
142
+ },
143
+ devDependencies: {
144
+ '@types/node': '^20.0.0',
145
+ 'typescript': '^5.0.0',
146
+ 'ts-node-dev': '^2.0.0',
147
+ },
148
+ author: projectConfig.author,
149
+ license: projectConfig.license,
150
+ };
151
+
152
+ fs.writeFileSync(
153
+ path.join(destPath, 'package.json'),
154
+ JSON.stringify(packageJson, null, 2)
155
+ );
156
+
157
+ // Create basic index.ts
158
+ const indexContent = `import { HazelApp, HazelModule, Controller, Get } from '@hazeljs/core';
159
+
160
+ @Controller('/')
161
+ export class AppController {
162
+ @Get()
163
+ hello() {
164
+ return { message: 'Hello from HazelJS!' };
165
+ }
166
+ }
167
+
168
+ @HazelModule({
169
+ controllers: [AppController],
170
+ })
171
+ export class AppModule {}
172
+
173
+ async function bootstrap() {
174
+ const app = await HazelApp.create(AppModule);
175
+ await app.listen(3000);
176
+ console.log('🚀 Server running on http://localhost:3000');
177
+ }
178
+
179
+ bootstrap();
180
+ `;
181
+ fs.writeFileSync(path.join(destPath, 'src', 'index.ts'), indexContent);
182
+
183
+ // Create tsconfig.json
184
+ const tsConfig = {
185
+ compilerOptions: {
186
+ target: 'ES2020',
187
+ module: 'commonjs',
188
+ lib: ['ES2020'],
189
+ outDir: './dist',
190
+ rootDir: './src',
191
+ strict: true,
192
+ esModuleInterop: true,
193
+ skipLibCheck: true,
194
+ forceConsistentCasingInFileNames: true,
195
+ experimentalDecorators: true,
196
+ emitDecoratorMetadata: true,
197
+ },
198
+ include: ['src/**/*'],
199
+ exclude: ['node_modules', 'dist'],
200
+ };
201
+
202
+ fs.writeFileSync(
203
+ path.join(destPath, 'tsconfig.json'),
204
+ JSON.stringify(tsConfig, null, 2)
205
+ );
206
+
207
+ console.log(chalk.green('✓ Basic structure created'));
208
+ }
209
+
210
+ // Initialize git
211
+ if (!options.skipGit) {
212
+ try {
213
+ console.log(chalk.blue('\n📝 Initializing git repository...'));
214
+ execSync('git init', { cwd: destPath, stdio: 'ignore' });
215
+
216
+ // Create .gitignore
217
+ const gitignore = `node_modules/
218
+ dist/
219
+ .env
220
+ .DS_Store
221
+ coverage/
222
+ *.log
223
+ `;
224
+ fs.writeFileSync(path.join(destPath, '.gitignore'), gitignore);
225
+ console.log(chalk.green('✓ Git initialized'));
226
+ } catch {
227
+ console.log(chalk.yellow('⚠ Git initialization skipped'));
228
+ }
229
+ }
230
+
231
+ // Install dependencies
232
+ if (!options.skipInstall) {
233
+ console.log(chalk.blue('\n📦 Installing dependencies...\n'));
234
+
235
+ try {
236
+ execSync('npm install', { cwd: destPath, stdio: 'inherit' });
237
+
238
+ // Install additional packages
239
+ if (projectConfig.packages.length > 0) {
240
+ console.log(chalk.blue('\n📦 Installing additional packages...\n'));
241
+ execSync(`npm install ${projectConfig.packages.join(' ')}`, {
242
+ cwd: destPath,
243
+ stdio: 'inherit',
244
+ });
245
+ }
246
+
247
+ console.log(chalk.green('\n✓ Dependencies installed'));
248
+ } catch {
249
+ console.log(chalk.yellow('\n⚠ Dependency installation failed'));
250
+ console.log(chalk.gray('You can install them manually with: npm install'));
251
+ }
252
+ }
253
+
254
+ // Success message
255
+ console.log(chalk.green.bold('\n✨ Project created successfully!\n'));
256
+ console.log(chalk.gray('Next steps:'));
257
+ console.log(chalk.gray(` cd ${appName}`));
258
+ if (options.skipInstall) {
259
+ console.log(chalk.gray(' npm install'));
260
+ }
261
+ console.log(chalk.gray(' npm run dev'));
262
+ console.log(chalk.gray('\nDocumentation: https://hazeljs.com/docs'));
263
+ console.log(chalk.gray('Discord: https://discord.gg/hazeljs\n'));
264
+
265
+ } catch (error) {
266
+ console.error(chalk.red('\n✗ Failed to create project:'), error);
267
+ process.exit(1);
268
+ }
269
+ });
270
+ }
@@ -0,0 +1,61 @@
1
+ import { Command } from 'commander';
2
+ import { Generator, GeneratorOptions } from '../utils/generator';
3
+
4
+ const CONTROLLER_TEMPLATE = `import { Controller, Get, Post, Body, Param, Delete, Put } from '@hazeljs/core';
5
+ import { {{className}}Service } from './{{fileName}}.service';
6
+ import { Create{{className}}Dto } from './dto/create-{{fileName}}.dto';
7
+ import { Update{{className}}Dto } from './dto/update-{{fileName}}.dto';
8
+
9
+ @Controller('{{fileName}}')
10
+ export class {{className}}Controller {
11
+ constructor(private readonly {{fileName}}Service: {{className}}Service) {}
12
+
13
+ @Get()
14
+ findAll() {
15
+ return this.{{fileName}}Service.findAll();
16
+ }
17
+
18
+ @Get(':id')
19
+ findOne(@Param('id') id: string) {
20
+ return this.{{fileName}}Service.findOne(id);
21
+ }
22
+
23
+ @Post()
24
+ create(@Body(Create{{className}}Dto) create{{className}}Dto: Create{{className}}Dto) {
25
+ return this.{{fileName}}Service.create(create{{className}}Dto);
26
+ }
27
+
28
+ @Put(':id')
29
+ update(@Param('id') id: string, @Body(Update{{className}}Dto) update{{className}}Dto: Update{{className}}Dto) {
30
+ return this.{{fileName}}Service.update(id, update{{className}}Dto);
31
+ }
32
+
33
+ @Delete(':id')
34
+ remove(@Param('id') id: string) {
35
+ return this.{{fileName}}Service.remove(id);
36
+ }
37
+ }
38
+ `;
39
+
40
+ class ControllerGenerator extends Generator {
41
+ protected getDefaultTemplate(): string {
42
+ return CONTROLLER_TEMPLATE;
43
+ }
44
+ }
45
+
46
+ export function generateController(program: Command): void {
47
+ program
48
+ .command('controller <name>')
49
+ .description('Generate a new controller')
50
+ .option('-p, --path <path>', 'Path where the controller should be generated')
51
+ .action(async (name: string, options: { path?: string }) => {
52
+ const generator = new ControllerGenerator();
53
+ const generatorOptions: Partial<GeneratorOptions> = {
54
+ name,
55
+ path: options.path,
56
+ };
57
+
58
+ const finalOptions = await generator.promptForOptions(generatorOptions);
59
+ await generator.generate(finalOptions);
60
+ });
61
+ }