@hazeljs/cli 0.5.4 → 0.6.5

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 (117) hide show
  1. package/@template-ai-native/package.json +1 -1
  2. package/README.md +140 -588
  3. package/cli-manifest.json +940 -0
  4. package/dist/commands/add.d.ts +9 -0
  5. package/dist/commands/add.js +35 -126
  6. package/dist/commands/generate-app.js +17 -230
  7. package/dist/commands/generate-auth.d.ts +12 -0
  8. package/dist/commands/generate-auth.js +12 -0
  9. package/dist/commands/generate-crud.d.ts +12 -0
  10. package/dist/commands/generate-crud.js +12 -0
  11. package/dist/commands/generate-dto.d.ts +12 -0
  12. package/dist/commands/generate-dto.js +12 -0
  13. package/dist/commands/generate-module.d.ts +12 -0
  14. package/dist/commands/generate-module.js +12 -0
  15. package/dist/commands/generate-simple.d.ts +74 -0
  16. package/dist/commands/generate-simple.js +104 -0
  17. package/dist/commands/generate-simple.test.js +100 -0
  18. package/dist/commands/info.d.ts +12 -0
  19. package/dist/commands/info.js +12 -0
  20. package/dist/commands/templates.d.ts +34 -0
  21. package/dist/commands/templates.js +387 -0
  22. package/dist/index.d.ts +40 -0
  23. package/dist/index.js +50 -48
  24. package/dist/index.list.test.js +8 -22
  25. package/dist/index.test.js +19 -56
  26. package/dist/utils/generator-registry.d.ts +5 -0
  27. package/dist/utils/generator-registry.js +34 -65
  28. package/dist/utils/generator.d.ts +0 -1
  29. package/dist/utils/generator.js +0 -22
  30. package/dist/utils/generator.test.js +0 -28
  31. package/dist/utils/packages-registry.d.ts +34 -0
  32. package/dist/utils/packages-registry.js +380 -0
  33. package/package.json +7 -7
  34. package/dist/commands/build.d.ts +0 -2
  35. package/dist/commands/build.js +0 -52
  36. package/dist/commands/generate-agent.d.ts +0 -4
  37. package/dist/commands/generate-agent.js +0 -64
  38. package/dist/commands/generate-agent.test.js +0 -36
  39. package/dist/commands/generate-ai-service.d.ts +0 -4
  40. package/dist/commands/generate-ai-service.js +0 -54
  41. package/dist/commands/generate-ai-service.test.d.ts +0 -1
  42. package/dist/commands/generate-ai-service.test.js +0 -41
  43. package/dist/commands/generate-cache.d.ts +0 -4
  44. package/dist/commands/generate-cache.js +0 -66
  45. package/dist/commands/generate-cache.test.d.ts +0 -1
  46. package/dist/commands/generate-cache.test.js +0 -36
  47. package/dist/commands/generate-config.d.ts +0 -4
  48. package/dist/commands/generate-config.js +0 -59
  49. package/dist/commands/generate-config.test.d.ts +0 -1
  50. package/dist/commands/generate-config.test.js +0 -35
  51. package/dist/commands/generate-controller.d.ts +0 -4
  52. package/dist/commands/generate-controller.js +0 -66
  53. package/dist/commands/generate-controller.test.d.ts +0 -1
  54. package/dist/commands/generate-controller.test.js +0 -48
  55. package/dist/commands/generate-cron.d.ts +0 -4
  56. package/dist/commands/generate-cron.js +0 -61
  57. package/dist/commands/generate-cron.test.d.ts +0 -1
  58. package/dist/commands/generate-cron.test.js +0 -42
  59. package/dist/commands/generate-discovery.d.ts +0 -4
  60. package/dist/commands/generate-discovery.js +0 -63
  61. package/dist/commands/generate-discovery.test.d.ts +0 -1
  62. package/dist/commands/generate-discovery.test.js +0 -36
  63. package/dist/commands/generate-exception-filter.d.ts +0 -4
  64. package/dist/commands/generate-exception-filter.js +0 -54
  65. package/dist/commands/generate-exception-filter.test.d.ts +0 -1
  66. package/dist/commands/generate-exception-filter.test.js +0 -43
  67. package/dist/commands/generate-guard.d.ts +0 -4
  68. package/dist/commands/generate-guard.js +0 -42
  69. package/dist/commands/generate-guard.test.d.ts +0 -1
  70. package/dist/commands/generate-guard.test.js +0 -41
  71. package/dist/commands/generate-interceptor.d.ts +0 -4
  72. package/dist/commands/generate-interceptor.js +0 -43
  73. package/dist/commands/generate-interceptor.test.d.ts +0 -1
  74. package/dist/commands/generate-interceptor.test.js +0 -41
  75. package/dist/commands/generate-middleware.d.ts +0 -4
  76. package/dist/commands/generate-middleware.js +0 -47
  77. package/dist/commands/generate-middleware.test.d.ts +0 -1
  78. package/dist/commands/generate-middleware.test.js +0 -41
  79. package/dist/commands/generate-pipe.d.ts +0 -4
  80. package/dist/commands/generate-pipe.js +0 -39
  81. package/dist/commands/generate-pipe.test.d.ts +0 -1
  82. package/dist/commands/generate-pipe.test.js +0 -35
  83. package/dist/commands/generate-rag.d.ts +0 -4
  84. package/dist/commands/generate-rag.js +0 -68
  85. package/dist/commands/generate-rag.test.d.ts +0 -1
  86. package/dist/commands/generate-rag.test.js +0 -35
  87. package/dist/commands/generate-repository.d.ts +0 -4
  88. package/dist/commands/generate-repository.js +0 -46
  89. package/dist/commands/generate-repository.test.d.ts +0 -1
  90. package/dist/commands/generate-repository.test.js +0 -41
  91. package/dist/commands/generate-serverless-handler.d.ts +0 -4
  92. package/dist/commands/generate-serverless-handler.js +0 -57
  93. package/dist/commands/generate-serverless-handler.test.d.ts +0 -1
  94. package/dist/commands/generate-serverless-handler.test.js +0 -42
  95. package/dist/commands/generate-service.d.ts +0 -4
  96. package/dist/commands/generate-service.js +0 -58
  97. package/dist/commands/generate-service.test.d.ts +0 -1
  98. package/dist/commands/generate-service.test.js +0 -41
  99. package/dist/commands/generate-setup.d.ts +0 -4
  100. package/dist/commands/generate-setup.js +0 -187
  101. package/dist/commands/generate-setup.test.d.ts +0 -1
  102. package/dist/commands/generate-setup.test.js +0 -50
  103. package/dist/commands/generate-websocket-gateway.d.ts +0 -4
  104. package/dist/commands/generate-websocket-gateway.js +0 -53
  105. package/dist/commands/generate-websocket-gateway.test.d.ts +0 -1
  106. package/dist/commands/generate-websocket-gateway.test.js +0 -41
  107. package/dist/commands/pdf-to-audio.d.ts +0 -2
  108. package/dist/commands/pdf-to-audio.js +0 -170
  109. package/dist/commands/pdf-to-audio.test.d.ts +0 -1
  110. package/dist/commands/pdf-to-audio.test.js +0 -92
  111. package/dist/commands/start.d.ts +0 -2
  112. package/dist/commands/start.js +0 -61
  113. package/dist/commands/test.d.ts +0 -2
  114. package/dist/commands/test.js +0 -63
  115. package/dist/commands/utility-commands.test.d.ts +0 -1
  116. package/dist/commands/utility-commands.test.js +0 -95
  117. /package/dist/commands/{generate-agent.test.d.ts → generate-simple.test.d.ts} +0 -0
