UNPKG

@hakkisagdic/context-manager

Version:

Universal LLM context manager supporting 14+ languages with method-level filtering, token optimization, and GitIngest format support

116 lines (95 loc) 4.05 kB
/** * GitIgnore Parser * Parses .gitignore, .calculatorignore, and .calculatorinclude files */ const fs = require('fs'); class GitIgnoreParser { constructor(gitignorePath, calculatorIgnorePath, calculatorIncludePath) { this.patterns = []; this.calculatorPatterns = []; this.hasIncludeFile = false; this._lastIgnoreReason = null; this.loadPatterns(gitignorePath, calculatorIgnorePath, calculatorIncludePath); } loadPatterns(gitignorePath, calculatorIgnorePath, calculatorIncludePath) { // Load .gitignore if (fs.existsSync(gitignorePath)) { this.patterns = this.parsePatternFile(gitignorePath); } // Load calculator patterns (include takes priority) if (calculatorIncludePath && fs.existsSync(calculatorIncludePath)) { this.calculatorPatterns = this.parsePatternFile(calculatorIncludePath); this.hasIncludeFile = true; console.log(`📅 Calculator include rules loaded: ${this.calculatorPatterns.length} patterns`); } else if (calculatorIgnorePath && fs.existsSync(calculatorIgnorePath)) { this.calculatorPatterns = this.parsePatternFile(calculatorIgnorePath); console.log(`📋 Calculator ignore rules loaded: ${this.calculatorPatterns.length} patterns`); } } parsePatternFile(filePath) { return fs.readFileSync(filePath, 'utf8') .split('\n') .map(line => line.trim()) .filter(line => line && !line.startsWith('#')) .map(pattern => this.convertToRegex(pattern)); } convertToRegex(pattern) { const isDirectory = pattern.endsWith('/'); const isNegation = pattern.startsWith('!'); const original = pattern; pattern = pattern.replace(/^[!/]/, '').replace(/\/$/, ''); let regexPattern = pattern .replace(/[.+^${}()|[\]\\]/g, '\\$&') .replace(/\*\*/g, '.*') .replace(/\*/g, '[^/]*') .replace(/\?/g, '[^/]'); regexPattern = original.startsWith('/') ? `^${regexPattern}` : `(^|/)${regexPattern}`; regexPattern += isDirectory ? '(/.*)?$' : '$'; return { regex: new RegExp(regexPattern), isNegation, original, isDirectory }; } isIgnored(filePath, relativePath) { let ignored = this.testPatterns(this.patterns, relativePath, 'gitignore'); if (this.hasIncludeFile) { if (ignored) return true; // Keep gitignore exclusions const stat = fs.statSync(filePath); if (stat.isDirectory()) { const shouldTraverse = this.calculatorPatterns.some(p => p.original.startsWith(relativePath) || p.original.includes('**') || relativePath === '' ); ignored = !shouldTraverse; } else { const included = this.testPatternsWithNegation(this.calculatorPatterns, relativePath); ignored = !included; } if (ignored) this._lastIgnoreReason = 'calculator-include'; } else if (!ignored) { ignored = this.testPatterns(this.calculatorPatterns, relativePath, 'calculator'); } return ignored; } testPatterns(patterns, relativePath, reason) { let ignored = false; for (const pattern of patterns) { if (pattern.regex.test(relativePath)) { ignored = !pattern.isNegation; if (ignored) this._lastIgnoreReason = reason; } } return ignored; } testPatternsWithNegation(patterns, relativePath) { let included = false; for (const pattern of patterns) { if (pattern.regex.test(relativePath)) { included = pattern.isNegation ? false : true; if (pattern.isNegation) break; } } return included; } } module.exports = GitIgnoreParser;