pury
Version:
🛡️ AI-powered security scanner with advanced threat detection, dual reporting system (detailed & summary), and comprehensive code analysis
130 lines • 5 kB
JavaScript
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