File Rank MCP Server

by admica
Verified
import * as fs from "fs/promises"; import * as path from "path"; import { FileNode } from "./types.js"; export function normalizePath(filepath: string): string { return filepath.split(path.sep).join('/'); } export function toPlatformPath(normalizedPath: string): string { return normalizedPath.split('/').join(path.sep); } const SUPPORTED_EXTENSIONS = [".py", ".c", ".cpp", ".h", ".rs", ".lua", ".js", ".jsx", ".ts", ".tsx"]; const IMPORT_PATTERNS: { [key: string]: RegExp } = { ".py": /import\s+[\w.]+|from\s+[\w.]+\s+import\s+[\w*]+/g, ".c": /#include\s+["<][^">]+[">]/g, ".cpp": /#include\s+["<][^">]+[">]/g, ".h": /#include\s+["<][^">]+[">]/g, ".rs": /use\s+[\w:]+|mod\s+\w+/g, ".lua": /require\s*\(['"][^'"]+['"]\)/g, ".js": /import\s+.*from\s+['"][^'"]+['"]/g, ".jsx": /import\s+.*from\s+['"][^'"]+['"]/g, ".ts": /import\s+.*from\s+['"][^'"]+['"]/g, ".tsx": /import\s+.*from\s+['"][^'"]+['"]/g, }; export async function scanDirectory(dirPath: string): Promise<FileNode> { const entries = await fs.readdir(dirPath, { withFileTypes: true }); const normalizedDirPath = normalizePath(dirPath); const node: FileNode = { path: normalizedDirPath, name: path.basename(dirPath), isDirectory: true, children: [], }; for (const entry of entries) { const fullPath = path.join(dirPath, entry.name); const normalizedFullPath = normalizePath(fullPath); const childNode: FileNode = { path: normalizedFullPath, name: entry.name, isDirectory: entry.isDirectory(), }; if (entry.isDirectory()) { if (!fullPath.includes("node_modules") && !fullPath.includes(".git")) { childNode.children = (await scanDirectory(fullPath)).children; } } else if (SUPPORTED_EXTENSIONS.includes(path.extname(entry.name))) { try { const content = await fs.readFile(fullPath, "utf-8"); const ext = path.extname(entry.name); const matches = content.match(IMPORT_PATTERNS[ext]) || []; childNode.dependencies = await Promise.all( matches .map(match => { const importPath = match.match(/['"]([^'"]+)['"]/)?.[1] || match.split(/\s+/)[1]; const resolvedPath = path.resolve(dirPath, importPath + (ext === ".py" ? ".py" : "")); return normalizePath(resolvedPath); }) .map(async dep => { try { await fs.access(toPlatformPath(dep)); return dep; } catch { return null; } }) ).then(results => results.filter(dep => dep !== null) as string[]); } catch (e) { console.warn(`Failed to read ${fullPath}: ${e}`); } } node.children!.push(childNode); } return node; } export function calculateImportance(node: FileNode) { if (!node.isDirectory && node.dependencies) { const depCount = node.dependencies.length; node.importance = Math.min(10, Math.max(0, Math.floor(depCount / 2))); } if (node.children) { node.children.forEach(calculateImportance); } }