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.

209 lines (182 loc) 6.1 kB
import * as plugins from '../plugins.js'; import type { IContextConfig, ITrimConfig, ITaskConfig, TaskType, ContextMode } from './types.js'; /** * Manages configuration for context building */ export class ConfigManager { private static instance: ConfigManager; private config: IContextConfig; private projectDir: string = ''; /** * Get the singleton instance of ConfigManager */ public static getInstance(): ConfigManager { if (!ConfigManager.instance) { ConfigManager.instance = new ConfigManager(); } return ConfigManager.instance; } /** * Private constructor for singleton pattern */ private constructor() { this.config = this.getDefaultConfig(); } /** * Initialize the config manager with a project directory * @param projectDir The project directory */ public async initialize(projectDir: string): Promise<void> { this.projectDir = projectDir; await this.loadConfig(); } /** * Get the default configuration */ private getDefaultConfig(): IContextConfig { 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 } }; } /** * Load configuration from npmextra.json */ private async loadConfig(): Promise<void> { try { if (!this.projectDir) { return; } // Create KeyValueStore for this project // We'll just use smartfile directly instead of KeyValueStore // Read the npmextra.json file const npmextraJsonFile = await plugins.smartfile.SmartFile.fromFilePath( plugins.path.join(this.projectDir, 'npmextra.json') ); 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); } } 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 */ private mergeConfigs(defaultConfig: IContextConfig, userConfig: Partial<IContextConfig>): IContextConfig { const result: IContextConfig = { ...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'] as TaskType[]).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 }; } return result; } /** * Get the complete configuration */ public getConfig(): IContextConfig { return this.config; } /** * Get the trimming configuration */ public getTrimConfig(): ITrimConfig { return this.config.trimming || {}; } /** * Get configuration for a specific task * @param taskType The type of task */ public getTaskConfig(taskType: TaskType): ITaskConfig { // 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 */ public getMaxTokens(): number { return this.config.maxTokens || 190000; } /** * Update the configuration * @param config The new configuration */ public async updateConfig(config: Partial<IContextConfig>): Promise<void> { // Merge with existing config this.config = this.mergeConfigs(this.config, config); 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 as any; 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); } } }