@@ -0,0 +1,387 @@
1
+ "use strict";
2
+ /**
3
+ * Mustache templates for all simple (single-file) generators.
4
+ *
5
+ * Each template uses three standard variables provided by the Generator base class:
6
+ * - {{className}} — PascalCase name (e.g. "Users")
7
+ * - {{fileName}} — kebab-case name (e.g. "users")
8
+ * - {{camelName}} — camelCase name (e.g. "users")
9
+ *
10
+ * Some templates accept additional data via `extraData` in SimpleGeneratorConfig:
11
+ * - AGENT_TEMPLATE — {{description}}
12
+ * - REPOSITORY_TEMPLATE — {{modelName}} (defaults to fileName)
13
+ *
14
+ * Templates are imported by generate-simple.ts and referenced in the
15
+ * SIMPLE_GENERATORS config array. To add a new generator, create a template
16
+ * here and add a config entry in generate-simple.ts.
17
+ */
18
+ Object.defineProperty(exports, "__esModule", { value: true });
19
+ exports.SERVERLESS_CLOUD_FUNCTION_TEMPLATE = exports.SERVERLESS_LAMBDA_TEMPLATE = exports.CONFIG_TEMPLATE = exports.DISCOVERY_TEMPLATE = exports.RAG_SERVICE_TEMPLATE = exports.CRON_SERVICE_TEMPLATE = exports.CACHE_SERVICE_TEMPLATE = exports.AGENT_TEMPLATE = exports.AI_SERVICE_TEMPLATE = exports.WEBSOCKET_GATEWAY_TEMPLATE = exports.REPOSITORY_TEMPLATE = exports.EXCEPTION_FILTER_TEMPLATE = exports.PIPE_TEMPLATE = exports.MIDDLEWARE_TEMPLATE = exports.INTERCEPTOR_TEMPLATE = exports.GUARD_TEMPLATE = exports.SERVICE_TEMPLATE = exports.CONTROLLER_TEMPLATE = void 0;
20
+ // ── Core framework generators ────────────────────────────────────────────────
21
+ exports.CONTROLLER_TEMPLATE = `import { Controller, Get, Post, Body, Param, Delete, Put } from '@hazeljs/core';
22
+ import { {{className}}Service } from './{{fileName}}.service';
23
+ import { Create{{className}}Dto } from './dto/create-{{fileName}}.dto';
24
+ import { Update{{className}}Dto } from './dto/update-{{fileName}}.dto';
25
+
26
+ @Controller('{{fileName}}')
27
+ export class {{className}}Controller {
28
+ constructor(private readonly {{camelName}}Service: {{className}}Service) {}
29
+
30
+ @Get()
31
+ findAll() {
32
+ return this.{{camelName}}Service.findAll();
33
+ }
34
+
35
+ @Get(':id')
36
+ findOne(@Param('id') id: string) {
37
+ return this.{{camelName}}Service.findOne(id);
38
+ }
39
+
40
+ @Post()
41
+ create(@Body(Create{{className}}Dto) createDto: Create{{className}}Dto) {
42
+ return this.{{camelName}}Service.create(createDto);
43
+ }
44
+
45
+ @Put(':id')
46
+ update(@Param('id') id: string, @Body(Update{{className}}Dto) updateDto: Update{{className}}Dto) {
47
+ return this.{{camelName}}Service.update(id, updateDto);
48
+ }
49
+
50
+ @Delete(':id')
51
+ remove(@Param('id') id: string) {
52
+ return this.{{camelName}}Service.remove(id);
53
+ }
54
+ }
55
+ `;
56
+ exports.SERVICE_TEMPLATE = `import { Service } from '@hazeljs/core';
57
+
58
+ @Service()
59
+ export class {{className}}Service {
60
+ constructor() {}
61
+
62
+ async findAll() {
63
+ return [];
64
+ }
65
+
66
+ async findOne(id: string) {
67
+ return { id };
68
+ }
69
+
70
+ async create(createDto: any) {
71
+ return createDto;
72
+ }
73
+
74
+ async update(id: string, updateDto: any) {
75
+ return { id, ...updateDto };
76
+ }
77
+
78
+ async remove(id: string) {
79
+ return { id };
80
+ }
81
+ }
82
+ `;
83
+ exports.GUARD_TEMPLATE = `import { Injectable, type CanActivate, type ExecutionContext } from '@hazeljs/core';
84
+
85
+ @Injectable()
86
+ export class {{className}}Guard implements CanActivate {
87
+ canActivate(context: ExecutionContext): boolean {
88
+ const request = context.switchToHttp().getRequest();
89
+ // Add your guard logic here
90
+ return true;
91
+ }
92
+ }
93
+ `;
94
+ exports.INTERCEPTOR_TEMPLATE = `import { Injectable, Interceptor, type ExecutionContext } from '@hazeljs/core';
95
+
96
+ @Injectable()
97
+ export class {{className}}Interceptor implements Interceptor {
98
+ async intercept(context: ExecutionContext, next: () => Promise<unknown>): Promise<unknown> {
99
+ // Pre-processing logic here (before handler execution)
100
+ const result = await next();
101
+ // Post-processing logic here (after handler execution)
102
+ return result;
103
+ }
104
+ }
105
+ `;
106
+ exports.MIDDLEWARE_TEMPLATE = `import { Injectable, type MiddlewareHandler, type Request, type Response, type NextFunction } from '@hazeljs/core';
107
+
108
+ @Injectable()
109
+ export class {{className}}Middleware implements MiddlewareHandler {
110
+ use(req: Request, res: Response, next: NextFunction) {
111
+ // Add your middleware logic here
112
+ console.log(\`[{{className}}Middleware] \${req.method} \${req.url}\`);
113
+
114
+ // Continue to next middleware
115
+ next();
116
+ }
117
+ }
118
+ `;
119
+ exports.PIPE_TEMPLATE = `import { type PipeTransform, type RequestContext } from '@hazeljs/core';
120
+
121
+ export class {{className}}Pipe implements PipeTransform {
122
+ transform(value: unknown, context: RequestContext): unknown {
123
+ // Transform logic here
124
+ return value;
125
+ }
126
+ }
127
+ `;
128
+ exports.EXCEPTION_FILTER_TEMPLATE = `import { Catch, type ExceptionFilter, type ArgumentsHost, HttpError, logger } from '@hazeljs/core';
129
+
130
+ @Catch(HttpError)
131
+ export class {{className}}ExceptionFilter implements ExceptionFilter<HttpError> {
132
+ catch(exception: HttpError, host: ArgumentsHost): void {
133
+ const ctx = host.switchToHttp();
134
+ const response = ctx.getResponse();
135
+ const request = ctx.getRequest();
136
+
137
+ const status = exception.statusCode || 500;
138
+ const message = exception.message || 'Internal server error';
139
+
140
+ logger.error(\`[\${request.method}] \${request.url} - \${message} (\${status})\`);
141
+
142
+ response.status(status).json({
143
+ statusCode: status,
144
+ message,
145
+ timestamp: new Date().toISOString(),
146
+ path: request.url,
147
+ });
148
+ }
149
+ }
150
+ `;
151
+ // ── Package-specific generators ──────────────────────────────────────────────
152
+ exports.REPOSITORY_TEMPLATE = `import { Repository, BaseRepository, PrismaService } from '@hazeljs/prisma';
153
+
154
+ // @Repository implies @Injectable() — no need for both decorators
155
+ @Repository({ model: '{{modelName}}' })
156
+ export class {{className}}Repository extends BaseRepository<any> {
157
+ constructor(prisma: PrismaService) {
158
+ super(prisma, '{{modelName}}');
159
+ }
160
+
161
+ // Add custom repository methods here
162
+ async findByName(name: string) {
163
+ return this.findMany({ where: { name } });
164
+ }
165
+ }
166
+ `;
167
+ exports.WEBSOCKET_GATEWAY_TEMPLATE = `import { Realtime, OnConnect, OnDisconnect, OnMessage, Subscribe, Client, Data, WebSocketClient } from '@hazeljs/websocket';
168
+
169
+ @Realtime('/{{fileName}}')
170
+ export class {{className}}Gateway {
171
+ @OnConnect()
172
+ handleConnection(@Client() client: WebSocketClient) {
173
+ console.log('Client connected:', client.id);
174
+ }
175
+
176
+ @OnDisconnect()
177
+ handleDisconnect(@Client() client: WebSocketClient) {
178
+ console.log('Client disconnected:', client.id);
179
+ }
180
+
181
+ @Subscribe('message')
182
+ @OnMessage('message')
183
+ handleMessage(@Client() client: WebSocketClient, @Data() data: unknown) {
184
+ console.log('Message received from', client.id, ':', data);
185
+ // Handle message logic here
186
+ }
187
+ }
188
+ `;
189
+ exports.AI_SERVICE_TEMPLATE = `import { Service } from '@hazeljs/core';
190
+ import { AIService, AIFunction, AIPrompt } from '@hazeljs/ai';
191
+
192
+ @Service()
193
+ export class {{className}}AIService {
194
+ constructor(private readonly aiService: AIService) {}
195
+
196
+ @AIFunction({
197
+ provider: 'openai',
198
+ model: 'gpt-4',
199
+ streaming: false,
200
+ })
201
+ async {{camelName}}Task(@AIPrompt() prompt: string): Promise<unknown> {
202
+ const result = await this.aiService.complete({
203
+ provider: 'openai',
204
+ model: 'gpt-4',
205
+ messages: [{ role: 'user', content: prompt }],
206
+ });
207
+
208
+ return result;
209
+ }
210
+ }
211
+ `;
212
+ exports.AGENT_TEMPLATE = `import { Agent, Tool } from '@hazeljs/agent';
213
+
214
+ @Agent({
215
+ name: '{{fileName}}',
216
+ description: '{{description}}',
217
+ systemPrompt: 'You are a helpful {{className}} agent.',
218
+ enableMemory: true,
219
+ enableRAG: true,
220
+ })
221
+ export class {{className}}Agent {
222
+ @Tool({
223
+ description: 'Example tool for {{fileName}}',
224
+ parameters: [
225
+ {
226
+ name: 'input',
227
+ type: 'string',
228
+ description: 'Input parameter',
229
+ required: true,
230
+ },
231
+ ],
232
+ })
233
+ async exampleTool(input: { input: string }): Promise<{ result: string }> {
234
+ // Implement your tool logic here
235
+ return {
236
+ result: \`Processed: \${input.input}\`,
237
+ };
238
+ }
239
+ }
240
+ `;
241
+ exports.CACHE_SERVICE_TEMPLATE = `import { Service } from '@hazeljs/core';
242
+ import { CacheService, Cacheable, CacheEvict } from '@hazeljs/cache';
243
+
244
+ @Service()
245
+ export class {{className}}CacheService {
246
+ constructor(private readonly cacheService: CacheService) {}
247
+
248
+ @Cacheable({ key: '{{fileName}}:all', ttl: 60 })
249
+ async findAll() {
250
+ // This result will be cached for 60 seconds
251
+ return [];
252
+ }
253
+
254
+ @Cacheable({ key: '{{fileName}}:{{=<% %>=}}#{id}<%={{ }}=%>', ttl: 300 })
255
+ async findOne(id: string) {
256
+ // This result will be cached for 5 minutes
257
+ return { id };
258
+ }
259
+
260
+ @CacheEvict({ key: '{{fileName}}:all' })
261
+ async create(data: any) {
262
+ // Creating a new item evicts the list cache
263
+ return data;
264
+ }
265
+
266
+ async clearAll() {
267
+ await this.cacheService.clear();
268
+ }
269
+ }
270
+ `;
271
+ exports.CRON_SERVICE_TEMPLATE = `import { Service } from '@hazeljs/core';
272
+ import { Cron, CronExpression } from '@hazeljs/cron';
273
+
274
+ @Service()
275
+ export class {{className}}CronService {
276
+ @Cron(CronExpression.EVERY_MINUTE)
277
+ handleEveryMinute() {
278
+ console.log('[{{className}}Cron] Running every minute...');
279
+ // Add your cron job logic here
280
+ }
281
+
282
+ @Cron('0 0 * * *') // Every day at midnight
283
+ handleDaily() {
284
+ console.log('[{{className}}Cron] Running daily task...');
285
+ // Add your daily task logic here
286
+ }
287
+
288
+ @Cron(CronExpression.EVERY_HOUR)
289
+ handleHourly() {
290
+ console.log('[{{className}}Cron] Running hourly cleanup...');
291
+ // Add your hourly task logic here
292
+ }
293
+ }
294
+ `;
295
+ exports.RAG_SERVICE_TEMPLATE = `import { Service } from '@hazeljs/core';
296
+ import { RAGPipeline, MemoryVectorStore } from '@hazeljs/rag';
297
+
298
+ @Service()
299
+ export class {{className}}RagService {
300
+ private pipeline: RAGPipeline;
301
+
302
+ constructor() {
303
+ // Initialize with a memory vector store (swap for Pinecone, Qdrant, etc. in production)
304
+ const vectorStore = new MemoryVectorStore();
305
+
306
+ this.pipeline = new RAGPipeline({
307
+ vectorStore,
308
+ topK: 5,
309
+ });
310
+ }
311
+
312
+ async addDocument(content: string, metadata?: Record<string, unknown>) {
313
+ // Add a document to the vector store for retrieval
314
+ await this.pipeline.addDocument({
315
+ content,
316
+ metadata: metadata || {},
317
+ });
318
+ }
319
+
320
+ async query(question: string) {
321
+ // Retrieve relevant documents and generate a response
322
+ const results = await this.pipeline.query(question);
323
+ return results;
324
+ }
325
+ }
326
+ `;
327
+ exports.DISCOVERY_TEMPLATE = `import { Service } from '@hazeljs/core';
328
+ import { ServiceRegistry, DiscoveryClient } from '@hazeljs/discovery';
329
+
330
+ @Service()
331
+ export class {{className}}DiscoveryService {
332
+ constructor(
333
+ private readonly registry: ServiceRegistry,
334
+ private readonly client: DiscoveryClient,
335
+ ) {}
336
+
337
+ async registerService() {
338
+ await this.registry.register({
339
+ name: '{{fileName}}-service',
340
+ host: 'localhost',
341
+ port: 3000,
342
+ metadata: {
343
+ version: '1.0.0',
344
+ },
345
+ });
346
+ }
347
+
348
+ async discoverService(serviceName: string) {
349
+ const instances = await this.client.getInstances(serviceName);
350
+ return instances;
351
+ }
352
+ }
353
+ `;
354
+ exports.CONFIG_TEMPLATE = `import { HazelModule } from '@hazeljs/core';
355
+ import { ConfigModule, ConfigService } from '@hazeljs/config';
356
+
357
+ // Import ConfigModule.forRoot() in your app module:
358
+ //
359
+ // @HazelModule({
360
+ // imports: [
361
+ // ConfigModule.forRoot({
362
+ // envFilePath: '.env',
363
+ // }),
364
+ // ],
365
+ // })
366
+ //
367
+ // Then inject ConfigService wherever you need it:
368
+ //
369
+ // constructor(private readonly config: ConfigService) {}
370
+ //
371
+ // Usage:
372
+ // this.config.get('DATABASE_URL');
373
+ // this.config.get('PORT', '3000'); // with default value
374
+
375
+ export { ConfigModule, ConfigService };
376
+ `;
377
+ // ── Serverless generators ────────────────────────────────────────────────────
378
+ exports.SERVERLESS_LAMBDA_TEMPLATE = `import { createLambdaHandler } from '@hazeljs/serverless';
379
+ import { AppModule } from './app.module';
380
+
381
+ export const handler = createLambdaHandler(AppModule);
382
+ `;
383
+ exports.SERVERLESS_CLOUD_FUNCTION_TEMPLATE = `import { createCloudFunctionHandler } from '@hazeljs/serverless';
384
+ import { AppModule } from './app.module';
385
+
386
+ export const handler = createCloudFunctionHandler(AppModule);
387
+ `;
package/dist/index.d.ts CHANGED
@@ -1,2 +1,42 @@
1
1
  #!/usr/bin/env node
