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
JavaScript
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;
}
}
}