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.

454 lines (453 loc) 19.8 kB
import { BaseLanguageHandler } from './base.js'; import { getNodeText } from '../astAnalyzer.js'; import logger from '../../../logger.js'; export class JavaHandler extends BaseLanguageHandler { getFunctionQueryPatterns() { return [ 'method_declaration', 'constructor_declaration', 'lambda_expression' ]; } getClassQueryPatterns() { return [ 'class_declaration', 'interface_declaration', 'enum_declaration' ]; } getImportQueryPatterns() { return [ 'import_declaration', 'static_import_declaration' ]; } extractFunctionName(node, sourceCode, _options) { try { if (node.type === 'method_declaration') { const nameNode = node.childForFieldName('name'); if (nameNode) { const name = getNodeText(nameNode, sourceCode); const annotations = this.getMethodAnnotations(node, sourceCode); if (annotations.includes('@GetMapping') || annotations.includes('@PostMapping') || annotations.includes('@RequestMapping') || annotations.includes('@PutMapping') || annotations.includes('@DeleteMapping')) { return `endpoint_${name}`; } if (annotations.includes('@Test')) { return `test_${name}`; } if (this.isAndroidLifecycleMethod(name)) { return `lifecycle_${name}`; } return name; } } if (node.type === 'constructor_declaration') { const className = this.findClassName(node, sourceCode); return `${className}_Constructor`; } if (node.type === 'lambda_expression') { if (node.parent?.type === 'argument_list' && node.parent.parent?.type === 'method_invocation') { const methodNode = node.parent.parent.childForFieldName('name'); if (methodNode) { const methodName = getNodeText(methodNode, sourceCode); if (['map', 'filter', 'forEach', 'reduce'].includes(methodName)) { return `${methodName}Lambda`; } if (methodName.startsWith('set') && methodName.endsWith('Listener')) { const eventType = methodName.substring(3, methodName.length - 8); return `${eventType}Handler`; } } } return 'lambda'; } return 'anonymous'; } catch (error) { logger.warn({ err: error, nodeType: node.type }, 'Error extracting Java 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 Java class name'); return 'Unknown'; } } getMethodAnnotations(node, sourceCode) { try { const annotations = []; const current = node; let prev = current.previousNamedSibling; while (prev && prev.type === 'annotation') { annotations.push(getNodeText(prev, sourceCode)); prev = prev.previousNamedSibling; } return annotations; } catch (error) { logger.warn({ err: error, nodeType: node.type }, 'Error getting Java method annotations'); return []; } } isAndroidLifecycleMethod(name) { try { const lifecycleMethods = [ 'onCreate', 'onStart', 'onResume', 'onPause', 'onStop', 'onDestroy', 'onCreateView', 'onViewCreated' ]; return lifecycleMethods.includes(name); } catch (error) { logger.warn({ err: error }, 'Error checking if method is Android lifecycle method'); return false; } } extractClassName(node, sourceCode) { try { if (node.type === 'class_declaration' || node.type === 'interface_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 Java class name'); return 'AnonymousClass'; } } extractParentClass(node, sourceCode) { try { if (node.type === 'class_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 Java parent class'); return undefined; } } extractImplementedInterfaces(node, sourceCode) { try { if (node.type === 'class_declaration') { const interfaces = []; const interfacesNode = node.childForFieldName('interfaces'); if (interfacesNode) { interfacesNode.descendantsOfType('type_identifier').forEach(typeNode => { interfaces.push(getNodeText(typeNode, sourceCode)); }); } return interfaces.length > 0 ? interfaces : undefined; } return undefined; } catch (error) { logger.warn({ err: error, nodeType: node.type }, 'Error extracting Java implemented interfaces'); return undefined; } } extractImportPath(node, sourceCode) { try { if (node.type === 'import_declaration' || node.type === 'static_import_declaration') { const nameNode = node.childForFieldName('name'); if (nameNode) { return getNodeText(nameNode, sourceCode); } } return 'unknown'; } catch (error) { logger.warn({ err: error, nodeType: node.type }, 'Error extracting Java import path'); return 'unknown'; } } isDefaultImport(node, _sourceCode) { try { return node.type === 'static_import_declaration'; } catch (error) { logger.warn({ err: error, nodeType: node.type }, 'Error checking if Java import is static'); return undefined; } } extractImportedItems(node, sourceCode) { try { if (node.type === 'import_declaration' || node.type === 'static_import_declaration') { const nameNode = node.childForFieldName('name'); if (nameNode) { const fullPath = getNodeText(nameNode, sourceCode); const parts = fullPath.split('.'); const name = parts[parts.length - 1]; const isStatic = node.type === 'static_import_declaration'; const packagePath = parts.slice(0, parts.length - 1).join('.'); if (name === '*') { return [{ name: '*', path: fullPath, isDefault: false, isNamespace: true, nodeText: node.text }]; } if (isStatic) { const className = parts[parts.length - 2] || ''; return [{ name: name, path: fullPath, isDefault: false, isNamespace: false, nodeText: node.text, alias: undefined, staticImport: { className: className, memberName: name, packageName: parts.slice(0, parts.length - 2).join('.') } }]; } return [{ name: name, path: fullPath, isDefault: false, isNamespace: false, nodeText: node.text, packageName: packagePath }]; } } return undefined; } catch (error) { logger.warn({ err: error, nodeType: node.type }, 'Error extracting Java imported items'); return undefined; } } extractClassProperties(node, _sourceCode) { try { const properties = []; if (node.type === 'class_declaration' || node.type === 'interface_declaration' || node.type === 'enum_declaration') { const bodyNode = node.childForFieldName('body'); if (bodyNode) { bodyNode.descendantsOfType('field_declaration').forEach(fieldNode => { const typeNode = fieldNode.childForFieldName('type'); const declaratorListNode = fieldNode.childForFieldName('declarator_list'); if (typeNode && declaratorListNode) { const type = getNodeText(typeNode, _sourceCode); const nodeText = fieldNode.text; let accessModifier; if (nodeText.includes('private ')) { accessModifier = 'private'; } else if (nodeText.includes('protected ')) { accessModifier = 'protected'; } else if (nodeText.includes('public ')) { accessModifier = 'public'; } else { accessModifier = 'package-private'; } const isStatic = nodeText.includes('static '); const isFinal = nodeText.includes('final '); const comment = this.extractPropertyComment(fieldNode, _sourceCode); declaratorListNode.children.forEach(declarator => { if (declarator.type === 'variable_declarator') { const nameNode = declarator.childForFieldName('name'); if (nameNode) { const name = getNodeText(nameNode, _sourceCode); let finalComment = comment; if (isFinal && !finalComment) { finalComment = 'Constant value'; } else if (isFinal && finalComment) { finalComment = `${finalComment} (Constant)`; } properties.push({ name, type, accessModifier, isStatic, comment: finalComment, startLine: declarator.startPosition.row + 1, endLine: declarator.endPosition.row + 1 }); } } }); } }); if (node.type === 'enum_declaration') { const enumBodyNode = bodyNode.childForFieldName('enum_body'); if (enumBodyNode) { enumBodyNode.descendantsOfType('enum_constant').forEach(constantNode => { const nameNode = constantNode.childForFieldName('name'); if (nameNode) { const name = getNodeText(nameNode, _sourceCode); const comment = this.extractPropertyComment(constantNode, _sourceCode); properties.push({ name, type: this.extractClassName(node, _sourceCode), accessModifier: 'public', isStatic: true, comment, startLine: constantNode.startPosition.row + 1, endLine: constantNode.endPosition.row + 1 }); } }); } } if (node.type === 'interface_declaration') { bodyNode.descendantsOfType('field_declaration').forEach(fieldNode => { const typeNode = fieldNode.childForFieldName('type'); const declaratorListNode = fieldNode.childForFieldName('declarator_list'); if (typeNode && declaratorListNode) { const type = getNodeText(typeNode, _sourceCode); const comment = this.extractPropertyComment(fieldNode, _sourceCode); declaratorListNode.children.forEach(declarator => { if (declarator.type === 'variable_declarator') { const nameNode = declarator.childForFieldName('name'); if (nameNode) { const name = getNodeText(nameNode, _sourceCode); properties.push({ name, type, accessModifier: 'public', isStatic: true, comment: comment ? `${comment} (Constant)` : 'Constant value', startLine: declarator.startPosition.row + 1, endLine: declarator.endPosition.row + 1 }); } } }); } }); } } } return properties; } catch (error) { logger.warn({ err: error, nodeType: node.type }, 'Error extracting Java class properties'); return []; } } extractPropertyComment(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.parseJavadocComment(prev.text); } return undefined; } catch (error) { logger.warn({ err: error, nodeType: node.type }, 'Error extracting Java property comment'); 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.parseJavadocComment(prev.text); } return undefined; } catch (error) { logger.warn({ err: error, nodeType: node.type }, 'Error extracting Java 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.parseJavadocComment(prev.text); } return undefined; } catch (error) { logger.warn({ err: error, nodeType: node.type }, 'Error extracting Java class comment'); return undefined; } } parseJavadocComment(comment) { try { const text = comment.substring(3, comment.length - 2); const lines = text.split('\n') .map(line => line.trim().replace(/^\*\s*/, '')) .filter(line => !line.startsWith('@')); return lines.join(' ').trim(); } catch (error) { logger.warn({ err: error }, 'Error parsing Javadoc comment'); return comment; } } detectFramework(sourceCode) { try { if (sourceCode.includes('org.springframework') || sourceCode.includes('@Controller') || sourceCode.includes('@Service')) { return 'spring'; } if (sourceCode.includes('android.') || sourceCode.includes('androidx.') || sourceCode.includes('extends Activity') || sourceCode.includes('extends Fragment')) { return 'android'; } if (sourceCode.includes('org.junit') || sourceCode.includes('@Test') || sourceCode.includes('extends TestCase')) { return 'junit'; } return null; } catch (error) { logger.warn({ err: error }, 'Error detecting Java framework'); return null; } } }