2
+ /**
3
+ * HazelJS CLI — Entry point and command registration
4
+ *
5
+ * Architecture Overview:
6
+ * =====================
7
+ *
8
+ * index.ts — Entry point, registers all commands with Commander
9
+ * ├─ commands/
10
+ * │ ├─ generate-app.ts — `hazel new` (full scaffolding) and `hazel g app` (skeleton)
11
+ * │ ├─ add.ts — `hazel add [pkg]` with --setup flag (replaces generate-setup)
12
+ * │ ├─ info.ts — `hazel info` (project diagnostics)
13
+ * │ ├─ generate-simple.ts — Config-driven single-file generators (18 types)
14
+ * │ ├─ generate-module.ts — Multi-file module generator
15
+ * │ ├─ generate-dto.ts — DTO pair generator
16
+ * │ ├─ generate-crud.ts — Full CRUD resource generator
17
+ * │ ├─ generate-auth.ts — Auth module with JWT guard
18
+ * │ └─ templates.ts — Mustache templates for all simple generators
19
+ * └─ utils/
20
+ * ├─ generator.ts — Base Generator class, shared types, string utils
21
+ * ├─ generator-registry.ts — Unified registry + runGenerator dispatcher
22
+ * └─ packages-registry.ts — All HazelJS package metadata (single source of truth)
23
+ *
24
+ * Command Structure:
25
+ * =================
26
+ *
27
+ * hazel new <app> — Full interactive scaffolding (packages, git, install)
28
+ * hazel g app <name> — Minimal skeleton app (no install/git)
29
+ * hazel g <type> <name> — Unified generator for 23+ types (see --list)
30
+ * hazel add <pkg> [--setup] — Install HazelJS packages + optional setup file
31
+ * hazel info — Project diagnostics
32
+ *
33
+ * Design Principles:
34
+ * ===================
35
+ *
36
+ * 1. Config-driven generators: SIMPLE_GENERATORS array defines 18+ single-file generators
37
+ * 2. Centralized package registry: HAZEL_PACKAGES drives `hazel add` and `hazel new -i`
38
+ * 3. Machine-readable output: --json and --list --list-json for LLM tool-use
39
+ * 4. Consistent CLI options: --path, --dry-run, --json available everywhere
40
+ * 5. Separation of concerns: Templates live separately from logic; registry is data-driven
41
+ */
2
42
  export {};
