@hazeljs/cli 0.2.0-alpha.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (121) hide show
  1. package/@template/.eslintrc.js +36 -0
  2. package/@template/.lintstagedrc +6 -0
  3. package/@template/README.md +61 -0
  4. package/@template/jest.config.js +28 -0
  5. package/@template/jest.setup.js +81 -0
  6. package/@template/package.json +34 -0
  7. package/@template/src/app.module.ts +7 -0
  8. package/@template/src/hello.controller.ts +9 -0
  9. package/@template/src/index.ts +18 -0
  10. package/@template/tsconfig.json +25 -0
  11. package/LICENSE +192 -0
  12. package/README.md +683 -0
  13. package/dist/commands/add.d.ts +2 -0
  14. package/dist/commands/add.js +176 -0
  15. package/dist/commands/add.test.d.ts +1 -0
  16. package/dist/commands/add.test.js +51 -0
  17. package/dist/commands/build.d.ts +2 -0
  18. package/dist/commands/build.js +52 -0
  19. package/dist/commands/generate-agent.d.ts +2 -0
  20. package/dist/commands/generate-agent.js +58 -0
  21. package/dist/commands/generate-agent.test.d.ts +1 -0
  22. package/dist/commands/generate-agent.test.js +36 -0
  23. package/dist/commands/generate-ai-service.d.ts +2 -0
  24. package/dist/commands/generate-ai-service.js +48 -0
  25. package/dist/commands/generate-ai-service.test.d.ts +1 -0
  26. package/dist/commands/generate-ai-service.test.js +41 -0
  27. package/dist/commands/generate-app.d.ts +2 -0
  28. package/dist/commands/generate-app.js +448 -0
  29. package/dist/commands/generate-auth.d.ts +2 -0
  30. package/dist/commands/generate-auth.js +194 -0
  31. package/dist/commands/generate-auth.test.d.ts +1 -0
  32. package/dist/commands/generate-auth.test.js +48 -0
  33. package/dist/commands/generate-cache.d.ts +2 -0
  34. package/dist/commands/generate-cache.js +64 -0
  35. package/dist/commands/generate-cache.test.d.ts +1 -0
  36. package/dist/commands/generate-cache.test.js +36 -0
  37. package/dist/commands/generate-config.d.ts +2 -0
  38. package/dist/commands/generate-config.js +57 -0
  39. package/dist/commands/generate-config.test.d.ts +1 -0
  40. package/dist/commands/generate-config.test.js +35 -0
  41. package/dist/commands/generate-controller.d.ts +2 -0
  42. package/dist/commands/generate-controller.js +60 -0
  43. package/dist/commands/generate-controller.test.d.ts +1 -0
  44. package/dist/commands/generate-controller.test.js +48 -0
  45. package/dist/commands/generate-cron.d.ts +2 -0
  46. package/dist/commands/generate-cron.js +59 -0
  47. package/dist/commands/generate-cron.test.d.ts +1 -0
  48. package/dist/commands/generate-cron.test.js +42 -0
  49. package/dist/commands/generate-crud.d.ts +2 -0
  50. package/dist/commands/generate-crud.js +177 -0
  51. package/dist/commands/generate-crud.test.d.ts +1 -0
  52. package/dist/commands/generate-crud.test.js +52 -0
  53. package/dist/commands/generate-discovery.d.ts +2 -0
  54. package/dist/commands/generate-discovery.js +61 -0
  55. package/dist/commands/generate-discovery.test.d.ts +1 -0
  56. package/dist/commands/generate-discovery.test.js +36 -0
  57. package/dist/commands/generate-dto.d.ts +2 -0
  58. package/dist/commands/generate-dto.js +69 -0
  59. package/dist/commands/generate-dto.test.d.ts +1 -0
  60. package/dist/commands/generate-dto.test.js +44 -0
  61. package/dist/commands/generate-exception-filter.d.ts +2 -0
  62. package/dist/commands/generate-exception-filter.js +48 -0
  63. package/dist/commands/generate-exception-filter.test.d.ts +1 -0
  64. package/dist/commands/generate-exception-filter.test.js +43 -0
  65. package/dist/commands/generate-guard.d.ts +2 -0
  66. package/dist/commands/generate-guard.js +36 -0
  67. package/dist/commands/generate-guard.test.d.ts +1 -0
  68. package/dist/commands/generate-guard.test.js +41 -0
  69. package/dist/commands/generate-interceptor.d.ts +2 -0
  70. package/dist/commands/generate-interceptor.js +37 -0
  71. package/dist/commands/generate-interceptor.test.d.ts +1 -0
  72. package/dist/commands/generate-interceptor.test.js +41 -0
  73. package/dist/commands/generate-middleware.d.ts +2 -0
  74. package/dist/commands/generate-middleware.js +46 -0
  75. package/dist/commands/generate-middleware.test.d.ts +1 -0
  76. package/dist/commands/generate-middleware.test.js +41 -0
  77. package/dist/commands/generate-module.d.ts +2 -0
  78. package/dist/commands/generate-module.js +106 -0
  79. package/dist/commands/generate-module.test.d.ts +1 -0
  80. package/dist/commands/generate-module.test.js +54 -0
  81. package/dist/commands/generate-pipe.d.ts +2 -0
  82. package/dist/commands/generate-pipe.js +33 -0
  83. package/dist/commands/generate-pipe.test.d.ts +1 -0
  84. package/dist/commands/generate-pipe.test.js +35 -0
  85. package/dist/commands/generate-rag.d.ts +2 -0
  86. package/dist/commands/generate-rag.js +66 -0
  87. package/dist/commands/generate-rag.test.d.ts +1 -0
  88. package/dist/commands/generate-rag.test.js +35 -0
  89. package/dist/commands/generate-repository.d.ts +2 -0
  90. package/dist/commands/generate-repository.js +40 -0
  91. package/dist/commands/generate-repository.test.d.ts +1 -0
  92. package/dist/commands/generate-repository.test.js +41 -0
  93. package/dist/commands/generate-serverless-handler.d.ts +2 -0
  94. package/dist/commands/generate-serverless-handler.js +46 -0
  95. package/dist/commands/generate-serverless-handler.test.d.ts +1 -0
  96. package/dist/commands/generate-serverless-handler.test.js +42 -0
  97. package/dist/commands/generate-service.d.ts +2 -0
  98. package/dist/commands/generate-service.js +52 -0
  99. package/dist/commands/generate-service.test.d.ts +1 -0
  100. package/dist/commands/generate-service.test.js +41 -0
  101. package/dist/commands/generate-websocket-gateway.d.ts +2 -0
  102. package/dist/commands/generate-websocket-gateway.js +47 -0
  103. package/dist/commands/generate-websocket-gateway.test.d.ts +1 -0
  104. package/dist/commands/generate-websocket-gateway.test.js +41 -0
  105. package/dist/commands/info.d.ts +2 -0
  106. package/dist/commands/info.js +91 -0
  107. package/dist/commands/pdf-to-audio.d.ts +2 -0
  108. package/dist/commands/pdf-to-audio.js +170 -0
  109. package/dist/commands/start.d.ts +2 -0
  110. package/dist/commands/start.js +61 -0
  111. package/dist/commands/test.d.ts +2 -0
  112. package/dist/commands/test.js +63 -0
  113. package/dist/index.d.ts +2 -0
  114. package/dist/index.js +75 -0
  115. package/dist/index.test.d.ts +1 -0
  116. package/dist/index.test.js +93 -0
  117. package/dist/utils/generator.d.ts +25 -0
  118. package/dist/utils/generator.js +107 -0
  119. package/dist/utils/generator.test.d.ts +1 -0
  120. package/dist/utils/generator.test.js +137 -0
  121. package/package.json +73 -0
