@notjustcoders/ioc-arise
Version:
Arise type-safe IoC containers from your code. Zero overhead, zero coupling.
161 lines ⢠7.96 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.generateCommand = void 0;
const commander_1 = require("commander");
const path_1 = require("path");
const fs_1 = require("fs");
const analyser_1 = require("../analyser");
const generator_1 = require("../generator");
const configManager_1 = require("../utils/configManager");
const configValidator_1 = require("../utils/configValidator");
const index_js_1 = require("../errors/index.js");
const moduleResolver_1 = require("../utils/moduleResolver");
const one_logger_client_sdk_1 = require("@notjustcoders/one-logger-client-sdk");
exports.generateCommand = new commander_1.Command('generate')
.description('Generate IoC container from TypeScript classes')
.option('-s, --source <dir>', 'Source directory to scan', '.')
.option('-o, --output <file>', 'Output file path', 'container.gen.ts')
.option('-i, --interface <pattern>', 'Interface name pattern to match (regex)')
.option('-e, --exclude <patterns...>', 'Exclude patterns for files')
.option('--check-cycles', 'Only check for circular dependencies without generating')
.option('--verbose', 'Enable verbose logging')
.action(async (options) => {
try {
await (0, one_logger_client_sdk_1.initializeOneLogger)({
name: "ioc-maker",
description: "ioc-maker",
tracer: {
batchSize: 1,
},
isDev: process.env.NODE_ENV === "development",
});
// Initialize config manager with the source directory
const initialSourceDir = (0, path_1.resolve)(options.source);
const configManager = new configManager_1.ConfigManager(initialSourceDir);
// Validate config if present
if (configManager.hasConfigFile()) {
const config = configManager.getConfig();
if (!configValidator_1.ConfigValidator.validateAndLog(config, configManager.getConfigPath())) {
process.exit(1);
}
}
// Merge CLI options with config file
const mergedOptions = configManager.mergeWithCliOptions(options);
const sourceDir = (0, path_1.resolve)(mergedOptions.source);
const outputPath = (0, path_1.resolve)(sourceDir, mergedOptions.output);
if (configManager.hasConfigFile() && mergedOptions.verbose) {
console.log(`š Using config file: ${configManager.getConfigPath()}`);
}
// Initialize module resolver if modules are configured
let moduleResolver = null;
if (mergedOptions.modules && Object.keys(mergedOptions.modules).length > 0) {
moduleResolver = new moduleResolver_1.ModuleResolver(mergedOptions.modules, sourceDir);
if (mergedOptions.verbose) {
console.log(`šļø Module support enabled with ${Object.keys(mergedOptions.modules).length} modules`);
}
}
if (!(0, fs_1.existsSync)(sourceDir)) {
const error = index_js_1.ErrorFactory.sourceDirectoryNotFound(sourceDir);
console.error(`ā ${index_js_1.ErrorUtils.formatForConsole(error)}`);
process.exit(1);
}
if (mergedOptions.verbose) {
console.log(`š Scanning directory: ${sourceDir}`);
console.log(`š Output file: ${outputPath}`);
if (mergedOptions.interface) {
console.log(`šÆ Interface pattern: ${mergedOptions.interface}`);
}
}
console.log("š Starting analysis...");
// Analyze the project
const classes = await (0, analyser_1.analyzeProject)(sourceDir, {
sourceDir,
interfacePattern: mergedOptions.interface,
excludePatterns: mergedOptions.exclude
});
console.log("analysis results", classes);
if (classes.length === 0) {
const error = index_js_1.ErrorFactory.noClassesFound(mergedOptions.interface || 'interfaces with "implements" keyword');
console.error(`ā ${index_js_1.ErrorUtils.formatForConsole(error)}`);
process.exit(1);
return;
}
// Group classes by modules if module resolver is available
let moduleGroupedClasses;
if (moduleResolver) {
moduleGroupedClasses = moduleResolver.groupClassesByModule(classes);
if (mergedOptions.verbose) {
console.log(`\nš Found ${classes.length} classes organized into ${moduleGroupedClasses.size} modules:`);
for (const [moduleName, moduleClasses] of moduleGroupedClasses) {
console.log(`\n š¦ ${moduleName} (${moduleClasses.length} classes):`);
moduleClasses.forEach(cls => {
console.log(` ⢠${cls.name} (${cls.dependencies.length} dependencies)`);
if (cls.dependencies.length > 0) {
console.log(` Dependencies: ${cls.dependencies.map(dep => dep.name).join(', ')}`);
}
});
}
}
}
else {
// Backward compatibility: single default module
moduleGroupedClasses = new Map([['CoreModule', classes]]);
if (mergedOptions.verbose) {
console.log(`\nš Found ${classes.length} classes:`);
classes.forEach(cls => {
console.log(` ⢠${cls.name} (${cls.dependencies.length} dependencies)`);
if (cls.dependencies.length > 0) {
console.log(` Dependencies: ${cls.dependencies.map(dep => dep.name).join(', ')}`);
}
});
}
}
// Check for circular dependencies
const cycles = (0, generator_1.detectCircularDependencies)(classes);
if (cycles.length > 0) {
const firstCycle = cycles[0];
if (firstCycle && firstCycle.length > 0) {
const className = firstCycle[0] || 'unknown';
const error = index_js_1.ErrorFactory.circularDependency(className, firstCycle);
console.error(`ā ${index_js_1.ErrorUtils.formatForConsole(error)}`);
if (cycles.length > 1) {
console.error('\n Additional cycles:');
cycles.slice(1).forEach((cycle, index) => {
console.error(` ${index + 2}. ${cycle.join(' ā ')}`);
});
}
}
else {
console.error('ā Circular dependencies detected but cycle information is incomplete');
}
process.exit(1);
}
if (mergedOptions.checkCycles) {
console.log('ā
No circular dependencies found.');
return;
}
// Generate container file
(0, generator_1.generateContainerFile)(moduleGroupedClasses, outputPath);
console.log(`ā
Container generated successfully!`);
console.log(` File: ${outputPath}`);
console.log(` Classes: ${classes.length}`);
if (mergedOptions.verbose) {
console.log('\nš You can now import and use your container:');
console.log(' import { container } from "./container.gen";');
console.log(' const userService = container.userService;');
}
// Force process exit to prevent hanging due to one-logger SDK
process.exit(0);
}
catch (error) {
if (index_js_1.ErrorUtils.isIoCError(error)) {
console.error(`ā ${index_js_1.ErrorUtils.formatForConsole(error)}`);
}
else {
const wrappedError = index_js_1.ErrorFactory.unexpectedError(error);
console.error(`ā ${index_js_1.ErrorUtils.formatForConsole(wrappedError)}`);
}
process.exit(1);
}
});
//# sourceMappingURL=generate.js.map