package/dist/index.js CHANGED
@@ -1,51 +1,70 @@
1
1
  #!/usr/bin/env node
2
2
  "use strict";
3
+ /**
4
+ * HazelJS CLI — Entry point and command registration
5
+ *
6
+ * Architecture Overview:
7
+ * =====================
8
+ *
9
+ * index.ts — Entry point, registers all commands with Commander
10
+ * ├─ commands/
11
+ * │ ├─ generate-app.ts — `hazel new` (full scaffolding) and `hazel g app` (skeleton)
12
+ * │ ├─ add.ts — `hazel add [pkg]` with --setup flag (replaces generate-setup)
13
+ * │ ├─ info.ts — `hazel info` (project diagnostics)
14
+ * │ ├─ generate-simple.ts — Config-driven single-file generators (18 types)
15
+ * │ ├─ generate-module.ts — Multi-file module generator
16
+ * │ ├─ generate-dto.ts — DTO pair generator
17
+ * │ ├─ generate-crud.ts — Full CRUD resource generator
18
+ * │ ├─ generate-auth.ts — Auth module with JWT guard
19
+ * │ └─ templates.ts — Mustache templates for all simple generators
20
+ * └─ utils/
21
+ * ├─ generator.ts — Base Generator class, shared types, string utils
22
+ * ├─ generator-registry.ts — Unified registry + runGenerator dispatcher
23
+ * └─ packages-registry.ts — All HazelJS package metadata (single source of truth)
24
+ *
25
+ * Command Structure:
26
+ * =================
27
+ *
28
+ * hazel new <app> — Full interactive scaffolding (packages, git, install)
29
+ * hazel g app <name> — Minimal skeleton app (no install/git)
30
+ * hazel g <type> <name> — Unified generator for 23+ types (see --list)
31
+ * hazel add <pkg> [--setup] — Install HazelJS packages + optional setup file
32
+ * hazel info — Project diagnostics
33
+ *
34
+ * Design Principles:
35
+ * ===================
36
+ *
37
+ * 1. Config-driven generators: SIMPLE_GENERATORS array defines 18+ single-file generators
38
+ * 2. Centralized package registry: HAZEL_PACKAGES drives `hazel add` and `hazel new -i`
39
+ * 3. Machine-readable output: --json and --list --list-json for LLM tool-use
40
+ * 4. Consistent CLI options: --path, --dry-run, --json available everywhere
41
+ * 5. Separation of concerns: Templates live separately from logic; registry is data-driven
42
+ */
3
43
  Object.defineProperty(exports, "__esModule", { value: true });
