UNPKG

gather-ts

Version:

A powerful code analysis and packaging tool designed for creating AI-friendly code representations for javascript and typescript projects.

324 lines 12.3 kB
#!/usr/bin/env node "use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.CLI = void 0; // src/cli.ts require("./register"); const events_1 = __importDefault(require("events")); const path_1 = __importDefault(require("path")); const Container_1 = require("./container/Container"); const ContainerConfig_1 = require("./container/ContainerConfig"); const errors_1 = require("./errors"); class CLI extends events_1.default { constructor(deps, options = {}) { super(); this.deps = deps; this.isInitialized = false; this.metrics = { executionTime: 0, memoryUsage: 0, filesProcessed: 0, errors: 0, warnings: 0, }; this.startTime = Date.now(); this.debug = options.debug || false; this.exitOnError = options.exitOnError ?? true; } logDebug(message) { if (this.debug) { this.deps.logger.debug(`[CLI] ${message}`); } } async initialize() { this.logDebug("Initializing CLI"); try { if (this.isInitialized) { this.logDebug("CLI already initialized"); return; } this.startTime = Date.now(); this.initializeMetrics(); this.setupEventListeners(); this.isInitialized = true; this.logDebug("CLI initialization complete"); } catch (error) { const err = error instanceof Error ? error : new Error(String(error)); this.deps.logger.error(`Failed to initialize CLI: ${err.message}`); throw err; } } cleanup() { this.logDebug("Cleaning up CLI"); this.removeAllListeners(); this.isInitialized = false; } initializeMetrics() { this.metrics = { executionTime: 0, memoryUsage: 0, filesProcessed: 0, errors: 0, warnings: 0, }; } setupEventListeners() { this.logDebug("Setting up event listeners"); this.on("command:start", ({ command, options }) => { if (this.debug) { this.deps.logger.debug(`Starting command: ${command}`); this.deps.logger.debug(`Options: ${JSON.stringify(options, null, 2)}`); } }); this.on("command:complete", ({ result }) => { this.metrics.executionTime = Date.now() - this.startTime; this.metrics.memoryUsage = process.memoryUsage().heapUsed; if (result.metrics) { Object.assign(this.metrics, result.metrics); } }); this.on("error", ({ error, command }) => { this.metrics.errors++; if (command) { this.deps.logger.error(`Error in command ${command}:`); } this.deps.logger.error(error.message); if (error.stack && this.debug) { this.deps.logger.debug(error.stack); } }); this.on("warning", ({ message }) => { this.metrics.warnings++; this.deps.logger.warn(message); }); this.on("progress", ({ phase, completed, total, message }) => { const percentage = Math.round((completed / total) * 100); this.deps.logger.info(`${phase}: ${percentage}% (${completed}/${total}) ${message || ""}`); }); } async generateDefaultConfig() { this.logDebug("Generating default configuration"); try { this.deps.logger.info("No gather-ts.config.json found. Creating one with default settings..."); await this.deps.configManager.initialize(); this.deps.logger.success("Created default configuration file: gather-ts.config.json"); return { success: true, exitCode: 0, output: "Configuration initialized successfully", }; } catch (error) { this.deps.logger.warn("Could not create default config file. Using default settings."); return { success: false, exitCode: 1, error: error instanceof Error ? error : new Error(String(error)), }; } } validateRoot(root) { if (!this.isInitialized) { throw new errors_1.ValidationError("CLI not initialized"); } this.logDebug(`Validating root directory: ${root}`); const absolutePath = path_1.default.resolve(root); if (!this.deps.fileSystem.exists(absolutePath)) { throw new errors_1.ValidationError("Invalid root directory", { root: absolutePath, }); } return absolutePath; } async run() { if (!this.isInitialized) { throw new errors_1.ValidationError("CLI not initialized"); } const configManager = this.deps.configManager; const compiler = this.deps.compiler; // Check if required services are initialized if (!configManager.isInitialized) { await configManager.initialize(); } if (!compiler.isInitialized) { await compiler.initialize(); } this.logDebug("Starting CLI execution"); try { // Parse command line arguments const compileOptions = this.deps.argumentParser.parseArguments(process.argv.slice(2)); const projectRoot = this.validateRoot(compileOptions.rootDir || process.cwd()); this.emit("command:start", { command: "compile", options: compileOptions, timestamp: Date.now(), }); // Handle --init flag if (compileOptions.init) { return await this.generateDefaultConfig(); } // Initialize compiler before using it await this.deps.compiler.initialize(); // Process required files if specified if (compileOptions.requiredFiles?.length) { this.deps.logger.info("Processing required files..."); for (const file of compileOptions.requiredFiles) { const absolutePath = path_1.default.resolve(projectRoot, file); if (!this.deps.fileSystem.exists(absolutePath)) { this.emit("warning", { message: `Required file not found: ${file}`, command: "compile", timestamp: Date.now(), }); } } } // Forward progress events from compiler this.deps.compiler.on("progress", (progress) => { this.emit("progress", progress); }); // Run compilation const result = await this.deps.compiler.compile({ ...compileOptions, rootDir: projectRoot, }); // Log results this.deps.logger.success(`\nAnalysis complete!`); this.deps.logger.info(`Files processed: ${result.filesProcessed}`); this.deps.logger.info(`Tokens analyzed: ${result.totalTokens.toLocaleString()}`); this.deps.logger.info(`Output: ${path_1.default.relative(projectRoot, result.outputPath)}`); // Show metrics if enabled if (compileOptions.includeMetrics) { const metrics = this.deps.compiler.getMetrics(); this.deps.logger.info("\nPerformance Metrics:"); this.deps.logger.info("------------------"); this.deps.logger.info(`Processing Time: ${metrics.processingTime}ms`); this.deps.logger.info(`Memory Usage: ${(metrics.memoryUsage / 1024 / 1024).toFixed(2)}MB`); this.deps.logger.info(`Files: ${metrics.filesProcessed}`); this.deps.logger.info(`Errors: ${metrics.errors}`); this.deps.logger.info(`Warnings: ${metrics.warnings}`); } // Check for warnings const warning = this.deps.configManager.getTokenWarning(result.totalTokens); if (warning) { this.emit("warning", { message: warning, command: "compile", timestamp: Date.now(), }); } const cliResult = { success: true, exitCode: 0, output: result.outputPath, metrics: this.metrics, }; this.emit("command:complete", { command: "compile", result: cliResult, timestamp: Date.now(), }); return cliResult; } catch (error) { const err = error instanceof Error ? error : new Error(String(error)); this.emit("error", { error: err, command: "compile", timestamp: Date.now(), }); if (err instanceof errors_1.ValidationError) { this.deps.argumentParser.printUsage(); } if (this.exitOnError) { process.exit(1); } return { success: false, exitCode: 1, error: err, metrics: this.metrics, }; } } } exports.CLI = CLI; async function main() { let cli; let container; const debug = process.argv.includes("--debug"); // Parse root directory from command line args first const rootIndex = process.argv.indexOf("--root"); const projectRoot = rootIndex > -1 ? process.argv[rootIndex + 1] : process.cwd(); try { container = await (0, ContainerConfig_1.configureContainer)(projectRoot, { debug, maxCacheAge: 7 * 24 * 60 * 60 * 1000, // 7 days fileExtensions: ["ts", "tsx", "js", "jsx"], }); if (!container) { throw new Error("Failed to configure container"); } // Initialize container first await container.initialize(); // Resolve and type cast services properly const logger = container.resolve(Container_1.ServiceTokens.LOGGER); const configManager = container.resolve(Container_1.ServiceTokens.CONFIG_MANAGER); const compiler = container.resolve(Container_1.ServiceTokens.COMPILER); const argumentParser = container.resolve(Container_1.ServiceTokens.ARGUMENT_PARSER); const fileSystem = container.resolve(Container_1.ServiceTokens.FILE_SYSTEM); if (debug) { logger.enableDebug(); logger.debug("Debug mode enabled"); logger.debug(`Current working directory: ${process.cwd()}`); logger.debug(`Command line arguments: ${process.argv.join(" ")}`); } // Initialize services sequentially await configManager.initialize(); await compiler.initialize(); await argumentParser.initialize(); await fileSystem.initialize(); cli = new CLI({ logger, configManager, compiler, argumentParser, fileSystem, }, { debug, exitOnError: true, }); await cli.initialize(); if (debug) { logger.debug("CLI initialized"); } const result = await cli.run(); if (!result.success) { process.exit(result.exitCode); } } catch (error) { console.error("Fatal error:", error); process.exit(1); } finally { if (cli) { cli.cleanup(); } if (container) { container.cleanup(); } } } // Make sure main is called correctly if (require.main === module) { main().catch((error) => { console.error("Fatal error:", error); process.exit(1); }); } //# sourceMappingURL=cli.js.map