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