UNPKG

ccguard

Version:

Automated enforcement of net-negative LOC, complexity constraints, and quality standards for Claude code

112 lines 4.18 kB
"use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.ConfigLoader = void 0; const fs_1 = __importDefault(require("fs")); const path_1 = __importDefault(require("path")); const schemas_1 = require("../contracts/schemas"); const zod_1 = require("zod"); class ConfigLoader { configPath; static DEFAULT_CONFIG = { enforcement: { mode: 'session-wide', strategy: 'cumulative', ignoreEmptyLines: true, limitType: 'hard', // Default to hard limit for backward compatibility }, whitelist: { patterns: [], extensions: [], }, thresholds: { allowedPositiveLines: 0, }, }; config; constructor(configPath) { this.configPath = configPath; this.config = this.loadConfig(); } findConfigFile() { const configNames = ['.ccguard.config.json', 'ccguard.config.json']; // Start from current directory and walk up let currentDir = process.cwd(); while (currentDir !== path_1.default.parse(currentDir).root) { for (const configName of configNames) { const configPath = path_1.default.join(currentDir, configName); if (fs_1.default.existsSync(configPath)) { return configPath; } } currentDir = path_1.default.dirname(currentDir); } return null; } loadConfig() { const configPath = this.configPath ?? this.findConfigFile(); if (!configPath || !fs_1.default.existsSync(configPath)) { return ConfigLoader.DEFAULT_CONFIG; } try { const rawConfig = fs_1.default.readFileSync(configPath, 'utf-8'); const parsedConfig = JSON.parse(rawConfig); // Validate and apply defaults const validated = schemas_1.GuardConfigSchema.parse(parsedConfig); return validated; } catch (error) { if (error instanceof zod_1.z.ZodError) { console.error(`Invalid config at ${configPath}:`, error.errors); } else if (error instanceof SyntaxError) { console.error(`Invalid JSON in config file ${configPath}`); } else { console.error(`Error loading config from ${configPath}:`, error); } return ConfigLoader.DEFAULT_CONFIG; } } getConfig() { return this.config; } isFileWhitelisted(filePath) { const { patterns, extensions } = this.config.whitelist; // Check extension whitelist if (extensions.length > 0) { const ext = path_1.default.extname(filePath).toLowerCase(); if (extensions.includes(ext)) { return true; } } // Check pattern whitelist (simple glob matching) if (patterns.length > 0) { const normalizedPath = path_1.default.normalize(filePath); for (const pattern of patterns) { if (this.matchPattern(normalizedPath, pattern)) { return true; } } } return false; } matchPattern(filePath, pattern) { // Simple glob matching - supports * and ** const regexPattern = pattern .replace(/[.+^${}()|[\]\\]/g, '\\$&') // Escape regex special chars except * and ? .replace(/\*\*/g, '___DOUBLE_STAR___') // Temporary placeholder .replace(/\*/g, '[^/]*') // Single * matches anything except / .replace(/\?/g, '.') // ? matches any single character .replace(/___DOUBLE_STAR___/g, '.*'); // ** matches anything including / const regex = new RegExp(`^${regexPattern}$`); return regex.test(filePath); } reloadConfig() { this.config = this.loadConfig(); } } exports.ConfigLoader = ConfigLoader; //# sourceMappingURL=ConfigLoader.js.map