UNPKG

ids-enterprise-mcp-server

Version:

Model Context Protocol (MCP) server providing comprehensive IDS Enterprise Web Components documentation access via GitLab API. Use with npx and GitLab token for instant access.

298 lines 14.9 kB
/** * Data loading service for components, documentation, and examples */ import { ComponentUtils, FrameworkUtils } from '../utils/index.js'; import { logger } from '../utils/logger.js'; export class DataLoaderService { gitlabService; config; constructor(config, gitlabService) { this.config = config; this.gitlabService = gitlabService; } /** * Load all components from GitLab */ async loadComponents() { const startTime = Date.now(); try { logger.separator('LOADING COMPONENTS FROM GITLAB'); logger.setup('Starting component discovery...'); // Get the components directory tree recursively to find ALL components logger.debug('Fetching components tree from src/components...'); const componentsTree = await this.gitlabService.getTree('src/components', true); logger.debug(`Found ${componentsTree.length} total items in src/components`); // Filter for component directories (those starting with 'ids-') const componentDirs = componentsTree.filter(item => { if (item.type !== 'tree') return false; const pathParts = item.path.split('/'); const dirName = pathParts[pathParts.length - 1]; const isIdsComponent = dirName.startsWith('ids-'); if (isIdsComponent) { logger.trace(`✓ Found component: ${dirName}`); } return isIdsComponent; }); logger.setup(`Found ${componentDirs.length} component directories`); if (componentDirs.length === 0) { logger.warn('⚠️ No component directories found!'); return []; } // Load each component's README with progress tracking const componentPromises = componentDirs.map(async (dir, index) => { try { logger.progress(index + 1, componentDirs.length, dir.name); const readmePath = `${dir.path}/README.md`; const readmeContent = await this.gitlabService.getFileContent(readmePath); if (readmeContent) { const dirName = dir.path.split('/').pop() || dir.name; const componentInfo = ComponentUtils.parseComponentReadme(dirName, readmeContent, this.gitlabService.getGitLabUrl(`${dir.path}/README.md`)); logger.component(`✓ ${dirName}: ${componentInfo.features.length} features, ${componentInfo.attributes.length} attributes, ${componentInfo.examples.length} examples`); return componentInfo; } else { logger.debug(`⚠️ No README for ${dir.name}, using fallback`); } } catch (error) { logger.warn(`❌ Error loading ${dir.name}:`, error instanceof Error ? error.message : String(error)); } // Create fallback component info const dirName = dir.path.split('/').pop() || dir.name; return { name: dirName, category: ComponentUtils.categorizeComponent(dirName), description: `${dirName} component from IDS Enterprise Web Components`, content: `# ${dirName}\n\nThis is a ${dirName} component from the IDS Enterprise Web Components library.\n\nFor detailed documentation, visit: ${this.gitlabService.getGitLabTreeUrl(dir.path)}`, features: [], attributes: [], methods: [], events: [], examples: [], filePath: this.gitlabService.getGitLabTreeUrl(dir.path) }; }); const components = await Promise.all(componentPromises); const validComponents = components.filter(c => c !== null); // Summary statistics const stats = { 'Total Components': validComponents.length, 'Categories': [...new Set(validComponents.map(c => c.category))].length, 'Total Features': validComponents.reduce((sum, c) => sum + c.features.length, 0), 'Total Attributes': validComponents.reduce((sum, c) => sum + c.attributes.length, 0), 'Total Examples': validComponents.reduce((sum, c) => sum + c.examples.length, 0) }; logger.table(stats); logger.performance('Component loading', startTime); logger.setup(`✅ Successfully loaded ${validComponents.length} components`); return validComponents; } catch (error) { logger.error('❌ Failed to load components:', error); throw error; } } /** * Load general documentation from GitLab */ async loadDocumentation() { try { logger.setup('Loading general documentation from GitLab...'); const docFiles = [ 'README.md', 'doc/CHANGELOG.md', 'doc/MIGRATION-GUIDE.md', 'doc/TESTING.md', 'doc/CONTRIBUTING.md', 'doc/DOCUMENTATION.md', 'doc/COMPONENTS.md', 'doc/LINTING.md', 'doc/CHECKLIST.md', 'doc/CUSTOMIZING.md', 'doc/CSP.md', 'doc/ARTICLES.md', 'doc/PUBLISH.md', 'doc/SIDE-BY-SIDE.md' ]; const docPromises = docFiles.map(async (filePath) => { try { const content = await this.gitlabService.getFileContent(filePath); if (content) { const fileName = filePath.split('/').pop()?.replace('.md', '') || filePath; logger.trace(`✓ Loaded doc: ${fileName}`); return { name: fileName, content, category: filePath.startsWith('doc/') ? 'General Documentation' : 'Overview', filePath: this.gitlabService.getGitLabUrl(filePath) }; } } catch (error) { logger.warn(`⚠️ Could not load ${filePath}:`, error instanceof Error ? error.message : String(error)); } return null; }); const docs = await Promise.all(docPromises); const validDocs = docs.filter(d => d !== null); logger.setup(`✅ Loaded ${validDocs.length} documentation files`); return validDocs; } catch (error) { logger.error('❌ Failed to load documentation:', error); throw error; } } /** * Load framework examples from GitLab examples repository */ async loadExamples() { try { logger.separator('LOADING FRAMEWORK EXAMPLES'); logger.setup('Loading examples from GitLab examples repository...'); // Load Angular and React examples from the examples repository const frameworkConfigs = [ { name: 'Angular', path: 'angular-ids-wc/src/app/components', readmePath: 'angular-ids-wc/README.MD' }, { name: 'React', path: 'react-ids-wc/src/examples', readmePath: 'react-ids-wc/README.MD' } ]; const frameworkPromises = frameworkConfigs.map(async (config) => { return await this.loadFrameworkExamples(config.name, config.path, config.readmePath); }); const frameworks = await Promise.all(frameworkPromises); const validFrameworks = frameworks.filter(f => f !== null); // Flatten all examples const examples = validFrameworks.reduce((acc, framework) => { return acc.concat(framework.examples); }, []); const stats = { 'Total Examples': examples.length, 'Frameworks': validFrameworks.length }; validFrameworks.forEach(fw => { stats[`${fw.name} Examples`] = fw.exampleCount; }); logger.table(stats); logger.setup(`✅ Loaded ${examples.length} examples from ${validFrameworks.length} frameworks`); return { frameworks: validFrameworks, examples }; } catch (error) { logger.error('❌ Failed to load examples:', error); return { frameworks: [], examples: [] }; } } /** * Load examples for a specific framework */ async loadFrameworkExamples(frameworkName, examplesPath, readmePath) { const startTime = Date.now(); try { logger.debug(`Loading ${frameworkName} examples from: ${examplesPath}`); // Load framework README from examples repository const readmeContent = await this.gitlabService.getFileContent(readmePath, this.config.examplesProjectId); if (!readmeContent) { logger.warn(`⚠️ No README found for ${frameworkName} at ${readmePath}`); } const framework = { name: frameworkName, description: readmeContent ? FrameworkUtils.extractFrameworkDescription(readmeContent) : `${frameworkName} integration with IDS Web Components`, setupGuide: readmeContent || `Setup guide for ${frameworkName} integration`, exampleCount: 0, examples: [], readmePath: this.gitlabService.getGitLabUrl(readmePath, this.config.examplesProjectId) }; // Get the examples directory tree from examples repository logger.debug(`Fetching tree for: ${examplesPath}`); const examplesTree = await this.gitlabService.getTree(examplesPath, true, this.config.examplesProjectId); logger.debug(`Found ${examplesTree.length} items in ${examplesPath}`); if (examplesTree.length === 0) { logger.warn(`⚠️ No examples found in ${examplesPath}`); return framework; } // Filter for component example files - be more inclusive for examples const exampleFiles = examplesTree.filter(item => { if (item.type !== 'blob') return false; const fileName = item.name.toLowerCase(); const filePath = item.path.toLowerCase(); // Look for component files (TypeScript, JavaScript, HTML, etc.) const hasValidExtension = (fileName.endsWith('.ts') || fileName.endsWith('.tsx') || fileName.endsWith('.js') || fileName.endsWith('.jsx') || fileName.endsWith('.html') || fileName.endsWith('.component.ts') || fileName.endsWith('.component.html') || fileName.endsWith('.scss') || fileName.endsWith('.css') || fileName.endsWith('.vue') || fileName.endsWith('.svelte')); // Exclude certain files that aren't examples const isExcluded = (fileName.includes('test') || fileName.includes('spec') || fileName.includes('.d.ts') || fileName.includes('node_modules') || fileName.includes('dist') || fileName.includes('build') || filePath.includes('node_modules') || filePath.includes('dist') || filePath.includes('build')); // Include files that are likely to be examples const isLikelyExample = (filePath.includes('example') || filePath.includes('component') || filePath.includes('demo') || hasValidExtension); const isValid = hasValidExtension && !isExcluded && isLikelyExample; if (isValid) { logger.trace(`✓ Valid example file: ${item.path}`); } return isValid; }); logger.debug(`Found ${exampleFiles.length} valid example files for ${frameworkName}`); // Load each example file (removed artificial limit) const examplePromises = exampleFiles.map(async (file, index) => { try { if (index % 50 === 0) { logger.progress(index + 1, exampleFiles.length, `${frameworkName} examples`); } const content = await this.gitlabService.getFileContent(file.path, this.config.examplesProjectId); if (content) { const componentName = ComponentUtils.extractComponentNameFromPath(file.path); return { name: `${componentName}-${frameworkName.toLowerCase()}`, framework: frameworkName, description: `${componentName} example in ${frameworkName} (${file.name})`, content: content.substring(0, 2000), // Limit content size filePath: this.gitlabService.getGitLabUrl(file.path, this.config.examplesProjectId), codeExample: content, setupInstructions: `See the ${frameworkName} README for setup instructions: ${framework.readmePath}` }; } } catch (error) { logger.trace(`⚠️ Could not load example file ${file.path}:`, error instanceof Error ? error.message : String(error)); } return null; }); const examples = await Promise.all(examplePromises); framework.examples = examples.filter(ex => ex !== null); framework.exampleCount = framework.examples.length; logger.performance(`${frameworkName} examples loading`, startTime); logger.setup(`✅ Loaded ${framework.exampleCount} examples for ${frameworkName}`); return framework; } catch (error) { logger.error(`❌ Failed to load framework ${frameworkName}:`, error); return null; } } } //# sourceMappingURL=data-loader.js.map