@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.
- package/@template/.eslintrc.js +36 -0
- package/@template/.lintstagedrc +6 -0
- package/@template/README.md +61 -0
- package/@template/jest.config.js +28 -0
- package/@template/jest.setup.js +81 -0
- package/@template/package.json +34 -0
- package/@template/src/app.module.ts +7 -0
- package/@template/src/hello.controller.ts +9 -0
- package/@template/src/index.ts +18 -0
- package/@template/tsconfig.json +25 -0
- package/LICENSE +192 -0
- package/README.md +683 -0
- package/dist/commands/add.d.ts +2 -0
- package/dist/commands/add.js +176 -0
- package/dist/commands/add.test.d.ts +1 -0
- package/dist/commands/add.test.js +51 -0
- package/dist/commands/build.d.ts +2 -0
- package/dist/commands/build.js +52 -0
- package/dist/commands/generate-agent.d.ts +2 -0
- package/dist/commands/generate-agent.js +58 -0
- package/dist/commands/generate-agent.test.d.ts +1 -0
- package/dist/commands/generate-agent.test.js +36 -0
- package/dist/commands/generate-ai-service.d.ts +2 -0
- package/dist/commands/generate-ai-service.js +48 -0
- package/dist/commands/generate-ai-service.test.d.ts +1 -0
- package/dist/commands/generate-ai-service.test.js +41 -0
- package/dist/commands/generate-app.d.ts +2 -0
- package/dist/commands/generate-app.js +448 -0
- package/dist/commands/generate-auth.d.ts +2 -0
- package/dist/commands/generate-auth.js +194 -0
- package/dist/commands/generate-auth.test.d.ts +1 -0
- package/dist/commands/generate-auth.test.js +48 -0
- package/dist/commands/generate-cache.d.ts +2 -0
- package/dist/commands/generate-cache.js +64 -0
- package/dist/commands/generate-cache.test.d.ts +1 -0
- package/dist/commands/generate-cache.test.js +36 -0
- package/dist/commands/generate-config.d.ts +2 -0
- package/dist/commands/generate-config.js +57 -0
- package/dist/commands/generate-config.test.d.ts +1 -0
- package/dist/commands/generate-config.test.js +35 -0
- package/dist/commands/generate-controller.d.ts +2 -0
- package/dist/commands/generate-controller.js +60 -0
- package/dist/commands/generate-controller.test.d.ts +1 -0
- package/dist/commands/generate-controller.test.js +48 -0
- package/dist/commands/generate-cron.d.ts +2 -0
- package/dist/commands/generate-cron.js +59 -0
- package/dist/commands/generate-cron.test.d.ts +1 -0
- package/dist/commands/generate-cron.test.js +42 -0
- package/dist/commands/generate-crud.d.ts +2 -0
- package/dist/commands/generate-crud.js +177 -0
- package/dist/commands/generate-crud.test.d.ts +1 -0
- package/dist/commands/generate-crud.test.js +52 -0
- package/dist/commands/generate-discovery.d.ts +2 -0
- package/dist/commands/generate-discovery.js +61 -0
- package/dist/commands/generate-discovery.test.d.ts +1 -0
- package/dist/commands/generate-discovery.test.js +36 -0
- package/dist/commands/generate-dto.d.ts +2 -0
- package/dist/commands/generate-dto.js +69 -0
- package/dist/commands/generate-dto.test.d.ts +1 -0
- package/dist/commands/generate-dto.test.js +44 -0
- package/dist/commands/generate-exception-filter.d.ts +2 -0
- package/dist/commands/generate-exception-filter.js +48 -0
- package/dist/commands/generate-exception-filter.test.d.ts +1 -0
- package/dist/commands/generate-exception-filter.test.js +43 -0
- package/dist/commands/generate-guard.d.ts +2 -0
- package/dist/commands/generate-guard.js +36 -0
- package/dist/commands/generate-guard.test.d.ts +1 -0
- package/dist/commands/generate-guard.test.js +41 -0
- package/dist/commands/generate-interceptor.d.ts +2 -0
- package/dist/commands/generate-interceptor.js +37 -0
- package/dist/commands/generate-interceptor.test.d.ts +1 -0
- package/dist/commands/generate-interceptor.test.js +41 -0
- package/dist/commands/generate-middleware.d.ts +2 -0
- package/dist/commands/generate-middleware.js +46 -0
- package/dist/commands/generate-middleware.test.d.ts +1 -0
- package/dist/commands/generate-middleware.test.js +41 -0
- package/dist/commands/generate-module.d.ts +2 -0
- package/dist/commands/generate-module.js +106 -0
- package/dist/commands/generate-module.test.d.ts +1 -0
- package/dist/commands/generate-module.test.js +54 -0
- package/dist/commands/generate-pipe.d.ts +2 -0
- package/dist/commands/generate-pipe.js +33 -0
- package/dist/commands/generate-pipe.test.d.ts +1 -0
- package/dist/commands/generate-pipe.test.js +35 -0
- package/dist/commands/generate-rag.d.ts +2 -0
- package/dist/commands/generate-rag.js +66 -0
- package/dist/commands/generate-rag.test.d.ts +1 -0
- package/dist/commands/generate-rag.test.js +35 -0
- package/dist/commands/generate-repository.d.ts +2 -0
- package/dist/commands/generate-repository.js +40 -0
- package/dist/commands/generate-repository.test.d.ts +1 -0
- package/dist/commands/generate-repository.test.js +41 -0
- package/dist/commands/generate-serverless-handler.d.ts +2 -0
- package/dist/commands/generate-serverless-handler.js +46 -0
- package/dist/commands/generate-serverless-handler.test.d.ts +1 -0
- package/dist/commands/generate-serverless-handler.test.js +42 -0
- package/dist/commands/generate-service.d.ts +2 -0
- package/dist/commands/generate-service.js +52 -0
- package/dist/commands/generate-service.test.d.ts +1 -0
- package/dist/commands/generate-service.test.js +41 -0
- package/dist/commands/generate-websocket-gateway.d.ts +2 -0
- package/dist/commands/generate-websocket-gateway.js +47 -0
- package/dist/commands/generate-websocket-gateway.test.d.ts +1 -0
- package/dist/commands/generate-websocket-gateway.test.js +41 -0
- package/dist/commands/info.d.ts +2 -0
- package/dist/commands/info.js +91 -0
- package/dist/commands/pdf-to-audio.d.ts +2 -0
- package/dist/commands/pdf-to-audio.js +170 -0
- package/dist/commands/start.d.ts +2 -0
- package/dist/commands/start.js +61 -0
- package/dist/commands/test.d.ts +2 -0
- package/dist/commands/test.js +63 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +75 -0
- package/dist/index.test.d.ts +1 -0
- package/dist/index.test.js +93 -0
- package/dist/utils/generator.d.ts +25 -0
- package/dist/utils/generator.js +107 -0
- package/dist/utils/generator.test.d.ts +1 -0
- package/dist/utils/generator.test.js +137 -0
- package/package.json +73 -0
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.generateModule = generateModule;
|
|
7
|
+
const fs_1 = __importDefault(require("fs"));
|
|
8
|
+
const path_1 = __importDefault(require("path"));
|
|
9
|
+
const chalk_1 = __importDefault(require("chalk"));
|
|
10
|
+
const generator_1 = require("../utils/generator");
|
|
11
|
+
const MODULE_TEMPLATE = `import { HazelModule } from '@hazeljs/core';
|
|
12
|
+
import { {{className}}Controller } from './{{fileName}}.controller';
|
|
13
|
+
import { {{className}}Service } from './{{fileName}}.service';
|
|
14
|
+
|
|
15
|
+
@HazelModule({
|
|
16
|
+
controllers: [{{className}}Controller],
|
|
17
|
+
providers: [{{className}}Service],
|
|
18
|
+
})
|
|
19
|
+
export class {{className}}Module {}
|
|
20
|
+
`;
|
|
21
|
+
const CONTROLLER_TEMPLATE = `import { Controller, Get, Post, Body } from '@hazeljs/core';
|
|
22
|
+
import { {{className}}Service } from './{{fileName}}.service';
|
|
23
|
+
import { Create{{className}}Dto } from './dto/create-{{fileName}}.dto';
|
|
24
|
+
|
|
25
|
+
@Controller('/{{fileName}}')
|
|
26
|
+
export class {{className}}Controller {
|
|
27
|
+
constructor(private readonly {{camelName}}Service: {{className}}Service) {}
|
|
28
|
+
|
|
29
|
+
@Get()
|
|
30
|
+
findAll() {
|
|
31
|
+
return this.{{camelName}}Service.findAll();
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
@Post()
|
|
35
|
+
create(@Body() createDto: Create{{className}}Dto) {
|
|
36
|
+
return this.{{camelName}}Service.create(createDto);
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
`;
|
|
40
|
+
const SERVICE_TEMPLATE = `import { Service } from '@hazeljs/core';
|
|
41
|
+
import { Create{{className}}Dto } from './dto/create-{{fileName}}.dto';
|
|
42
|
+
|
|
43
|
+
@Service()
|
|
44
|
+
export class {{className}}Service {
|
|
45
|
+
private items: any[] = [];
|
|
46
|
+
|
|
47
|
+
findAll() {
|
|
48
|
+
return this.items;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
create(dto: Create{{className}}Dto) {
|
|
52
|
+
this.items.push(dto);
|
|
53
|
+
return dto;
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
`;
|
|
57
|
+
const CREATE_DTO_TEMPLATE = `export class Create{{className}}Dto {
|
|
58
|
+
// Add your properties here
|
|
59
|
+
name: string;
|
|
60
|
+
}
|
|
61
|
+
`;
|
|
62
|
+
const UPDATE_DTO_TEMPLATE = `export class Update{{className}}Dto {
|
|
63
|
+
// Add your properties here
|
|
64
|
+
name?: string;
|
|
65
|
+
}
|
|
66
|
+
`;
|
|
67
|
+
function generateModule(program) {
|
|
68
|
+
program
|
|
69
|
+
.command('module <name>')
|
|
70
|
+
.description('Generate a new module (with controller, service, DTOs)')
|
|
71
|
+
.alias('m')
|
|
72
|
+
.option('-p, --path <path>', 'Path where the module should be generated')
|
|
73
|
+
.option('--dry-run', 'Preview files without writing them')
|
|
74
|
+
.action(async (name, options) => {
|
|
75
|
+
const className = (0, generator_1.toPascalCase)(name);
|
|
76
|
+
const fileName = (0, generator_1.toKebabCase)(name);
|
|
77
|
+
const camelName = fileName.replace(/-([a-z])/g, (_, c) => c.toUpperCase());
|
|
78
|
+
const baseDir = path_1.default.join(process.cwd(), options.path || 'src', fileName);
|
|
79
|
+
const data = { className, fileName, camelName };
|
|
80
|
+
const files = [
|
|
81
|
+
{ file: `${fileName}.module.ts`, template: MODULE_TEMPLATE },
|
|
82
|
+
{ file: `${fileName}.controller.ts`, template: CONTROLLER_TEMPLATE },
|
|
83
|
+
{ file: `${fileName}.service.ts`, template: SERVICE_TEMPLATE },
|
|
84
|
+
{ file: `dto/create-${fileName}.dto.ts`, template: CREATE_DTO_TEMPLATE },
|
|
85
|
+
{ file: `dto/update-${fileName}.dto.ts`, template: UPDATE_DTO_TEMPLATE },
|
|
86
|
+
];
|
|
87
|
+
for (const { file, template } of files) {
|
|
88
|
+
const filePath = path_1.default.join(baseDir, file);
|
|
89
|
+
if (options.dryRun) {
|
|
90
|
+
console.log(chalk_1.default.blue(`[dry-run] Would create ${filePath}`));
|
|
91
|
+
continue;
|
|
92
|
+
}
|
|
93
|
+
const dir = path_1.default.dirname(filePath);
|
|
94
|
+
if (!fs_1.default.existsSync(dir)) {
|
|
95
|
+
fs_1.default.mkdirSync(dir, { recursive: true });
|
|
96
|
+
}
|
|
97
|
+
fs_1.default.writeFileSync(filePath, (0, generator_1.renderTemplate)(template, data));
|
|
98
|
+
console.log(chalk_1.default.green(`✓ Generated ${filePath}`));
|
|
99
|
+
}
|
|
100
|
+
if (!options.dryRun) {
|
|
101
|
+
console.log(chalk_1.default.blue(`\n📦 Module generated in ${baseDir}`));
|
|
102
|
+
console.log(chalk_1.default.gray(`\nNext steps:`));
|
|
103
|
+
console.log(chalk_1.default.gray(` Import ${className}Module in your app module.`));
|
|
104
|
+
}
|
|
105
|
+
});
|
|
106
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,54 @@
|
|
|
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_module_1 = require("./generate-module");
|
|
9
|
+
jest.mock('fs');
|
|
10
|
+
describe('generateModule', () => {
|
|
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 register the module command with alias', () => {
|
|
25
|
+
(0, generate_module_1.generateModule)(program);
|
|
26
|
+
const cmd = program.commands.find(c => c.name() === 'module');
|
|
27
|
+
expect(cmd).toBeDefined();
|
|
28
|
+
expect(cmd?.alias()).toBe('m');
|
|
29
|
+
});
|
|
30
|
+
it('should generate all module files', async () => {
|
|
31
|
+
(0, generate_module_1.generateModule)(program);
|
|
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);
|
|
39
|
+
});
|
|
40
|
+
it('should use @hazeljs/core imports in all generated files', async () => {
|
|
41
|
+
(0, generate_module_1.generateModule)(program);
|
|
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'));
|
|
45
|
+
expect(moduleContent).toContain("from '@hazeljs/core'");
|
|
46
|
+
const controllerContent = writtenContents.find(c => c.includes('Controller'));
|
|
47
|
+
expect(controllerContent).toContain("from '@hazeljs/core'");
|
|
48
|
+
});
|
|
49
|
+
it('should support --dry-run flag', async () => {
|
|
50
|
+
(0, generate_module_1.generateModule)(program);
|
|
51
|
+
await program.parseAsync(['node', 'test', 'module', 'user', '--dry-run']);
|
|
52
|
+
expect(mockFs.writeFileSync).not.toHaveBeenCalled();
|
|
53
|
+
});
|
|
54
|
+
});
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.generatePipe = generatePipe;
|
|
4
|
+
const generator_1 = require("../utils/generator");
|
|
5
|
+
const PIPE_TEMPLATE = `import { type PipeTransform, type RequestContext } from '@hazeljs/core';
|
|
6
|
+
|
|
7
|
+
export class {{className}}Pipe implements PipeTransform {
|
|
8
|
+
transform(value: unknown, context: RequestContext): unknown {
|
|
9
|
+
// Transform logic here
|
|
10
|
+
return value;
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
`;
|
|
14
|
+
class PipeGenerator extends generator_1.Generator {
|
|
15
|
+
constructor() {
|
|
16
|
+
super(...arguments);
|
|
17
|
+
this.suffix = 'pipe';
|
|
18
|
+
}
|
|
19
|
+
getDefaultTemplate() {
|
|
20
|
+
return PIPE_TEMPLATE;
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
function generatePipe(program) {
|
|
24
|
+
program
|
|
25
|
+
.command('pipe <name>')
|
|
26
|
+
.description('Generate a new pipe')
|
|
27
|
+
.option('-p, --path <path>', 'Path where the pipe should be generated')
|
|
28
|
+
.option('--dry-run', 'Preview files without writing them')
|
|
29
|
+
.action(async (name, options) => {
|
|
30
|
+
const generator = new PipeGenerator();
|
|
31
|
+
await generator.generate({ name, path: options.path, dryRun: options.dryRun });
|
|
32
|
+
});
|
|
33
|
+
}
|
|
@@ -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_pipe_1 = require("./generate-pipe");
|
|
9
|
+
jest.mock('fs');
|
|
10
|
+
describe('generatePipe', () => {
|
|
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 pipe file with correct suffix', async () => {
|
|
24
|
+
(0, generate_pipe_1.generatePipe)(program);
|
|
25
|
+
await program.parseAsync(['node', 'test', 'pipe', 'validation']);
|
|
26
|
+
expect(mockFs.writeFileSync).toHaveBeenCalledWith(expect.stringContaining('validation.pipe.ts'), expect.stringContaining('ValidationPipe'));
|
|
27
|
+
});
|
|
28
|
+
it('should implement PipeTransform interface', async () => {
|
|
29
|
+
(0, generate_pipe_1.generatePipe)(program);
|
|
30
|
+
await program.parseAsync(['node', 'test', 'pipe', 'validation']);
|
|
31
|
+
const writtenContent = mockFs.writeFileSync.mock.calls[0][1];
|
|
32
|
+
expect(writtenContent).toContain('PipeTransform');
|
|
33
|
+
expect(writtenContent).toContain('transform');
|
|
34
|
+
});
|
|
35
|
+
});
|
|
@@ -0,0 +1,66 @@
|
|
|
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.generateRag = generateRag;
|
|
7
|
+
const generator_1 = require("../utils/generator");
|
|
8
|
+
const chalk_1 = __importDefault(require("chalk"));
|
|
9
|
+
const RAG_SERVICE_TEMPLATE = `import { Service } from '@hazeljs/core';
|
|
10
|
+
import { RAGPipeline, MemoryVectorStore } from '@hazeljs/rag';
|
|
11
|
+
|
|
12
|
+
@Service()
|
|
13
|
+
export class {{className}}RagService {
|
|
14
|
+
private pipeline: RAGPipeline;
|
|
15
|
+
|
|
16
|
+
constructor() {
|
|
17
|
+
// Initialize with a memory vector store (swap for Pinecone, Qdrant, etc. in production)
|
|
18
|
+
const vectorStore = new MemoryVectorStore();
|
|
19
|
+
|
|
20
|
+
this.pipeline = new RAGPipeline({
|
|
21
|
+
vectorStore,
|
|
22
|
+
topK: 5,
|
|
23
|
+
});
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
async addDocument(content: string, metadata?: Record<string, unknown>) {
|
|
27
|
+
// Add a document to the vector store for retrieval
|
|
28
|
+
await this.pipeline.addDocument({
|
|
29
|
+
content,
|
|
30
|
+
metadata: metadata || {},
|
|
31
|
+
});
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
async query(question: string) {
|
|
35
|
+
// Retrieve relevant documents and generate a response
|
|
36
|
+
const results = await this.pipeline.query(question);
|
|
37
|
+
return results;
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
`;
|
|
41
|
+
class RagServiceGenerator extends generator_1.Generator {
|
|
42
|
+
constructor() {
|
|
43
|
+
super(...arguments);
|
|
44
|
+
this.suffix = 'rag';
|
|
45
|
+
}
|
|
46
|
+
getDefaultTemplate() {
|
|
47
|
+
return RAG_SERVICE_TEMPLATE;
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
function generateRag(command) {
|
|
51
|
+
command
|
|
52
|
+
.command('rag <name>')
|
|
53
|
+
.description('Generate a RAG (Retrieval-Augmented Generation) service')
|
|
54
|
+
.option('-p, --path <path>', 'Specify the path')
|
|
55
|
+
.option('--dry-run', 'Preview files without writing them')
|
|
56
|
+
.action(async (name, options) => {
|
|
57
|
+
const generator = new RagServiceGenerator();
|
|
58
|
+
await generator.generate({ name, path: options.path, dryRun: options.dryRun });
|
|
59
|
+
if (!options.dryRun) {
|
|
60
|
+
console.log(chalk_1.default.gray('\nNext steps:'));
|
|
61
|
+
console.log(chalk_1.default.gray(' 1. npm install @hazeljs/rag'));
|
|
62
|
+
console.log(chalk_1.default.gray(' 2. Register this service as a provider in your module'));
|
|
63
|
+
console.log(chalk_1.default.gray(' 3. Configure your embedding provider and vector store'));
|
|
64
|
+
}
|
|
65
|
+
});
|
|
66
|
+
}
|
|
@@ -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_rag_1 = require("./generate-rag");
|
|
9
|
+
jest.mock('fs');
|
|
10
|
+
describe('generateRag', () => {
|
|
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 RAG service file', async () => {
|
|
24
|
+
(0, generate_rag_1.generateRag)(program);
|
|
25
|
+
await program.parseAsync(['node', 'test', 'rag', 'knowledge']);
|
|
26
|
+
expect(mockFs.writeFileSync).toHaveBeenCalledWith(expect.stringContaining('knowledge.rag.ts'), expect.stringContaining('KnowledgeRagService'));
|
|
27
|
+
});
|
|
28
|
+
it('should import from @hazeljs/rag', async () => {
|
|
29
|
+
(0, generate_rag_1.generateRag)(program);
|
|
30
|
+
await program.parseAsync(['node', 'test', 'rag', 'knowledge']);
|
|
31
|
+
const writtenContent = mockFs.writeFileSync.mock.calls[0][1];
|
|
32
|
+
expect(writtenContent).toContain("from '@hazeljs/rag'");
|
|
33
|
+
expect(writtenContent).toContain('RAGPipeline');
|
|
34
|
+
});
|
|
35
|
+
});
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.generateRepository = generateRepository;
|
|
4
|
+
const generator_1 = require("../utils/generator");
|
|
5
|
+
const REPOSITORY_TEMPLATE = `import { Repository, BaseRepository, PrismaService } from '@hazeljs/prisma';
|
|
6
|
+
|
|
7
|
+
// @Repository implies @Injectable() — no need for both decorators
|
|
8
|
+
@Repository({ model: '{{modelName}}' })
|
|
9
|
+
export class {{className}}Repository extends BaseRepository<any> {
|
|
10
|
+
constructor(prisma: PrismaService) {
|
|
11
|
+
super(prisma, '{{modelName}}');
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
// Add custom repository methods here
|
|
15
|
+
async findByName(name: string) {
|
|
16
|
+
return this.findMany({ where: { name } });
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
`;
|
|
20
|
+
class RepositoryGenerator extends generator_1.Generator {
|
|
21
|
+
constructor() {
|
|
22
|
+
super(...arguments);
|
|
23
|
+
this.suffix = 'repository';
|
|
24
|
+
}
|
|
25
|
+
getDefaultTemplate() {
|
|
26
|
+
return REPOSITORY_TEMPLATE;
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
function generateRepository(program) {
|
|
30
|
+
program
|
|
31
|
+
.command('repository <name>')
|
|
32
|
+
.description('Generate a new Prisma repository')
|
|
33
|
+
.alias('repo')
|
|
34
|
+
.option('-p, --path <path>', 'Path where the repository should be generated')
|
|
35
|
+
.option('--dry-run', 'Preview files without writing them')
|
|
36
|
+
.action(async (name, options) => {
|
|
37
|
+
const generator = new RepositoryGenerator();
|
|
38
|
+
await generator.generate({ name, path: options.path, dryRun: options.dryRun });
|
|
39
|
+
});
|
|
40
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,41 @@
|
|
|
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_repository_1 = require("./generate-repository");
|
|
9
|
+
jest.mock('fs');
|
|
10
|
+
describe('generateRepository', () => {
|
|
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 repository command with alias', () => {
|
|
24
|
+
(0, generate_repository_1.generateRepository)(program);
|
|
25
|
+
const cmd = program.commands.find(c => c.name() === 'repository');
|
|
26
|
+
expect(cmd).toBeDefined();
|
|
27
|
+
expect(cmd?.alias()).toBe('repo');
|
|
28
|
+
});
|
|
29
|
+
it('should generate a repository file with correct suffix', async () => {
|
|
30
|
+
(0, generate_repository_1.generateRepository)(program);
|
|
31
|
+
await program.parseAsync(['node', 'test', 'repository', 'user']);
|
|
32
|
+
expect(mockFs.writeFileSync).toHaveBeenCalledWith(expect.stringContaining('user.repository.ts'), expect.stringContaining('UserRepository'));
|
|
33
|
+
});
|
|
34
|
+
it('should import from @hazeljs/prisma', async () => {
|
|
35
|
+
(0, generate_repository_1.generateRepository)(program);
|
|
36
|
+
await program.parseAsync(['node', 'test', 'repository', 'user']);
|
|
37
|
+
const writtenContent = mockFs.writeFileSync.mock.calls[0][1];
|
|
38
|
+
expect(writtenContent).toContain("from '@hazeljs/prisma'");
|
|
39
|
+
expect(writtenContent).toContain('BaseRepository');
|
|
40
|
+
});
|
|
41
|
+
});
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.generateServerlessHandler = generateServerlessHandler;
|
|
4
|
+
const generator_1 = require("../utils/generator");
|
|
5
|
+
const SERVERLESS_LAMBDA_TEMPLATE = `import { createLambdaHandler } from '@hazeljs/serverless';
|
|
6
|
+
import { AppModule } from './app.module';
|
|
7
|
+
|
|
8
|
+
export const handler = createLambdaHandler(AppModule);
|
|
9
|
+
`;
|
|
10
|
+
const SERVERLESS_CLOUD_FUNCTION_TEMPLATE = `import { createCloudFunctionHandler } from '@hazeljs/serverless';
|
|
11
|
+
import { AppModule } from './app.module';
|
|
12
|
+
|
|
13
|
+
export const handler = createCloudFunctionHandler(AppModule);
|
|
14
|
+
`;
|
|
15
|
+
class ServerlessHandlerGenerator extends generator_1.Generator {
|
|
16
|
+
constructor() {
|
|
17
|
+
super(...arguments);
|
|
18
|
+
this.suffix = 'handler';
|
|
19
|
+
}
|
|
20
|
+
getDefaultTemplate() {
|
|
21
|
+
return SERVERLESS_LAMBDA_TEMPLATE;
|
|
22
|
+
}
|
|
23
|
+
async generate(options) {
|
|
24
|
+
const { platform = 'lambda', ...restOptions } = options;
|
|
25
|
+
const template = platform === 'lambda'
|
|
26
|
+
? SERVERLESS_LAMBDA_TEMPLATE
|
|
27
|
+
: SERVERLESS_CLOUD_FUNCTION_TEMPLATE;
|
|
28
|
+
await super.generate({
|
|
29
|
+
...restOptions,
|
|
30
|
+
template,
|
|
31
|
+
});
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
function generateServerlessHandler(program) {
|
|
35
|
+
program
|
|
36
|
+
.command('serverless <name>')
|
|
37
|
+
.description('Generate a serverless handler (Lambda or Cloud Function)')
|
|
38
|
+
.alias('sls')
|
|
39
|
+
.option('-p, --path <path>', 'Path where the handler should be generated', 'src')
|
|
40
|
+
.option('--platform <platform>', 'Platform: lambda or cloud-function', 'lambda')
|
|
41
|
+
.option('--dry-run', 'Preview files without writing them')
|
|
42
|
+
.action(async (name, options) => {
|
|
43
|
+
const generator = new ServerlessHandlerGenerator();
|
|
44
|
+
await generator.generate({ name, path: options.path, platform: options.platform, dryRun: options.dryRun });
|
|
45
|
+
});
|
|
46
|
+
}
|
|
@@ -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_serverless_handler_1 = require("./generate-serverless-handler");
|
|
9
|
+
jest.mock('fs');
|
|
10
|
+
describe('generateServerlessHandler', () => {
|
|
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 serverless command with alias', () => {
|
|
24
|
+
(0, generate_serverless_handler_1.generateServerlessHandler)(program);
|
|
25
|
+
const cmd = program.commands.find(c => c.name() === 'serverless');
|
|
26
|
+
expect(cmd).toBeDefined();
|
|
27
|
+
expect(cmd?.alias()).toBe('sls');
|
|
28
|
+
});
|
|
29
|
+
it('should generate a lambda handler by default', async () => {
|
|
30
|
+
(0, generate_serverless_handler_1.generateServerlessHandler)(program);
|
|
31
|
+
await program.parseAsync(['node', 'test', 'serverless', 'api']);
|
|
32
|
+
const writtenContent = mockFs.writeFileSync.mock.calls[0][1];
|
|
33
|
+
expect(writtenContent).toContain('createLambdaHandler');
|
|
34
|
+
expect(writtenContent).toContain("from '@hazeljs/serverless'");
|
|
35
|
+
});
|
|
36
|
+
it('should generate a cloud function handler', async () => {
|
|
37
|
+
(0, generate_serverless_handler_1.generateServerlessHandler)(program);
|
|
38
|
+
await program.parseAsync(['node', 'test', 'serverless', 'api', '--platform', 'cloud-function']);
|
|
39
|
+
const writtenContent = mockFs.writeFileSync.mock.calls[0][1];
|
|
40
|
+
expect(writtenContent).toContain('createCloudFunctionHandler');
|
|
41
|
+
});
|
|
42
|
+
});
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.generateService = generateService;
|
|
4
|
+
const generator_1 = require("../utils/generator");
|
|
5
|
+
const SERVICE_TEMPLATE = `import { Service } from '@hazeljs/core';
|
|
6
|
+
|
|
7
|
+
@Service()
|
|
8
|
+
export class {{className}}Service {
|
|
9
|
+
constructor() {}
|
|
10
|
+
|
|
11
|
+
async findAll() {
|
|
12
|
+
return [];
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
async findOne(id: string) {
|
|
16
|
+
return { id };
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
async create(createDto: any) {
|
|
20
|
+
return createDto;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
async update(id: string, updateDto: any) {
|
|
24
|
+
return { id, ...updateDto };
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
async remove(id: string) {
|
|
28
|
+
return { id };
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
`;
|
|
32
|
+
class ServiceGenerator extends generator_1.Generator {
|
|
33
|
+
constructor() {
|
|
34
|
+
super(...arguments);
|
|
35
|
+
this.suffix = 'service';
|
|
36
|
+
}
|
|
37
|
+
getDefaultTemplate() {
|
|
38
|
+
return SERVICE_TEMPLATE;
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
function generateService(program) {
|
|
42
|
+
program
|
|
43
|
+
.command('service <name>')
|
|
44
|
+
.description('Generate a new service')
|
|
45
|
+
.alias('s')
|
|
46
|
+
.option('-p, --path <path>', 'Path where the service should be generated')
|
|
47
|
+
.option('--dry-run', 'Preview files without writing them')
|
|
48
|
+
.action(async (name, options) => {
|
|
49
|
+
const generator = new ServiceGenerator();
|
|
50
|
+
await generator.generate({ name, path: options.path, dryRun: options.dryRun });
|
|
51
|
+
});
|
|
52
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,41 @@
|
|
|
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_service_1 = require("./generate-service");
|
|
9
|
+
jest.mock('fs');
|
|
10
|
+
describe('generateService', () => {
|
|
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 service command with alias', () => {
|
|
24
|
+
(0, generate_service_1.generateService)(program);
|
|
25
|
+
const cmd = program.commands.find(c => c.name() === 'service');
|
|
26
|
+
expect(cmd).toBeDefined();
|
|
27
|
+
expect(cmd?.alias()).toBe('s');
|
|
28
|
+
});
|
|
29
|
+
it('should generate a service file with correct suffix', async () => {
|
|
30
|
+
(0, generate_service_1.generateService)(program);
|
|
31
|
+
await program.parseAsync(['node', 'test', 'service', 'user']);
|
|
32
|
+
expect(mockFs.writeFileSync).toHaveBeenCalledWith(expect.stringContaining('user.service.ts'), expect.stringContaining('UserService'));
|
|
33
|
+
});
|
|
34
|
+
it('should include Service decorator', async () => {
|
|
35
|
+
(0, generate_service_1.generateService)(program);
|
|
36
|
+
await program.parseAsync(['node', 'test', 'service', 'user']);
|
|
37
|
+
const writtenContent = mockFs.writeFileSync.mock.calls[0][1];
|
|
38
|
+
expect(writtenContent).toContain('@Service()');
|
|
39
|
+
expect(writtenContent).toContain("from '@hazeljs/core'");
|
|
40
|
+
});
|
|
41
|
+
});
|