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.

261 lines (260 loc) 10.8 kB
import { BaseLanguageHandler } from './base.js'; import { getNodeText } from '../astAnalyzer.js'; import logger from '../../../logger.js'; export class RHandler extends BaseLanguageHandler { getFunctionQueryPatterns() { return [ 'function_definition', 'assignment', 'left_assignment', 'right_assignment' ]; } getClassQueryPatterns() { return [ 'call', 'assignment', 'left_assignment', 'right_assignment' ]; } getImportQueryPatterns() { return [ 'call' ]; } extractFunctionName(node, sourceCode, _options) { try { if (node.type === 'function_definition') { if (node.parent?.type === 'assignment' || node.parent?.type === 'left_assignment' || node.parent?.type === 'right_assignment') { const leftNode = node.parent.childForFieldName('left'); if (leftNode) { const name = getNodeText(leftNode, sourceCode); if (name.startsWith('test_') || name.startsWith('test.')) { return `test_${name.substring(5)}`; } if (name.includes('.')) { const parts = name.split('.'); if (parts.length >= 2) { return `method_${parts[0]}_${parts[1]}`; } } return name; } } return 'anonymous_function'; } if (node.type === 'assignment' || node.type === 'left_assignment' || node.type === 'right_assignment') { const rightNode = node.childForFieldName('right'); const leftNode = node.childForFieldName('left'); if (rightNode?.type === 'function_definition' && leftNode) { const name = getNodeText(leftNode, sourceCode); if (name.startsWith('test_') || name.startsWith('test.')) { return `test_${name.substring(5)}`; } if (name.includes('.')) { const parts = name.split('.'); if (parts.length >= 2) { return `method_${parts[0]}_${parts[1]}`; } } return name; } } return 'anonymous'; } catch (error) { logger.warn({ err: error, nodeType: node.type }, 'Error extracting R function name'); return 'anonymous'; } } extractClassName(node, sourceCode) { try { if (node.type === 'call') { const functionNode = node.childForFieldName('function'); if (functionNode && getNodeText(functionNode, sourceCode) === 'setClass') { const argsNode = node.childForFieldName('arguments'); if (argsNode?.firstChild) { return getNodeText(argsNode.firstChild, sourceCode).replace(/^["']|["']$/g, ''); } } } else if (node.type === 'assignment' || node.type === 'left_assignment' || node.type === 'right_assignment') { const rightNode = node.childForFieldName('right'); const leftNode = node.childForFieldName('left'); if (rightNode?.type === 'call' && getNodeText(rightNode.childForFieldName('function') || rightNode, sourceCode) === 'setClass' && leftNode) { return getNodeText(leftNode, sourceCode); } if (rightNode?.type === 'call' && getNodeText(rightNode.childForFieldName('function') || rightNode, sourceCode).includes('R6Class') && leftNode) { return getNodeText(leftNode, sourceCode); } if (rightNode?.type === 'call' && getNodeText(rightNode.childForFieldName('function') || rightNode, sourceCode) === 'structure' && leftNode) { const argsNode = rightNode.childForFieldName('arguments'); if (argsNode) { for (let i = 0; i < argsNode.childCount; i++) { const arg = argsNode.child(i); if (arg?.text.includes('class =')) { return getNodeText(leftNode, sourceCode); } } } } } return 'AnonymousClass'; } catch (error) { logger.warn({ err: error, nodeType: node.type }, 'Error extracting R class name'); return 'AnonymousClass'; } } extractParentClass(node, sourceCode) { try { if (node.type === 'call') { const functionNode = node.childForFieldName('function'); if (functionNode && getNodeText(functionNode, sourceCode) === 'setClass') { const argsNode = node.childForFieldName('arguments'); if (argsNode) { for (let i = 0; i < argsNode.childCount; i++) { const arg = argsNode.child(i); if (arg?.text.includes('contains =')) { const valueNode = arg.childForFieldName('value'); if (valueNode) { return getNodeText(valueNode, sourceCode); } } } } } } if (node.type === 'assignment' || node.type === 'left_assignment' || node.type === 'right_assignment') { const rightNode = node.childForFieldName('right'); if (rightNode?.type === 'call' && getNodeText(rightNode.childForFieldName('function') || rightNode, sourceCode).includes('R6Class')) { const argsNode = rightNode.childForFieldName('arguments'); if (argsNode) { for (let i = 0; i < argsNode.childCount; i++) { const arg = argsNode.child(i); if (arg?.text.includes('inherit =')) { const valueNode = arg.childForFieldName('value'); if (valueNode) { return getNodeText(valueNode, sourceCode); } } } } } } return undefined; } catch (error) { logger.warn({ err: error, nodeType: node.type }, 'Error extracting R parent class'); return undefined; } } extractImportPath(node, sourceCode) { try { if (node.type === 'call') { const functionNode = node.childForFieldName('function'); if (functionNode) { const funcName = getNodeText(functionNode, sourceCode); if (funcName === 'library' || funcName === 'require') { const argsNode = node.childForFieldName('arguments'); if (argsNode?.firstChild) { return getNodeText(argsNode.firstChild, sourceCode).replace(/^["']|["']$/g, ''); } } } } return 'unknown'; } catch (error) { logger.warn({ err: error, nodeType: node.type }, 'Error extracting R import path'); return 'unknown'; } } extractFunctionComment(node, sourceCode) { try { const current = node; let prev = current.previousNamedSibling; while (prev && prev.type !== 'comment') { prev = prev.previousNamedSibling; } if (prev && prev.type === 'comment') { const commentText = getNodeText(prev, sourceCode); return commentText .replace(/^#'\s*/mg, '') .replace(/^#\s*/mg, '') .trim(); } return undefined; } catch (error) { logger.warn({ err: error, nodeType: node.type }, 'Error extracting R function comment'); return undefined; } } extractClassComment(node, sourceCode) { try { const current = node; let prev = current.previousNamedSibling; while (prev && prev.type !== 'comment') { prev = prev.previousNamedSibling; } if (prev && prev.type === 'comment') { const commentText = getNodeText(prev, sourceCode); return commentText .replace(/^#'\s*/mg, '') .replace(/^#\s*/mg, '') .trim(); } return undefined; } catch (error) { logger.warn({ err: error, nodeType: node.type }, 'Error extracting R class comment'); return undefined; } } detectFramework(sourceCode) { try { if (sourceCode.includes('library(shiny)') || sourceCode.includes('shinyApp(') || sourceCode.includes('renderPlot(')) { return 'shiny'; } if (sourceCode.includes('library(ggplot2)') || sourceCode.includes('ggplot(') || sourceCode.includes('geom_')) { return 'ggplot2'; } if (sourceCode.includes('library(dplyr)') || sourceCode.includes('%>%') || sourceCode.includes('mutate(')) { return 'dplyr'; } if (sourceCode.includes('library(tidyverse)') || sourceCode.includes('tidyr::') || sourceCode.includes('readr::')) { return 'tidyverse'; } return null; } catch (error) { logger.warn({ err: error }, 'Error detecting R framework'); return null; } } }