UNPKG

galaxy-uniapp-mcp-server

Version:

Galaxy组件库到UniApp组件转换MCP服务器 - 支持跨平台组件转换、兼容性分析和项目集成

940 lines (815 loc) 25.9 kB
#!/usr/bin/env node const fs = require('fs'); const path = require('path'); /** * Galaxy UniApp MCP服务器 * 提供Galaxy组件库到UniApp组件的转换和查询服务 */ class GalaxyUniAppMCPServer { constructor() { this.dataPath = path.join(__dirname, 'data'); this.componentIndex = this.loadComponentIndex(); this.authors = this.loadAuthors(); this.tags = this.loadTags(); this.conversionRules = this.loadConversionRules(); } /** * 加载组件索引 */ loadComponentIndex() { try { const indexPath = path.join(this.dataPath, 'metadata/component-index.json'); return JSON.parse(fs.readFileSync(indexPath, 'utf8')); } catch (error) { console.error('加载组件索引失败:', error.message); return { total: 0, categories: {}, components: [] }; } } /** * 加载作者信息 */ loadAuthors() { try { const authorsPath = path.join(this.dataPath, 'metadata/authors.json'); return JSON.parse(fs.readFileSync(authorsPath, 'utf8')); } catch (error) { console.error('加载作者信息失败:', error.message); return { total: 0, authors: [] }; } } /** * 加载标签信息 */ loadTags() { try { const tagsPath = path.join(this.dataPath, 'metadata/tags.json'); return JSON.parse(fs.readFileSync(tagsPath, 'utf8')); } catch (error) { console.error('加载标签信息失败:', error.message); return { total: 0, tags: [] }; } } /** * 加载转换规则 */ loadConversionRules() { try { const rulesPath = path.join(this.dataPath, 'templates/conversion-rules.json'); return JSON.parse(fs.readFileSync(rulesPath, 'utf8')); } catch (error) { console.error('加载转换规则失败:', error.message); return {}; } } /** * 加载单个组件数据 */ loadComponent(componentId) { try { // 查找组件文件路径 const component = this.componentIndex.components.find(c => c.id === componentId); if (!component) { throw new Error(`组件 ${componentId} 不存在`); } // 构建相对于当前包的文件路径 const relativePath = `components/${component.category}/${componentId}.json`; const componentPath = path.join(this.dataPath, relativePath); const componentData = JSON.parse(fs.readFileSync(componentPath, 'utf8')); return componentData; } catch (error) { console.error(`加载组件 ${componentId} 失败:`, error.message); return null; } } /** * MCP工具: 分析UniApp平台兼容性 */ async analyzeUniappCompatibility(params) { const { component_id, target_platforms = ['H5', 'MP-WEIXIN', 'MP-ALIPAY', 'APP-PLUS'], check_performance = true } = params; const component = this.loadComponent(component_id); if (!component) { return { error: `组件 ${component_id} 不存在` }; } const result = { component_id, component_name: component.name, target_platforms, compatibility: {}, performance_analysis: null, recommendations: [] }; // 分析每个平台的兼容性 target_platforms.forEach(platform => { const platformKey = platform.toLowerCase().replace('-', '_'); const compatibility = component.compatibility[platformKey] || { supported: true, issues: [], alternatives: [] }; result.compatibility[platform] = { supported: compatibility.supported, issues: compatibility.issues || [], alternatives: compatibility.alternatives || [], confidence: this.calculateCompatibilityConfidence(compatibility) }; }); // 性能分析 if (check_performance && component.performance) { result.performance_analysis = { complexity: component.performance.complexity, bundle_size: component.performance.bundle_size, render_cost: component.performance.render_cost, memory_usage: component.performance.memory_usage, optimization_suggestions: this.generateOptimizationSuggestions(component) }; } // 生成建议 result.recommendations = this.generateCompatibilityRecommendations(component, target_platforms); return result; } /** * MCP工具: 转换为UniApp组件 */ async convertToUniappComponent(params) { const { component_id, target_platforms = ['H5', 'MP-WEIXIN', 'MP-ALIPAY', 'APP-PLUS'], design_width = 750, enable_conditions = true, optimize_for_mp = true, component_name, props_config = {} } = params; const component = this.loadComponent(component_id); if (!component) { return { error: `组件 ${component_id} 不存在` }; } const result = { component_id, original_name: component.name, converted_name: component_name || component.uniapp.component_name, target_platforms, uniapp_component: { template: component.uniapp.template, script: this.enhanceVueScript(component, props_config), style: this.optimizeStyleForPlatforms(component.uniapp.style, target_platforms, enable_conditions), component_name: component_name || component.uniapp.component_name }, usage_example: this.generateUsageExample(component, component_name), integration_guide: this.generateIntegrationGuide(component, target_platforms), performance_tips: optimize_for_mp ? this.generatePerformanceTips(component) : [] }; return result; } /** * MCP工具: 搜索UniApp组件 */ async searchUniappComponents(params) { const { query = '', category, author, tags = [], platforms = [], complexity, limit = 10, offset = 0 } = params; let filteredComponents = [...this.componentIndex.components]; // 按查询词过滤 if (query) { const queryLower = query.toLowerCase(); filteredComponents = filteredComponents.filter(comp => comp.name.toLowerCase().includes(queryLower) || comp.id.toLowerCase().includes(queryLower) || comp.author.toLowerCase().includes(queryLower) ); } // 按分类过滤 if (category) { filteredComponents = filteredComponents.filter(comp => comp.category === category); } // 按作者过滤 if (author) { filteredComponents = filteredComponents.filter(comp => comp.author === author); } // 加载详细信息并进一步过滤 const detailedComponents = filteredComponents.map(comp => { const detail = this.loadComponent(comp.id); return detail ? { ...comp, ...detail } : comp; }).filter(Boolean); // 按标签过滤 if (tags.length > 0) { filteredComponents = detailedComponents.filter(comp => tags.some(tag => comp.tags && comp.tags.includes(tag)) ); } // 按平台过滤 if (platforms.length > 0) { filteredComponents = detailedComponents.filter(comp => { if (!comp.platforms) return true; return platforms.every(platform => { const platformKey = platform.toLowerCase().replace('-', '_'); return comp.platforms[platformKey] !== false; }); }); } // 按复杂度过滤 if (complexity) { filteredComponents = detailedComponents.filter(comp => comp.performance && comp.performance.complexity === complexity ); } // 分页 const total = filteredComponents.length; const paginatedComponents = filteredComponents.slice(offset, offset + limit); return { total, limit, offset, components: paginatedComponents.map(comp => ({ id: comp.id, name: comp.name, category: comp.category, author: comp.author, description: comp.description, tags: comp.tags || [], platforms: comp.platforms || {}, performance: comp.performance || {}, preview_url: this.generatePreviewUrl(comp.id) })) }; } /** * MCP工具: 列出可用组件 */ async listAvailableComponents(params) { const { category, author, sort_by = 'name', // name, author, category, created_at, complexity sort_order = 'asc', // asc, desc include_stats = true, include_preview = false, limit = 50, offset = 0 } = params; let components = [...this.componentIndex.components]; // 过滤 if (category) { components = components.filter(comp => comp.category === category); } if (author) { components = components.filter(comp => comp.author === author); } // 加载详细信息 const detailedComponents = components.map(comp => { const detail = this.loadComponent(comp.id); return detail ? { ...comp, ...detail } : comp; }).filter(Boolean); // 排序 detailedComponents.sort((a, b) => { let aValue, bValue; switch (sort_by) { case 'author': aValue = a.author || ''; bValue = b.author || ''; break; case 'category': aValue = a.category || ''; bValue = b.category || ''; break; case 'created_at': aValue = new Date(a.created_at || 0); bValue = new Date(b.created_at || 0); break; case 'complexity': const complexityOrder = { 'low': 1, 'medium': 2, 'high': 3 }; aValue = complexityOrder[a.performance?.complexity] || 0; bValue = complexityOrder[b.performance?.complexity] || 0; break; default: // name aValue = a.name || ''; bValue = b.name || ''; } if (sort_order === 'desc') { return aValue > bValue ? -1 : aValue < bValue ? 1 : 0; } else { return aValue < bValue ? -1 : aValue > bValue ? 1 : 0; } }); // 分页 const total = detailedComponents.length; const paginatedComponents = detailedComponents.slice(offset, offset + limit); const result = { total, limit, offset, components: paginatedComponents.map(comp => ({ id: comp.id, name: comp.name, category: comp.category, author: comp.author, description: comp.description, tags: comp.tags || [], platforms: comp.platforms || {}, performance: comp.performance || {}, created_at: comp.created_at, updated_at: comp.updated_at, preview_url: include_preview ? this.generatePreviewUrl(comp.id) : undefined })) }; // 添加统计信息 if (include_stats) { result.statistics = this.generateComponentStatistics(detailedComponents); } return result; } /** * MCP工具: 获取组件详细信息 */ async getComponentDetails(params) { const { component_id, include_code = false, include_usage = true } = params; const component = this.loadComponent(component_id); if (!component) { return { error: `组件 ${component_id} 不存在` }; } const result = { id: component.id, name: component.name, category: component.category, author: component.author, description: component.description, tags: component.tags || [], platforms: component.platforms || {}, compatibility: component.compatibility || {}, performance: component.performance || {}, props: component.props || [], events: component.events || [], slots: component.slots || [], created_at: component.created_at, updated_at: component.updated_at, preview_url: this.generatePreviewUrl(component.id) }; // 包含代码 if (include_code) { result.original_code = component.original; result.uniapp_code = component.uniapp; } // 包含使用示例 if (include_usage) { result.usage_example = this.generateUsageExample(component); result.integration_guide = this.generateIntegrationGuide(component, ['H5', 'MP-WEIXIN', 'APP-PLUS']); } return result; } /** * MCP工具: 生成UniApp项目集成代码 */ async generateUniappProjectIntegration(params) { const { components = [], project_structure = {}, global_styles = false, auto_import = true } = params; const result = { components_count: components.length, integration_files: {}, configuration: {}, usage_examples: {}, installation_guide: [] }; // 生成pages.json配置 if (auto_import) { result.configuration['pages.json'] = this.generatePagesJsonConfig(components); } // 生成main.js配置 result.configuration['main.js'] = this.generateMainJsConfig(components, auto_import); // 生成全局样式 if (global_styles) { result.configuration['App.vue'] = this.generateGlobalStyles(components); } // 生成组件文件 components.forEach(componentId => { const component = this.loadComponent(componentId); if (component) { const fileName = `${component.uniapp.component_name}.vue`; result.integration_files[fileName] = this.generateCompleteVueComponent(component); result.usage_examples[componentId] = this.generateUsageExample(component); } }); // 生成安装指南 result.installation_guide = this.generateInstallationGuide(components); return result; } /** * 计算兼容性置信度 */ calculateCompatibilityConfidence(compatibility) { if (!compatibility.supported) return 0; const issueCount = compatibility.issues ? compatibility.issues.length : 0; return Math.max(0, 100 - issueCount * 20); } /** * 生成优化建议 */ generateOptimizationSuggestions(component) { const suggestions = []; if (component.performance.complexity === 'high') { suggestions.push('考虑简化动画效果以提升性能'); suggestions.push('使用条件编译为不同平台提供不同的实现'); } if (component.performance.bundle_size > 1000) { suggestions.push('考虑拆分为多个小组件'); suggestions.push('移除不必要的CSS规则'); } return suggestions; } /** * 生成兼容性建议 */ generateCompatibilityRecommendations(component, platforms) { const recommendations = []; platforms.forEach(platform => { const platformKey = platform.toLowerCase().replace('-', '_'); const compatibility = component.compatibility[platformKey]; if (compatibility && compatibility.issues.length > 0) { recommendations.push({ platform, type: 'warning', message: `${platform}平台存在兼容性问题`, details: compatibility.issues, solutions: compatibility.alternatives }); } }); return recommendations; } /** * 增强Vue脚本 */ enhanceVueScript(component, propsConfig) { const props = Array.isArray(component.props) ? component.props : []; const events = Array.isArray(component.events) ? component.events : []; const propsCode = props.length > 0 ? props.map(prop => ` ${prop.name}: { type: ${prop.type}, default: ${JSON.stringify(prop.default)}, required: ${prop.required} }`).join(',\n') : ' // 无props定义'; const methodsCode = events.length > 0 ? events.map(event => ` handle${event.name.charAt(0).toUpperCase() + event.name.slice(1)}(e) { this.$emit('${event.name}', e); }`).join(',\n') : ' // 无事件处理方法'; return `export default { name: '${component.uniapp.component_name}', props: { ${propsCode} }, data() { return { isPressed: false, isLoading: false }; }, methods: { ${methodsCode} } }`; } /** * 优化样式为多平台 */ optimizeStyleForPlatforms(style, platforms, enableConditions) { if (!enableConditions) return style; let optimizedStyle = style; // 为小程序平台添加特殊处理 if (platforms.includes('MP-WEIXIN') || platforms.includes('MP-ALIPAY')) { optimizedStyle = optimizedStyle.replace( /box-shadow:[^;]+;/gi, '/* #ifdef H5 */\n $&\n /* #endif */\n /* #ifdef MP */\n border: 1rpx solid rgba(0,0,0,0.1);\n /* #endif */' ); } return optimizedStyle; } /** * 生成使用示例 */ generateUsageExample(component, customName) { const componentName = customName || component.uniapp.component_name; const kebabName = componentName.replace(/([A-Z])/g, '-$1').toLowerCase().replace(/^-/, ''); const props = component.props || []; const propsExample = props.slice(0, 3).map(prop => ` ${prop.name}="${prop.default}"` ).join('\n'); return `<template> <view class="page"> <${kebabName} ${propsExample} @click="handleClick" /> </view> </template> <script> export default { methods: { handleClick(e) { console.log('组件被点击', e); } } } </script>`; } /** * 生成集成指南 */ generateIntegrationGuide(component, platforms) { return { steps: [ '1. 将组件文件复制到 components 目录', '2. 在 pages.json 中配置 easycom 自动导入', '3. 在页面中直接使用组件', '4. 根据需要自定义组件属性' ], platforms: platforms.map(platform => ({ name: platform, notes: this.getPlatformNotes(platform, component) })), dependencies: component.dependencies || [] }; } /** * 获取平台注意事项 */ getPlatformNotes(platform, component) { const notes = []; const platformKey = platform.toLowerCase().replace('-', '_'); const compatibility = component.compatibility[platformKey]; if (compatibility && compatibility.issues.length > 0) { notes.push(...compatibility.issues); } return notes; } /** * 生成性能提示 */ generatePerformanceTips(component) { const tips = []; if (component.performance.complexity === 'high') { tips.push('建议在小程序中减少动画复杂度'); tips.push('考虑使用 transform 替代 position 变化'); } tips.push('使用 v-if 而不是 v-show 来条件渲染'); tips.push('避免在模板中使用复杂的表达式'); return tips; } /** * 生成预览URL */ generatePreviewUrl(componentId) { return `https://uiverse.io/preview/${componentId}`; } /** * 生成pages.json配置 */ generatePagesJsonConfig(components) { const easycomRules = {}; components.forEach(componentId => { const component = this.loadComponent(componentId); if (component) { const kebabName = component.uniapp.component_name .replace(/([A-Z])/g, '-$1') .toLowerCase() .replace(/^-/, ''); easycomRules[`^${kebabName}$`] = `@/components/${kebabName}/${kebabName}.vue`; } }); return { easycom: { autoscan: true, custom: easycomRules } }; } /** * 生成main.js配置 */ generateMainJsConfig(components, autoImport) { if (autoImport) { return '// 使用 easycom 自动导入,无需手动注册组件'; } const imports = []; const registrations = []; components.forEach(componentId => { const component = this.loadComponent(componentId); if (component) { const componentName = component.uniapp.component_name; const kebabName = componentName.replace(/([A-Z])/g, '-$1').toLowerCase().replace(/^-/, ''); imports.push(`import ${componentName} from '@/components/${kebabName}/${kebabName}.vue'`); registrations.push(`Vue.component('${kebabName}', ${componentName})`); } }); return `${imports.join('\n')} // 全局注册组件 ${registrations.join('\n')}`; } /** * 生成全局样式 */ generateGlobalStyles(components) { return `<style> /* Galaxy组件库全局样式 */ .galaxy-component { box-sizing: border-box; } /* 通用动画 */ .galaxy-transition { transition: all 0.3s ease; } /* 响应式工具类 */ .galaxy-flex { display: flex; } .galaxy-center { align-items: center; justify-content: center; } </style>`; } /** * 生成完整的Vue组件 */ generateCompleteVueComponent(component) { return `<template> ${component.uniapp.template} </template> <script> ${this.enhanceVueScript(component, {})} </script> <style scoped> ${component.uniapp.style} </style>`; } /** * 生成安装指南 */ generateInstallationGuide(components) { return [ '1. 创建 components 目录(如果不存在)', '2. 将组件文件复制到对应的子目录中', '3. 在 pages.json 中配置 easycom 规则', '4. 重启开发服务器', '5. 在页面中直接使用组件标签', `6. 总共集成了 ${components.length} 个组件` ]; } /** * 生成组件统计信息 */ generateComponentStatistics(components) { const stats = { total_components: components.length, categories: {}, authors: {}, tags: {}, complexity_distribution: { low: 0, medium: 0, high: 0, unknown: 0 }, platform_support: { h5: 0, mp_weixin: 0, mp_alipay: 0, mp_baidu: 0, mp_toutiao: 0, app_plus: 0 }, performance_metrics: { avg_bundle_size: 0, total_bundle_size: 0, min_bundle_size: Infinity, max_bundle_size: 0 }, top_authors: [], popular_tags: [], recent_components: [] }; let totalBundleSize = 0; let bundleSizeCount = 0; components.forEach(comp => { // 分类统计 stats.categories[comp.category] = (stats.categories[comp.category] || 0) + 1; // 作者统计 stats.authors[comp.author] = (stats.authors[comp.author] || 0) + 1; // 标签统计 if (comp.tags) { comp.tags.forEach(tag => { stats.tags[tag] = (stats.tags[tag] || 0) + 1; }); } // 复杂度统计 const complexity = comp.performance?.complexity || 'unknown'; stats.complexity_distribution[complexity]++; // 平台支持统计 if (comp.platforms) { Object.entries(comp.platforms).forEach(([platform, supported]) => { if (supported) { const platformKey = platform.replace('-', '_'); if (stats.platform_support.hasOwnProperty(platformKey)) { stats.platform_support[platformKey]++; } } }); } // 性能指标统计 if (comp.performance?.bundle_size) { const bundleSize = comp.performance.bundle_size; totalBundleSize += bundleSize; bundleSizeCount++; stats.performance_metrics.min_bundle_size = Math.min(stats.performance_metrics.min_bundle_size, bundleSize); stats.performance_metrics.max_bundle_size = Math.max(stats.performance_metrics.max_bundle_size, bundleSize); } }); // 计算平均包大小 if (bundleSizeCount > 0) { stats.performance_metrics.avg_bundle_size = Math.round(totalBundleSize / bundleSizeCount); stats.performance_metrics.total_bundle_size = totalBundleSize; } if (stats.performance_metrics.min_bundle_size === Infinity) { stats.performance_metrics.min_bundle_size = 0; } // 热门作者 (前10) stats.top_authors = Object.entries(stats.authors) .sort(([,a], [,b]) => b - a) .slice(0, 10) .map(([author, count]) => ({ author, count })); // 热门标签 (前15) stats.popular_tags = Object.entries(stats.tags) .sort(([,a], [,b]) => b - a) .slice(0, 15) .map(([tag, count]) => ({ tag, count })); // 最近组件 (前5) stats.recent_components = components .filter(comp => comp.created_at) .sort((a, b) => new Date(b.created_at) - new Date(a.created_at)) .slice(0, 5) .map(comp => ({ id: comp.id, name: comp.name, author: comp.author, created_at: comp.created_at })); return stats; } } // MCP服务器主函数 async function main() { const server = new GalaxyUniAppMCPServer(); // 模拟MCP协议处理 process.stdin.on('data', async (data) => { try { const request = JSON.parse(data.toString()); let response; switch (request.method) { case 'analyze_uniapp_compatibility': response = await server.analyzeUniappCompatibility(request.params); break; case 'convert_to_uniapp_component': response = await server.convertToUniappComponent(request.params); break; case 'search_uniapp_components': response = await server.searchUniappComponents(request.params); break; case 'generate_uniapp_project_integration': response = await server.generateUniappProjectIntegration(request.params); break; case 'list_available_components': response = await server.listAvailableComponents(request.params); break; case 'get_component_details': response = await server.getComponentDetails(request.params); break; default: response = { error: `未知方法: ${request.method}` }; } console.log(JSON.stringify({ id: request.id, result: response })); } catch (error) { console.error('处理请求失败:', error.message); } }); console.log('Galaxy UniApp MCP服务器已启动'); } if (require.main === module) { main().catch(console.error); } module.exports = GalaxyUniAppMCPServer;