@hazeljs/cli 0.7.8 → 0.8.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.
@@ -19,7 +19,7 @@ describe('addCommand', () => {
19
19
  });
20
20
  it('should register the add command', () => {
21
21
  (0, add_1.addCommand)(program);
22
- const cmd = program.commands.find(c => c.name() === 'add');
22
+ const cmd = program.commands.find((c) => c.name() === 'add');
23
23
  expect(cmd).toBeDefined();
24
24
  });
25
25
  it('should install a known package', async () => {
@@ -39,8 +39,21 @@ describe('addCommand', () => {
39
39
  (0, add_1.addCommand)(program);
40
40
  // Test that all documented packages are available
41
41
  const expectedPackages = [
42
- 'ai', 'agent', 'auth', 'cache', 'config', 'cron',
43
- 'discovery', 'mcp', 'prompts', 'prisma', 'typeorm', 'rag', 'serverless', 'swagger', 'websocket'
42
+ 'ai',
43
+ 'agent',
44
+ 'auth',
45
+ 'cache',
46
+ 'config',
47
+ 'cron',
48
+ 'discovery',
49
+ 'mcp',
50
+ 'prompts',
51
+ 'prisma',
52
+ 'typeorm',
53
+ 'rag',
54
+ 'serverless',
55
+ 'swagger',
56
+ 'websocket',
44
57
  ];
45
58
  for (const pkg of expectedPackages) {
46
59
  mockExecSync.mockClear();
@@ -68,7 +68,8 @@ describe('generateApp interactive package wiring', () => {
68
68
  const s = String(p);
69
69
  if (s.includes(path_1.default.join('@template')))
70
70
  return true; // template exists
71
- if (s.endsWith(path_1.default.join('.', 'my-app')) || s.endsWith(path_1.default.join(process.cwd(), '.', 'my-app')))
71
+ if (s.endsWith(path_1.default.join('.', 'my-app')) ||
72
+ s.endsWith(path_1.default.join(process.cwd(), '.', 'my-app')))
72
73
  return false; // dest doesn't exist
73
74
  if (s.endsWith(path_1.default.join('my-app', 'package.json')))
74
75
  return true; // updatePackageJson path
@@ -151,9 +151,7 @@ function scaffoldPackageBoilerplate(destPath, packages) {
151
151
  moduleImports.push(meta.moduleExpression);
152
152
  }
153
153
  // Generate the enhanced app.module.ts
154
- const importsSection = moduleImports.length > 0
155
- ? `\n imports: [\n ${moduleImports.join(',\n ')},\n ],`
156
- : '';
154
+ const importsSection = moduleImports.length > 0 ? `\n imports: [\n ${moduleImports.join(',\n ')},\n ],` : '';
157
155
  const appModule = `${imports.join('\n')}
158
156
 
159
157
  @HazelModule({${importsSection}
@@ -235,7 +233,10 @@ function generateApp(program) {
235
233
  type: 'checkbox',
236
234
  name: 'packages',
237
235
  message: 'Select additional HazelJS packages to install:',
238
- choices: packages_registry_1.HAZEL_PACKAGES.map((p) => ({ name: p.label, value: p.npm })),
236
+ choices: packages_registry_1.HAZEL_PACKAGES.map((p) => ({
237
+ name: p.label,
238
+ value: p.npm,
239
+ })),
239
240
  },
240
241
  ]);
241
242
  projectConfig = { ...projectConfig, ...answers };
@@ -318,7 +319,7 @@ coverage/
318
319
  }
319
320
  console.log(chalk_1.default.gray(' npm run dev'));
320
321
  console.log(chalk_1.default.gray('\nDocumentation: https://hazeljs.ai/docs'));
321
- console.log(chalk_1.default.gray('Discord: https://discord.com/channels/1448263814238965833/1448263814859456575\n'));
322
+ console.log(chalk_1.default.gray('Discord: https://discord.gg/PxNBPzvQk7\n'));
322
323
  }
323
324
  catch (error) {
324
325
  console.error(chalk_1.default.red('\n✗ Failed to create project:'), error);
@@ -57,7 +57,9 @@ describe('generateApp (hazel new)', () => {
57
57
  });
58
58
  const program = new commander_1.Command();
59
59
  (0, generate_app_1.generateApp)(program);
60
- await program.parseAsync(['new', 'my-app', '--dest', '.', '--skip-install', '--skip-git'], { from: 'user' });
60
+ await program.parseAsync(['new', 'my-app', '--dest', '.', '--skip-install', '--skip-git'], {
61
+ from: 'user',
62
+ });
61
63
  expect(mockFs.mkdirSync).toHaveBeenCalled();
62
64
  expect(mockFs.writeFileSync).toHaveBeenCalled();
63
65
  expect(mockExec).not.toHaveBeenCalled(); // skipped install + git
@@ -35,7 +35,8 @@ describe('runApp (skeleton app)', () => {
35
35
  // destPath doesn't exist; templatePath also doesn't exist -> fallback basic structure
36
36
  mockFs.existsSync.mockImplementation((p) => {
37
37
  const s = String(p);
38
- if (s.endsWith(path_1.default.join('.', 'my-app')) || s.endsWith(path_1.default.join(process.cwd(), '.', 'my-app')))
38
+ if (s.endsWith(path_1.default.join('.', 'my-app')) ||
39
+ s.endsWith(path_1.default.join(process.cwd(), '.', 'my-app')))
39
40
  return false;
40
41
  if (s.includes('@template'))
41
42
  return false;
@@ -24,19 +24,18 @@ describe('generateAuth', () => {
24
24
  it('should generate all auth files', async () => {
25
25
  (0, generate_auth_1.generateAuth)(program);
26
26
  await program.parseAsync(['node', 'test', 'auth']);
27
- const writtenFiles = mockFs.writeFileSync.mock.calls.map(call => call[0]);
28
- expect(writtenFiles.some(f => f.includes('auth.module.ts'))).toBe(true);
29
- expect(writtenFiles.some(f => f.includes('auth.service.ts'))).toBe(true);
30
- expect(writtenFiles.some(f => f.includes('auth.controller.ts'))).toBe(true);
31
- expect(writtenFiles.some(f => f.includes('jwt-auth.guard.ts'))).toBe(true);
32
- expect(writtenFiles.some(f => f.includes('register.dto.ts'))).toBe(true);
33
- expect(writtenFiles.some(f => f.includes('login.dto.ts'))).toBe(true);
27
+ const writtenFiles = mockFs.writeFileSync.mock.calls.map((call) => call[0]);
28
+ expect(writtenFiles.some((f) => f.includes('auth.module.ts'))).toBe(true);
29
+ expect(writtenFiles.some((f) => f.includes('auth.service.ts'))).toBe(true);
30
+ expect(writtenFiles.some((f) => f.includes('auth.controller.ts'))).toBe(true);
31
+ expect(writtenFiles.some((f) => f.includes('jwt-auth.guard.ts'))).toBe(true);
32
+ expect(writtenFiles.some((f) => f.includes('register.dto.ts'))).toBe(true);
33
+ expect(writtenFiles.some((f) => f.includes('login.dto.ts'))).toBe(true);
34
34
  });
35
35
  it('should use @hazeljs/auth imports in guard', async () => {
36
36
  (0, generate_auth_1.generateAuth)(program);
37
37
  await program.parseAsync(['node', 'test', 'auth']);
38
- const guardContent = mockFs.writeFileSync.mock.calls
39
- .find(call => call[0].includes('jwt-auth.guard'))?.[1];
38
+ const guardContent = mockFs.writeFileSync.mock.calls.find((call) => call[0].includes('jwt-auth.guard'))?.[1];
40
39
  expect(guardContent).toContain("from '@hazeljs/auth'");
41
40
  expect(guardContent).toContain('JwtService');
42
41
  });
@@ -24,17 +24,16 @@ describe('generateCrud', () => {
24
24
  it('should generate all CRUD files', async () => {
25
25
  (0, generate_crud_1.generateCrud)(program);
26
26
  await program.parseAsync(['node', 'test', 'crud', 'product']);
27
- const writtenFiles = mockFs.writeFileSync.mock.calls.map(call => call[0]);
28
- expect(writtenFiles.some(f => f.includes('product.controller.ts'))).toBe(true);
29
- expect(writtenFiles.some(f => f.includes('product.service.ts'))).toBe(true);
30
- expect(writtenFiles.some(f => f.includes('product.dto.ts'))).toBe(true);
31
- expect(writtenFiles.some(f => f.includes('product.module.ts'))).toBe(true);
27
+ const writtenFiles = mockFs.writeFileSync.mock.calls.map((call) => call[0]);
28
+ expect(writtenFiles.some((f) => f.includes('product.controller.ts'))).toBe(true);
29
+ expect(writtenFiles.some((f) => f.includes('product.service.ts'))).toBe(true);
30
+ expect(writtenFiles.some((f) => f.includes('product.dto.ts'))).toBe(true);
31
+ expect(writtenFiles.some((f) => f.includes('product.module.ts'))).toBe(true);
32
32
  });
33
33
  it('should use @hazeljs/core imports', async () => {
34
34
  (0, generate_crud_1.generateCrud)(program);
35
35
  await program.parseAsync(['node', 'test', 'crud', 'product']);
36
- const controllerContent = mockFs.writeFileSync.mock.calls
37
- .find(call => call[0].includes('controller'))?.[1];
36
+ const controllerContent = mockFs.writeFileSync.mock.calls.find((call) => call[0].includes('controller'))?.[1];
38
37
  expect(controllerContent).toContain("from '@hazeljs/core'");
39
38
  });
40
39
  it('should support --dry-run flag', async () => {
@@ -45,8 +44,7 @@ describe('generateCrud', () => {
45
44
  it('should support custom route path', async () => {
46
45
  (0, generate_crud_1.generateCrud)(program);
47
46
  await program.parseAsync(['node', 'test', 'crud', 'product', '-r', 'api/products']);
48
- const controllerContent = mockFs.writeFileSync.mock.calls
49
- .find(call => call[0].includes('controller'))?.[1];
47
+ const controllerContent = mockFs.writeFileSync.mock.calls.find((call) => call[0].includes('controller'))?.[1];
50
48
  expect(controllerContent).toContain('api/products');
51
49
  });
52
50
  });
@@ -22,7 +22,7 @@ describe('generateDto', () => {
22
22
  });
23
23
  it('should register the dto command with alias', () => {
24
24
  (0, generate_dto_1.generateDto)(program);
25
- const cmd = program.commands.find(c => c.name() === 'dto');
25
+ const cmd = program.commands.find((c) => c.name() === 'dto');
26
26
  expect(cmd).toBeDefined();
27
27
  expect(cmd?.alias()).toBe('d');
28
28
  });
@@ -30,9 +30,9 @@ describe('generateDto', () => {
30
30
  (0, generate_dto_1.generateDto)(program);
31
31
  await program.parseAsync(['node', 'test', 'dto', 'user']);
32
32
  expect(mockFs.writeFileSync).toHaveBeenCalledTimes(2);
33
- const writtenFiles = mockFs.writeFileSync.mock.calls.map(call => call[0]);
34
- expect(writtenFiles.some(f => f.includes('user.dto.ts'))).toBe(true);
35
- expect(writtenFiles.some(f => f.includes('update-user.dto.ts'))).toBe(true);
33
+ const writtenFiles = mockFs.writeFileSync.mock.calls.map((call) => call[0]);
34
+ expect(writtenFiles.some((f) => f.includes('user.dto.ts'))).toBe(true);
35
+ expect(writtenFiles.some((f) => f.includes('update-user.dto.ts'))).toBe(true);
36
36
  });
37
37
  it('should include class-validator decorators', async () => {
38
38
  (0, generate_dto_1.generateDto)(program);
@@ -23,27 +23,27 @@ describe('generateModule', () => {
23
23
  });
24
24
  it('should register the module command with alias', () => {
25
25
  (0, generate_module_1.generateModule)(program);
26
- const cmd = program.commands.find(c => c.name() === 'module');
26
+ const cmd = program.commands.find((c) => c.name() === 'module');
27
27
  expect(cmd).toBeDefined();
28
28
  expect(cmd?.alias()).toBe('m');
29
29
  });
30
30
  it('should generate all module files', async () => {
31
31
  (0, generate_module_1.generateModule)(program);
32
32
  await program.parseAsync(['node', 'test', 'module', 'user']);
33
- const writtenFiles = mockFs.writeFileSync.mock.calls.map(call => call[0]);
34
- expect(writtenFiles.some(f => f.includes('user.module.ts'))).toBe(true);
35
- expect(writtenFiles.some(f => f.includes('user.controller.ts'))).toBe(true);
36
- expect(writtenFiles.some(f => f.includes('user.service.ts'))).toBe(true);
37
- expect(writtenFiles.some(f => f.includes('create-user.dto.ts'))).toBe(true);
38
- expect(writtenFiles.some(f => f.includes('update-user.dto.ts'))).toBe(true);
33
+ const writtenFiles = mockFs.writeFileSync.mock.calls.map((call) => call[0]);
34
+ expect(writtenFiles.some((f) => f.includes('user.module.ts'))).toBe(true);
35
+ expect(writtenFiles.some((f) => f.includes('user.controller.ts'))).toBe(true);
36
+ expect(writtenFiles.some((f) => f.includes('user.service.ts'))).toBe(true);
37
+ expect(writtenFiles.some((f) => f.includes('create-user.dto.ts'))).toBe(true);
38
+ expect(writtenFiles.some((f) => f.includes('update-user.dto.ts'))).toBe(true);
39
39
  });
40
40
  it('should use @hazeljs/core imports in all generated files', async () => {
41
41
  (0, generate_module_1.generateModule)(program);
42
42
  await program.parseAsync(['node', 'test', 'module', 'user']);
43
- const writtenContents = mockFs.writeFileSync.mock.calls.map(call => call[1]);
44
- const moduleContent = writtenContents.find(c => c.includes('HazelModule'));
43
+ const writtenContents = mockFs.writeFileSync.mock.calls.map((call) => call[1]);
44
+ const moduleContent = writtenContents.find((c) => c.includes('HazelModule'));
45
45
  expect(moduleContent).toContain("from '@hazeljs/core'");
46
- const controllerContent = writtenContents.find(c => c.includes('Controller'));
46
+ const controllerContent = writtenContents.find((c) => c.includes('Controller'));
47
47
  expect(controllerContent).toContain("from '@hazeljs/core'");
48
48
  });
49
49
  it('should support --dry-run flag', async () => {
@@ -7,23 +7,165 @@ exports.findSimpleGenerator = findSimpleGenerator;
7
7
  const generator_1 = require("../utils/generator");
8
8
  const templates_1 = require("./templates");
9
9
  exports.SIMPLE_GENERATORS = [
10
- { type: 'controller', description: 'REST controller', suffix: 'controller', template: templates_1.CONTROLLER_TEMPLATE, alias: 'c', nameRequired: true },
11
- { type: 'service', description: 'Service class', suffix: 'service', template: templates_1.SERVICE_TEMPLATE, alias: 's', nameRequired: true },
12
- { type: 'guard', description: 'Guard (e.g. auth)', suffix: 'guard', template: templates_1.GUARD_TEMPLATE, alias: 'gu', nameRequired: true },
13
- { type: 'interceptor', description: 'Interceptor', suffix: 'interceptor', template: templates_1.INTERCEPTOR_TEMPLATE, alias: 'i', nameRequired: true },
14
- { type: 'middleware', description: 'Middleware', suffix: 'middleware', template: templates_1.MIDDLEWARE_TEMPLATE, alias: 'mw', defaultPath: 'src/middleware', nameRequired: true, nextSteps: ['Import the middleware in your module or apply it globally.'] },
15
- { type: 'pipe', description: 'Validation/transform pipe', suffix: 'pipe', template: templates_1.PIPE_TEMPLATE, nameRequired: true },
16
- { type: 'filter', description: 'Exception filter', suffix: 'filter', template: templates_1.EXCEPTION_FILTER_TEMPLATE, alias: 'f', nameRequired: true },
17
- { type: 'repository', description: 'Prisma repository', suffix: 'repository', template: templates_1.REPOSITORY_TEMPLATE, alias: 'repo', nameRequired: true },
18
- { type: 'gateway', description: 'WebSocket gateway', suffix: 'gateway', template: templates_1.WEBSOCKET_GATEWAY_TEMPLATE, alias: 'ws', nameRequired: true },
19
- { type: 'ai-service', description: 'AI service with decorators', suffix: 'ai-service', template: templates_1.AI_SERVICE_TEMPLATE, alias: 'ai', nameRequired: true },
20
- { type: 'agent', description: 'AI agent with @Agent and @Tool', suffix: 'agent', template: templates_1.AGENT_TEMPLATE, nameRequired: true, extraData: (name) => ({ description: `A ${name} agent` }) },
21
- { type: 'cache', description: 'Cache service with decorators', suffix: 'cache', template: templates_1.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)'] },
22
- { type: 'cron', description: 'Cron/scheduled job service', suffix: 'cron', template: templates_1.CRON_SERVICE_TEMPLATE, alias: 'job', nameRequired: true, nextSteps: ['npm install @hazeljs/cron', 'Add CronModule to your module imports', 'Register this service as a provider'] },
23
- { type: 'rag', description: 'RAG (Retrieval-Augmented Generation) service', suffix: 'rag', template: templates_1.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'] },
24
- { type: 'discovery', description: 'Service discovery setup', suffix: 'discovery', template: templates_1.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)'] },
25
- { type: 'config', description: 'Config module setup', suffix: 'config', template: templates_1.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'] },
26
- { type: 'serverless', description: 'Serverless handler (Lambda or Cloud Function)', suffix: 'handler', template: templates_1.SERVERLESS_LAMBDA_TEMPLATE, alias: 'sls', nameRequired: true, extraOptions: ['platform'] },
10
+ {
11
+ type: 'controller',
12
+ description: 'REST controller',
13
+ suffix: 'controller',
14
+ template: templates_1.CONTROLLER_TEMPLATE,
15
+ alias: 'c',
16
+ nameRequired: true,
17
+ },
18
+ {
19
+ type: 'service',
20
+ description: 'Service class',
21
+ suffix: 'service',
22
+ template: templates_1.SERVICE_TEMPLATE,
23
+ alias: 's',
24
+ nameRequired: true,
25
+ },
26
+ {
27
+ type: 'guard',
28
+ description: 'Guard (e.g. auth)',
29
+ suffix: 'guard',
30
+ template: templates_1.GUARD_TEMPLATE,
31
+ alias: 'gu',
32
+ nameRequired: true,
33
+ },
34
+ {
35
+ type: 'interceptor',
36
+ description: 'Interceptor',
37
+ suffix: 'interceptor',
38
+ template: templates_1.INTERCEPTOR_TEMPLATE,
39
+ alias: 'i',
40
+ nameRequired: true,
41
+ },
42
+ {
43
+ type: 'middleware',
44
+ description: 'Middleware',
45
+ suffix: 'middleware',
46
+ template: templates_1.MIDDLEWARE_TEMPLATE,
47
+ alias: 'mw',
48
+ defaultPath: 'src/middleware',
49
+ nameRequired: true,
50
+ nextSteps: ['Import the middleware in your module or apply it globally.'],
51
+ },
52
+ {
53
+ type: 'pipe',
54
+ description: 'Validation/transform pipe',
55
+ suffix: 'pipe',
56
+ template: templates_1.PIPE_TEMPLATE,
57
+ nameRequired: true,
58
+ },
59
+ {
60
+ type: 'filter',
61
+ description: 'Exception filter',
62
+ suffix: 'filter',
63
+ template: templates_1.EXCEPTION_FILTER_TEMPLATE,
64
+ alias: 'f',
65
+ nameRequired: true,
66
+ },
67
+ {
68
+ type: 'repository',
69
+ description: 'Prisma repository',
70
+ suffix: 'repository',
71
+ template: templates_1.REPOSITORY_TEMPLATE,
72
+ alias: 'repo',
73
+ nameRequired: true,
74
+ },
75
+ {
76
+ type: 'gateway',
77
+ description: 'WebSocket gateway',
78
+ suffix: 'gateway',
79
+ template: templates_1.WEBSOCKET_GATEWAY_TEMPLATE,
80
+ alias: 'ws',
81
+ nameRequired: true,
82
+ },
83
+ {
84
+ type: 'ai-service',
85
+ description: 'AI service with decorators',
86
+ suffix: 'ai-service',
87
+ template: templates_1.AI_SERVICE_TEMPLATE,
88
+ alias: 'ai',
89
+ nameRequired: true,
90
+ },
91
+ {
92
+ type: 'agent',
93
+ description: 'AI agent with @Agent and @Tool',
94
+ suffix: 'agent',
95
+ template: templates_1.AGENT_TEMPLATE,
96
+ nameRequired: true,
97
+ extraData: (name) => ({ description: `A ${name} agent` }),
98
+ },
99
+ {
100
+ type: 'cache',
101
+ description: 'Cache service with decorators',
102
+ suffix: 'cache',
103
+ template: templates_1.CACHE_SERVICE_TEMPLATE,
104
+ nameRequired: true,
105
+ nextSteps: [
106
+ 'npm install @hazeljs/cache',
107
+ 'Add CacheModule to your module imports',
108
+ 'Configure the cache strategy (memory, redis, or multi-tier)',
109
+ ],
110
+ },
111
+ {
112
+ type: 'cron',
113
+ description: 'Cron/scheduled job service',
114
+ suffix: 'cron',
115
+ template: templates_1.CRON_SERVICE_TEMPLATE,
116
+ alias: 'job',
117
+ nameRequired: true,
118
+ nextSteps: [
119
+ 'npm install @hazeljs/cron',
120
+ 'Add CronModule to your module imports',
121
+ 'Register this service as a provider',
122
+ ],
123
+ },
124
+ {
125
+ type: 'rag',
126
+ description: 'RAG (Retrieval-Augmented Generation) service',
127
+ suffix: 'rag',
128
+ template: templates_1.RAG_SERVICE_TEMPLATE,
129
+ nameRequired: true,
130
+ nextSteps: [
131
+ 'npm install @hazeljs/rag',
132
+ 'Register this service as a provider in your module',
133
+ 'Configure your embedding provider and vector store',
134
+ ],
135
+ },
136
+ {
137
+ type: 'discovery',
138
+ description: 'Service discovery setup',
139
+ suffix: 'discovery',
140
+ template: templates_1.DISCOVERY_TEMPLATE,
141
+ nameRequired: true,
142
+ nextSteps: [
143
+ 'npm install @hazeljs/discovery',
144
+ 'Register this service as a provider in your module',
145
+ 'Configure your discovery backend (memory, redis, consul, or kubernetes)',
146
+ ],
147
+ },
148
+ {
149
+ type: 'config',
150
+ description: 'Config module setup',
151
+ suffix: 'config',
152
+ template: templates_1.CONFIG_TEMPLATE,
153
+ nameRequired: false,
154
+ nextSteps: [
155
+ 'npm install @hazeljs/config',
156
+ 'Add ConfigModule.forRoot({ envFilePath: ".env" }) to your app module imports',
157
+ 'Create a .env file in your project root',
158
+ ],
159
+ },
160
+ {
161
+ type: 'serverless',
162
+ description: 'Serverless handler (Lambda or Cloud Function)',
163
+ suffix: 'handler',
164
+ template: templates_1.SERVERLESS_LAMBDA_TEMPLATE,
165
+ alias: 'sls',
166
+ nameRequired: true,
167
+ extraOptions: ['platform'],
168
+ },
27
169
  ];
28
170
  // ── Runner factory ───────────────────────────────────────────────────────────
29
171
  class SimpleGenerator extends generator_1.Generator {
@@ -52,7 +194,7 @@ async function runSimpleGenerator(config, name, options) {
52
194
  template = templates_1.SERVERLESS_CLOUD_FUNCTION_TEMPLATE;
53
195
  }
54
196
  const generator = new SimpleGenerator(config.suffix, template);
55
- const effectiveName = config.nameRequired ? name : (name || 'app');
197
+ const effectiveName = config.nameRequired ? name : name || 'app';
56
198
  const result = await generator.generate({
57
199
  name: effectiveName,
58
200
  path: options.path || config.defaultPath,
@@ -87,7 +229,7 @@ function registerSimpleGenerators(generateCommand) {
87
229
  }
88
230
  cmd.action(async (nameOrOptions, maybeOptions) => {
89
231
  const name = typeof nameOrOptions === 'string' ? nameOrOptions : '';
90
- const opts = typeof nameOrOptions === 'string' ? (maybeOptions || {}) : nameOrOptions;
232
+ const opts = typeof nameOrOptions === 'string' ? maybeOptions || {} : nameOrOptions;
91
233
  const result = await runSimpleGenerator(config, name, opts);
92
234
  (0, generator_1.printGenerateResult)(result, { json: opts.json });
93
235
  });
@@ -73,13 +73,19 @@ describe('generate-simple', () => {
73
73
  });
74
74
  it('handles serverless with cloud-function platform', async () => {
75
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' });
76
+ const result = await (0, generate_simple_1.runSimpleGenerator)(config, 'api', {
77
+ dryRun: true,
78
+ platform: 'cloud-function',
79
+ });
77
80
  expect(result.ok).toBe(true);
78
81
  expect(result.created[0]).toContain('api.handler.ts');
79
82
  });
80
83
  it('generates with custom path', async () => {
81
84
  const config = (0, generate_simple_1.findSimpleGenerator)('service');
82
- const result = await (0, generate_simple_1.runSimpleGenerator)(config, 'order', { path: 'src/orders', dryRun: true });
85
+ const result = await (0, generate_simple_1.runSimpleGenerator)(config, 'order', {
86
+ path: 'src/orders',
87
+ dryRun: true,
88
+ });
83
89
  expect(result.ok).toBe(true);
84
90
  expect(result.created[0]).toContain('src/orders');
85
91
  });
@@ -47,9 +47,7 @@ describe('infoCommand', () => {
47
47
  const program = new commander_1.Command();
48
48
  (0, info_1.infoCommand)(program);
49
49
  await program.parseAsync(['info'], { from: 'user' });
50
- const out = logSpy.mock.calls
51
- .map((c) => c.map((x) => String(x)).join(' '))
52
- .join('\n');
50
+ const out = logSpy.mock.calls.map((c) => c.map((x) => String(x)).join(' ')).join('\n');
53
51
  expect(out).toContain('Project Information');
54
52
  expect(out).toContain('@hazeljs/core');
55
53
  expect(out).toContain('@hazeljs/swagger');
@@ -11,7 +11,13 @@ jest.mock('./commands/generate-auth', () => ({ generateAuth: jest.fn() }));
11
11
  jest.mock('./commands/generate-simple', () => ({
12
12
  registerSimpleGenerators: jest.fn(),
13
13
  SIMPLE_GENERATORS: [
14
- { type: 'controller', description: 'REST controller', suffix: 'controller', template: '', nameRequired: true },
14
+ {
15
+ type: 'controller',
16
+ description: 'REST controller',
17
+ suffix: 'controller',
18
+ template: '',
19
+ nameRequired: true,
20
+ },
15
21
  ],
16
22
  findSimpleGenerator: jest.fn(),
17
23
  runSimpleGenerator: jest.fn(),
@@ -17,7 +17,13 @@ jest.mock('./commands/generate-auth');
17
17
  jest.mock('./commands/generate-simple', () => ({
18
18
  registerSimpleGenerators: jest.fn(),
19
19
  SIMPLE_GENERATORS: [
20
- { type: 'controller', description: 'REST controller', suffix: 'controller', template: '', nameRequired: true },
20
+ {
21
+ type: 'controller',
22
+ description: 'REST controller',
23
+ suffix: 'controller',
24
+ template: '',
25
+ nameRequired: true,
26
+ },
21
27
  ],
22
28
  findSimpleGenerator: jest.fn(),
23
29
  runSimpleGenerator: jest.fn(),
@@ -11,11 +11,25 @@ const generate_app_1 = require("../commands/generate-app");
11
11
  const generate_simple_1 = require("../commands/generate-simple");
12
12
  /** Complex generators that need their own files (multi-file output or custom logic) */
13
13
  const COMPLEX_GENERATORS = [
14
- { type: 'app', description: 'Skeleton HazelJS application (minimal template)', nameRequired: true, options: ['path'] },
14
+ {
15
+ type: 'app',
16
+ description: 'Skeleton HazelJS application (minimal template)',
17
+ nameRequired: true,
18
+ options: ['path'],
19
+ },
15
20
  { type: 'module', description: 'Module with controller, service, DTOs', nameRequired: true },
16
21
  { type: 'dto', description: 'Create and update DTOs', nameRequired: true },
17
- { type: 'crud', description: 'Full CRUD resource (controller, service, module, DTOs)', nameRequired: true, options: ['route'] },
18
- { type: 'auth', description: 'Auth module (JWT guard, service, controller, DTOs)', nameRequired: false },
22
+ {
23
+ type: 'crud',
24
+ description: 'Full CRUD resource (controller, service, module, DTOs)',
25
+ nameRequired: true,
26
+ options: ['route'],
27
+ },
28
+ {
29
+ type: 'auth',
30
+ description: 'Auth module (JWT guard, service, controller, DTOs)',
31
+ nameRequired: false,
32
+ },
19
33
  ];
20
34
  /** All available generator types and their metadata (for --list). */
21
35
  exports.GENERATOR_LIST = [
@@ -93,7 +93,9 @@ function printGenerateResult(result, options) {
93
93
  console.error(chalk_1.default.red(result.error ?? 'Generation failed'));
94
94
  return;
95
95
  }
96
- const prefix = result.dryRun ? chalk_1.default.blue('[dry-run] Would create ') : chalk_1.default.green('✓ Generated ');
96
+ const prefix = result.dryRun
97
+ ? chalk_1.default.blue('[dry-run] Would create ')
98
+ : chalk_1.default.green('✓ Generated ');
97
99
  for (const file of result.created) {
98
100
  console.log(prefix + file);
99
101
  }
@@ -75,7 +75,9 @@ describe('Generator class', () => {
75
75
  path: 'src/test',
76
76
  template: 'test template',
77
77
  });
78
- expect(mockFs.mkdirSync).toHaveBeenCalledWith(path_1.default.join(process.cwd(), 'src/test'), { recursive: true });
78
+ expect(mockFs.mkdirSync).toHaveBeenCalledWith(path_1.default.join(process.cwd(), 'src/test'), {
79
+ recursive: true,
80
+ });
79
81
  });
80
82
  it('should write file with rendered template', async () => {
81
83
  await generator.generate({
@@ -31,7 +31,7 @@ exports.HAZEL_PACKAGES = [
31
31
  label: 'Audit Logging (@hazeljs/audit)',
32
32
  hint: 'import { AuditModule, ConsoleAuditTransport } from "@hazeljs/audit";\n // AuditModule.forRoot({ transports: [new ConsoleAuditTransport()] })',
33
33
  moduleImport: "import { AuditModule, ConsoleAuditTransport } from '@hazeljs/audit';",
34
- moduleExpression: "AuditModule.forRoot({ transports: [new ConsoleAuditTransport()] })",
34
+ moduleExpression: 'AuditModule.forRoot({ transports: [new ConsoleAuditTransport()] })',
35
35
  setupTemplate: `import { AuditModule, ConsoleAuditTransport } from '@hazeljs/audit';
36
36
 
37
37
  // Add AuditModule.forRoot(...) to your HazelModule imports.
@@ -53,7 +53,7 @@ export const auditImports = [AuditModule.forRoot({ transports: [new ConsoleAudit
53
53
  label: 'OAuth - Google/Microsoft/GitHub (@hazeljs/oauth)',
54
54
  hint: 'import { OAuthModule } from "@hazeljs/oauth";\n // OAuthModule.forRoot({ providers: { google: {...}, microsoft: {...}, github: {...} } })',
55
55
  moduleImport: "import { OAuthModule } from '@hazeljs/oauth';",
56
- moduleExpression: "OAuthModule.forRoot({ providers: { google: { clientId: process.env.GOOGLE_CLIENT_ID!, clientSecret: process.env.GOOGLE_CLIENT_SECRET!, redirectUri: process.env.OAUTH_REDIRECT_URI! } } })",
56
+ moduleExpression: 'OAuthModule.forRoot({ providers: { google: { clientId: process.env.GOOGLE_CLIENT_ID!, clientSecret: process.env.GOOGLE_CLIENT_SECRET!, redirectUri: process.env.OAUTH_REDIRECT_URI! } } })',
57
57
  setupTemplate: `import { OAuthModule } from '@hazeljs/oauth';
58
58
 
59
59
  // Example (Google). Put secrets in env vars:
@@ -154,7 +154,7 @@ export const gatewayImports = [GatewayModule];
154
154
  label: 'Guardrails (@hazeljs/guardrails)',
155
155
  hint: 'import { GuardrailsModule } from "@hazeljs/guardrails";\n // GuardrailsModule.forRoot({ redactPIIByDefault: true })',
156
156
  moduleImport: "import { GuardrailsModule } from '@hazeljs/guardrails';",
157
- moduleExpression: "GuardrailsModule.forRoot({ redactPIIByDefault: true })",
157
+ moduleExpression: 'GuardrailsModule.forRoot({ redactPIIByDefault: true })',
158
158
  setupTemplate: null,
159
159
  },
160
160
  {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hazeljs/cli",
3
- "version": "0.7.8",
3
+ "version": "0.8.0",
4
4
  "description": "Command-line interface for scaffolding and generating HazelJS applications and components",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -70,5 +70,5 @@
70
70
  "type": "opencollective",
71
71
  "url": "https://opencollective.com/hazeljs"
72
72
  },
73
- "gitHead": "906cacdc08d52c4616831b888748f1d1887edb80"
73
+ "gitHead": "e0ed98ca074dd4f7472816d3c32ef576900dcca6"
74
74
  }