UNPKG

vibe-coder-mcp

Version:

Production-ready MCP server with complete agent integration, multi-transport support, and comprehensive development automation tools for AI-assisted workflows.

367 lines (366 loc) 14.8 kB
import { BaseLanguageHandler } from './base.js'; import { getNodeText } from '../astAnalyzer.js'; import logger from '../../../logger.js'; export class CSharpHandler extends BaseLanguageHandler { getFunctionQueryPatterns() { return [ 'method_declaration', 'constructor_declaration', 'local_function_statement', 'anonymous_method_expression', 'lambda_expression' ]; } getClassQueryPatterns() { return [ 'class_declaration', 'interface_declaration', 'struct_declaration', 'enum_declaration' ]; } getImportQueryPatterns() { return [ 'using_directive' ]; } extractFunctionName(node, sourceCode, _options) { try { if (node.type === 'method_declaration') { const nameNode = node.childForFieldName('name'); if (nameNode) { const name = getNodeText(nameNode, sourceCode); const attributes = this.getMethodAttributes(node, sourceCode); if (attributes.includes('[HttpGet]') || attributes.includes('[HttpPost]') || attributes.includes('[Route]') || attributes.includes('[ApiController]')) { return `api_${name}`; } if (attributes.includes('[Fact]') || attributes.includes('[Theory]') || attributes.includes('[Test]')) { return `test_${name}`; } return name; } } if (node.type === 'constructor_declaration') { const className = this.findClassName(node, sourceCode); return `${className}_Constructor`; } if (node.type === 'local_function_statement') { const nameNode = node.childForFieldName('name'); if (nameNode) { return `local_${getNodeText(nameNode, sourceCode)}`; } } if (node.type === 'anonymous_method_expression') { if (node.parent?.type === 'assignment_expression') { const leftNode = node.parent.childForFieldName('left'); if (leftNode) { return getNodeText(leftNode, sourceCode); } } if (node.parent?.type === 'assignment_expression' && node.parent.parent?.type === 'expression_statement' && node.parent.parent.previousNamedSibling?.type === 'event_field_declaration') { const eventNode = node.parent.parent.previousNamedSibling.childForFieldName('declarator'); if (eventNode) { const eventName = getNodeText(eventNode, sourceCode); return `${eventName}Handler`; } } return 'anonymousMethod'; } if (node.type === 'lambda_expression') { if (node.parent?.type === 'variable_declarator') { const nameNode = node.parent.childForFieldName('name'); if (nameNode) { return getNodeText(nameNode, sourceCode); } } if (node.parent?.type === 'argument' && node.parent.parent?.type === 'argument_list' && node.parent.parent.parent?.type === 'invocation_expression') { const methodNode = node.parent.parent.parent.childForFieldName('name'); if (methodNode) { const methodName = getNodeText(methodNode, sourceCode); if (['Select', 'Where', 'OrderBy', 'GroupBy', 'Join', 'ForEach'].includes(methodName)) { return `linq_${methodName}`; } } } if (node.parent?.type === 'assignment_expression' && node.parent.childForFieldName('left')?.text.includes('+=')) { const leftNode = node.parent.childForFieldName('left'); if (leftNode) { const eventName = getNodeText(leftNode, sourceCode).split('+=')[0].trim(); return `${eventName}Handler`; } } return 'lambda'; } return 'anonymous'; } catch (error) { logger.warn({ err: error, nodeType: node.type }, 'Error extracting C# function name'); return 'anonymous'; } } findClassName(node, sourceCode) { try { let current = node.parent; while (current && current.type !== 'class_declaration') { current = current.parent; } if (current) { const nameNode = current.childForFieldName('name'); if (nameNode) { return getNodeText(nameNode, sourceCode); } } return 'Unknown'; } catch (error) { logger.warn({ err: error, nodeType: node.type }, 'Error finding C# class name'); return 'Unknown'; } } getMethodAttributes(node, sourceCode) { try { const attributes = []; const current = node; let prev = current.previousNamedSibling; while (prev && prev.type === 'attribute_list') { attributes.push(getNodeText(prev, sourceCode)); prev = prev.previousNamedSibling; } return attributes; } catch (error) { logger.warn({ err: error, nodeType: node.type }, 'Error getting C# method attributes'); return []; } } extractClassName(node, sourceCode) { try { if (node.type === 'class_declaration' || node.type === 'interface_declaration' || node.type === 'struct_declaration' || node.type === 'enum_declaration') { const nameNode = node.childForFieldName('name'); if (nameNode) { return getNodeText(nameNode, sourceCode); } } return 'AnonymousClass'; } catch (error) { logger.warn({ err: error, nodeType: node.type }, 'Error extracting C# class name'); return 'AnonymousClass'; } } extractParentClass(node, sourceCode) { try { if (node.type === 'class_declaration') { const baseListNode = node.childForFieldName('base_list'); if (baseListNode) { const baseTypes = baseListNode.descendantsOfType('base_type'); for (const baseType of baseTypes) { const typeNode = baseType.childForFieldName('type'); if (typeNode) { const typeName = getNodeText(typeNode, sourceCode); if (!typeName.startsWith('I') || typeName.length <= 1) { return typeName; } } } } } return undefined; } catch (error) { logger.warn({ err: error, nodeType: node.type }, 'Error extracting C# parent class'); return undefined; } } extractImplementedInterfaces(node, sourceCode) { try { if (node.type === 'class_declaration' || node.type === 'struct_declaration') { const interfaces = []; const baseListNode = node.childForFieldName('base_list'); if (baseListNode) { const baseTypes = baseListNode.descendantsOfType('base_type'); for (const baseType of baseTypes) { const typeNode = baseType.childForFieldName('type'); if (typeNode) { const typeName = getNodeText(typeNode, sourceCode); if (typeName.startsWith('I') && typeName.length > 1) { interfaces.push(typeName); } } } } return interfaces.length > 0 ? interfaces : undefined; } return undefined; } catch (error) { logger.warn({ err: error, nodeType: node.type }, 'Error extracting C# implemented interfaces'); return undefined; } } extractImportPath(node, sourceCode) { try { if (node.type === 'using_directive') { const nameNode = node.childForFieldName('name'); if (nameNode) { return getNodeText(nameNode, sourceCode); } } return 'unknown'; } catch (error) { logger.warn({ err: error, nodeType: node.type }, 'Error extracting C# import path'); return 'unknown'; } } extractImportedItems(node, sourceCode) { try { if (node.type === 'using_directive') { const nameNode = node.childForFieldName('name'); if (nameNode) { const fullPath = getNodeText(nameNode, sourceCode); const parts = fullPath.split('.'); const name = parts[parts.length - 1]; const isStatic = this.isStaticUsing(node, sourceCode); const aliasNode = node.childForFieldName('alias'); const alias = aliasNode ? getNodeText(aliasNode, sourceCode) : undefined; const isGlobal = this.isGlobalUsing(node, sourceCode); return [{ name: alias || name, path: fullPath, alias: alias, isDefault: false, isNamespace: true, nodeText: node.text, isStatic, isGlobal }]; } } return undefined; } catch (error) { logger.warn({ err: error, nodeType: node.type }, 'Error extracting C# imported items'); return undefined; } } isStaticUsing(node, _sourceCode) { try { const staticNode = node.childForFieldName('static'); return staticNode !== null; } catch (error) { logger.warn({ err: error, nodeType: node.type }, 'Error checking if C# using is static'); return false; } } isGlobalUsing(node, _sourceCode) { try { const globalNode = node.childForFieldName('global'); return globalNode !== null; } catch (error) { logger.warn({ err: error, nodeType: node.type }, 'Error checking if C# using is global'); return false; } } extractFunctionComment(node, _sourceCode) { try { let prev = node.previousNamedSibling; while (prev && prev.type !== 'comment') { prev = prev.previousNamedSibling; } if (prev && prev.type === 'comment' && prev.text.startsWith('///')) { return this.parseXmlDocComment(prev.text); } return undefined; } catch (error) { logger.warn({ err: error, nodeType: node.type }, 'Error extracting C# function comment'); return undefined; } } extractClassComment(node, _sourceCode) { try { let prev = node.previousNamedSibling; while (prev && prev.type !== 'comment') { prev = prev.previousNamedSibling; } if (prev && prev.type === 'comment' && prev.text.startsWith('///')) { return this.parseXmlDocComment(prev.text); } return undefined; } catch (error) { logger.warn({ err: error, nodeType: node.type }, 'Error extracting C# class comment'); return undefined; } } parseXmlDocComment(comment) { try { const lines = comment.split('\n') .map(line => line.trim().replace(/^\/\/\/\s*/, '')); const summaryStart = lines.findIndex(line => line.includes('<summary>')); const summaryEnd = lines.findIndex(line => line.includes('</summary>')); if (summaryStart !== -1 && summaryEnd !== -1 && summaryEnd > summaryStart) { const summaryLines = lines.slice(summaryStart + 1, summaryEnd); return summaryLines .map(line => line.trim()) .join(' ') .replace(/<[^>]+>/g, '') .trim(); } return lines .map(line => line.trim()) .join(' ') .replace(/<[^>]+>/g, '') .trim(); } catch (error) { logger.warn({ err: error }, 'Error parsing C# XML documentation comment'); return comment; } } detectFramework(sourceCode) { try { if (sourceCode.includes('Microsoft.AspNetCore') || sourceCode.includes('[ApiController]') || sourceCode.includes('IActionResult')) { return 'aspnetcore'; } if (sourceCode.includes('System.Windows') || sourceCode.includes('Window') || sourceCode.includes('UserControl')) { return 'wpf'; } if (sourceCode.includes('Microsoft.EntityFrameworkCore') || sourceCode.includes('DbContext') || sourceCode.includes('DbSet<')) { return 'entityframework'; } if (sourceCode.includes('Xunit') || sourceCode.includes('[Fact]') || sourceCode.includes('[Theory]')) { return 'xunit'; } return null; } catch (error) { logger.warn({ err: error }, 'Error detecting C# framework'); return null; } } }