@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,93 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const commander_1 = require("commander");
|
|
4
|
+
const generate_controller_1 = require("./commands/generate-controller");
|
|
5
|
+
const generate_service_1 = require("./commands/generate-service");
|
|
6
|
+
const generate_module_1 = require("./commands/generate-module");
|
|
7
|
+
const generate_dto_1 = require("./commands/generate-dto");
|
|
8
|
+
const generate_guard_1 = require("./commands/generate-guard");
|
|
9
|
+
const generate_interceptor_1 = require("./commands/generate-interceptor");
|
|
10
|
+
const generate_middleware_1 = require("./commands/generate-middleware");
|
|
11
|
+
const generate_crud_1 = require("./commands/generate-crud");
|
|
12
|
+
const generate_auth_1 = require("./commands/generate-auth");
|
|
13
|
+
const generate_websocket_gateway_1 = require("./commands/generate-websocket-gateway");
|
|
14
|
+
const generate_exception_filter_1 = require("./commands/generate-exception-filter");
|
|
15
|
+
const generate_pipe_1 = require("./commands/generate-pipe");
|
|
16
|
+
const generate_repository_1 = require("./commands/generate-repository");
|
|
17
|
+
const generate_ai_service_1 = require("./commands/generate-ai-service");
|
|
18
|
+
const generate_agent_1 = require("./commands/generate-agent");
|
|
19
|
+
const generate_serverless_handler_1 = require("./commands/generate-serverless-handler");
|
|
20
|
+
const generate_config_1 = require("./commands/generate-config");
|
|
21
|
+
const generate_cache_1 = require("./commands/generate-cache");
|
|
22
|
+
const generate_cron_1 = require("./commands/generate-cron");
|
|
23
|
+
const generate_rag_1 = require("./commands/generate-rag");
|
|
24
|
+
const generate_discovery_1 = require("./commands/generate-discovery");
|
|
25
|
+
jest.mock('./commands/generate-controller');
|
|
26
|
+
jest.mock('./commands/generate-service');
|
|
27
|
+
jest.mock('./commands/generate-module');
|
|
28
|
+
jest.mock('./commands/generate-dto');
|
|
29
|
+
jest.mock('./commands/generate-guard');
|
|
30
|
+
jest.mock('./commands/generate-interceptor');
|
|
31
|
+
jest.mock('./commands/generate-middleware');
|
|
32
|
+
jest.mock('./commands/generate-crud');
|
|
33
|
+
jest.mock('./commands/generate-auth');
|
|
34
|
+
jest.mock('./commands/generate-websocket-gateway');
|
|
35
|
+
jest.mock('./commands/generate-exception-filter');
|
|
36
|
+
jest.mock('./commands/generate-pipe');
|
|
37
|
+
jest.mock('./commands/generate-repository');
|
|
38
|
+
jest.mock('./commands/generate-ai-service');
|
|
39
|
+
jest.mock('./commands/generate-agent');
|
|
40
|
+
jest.mock('./commands/generate-serverless-handler');
|
|
41
|
+
jest.mock('./commands/generate-config');
|
|
42
|
+
jest.mock('./commands/generate-cache');
|
|
43
|
+
jest.mock('./commands/generate-cron');
|
|
44
|
+
jest.mock('./commands/generate-rag');
|
|
45
|
+
jest.mock('./commands/generate-discovery');
|
|
46
|
+
let exitSpy;
|
|
47
|
+
beforeAll(() => {
|
|
48
|
+
exitSpy = jest.spyOn(process, 'exit').mockImplementation(() => undefined);
|
|
49
|
+
});
|
|
50
|
+
afterAll(() => {
|
|
51
|
+
exitSpy.mockRestore();
|
|
52
|
+
});
|
|
53
|
+
describe('CLI', () => {
|
|
54
|
+
beforeEach(() => {
|
|
55
|
+
jest.clearAllMocks();
|
|
56
|
+
});
|
|
57
|
+
it('should register all generator commands', () => {
|
|
58
|
+
// eslint-disable-next-line @typescript-eslint/no-require-imports
|
|
59
|
+
require('./index');
|
|
60
|
+
// Core generators
|
|
61
|
+
expect(generate_controller_1.generateController).toHaveBeenCalled();
|
|
62
|
+
expect(generate_service_1.generateService).toHaveBeenCalled();
|
|
63
|
+
expect(generate_module_1.generateModule).toHaveBeenCalled();
|
|
64
|
+
expect(generate_dto_1.generateDto).toHaveBeenCalled();
|
|
65
|
+
expect(generate_guard_1.generateGuard).toHaveBeenCalled();
|
|
66
|
+
expect(generate_interceptor_1.generateInterceptor).toHaveBeenCalled();
|
|
67
|
+
expect(generate_middleware_1.generateMiddleware).toHaveBeenCalled();
|
|
68
|
+
// Advanced generators
|
|
69
|
+
expect(generate_crud_1.generateCrud).toHaveBeenCalled();
|
|
70
|
+
expect(generate_auth_1.generateAuth).toHaveBeenCalled();
|
|
71
|
+
expect(generate_websocket_gateway_1.generateWebSocketGateway).toHaveBeenCalled();
|
|
72
|
+
expect(generate_exception_filter_1.generateExceptionFilter).toHaveBeenCalled();
|
|
73
|
+
expect(generate_pipe_1.generatePipe).toHaveBeenCalled();
|
|
74
|
+
expect(generate_repository_1.generateRepository).toHaveBeenCalled();
|
|
75
|
+
expect(generate_ai_service_1.generateAIService).toHaveBeenCalled();
|
|
76
|
+
expect(generate_agent_1.generateAgent).toHaveBeenCalled();
|
|
77
|
+
expect(generate_serverless_handler_1.generateServerlessHandler).toHaveBeenCalled();
|
|
78
|
+
expect(generate_config_1.generateConfig).toHaveBeenCalled();
|
|
79
|
+
expect(generate_cache_1.generateCache).toHaveBeenCalled();
|
|
80
|
+
expect(generate_cron_1.generateCron).toHaveBeenCalled();
|
|
81
|
+
expect(generate_rag_1.generateRag).toHaveBeenCalled();
|
|
82
|
+
expect(generate_discovery_1.generateDiscovery).toHaveBeenCalled();
|
|
83
|
+
});
|
|
84
|
+
it('should have generate command with alias g', () => {
|
|
85
|
+
const program = new commander_1.Command();
|
|
86
|
+
program.name('hazel').description('CLI for generating HazelJS components').version('0.2.0');
|
|
87
|
+
const generate = program.command('generate').description('Generate a new component').alias('g');
|
|
88
|
+
(0, generate_controller_1.generateController)(generate);
|
|
89
|
+
(0, generate_service_1.generateService)(generate);
|
|
90
|
+
(0, generate_module_1.generateModule)(generate);
|
|
91
|
+
expect(generate.alias()).toBe('g');
|
|
92
|
+
});
|
|
93
|
+
});
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared string transformation utilities
|
|
3
|
+
*/
|
|
4
|
+
export declare function toPascalCase(str: string): string;
|
|
5
|
+
export declare function toKebabCase(str: string): string;
|
|
6
|
+
export declare function toCamelCase(str: string): string;
|
|
7
|
+
export declare function renderTemplate(template: string, data: Record<string, string>): string;
|
|
8
|
+
export interface GeneratorOptions {
|
|
9
|
+
name: string;
|
|
10
|
+
path?: string;
|
|
11
|
+
template?: string;
|
|
12
|
+
data?: Record<string, unknown>;
|
|
13
|
+
dryRun?: boolean;
|
|
14
|
+
}
|
|
15
|
+
export declare class Generator {
|
|
16
|
+
/**
|
|
17
|
+
* File suffix appended before .ts (e.g. 'controller' -> name.controller.ts)
|
|
18
|
+
* Override in subclasses.
|
|
19
|
+
*/
|
|
20
|
+
protected suffix: string;
|
|
21
|
+
generate(options: GeneratorOptions): Promise<void>;
|
|
22
|
+
protected getFilePath(name: string, customPath?: string): string;
|
|
23
|
+
protected getDefaultTemplate(): string;
|
|
24
|
+
promptForOptions(options: Partial<GeneratorOptions>): Promise<GeneratorOptions>;
|
|
25
|
+
}
|
|
@@ -0,0 +1,107 @@
|
|
|
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.Generator = void 0;
|
|
7
|
+
exports.toPascalCase = toPascalCase;
|
|
8
|
+
exports.toKebabCase = toKebabCase;
|
|
9
|
+
exports.toCamelCase = toCamelCase;
|
|
10
|
+
exports.renderTemplate = renderTemplate;
|
|
11
|
+
const fs_1 = __importDefault(require("fs"));
|
|
12
|
+
const path_1 = __importDefault(require("path"));
|
|
13
|
+
const chalk_1 = __importDefault(require("chalk"));
|
|
14
|
+
const inquirer_1 = __importDefault(require("inquirer"));
|
|
15
|
+
const mustache_1 = __importDefault(require("mustache"));
|
|
16
|
+
/**
|
|
17
|
+
* Shared string transformation utilities
|
|
18
|
+
*/
|
|
19
|
+
function toPascalCase(str) {
|
|
20
|
+
return str
|
|
21
|
+
.split(/[-_]/)
|
|
22
|
+
.map((word) => word.charAt(0).toUpperCase() + word.slice(1).toLowerCase())
|
|
23
|
+
.join('');
|
|
24
|
+
}
|
|
25
|
+
function toKebabCase(str) {
|
|
26
|
+
return str
|
|
27
|
+
.replace(/([a-z])([A-Z])/g, '$1-$2')
|
|
28
|
+
.replace(/[\s_]+/g, '-')
|
|
29
|
+
.toLowerCase();
|
|
30
|
+
}
|
|
31
|
+
function toCamelCase(str) {
|
|
32
|
+
const pascal = toPascalCase(str);
|
|
33
|
+
return pascal.charAt(0).toLowerCase() + pascal.slice(1);
|
|
34
|
+
}
|
|
35
|
+
function renderTemplate(template, data) {
|
|
36
|
+
return mustache_1.default.render(template, data);
|
|
37
|
+
}
|
|
38
|
+
class Generator {
|
|
39
|
+
constructor() {
|
|
40
|
+
/**
|
|
41
|
+
* File suffix appended before .ts (e.g. 'controller' -> name.controller.ts)
|
|
42
|
+
* Override in subclasses.
|
|
43
|
+
*/
|
|
44
|
+
this.suffix = '';
|
|
45
|
+
}
|
|
46
|
+
async generate(options) {
|
|
47
|
+
const { name, path: customPath, template, data = {}, dryRun = false } = options;
|
|
48
|
+
// Get the template
|
|
49
|
+
const templateContent = template || this.getDefaultTemplate();
|
|
50
|
+
// Prepare the data
|
|
51
|
+
const templateData = {
|
|
52
|
+
name,
|
|
53
|
+
className: toPascalCase(name),
|
|
54
|
+
fileName: toKebabCase(name),
|
|
55
|
+
camelName: toCamelCase(name),
|
|
56
|
+
...data,
|
|
57
|
+
};
|
|
58
|
+
// Render the template
|
|
59
|
+
const content = mustache_1.default.render(templateContent, templateData);
|
|
60
|
+
// Determine the file path
|
|
61
|
+
const filePath = this.getFilePath(name, customPath);
|
|
62
|
+
if (dryRun) {
|
|
63
|
+
console.log(chalk_1.default.blue(`[dry-run] Would create ${filePath}`));
|
|
64
|
+
console.log(chalk_1.default.gray(content));
|
|
65
|
+
return;
|
|
66
|
+
}
|
|
67
|
+
// Create directory if it doesn't exist
|
|
68
|
+
const dir = path_1.default.dirname(filePath);
|
|
69
|
+
if (!fs_1.default.existsSync(dir)) {
|
|
70
|
+
fs_1.default.mkdirSync(dir, { recursive: true });
|
|
71
|
+
}
|
|
72
|
+
// Write the file
|
|
73
|
+
fs_1.default.writeFileSync(filePath, content);
|
|
74
|
+
console.log(chalk_1.default.green(`✓ Generated ${filePath}`));
|
|
75
|
+
}
|
|
76
|
+
getFilePath(name, customPath) {
|
|
77
|
+
const fileName = toKebabCase(name);
|
|
78
|
+
const basePath = customPath || 'src';
|
|
79
|
+
const suffix = this.suffix ? `.${this.suffix}` : '';
|
|
80
|
+
return path_1.default.join(process.cwd(), basePath, `${fileName}${suffix}.ts`);
|
|
81
|
+
}
|
|
82
|
+
getDefaultTemplate() {
|
|
83
|
+
return '';
|
|
84
|
+
}
|
|
85
|
+
async promptForOptions(options) {
|
|
86
|
+
const answers = await inquirer_1.default.prompt([
|
|
87
|
+
{
|
|
88
|
+
type: 'input',
|
|
89
|
+
name: 'name',
|
|
90
|
+
message: 'What is the name of the component?',
|
|
91
|
+
when: !options.name,
|
|
92
|
+
},
|
|
93
|
+
{
|
|
94
|
+
type: 'input',
|
|
95
|
+
name: 'path',
|
|
96
|
+
message: 'Where should the component be generated?',
|
|
97
|
+
default: 'src',
|
|
98
|
+
when: !options.path,
|
|
99
|
+
},
|
|
100
|
+
]);
|
|
101
|
+
return {
|
|
102
|
+
...options,
|
|
103
|
+
...answers,
|
|
104
|
+
};
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
exports.Generator = Generator;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,137 @@
|
|
|
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 path_1 = __importDefault(require("path"));
|
|
8
|
+
const generator_1 = require("./generator");
|
|
9
|
+
const inquirer_1 = __importDefault(require("inquirer"));
|
|
10
|
+
jest.mock('fs');
|
|
11
|
+
jest.mock('inquirer');
|
|
12
|
+
describe('Generator utilities', () => {
|
|
13
|
+
describe('toPascalCase', () => {
|
|
14
|
+
it('should convert kebab-case', () => {
|
|
15
|
+
expect((0, generator_1.toPascalCase)('test-name')).toBe('TestName');
|
|
16
|
+
});
|
|
17
|
+
it('should convert snake_case', () => {
|
|
18
|
+
expect((0, generator_1.toPascalCase)('test_name')).toBe('TestName');
|
|
19
|
+
});
|
|
20
|
+
it('should handle single word', () => {
|
|
21
|
+
expect((0, generator_1.toPascalCase)('test')).toBe('Test');
|
|
22
|
+
});
|
|
23
|
+
});
|
|
24
|
+
describe('toKebabCase', () => {
|
|
25
|
+
it('should convert camelCase', () => {
|
|
26
|
+
expect((0, generator_1.toKebabCase)('testName')).toBe('test-name');
|
|
27
|
+
});
|
|
28
|
+
it('should convert PascalCase', () => {
|
|
29
|
+
expect((0, generator_1.toKebabCase)('TestName')).toBe('test-name');
|
|
30
|
+
});
|
|
31
|
+
it('should convert snake_case', () => {
|
|
32
|
+
expect((0, generator_1.toKebabCase)('test_name')).toBe('test-name');
|
|
33
|
+
});
|
|
34
|
+
it('should handle single word', () => {
|
|
35
|
+
expect((0, generator_1.toKebabCase)('test')).toBe('test');
|
|
36
|
+
});
|
|
37
|
+
});
|
|
38
|
+
describe('toCamelCase', () => {
|
|
39
|
+
it('should convert kebab-case', () => {
|
|
40
|
+
expect((0, generator_1.toCamelCase)('test-name')).toBe('testName');
|
|
41
|
+
});
|
|
42
|
+
it('should convert snake_case', () => {
|
|
43
|
+
expect((0, generator_1.toCamelCase)('test_name')).toBe('testName');
|
|
44
|
+
});
|
|
45
|
+
it('should handle single word', () => {
|
|
46
|
+
expect((0, generator_1.toCamelCase)('test')).toBe('test');
|
|
47
|
+
});
|
|
48
|
+
});
|
|
49
|
+
describe('renderTemplate', () => {
|
|
50
|
+
it('should replace mustache variables', () => {
|
|
51
|
+
const result = (0, generator_1.renderTemplate)('Hello {{name}}!', { name: 'World' });
|
|
52
|
+
expect(result).toBe('Hello World!');
|
|
53
|
+
});
|
|
54
|
+
it('should handle multiple variables', () => {
|
|
55
|
+
const result = (0, generator_1.renderTemplate)('{{className}} at {{fileName}}', {
|
|
56
|
+
className: 'Test',
|
|
57
|
+
fileName: 'test',
|
|
58
|
+
});
|
|
59
|
+
expect(result).toBe('Test at test');
|
|
60
|
+
});
|
|
61
|
+
});
|
|
62
|
+
});
|
|
63
|
+
describe('Generator class', () => {
|
|
64
|
+
let generator;
|
|
65
|
+
const mockFs = fs_1.default;
|
|
66
|
+
const mockInquirer = inquirer_1.default;
|
|
67
|
+
beforeEach(() => {
|
|
68
|
+
generator = new generator_1.Generator();
|
|
69
|
+
jest.clearAllMocks();
|
|
70
|
+
mockFs.existsSync.mockReturnValue(true);
|
|
71
|
+
mockFs.writeFileSync.mockImplementation(() => { });
|
|
72
|
+
});
|
|
73
|
+
describe('generate', () => {
|
|
74
|
+
it('should create directory if it does not exist', async () => {
|
|
75
|
+
mockFs.existsSync.mockReturnValue(false);
|
|
76
|
+
await generator.generate({
|
|
77
|
+
name: 'test',
|
|
78
|
+
path: 'src/test',
|
|
79
|
+
template: 'test template',
|
|
80
|
+
});
|
|
81
|
+
expect(mockFs.mkdirSync).toHaveBeenCalledWith(path_1.default.join(process.cwd(), 'src/test'), { recursive: true });
|
|
82
|
+
});
|
|
83
|
+
it('should write file with rendered template', async () => {
|
|
84
|
+
await generator.generate({
|
|
85
|
+
name: 'test',
|
|
86
|
+
path: 'src/test',
|
|
87
|
+
template: 'Hello {{name}}!',
|
|
88
|
+
data: { name: 'World' },
|
|
89
|
+
});
|
|
90
|
+
expect(mockFs.writeFileSync).toHaveBeenCalledWith(expect.stringContaining('test.ts'), 'Hello World!');
|
|
91
|
+
});
|
|
92
|
+
it('should include className and fileName in template data', async () => {
|
|
93
|
+
await generator.generate({
|
|
94
|
+
name: 'my-widget',
|
|
95
|
+
path: 'src',
|
|
96
|
+
template: '{{className}} {{fileName}} {{camelName}}',
|
|
97
|
+
});
|
|
98
|
+
expect(mockFs.writeFileSync).toHaveBeenCalledWith(expect.any(String), 'MyWidget my-widget myWidget');
|
|
99
|
+
});
|
|
100
|
+
it('should not write files in dry-run mode', async () => {
|
|
101
|
+
const consoleSpy = jest.spyOn(console, 'log').mockImplementation();
|
|
102
|
+
await generator.generate({
|
|
103
|
+
name: 'test',
|
|
104
|
+
template: 'content',
|
|
105
|
+
dryRun: true,
|
|
106
|
+
});
|
|
107
|
+
expect(mockFs.writeFileSync).not.toHaveBeenCalled();
|
|
108
|
+
expect(consoleSpy).toHaveBeenCalledWith(expect.stringContaining('[dry-run]'));
|
|
109
|
+
consoleSpy.mockRestore();
|
|
110
|
+
});
|
|
111
|
+
});
|
|
112
|
+
describe('promptForOptions', () => {
|
|
113
|
+
it('should prompt for missing options', async () => {
|
|
114
|
+
mockInquirer.prompt.mockResolvedValue({
|
|
115
|
+
name: 'test',
|
|
116
|
+
path: 'src/test',
|
|
117
|
+
});
|
|
118
|
+
const result = await generator.promptForOptions({});
|
|
119
|
+
expect(mockInquirer.prompt).toHaveBeenCalled();
|
|
120
|
+
expect(result).toEqual({
|
|
121
|
+
name: 'test',
|
|
122
|
+
path: 'src/test',
|
|
123
|
+
});
|
|
124
|
+
});
|
|
125
|
+
it('should not prompt for provided options', async () => {
|
|
126
|
+
mockInquirer.prompt.mockResolvedValue({});
|
|
127
|
+
const result = await generator.promptForOptions({
|
|
128
|
+
name: 'test',
|
|
129
|
+
path: 'src/test',
|
|
130
|
+
});
|
|
131
|
+
expect(result).toEqual({
|
|
132
|
+
name: 'test',
|
|
133
|
+
path: 'src/test',
|
|
134
|
+
});
|
|
135
|
+
});
|
|
136
|
+
});
|
|
137
|
+
});
|
package/package.json
ADDED
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@hazeljs/cli",
|
|
3
|
+
"version": "0.2.0-alpha.1",
|
|
4
|
+
"description": "Command-line interface for scaffolding and generating HazelJS applications and components",
|
|
5
|
+
"main": "dist/index.js",
|
|
6
|
+
"types": "dist/index.d.ts",
|
|
7
|
+
"files": [
|
|
8
|
+
"dist",
|
|
9
|
+
"@template"
|
|
10
|
+
],
|
|
11
|
+
"bin": {
|
|
12
|
+
"hazel": "./dist/index.js"
|
|
13
|
+
},
|
|
14
|
+
"scripts": {
|
|
15
|
+
"build": "tsc",
|
|
16
|
+
"test": "jest",
|
|
17
|
+
"lint": "eslint src --ext .ts",
|
|
18
|
+
"format": "prettier --write \"src/**/*.ts\"",
|
|
19
|
+
"prepare": "npm run build"
|
|
20
|
+
},
|
|
21
|
+
"dependencies": {
|
|
22
|
+
"chalk": "^4.1.2",
|
|
23
|
+
"commander": "^11.1.0",
|
|
24
|
+
"form-data": "^4.0.0",
|
|
25
|
+
"inquirer": "^8.2.6",
|
|
26
|
+
"mustache": "^4.2.0",
|
|
27
|
+
"ora": "^5.4.1"
|
|
28
|
+
},
|
|
29
|
+
"devDependencies": {
|
|
30
|
+
"@types/inquirer": "^8.2.6",
|
|
31
|
+
"@types/jest": "^29.5.12",
|
|
32
|
+
"@types/mustache": "^4.2.4",
|
|
33
|
+
"@types/node": "^20.11.24",
|
|
34
|
+
"@typescript-eslint/eslint-plugin": "^8.18.2",
|
|
35
|
+
"@typescript-eslint/parser": "^8.18.2",
|
|
36
|
+
"eslint": "^8.57.0",
|
|
37
|
+
"jest": "^29.7.0",
|
|
38
|
+
"prettier": "^3.2.5",
|
|
39
|
+
"ts-jest": "^29.1.2",
|
|
40
|
+
"typescript": "^5.3.3"
|
|
41
|
+
},
|
|
42
|
+
"engines": {
|
|
43
|
+
"node": ">=14.0.0"
|
|
44
|
+
},
|
|
45
|
+
"publishConfig": {
|
|
46
|
+
"access": "public"
|
|
47
|
+
},
|
|
48
|
+
"keywords": [
|
|
49
|
+
"hazeljs",
|
|
50
|
+
"cli",
|
|
51
|
+
"generator",
|
|
52
|
+
"scaffolding",
|
|
53
|
+
"code-generator",
|
|
54
|
+
"typescript",
|
|
55
|
+
"framework"
|
|
56
|
+
],
|
|
57
|
+
"author": "Muhammad Arslan <muhammad.arslan@hazeljs.com>",
|
|
58
|
+
"license": "Apache-2.0",
|
|
59
|
+
"repository": {
|
|
60
|
+
"type": "git",
|
|
61
|
+
"url": "git+https://github.com/hazel-js/hazeljs.git",
|
|
62
|
+
"directory": "packages/cli"
|
|
63
|
+
},
|
|
64
|
+
"bugs": {
|
|
65
|
+
"url": "https://github.com/hazeljs/hazel-js/issues"
|
|
66
|
+
},
|
|
67
|
+
"homepage": "https://hazeljs.com",
|
|
68
|
+
"funding": {
|
|
69
|
+
"type": "opencollective",
|
|
70
|
+
"url": "https://opencollective.com/hazeljs"
|
|
71
|
+
},
|
|
72
|
+
"gitHead": "cbc5ee2c12ced28fd0576faf13c5f078c1e8421e"
|
|
73
|
+
}
|