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.

249 lines (248 loc) 9.24 kB
import { BaseLanguageHandler } from './base.js'; import { getNodeText } from '../astAnalyzer.js'; import logger from '../../../logger.js'; export class RubyHandler extends BaseLanguageHandler { getFunctionQueryPatterns() { return [ 'method', 'method_definition', 'singleton_method', 'lambda', 'block' ]; } getClassQueryPatterns() { return [ 'class', 'class_definition', 'module', 'module_definition' ]; } getImportQueryPatterns() { return [ 'require', 'require_relative', 'include', 'extend' ]; } extractFunctionName(node, sourceCode, _options) { try { if (node.type === 'method' || node.type === 'method_definition') { const nameNode = node.childForFieldName('name'); if (nameNode) { const name = getNodeText(nameNode, sourceCode); if (name.startsWith('test_')) { return name; } if (this.isRailsControllerAction(node, sourceCode)) { return `action_${name}`; } if (this.isRailsModelCallback(name)) { return `callback_${name}`; } if (name.startsWith('get_') || name.startsWith('set_')) { return name; } if (name.endsWith('?')) { return `predicate_${name.slice(0, -1)}`; } if (name.endsWith('!')) { return `destructive_${name.slice(0, -1)}`; } return name; } } if (node.type === 'singleton_method') { const nameNode = node.childForFieldName('name'); if (nameNode) { const name = getNodeText(nameNode, sourceCode); return `self_${name}`; } } if (node.type === 'lambda') { if (node.parent?.type === 'assignment') { const leftNode = node.parent.childForFieldName('left'); if (leftNode) { return getNodeText(leftNode, sourceCode); } } return 'lambda'; } if (node.type === 'block') { if (node.parent?.type === 'method_call') { const methodNode = node.parent.childForFieldName('method'); if (methodNode) { const methodName = getNodeText(methodNode, sourceCode); if (['map', 'each', 'select', 'reject', 'reduce'].includes(methodName)) { return `${methodName}_block`; } if (['before_action', 'after_action', 'around_action'].includes(methodName)) { return `filter_${methodName.split('_')[0]}`; } return `${methodName}_block`; } } return 'block'; } return 'anonymous'; } catch (error) { logger.warn({ err: error, nodeType: node.type }, 'Error extracting Ruby function name'); return 'anonymous'; } } isRailsControllerAction(node, sourceCode) { try { let current = node.parent; while (current && current.type !== 'class') { current = current.parent; } if (current) { const superclassNode = current.childForFieldName('superclass'); if (superclassNode) { const superclass = getNodeText(superclassNode, sourceCode); return superclass.includes('Controller'); } } return false; } catch (error) { logger.warn({ err: error, nodeType: node.type }, 'Error checking if method is a Rails controller action'); return false; } } isRailsModelCallback(name) { const callbacks = [ 'before_validation', 'after_validation', 'before_save', 'after_save', 'before_create', 'after_create', 'before_update', 'after_update', 'before_destroy', 'after_destroy' ]; return callbacks.includes(name); } extractClassName(node, sourceCode) { try { if (node.type === 'class' || node.type === 'class_definition') { const nameNode = node.childForFieldName('name'); if (nameNode) { return getNodeText(nameNode, sourceCode); } } else if (node.type === 'module' || node.type === 'module_definition') { const nameNode = node.childForFieldName('name'); if (nameNode) { return `Module_${getNodeText(nameNode, sourceCode)}`; } } return 'AnonymousClass'; } catch (error) { logger.warn({ err: error, nodeType: node.type }, 'Error extracting Ruby class name'); return 'AnonymousClass'; } } extractParentClass(node, sourceCode) { try { if (node.type === 'class' || node.type === 'class_definition') { const superclassNode = node.childForFieldName('superclass'); if (superclassNode) { return getNodeText(superclassNode, sourceCode); } } return undefined; } catch (error) { logger.warn({ err: error, nodeType: node.type }, 'Error extracting Ruby parent class'); return undefined; } } extractImportPath(node, sourceCode) { try { if (node.type === 'require' || node.type === 'require_relative') { const argumentNode = node.childForFieldName('argument'); if (argumentNode) { const path = getNodeText(argumentNode, sourceCode); return path.replace(/^['"]|['"]$/g, ''); } } else if (node.type === 'include' || node.type === 'extend') { const argumentNode = node.childForFieldName('argument'); if (argumentNode) { return getNodeText(argumentNode, sourceCode); } } return 'unknown'; } catch (error) { logger.warn({ err: error, nodeType: node.type }, 'Error extracting Ruby 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, '') .trim(); } return undefined; } catch (error) { logger.warn({ err: error, nodeType: node.type }, 'Error extracting Ruby 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, '') .trim(); } return undefined; } catch (error) { logger.warn({ err: error, nodeType: node.type }, 'Error extracting Ruby class comment'); return undefined; } } detectFramework(sourceCode) { try { if (sourceCode.includes('Rails') || sourceCode.includes('ActiveRecord') || sourceCode.includes('ApplicationController')) { return 'rails'; } if (sourceCode.includes('Sinatra') || sourceCode.includes('get {') || sourceCode.includes('post {')) { return 'sinatra'; } if (sourceCode.includes('RSpec') || sourceCode.includes('describe') || sourceCode.includes('it "')) { return 'rspec'; } return null; } catch (error) { logger.warn({ err: error }, 'Error detecting Ruby framework'); return null; } } }