@@ -0,0 +1,48 @@
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_auth_1 = require("./generate-auth");
9
+ jest.mock('fs');
10
+ describe('generateAuth', () => {
11
+ const mockFs = fs_1.default;
12
+ let program;
13
+ beforeEach(() => {
14
+ jest.clearAllMocks();
15
+ mockFs.existsSync.mockReturnValue(false);
16
+ mockFs.mkdirSync.mockImplementation(() => undefined);
17
+ mockFs.writeFileSync.mockImplementation(() => { });
18
+ jest.spyOn(console, 'log').mockImplementation();
19
+ program = new commander_1.Command();
20
+ });
21
+ afterEach(() => {
22
+ jest.restoreAllMocks();
23
+ });
24
+ it('should generate all auth files', async () => {
25
+ (0, generate_auth_1.generateAuth)(program);
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);
34
+ });
35
+ it('should use @hazeljs/auth imports in guard', async () => {
36
+ (0, generate_auth_1.generateAuth)(program);
37
+ await program.parseAsync(['node', 'test', 'auth']);
38
+ const guardContent = mockFs.writeFileSync.mock.calls
39
+ .find(call => call[0].includes('jwt-auth.guard'))?.[1];
40
+ expect(guardContent).toContain("from '@hazeljs/auth'");
41
+ expect(guardContent).toContain('JwtService');
42
+ });
43
+ it('should support --dry-run flag', async () => {
44
+ (0, generate_auth_1.generateAuth)(program);
45
+ await program.parseAsync(['node', 'test', 'auth', '--dry-run']);
46
+ expect(mockFs.writeFileSync).not.toHaveBeenCalled();
47
+ });
48
+ });
@@ -0,0 +1,2 @@
1
+ import { Command } from 'commander';
2
+ export declare function generateCache(command: Command): void;
@@ -0,0 +1,64 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.generateCache = generateCache;
7
+ const generator_1 = require("../utils/generator");
8
+ const chalk_1 = __importDefault(require("chalk"));
9
+ const CACHE_SERVICE_TEMPLATE = `import { Service } from '@hazeljs/core';
10
+ import { CacheService, Cacheable, CacheEvict } from '@hazeljs/cache';
11
+
12
+ @Service()
13
+ export class {{className}}CacheService {
14
+ constructor(private readonly cacheService: CacheService) {}
15
+
16
+ @Cacheable({ key: '{{fileName}}:all', ttl: 60 })
17
+ async findAll() {
18
+ // This result will be cached for 60 seconds
19
+ return [];
20
+ }
21
+
22
+ @Cacheable({ key: '{{fileName}}:{{=<% %>=}}#{id}<%={{ }}=%>', ttl: 300 })
23
+ async findOne(id: string) {
24
+ // This result will be cached for 5 minutes
25
+ return { id };
26
+ }
27
+
28
+ @CacheEvict({ key: '{{fileName}}:all' })
29
+ async create(data: any) {
30
+ // Creating a new item evicts the list cache
31
+ return data;
32
+ }
33
+
34
+ async clearAll() {
35
+ await this.cacheService.clear();
36
+ }
37
+ }
38
+ `;
39
+ class CacheServiceGenerator extends generator_1.Generator {
40
+ constructor() {
41
+ super(...arguments);
42
+ this.suffix = 'cache';
43
+ }
44
+ getDefaultTemplate() {
45
+ return CACHE_SERVICE_TEMPLATE;
46
+ }
47
+ }
48
+ function generateCache(command) {
49
+ command
50
+ .command('cache <name>')
51
+ .description('Generate a cache service with decorators')
52
+ .option('-p, --path <path>', 'Specify the path')
53
+ .option('--dry-run', 'Preview files without writing them')
54
+ .action(async (name, options) => {
55
+ const generator = new CacheServiceGenerator();
56
+ await generator.generate({ name, path: options.path, dryRun: options.dryRun });
57
+ if (!options.dryRun) {
58
+ console.log(chalk_1.default.gray('\nNext steps:'));
59
+ console.log(chalk_1.default.gray(' 1. npm install @hazeljs/cache'));
60
+ console.log(chalk_1.default.gray(' 2. Add CacheModule to your module imports'));
61
+ console.log(chalk_1.default.gray(' 3. Configure the cache strategy (memory, redis, or multi-tier)'));
62
+ }
63
+ });
64
+ }
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,36 @@
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_cache_1 = require("./generate-cache");
9
+ jest.mock('fs');
10
+ describe('generateCache', () => {
11
+ const mockFs = fs_1.default;
12
+ let program;
13
+ beforeEach(() => {
14
+ jest.clearAllMocks();
15
+ mockFs.existsSync.mockReturnValue(true);
16
+ mockFs.writeFileSync.mockImplementation(() => { });
17
+ jest.spyOn(console, 'log').mockImplementation();
18
+ program = new commander_1.Command();
19
+ });
20
+ afterEach(() => {
21
+ jest.restoreAllMocks();
22
+ });
23
+ it('should generate a cache service file', async () => {
24
+ (0, generate_cache_1.generateCache)(program);
25
+ await program.parseAsync(['node', 'test', 'cache', 'product']);
26
+ expect(mockFs.writeFileSync).toHaveBeenCalledWith(expect.stringContaining('product.cache.ts'), expect.stringContaining('ProductCacheService'));
27
+ });
28
+ it('should import from @hazeljs/cache', async () => {
29
+ (0, generate_cache_1.generateCache)(program);
30
+ await program.parseAsync(['node', 'test', 'cache', 'product']);
31
+ const writtenContent = mockFs.writeFileSync.mock.calls[0][1];
32
+ expect(writtenContent).toContain("from '@hazeljs/cache'");
33
+ expect(writtenContent).toContain('@Cacheable');
34
+ expect(writtenContent).toContain('@CacheEvict');
35
+ });
36
+ });
@@ -0,0 +1,2 @@
1
+ import { Command } from 'commander';
2
+ export declare function generateConfig(command: Command): void;
@@ -0,0 +1,57 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.generateConfig = generateConfig;
7
+ const generator_1 = require("../utils/generator");
8
+ const chalk_1 = __importDefault(require("chalk"));
9
+ const CONFIG_TEMPLATE = `import { HazelModule } from '@hazeljs/core';
10
+ import { ConfigModule, ConfigService } from '@hazeljs/config';
11
+
12
+ // Import ConfigModule.forRoot() in your app module:
13
+ //
14
+ // @HazelModule({
15
+ // imports: [
16
+ // ConfigModule.forRoot({
17
+ // envFilePath: '.env',
18
+ // }),
19
+ // ],
20
+ // })
21
+ //
22
+ // Then inject ConfigService wherever you need it:
23
+ //
24
+ // constructor(private readonly config: ConfigService) {}
25
+ //
26
+ // Usage:
27
+ // this.config.get('DATABASE_URL');
28
+ // this.config.get('PORT', '3000'); // with default value
29
+
30
+ export { ConfigModule, ConfigService };
31
+ `;
32
+ class ConfigGenerator extends generator_1.Generator {
33
+ constructor() {
34
+ super(...arguments);
35
+ this.suffix = 'config';
36
+ }
37
+ getDefaultTemplate() {
38
+ return CONFIG_TEMPLATE;
39
+ }
40
+ }
41
+ function generateConfig(command) {
42
+ command
43
+ .command('config')
44
+ .description('Generate a config module setup')
45
+ .option('-p, --path <path>', 'Specify the path', 'src')
46
+ .option('--dry-run', 'Preview files without writing them')
47
+ .action(async (options) => {
48
+ const generator = new ConfigGenerator();
49
+ await generator.generate({ name: 'app', path: options.path, dryRun: options.dryRun });
50
+ if (!options.dryRun) {
51
+ console.log(chalk_1.default.gray('\nNext steps:'));
52
+ console.log(chalk_1.default.gray(' 1. npm install @hazeljs/config'));
53
+ console.log(chalk_1.default.gray(' 2. Add ConfigModule.forRoot({ envFilePath: ".env" }) to your app module imports'));
54
+ console.log(chalk_1.default.gray(' 3. Create a .env file in your project root'));
55
+ }
56
+ });
57
+ }
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,35 @@
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_config_1 = require("./generate-config");
9
+ jest.mock('fs');
10
+ describe('generateConfig', () => {
11
+ const mockFs = fs_1.default;
12
+ let program;
13
+ beforeEach(() => {
14
+ jest.clearAllMocks();
15
+ mockFs.existsSync.mockReturnValue(true);
16
+ mockFs.writeFileSync.mockImplementation(() => { });
17
+ jest.spyOn(console, 'log').mockImplementation();
18
+ program = new commander_1.Command();
19
+ });
20
+ afterEach(() => {
21
+ jest.restoreAllMocks();
22
+ });
23
+ it('should generate a config module file', async () => {
24
+ (0, generate_config_1.generateConfig)(program);
25
+ await program.parseAsync(['node', 'test', 'config']);
26
+ expect(mockFs.writeFileSync).toHaveBeenCalledWith(expect.stringContaining('app.config.ts'), expect.stringContaining('ConfigModule'));
27
+ });
28
+ it('should import from @hazeljs/config', async () => {
29
+ (0, generate_config_1.generateConfig)(program);
30
+ await program.parseAsync(['node', 'test', 'config']);
31
+ const writtenContent = mockFs.writeFileSync.mock.calls[0][1];
32
+ expect(writtenContent).toContain("from '@hazeljs/config'");
33
+ expect(writtenContent).toContain('ConfigService');
34
+ });
35
+ });
@@ -0,0 +1,2 @@
1
+ import { Command } from 'commander';
2
+ export declare function generateController(program: Command): void;
@@ -0,0 +1,60 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.generateController = generateController;
4
+ const generator_1 = require("../utils/generator");
5
+ const CONTROLLER_TEMPLATE = `import { Controller, Get, Post, Body, Param, Delete, Put } from '@hazeljs/core';
6
+ import { {{className}}Service } from './{{fileName}}.service';
7
+ import { Create{{className}}Dto } from './dto/create-{{fileName}}.dto';
8
+ import { Update{{className}}Dto } from './dto/update-{{fileName}}.dto';
9
+
10
+ @Controller('{{fileName}}')
11
+ export class {{className}}Controller {
12
+ constructor(private readonly {{camelName}}Service: {{className}}Service) {}
13
+
14
+ @Get()
15
+ findAll() {
16
+ return this.{{camelName}}Service.findAll();
17
+ }
18
+
19
+ @Get(':id')
20
+ findOne(@Param('id') id: string) {
21
+ return this.{{camelName}}Service.findOne(id);
22
+ }
23
+
24
+ @Post()
25
+ create(@Body(Create{{className}}Dto) createDto: Create{{className}}Dto) {
26
+ return this.{{camelName}}Service.create(createDto);
27
+ }
28
+
29
+ @Put(':id')
30
+ update(@Param('id') id: string, @Body(Update{{className}}Dto) updateDto: Update{{className}}Dto) {
31
+ return this.{{camelName}}Service.update(id, updateDto);
32
+ }
33
+
34
+ @Delete(':id')
35
+ remove(@Param('id') id: string) {
36
+ return this.{{camelName}}Service.remove(id);
37
+ }
38
+ }
39
+ `;
40
+ class ControllerGenerator extends generator_1.Generator {
41
+ constructor() {
42
+ super(...arguments);
43
+ this.suffix = 'controller';
44
+ }
45
+ getDefaultTemplate() {
46
+ return CONTROLLER_TEMPLATE;
47
+ }
48
+ }
49
+ function generateController(program) {
50
+ program
51
+ .command('controller <name>')
52
+ .description('Generate a new controller')
53
+ .alias('c')
54
+ .option('-p, --path <path>', 'Path where the controller should be generated')
55
+ .option('--dry-run', 'Preview files without writing them')
56
+ .action(async (name, options) => {
57
+ const generator = new ControllerGenerator();
58
+ await generator.generate({ name, path: options.path, dryRun: options.dryRun });
59
+ });
60
+ }
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,48 @@
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_controller_1 = require("./generate-controller");
9
+ jest.mock('fs');
10
+ describe('generateController', () => {
11
+ const mockFs = fs_1.default;
12
+ let program;
13
+ beforeEach(() => {
14
+ jest.clearAllMocks();
15
+ mockFs.existsSync.mockReturnValue(true);
16
+ mockFs.writeFileSync.mockImplementation(() => { });
17
+ jest.spyOn(console, 'log').mockImplementation();
18
+ program = new commander_1.Command();
19
+ });
20
+ afterEach(() => {
21
+ jest.restoreAllMocks();
22
+ });
23
+ it('should register the controller command with alias', () => {
24
+ (0, generate_controller_1.generateController)(program);
25
+ const cmd = program.commands.find(c => c.name() === 'controller');
26
+ expect(cmd).toBeDefined();
27
+ expect(cmd?.alias()).toBe('c');
28
+ });
29
+ it('should generate a controller file with correct suffix', async () => {
30
+ (0, generate_controller_1.generateController)(program);
31
+ await program.parseAsync(['node', 'test', 'controller', 'user']);
32
+ expect(mockFs.writeFileSync).toHaveBeenCalledWith(expect.stringContaining('user.controller.ts'), expect.stringContaining('UserController'));
33
+ });
34
+ it('should include proper imports from @hazeljs/core', async () => {
35
+ (0, generate_controller_1.generateController)(program);
36
+ await program.parseAsync(['node', 'test', 'controller', 'user']);
37
+ const writtenContent = mockFs.writeFileSync.mock.calls[0][1];
38
+ expect(writtenContent).toContain("from '@hazeljs/core'");
39
+ expect(writtenContent).toContain('Controller');
40
+ expect(writtenContent).toContain('Get');
41
+ expect(writtenContent).toContain('Post');
42
+ });
43
+ it('should support --dry-run flag', async () => {
44
+ (0, generate_controller_1.generateController)(program);
45
+ await program.parseAsync(['node', 'test', 'controller', 'user', '--dry-run']);
46
+ expect(mockFs.writeFileSync).not.toHaveBeenCalled();
47
+ });
48
+ });
@@ -0,0 +1,2 @@
1
+ import { Command } from 'commander';
2
+ export declare function generateCron(command: Command): void;
@@ -0,0 +1,59 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.generateCron = generateCron;
7
+ const generator_1 = require("../utils/generator");
8
+ const chalk_1 = __importDefault(require("chalk"));
9
+ const CRON_SERVICE_TEMPLATE = `import { Service } from '@hazeljs/core';
10
+ import { Cron, CronExpression } from '@hazeljs/cron';
11
+
12
+ @Service()
13
+ export class {{className}}CronService {
14
+ @Cron(CronExpression.EVERY_MINUTE)
15
+ handleEveryMinute() {
16
+ console.log('[{{className}}Cron] Running every minute...');
17
+ // Add your cron job logic here
18
+ }
19
+
20
+ @Cron('0 0 * * *') // Every day at midnight
21
+ handleDaily() {
22
+ console.log('[{{className}}Cron] Running daily task...');
23
+ // Add your daily task logic here
24
+ }
25
+
26
+ @Cron(CronExpression.EVERY_HOUR)
27
+ handleHourly() {
28
+ console.log('[{{className}}Cron] Running hourly cleanup...');
29
+ // Add your hourly task logic here
30
+ }
31
+ }
32
+ `;
33
+ class CronServiceGenerator extends generator_1.Generator {
34
+ constructor() {
35
+ super(...arguments);
36
+ this.suffix = 'cron';
37
+ }
38
+ getDefaultTemplate() {
39
+ return CRON_SERVICE_TEMPLATE;
40
+ }
41
+ }
42
+ function generateCron(command) {
43
+ command
44
+ .command('cron <name>')
45
+ .description('Generate a cron/scheduled job service')
46
+ .alias('job')
47
+ .option('-p, --path <path>', 'Specify the path')
48
+ .option('--dry-run', 'Preview files without writing them')
49
+ .action(async (name, options) => {
50
+ const generator = new CronServiceGenerator();
51
+ await generator.generate({ name, path: options.path, dryRun: options.dryRun });
52
+ if (!options.dryRun) {
53
+ console.log(chalk_1.default.gray('\nNext steps:'));
54
+ console.log(chalk_1.default.gray(' 1. npm install @hazeljs/cron'));
55
+ console.log(chalk_1.default.gray(' 2. Add CronModule to your module imports'));
56
+ console.log(chalk_1.default.gray(' 3. Register this service as a provider'));
57
+ }
58
+ });
59
+ }
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,42 @@
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_cron_1 = require("./generate-cron");
9
+ jest.mock('fs');
10
+ describe('generateCron', () => {
11
+ const mockFs = fs_1.default;
12
+ let program;
13
+ beforeEach(() => {
14
+ jest.clearAllMocks();
15
+ mockFs.existsSync.mockReturnValue(true);
16
+ mockFs.writeFileSync.mockImplementation(() => { });
17
+ jest.spyOn(console, 'log').mockImplementation();
18
+ program = new commander_1.Command();
19
+ });
20
+ afterEach(() => {
21
+ jest.restoreAllMocks();
22
+ });
23
+ it('should register the cron command with alias', () => {
24
+ (0, generate_cron_1.generateCron)(program);
25
+ const cmd = program.commands.find(c => c.name() === 'cron');
26
+ expect(cmd).toBeDefined();
27
+ expect(cmd?.alias()).toBe('job');
28
+ });
29
+ it('should generate a cron service file', async () => {
30
+ (0, generate_cron_1.generateCron)(program);
31
+ await program.parseAsync(['node', 'test', 'cron', 'cleanup']);
32
+ expect(mockFs.writeFileSync).toHaveBeenCalledWith(expect.stringContaining('cleanup.cron.ts'), expect.stringContaining('CleanupCronService'));
33
+ });
34
+ it('should import from @hazeljs/cron', async () => {
35
+ (0, generate_cron_1.generateCron)(program);
36
+ await program.parseAsync(['node', 'test', 'cron', 'cleanup']);
37
+ const writtenContent = mockFs.writeFileSync.mock.calls[0][1];
38
+ expect(writtenContent).toContain("from '@hazeljs/cron'");
39
+ expect(writtenContent).toContain('@Cron');
40
+ expect(writtenContent).toContain('CronExpression');
41
+ });
42
+ });
@@ -0,0 +1,2 @@
1
+ import { Command } from 'commander';
2
+ export declare function generateCrud(command: Command): void;
@@ -0,0 +1,177 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.generateCrud = generateCrud;
7
+ const fs_1 = __importDefault(require("fs"));
8
+ const path_1 = __importDefault(require("path"));
9
+ const chalk_1 = __importDefault(require("chalk"));
10
+ const generator_1 = require("../utils/generator");
11
+ const controllerTemplate = `import { Controller, Get, Post, Put, Delete, Body, Param } from '@hazeljs/core';
12
+ import { {{className}}Service } from './{{fileName}}.service';
13
+ import { Create{{className}}Dto, Update{{className}}Dto } from './dto/{{fileName}}.dto';
14
+
15
+ @Controller('/{{{routePath}}}')
16
+ export class {{className}}Controller {
17
+ constructor(private {{camelName}}Service: {{className}}Service) {}
18
+
19
+ @Get()
20
+ findAll() {
21
+ return this.{{camelName}}Service.findAll();
22
+ }
23
+
24
+ @Get('/:id')
25
+ findOne(@Param('id') id: string) {
26
+ return this.{{camelName}}Service.findOne(id);
27
+ }
28
+
29
+ @Post()
30
+ create(@Body() createDto: Create{{className}}Dto) {
31
+ return this.{{camelName}}Service.create(createDto);
32
+ }
33
+
34
+ @Put('/:id')
35
+ update(@Param('id') id: string, @Body() updateDto: Update{{className}}Dto) {
36
+ return this.{{camelName}}Service.update(id, updateDto);
37
+ }
38
+
39
+ @Delete('/:id')
40
+ delete(@Param('id') id: string) {
41
+ return this.{{camelName}}Service.delete(id);
42
+ }
43
+ }
44
+ `;
45
+ const serviceTemplate = `import { Service } from '@hazeljs/core';
46
+ import { Create{{className}}Dto, Update{{className}}Dto } from './dto/{{fileName}}.dto';
47
+
48
+ @Service()
49
+ export class {{className}}Service {
50
+ private {{camelName}}s: any[] = [];
51
+
52
+ findAll() {
53
+ return this.{{camelName}}s;
54
+ }
55
+
56
+ findOne(id: string) {
57
+ const {{camelName}} = this.{{camelName}}s.find(item => item.id === id);
58
+ if (!{{camelName}}) {
59
+ throw new Error('{{className}} not found');
60
+ }
61
+ return {{camelName}};
62
+ }
63
+
64
+ create(createDto: Create{{className}}Dto) {
65
+ const {{camelName}} = {
66
+ id: Date.now().toString(),
67
+ ...createDto,
68
+ createdAt: new Date(),
69
+ updatedAt: new Date(),
70
+ };
71
+ this.{{camelName}}s.push({{camelName}});
72
+ return {{camelName}};
73
+ }
74
+
75
+ update(id: string, updateDto: Update{{className}}Dto) {
76
+ const index = this.{{camelName}}s.findIndex(item => item.id === id);
77
+ if (index === -1) {
78
+ throw new Error('{{className}} not found');
79
+ }
80
+ this.{{camelName}}s[index] = {
81
+ ...this.{{camelName}}s[index],
82
+ ...updateDto,
83
+ updatedAt: new Date(),
84
+ };
85
+ return this.{{camelName}}s[index];
86
+ }
87
+
88
+ delete(id: string) {
89
+ const index = this.{{camelName}}s.findIndex(item => item.id === id);
90
+ if (index === -1) {
91
+ throw new Error('{{className}} not found');
92
+ }
93
+ const deleted = this.{{camelName}}s.splice(index, 1);
94
+ return deleted[0];
95
+ }
96
+ }
97
+ `;
98
+ const dtoTemplate = `import { IsString, IsOptional, IsNotEmpty } from 'class-validator';
99
+
100
+ export class Create{{className}}Dto {
101
+ @IsString()
102
+ @IsNotEmpty()
103
+ name: string;
104
+
105
+ @IsString()
106
+ @IsOptional()
107
+ description?: string;
108
+ }
109
+
110
+ export class Update{{className}}Dto {
111
+ @IsString()
112
+ @IsOptional()
113
+ name?: string;
114
+
115
+ @IsString()
116
+ @IsOptional()
117
+ description?: string;
118
+ }
119
+ `;
120
+ const moduleTemplate = `import { HazelModule } from '@hazeljs/core';
121
+ import { {{className}}Controller } from './{{fileName}}.controller';
122
+ import { {{className}}Service } from './{{fileName}}.service';
123
+
124
+ @HazelModule({
125
+ controllers: [{{className}}Controller],
126
+ providers: [{{className}}Service],
127
+ })
128
+ export class {{className}}Module {}
129
+ `;
130
+ function generateCrud(command) {
131
+ command
132
+ .command('crud <name>')
133
+ .description('Generate a complete CRUD resource (controller, service, module, DTOs)')
134
+ .option('-p, --path <path>', 'Specify the path', 'src')
135
+ .option('-r, --route <route>', 'Specify the route path')
136
+ .option('--dry-run', 'Preview files without writing them')
137
+ .action((name, options) => {
138
+ const className = (0, generator_1.toPascalCase)(name);
139
+ const fileName = (0, generator_1.toKebabCase)(name);
140
+ const camelName = (0, generator_1.toCamelCase)(name);
141
+ const routePath = options.route || fileName;
142
+ const basePath = path_1.default.join(process.cwd(), options.path || 'src', fileName);
143
+ const data = { className, fileName, camelName, routePath };
144
+ const files = [
145
+ { file: `${fileName}.controller.ts`, template: controllerTemplate },
146
+ { file: `${fileName}.service.ts`, template: serviceTemplate },
147
+ { file: `dto/${fileName}.dto.ts`, template: dtoTemplate },
148
+ { file: `${fileName}.module.ts`, template: moduleTemplate },
149
+ ];
150
+ try {
151
+ for (const { file, template } of files) {
152
+ const filePath = path_1.default.join(basePath, file);
153
+ if (options.dryRun) {
154
+ console.log(chalk_1.default.blue(`[dry-run] Would create ${filePath}`));
155
+ continue;
156
+ }
157
+ const dir = path_1.default.dirname(filePath);
158
+ if (!fs_1.default.existsSync(dir)) {
159
+ fs_1.default.mkdirSync(dir, { recursive: true });
160
+ }
161
+ fs_1.default.writeFileSync(filePath, (0, generator_1.renderTemplate)(template, data));
162
+ console.log(chalk_1.default.green(`\u2713 Generated ${filePath}`));
163
+ }
164
+ if (!options.dryRun) {
165
+ console.log(chalk_1.default.blue('\n\uD83D\uDCE6 CRUD resource generated successfully!'));
166
+ console.log(chalk_1.default.gray(`\nNext steps:`));
167
+ console.log(chalk_1.default.gray(`1. Import ${className}Module in your app module`));
168
+ console.log(chalk_1.default.gray(`2. Customize the DTOs`));
169
+ console.log(chalk_1.default.gray(`3. Implement your business logic in the service`));
170
+ }
171
+ }
172
+ catch (error) {
173
+ console.error(chalk_1.default.red('Error generating CRUD resource:'), error);
174
+ process.exit(1);
175
+ }
176
+ });
177
+ }
@@ -0,0 +1 @@
1
+ export {};