UNPKG

pury

Version:

🛡️ AI-powered security scanner with advanced threat detection, dual reporting system (detailed & summary), and comprehensive code analysis

130 lines 5 kB
import { promises as fs } from 'fs'; import { join, dirname } from 'path'; import yaml from 'js-yaml'; import { DEFAULT_CONFIG } from './defaults.js'; import { fileExists, ensureDirectory } from '../utils/file-utils.js'; import { validateConfig } from '../utils/validation.js'; import { logger } from '../utils/logger.js'; export class ConfigManager { static CONFIG_FILES = [ 'puryai.config.yaml', 'puryai.config.yml', 'puryai.config.json', '.puryairc', '.puryairc.yaml', '.puryairc.yml', '.puryairc.json' ]; static GLOBAL_CONFIG_DIR = process.platform === 'win32' ? join(process.env.APPDATA || '', 'puryai') : join(process.env.HOME || '', '.puryai'); async loadConfig(searchPath = process.cwd()) { // Try to find config in current directory and parent directories let config = await this.findAndLoadConfig(searchPath); // If not found, try global config if (!config) { config = await this.loadGlobalConfig(); } // Merge with defaults and validate const mergedConfig = this.mergeWithDefaults(config || {}); return validateConfig(mergedConfig); } async findAndLoadConfig(startPath) { let currentPath = startPath; while (currentPath !== dirname(currentPath)) { for (const configFile of ConfigManager.CONFIG_FILES) { const configPath = join(currentPath, configFile); if (await fileExists(configPath)) { logger.debug(`Found config file: ${configPath}`); return await this.loadConfigFile(configPath); } } currentPath = dirname(currentPath); } return null; } async loadGlobalConfig() { const globalConfigPath = join(ConfigManager.GLOBAL_CONFIG_DIR, 'config.yaml'); if (await fileExists(globalConfigPath)) { logger.debug(`Loading global config: ${globalConfigPath}`); return await this.loadConfigFile(globalConfigPath); } return null; } async loadConfigFile(configPath) { try { const content = await fs.readFile(configPath, 'utf8'); const ext = configPath.split('.').pop()?.toLowerCase(); if (ext === 'json' || configPath.endsWith('.puryairc')) { return JSON.parse(content); } else if (ext === 'yaml' || ext === 'yml') { return yaml.load(content); } else { throw new Error(`Unsupported config file format: ${ext}`); } } catch (error) { logger.error(`Failed to load config file ${configPath}: ${error.message}`); throw error; } } async saveConfig(config, filePath) { const configPath = filePath || join(process.cwd(), 'puryai.config.yaml'); await ensureDirectory(dirname(configPath)); const yamlContent = yaml.dump(config, { indent: 2, lineWidth: 120, noRefs: true }); await fs.writeFile(configPath, yamlContent, 'utf8'); logger.success(`Config saved to: ${configPath}`); } async saveGlobalConfig(config) { const globalConfigPath = join(ConfigManager.GLOBAL_CONFIG_DIR, 'config.yaml'); await ensureDirectory(ConfigManager.GLOBAL_CONFIG_DIR); const yamlContent = yaml.dump(config, { indent: 2, lineWidth: 120, noRefs: true }); await fs.writeFile(globalConfigPath, yamlContent, 'utf8'); logger.success(`Global config saved to: ${globalConfigPath}`); } mergeWithDefaults(config) { return this.deepMerge(DEFAULT_CONFIG, config); } deepMerge(target, source) { const result = { ...target }; for (const key in source) { if (source[key] && typeof source[key] === 'object' && !Array.isArray(source[key])) { result[key] = this.deepMerge(result[key] || {}, source[key]); } else if (source[key] !== undefined) { result[key] = source[key]; } } return result; } generateDefaultConfig() { return yaml.dump(DEFAULT_CONFIG, { indent: 2, lineWidth: 120, noRefs: true }); } async initConfig(path = process.cwd()) { const configPath = join(path, 'puryai.config.yaml'); if (await fileExists(configPath)) { throw new Error(`Config file already exists: ${configPath}`); } await this.saveConfig(DEFAULT_CONFIG, configPath); } getConfigFilePath(searchPath = process.cwd()) { // This would need to be implemented as a synchronous version // of findAndLoadConfig for CLI usage return join(searchPath, 'puryai.config.yaml'); } } //# sourceMappingURL=config-manager.js.map