@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
JavaScript
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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