@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,214 @@
1
+ import { Command } from 'commander';
2
+ import fs from 'fs';
3
+ import path from 'path';
4
+ import chalk from 'chalk';
5
+
6
+ const controllerTemplate = `import { Controller, Get, Post, Put, Delete, Body, Param } from '@hazeljs/core';
7
+ import { {{className}}Service } from './{{fileName}}.service';
8
+ import { Create{{className}}Dto, Update{{className}}Dto } from './dto/{{fileName}}.dto';
9
+
10
+ @Controller('/{{routePath}}')
11
+ export class {{className}}Controller {
12
+ constructor(private {{camelName}}Service: {{className}}Service) {}
13
+
14
+ @Get()
15
+ findAll() {
16
+ return this.{{camelName}}Service.findAll();
17
+ }
18
+
19
+ @Get('/:id')
20
+ findOne(@Param('id') id: string) {
21
+ return this.{{camelName}}Service.findOne(id);
22
+ }
23
+
24
+ @Post()
25
+ create(@Body() createDto: Create{{className}}Dto) {
26
+ return this.{{camelName}}Service.create(createDto);
27
+ }
28
+
29
+ @Put('/:id')
30
+ update(@Param('id') id: string, @Body() updateDto: Update{{className}}Dto) {
31
+ return this.{{camelName}}Service.update(id, updateDto);
32
+ }
33
+
34
+ @Delete('/:id')
35
+ delete(@Param('id') id: string) {
36
+ return this.{{camelName}}Service.delete(id);
37
+ }
38
+ }
39
+ `;
40
+
41
+ const serviceTemplate = `import { Injectable } from '@hazeljs/core';
42
+ import { Create{{className}}Dto, Update{{className}}Dto } from './dto/{{fileName}}.dto';
43
+
44
+ @Injectable()
45
+ export class {{className}}Service {
46
+ private {{camelName}}s: any[] = [];
47
+
48
+ findAll() {
49
+ return this.{{camelName}}s;
50
+ }
51
+
52
+ findOne(id: string) {
53
+ const {{camelName}} = this.{{camelName}}s.find(item => item.id === id);
54
+ if (!{{camelName}}) {
55
+ throw new Error('{{className}} not found');
56
+ }
57
+ return {{camelName}};
58
+ }
59
+
60
+ create(createDto: Create{{className}}Dto) {
61
+ const {{camelName}} = {
62
+ id: Date.now().toString(),
63
+ ...createDto,
64
+ createdAt: new Date(),
65
+ updatedAt: new Date(),
66
+ };
67
+ this.{{camelName}}s.push({{camelName}});
68
+ return {{camelName}};
69
+ }
70
+
71
+ update(id: string, updateDto: Update{{className}}Dto) {
72
+ const index = this.{{camelName}}s.findIndex(item => item.id === id);
73
+ if (index === -1) {
74
+ throw new Error('{{className}} not found');
75
+ }
76
+ this.{{camelName}}s[index] = {
77
+ ...this.{{camelName}}s[index],
78
+ ...updateDto,
79
+ updatedAt: new Date(),
80
+ };
81
+ return this.{{camelName}}s[index];
82
+ }
83
+
84
+ delete(id: string) {
85
+ const index = this.{{camelName}}s.findIndex(item => item.id === id);
86
+ if (index === -1) {
87
+ throw new Error('{{className}} not found');
88
+ }
89
+ const deleted = this.{{camelName}}s.splice(index, 1);
90
+ return deleted[0];
91
+ }
92
+ }
93
+ `;
94
+
95
+ const dtoTemplate = `import { IsString, IsOptional, IsNotEmpty } from 'class-validator';
96
+
97
+ export class Create{{className}}Dto {
98
+ @IsString()
99
+ @IsNotEmpty()
100
+ name: string;
101
+
102
+ @IsString()
103
+ @IsOptional()
104
+ description?: string;
105
+ }
106
+
107
+ export class Update{{className}}Dto {
108
+ @IsString()
109
+ @IsOptional()
110
+ name?: string;
111
+
112
+ @IsString()
113
+ @IsOptional()
114
+ description?: string;
115
+ }
116
+ `;
117
+
118
+ const moduleTemplate = `import { HazelModule } from '@hazeljs/core';
119
+ import { {{className}}Controller } from './{{fileName}}.controller';
120
+ import { {{className}}Service } from './{{fileName}}.service';
121
+
122
+ @HazelModule({
123
+ controllers: [{{className}}Controller],
124
+ providers: [{{className}}Service],
125
+ })
126
+ export class {{className}}Module {}
127
+ `;
128
+
129
+ function toPascalCase(str: string): string {
130
+ return str
131
+ .split(/[-_]/)
132
+ .map((word) => word.charAt(0).toUpperCase() + word.slice(1).toLowerCase())
133
+ .join('');
134
+ }
135
+
136
+ function toKebabCase(str: string): string {
137
+ return str
138
+ .replace(/([a-z])([A-Z])/g, '$1-$2')
139
+ .replace(/[\s_]+/g, '-')
140
+ .toLowerCase();
141
+ }
142
+
143
+ function toCamelCase(str: string): string {
144
+ const pascal = toPascalCase(str);
145
+ return pascal.charAt(0).toLowerCase() + pascal.slice(1);
146
+ }
147
+
148
+ function renderTemplate(template: string, data: Record<string, string>): string {
149
+ return template.replace(/\{\{(\w+)\}\}/g, (_, key) => data[key] || '');
150
+ }
151
+
152
+ export function generateCrud(command: Command) {
153
+ command
154
+ .command('crud <name>')
155
+ .description('Generate a complete CRUD resource (controller, service, module, DTOs)')
156
+ .option('-p, --path <path>', 'Specify the path', 'src')
157
+ .option('-r, --route <route>', 'Specify the route path')
158
+ .action((name: string, options: { path?: string; route?: string }) => {
159
+ const className = toPascalCase(name);
160
+ const fileName = toKebabCase(name);
161
+ const camelName = toCamelCase(name);
162
+ const routePath = options.route || fileName;
163
+ const basePath = path.join(process.cwd(), options.path || 'src', fileName);
164
+
165
+ const data = {
166
+ className,
167
+ fileName,
168
+ camelName,
169
+ routePath,
170
+ };
171
+
172
+ try {
173
+ // Create directory
174
+ if (!fs.existsSync(basePath)) {
175
+ fs.mkdirSync(basePath, { recursive: true });
176
+ }
177
+
178
+ // Create DTO directory
179
+ const dtoPath = path.join(basePath, 'dto');
180
+ if (!fs.existsSync(dtoPath)) {
181
+ fs.mkdirSync(dtoPath, { recursive: true });
182
+ }
183
+
184
+ // Generate controller
185
+ const controllerPath = path.join(basePath, `${fileName}.controller.ts`);
186
+ fs.writeFileSync(controllerPath, renderTemplate(controllerTemplate, data));
187
+ console.log(chalk.green(`✓ Generated ${controllerPath}`));
188
+
189
+ // Generate service
190
+ const servicePath = path.join(basePath, `${fileName}.service.ts`);
191
+ fs.writeFileSync(servicePath, renderTemplate(serviceTemplate, data));
192
+ console.log(chalk.green(`✓ Generated ${servicePath}`));
193
+
194
+ // Generate DTOs
195
+ const dtoFilePath = path.join(dtoPath, `${fileName}.dto.ts`);
196
+ fs.writeFileSync(dtoFilePath, renderTemplate(dtoTemplate, data));
197
+ console.log(chalk.green(`✓ Generated ${dtoFilePath}`));
198
+
199
+ // Generate module
200
+ const modulePath = path.join(basePath, `${fileName}.module.ts`);
201
+ fs.writeFileSync(modulePath, renderTemplate(moduleTemplate, data));
202
+ console.log(chalk.green(`✓ Generated ${modulePath}`));
203
+
204
+ console.log(chalk.blue('\n📦 CRUD resource generated successfully!'));
205
+ console.log(chalk.gray(`\nNext steps:`));
206
+ console.log(chalk.gray(`1. Import ${className}Module in your app module`));
207
+ console.log(chalk.gray(`2. Customize the DTOs in ${dtoFilePath}`));
208
+ console.log(chalk.gray(`3. Implement your business logic in ${servicePath}`));
209
+ } catch (error) {
210
+ console.error(chalk.red('Error generating CRUD resource:'), error);
211
+ process.exit(1);
212
+ }
213
+ });
214
+ }
@@ -0,0 +1,61 @@
1
+ import { Command } from 'commander';
2
+ import { Generator, GeneratorOptions } from '../utils/generator';
3
+
4
+ const CREATE_DTO_TEMPLATE = `import { IsString, IsOptional } from 'class-validator';
5
+
6
+ export class Create{{className}}Dto {
7
+ @IsString()
8
+ name: string;
9
+
10
+ @IsString()
11
+ @IsOptional()
12
+ description?: string;
13
+ }
14
+ `;
15
+
16
+ const UPDATE_DTO_TEMPLATE = `import { PartialType } from '@hazeljs/core';
17
+ import { Create{{className}}Dto } from './create-{{fileName}}.dto';
18
+
19
+ export class Update{{className}}Dto extends PartialType(Create{{className}}Dto) {}
20
+ `;
21
+
22
+ class DtoGenerator extends Generator {
23
+ protected getDefaultTemplate(): string {
24
+ return CREATE_DTO_TEMPLATE;
25
+ }
26
+
27
+ public async generate(options: GeneratorOptions): Promise<void> {
28
+ // Generate create DTO
29
+ const createDtoOptions = {
30
+ ...options,
31
+ template: CREATE_DTO_TEMPLATE,
32
+ path: options.path ? `${options.path}/dto` : 'src/dto',
33
+ };
34
+ await super.generate(createDtoOptions);
35
+
36
+ // Generate update DTO
37
+ const updateDtoOptions = {
38
+ ...options,
39
+ template: UPDATE_DTO_TEMPLATE,
40
+ path: options.path ? `${options.path}/dto` : 'src/dto',
41
+ };
42
+ await super.generate(updateDtoOptions);
43
+ }
44
+ }
45
+
46
+ export function generateDto(program: Command): void {
47
+ program
48
+ .command('dto <name>')
49
+ .description('Generate create and update DTOs')
50
+ .option('-p, --path <path>', 'Path where the DTOs should be generated')
51
+ .action(async (name: string, options: { path?: string }) => {
52
+ const generator = new DtoGenerator();
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
+ }
@@ -0,0 +1,53 @@
1
+ import { Command } from 'commander';
2
+ import { Generator, GeneratorOptions } from '../utils/generator';
3
+
4
+ const EXCEPTION_FILTER_TEMPLATE = `import { Catch, ExceptionFilter, ArgumentsHost, HttpError } from '@hazeljs/core';
5
+ import logger from '@hazeljs/core';
6
+
7
+ @Catch(HttpError)
8
+ export class {{className}}ExceptionFilter implements ExceptionFilter<HttpError> {
9
+ catch(exception: HttpError, host: ArgumentsHost): void {
10
+ const ctx = host.switchToHttp();
11
+ const response = ctx.getResponse();
12
+ const request = ctx.getRequest();
13
+
14
+ const status = exception.statusCode || 500;
15
+ const message = exception.message || 'Internal server error';
16
+
17
+ logger.error(\`[\${request.method}] \${request.url} - \${message} (\${status})\`);
18
+
19
+ response.status(status).json({
20
+ statusCode: status,
21
+ message,
22
+ timestamp: new Date().toISOString(),
23
+ path: request.url,
24
+ ...(exception.errors && { errors: exception.errors }),
25
+ });
26
+ }
27
+ }
28
+ `;
29
+
30
+ class ExceptionFilterGenerator extends Generator {
31
+ protected getDefaultTemplate(): string {
32
+ return EXCEPTION_FILTER_TEMPLATE;
33
+ }
34
+ }
35
+
36
+ export function generateExceptionFilter(program: Command): void {
37
+ program
38
+ .command('filter <name>')
39
+ .description('Generate a new exception filter')
40
+ .alias('f')
41
+ .option('-p, --path <path>', 'Path where the filter should be generated')
42
+ .action(async (name: string, options: { path?: string }) => {
43
+ const generator = new ExceptionFilterGenerator();
44
+ const generatorOptions: Partial<GeneratorOptions> = {
45
+ name,
46
+ path: options.path,
47
+ };
48
+
49
+ const finalOptions = await generator.promptForOptions(generatorOptions);
50
+ await generator.generate(finalOptions);
51
+ });
52
+ }
53
+
@@ -0,0 +1,37 @@
1
+ import { Command } from 'commander';
2
+ import { Generator, GeneratorOptions } from '../utils/generator';
3
+
4
+ const GUARD_TEMPLATE = `import { Injectable, CanActivate, ExecutionContext } from '@hazeljs/core';
5
+
6
+ @Injectable()
7
+ export class {{className}}Guard implements CanActivate {
8
+ canActivate(context: ExecutionContext): boolean {
9
+ const request = context.switchToHttp().getRequest();
10
+ // Add your guard logic here
11
+ return true;
12
+ }
13
+ }
14
+ `;
15
+
16
+ class GuardGenerator extends Generator {
17
+ protected getDefaultTemplate(): string {
18
+ return GUARD_TEMPLATE;
19
+ }
20
+ }
21
+
22
+ export function generateGuard(program: Command): void {
23
+ program
24
+ .command('guard <name>')
25
+ .description('Generate a new guard')
26
+ .option('-p, --path <path>', 'Path where the guard should be generated')
27
+ .action(async (name: string, options: { path?: string }) => {
28
+ const generator = new GuardGenerator();
29
+ const generatorOptions: Partial<GeneratorOptions> = {
30
+ name,
31
+ path: options.path,
32
+ };
33
+
34
+ const finalOptions = await generator.promptForOptions(generatorOptions);
35
+ await generator.generate(finalOptions);
36
+ });
37
+ }
@@ -0,0 +1,39 @@
1
+ import { Command } from 'commander';
2
+ import { Generator, GeneratorOptions } from '../utils/generator';
3
+
4
+ const INTERCEPTOR_TEMPLATE = `import { Injectable, Interceptor, ExecutionContext } from '@hazeljs/core';
5
+
6
+ @Injectable()
7
+ export class {{className}}Interceptor implements Interceptor {
8
+ async intercept(context: ExecutionContext, next: () => Promise<unknown>): Promise<unknown> {
9
+ // Pre-processing logic here (before handler execution)
10
+ const result = await next();
11
+ // Post-processing logic here (after handler execution)
12
+ // Transform the response data here
13
+ return result;
14
+ }
15
+ }
16
+ `;
17
+
18
+ class InterceptorGenerator extends Generator {
19
+ protected getDefaultTemplate(): string {
20
+ return INTERCEPTOR_TEMPLATE;
21
+ }
22
+ }
23
+
24
+ export function generateInterceptor(program: Command): void {
25
+ program
26
+ .command('interceptor <name>')
27
+ .description('Generate a new interceptor')
28
+ .option('-p, --path <path>', 'Path where the interceptor should be generated')
29
+ .action(async (name: string, options: { path?: string }) => {
30
+ const generator = new InterceptorGenerator();
31
+ const generatorOptions: Partial<GeneratorOptions> = {
32
+ name,
33
+ path: options.path,
34
+ };
35
+
36
+ const finalOptions = await generator.promptForOptions(generatorOptions);
37
+ await generator.generate(finalOptions);
38
+ });
39
+ }
@@ -0,0 +1,86 @@
1
+ import { Command } from 'commander';
2
+ import fs from 'fs';
3
+ import path from 'path';
4
+ import chalk from 'chalk';
5
+
6
+ const middlewareTemplate = `import { Request, Response, NextFunction } from 'express';
7
+ import { Injectable } from '@hazeljs/core';
8
+
9
+ @Injectable()
10
+ export class {{className}}Middleware {
11
+ use(req: Request, res: Response, next: NextFunction) {
12
+ // Add your middleware logic here
13
+ console.log(\`[{{className}}Middleware] \${req.method} \${req.path}\`);
14
+
15
+ // Example: Add custom header
16
+ res.setHeader('X-{{className}}', 'true');
17
+
18
+ // Continue to next middleware
19
+ next();
20
+ }
21
+ }
22
+ `;
23
+
24
+ function toPascalCase(str: string): string {
25
+ return str
26
+ .split(/[-_]/)
27
+ .map((word) => word.charAt(0).toUpperCase() + word.slice(1).toLowerCase())
28
+ .join('');
29
+ }
30
+
31
+ function toKebabCase(str: string): string {
32
+ return str
33
+ .replace(/([a-z])([A-Z])/g, '$1-$2')
34
+ .replace(/[\s_]+/g, '-')
35
+ .toLowerCase();
36
+ }
37
+
38
+ function renderTemplate(template: string, data: Record<string, string>): string {
39
+ return template.replace(/\{\{(\w+)\}\}/g, (_, key) => data[key] || '');
40
+ }
41
+
42
+ export function generateMiddleware(command: Command) {
43
+ command
44
+ .command('middleware <name>')
45
+ .alias('mw')
46
+ .description('Generate a middleware')
47
+ .option('-p, --path <path>', 'Specify the path', 'src/middleware')
48
+ .action((name: string, options: { path?: string }) => {
49
+ const className = toPascalCase(name);
50
+ const fileName = toKebabCase(name);
51
+ const filePath = path.join(
52
+ process.cwd(),
53
+ options.path || 'src/middleware',
54
+ `${fileName}.middleware.ts`
55
+ );
56
+
57
+ const data = {
58
+ className,
59
+ fileName,
60
+ };
61
+
62
+ try {
63
+ // Create directory if it doesn't exist
64
+ const dir = path.dirname(filePath);
65
+ if (!fs.existsSync(dir)) {
66
+ fs.mkdirSync(dir, { recursive: true });
67
+ }
68
+
69
+ // Generate middleware
70
+ fs.writeFileSync(filePath, renderTemplate(middlewareTemplate, data));
71
+ console.log(chalk.green(`✓ Generated ${filePath}`));
72
+
73
+ console.log(chalk.gray('\nUsage:'));
74
+ console.log(chalk.gray(`import { ${className}Middleware } from './${options.path?.replace('src/', '') || 'middleware'}/${fileName}.middleware';`));
75
+ console.log(chalk.gray(`\n// In your module:`));
76
+ console.log(chalk.gray(`@HazelModule({`));
77
+ console.log(chalk.gray(` providers: [${className}Middleware],`));
78
+ console.log(chalk.gray(`})`));
79
+ console.log(chalk.gray(`\n// Or apply globally in main.ts:`));
80
+ console.log(chalk.gray(`app.use(new ${className}Middleware().use);`));
81
+ } catch (error) {
82
+ console.error(chalk.red('Error generating middleware:'), error);
83
+ process.exit(1);
84
+ }
85
+ });
86
+ }
@@ -0,0 +1,102 @@
1
+ import fs from 'fs';
2
+ import path from 'path';
3
+ import { Command } from 'commander';
4
+ import { Generator, GeneratorOptions } from '../utils/generator';
5
+
6
+ const MODULE_TEMPLATE = `import { HazelModule } from '@hazeljs/core';
7
+ import { {{className}}Controller } from './{{fileName}}.controller';
8
+ import { {{className}}Service } from './{{fileName}}.service';
9
+
10
+ @HazelModule({
11
+ controllers: [{{className}}Controller],
12
+ providers: [{{className}}Service],
13
+ })
14
+ export class {{className}}Module {}
15
+ `;
16
+
17
+ const CONTROLLER_TEMPLATE = `import { Controller, Get, Post, Body } from '../../core/decorators';
18
+ import { {{className}}Service } from './{{fileName}}.service';
19
+ import { Create{{className}}Dto } from './dto/create-{{fileName}}.dto';
20
+
21
+ @Controller('/{{fileName}}')
22
+ export class {{className}}Controller {
23
+ constructor(private readonly {{fileName}}Service: {{className}}Service) {}
24
+
25
+ @Get()
26
+ findAll() {
27
+ return this.{{fileName}}Service.findAll();
28
+ }
29
+
30
+ @Post()
31
+ create(@Body() createDto: Create{{className}}Dto) {
32
+ return this.{{fileName}}Service.create(createDto);
33
+ }
34
+ }
35
+ `;
36
+
37
+ const SERVICE_TEMPLATE = `import { Injectable } from '../../core/decorators';
38
+ import { Create{{className}}Dto } from './dto/create-{{fileName}}.dto';
39
+
40
+ @Injectable()
41
+ export class {{className}}Service {
42
+ private items = [];
43
+
44
+ findAll() {
45
+ return this.items;
46
+ }
47
+
48
+ create(dto: Create{{className}}Dto) {
49
+ this.items.push(dto);
50
+ return dto;
51
+ }
52
+ }
53
+ `;
54
+
55
+ const CREATE_DTO_TEMPLATE = `export class Create{{className}}Dto {
56
+ // Add your properties here
57
+ name: string;
58
+ }
59
+ `;
60
+
61
+ const UPDATE_DTO_TEMPLATE = `export class Update{{className}}Dto {
62
+ // Add your properties here
63
+ name?: string;
64
+ }
65
+ `;
66
+
67
+ class FullModuleGenerator extends Generator {
68
+ async generate(options: GeneratorOptions): Promise<void> {
69
+ const { name, path: customPath } = options;
70
+ const className = this.toPascalCase(name);
71
+ const fileName = this.toKebabCase(name);
72
+ const baseDir = path.join(process.cwd(), customPath || 'src', fileName);
73
+
74
+ // Create module directory and dto subdirectory
75
+ fs.mkdirSync(baseDir, { recursive: true });
76
+ fs.mkdirSync(path.join(baseDir, 'dto'), { recursive: true });
77
+
78
+ // Generate files
79
+ fs.writeFileSync(path.join(baseDir, `${fileName}.module.ts`), this.render(MODULE_TEMPLATE, { className, fileName }));
80
+ fs.writeFileSync(path.join(baseDir, `${fileName}.controller.ts`), this.render(CONTROLLER_TEMPLATE, { className, fileName }));
81
+ fs.writeFileSync(path.join(baseDir, `${fileName}.service.ts`), this.render(SERVICE_TEMPLATE, { className, fileName }));
82
+ fs.writeFileSync(path.join(baseDir, 'dto', `create-${fileName}.dto.ts`), this.render(CREATE_DTO_TEMPLATE, { className, fileName }));
83
+ fs.writeFileSync(path.join(baseDir, 'dto', `update-${fileName}.dto.ts`), this.render(UPDATE_DTO_TEMPLATE, { className, fileName }));
84
+
85
+ console.log(`✓ Generated module in ${baseDir}`);
86
+ }
87
+
88
+ render(template: string, data: Record<string, string>) {
89
+ return template.replace(/{{(\w+)}}/g, (_, key) => data[key] || '');
90
+ }
91
+ }
92
+
93
+ export function generateModule(program: Command): void {
94
+ program
95
+ .command('module <name>')
96
+ .description('Generate a new module (with controller, service, DTOs)')
97
+ .option('-p, --path <path>', 'Path where the module should be generated')
98
+ .action(async (name: string, options: { path?: string }) => {
99
+ const generator = new FullModuleGenerator();
100
+ await generator.generate({ name, path: options.path });
101
+ });
102
+ }
@@ -0,0 +1,36 @@
1
+ import { Command } from 'commander';
2
+ import { Generator, GeneratorOptions } from '../utils/generator';
3
+
4
+ const PIPE_TEMPLATE = `import { PipeTransform, RequestContext } from '@hazeljs/core';
5
+
6
+ export class {{className}}Pipe implements PipeTransform {
7
+ transform(value: unknown, context: RequestContext): unknown {
8
+ // Transform logic here
9
+ return value;
10
+ }
11
+ }
12
+ `;
13
+
14
+ class PipeGenerator extends Generator {
15
+ protected getDefaultTemplate(): string {
16
+ return PIPE_TEMPLATE;
17
+ }
18
+ }
19
+
20
+ export function generatePipe(program: Command): void {
21
+ program
22
+ .command('pipe <name>')
23
+ .description('Generate a new pipe')
24
+ .option('-p, --path <path>', 'Path where the pipe should be generated')
25
+ .action(async (name: string, options: { path?: string }) => {
26
+ const generator = new PipeGenerator();
27
+ const generatorOptions: Partial<GeneratorOptions> = {
28
+ name,
29
+ path: options.path,
30
+ };
31
+
32
+ const finalOptions = await generator.promptForOptions(generatorOptions);
33
+ await generator.generate(finalOptions);
34
+ });
35
+ }
36
+
@@ -0,0 +1,41 @@
1
+ import { Command } from 'commander';
2
+ import { Generator, GeneratorOptions } from '../utils/generator';
3
+
4
+ const REPOSITORY_TEMPLATE = `import { Injectable } from '@hazeljs/core';
5
+ import { BaseRepository, PrismaService, PrismaModel } from '@hazeljs/prisma';
6
+
7
+ @Injectable()
8
+ export class {{className}}Repository extends BaseRepository<PrismaModel> {
9
+ constructor(prisma: PrismaService) {
10
+ // Replace 'modelName' with your actual Prisma model name
11
+ super(prisma.modelName as unknown as { findMany: () => Promise<PrismaModel[]>; findUnique: (args: { where: { id?: number } }) => Promise<PrismaModel | null>; create: (args: { data: unknown }) => Promise<PrismaModel>; update: (args: { where: { id?: number }; data: unknown }) => Promise<PrismaModel>; delete: (args: { where: { id?: number } }) => Promise<PrismaModel>; count: (args?: unknown) => Promise<number> });
12
+ }
13
+
14
+ // Add custom repository methods here
15
+ }
16
+ `;
17
+
18
+ class RepositoryGenerator extends Generator {
19
+ protected getDefaultTemplate(): string {
20
+ return REPOSITORY_TEMPLATE;
21
+ }
22
+ }
23
+
24
+ export function generateRepository(program: Command): void {
25
+ program
26
+ .command('repository <name>')
27
+ .description('Generate a new Prisma repository')
28
+ .alias('repo')
29
+ .option('-p, --path <path>', 'Path where the repository should be generated')
30
+ .action(async (name: string, options: { path?: string }) => {
31
+ const generator = new RepositoryGenerator();
32
+ const generatorOptions: Partial<GeneratorOptions> = {
33
+ name,
34
+ path: options.path,
35
+ };
36
+
37
+ const finalOptions = await generator.promptForOptions(generatorOptions);
38
+ await generator.generate(finalOptions);
39
+ });
40
+ }
41
+