4
44
  const commander_1 = require("commander");
5
- const generate_module_1 = require("./commands/generate-module");
45
+ const fs_1 = require("fs");
46
+ const path_1 = require("path");
6
47
  const generate_app_1 = require("./commands/generate-app");
7
- const generate_controller_1 = require("./commands/generate-controller");
8
- const generate_service_1 = require("./commands/generate-service");
48
+ const generate_module_1 = require("./commands/generate-module");
9
49
  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
50
  const generate_crud_1 = require("./commands/generate-crud");
20
- const generate_middleware_1 = require("./commands/generate-middleware");
21
51
  const generate_auth_1 = require("./commands/generate-auth");
22
- const generate_config_1 = require("./commands/generate-config");
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");
52
+ const generate_simple_1 = require("./commands/generate-simple");
28
53
  const generator_registry_1 = require("./utils/generator-registry");
29
54
  const info_1 = require("./commands/info");
30
55
  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");
56
+ // Read version from package.json to ensure consistency
57
+ const packageJson = JSON.parse((0, fs_1.readFileSync)((0, path_1.join)(__dirname, '../package.json'), 'utf8'));
35
58
  const program = new commander_1.Command();
36
59
  program
37
60
  .name('hazel')
38
61
  .description('CLI for generating HazelJS components and applications')
