Skip to main content
Glama

CodeCompass MCP

refactor.ts•35.7 kB
import { RefactorResult, RefactorOptions, ExtractableComponent, ReusableUtility, GeneratedTemplate, ComponentLibrary } from '../types/index.js'; import { GitHubService } from './github.js'; export class RefactorService { private githubService: GitHubService; constructor() { this.githubService = new GitHubService(); } async extractFunctions(url: string, filePath: string, functionNames?: string[]): Promise<{ functions: any[], dependencies: string[] }> { const content = await this.githubService.getFileContent(url, filePath); const functions = this.parseFunctions(content, functionNames); const dependencies = this.extractDependencies(content); return { functions, dependencies, }; } async analyzeDependencies(url: string): Promise<any> { const repositoryInfo = await this.githubService.getRepositoryInfo(url); const dependencies = await this.githubService.analyzeDependencies(url); return { external: dependencies, internal: this.analyzeInternalDependencies(repositoryInfo.keyFiles), graph: this.buildDependencyGraph(repositoryInfo.keyFiles), }; } async refactorForProject(url: string, targetProject: any, refactorOptions: RefactorOptions): Promise<RefactorResult> { const repositoryInfo = await this.githubService.getRepositoryInfo(url); const keyFiles = repositoryInfo.keyFiles; let refactoredCode = ''; const changes: any[] = []; const warnings: string[] = []; const dependencies: string[] = []; const instructions: string[] = []; // Process each file for (const [filePath, content] of Object.entries(keyFiles)) { let processedContent = content; // Apply naming convention transformation if (refactorOptions.namingConvention) { const result = await this.transformNamingConvention( processedContent, refactorOptions.namingConvention ); processedContent = result.code; changes.push(...result.changes); } // Modernize code if requested if (refactorOptions.modernizationLevel && refactorOptions.modernizationLevel !== 'minimal') { const result = await this.modernizeCode( processedContent, this.detectLanguage(filePath), refactorOptions.modernizationLevel ); processedContent = result.refactoredCode; changes.push(...result.changes); } // Remove project-specific coupling if (refactorOptions.removeProjectSpecific) { const result = await this.removeProjectCoupling( processedContent, this.detectLanguage(filePath) ); processedContent = result.refactoredCode; changes.push(...result.changes); } // Add TypeScript if requested if (refactorOptions.addTypeScript && this.isJavaScriptFile(filePath)) { const result = await this.addTypeScript(processedContent, filePath); processedContent = result.code; changes.push(...result.changes); } refactoredCode += `\n\n// === ${filePath} ===\n${processedContent}`; } // Generate integration instructions instructions.push('1. Review the refactored code for compatibility with your project'); instructions.push('2. Update import paths to match your project structure'); instructions.push('3. Install any required dependencies'); instructions.push('4. Run tests to ensure functionality is preserved'); if (refactorOptions.extractComponents) { instructions.push('5. Consider extracting reusable components into separate files'); } return { originalCode: Object.values(keyFiles).join('\n\n'), refactoredCode, changes, warnings, dependencies, instructions, }; } async extractReusableComponents(url: string, componentTypes?: string[]): Promise<ExtractableComponent[]> { const repositoryInfo = await this.githubService.getRepositoryInfo(url); const components: ExtractableComponent[] = []; for (const [filePath, content] of Object.entries(repositoryInfo.keyFiles)) { if (this.isComponentFile(filePath, content)) { const component = await this.analyzeComponent(filePath, content); if (!componentTypes || componentTypes.includes(component.type)) { components.push(component); } } } return components.sort((a, b) => b.reusabilityScore - a.reusabilityScore); } async adaptDependencies(code: string, dependencyMappings: Record<string, string>): Promise<string> { let adaptedCode = code; // Replace import statements for (const [oldDep, newDep] of Object.entries(dependencyMappings)) { const importRegex = new RegExp(`from\\s+['"]${oldDep}['"]`, 'g'); adaptedCode = adaptedCode.replace(importRegex, `from '${newDep}'`); const requireRegex = new RegExp(`require\\(['"]${oldDep}['"]\\)`, 'g'); adaptedCode = adaptedCode.replace(requireRegex, `require('${newDep}')`); } return adaptedCode; } async transformNamingConventions(code: string, fromConvention: string, toConvention: string): Promise<string> { const { code: transformedCode } = await this.transformNamingConvention(code, { variables: toConvention as any, functions: toConvention as any, classes: toConvention as any, files: toConvention as any, folders: toConvention as any, }); return transformedCode; } async modernizeCode(code: string, language: string, targetVersion?: string): Promise<RefactorResult> { const changes: any[] = []; let modernizedCode = code; if (language === 'javascript' || language === 'typescript') { // Convert var to const/let const varMatches = code.match(/var\s+(\w+)/g); if (varMatches) { modernizedCode = modernizedCode.replace(/var\s+(\w+)/g, 'const $1'); changes.push({ type: 'modify', file: 'current', description: 'Replaced var with const/let', oldValue: 'var', newValue: 'const/let', }); } // Convert function declarations to arrow functions where appropriate const functionRegex = /function\s+(\w+)\s*\(([^)]*)\)\s*\{/g; modernizedCode = modernizedCode.replace(functionRegex, 'const $1 = ($2) => {'); // Use template literals instead of string concatenation const concatRegex = /['"]([^'"]*)['"]\s*\+\s*(\w+)\s*\+\s*['"]([^'"]*)['"]/g; modernizedCode = modernizedCode.replace(concatRegex, '`$1${$2}$3`'); // Convert promises to async/await if possible if (modernizedCode.includes('.then(') && !modernizedCode.includes('async ')) { changes.push({ type: 'modify', file: 'current', description: 'Consider converting promises to async/await', }); } } return { originalCode: code, refactoredCode: modernizedCode, changes, warnings: [], dependencies: [], instructions: ['Review modernized code for compatibility'], }; } async removeProjectCoupling(code: string, language: string): Promise<RefactorResult> { let decoupledCode = code; const changes: any[] = []; // Remove hard-coded URLs and endpoints const urlRegex = /https?:\/\/[^\s'"]+/g; const urls = code.match(urlRegex); if (urls) { for (const url of urls) { decoupledCode = decoupledCode.replace(url, '${API_BASE_URL}/endpoint'); changes.push({ type: 'modify', file: 'current', description: `Parameterized hard-coded URL: ${url}`, oldValue: url, newValue: '${API_BASE_URL}/endpoint', }); } } // Remove environment-specific imports const envImports = [ 'process.env', 'window.', 'document.', 'localStorage.', 'sessionStorage.', ]; for (const envImport of envImports) { if (decoupledCode.includes(envImport)) { changes.push({ type: 'modify', file: 'current', description: `Environment-specific code found: ${envImport}`, }); } } // Replace hard-coded values with configuration const configValues = this.extractConfigurableValues(code); for (const value of configValues) { decoupledCode = decoupledCode.replace(value.pattern, value.replacement); changes.push({ type: 'modify', file: 'current', description: `Made configurable: ${value.description}`, oldValue: value.pattern, newValue: value.replacement, }); } return { originalCode: code, refactoredCode: decoupledCode, changes, warnings: [], dependencies: [], instructions: [ 'Create a configuration file for parameterized values', 'Set up environment-specific configuration', 'Test with different configurations', ], }; } async generateBoilerplate(url: string, templateType: string, options: any): Promise<GeneratedTemplate> { const repositoryInfo = await this.githubService.getRepositoryInfo(url); const analysis = await this.githubService.analyzeRepository(url); const template: GeneratedTemplate = { name: options.name || `${repositoryInfo.name}-template`, description: options.description || `Template based on ${repositoryInfo.name}`, files: [], dependencies: [], scripts: {}, instructions: [], }; // Generate package.json const packageJson = await this.generatePackageJson(repositoryInfo, options); template.files.push({ path: 'package.json', content: JSON.stringify(packageJson, null, 2), type: 'config', }); // Generate main files based on template type switch (templateType) { case 'starter': template.files.push(...await this.generateStarterFiles(repositoryInfo, options)); break; case 'component-library': template.files.push(...await this.generateComponentLibraryFiles(repositoryInfo, options)); break; case 'microservice': template.files.push(...await this.generateMicroserviceFiles(repositoryInfo, options)); break; } // Generate configuration files if (options.includeConfig) { template.files.push(...await this.generateConfigFiles(repositoryInfo, options)); } // Generate test files if (options.includeTests) { template.files.push(...await this.generateTestFiles(repositoryInfo, options)); } // Generate documentation if (options.includeDocs) { template.files.push(...await this.generateDocumentationFiles(repositoryInfo, options)); } return template; } async createComponentLibrary(url: string, componentPaths?: string[]): Promise<ComponentLibrary> { const repositoryInfo = await this.githubService.getRepositoryInfo(url); const components = await this.extractReusableComponents(url, ['ui-components']); const library: ComponentLibrary = { name: `${repositoryInfo.name}-components`, description: `Component library extracted from ${repositoryInfo.name}`, components: [], utilities: [], types: [], styles: [], documentation: '', packageJson: {}, }; // Process components for (const component of components) { if (!componentPaths || componentPaths.includes(component.path)) { const libraryComponent = await this.convertToLibraryComponent(component); library.components.push(libraryComponent); } } // Extract utilities const utilities = await this.extractReusableUtilities(url); library.utilities = utilities.map(util => ({ ...util, documentation: util.description, functions: util.functions.map(func => ({ name: func, parameters: [], returnType: 'any', description: 'Function extracted from code', examples: [] })) })); // Generate package.json for the library library.packageJson = await this.generateLibraryPackageJson(repositoryInfo); return library; } async scaffoldProjectStructure(url: string, projectType: string): Promise<any> { const repositoryInfo = await this.githubService.getRepositoryInfo(url); const analysis = await this.githubService.analyzeRepository(url); const structure = { name: `${repositoryInfo.name}-scaffold`, type: projectType, folders: this.generateFolderStructure(projectType, analysis), files: this.generateScaffoldFiles(projectType, repositoryInfo), scripts: this.generateScripts(projectType, repositoryInfo), dependencies: this.extractRelevantDependencies(analysis.dependencies), }; return structure; } // Helper methods private parseFunctions(content: string, functionNames?: string[]): any[] { const functions: any[] = []; const functionRegex = /(?:function\s+(\w+)|const\s+(\w+)\s*=\s*(?:async\s+)?(?:\([^)]*\)\s*=>|\([^)]*\)\s*\{|function))/g; let match; while ((match = functionRegex.exec(content)) !== null) { const functionName = match[1] || match[2]; if (functionName && (!functionNames || functionNames.includes(functionName))) { const functionInfo = this.extractFunctionInfo(content, functionName, match.index); functions.push(functionInfo); } } return functions; } private extractFunctionInfo(content: string, name: string, startIndex: number): any { // Find function body const lines = content.split('\n'); let currentLine = 0; let currentIndex = 0; while (currentIndex < startIndex) { currentIndex = content.indexOf('\n', currentIndex) + 1; currentLine++; } // Extract function signature and body const functionStart = content.indexOf('{', startIndex); const functionEnd = this.findMatchingBrace(content, functionStart); return { name, signature: content.substring(startIndex, functionStart).trim(), body: content.substring(functionStart + 1, functionEnd).trim(), startLine: currentLine, endLine: currentLine + content.substring(functionStart, functionEnd).split('\n').length, }; } private findMatchingBrace(content: string, start: number): number { let braceCount = 1; let index = start + 1; while (index < content.length && braceCount > 0) { if (content[index] === '{') braceCount++; else if (content[index] === '}') braceCount--; index++; } return index - 1; } private extractDependencies(content: string): string[] { const dependencies: string[] = []; const importRegex = /import\s+.*?\s+from\s+['"]([^'"]+)['"]/g; const requireRegex = /require\(['"]([^'"]+)['"]\)/g; let match; while ((match = importRegex.exec(content)) !== null) { dependencies.push(match[1]); } while ((match = requireRegex.exec(content)) !== null) { dependencies.push(match[1]); } return [...new Set(dependencies)]; } private analyzeInternalDependencies(keyFiles: Record<string, string>): any { const dependencies: Record<string, string[]> = {}; for (const [filePath, content] of Object.entries(keyFiles)) { const fileDeps = this.extractDependencies(content); dependencies[filePath] = fileDeps.filter(dep => dep.startsWith('.')); } return dependencies; } private buildDependencyGraph(keyFiles: Record<string, string>): any { const graph: Record<string, string[]> = {}; const internalDeps = this.analyzeInternalDependencies(keyFiles); for (const [file, deps] of Object.entries(internalDeps)) { graph[file] = deps as string[]; } return graph; } private async transformNamingConvention(code: string, convention: any): Promise<{ code: string; changes: any[] }> { const changes: any[] = []; let transformedCode = code; // Variable naming const variableRegex = /(?:let|const|var)\s+(\w+)/g; transformedCode = transformedCode.replace(variableRegex, (match, varName) => { const newName = this.convertNamingConvention(varName, convention.variables); if (newName !== varName) { changes.push({ type: 'modify', description: `Renamed variable ${varName} to ${newName}`, oldValue: varName, newValue: newName, }); } return match.replace(varName, newName); }); // Function naming const functionRegex = /function\s+(\w+)/g; transformedCode = transformedCode.replace(functionRegex, (match, funcName) => { const newName = this.convertNamingConvention(funcName, convention.functions); if (newName !== funcName) { changes.push({ type: 'modify', description: `Renamed function ${funcName} to ${newName}`, oldValue: funcName, newValue: newName, }); } return match.replace(funcName, newName); }); return { code: transformedCode, changes }; } private convertNamingConvention(name: string, targetConvention: string): string { switch (targetConvention) { case 'camelCase': return name.replace(/_([a-z])/g, (_, letter) => letter.toUpperCase()); case 'snake_case': return name.replace(/([A-Z])/g, '_$1').toLowerCase(); case 'kebab-case': return name.replace(/([A-Z])/g, '-$1').toLowerCase(); case 'PascalCase': return name.charAt(0).toUpperCase() + name.slice(1); default: return name; } } private detectLanguage(filePath: string): string { const ext = filePath.split('.').pop()?.toLowerCase(); switch (ext) { case 'js': case 'jsx': return 'javascript'; case 'ts': case 'tsx': return 'typescript'; case 'py': return 'python'; case 'java': return 'java'; case 'cpp': case 'cc': case 'c': return 'cpp'; case 'go': return 'go'; case 'rs': return 'rust'; default: return 'unknown'; } } private isJavaScriptFile(filePath: string): boolean { return /\.(js|jsx)$/.test(filePath); } private async addTypeScript(code: string, filePath: string): Promise<{ code: string; changes: any[] }> { const changes: any[] = []; let tsCode = code; // Add basic type annotations tsCode = tsCode.replace(/function\s+(\w+)\s*\(([^)]*)\)/g, (match, funcName, params) => { const typedParams = params.replace(/(\w+)/g, '$1: any'); changes.push({ type: 'modify', description: `Added TypeScript types to function ${funcName}`, }); return `function ${funcName}(${typedParams}): any`; }); // Add interface definitions for objects const objectRegex = /const\s+(\w+)\s*=\s*\{([^}]+)\}/g; tsCode = tsCode.replace(objectRegex, (match, objName, objContent) => { changes.push({ type: 'add', description: `Added interface for object ${objName}`, }); return `interface ${objName}Interface {\n // Add properties here\n}\n\n${match}: ${objName}Interface`; }); return { code: tsCode, changes }; } private isComponentFile(filePath: string, content: string): boolean { return ( filePath.includes('component') || filePath.includes('Component') || content.includes('export default') || content.includes('React.Component') || content.includes('function Component') ); } private async analyzeComponent(filePath: string, content: string): Promise<ExtractableComponent> { const name = this.extractComponentName(filePath); const dependencies = this.extractDependencies(content); const complexity = this.calculateComplexity(content); const reusabilityScore = this.calculateReusabilityScore(content); return { name, path: filePath, type: this.determineComponentType(content), dependencies, complexity, reusabilityScore, description: this.extractDescription(content), }; } private extractComponentName(filePath: string): string { const parts = filePath.split('/'); const fileName = parts[parts.length - 1]; return fileName.replace(/\.(js|ts|jsx|tsx)$/, ''); } private determineComponentType(content: string): 'component' | 'hook' | 'utility' | 'service' | 'model' { if (content.includes('React.Component') || content.includes('extends Component')) { return 'component'; } else if (content.includes('useState') || content.includes('useEffect')) { return 'hook'; } else if (content.includes('export function') || content.includes('export const')) { return 'utility'; } else if (content.includes('class') && content.includes('constructor')) { return 'service'; } else if (content.includes('interface') || content.includes('type ')) { return 'model'; } return 'utility'; } private calculateComplexity(content: string): number { const complexityPatterns = [ { pattern: /\bif\b/g, type: 'if' }, { pattern: /\belse\b/g, type: 'else' }, { pattern: /\bfor\b/g, type: 'for' }, { pattern: /\bwhile\b/g, type: 'while' }, { pattern: /\bswitch\b/g, type: 'switch' }, { pattern: /\bcase\b/g, type: 'case' }, { pattern: /\bcatch\b/g, type: 'catch' }, { pattern: /\bthrow\b/g, type: 'throw' }, { pattern: /&&/g, type: '&&' }, { pattern: /\|\|/g, type: '||' }, { pattern: /\?/g, type: '?' }, { pattern: /:/g, type: ':' }, { pattern: /\bfunction\b/g, type: 'function' }, { pattern: /\bclass\b/g, type: 'class' } ]; let complexity = 1; for (const { pattern } of complexityPatterns) { try { const matches = content.match(pattern); if (matches) { complexity += matches.length; } } catch (error) { // Skip invalid patterns } } return complexity; } private calculateReusabilityScore(content: string): number { let score = 50; // Increase score for pure functions if (content.includes('export') && !content.includes('import')) { score += 20; } // Increase score for TypeScript if (content.includes('interface') || content.includes('type ')) { score += 15; } // Increase score for documentation if (content.includes('/**') || content.includes('//')) { score += 10; } // Decrease score for framework-specific code if (content.includes('React') || content.includes('Vue') || content.includes('Angular')) { score -= 10; } // Decrease score for external dependencies const dependencies = this.extractDependencies(content); score -= dependencies.length * 2; return Math.max(0, Math.min(100, score)); } private extractDescription(content: string): string { const jsdocMatch = content.match(/\/\*\*\s*\n\s*\*\s*([^*]+)/); if (jsdocMatch) { return jsdocMatch[1].trim(); } const commentMatch = content.match(/\/\/\s*(.+)/); if (commentMatch) { return commentMatch[1].trim(); } return 'No description available'; } private extractConfigurableValues(code: string): any[] { const configurableValues: any[] = []; // Hard-coded strings that might be configurable const stringRegex = /['"]([^'"]{10,})['"](?!\s*:)/g; let match; while ((match = stringRegex.exec(code)) !== null) { const value = match[1]; if (this.isLikelyConfigurable(value)) { configurableValues.push({ pattern: match[0], replacement: '${CONFIG.' + this.toConfigKey(value) + '}', description: value.substring(0, 30) + '...', }); } } return configurableValues; } private isLikelyConfigurable(value: string): boolean { return ( value.includes('api') || value.includes('endpoint') || value.includes('url') || value.includes('key') || value.includes('secret') || value.includes('token') || value.length > 20 ); } private toConfigKey(value: string): string { return value .replace(/[^a-zA-Z0-9]/g, '_') .toUpperCase() .substring(0, 20); } private async generatePackageJson(repositoryInfo: any, options: any): Promise<any> { const originalDeps = repositoryInfo.dependencies || []; return { name: options.name || repositoryInfo.name, version: '1.0.0', description: options.description || repositoryInfo.description, main: 'index.js', scripts: { start: 'node index.js', dev: 'nodemon index.js', test: 'jest', build: 'webpack --mode production', }, dependencies: originalDeps.filter((dep: any) => dep.type === 'dependency'), devDependencies: originalDeps.filter((dep: any) => dep.type === 'devDependency'), }; } private async generateStarterFiles(repositoryInfo: any, options: any): Promise<any[]> { const files: any[] = []; // Generate main entry file files.push({ path: 'index.js', content: `// Main entry point for ${options.name || repositoryInfo.name} console.log('Starting ${options.name || repositoryInfo.name}...'); // Add your application logic here `, type: 'source', }); return files; } private async generateComponentLibraryFiles(repositoryInfo: any, options: any): Promise<any[]> { const files: any[] = []; // Generate index file files.push({ path: 'src/index.js', content: `// Component library entry point export { default as Button } from './components/Button'; export { default as Input } from './components/Input'; // Add more component exports here `, type: 'source', }); return files; } private async generateMicroserviceFiles(repositoryInfo: any, options: any): Promise<any[]> { const files: any[] = []; // Generate main service file files.push({ path: 'src/server.js', content: `// Microservice entry point const express = require('express'); const app = express(); app.use(express.json()); app.get('/health', (req, res) => { res.json({ status: 'healthy' }); }); const PORT = process.env.PORT || 3000; app.listen(PORT, () => { console.log(\`Server running on port \${PORT}\`); }); `, type: 'source', }); return files; } private async generateConfigFiles(repositoryInfo: any, options: any): Promise<any[]> { const files: any[] = []; // Generate .env template files.push({ path: '.env.example', content: `# Environment variables template NODE_ENV=development PORT=3000 API_URL=http://localhost:3000 `, type: 'config', }); return files; } private async generateTestFiles(repositoryInfo: any, options: any): Promise<any[]> { const files: any[] = []; // Generate test file files.push({ path: 'tests/index.test.js', content: `// Test file for ${options.name || repositoryInfo.name} describe('${options.name || repositoryInfo.name}', () => { test('should work correctly', () => { expect(true).toBe(true); }); }); `, type: 'test', }); return files; } private async generateDocumentationFiles(repositoryInfo: any, options: any): Promise<any[]> { const files: any[] = []; // Generate README files.push({ path: 'README.md', content: `# ${options.name || repositoryInfo.name} ${options.description || repositoryInfo.description || 'Generated template'} ## Installation \`\`\`bash npm install \`\`\` ## Usage \`\`\`bash npm start \`\`\` ## Documentation Add your documentation here. `, type: 'documentation', }); return files; } private async convertToLibraryComponent(component: ExtractableComponent): Promise<any> { return { name: component.name, path: component.path, props: [], // Extract props from component examples: [], // Generate examples documentation: component.description, dependencies: component.dependencies, }; } private async extractReusableUtilities(url: string): Promise<ReusableUtility[]> { const repositoryInfo = await this.githubService.getRepositoryInfo(url); const utilities: ReusableUtility[] = []; for (const [filePath, content] of Object.entries(repositoryInfo.keyFiles)) { if (this.isUtilityFile(filePath, content)) { const utility = await this.analyzeUtility(filePath, content); utilities.push(utility); } } return utilities; } private isUtilityFile(filePath: string, content: string): boolean { return ( filePath.includes('util') || filePath.includes('helper') || filePath.includes('lib') || content.includes('export function') || content.includes('export const') ); } private async analyzeUtility(filePath: string, content: string): Promise<ReusableUtility> { const name = this.extractUtilityName(filePath); const functions = this.extractFunctionNames(content); const dependencies = this.extractDependencies(content); const description = this.extractDescription(content); return { name, path: filePath, functions, description, dependencies, }; } private extractUtilityName(filePath: string): string { const parts = filePath.split('/'); const fileName = parts[parts.length - 1]; return fileName.replace(/\.(js|ts)$/, ''); } private extractFunctionNames(content: string): string[] { const functions: string[] = []; const functionRegex = /function\s+(\w+)|const\s+(\w+)\s*=\s*\(|(\w+)\s*:\s*\(/g; let match; while ((match = functionRegex.exec(content)) !== null) { const functionName = match[1] || match[2] || match[3]; if (functionName) { functions.push(functionName); } } return functions; } private async generateLibraryPackageJson(repositoryInfo: any): Promise<any> { return { name: `${repositoryInfo.name}-components`, version: '1.0.0', description: `Component library extracted from ${repositoryInfo.name}`, main: 'dist/index.js', module: 'dist/index.esm.js', types: 'dist/index.d.ts', scripts: { build: 'rollup -c', dev: 'rollup -c -w', test: 'jest', storybook: 'start-storybook -p 6006', }, peerDependencies: { react: '^16.8.0 || ^17.0.0 || ^18.0.0', 'react-dom': '^16.8.0 || ^17.0.0 || ^18.0.0', }, devDependencies: { '@rollup/plugin-babel': '^5.3.0', '@rollup/plugin-commonjs': '^22.0.0', '@rollup/plugin-node-resolve': '^13.3.0', rollup: '^2.75.0', jest: '^28.0.0', '@storybook/react': '^6.5.0', }, }; } private generateFolderStructure(projectType: string, analysis: any): any { const baseStructure = { src: 'Source code', tests: 'Test files', docs: 'Documentation', config: 'Configuration files', }; switch (projectType) { case 'web-app': return { ...baseStructure, components: 'React components', pages: 'Page components', hooks: 'Custom hooks', utils: 'Utility functions', }; case 'api': return { ...baseStructure, routes: 'API routes', controllers: 'Route controllers', models: 'Data models', middleware: 'Express middleware', }; case 'library': return { ...baseStructure, lib: 'Library source code', examples: 'Usage examples', types: 'TypeScript definitions', }; default: return baseStructure; } } private generateScaffoldFiles(projectType: string, repositoryInfo: any): any[] { const files: any[] = []; // Generate based on project type switch (projectType) { case 'web-app': files.push({ path: 'src/App.jsx', content: 'import React from "react";\n\nfunction App() {\n return <div>Hello World</div>;\n}\n\nexport default App;', type: 'source', }); break; case 'api': files.push({ path: 'src/server.js', content: 'const express = require("express");\nconst app = express();\n\napp.get("/", (req, res) => {\n res.json({ message: "Hello World" });\n});\n\napp.listen(3000);', type: 'source', }); break; } return files; } private generateScripts(projectType: string, repositoryInfo: any): any { const baseScripts = { test: 'jest', lint: 'eslint src/', }; switch (projectType) { case 'web-app': return { ...baseScripts, start: 'react-scripts start', build: 'react-scripts build', dev: 'react-scripts start', }; case 'api': return { ...baseScripts, start: 'node src/server.js', dev: 'nodemon src/server.js', }; default: return baseScripts; } } private extractRelevantDependencies(dependencies: any[]): string[] { return dependencies .filter(dep => dep.type === 'dependency') .map(dep => dep.name); } // Additional methods for MCP tool handlers async transformCode(code: string, transformations: any[], language: string, target_language?: string, options: any = {}): Promise<any> { let transformedCode = code; const changes = []; const warnings = []; for (const transformation of transformations) { switch (transformation.type) { case 'naming': const namingResult = await this.transformNamingConvention(transformedCode, transformation.options); transformedCode = namingResult.code; changes.push(...namingResult.changes); break; case 'modernize': const modernizeResult = await this.modernizeCode(transformedCode, language); transformedCode = modernizeResult.refactoredCode; changes.push(...modernizeResult.changes); break; case 'performance': warnings.push('Performance optimization not implemented'); break; case 'security': warnings.push('Security transformation not implemented'); break; } } return { originalCode: code, transformedCode, changes, warnings, instructions: ['Review transformed code for correctness'], }; } async adaptCodeStructure(url: string, target_structure: any, options: any = {}): Promise<any> { const repositoryInfo = await this.githubService.getRepositoryInfo(url); const adaptedStructure: any = { name: `${repositoryInfo.name}-adapted`, structure: target_structure, files: [], changes: [], instructions: [], }; // Generate adapted structure based on target framework if (target_structure.framework === 'react') { adaptedStructure.files.push({ path: 'src/App.jsx', content: 'import React from "react";\n\nfunction App() {\n return <div>Hello World</div>;\n}\n\nexport default App;', }); } return adaptedStructure; } }

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/TheAlchemist6/codecompass-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server