@hazeljs/cli 0.5.4 → 0.6.0
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-ai-native/package.json +1 -1
- package/README.md +122 -591
- package/dist/commands/add.js +26 -126
- package/dist/commands/generate-app.js +17 -230
- package/dist/commands/generate-simple.d.ts +27 -0
- package/dist/commands/generate-simple.js +448 -0
- package/dist/commands/generate-simple.test.js +100 -0
- package/dist/index.js +5 -47
- package/dist/index.list.test.js +8 -22
- package/dist/index.test.js +19 -56
- package/dist/utils/generator-registry.js +29 -65
- package/dist/utils/generator.d.ts +0 -1
- package/dist/utils/generator.js +0 -22
- package/dist/utils/generator.test.js +0 -28
- package/dist/utils/packages-registry.d.ts +25 -0
- package/dist/utils/packages-registry.js +371 -0
- package/package.json +3 -5
- package/dist/commands/build.d.ts +0 -2
- package/dist/commands/build.js +0 -52
- package/dist/commands/generate-agent.d.ts +0 -4
- package/dist/commands/generate-agent.js +0 -64
- package/dist/commands/generate-agent.test.js +0 -36
- package/dist/commands/generate-ai-service.d.ts +0 -4
- package/dist/commands/generate-ai-service.js +0 -54
- package/dist/commands/generate-ai-service.test.d.ts +0 -1
- package/dist/commands/generate-ai-service.test.js +0 -41
- package/dist/commands/generate-cache.d.ts +0 -4
- package/dist/commands/generate-cache.js +0 -66
- package/dist/commands/generate-cache.test.d.ts +0 -1
- package/dist/commands/generate-cache.test.js +0 -36
- package/dist/commands/generate-config.d.ts +0 -4
- package/dist/commands/generate-config.js +0 -59
- package/dist/commands/generate-config.test.d.ts +0 -1
- package/dist/commands/generate-config.test.js +0 -35
- package/dist/commands/generate-controller.d.ts +0 -4
- package/dist/commands/generate-controller.js +0 -66
- package/dist/commands/generate-controller.test.d.ts +0 -1
- package/dist/commands/generate-controller.test.js +0 -48
- package/dist/commands/generate-cron.d.ts +0 -4
- package/dist/commands/generate-cron.js +0 -61
- package/dist/commands/generate-cron.test.d.ts +0 -1
- package/dist/commands/generate-cron.test.js +0 -42
- package/dist/commands/generate-discovery.d.ts +0 -4
- package/dist/commands/generate-discovery.js +0 -63
- package/dist/commands/generate-discovery.test.d.ts +0 -1
- package/dist/commands/generate-discovery.test.js +0 -36
- package/dist/commands/generate-exception-filter.d.ts +0 -4
- package/dist/commands/generate-exception-filter.js +0 -54
- package/dist/commands/generate-exception-filter.test.d.ts +0 -1
- package/dist/commands/generate-exception-filter.test.js +0 -43
- package/dist/commands/generate-guard.d.ts +0 -4
- package/dist/commands/generate-guard.js +0 -42
- package/dist/commands/generate-guard.test.d.ts +0 -1
- package/dist/commands/generate-guard.test.js +0 -41
- package/dist/commands/generate-interceptor.d.ts +0 -4
- package/dist/commands/generate-interceptor.js +0 -43
- package/dist/commands/generate-interceptor.test.d.ts +0 -1
- package/dist/commands/generate-interceptor.test.js +0 -41
- package/dist/commands/generate-middleware.d.ts +0 -4
- package/dist/commands/generate-middleware.js +0 -47
- package/dist/commands/generate-middleware.test.d.ts +0 -1
- package/dist/commands/generate-middleware.test.js +0 -41
- package/dist/commands/generate-pipe.d.ts +0 -4
- package/dist/commands/generate-pipe.js +0 -39
- package/dist/commands/generate-pipe.test.d.ts +0 -1
- package/dist/commands/generate-pipe.test.js +0 -35
- package/dist/commands/generate-rag.d.ts +0 -4
- package/dist/commands/generate-rag.js +0 -68
- package/dist/commands/generate-rag.test.d.ts +0 -1
- package/dist/commands/generate-rag.test.js +0 -35
- package/dist/commands/generate-repository.d.ts +0 -4
- package/dist/commands/generate-repository.js +0 -46
- package/dist/commands/generate-repository.test.d.ts +0 -1
- package/dist/commands/generate-repository.test.js +0 -41
- package/dist/commands/generate-serverless-handler.d.ts +0 -4
- package/dist/commands/generate-serverless-handler.js +0 -57
- package/dist/commands/generate-serverless-handler.test.d.ts +0 -1
- package/dist/commands/generate-serverless-handler.test.js +0 -42
- package/dist/commands/generate-service.d.ts +0 -4
- package/dist/commands/generate-service.js +0 -58
- package/dist/commands/generate-service.test.d.ts +0 -1
- package/dist/commands/generate-service.test.js +0 -41
- package/dist/commands/generate-setup.d.ts +0 -4
- package/dist/commands/generate-setup.js +0 -187
- package/dist/commands/generate-setup.test.d.ts +0 -1
- package/dist/commands/generate-setup.test.js +0 -50
- package/dist/commands/generate-websocket-gateway.d.ts +0 -4
- package/dist/commands/generate-websocket-gateway.js +0 -53
- package/dist/commands/generate-websocket-gateway.test.d.ts +0 -1
- package/dist/commands/generate-websocket-gateway.test.js +0 -41
- package/dist/commands/pdf-to-audio.d.ts +0 -2
- package/dist/commands/pdf-to-audio.js +0 -170
- package/dist/commands/pdf-to-audio.test.d.ts +0 -1
- package/dist/commands/pdf-to-audio.test.js +0 -92
- package/dist/commands/start.d.ts +0 -2
- package/dist/commands/start.js +0 -61
- package/dist/commands/test.d.ts +0 -2
- package/dist/commands/test.js +0 -63
- package/dist/commands/utility-commands.test.d.ts +0 -1
- package/dist/commands/utility-commands.test.js +0 -95
- /package/dist/commands/{generate-agent.test.d.ts → generate-simple.test.d.ts} +0 -0
|
@@ -0,0 +1,448 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.SIMPLE_GENERATORS = void 0;
|
|
4
|
+
exports.runSimpleGenerator = runSimpleGenerator;
|
|
5
|
+
exports.registerSimpleGenerators = registerSimpleGenerators;
|
|
6
|
+
exports.findSimpleGenerator = findSimpleGenerator;
|
|
7
|
+
const generator_1 = require("../utils/generator");
|
|
8
|
+
// ── Templates ────────────────────────────────────────────────────────────────
|
|
9
|
+
const CONTROLLER_TEMPLATE = `import { Controller, Get, Post, Body, Param, Delete, Put } from '@hazeljs/core';
|
|
10
|
+
import { {{className}}Service } from './{{fileName}}.service';
|
|
11
|
+
import { Create{{className}}Dto } from './dto/create-{{fileName}}.dto';
|
|
12
|
+
import { Update{{className}}Dto } from './dto/update-{{fileName}}.dto';
|
|
13
|
+
|
|
14
|
+
@Controller('{{fileName}}')
|
|
15
|
+
export class {{className}}Controller {
|
|
16
|
+
constructor(private readonly {{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(Create{{className}}Dto) createDto: Create{{className}}Dto) {
|
|
30
|
+
return this.{{camelName}}Service.create(createDto);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
@Put(':id')
|
|
34
|
+
update(@Param('id') id: string, @Body(Update{{className}}Dto) updateDto: Update{{className}}Dto) {
|
|
35
|
+
return this.{{camelName}}Service.update(id, updateDto);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
@Delete(':id')
|
|
39
|
+
remove(@Param('id') id: string) {
|
|
40
|
+
return this.{{camelName}}Service.remove(id);
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
`;
|
|
44
|
+
const SERVICE_TEMPLATE = `import { Service } from '@hazeljs/core';
|
|
45
|
+
|
|
46
|
+
@Service()
|
|
47
|
+
export class {{className}}Service {
|
|
48
|
+
constructor() {}
|
|
49
|
+
|
|
50
|
+
async findAll() {
|
|
51
|
+
return [];
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
async findOne(id: string) {
|
|
55
|
+
return { id };
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
async create(createDto: any) {
|
|
59
|
+
return createDto;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
async update(id: string, updateDto: any) {
|
|
63
|
+
return { id, ...updateDto };
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
async remove(id: string) {
|
|
67
|
+
return { id };
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
`;
|
|
71
|
+
const GUARD_TEMPLATE = `import { Injectable, type CanActivate, type ExecutionContext } from '@hazeljs/core';
|
|
72
|
+
|
|
73
|
+
@Injectable()
|
|
74
|
+
export class {{className}}Guard implements CanActivate {
|
|
75
|
+
canActivate(context: ExecutionContext): boolean {
|
|
76
|
+
const request = context.switchToHttp().getRequest();
|
|
77
|
+
// Add your guard logic here
|
|
78
|
+
return true;
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
`;
|
|
82
|
+
const INTERCEPTOR_TEMPLATE = `import { Injectable, Interceptor, type ExecutionContext } from '@hazeljs/core';
|
|
83
|
+
|
|
84
|
+
@Injectable()
|
|
85
|
+
export class {{className}}Interceptor implements Interceptor {
|
|
86
|
+
async intercept(context: ExecutionContext, next: () => Promise<unknown>): Promise<unknown> {
|
|
87
|
+
// Pre-processing logic here (before handler execution)
|
|
88
|
+
const result = await next();
|
|
89
|
+
// Post-processing logic here (after handler execution)
|
|
90
|
+
return result;
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
`;
|
|
94
|
+
const MIDDLEWARE_TEMPLATE = `import { Injectable, type MiddlewareHandler, type Request, type Response, type NextFunction } from '@hazeljs/core';
|
|
95
|
+
|
|
96
|
+
@Injectable()
|
|
97
|
+
export class {{className}}Middleware implements MiddlewareHandler {
|
|
98
|
+
use(req: Request, res: Response, next: NextFunction) {
|
|
99
|
+
// Add your middleware logic here
|
|
100
|
+
console.log(\`[{{className}}Middleware] \${req.method} \${req.url}\`);
|
|
101
|
+
|
|
102
|
+
// Continue to next middleware
|
|
103
|
+
next();
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
`;
|
|
107
|
+
const PIPE_TEMPLATE = `import { type PipeTransform, type RequestContext } from '@hazeljs/core';
|
|
108
|
+
|
|
109
|
+
export class {{className}}Pipe implements PipeTransform {
|
|
110
|
+
transform(value: unknown, context: RequestContext): unknown {
|
|
111
|
+
// Transform logic here
|
|
112
|
+
return value;
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
`;
|
|
116
|
+
const EXCEPTION_FILTER_TEMPLATE = `import { Catch, type ExceptionFilter, type ArgumentsHost, HttpError, logger } from '@hazeljs/core';
|
|
117
|
+
|
|
118
|
+
@Catch(HttpError)
|
|
119
|
+
export class {{className}}ExceptionFilter implements ExceptionFilter<HttpError> {
|
|
120
|
+
catch(exception: HttpError, host: ArgumentsHost): void {
|
|
121
|
+
const ctx = host.switchToHttp();
|
|
122
|
+
const response = ctx.getResponse();
|
|
123
|
+
const request = ctx.getRequest();
|
|
124
|
+
|
|
125
|
+
const status = exception.statusCode || 500;
|
|
126
|
+
const message = exception.message || 'Internal server error';
|
|
127
|
+
|
|
128
|
+
logger.error(\`[\${request.method}] \${request.url} - \${message} (\${status})\`);
|
|
129
|
+
|
|
130
|
+
response.status(status).json({
|
|
131
|
+
statusCode: status,
|
|
132
|
+
message,
|
|
133
|
+
timestamp: new Date().toISOString(),
|
|
134
|
+
path: request.url,
|
|
135
|
+
});
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
`;
|
|
139
|
+
const REPOSITORY_TEMPLATE = `import { Repository, BaseRepository, PrismaService } from '@hazeljs/prisma';
|
|
140
|
+
|
|
141
|
+
// @Repository implies @Injectable() — no need for both decorators
|
|
142
|
+
@Repository({ model: '{{modelName}}' })
|
|
143
|
+
export class {{className}}Repository extends BaseRepository<any> {
|
|
144
|
+
constructor(prisma: PrismaService) {
|
|
145
|
+
super(prisma, '{{modelName}}');
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
// Add custom repository methods here
|
|
149
|
+
async findByName(name: string) {
|
|
150
|
+
return this.findMany({ where: { name } });
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
`;
|
|
154
|
+
const WEBSOCKET_GATEWAY_TEMPLATE = `import { Realtime, OnConnect, OnDisconnect, OnMessage, Subscribe, Client, Data, WebSocketClient } from '@hazeljs/websocket';
|
|
155
|
+
|
|
156
|
+
@Realtime('/{{fileName}}')
|
|
157
|
+
export class {{className}}Gateway {
|
|
158
|
+
@OnConnect()
|
|
159
|
+
handleConnection(@Client() client: WebSocketClient) {
|
|
160
|
+
console.log('Client connected:', client.id);
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
@OnDisconnect()
|
|
164
|
+
handleDisconnect(@Client() client: WebSocketClient) {
|
|
165
|
+
console.log('Client disconnected:', client.id);
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
@Subscribe('message')
|
|
169
|
+
@OnMessage('message')
|
|
170
|
+
handleMessage(@Client() client: WebSocketClient, @Data() data: unknown) {
|
|
171
|
+
console.log('Message received from', client.id, ':', data);
|
|
172
|
+
// Handle message logic here
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
`;
|
|
176
|
+
const AI_SERVICE_TEMPLATE = `import { Service } from '@hazeljs/core';
|
|
177
|
+
import { AIService, AIFunction, AIPrompt } from '@hazeljs/ai';
|
|
178
|
+
|
|
179
|
+
@Service()
|
|
180
|
+
export class {{className}}AIService {
|
|
181
|
+
constructor(private readonly aiService: AIService) {}
|
|
182
|
+
|
|
183
|
+
@AIFunction({
|
|
184
|
+
provider: 'openai',
|
|
185
|
+
model: 'gpt-4',
|
|
186
|
+
streaming: false,
|
|
187
|
+
})
|
|
188
|
+
async {{camelName}}Task(@AIPrompt() prompt: string): Promise<unknown> {
|
|
189
|
+
const result = await this.aiService.complete({
|
|
190
|
+
provider: 'openai',
|
|
191
|
+
model: 'gpt-4',
|
|
192
|
+
messages: [{ role: 'user', content: prompt }],
|
|
193
|
+
});
|
|
194
|
+
|
|
195
|
+
return result;
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
`;
|
|
199
|
+
const AGENT_TEMPLATE = `import { Agent, Tool } from '@hazeljs/agent';
|
|
200
|
+
|
|
201
|
+
@Agent({
|
|
202
|
+
name: '{{fileName}}',
|
|
203
|
+
description: '{{description}}',
|
|
204
|
+
systemPrompt: 'You are a helpful {{className}} agent.',
|
|
205
|
+
enableMemory: true,
|
|
206
|
+
enableRAG: true,
|
|
207
|
+
})
|
|
208
|
+
export class {{className}}Agent {
|
|
209
|
+
@Tool({
|
|
210
|
+
description: 'Example tool for {{fileName}}',
|
|
211
|
+
parameters: [
|
|
212
|
+
{
|
|
213
|
+
name: 'input',
|
|
214
|
+
type: 'string',
|
|
215
|
+
description: 'Input parameter',
|
|
216
|
+
required: true,
|
|
217
|
+
},
|
|
218
|
+
],
|
|
219
|
+
})
|
|
220
|
+
async exampleTool(input: { input: string }): Promise<{ result: string }> {
|
|
221
|
+
// Implement your tool logic here
|
|
222
|
+
return {
|
|
223
|
+
result: \`Processed: \${input.input}\`,
|
|
224
|
+
};
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
`;
|
|
228
|
+
const CACHE_SERVICE_TEMPLATE = `import { Service } from '@hazeljs/core';
|
|
229
|
+
import { CacheService, Cacheable, CacheEvict } from '@hazeljs/cache';
|
|
230
|
+
|
|
231
|
+
@Service()
|
|
232
|
+
export class {{className}}CacheService {
|
|
233
|
+
constructor(private readonly cacheService: CacheService) {}
|
|
234
|
+
|
|
235
|
+
@Cacheable({ key: '{{fileName}}:all', ttl: 60 })
|
|
236
|
+
async findAll() {
|
|
237
|
+
// This result will be cached for 60 seconds
|
|
238
|
+
return [];
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
@Cacheable({ key: '{{fileName}}:{{=<% %>=}}#{id}<%={{ }}=%>', ttl: 300 })
|
|
242
|
+
async findOne(id: string) {
|
|
243
|
+
// This result will be cached for 5 minutes
|
|
244
|
+
return { id };
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
@CacheEvict({ key: '{{fileName}}:all' })
|
|
248
|
+
async create(data: any) {
|
|
249
|
+
// Creating a new item evicts the list cache
|
|
250
|
+
return data;
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
async clearAll() {
|
|
254
|
+
await this.cacheService.clear();
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
`;
|
|
258
|
+
const CRON_SERVICE_TEMPLATE = `import { Service } from '@hazeljs/core';
|
|
259
|
+
import { Cron, CronExpression } from '@hazeljs/cron';
|
|
260
|
+
|
|
261
|
+
@Service()
|
|
262
|
+
export class {{className}}CronService {
|
|
263
|
+
@Cron(CronExpression.EVERY_MINUTE)
|
|
264
|
+
handleEveryMinute() {
|
|
265
|
+
console.log('[{{className}}Cron] Running every minute...');
|
|
266
|
+
// Add your cron job logic here
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
@Cron('0 0 * * *') // Every day at midnight
|
|
270
|
+
handleDaily() {
|
|
271
|
+
console.log('[{{className}}Cron] Running daily task...');
|
|
272
|
+
// Add your daily task logic here
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
@Cron(CronExpression.EVERY_HOUR)
|
|
276
|
+
handleHourly() {
|
|
277
|
+
console.log('[{{className}}Cron] Running hourly cleanup...');
|
|
278
|
+
// Add your hourly task logic here
|
|
279
|
+
}
|
|
280
|
+
}
|
|
281
|
+
`;
|
|
282
|
+
const RAG_SERVICE_TEMPLATE = `import { Service } from '@hazeljs/core';
|
|
283
|
+
import { RAGPipeline, MemoryVectorStore } from '@hazeljs/rag';
|
|
284
|
+
|
|
285
|
+
@Service()
|
|
286
|
+
export class {{className}}RagService {
|
|
287
|
+
private pipeline: RAGPipeline;
|
|
288
|
+
|
|
289
|
+
constructor() {
|
|
290
|
+
// Initialize with a memory vector store (swap for Pinecone, Qdrant, etc. in production)
|
|
291
|
+
const vectorStore = new MemoryVectorStore();
|
|
292
|
+
|
|
293
|
+
this.pipeline = new RAGPipeline({
|
|
294
|
+
vectorStore,
|
|
295
|
+
topK: 5,
|
|
296
|
+
});
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
async addDocument(content: string, metadata?: Record<string, unknown>) {
|
|
300
|
+
// Add a document to the vector store for retrieval
|
|
301
|
+
await this.pipeline.addDocument({
|
|
302
|
+
content,
|
|
303
|
+
metadata: metadata || {},
|
|
304
|
+
});
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
async query(question: string) {
|
|
308
|
+
// Retrieve relevant documents and generate a response
|
|
309
|
+
const results = await this.pipeline.query(question);
|
|
310
|
+
return results;
|
|
311
|
+
}
|
|
312
|
+
}
|
|
313
|
+
`;
|
|
314
|
+
const DISCOVERY_TEMPLATE = `import { Service } from '@hazeljs/core';
|
|
315
|
+
import { ServiceRegistry, DiscoveryClient } from '@hazeljs/discovery';
|
|
316
|
+
|
|
317
|
+
@Service()
|
|
318
|
+
export class {{className}}DiscoveryService {
|
|
319
|
+
constructor(
|
|
320
|
+
private readonly registry: ServiceRegistry,
|
|
321
|
+
private readonly client: DiscoveryClient,
|
|
322
|
+
) {}
|
|
323
|
+
|
|
324
|
+
async registerService() {
|
|
325
|
+
await this.registry.register({
|
|
326
|
+
name: '{{fileName}}-service',
|
|
327
|
+
host: 'localhost',
|
|
328
|
+
port: 3000,
|
|
329
|
+
metadata: {
|
|
330
|
+
version: '1.0.0',
|
|
331
|
+
},
|
|
332
|
+
});
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
async discoverService(serviceName: string) {
|
|
336
|
+
const instances = await this.client.getInstances(serviceName);
|
|
337
|
+
return instances;
|
|
338
|
+
}
|
|
339
|
+
}
|
|
340
|
+
`;
|
|
341
|
+
const CONFIG_TEMPLATE = `import { HazelModule } from '@hazeljs/core';
|
|
342
|
+
import { ConfigModule, ConfigService } from '@hazeljs/config';
|
|
343
|
+
|
|
344
|
+
// Import ConfigModule.forRoot() in your app module:
|
|
345
|
+
//
|
|
346
|
+
// @HazelModule({
|
|
347
|
+
// imports: [
|
|
348
|
+
// ConfigModule.forRoot({
|
|
349
|
+
// envFilePath: '.env',
|
|
350
|
+
// }),
|
|
351
|
+
// ],
|
|
352
|
+
// })
|
|
353
|
+
//
|
|
354
|
+
// Then inject ConfigService wherever you need it:
|
|
355
|
+
//
|
|
356
|
+
// constructor(private readonly config: ConfigService) {}
|
|
357
|
+
//
|
|
358
|
+
// Usage:
|
|
359
|
+
// this.config.get('DATABASE_URL');
|
|
360
|
+
// this.config.get('PORT', '3000'); // with default value
|
|
361
|
+
|
|
362
|
+
export { ConfigModule, ConfigService };
|
|
363
|
+
`;
|
|
364
|
+
const SERVERLESS_LAMBDA_TEMPLATE = `import { createLambdaHandler } from '@hazeljs/serverless';
|
|
365
|
+
import { AppModule } from './app.module';
|
|
366
|
+
|
|
367
|
+
export const handler = createLambdaHandler(AppModule);
|
|
368
|
+
`;
|
|
369
|
+
const SERVERLESS_CLOUD_FUNCTION_TEMPLATE = `import { createCloudFunctionHandler } from '@hazeljs/serverless';
|
|
370
|
+
import { AppModule } from './app.module';
|
|
371
|
+
|
|
372
|
+
export const handler = createCloudFunctionHandler(AppModule);
|
|
373
|
+
`;
|
|
374
|
+
exports.SIMPLE_GENERATORS = [
|
|
375
|
+
{ type: 'controller', description: 'REST controller', suffix: 'controller', template: CONTROLLER_TEMPLATE, alias: 'c', nameRequired: true },
|
|
376
|
+
{ type: 'service', description: 'Service class', suffix: 'service', template: SERVICE_TEMPLATE, alias: 's', nameRequired: true },
|
|
377
|
+
{ type: 'guard', description: 'Guard (e.g. auth)', suffix: 'guard', template: GUARD_TEMPLATE, alias: 'gu', nameRequired: true },
|
|
378
|
+
{ type: 'interceptor', description: 'Interceptor', suffix: 'interceptor', template: INTERCEPTOR_TEMPLATE, alias: 'i', nameRequired: true },
|
|
379
|
+
{ type: 'middleware', description: 'Middleware', suffix: 'middleware', template: MIDDLEWARE_TEMPLATE, alias: 'mw', defaultPath: 'src/middleware', nameRequired: true, nextSteps: ['Import the middleware in your module or apply it globally.'] },
|
|
380
|
+
{ type: 'pipe', description: 'Validation/transform pipe', suffix: 'pipe', template: PIPE_TEMPLATE, nameRequired: true },
|
|
381
|
+
{ type: 'filter', description: 'Exception filter', suffix: 'filter', template: EXCEPTION_FILTER_TEMPLATE, alias: 'f', nameRequired: true },
|
|
382
|
+
{ type: 'repository', description: 'Prisma repository', suffix: 'repository', template: REPOSITORY_TEMPLATE, alias: 'repo', nameRequired: true },
|
|
383
|
+
{ type: 'gateway', description: 'WebSocket gateway', suffix: 'gateway', template: WEBSOCKET_GATEWAY_TEMPLATE, alias: 'ws', nameRequired: true },
|
|
384
|
+
{ type: 'ai-service', description: 'AI service with decorators', suffix: 'ai-service', template: AI_SERVICE_TEMPLATE, alias: 'ai', nameRequired: true },
|
|
385
|
+
{ type: 'agent', description: 'AI agent with @Agent and @Tool', suffix: 'agent', template: AGENT_TEMPLATE, nameRequired: true, extraData: (name) => ({ description: `A ${name} agent` }) },
|
|
386
|
+
{ type: 'cache', description: 'Cache service with decorators', suffix: 'cache', template: CACHE_SERVICE_TEMPLATE, nameRequired: true, nextSteps: ['npm install @hazeljs/cache', 'Add CacheModule to your module imports', 'Configure the cache strategy (memory, redis, or multi-tier)'] },
|
|
387
|
+
{ type: 'cron', description: 'Cron/scheduled job service', suffix: 'cron', template: CRON_SERVICE_TEMPLATE, alias: 'job', nameRequired: true, nextSteps: ['npm install @hazeljs/cron', 'Add CronModule to your module imports', 'Register this service as a provider'] },
|
|
388
|
+
{ type: 'rag', description: 'RAG (Retrieval-Augmented Generation) service', suffix: 'rag', template: RAG_SERVICE_TEMPLATE, nameRequired: true, nextSteps: ['npm install @hazeljs/rag', 'Register this service as a provider in your module', 'Configure your embedding provider and vector store'] },
|
|
389
|
+
{ type: 'discovery', description: 'Service discovery setup', suffix: 'discovery', template: DISCOVERY_TEMPLATE, nameRequired: true, nextSteps: ['npm install @hazeljs/discovery', 'Register this service as a provider in your module', 'Configure your discovery backend (memory, redis, consul, or kubernetes)'] },
|
|
390
|
+
{ type: 'config', description: 'Config module setup', suffix: 'config', template: CONFIG_TEMPLATE, nameRequired: false, nextSteps: ['npm install @hazeljs/config', 'Add ConfigModule.forRoot({ envFilePath: ".env" }) to your app module imports', 'Create a .env file in your project root'] },
|
|
391
|
+
{ type: 'serverless', description: 'Serverless handler (Lambda or Cloud Function)', suffix: 'handler', template: SERVERLESS_LAMBDA_TEMPLATE, alias: 'sls', nameRequired: true, extraOptions: ['platform'] },
|
|
392
|
+
];
|
|
393
|
+
// ── Runner factory ───────────────────────────────────────────────────────────
|
|
394
|
+
class SimpleGenerator extends generator_1.Generator {
|
|
395
|
+
constructor(_suffix, _template) {
|
|
396
|
+
super();
|
|
397
|
+
this._suffix = _suffix;
|
|
398
|
+
this._template = _template;
|
|
399
|
+
this.suffix = _suffix;
|
|
400
|
+
}
|
|
401
|
+
getDefaultTemplate() {
|
|
402
|
+
return this._template;
|
|
403
|
+
}
|
|
404
|
+
}
|
|
405
|
+
async function runSimpleGenerator(config, name, options) {
|
|
406
|
+
// Handle serverless platform option
|
|
407
|
+
let template = config.template;
|
|
408
|
+
if (config.type === 'serverless' && options.platform === 'cloud-function') {
|
|
409
|
+
template = SERVERLESS_CLOUD_FUNCTION_TEMPLATE;
|
|
410
|
+
}
|
|
411
|
+
const generator = new SimpleGenerator(config.suffix, template);
|
|
412
|
+
const effectiveName = config.nameRequired ? name : (name || 'app');
|
|
413
|
+
const result = await generator.generate({
|
|
414
|
+
name: effectiveName,
|
|
415
|
+
path: options.path || config.defaultPath,
|
|
416
|
+
dryRun: options.dryRun,
|
|
417
|
+
data: config.extraData ? config.extraData(effectiveName) : undefined,
|
|
418
|
+
});
|
|
419
|
+
if (config.nextSteps) {
|
|
420
|
+
result.nextSteps = [...(result.nextSteps ?? []), ...config.nextSteps];
|
|
421
|
+
}
|
|
422
|
+
return result;
|
|
423
|
+
}
|
|
424
|
+
/** Register all simple generators as sub-commands of the generate command */
|
|
425
|
+
function registerSimpleGenerators(generateCommand) {
|
|
426
|
+
for (const config of exports.SIMPLE_GENERATORS) {
|
|
427
|
+
const cmdStr = config.nameRequired ? `${config.type} <name>` : config.type;
|
|
428
|
+
const cmd = generateCommand.command(cmdStr).description(config.description);
|
|
429
|
+
if (config.alias)
|
|
430
|
+
cmd.alias(config.alias);
|
|
431
|
+
cmd.option('-p, --path <path>', 'Path where the file should be generated', config.defaultPath);
|
|
432
|
+
cmd.option('--dry-run', 'Preview files without writing them');
|
|
433
|
+
cmd.option('--json', 'Output result as JSON');
|
|
434
|
+
if (config.extraOptions?.includes('platform')) {
|
|
435
|
+
cmd.option('--platform <platform>', 'Platform: lambda or cloud-function', 'lambda');
|
|
436
|
+
}
|
|
437
|
+
cmd.action(async (nameOrOptions, maybeOptions) => {
|
|
438
|
+
const name = typeof nameOrOptions === 'string' ? nameOrOptions : '';
|
|
439
|
+
const opts = typeof nameOrOptions === 'string' ? (maybeOptions || {}) : nameOrOptions;
|
|
440
|
+
const result = await runSimpleGenerator(config, name, opts);
|
|
441
|
+
(0, generator_1.printGenerateResult)(result, { json: opts.json });
|
|
442
|
+
});
|
|
443
|
+
}
|
|
444
|
+
}
|
|
445
|
+
/** Lookup a simple generator config by type */
|
|
446
|
+
function findSimpleGenerator(type) {
|
|
447
|
+
return exports.SIMPLE_GENERATORS.find((g) => g.type === type);
|
|
448
|
+
}
|
|
@@ -0,0 +1,100 @@
|
|
|
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
|
+
const fs_1 = __importDefault(require("fs"));
|
|
7
|
+
const commander_1 = require("commander");
|
|
8
|
+
const generate_simple_1 = require("./generate-simple");
|
|
9
|
+
jest.mock('fs');
|
|
10
|
+
describe('generate-simple', () => {
|
|
11
|
+
const mockFs = fs_1.default;
|
|
12
|
+
beforeEach(() => {
|
|
13
|
+
jest.clearAllMocks();
|
|
14
|
+
mockFs.existsSync.mockReturnValue(true);
|
|
15
|
+
mockFs.writeFileSync.mockImplementation(() => { });
|
|
16
|
+
});
|
|
17
|
+
describe('SIMPLE_GENERATORS', () => {
|
|
18
|
+
it('should have at least 15 generator configs', () => {
|
|
19
|
+
expect(generate_simple_1.SIMPLE_GENERATORS.length).toBeGreaterThanOrEqual(15);
|
|
20
|
+
});
|
|
21
|
+
it('should have unique types', () => {
|
|
22
|
+
const types = generate_simple_1.SIMPLE_GENERATORS.map((g) => g.type);
|
|
23
|
+
expect(new Set(types).size).toBe(types.length);
|
|
24
|
+
});
|
|
25
|
+
it('should all have non-empty templates', () => {
|
|
26
|
+
for (const g of generate_simple_1.SIMPLE_GENERATORS) {
|
|
27
|
+
expect(g.template.length).toBeGreaterThan(0);
|
|
28
|
+
}
|
|
29
|
+
});
|
|
30
|
+
});
|
|
31
|
+
describe('findSimpleGenerator', () => {
|
|
32
|
+
it('finds by type', () => {
|
|
33
|
+
const config = (0, generate_simple_1.findSimpleGenerator)('controller');
|
|
34
|
+
expect(config).toBeDefined();
|
|
35
|
+
expect(config.type).toBe('controller');
|
|
36
|
+
});
|
|
37
|
+
it('returns undefined for unknown type', () => {
|
|
38
|
+
expect((0, generate_simple_1.findSimpleGenerator)('nope')).toBeUndefined();
|
|
39
|
+
});
|
|
40
|
+
});
|
|
41
|
+
describe('runSimpleGenerator', () => {
|
|
42
|
+
it('generates a controller file in dry-run', async () => {
|
|
43
|
+
const config = (0, generate_simple_1.findSimpleGenerator)('controller');
|
|
44
|
+
const result = await (0, generate_simple_1.runSimpleGenerator)(config, 'users', { dryRun: true });
|
|
45
|
+
expect(result.ok).toBe(true);
|
|
46
|
+
expect(result.dryRun).toBe(true);
|
|
47
|
+
expect(result.created[0]).toContain('users.controller.ts');
|
|
48
|
+
});
|
|
49
|
+
it('generates a guard file', async () => {
|
|
50
|
+
const config = (0, generate_simple_1.findSimpleGenerator)('guard');
|
|
51
|
+
const result = await (0, generate_simple_1.runSimpleGenerator)(config, 'auth', {});
|
|
52
|
+
expect(result.ok).toBe(true);
|
|
53
|
+
expect(result.created[0]).toContain('auth.guard.ts');
|
|
54
|
+
expect(mockFs.writeFileSync).toHaveBeenCalled();
|
|
55
|
+
});
|
|
56
|
+
it('generates agent with extra data', async () => {
|
|
57
|
+
const config = (0, generate_simple_1.findSimpleGenerator)('agent');
|
|
58
|
+
const result = await (0, generate_simple_1.runSimpleGenerator)(config, 'weather', { dryRun: true });
|
|
59
|
+
expect(result.ok).toBe(true);
|
|
60
|
+
expect(result.created[0]).toContain('weather.agent.ts');
|
|
61
|
+
});
|
|
62
|
+
it('appends nextSteps for cache generator', async () => {
|
|
63
|
+
const config = (0, generate_simple_1.findSimpleGenerator)('cache');
|
|
64
|
+
const result = await (0, generate_simple_1.runSimpleGenerator)(config, 'product', { dryRun: true });
|
|
65
|
+
expect(result.nextSteps).toBeDefined();
|
|
66
|
+
expect(result.nextSteps.some((s) => s.includes('@hazeljs/cache'))).toBe(true);
|
|
67
|
+
});
|
|
68
|
+
it('handles config generator (no name required)', async () => {
|
|
69
|
+
const config = (0, generate_simple_1.findSimpleGenerator)('config');
|
|
70
|
+
const result = await (0, generate_simple_1.runSimpleGenerator)(config, '', { dryRun: true });
|
|
71
|
+
expect(result.ok).toBe(true);
|
|
72
|
+
expect(result.created[0]).toContain('app.config.ts');
|
|
73
|
+
});
|
|
74
|
+
it('handles serverless with cloud-function platform', async () => {
|
|
75
|
+
const config = (0, generate_simple_1.findSimpleGenerator)('serverless');
|
|
76
|
+
const result = await (0, generate_simple_1.runSimpleGenerator)(config, 'api', { dryRun: true, platform: 'cloud-function' });
|
|
77
|
+
expect(result.ok).toBe(true);
|
|
78
|
+
expect(result.created[0]).toContain('api.handler.ts');
|
|
79
|
+
});
|
|
80
|
+
it('generates with custom path', async () => {
|
|
81
|
+
const config = (0, generate_simple_1.findSimpleGenerator)('service');
|
|
82
|
+
const result = await (0, generate_simple_1.runSimpleGenerator)(config, 'order', { path: 'src/orders', dryRun: true });
|
|
83
|
+
expect(result.ok).toBe(true);
|
|
84
|
+
expect(result.created[0]).toContain('src/orders');
|
|
85
|
+
});
|
|
86
|
+
});
|
|
87
|
+
describe('registerSimpleGenerators', () => {
|
|
88
|
+
it('registers all simple generators as sub-commands', () => {
|
|
89
|
+
const program = new commander_1.Command();
|
|
90
|
+
(0, generate_simple_1.registerSimpleGenerators)(program);
|
|
91
|
+
const commandNames = program.commands.map((c) => c.name());
|
|
92
|
+
expect(commandNames).toContain('controller');
|
|
93
|
+
expect(commandNames).toContain('guard');
|
|
94
|
+
expect(commandNames).toContain('agent');
|
|
95
|
+
expect(commandNames).toContain('serverless');
|
|
96
|
+
expect(commandNames).toContain('config');
|
|
97
|
+
expect(commandNames.length).toBe(generate_simple_1.SIMPLE_GENERATORS.length);
|
|
98
|
+
});
|
|
99
|
+
});
|
|
100
|
+
});
|
package/dist/index.js
CHANGED
|
@@ -2,36 +2,15 @@
|
|
|
2
2
|
"use strict";
|
|
3
3
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
4
4
|
const commander_1 = require("commander");
|
|
5
|
-
const generate_module_1 = require("./commands/generate-module");
|
|
6
5
|
const generate_app_1 = require("./commands/generate-app");
|
|
7
|
-
const
|
|
8
|
-
const generate_service_1 = require("./commands/generate-service");
|
|
6
|
+
const generate_module_1 = require("./commands/generate-module");
|
|
9
7
|
const generate_dto_1 = require("./commands/generate-dto");
|
|
10
|
-
const generate_guard_1 = require("./commands/generate-guard");
|
|
11
|
-
const generate_interceptor_1 = require("./commands/generate-interceptor");
|
|
12
|
-
const generate_websocket_gateway_1 = require("./commands/generate-websocket-gateway");
|
|
13
|
-
const generate_exception_filter_1 = require("./commands/generate-exception-filter");
|
|
14
|
-
const generate_pipe_1 = require("./commands/generate-pipe");
|
|
15
|
-
const generate_repository_1 = require("./commands/generate-repository");
|
|
16
|
-
const generate_ai_service_1 = require("./commands/generate-ai-service");
|
|
17
|
-
const generate_agent_1 = require("./commands/generate-agent");
|
|
18
|
-
const generate_serverless_handler_1 = require("./commands/generate-serverless-handler");
|
|
19
8
|
const generate_crud_1 = require("./commands/generate-crud");
|
|
20
|
-
const generate_middleware_1 = require("./commands/generate-middleware");
|
|
21
9
|
const generate_auth_1 = require("./commands/generate-auth");
|
|
22
|
-
const
|
|
23
|
-
const generate_cache_1 = require("./commands/generate-cache");
|
|
24
|
-
const generate_cron_1 = require("./commands/generate-cron");
|
|
25
|
-
const generate_rag_1 = require("./commands/generate-rag");
|
|
26
|
-
const generate_discovery_1 = require("./commands/generate-discovery");
|
|
27
|
-
const generate_setup_1 = require("./commands/generate-setup");
|
|
10
|
+
const generate_simple_1 = require("./commands/generate-simple");
|
|
28
11
|
const generator_registry_1 = require("./utils/generator-registry");
|
|
29
12
|
const info_1 = require("./commands/info");
|
|
30
13
|
const add_1 = require("./commands/add");
|
|
31
|
-
const build_1 = require("./commands/build");
|
|
32
|
-
const pdf_to_audio_1 = require("./commands/pdf-to-audio");
|
|
33
|
-
const start_1 = require("./commands/start");
|
|
34
|
-
const test_1 = require("./commands/test");
|
|
35
14
|
const program = new commander_1.Command();
|
|
36
15
|
program
|
|
37
16
|
.name('hazel')
|
|
@@ -42,10 +21,6 @@ program
|
|
|
42
21
|
// Utility commands
|
|
43
22
|
(0, info_1.infoCommand)(program);
|
|
44
23
|
(0, add_1.addCommand)(program);
|
|
45
|
-
(0, build_1.buildCommand)(program);
|
|
46
|
-
(0, pdf_to_audio_1.pdfToAudioCommand)(program);
|
|
47
|
-
(0, start_1.startCommand)(program);
|
|
48
|
-
(0, test_1.testCommand)(program);
|
|
49
24
|
// Generate command group (unified: hazel g <type> <name> [--path] [--dry-run] [--json], or hazel g --list)
|
|
50
25
|
const generateCommand = program
|
|
51
26
|
.command('generate')
|
|
@@ -77,28 +52,11 @@ const generateCommand = program
|
|
|
77
52
|
});
|
|
78
53
|
// Skeleton app
|
|
79
54
|
(0, generate_app_1.registerGenerateApp)(generateCommand);
|
|
80
|
-
//
|
|
81
|
-
(0, generate_controller_1.generateController)(generateCommand);
|
|
82
|
-
(0, generate_service_1.generateService)(generateCommand);
|
|
55
|
+
// Complex generators (multi-file output)
|
|
83
56
|
(0, generate_module_1.generateModule)(generateCommand);
|
|
84
57
|
(0, generate_dto_1.generateDto)(generateCommand);
|
|
85
|
-
(0, generate_guard_1.generateGuard)(generateCommand);
|
|
86
|
-
(0, generate_interceptor_1.generateInterceptor)(generateCommand);
|
|
87
|
-
(0, generate_middleware_1.generateMiddleware)(generateCommand);
|
|
88
|
-
// Advanced generators
|
|
89
58
|
(0, generate_crud_1.generateCrud)(generateCommand);
|
|
90
59
|
(0, generate_auth_1.generateAuth)(generateCommand);
|
|
91
|
-
(
|
|
92
|
-
(0,
|
|
93
|
-
(0, generate_pipe_1.generatePipe)(generateCommand);
|
|
94
|
-
(0, generate_repository_1.generateRepository)(generateCommand);
|
|
95
|
-
(0, generate_ai_service_1.generateAIService)(generateCommand);
|
|
96
|
-
(0, generate_agent_1.generateAgent)(generateCommand);
|
|
97
|
-
(0, generate_serverless_handler_1.generateServerlessHandler)(generateCommand);
|
|
98
|
-
(0, generate_config_1.generateConfig)(generateCommand);
|
|
99
|
-
(0, generate_cache_1.generateCache)(generateCommand);
|
|
100
|
-
(0, generate_cron_1.generateCron)(generateCommand);
|
|
101
|
-
(0, generate_rag_1.generateRag)(generateCommand);
|
|
102
|
-
(0, generate_discovery_1.generateDiscovery)(generateCommand);
|
|
103
|
-
(0, generate_setup_1.generateSetup)(generateCommand);
|
|
60
|
+
// Simple generators (config-driven single-file output)
|
|
61
|
+
(0, generate_simple_1.registerSimpleGenerators)(generateCommand);
|
|
104
62
|
program.parse(process.argv);
|
package/dist/index.list.test.js
CHANGED
|
@@ -4,34 +4,20 @@ jest.mock('./commands/generate-app', () => ({
|
|
|
4
4
|
generateApp: jest.fn(),
|
|
5
5
|
registerGenerateApp: jest.fn(),
|
|
6
6
|
}));
|
|
7
|
-
jest.mock('./commands/generate-controller', () => ({ generateController: jest.fn() }));
|
|
8
|
-
jest.mock('./commands/generate-service', () => ({ generateService: jest.fn() }));
|
|
9
7
|
jest.mock('./commands/generate-module', () => ({ generateModule: jest.fn() }));
|
|
10
8
|
jest.mock('./commands/generate-dto', () => ({ generateDto: jest.fn() }));
|
|
11
|
-
jest.mock('./commands/generate-guard', () => ({ generateGuard: jest.fn() }));
|
|
12
|
-
jest.mock('./commands/generate-interceptor', () => ({ generateInterceptor: jest.fn() }));
|
|
13
|
-
jest.mock('./commands/generate-middleware', () => ({ generateMiddleware: jest.fn() }));
|
|
14
9
|
jest.mock('./commands/generate-crud', () => ({ generateCrud: jest.fn() }));
|
|
15
10
|
jest.mock('./commands/generate-auth', () => ({ generateAuth: jest.fn() }));
|
|
16
|
-
jest.mock('./commands/generate-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
jest.mock('./commands/generate-cache', () => ({ generateCache: jest.fn() }));
|
|
25
|
-
jest.mock('./commands/generate-cron', () => ({ generateCron: jest.fn() }));
|
|
26
|
-
jest.mock('./commands/generate-rag', () => ({ generateRag: jest.fn() }));
|
|
27
|
-
jest.mock('./commands/generate-discovery', () => ({ generateDiscovery: jest.fn() }));
|
|
28
|
-
jest.mock('./commands/generate-setup', () => ({ generateSetup: jest.fn() }));
|
|
11
|
+
jest.mock('./commands/generate-simple', () => ({
|
|
12
|
+
registerSimpleGenerators: jest.fn(),
|
|
13
|
+
SIMPLE_GENERATORS: [
|
|
14
|
+
{ type: 'controller', description: 'REST controller', suffix: 'controller', template: '', nameRequired: true },
|
|
15
|
+
],
|
|
16
|
+
findSimpleGenerator: jest.fn(),
|
|
17
|
+
runSimpleGenerator: jest.fn(),
|
|
18
|
+
}));
|
|
29
19
|
jest.mock('./commands/info', () => ({ infoCommand: jest.fn() }));
|
|
30
20
|
jest.mock('./commands/add', () => ({ addCommand: jest.fn() }));
|
|
31
|
-
jest.mock('./commands/build', () => ({ buildCommand: jest.fn() }));
|
|
32
|
-
jest.mock('./commands/pdf-to-audio', () => ({ pdfToAudioCommand: jest.fn() }));
|
|
33
|
-
jest.mock('./commands/start', () => ({ startCommand: jest.fn() }));
|
|
34
|
-
jest.mock('./commands/test', () => ({ testCommand: jest.fn() }));
|
|
35
21
|
describe('CLI generate --list', () => {
|
|
36
22
|
let logSpy;
|
|
37
23
|
beforeAll(() => {
|