UNPKG

@git.zone/tsdoc

Version:

A comprehensive TypeScript documentation tool that leverages AI to generate and enhance project documentation, including dynamic README creation, API docs via TypeDoc, and smart commit message generation.

318 lines 20.4 kB
import * as plugins from '../plugins.js'; import * as fs from 'fs'; /** * Manages configuration for context building */ export class ConfigManager { /** * Get the singleton instance of ConfigManager */ static getInstance() { if (!ConfigManager.instance) { ConfigManager.instance = new ConfigManager(); } return ConfigManager.instance; } /** * Private constructor for singleton pattern */ constructor() { this.projectDir = ''; this.configCache = null; this.config = this.getDefaultConfig(); } /** * Initialize the config manager with a project directory * @param projectDir The project directory */ async initialize(projectDir) { this.projectDir = projectDir; await this.loadConfig(); } /** * Get the default configuration */ getDefaultConfig() { return { maxTokens: 190000, // Default for o4-mini with some buffer defaultMode: 'trimmed', taskSpecificSettings: { readme: { mode: 'trimmed', includePaths: ['ts/', 'src/'], excludePaths: ['test/', 'node_modules/'] }, commit: { mode: 'trimmed', focusOnChangedFiles: true }, description: { mode: 'trimmed', includePackageInfo: true } }, trimming: { removeImplementations: true, preserveInterfaces: true, preserveTypeDefs: true, preserveJSDoc: true, maxFunctionLines: 5, removeComments: true, removeBlankLines: true }, cache: { enabled: true, ttl: 3600, // 1 hour maxSize: 100, // 100MB directory: undefined // Will be set to .nogit/context-cache by ContextCache }, analyzer: { useAIRefinement: false, // Disabled by default for now aiModel: 'haiku' }, prioritization: { dependencyWeight: 0.3, relevanceWeight: 0.4, efficiencyWeight: 0.2, recencyWeight: 0.1 }, tiers: { essential: { minScore: 0.8, trimLevel: 'none' }, important: { minScore: 0.5, trimLevel: 'light' }, optional: { minScore: 0.2, trimLevel: 'aggressive' } }, iterative: { maxIterations: 5, firstPassFileLimit: 10, subsequentPassFileLimit: 5, temperature: 0.3, model: 'gpt-4-turbo-preview' } }; } /** * Load configuration from npmextra.json */ async loadConfig() { try { if (!this.projectDir) { return; } const npmextraJsonPath = plugins.path.join(this.projectDir, 'npmextra.json'); // Check if file exists const fileExists = await plugins.smartfile.fs.fileExists(npmextraJsonPath); if (!fileExists) { return; } // Check cache const stats = await fs.promises.stat(npmextraJsonPath); const currentMtime = Math.floor(stats.mtimeMs); if (this.configCache && this.configCache.mtime === currentMtime) { // Use cached config this.config = this.configCache.config; return; } // Read the npmextra.json file const npmextraJsonFile = await plugins.smartfile.SmartFile.fromFilePath(npmextraJsonPath); const npmextraContent = JSON.parse(npmextraJsonFile.contents.toString()); // Check for tsdoc context configuration if (npmextraContent?.tsdoc?.context) { // Merge with default config this.config = this.mergeConfigs(this.config, npmextraContent.tsdoc.context); } // Cache the config this.configCache = { mtime: currentMtime, config: { ...this.config } }; } catch (error) { console.error('Error loading context configuration:', error); } } /** * Merge configurations, with userConfig taking precedence * @param defaultConfig The default configuration * @param userConfig The user configuration */ mergeConfigs(defaultConfig, userConfig) { const result = { ...defaultConfig }; // Merge top-level properties if (userConfig.maxTokens !== undefined) result.maxTokens = userConfig.maxTokens; if (userConfig.defaultMode !== undefined) result.defaultMode = userConfig.defaultMode; // Merge task-specific settings if (userConfig.taskSpecificSettings) { result.taskSpecificSettings = result.taskSpecificSettings || {}; // For each task type, merge settings ['readme', 'commit', 'description'].forEach(taskType => { if (userConfig.taskSpecificSettings?.[taskType]) { result.taskSpecificSettings[taskType] = { ...result.taskSpecificSettings[taskType], ...userConfig.taskSpecificSettings[taskType] }; } }); } // Merge trimming configuration if (userConfig.trimming) { result.trimming = { ...result.trimming, ...userConfig.trimming }; } // Merge cache configuration if (userConfig.cache) { result.cache = { ...result.cache, ...userConfig.cache }; } // Merge analyzer configuration if (userConfig.analyzer) { result.analyzer = { ...result.analyzer, ...userConfig.analyzer }; } // Merge prioritization weights if (userConfig.prioritization) { result.prioritization = { ...result.prioritization, ...userConfig.prioritization }; } // Merge tier configuration if (userConfig.tiers) { result.tiers = { ...result.tiers, ...userConfig.tiers }; } // Merge iterative configuration if (userConfig.iterative) { result.iterative = { ...result.iterative, ...userConfig.iterative }; } return result; } /** * Get the complete configuration */ getConfig() { return this.config; } /** * Get the trimming configuration */ getTrimConfig() { return this.config.trimming || {}; } /** * Get configuration for a specific task * @param taskType The type of task */ getTaskConfig(taskType) { // Get task-specific config or empty object const taskConfig = this.config.taskSpecificSettings?.[taskType] || {}; // If mode is not specified, use default mode if (!taskConfig.mode) { taskConfig.mode = this.config.defaultMode; } return taskConfig; } /** * Get the maximum tokens allowed for context */ getMaxTokens() { return this.config.maxTokens || 190000; } /** * Update the configuration * @param config The new configuration */ async updateConfig(config) { // Merge with existing config this.config = this.mergeConfigs(this.config, config); // Invalidate cache this.configCache = null; try { if (!this.projectDir) { return; } // Read the existing npmextra.json file const npmextraJsonPath = plugins.path.join(this.projectDir, 'npmextra.json'); let npmextraContent = {}; if (await plugins.smartfile.fs.fileExists(npmextraJsonPath)) { const npmextraJsonFile = await plugins.smartfile.SmartFile.fromFilePath(npmextraJsonPath); npmextraContent = JSON.parse(npmextraJsonFile.contents.toString()) || {}; } // Update the tsdoc context configuration const typedContent = npmextraContent; if (!typedContent.tsdoc) typedContent.tsdoc = {}; typedContent.tsdoc.context = this.config; // Write back to npmextra.json const updatedContent = JSON.stringify(npmextraContent, null, 2); await plugins.smartfile.memory.toFs(updatedContent, npmextraJsonPath); } catch (error) { console.error('Error updating context configuration:', error); } } /** * Get cache configuration */ getCacheConfig() { return this.config.cache || { enabled: true, ttl: 3600, maxSize: 100 }; } /** * Get analyzer configuration */ getAnalyzerConfig() { return this.config.analyzer || { useAIRefinement: false, aiModel: 'haiku' }; } /** * Get prioritization weights */ getPrioritizationWeights() { return this.config.prioritization || { dependencyWeight: 0.3, relevanceWeight: 0.4, efficiencyWeight: 0.2, recencyWeight: 0.1 }; } /** * Get tier configuration */ getTierConfig() { return this.config.tiers || { essential: { minScore: 0.8, trimLevel: 'none' }, important: { minScore: 0.5, trimLevel: 'light' }, optional: { minScore: 0.2, trimLevel: 'aggressive' } }; } /** * Get iterative configuration */ getIterativeConfig() { return this.config.iterative || { maxIterations: 5, firstPassFileLimit: 10, subsequentPassFileLimit: 5, temperature: 0.3, model: 'gpt-4-turbo-preview' }; } /** * Clear the config cache (force reload on next access) */ clearCache() { this.configCache = null; } } //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY29uZmlnLW1hbmFnZXIuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi90cy9jb250ZXh0L2NvbmZpZy1tYW5hZ2VyLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sS0FBSyxPQUFPLE1BQU0sZUFBZSxDQUFDO0FBQ3pDLE9BQU8sS0FBSyxFQUFFLE1BQU0sSUFBSSxDQUFDO0FBY3pCOztHQUVHO0FBQ0gsTUFBTSxPQUFPLGFBQWE7SUFNeEI7O09BRUc7SUFDSSxNQUFNLENBQUMsV0FBVztRQUN2QixJQUFJLENBQUMsYUFBYSxDQUFDLFFBQVEsRUFBRSxDQUFDO1lBQzVCLGFBQWEsQ0FBQyxRQUFRLEdBQUcsSUFBSSxhQUFhLEVBQUUsQ0FBQztRQUMvQyxDQUFDO1FBQ0QsT0FBTyxhQUFhLENBQUMsUUFBUSxDQUFDO0lBQ2hDLENBQUM7SUFFRDs7T0FFRztJQUNIO1FBaEJRLGVBQVUsR0FBVyxFQUFFLENBQUM7UUFDeEIsZ0JBQVcsR0FBcUQsSUFBSSxDQUFDO1FBZ0IzRSxJQUFJLENBQUMsTUFBTSxHQUFHLElBQUksQ0FBQyxnQkFBZ0IsRUFBRSxDQUFDO0lBQ3hDLENBQUM7SUFFRDs7O09BR0c7SUFDSSxLQUFLLENBQUMsVUFBVSxDQUFDLFVBQWtCO1FBQ3hDLElBQUksQ0FBQyxVQUFVLEdBQUcsVUFBVSxDQUFDO1FBQzdCLE1BQU0sSUFBSSxDQUFDLFVBQVUsRUFBRSxDQUFDO0lBQzFCLENBQUM7SUFFRDs7T0FFRztJQUNLLGdCQUFnQjtRQUN0QixPQUFPO1lBQ0wsU0FBUyxFQUFFLE1BQU0sRUFBRSx1Q0FBdUM7WUFDMUQsV0FBVyxFQUFFLFNBQVM7WUFDdEIsb0JBQW9CLEVBQUU7Z0JBQ3BCLE1BQU0sRUFBRTtvQkFDTixJQUFJLEVBQUUsU0FBUztvQkFDZixZQUFZLEVBQUUsQ0FBQyxLQUFLLEVBQUUsTUFBTSxDQUFDO29CQUM3QixZQUFZLEVBQUUsQ0FBQyxPQUFPLEVBQUUsZUFBZSxDQUFDO2lCQUN6QztnQkFD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