UNPKG

@lishenxydlgzs/simple-files-vectorstore

Version:

A Model Context Protocol (MCP) server that provides semantic search capabilities across files. This server watches specified directories and creates vector embeddings of file contents, enabling semantic search across your documents.

91 lines (90 loc) 3.88 kB
import * as fs from 'fs/promises'; import * as path from 'path'; import { minimatch } from 'minimatch'; export class IgnorePatternMatcher { constructor(ignoreFilePath) { this.ignoreFilePath = ignoreFilePath; this.patterns = []; this.loaded = false; this.watchedDirectories = []; } async loadPatterns() { if (this.loaded || !this.ignoreFilePath) return; try { const content = await fs.readFile(this.ignoreFilePath, 'utf-8'); this.patterns = content .split('\n') .map(line => line.trim()) .filter(line => line && !line.startsWith('#')); this.loaded = true; } catch (error) { console.error(`Error loading ignore file ${this.ignoreFilePath}:`, error); // Continue without patterns if file can't be loaded this.patterns = []; this.loaded = true; } } setWatchedDirectories(directories) { this.watchedDirectories = directories.map(dir => path.normalize(dir)); } shouldIgnore(filePath, isDirectory = false) { if (!this.loaded || this.patterns.length === 0) return false; const normalizedPath = path.normalize(filePath); // Check each pattern for (const pattern of this.patterns) { // For patterns without leading slash, check if any part of the path matches if (!pattern.startsWith('/')) { // Get the basename or the relevant part for matching const basename = path.basename(normalizedPath); // Direct name match (e.g., ".vscode" matches any file/dir named ".vscode") if (basename === pattern) { return true; } // Check if any directory in the path matches the pattern const pathParts = normalizedPath.split(path.sep); for (const part of pathParts) { if (part === pattern) { return true; } } // Check if the path contains the pattern anywhere if (normalizedPath.includes(`${path.sep}${pattern}`) || normalizedPath.endsWith(`${path.sep}${pattern}`)) { return true; } // For wildcard patterns, use minimatch if (pattern.includes('*') || pattern.includes('?') || pattern.includes('[')) { // Try to match against the full path if (minimatch(normalizedPath, `**/${pattern}`, { dot: true })) { return true; } // Try to match against just the basename if (minimatch(basename, pattern, { dot: true })) { return true; } } } else { // For patterns with leading slash, they should match from the root of the watched directories const patternWithoutLeadingSlash = pattern.substring(1); for (const watchedDir of this.watchedDirectories) { const fullPattern = path.join(watchedDir, patternWithoutLeadingSlash); if (minimatch(normalizedPath, fullPattern, { dot: true })) { return true; } } } // Handle directory-specific patterns (ending with /) if (isDirectory && pattern.endsWith('/')) { const patternWithoutSlash = pattern.slice(0, -1); if (path.basename(normalizedPath) === patternWithoutSlash) { return true; } } } return false; } }