pury
Version:
🛡️ AI-powered security scanner with advanced threat detection, dual reporting system (detailed & summary), and comprehensive code analysis
84 lines • 3.35 kB
JavaScript
import { minimatch } from 'minimatch';
import { DEFAULT_EXCLUDE_PATTERNS, TEXT_FILE_EXTENSIONS } from '../config/defaults.js';
export class PatternMatcher {
includePatterns;
excludePatterns;
constructor(include = ['**/*'], exclude = DEFAULT_EXCLUDE_PATTERNS) {
this.includePatterns = include;
this.excludePatterns = exclude;
}
shouldIncludeFile(filePath) {
// First check if it matches include patterns
const isIncluded = this.includePatterns.some(pattern => minimatch(filePath, pattern, { dot: true }));
if (!isIncluded) {
return false;
}
// Then check if it matches any exclude patterns
const isExcluded = this.excludePatterns.some(pattern => minimatch(filePath, pattern, { dot: true }));
return !isExcluded;
}
shouldIncludeDirectory(dirPath) {
// Don't scan directories that match exclude patterns
const isExcluded = this.excludePatterns.some(pattern => {
// For directory patterns, we need to handle both exact matches and parent directories
const normalizedPattern = pattern.endsWith('/**') ? pattern.slice(0, -3) : pattern;
return (minimatch(dirPath, normalizedPattern, { dot: true }) ||
minimatch(dirPath, pattern, { dot: true }));
});
return !isExcluded;
}
isTextFile(filePath) {
const extension = this.getFileExtension(filePath);
return TEXT_FILE_EXTENSIONS.includes(extension);
}
isSupportedFile(filePath) {
// File must be included by patterns and be a text file
return this.shouldIncludeFile(filePath) && this.isTextFile(filePath);
}
getFileExtension(filePath) {
const parts = filePath.split('.');
return parts.length > 1 ? `.${parts.pop()?.toLowerCase()}` : '';
}
addIncludePattern(pattern) {
if (!this.includePatterns.includes(pattern)) {
this.includePatterns.push(pattern);
}
}
addExcludePattern(pattern) {
if (!this.excludePatterns.includes(pattern)) {
this.excludePatterns.push(pattern);
}
}
removeIncludePattern(pattern) {
this.includePatterns = this.includePatterns.filter(p => p !== pattern);
}
removeExcludePattern(pattern) {
this.excludePatterns = this.excludePatterns.filter(p => p !== pattern);
}
getPatterns() {
return {
include: [...this.includePatterns],
exclude: [...this.excludePatterns]
};
}
static createForLanguage(language) {
const languagePatterns = {
javascript: ['**/*.js', '**/*.jsx', '**/*.mjs', '**/*.cjs'],
typescript: ['**/*.ts', '**/*.tsx'],
python: ['**/*.py', '**/*.pyw'],
java: ['**/*.java'],
csharp: ['**/*.cs'],
cpp: ['**/*.cpp', '**/*.cxx', '**/*.cc', '**/*.c', '**/*.h', '**/*.hpp'],
php: ['**/*.php'],
ruby: ['**/*.rb'],
go: ['**/*.go'],
rust: ['**/*.rs'],
swift: ['**/*.swift'],
kotlin: ['**/*.kt'],
scala: ['**/*.scala']
};
const patterns = languagePatterns[language.toLowerCase()] || ['**/*'];
return new PatternMatcher(patterns);
}
}
//# sourceMappingURL=pattern-matcher.js.map