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.

346 lines (345 loc) 13.6 kB
import { BaseLanguageHandler } from './base.js'; import { getNodeText } from '../astAnalyzer.js'; import logger from '../../../logger.js'; export class GoHandler extends BaseLanguageHandler { getFunctionQueryPatterns() { return [ 'function_declaration', 'method_declaration', 'func_literal' ]; } getClassQueryPatterns() { return [ 'type_declaration', 'type_spec', 'struct_type', 'interface_type' ]; } getImportQueryPatterns() { return [ 'import_declaration', 'import_spec' ]; } extractFunctionName(node, sourceCode, _options) { try { if (node.type === 'function_declaration') { const nameNode = node.childForFieldName('name'); if (nameNode) { const name = getNodeText(nameNode, sourceCode); if (name.startsWith('Test') && this.hasTestSignature(node, sourceCode)) { return `test_${name.substring(4)}`; } if (name.startsWith('Benchmark') && this.hasBenchmarkSignature(node, sourceCode)) { return `benchmark_${name.substring(9)}`; } if (name.startsWith('Example')) { return `example_${name.substring(7)}`; } if (name === 'main') { return 'main_entrypoint'; } if (name === 'init') { return 'init_function'; } return name; } } if (node.type === 'method_declaration') { const nameNode = node.childForFieldName('name'); const receiverNode = node.childForFieldName('receiver'); if (nameNode) { const name = getNodeText(nameNode, sourceCode); if (receiverNode) { const receiverType = this.extractReceiverType(receiverNode, sourceCode); if (this.isHttpHandler(node, sourceCode)) { return `http_handler_${receiverType}_${name}`; } return `${receiverType}.${name}`; } return name; } } if (node.type === 'func_literal') { if (node.parent?.type === 'short_var_declaration' || node.parent?.type === 'assignment_statement') { const leftNode = node.parent.childForFieldName('left'); if (leftNode?.firstChild) { return getNodeText(leftNode.firstChild, sourceCode); } } if (node.parent?.type === 'call_expression' && node.parent.previousSibling?.type === 'go') { return 'goroutine'; } if (node.parent?.type === 'argument_list' && node.parent.parent?.type === 'call_expression') { const funcNode = node.parent.parent.childForFieldName('function'); if (funcNode) { if (funcNode.type === 'selector_expression') { const methodNode = funcNode.childForFieldName('field'); if (methodNode) { const methodName = getNodeText(methodNode, sourceCode); if (['Map', 'Filter', 'ForEach', 'Handle', 'HandleFunc'].includes(methodName)) { return `${methodName.toLowerCase()}_callback`; } } } } } return 'closure'; } return 'anonymous'; } catch (error) { logger.warn({ err: error, nodeType: node.type }, 'Error extracting Go function name'); return 'anonymous'; } } hasTestSignature(node, _sourceCode) { try { const paramsNode = node.childForFieldName('parameters'); if (!paramsNode) return false; return paramsNode.text.includes('*testing.T'); } catch (error) { logger.warn({ err: error, nodeType: node.type }, 'Error checking Go test signature'); return false; } } hasBenchmarkSignature(node, _sourceCode) { try { const paramsNode = node.childForFieldName('parameters'); if (!paramsNode) return false; return paramsNode.text.includes('*testing.B'); } catch (error) { logger.warn({ err: error, nodeType: node.type }, 'Error checking Go benchmark signature'); return false; } } extractReceiverType(receiverNode, sourceCode) { try { const parameterNode = receiverNode.childForFieldName('parameter'); if (!parameterNode) return 'Unknown'; const typeNode = parameterNode.childForFieldName('type'); if (!typeNode) return 'Unknown'; if (typeNode.type === 'pointer_type') { const baseTypeNode = typeNode.childForFieldName('type'); if (baseTypeNode) { return getNodeText(baseTypeNode, sourceCode); } } return getNodeText(typeNode, sourceCode); } catch (error) { logger.warn({ err: error, nodeType: 'unknown' }, 'Error extracting Go receiver type'); return 'Unknown'; } } isHttpHandler(node, sourceCode) { try { const paramsNode = node.childForFieldName('parameters'); if (!paramsNode) return false; const paramsText = getNodeText(paramsNode, sourceCode); return paramsText.includes('http.ResponseWriter') && paramsText.includes('*http.Request'); } catch (error) { logger.warn({ err: error, nodeType: node.type }, 'Error checking if Go method is HTTP handler'); return false; } } extractClassName(node, sourceCode) { try { if (node.type === 'type_declaration') { const specNode = node.childForFieldName('spec'); if (specNode && specNode.type === 'type_spec') { const nameNode = specNode.childForFieldName('name'); if (nameNode) { return getNodeText(nameNode, sourceCode); } } } else if (node.type === 'type_spec') { const nameNode = node.childForFieldName('name'); if (nameNode) { return getNodeText(nameNode, sourceCode); } } return 'AnonymousType'; } catch (error) { logger.warn({ err: error, nodeType: node.type }, 'Error extracting Go class name'); return 'AnonymousType'; } } extractImportPath(node, sourceCode) { try { if (node.type === 'import_spec') { const pathNode = node.childForFieldName('path'); if (pathNode) { const path = getNodeText(pathNode, sourceCode); return path.replace(/^["']|["']$/g, ''); } } else if (node.type === 'import_declaration') { const specNode = node.childForFieldName('spec'); if (specNode && specNode.type === 'import_spec') { const pathNode = specNode.childForFieldName('path'); if (pathNode) { const path = getNodeText(pathNode, sourceCode); return path.replace(/^["']|["']$/g, ''); } } } return 'unknown'; } catch (error) { logger.warn({ err: error, nodeType: node.type }, 'Error extracting Go import path'); return 'unknown'; } } extractImportedItems(node, sourceCode) { try { if (node.type === 'import_spec') { const nameNode = node.childForFieldName('name'); const pathNode = node.childForFieldName('path'); if (pathNode) { const path = getNodeText(pathNode, sourceCode).replace(/^["']|["']$/g, ''); const parts = path.split('/'); const name = parts[parts.length - 1]; if (nameNode) { return [{ name: getNodeText(nameNode, sourceCode), path: path, isDefault: false, isNamespace: false, nodeText: node.text }]; } else { return [{ name: name, path: path, isDefault: false, isNamespace: false, nodeText: node.text }]; } } } return undefined; } catch (error) { logger.warn({ err: error, nodeType: node.type }, 'Error extracting Go imported items'); return undefined; } } isDefaultImport(node, sourceCode) { try { if (node.type === 'import_spec') { const nameNode = node.childForFieldName('name'); return nameNode ? getNodeText(nameNode, sourceCode) === '.' : false; } return undefined; } catch (error) { logger.warn({ err: error, nodeType: node.type }, 'Error checking if Go import is default'); return undefined; } } extractImportAlias(node, sourceCode) { try { if (node.type === 'import_spec') { const nameNode = node.childForFieldName('name'); if (nameNode) { return getNodeText(nameNode, sourceCode); } } return undefined; } catch (error) { logger.warn({ err: error, nodeType: node.type }, 'Error extracting Go import alias'); return undefined; } } 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.parseGoDocComment(prev.text); } return undefined; } catch (error) { logger.warn({ err: error, nodeType: node.type }, 'Error extracting Go 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.parseGoDocComment(prev.text); } return undefined; } catch (error) { logger.warn({ err: error, nodeType: node.type }, 'Error extracting Go class comment'); return undefined; } } parseGoDocComment(comment) { try { const lines = comment.split('\n') .map(line => line.trim().replace(/^\/\/\s*/, '')); return lines.join(' ').trim(); } catch (error) { logger.warn({ err: error }, 'Error parsing Go doc comment'); return comment; } } detectFramework(sourceCode) { try { if (sourceCode.includes('github.com/gin-gonic/gin') || sourceCode.includes('gin.Context') || sourceCode.includes('gin.Engine')) { return 'gin'; } if (sourceCode.includes('github.com/labstack/echo') || sourceCode.includes('echo.Context') || sourceCode.includes('echo.New()')) { return 'echo'; } if (sourceCode.includes('github.com/gorilla/mux') || sourceCode.includes('mux.Router') || sourceCode.includes('gorilla/websocket')) { return 'gorilla'; } if (sourceCode.includes('net/http') && (sourceCode.includes('http.HandleFunc') || sourceCode.includes('http.Handler') || sourceCode.includes('http.ServeMux'))) { return 'net/http'; } return null; } catch (error) { logger.warn({ err: error }, 'Error detecting Go framework'); return null; } } }