39
- .version('0.2.0');
62
+ .version(packageJson.version);
40
63
  // New app command
41
64
  (0, generate_app_1.generateApp)(program);
42
65
  // Utility commands
43
66
  (0, info_1.infoCommand)(program);
44
67
  (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
68
  // Generate command group (unified: hazel g <type> <name> [--path] [--dry-run] [--json], or hazel g --list)
50
69
  const generateCommand = program
51
70
  .command('generate')
@@ -77,28 +96,11 @@ const generateCommand = program
77
96
  });
78
97
  // Skeleton app
79
98
  (0, generate_app_1.registerGenerateApp)(generateCommand);
80
- // Core components
81
- (0, generate_controller_1.generateController)(generateCommand);
82
- (0, generate_service_1.generateService)(generateCommand);
99
+ // Complex generators (multi-file output)
83
100
  (0, generate_module_1.generateModule)(generateCommand);
84
101
  (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
102
  (0, generate_crud_1.generateCrud)(generateCommand);
90
103
  (0, generate_auth_1.generateAuth)(generateCommand);
91
- (0, generate_websocket_gateway_1.generateWebSocketGateway)(generateCommand);
92
- (0, generate_exception_filter_1.generateExceptionFilter)(generateCommand);
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);
104
+ // Simple generators (config-driven single-file output)
105
+ (0, generate_simple_1.registerSimpleGenerators)(generateCommand);
104
106
  program.parse(process.argv);
@@ -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-websocket-gateway', () => ({ generateWebSocketGateway: jest.fn() }));
17
- jest.mock('./commands/generate-exception-filter', () => ({ generateExceptionFilter: jest.fn() }));
18
- jest.mock('./commands/generate-pipe', () => ({ generatePipe: jest.fn() }));
19
- jest.mock('./commands/generate-repository', () => ({ generateRepository: jest.fn() }));
20
- jest.mock('./commands/generate-ai-service', () => ({ generateAIService: jest.fn() }));
21
- jest.mock('./commands/generate-agent', () => ({ generateAgent: jest.fn() }));
22
- jest.mock('./commands/generate-serverless-handler', () => ({ generateServerlessHandler: jest.fn() }));
23
- jest.mock('./commands/generate-config', () => ({ generateConfig: jest.fn() }));
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(() => {