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.

328 lines (327 loc) 13.1 kB
import { BaseLanguageHandler } from './base.js'; import { getNodeText } from '../astAnalyzer.js'; import logger from '../../../logger.js'; export class ObjectiveCHandler extends BaseLanguageHandler { getFunctionQueryPatterns() { return [ 'function_definition', 'method_definition', 'method_declaration', 'block_literal_expression' ]; } getClassQueryPatterns() { return [ 'interface_declaration', 'implementation_definition', 'category_definition', 'protocol_declaration' ]; } getImportQueryPatterns() { return [ 'import_declaration', 'include_directive' ]; } extractFunctionName(node, sourceCode, _options) { try { if (node.type === 'function_definition') { const declaratorNode = node.childForFieldName('declarator'); if (declaratorNode) { if (declaratorNode.type === 'function_declarator') { const declaratorName = this.extractFunctionDeclaratorName(declaratorNode, sourceCode); if (declaratorName) { return declaratorName; } } } } if (node.type === 'method_definition' || node.type === 'method_declaration') { const selectorNode = node.childForFieldName('selector'); if (selectorNode) { const selector = getNodeText(selectorNode, sourceCode); if (this.isUIKitLifecycleMethod(selector)) { return `lifecycle_${selector}`; } if (selector.startsWith('init')) { return `initializer_${selector}`; } if (this.isDelegateMethod(node, sourceCode)) { return `delegate_${selector}`; } if (this.hasIBActionAttribute(node, sourceCode)) { return `action_${selector}`; } return selector; } } if (node.type === 'block_literal_expression') { if (node.parent?.type === 'init_declarator') { const declaratorNode = node.parent.childForFieldName('declarator'); if (declaratorNode) { return getNodeText(declaratorNode, sourceCode); } } if (node.parent?.type === 'argument_list' && node.parent.parent?.type === 'message_expression') { const selectorNode = node.parent.parent.childForFieldName('selector'); if (selectorNode) { const selector = getNodeText(selectorNode, sourceCode); if (['enumerateObjectsUsingBlock', 'animateWithDuration', 'performBlockAndWait'].includes(selector)) { return `${selector}_block`; } } } return 'block'; } return 'anonymous'; } catch (error) { logger.warn({ err: error, nodeType: node.type }, 'Error extracting Objective-C function name'); return 'anonymous'; } } extractFunctionDeclaratorName(node, sourceCode) { try { const declaratorNode = node.childForFieldName('declarator'); if (declaratorNode) { if (declaratorNode.type === 'identifier') { return getNodeText(declaratorNode, sourceCode); } } return null; } catch (error) { logger.warn({ err: error, nodeType: node.type }, 'Error extracting Objective-C function declarator name'); return null; } } isUIKitLifecycleMethod(selector) { const lifecycleMethods = [ 'viewDidLoad', 'viewWillAppear:', 'viewDidAppear:', 'viewWillDisappear:', 'viewDidDisappear:', 'didReceiveMemoryWarning', 'applicationDidFinishLaunching:', 'applicationWillTerminate:' ]; return lifecycleMethods.includes(selector); } isDelegateMethod(node, sourceCode) { try { let current = node.parent; while (current && current.type !== 'interface_declaration' && current.type !== 'implementation_definition') { current = current.parent; } if (current) { const nameNode = current.childForFieldName('name'); if (nameNode) { const className = getNodeText(nameNode, sourceCode); return className.includes('Delegate'); } } const selectorNode = node.childForFieldName('selector'); if (selectorNode) { const selector = getNodeText(selectorNode, sourceCode); return selector.includes('delegate'); } return false; } catch (error) { logger.warn({ err: error, nodeType: node.type }, 'Error checking if Objective-C method is delegate method'); return false; } } hasIBActionAttribute(node, sourceCode) { try { const returnTypeNode = node.childForFieldName('return_type'); if (returnTypeNode) { const returnType = getNodeText(returnTypeNode, sourceCode); return returnType.includes('IBAction'); } return false; } catch (error) { logger.warn({ err: error, nodeType: node.type }, 'Error checking if Objective-C method has IBAction attribute'); return false; } } extractClassName(node, sourceCode) { try { if (node.type === 'interface_declaration' || node.type === 'implementation_definition' || node.type === 'protocol_declaration') { const nameNode = node.childForFieldName('name'); if (nameNode) { return getNodeText(nameNode, sourceCode); } } else if (node.type === 'category_definition') { const nameNode = node.childForFieldName('name'); const categoryNode = node.childForFieldName('category'); if (nameNode && categoryNode) { return `${getNodeText(nameNode, sourceCode)}+${getNodeText(categoryNode, sourceCode)}`; } } return 'AnonymousClass'; } catch (error) { logger.warn({ err: error, nodeType: node.type }, 'Error extracting Objective-C class name'); return 'AnonymousClass'; } } extractParentClass(node, sourceCode) { try { if (node.type === 'interface_declaration') { const superclassNode = node.childForFieldName('superclass'); if (superclassNode) { return getNodeText(superclassNode, sourceCode); } } return undefined; } catch (error) { logger.warn({ err: error, nodeType: node.type }, 'Error extracting Objective-C parent class'); return undefined; } } extractImplementedInterfaces(node, sourceCode) { try { if (node.type === 'interface_declaration') { const protocolsNode = node.childForFieldName('protocols'); if (protocolsNode) { const protocols = []; const protocolList = getNodeText(protocolsNode, sourceCode); if (protocolList) { const protocolNames = protocolList.replace(/^<|>$/g, '').split(','); for (const name of protocolNames) { protocols.push(name.trim()); } } return protocols.length > 0 ? protocols : undefined; } } return undefined; } catch (error) { logger.warn({ err: error, nodeType: node.type }, 'Error extracting Objective-C implemented interfaces'); return undefined; } } extractImportPath(node, sourceCode) { try { if (node.type === 'import_declaration') { const pathNode = node.childForFieldName('path'); if (pathNode) { return getNodeText(pathNode, sourceCode); } } else if (node.type === 'include_directive') { const pathNode = node.childForFieldName('path'); if (pathNode) { return getNodeText(pathNode, sourceCode); } } return 'unknown'; } catch (error) { logger.warn({ err: error, nodeType: node.type }, 'Error extracting Objective-C 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') { if (prev.text.startsWith('/**') || prev.text.startsWith('/*!') || prev.text.startsWith('///') || prev.text.startsWith('//!')) { return this.parseDoxygenComment(prev.text); } return prev.text.replace(/^\/\/\s*/mg, '').trim(); } return undefined; } catch (error) { logger.warn({ err: error, nodeType: node.type }, 'Error extracting Objective-C 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') { if (prev.text.startsWith('/**') || prev.text.startsWith('/*!') || prev.text.startsWith('///') || prev.text.startsWith('//!')) { return this.parseDoxygenComment(prev.text); } return prev.text.replace(/^\/\/\s*/mg, '').trim(); } return undefined; } catch (error) { logger.warn({ err: error, nodeType: node.type }, 'Error extracting Objective-C class comment'); return undefined; } } parseDoxygenComment(comment) { try { if (comment.startsWith('/**') || comment.startsWith('/*!')) { const text = comment.substring(3, comment.length - 2); const lines = text.split('\n') .map(line => line.trim().replace(/^\*\s*/, '')) .filter(line => !line.startsWith('@') && !line.startsWith('\\')); return lines.join(' ').trim(); } else if (comment.startsWith('///') || comment.startsWith('//!')) { return comment.replace(/^\/\/[/!]\s*/mg, '').trim(); } return comment; } catch (error) { logger.warn({ err: error }, 'Error parsing Doxygen comment'); return comment; } } detectFramework(sourceCode) { try { if (sourceCode.includes('#import <UIKit/UIKit.h>') || sourceCode.includes('UIViewController') || sourceCode.includes('UIView')) { return 'uikit'; } if (sourceCode.includes('#import <Foundation/Foundation.h>') || sourceCode.includes('NSObject') || sourceCode.includes('NSString')) { return 'foundation'; } if (sourceCode.includes('#import <AppKit/AppKit.h>') || sourceCode.includes('NSViewController') || sourceCode.includes('NSView')) { return 'appkit'; } if (sourceCode.includes('#import <CoreData/CoreData.h>') || sourceCode.includes('NSManagedObject') || sourceCode.includes('NSPersistentContainer')) { return 'coredata'; } return null; } catch (error) { logger.warn({ err: error }, 'Error detecting Objective-C framework'); return null; } } }