UNPKG

@xiaohui-wang/mcpadvisor

Version:

MCP Advisor & Installation - Find the right MCP server for your needs

120 lines (119 loc) 4.23 kB
import { InstallationContentType } from '../types/InstallationGuideTypes.js'; /** * Traditional installation extractor * Specialized in extracting traditional installation sections from README content */ export class TraditionalInstallationExtractor { installationKeywords = [ 'installation', '安装', 'setup', '设置', 'getting started', '开始', 'quick start', '快速开始', 'install', 'how to install', '如何安装', 'usage', '使用', 'running', '运行' ]; /** * Extract traditional installation section from README content * @param readmeContent - README content to extract from * @returns Installation section data or null if not found */ extractInstallationSection(readmeContent) { const headings = this.extractHeadings(readmeContent); console.log('找到的所有标题:', headings); let bestScore = 0; let bestMatch = null; // Score each heading based on installation keywords for (const heading of headings) { const lowerHeading = heading.toLowerCase(); let score = 0; for (const keyword of this.installationKeywords) { if (lowerHeading.includes(keyword)) { // Exact match gets higher score if (lowerHeading === `## ${keyword}` || lowerHeading === `# ${keyword}`) { score += 10; } else { score += 5; } } } if (score > bestScore) { bestScore = score; bestMatch = { heading, index: readmeContent.indexOf(heading), }; } } if (bestMatch) { console.log('最佳匹配标题:', bestMatch.heading); const content = this.extractSectionContent(readmeContent, bestMatch.heading, bestMatch.index); return { content, type: InstallationContentType.TRADITIONAL_INSTALLATION, hasJsonConfig: false, mcpKeywords: [], }; } return null; } /** * Check if this extractor can handle the given content * @param readmeContent - README content to check * @returns True if this extractor can handle the content */ canHandle(readmeContent) { // This extractor can handle any content as a fallback return true; } /** * Get the priority of this extractor (higher number = higher priority) * @returns Priority number */ getPriority() { return 10; // Low priority as fallback } /** * Extract headings from README content * @param content - README content * @returns Array of headings */ extractHeadings(content) { const headingRegex = /^(#{1,6})\s+(.+)$/gm; const headings = []; let match; while ((match = headingRegex.exec(content)) !== null) { headings.push(match[0].trim()); } return headings; } /** * Extract section content under a specific heading * @param content - Full content * @param heading - Target heading * @param headingIndex - Index of the heading * @returns Section content */ extractSectionContent(content, heading, headingIndex) { const headingLevel = (heading.match(/^#+/) || [''])[0].length; const afterHeading = content.substring(headingIndex + heading.length); // Find the next heading of the same or higher level const nextHeadingRegex = new RegExp(`^#{1,${headingLevel}}\\s+`, 'm'); const nextHeadingMatch = afterHeading.match(nextHeadingRegex); if (nextHeadingMatch) { const nextHeadingIndex = afterHeading.indexOf(nextHeadingMatch[0]); return (heading + afterHeading.substring(0, nextHeadingIndex)).trim(); } // If no next heading found, take the rest of the content return (heading + afterHeading).trim(); } }