vibe-coder-mcp
Version:
Production-ready MCP server with complete agent integration, multi-transport support, and comprehensive development automation tools for AI-assisted workflows.
207 lines (206 loc) • 9.16 kB
JavaScript
import { JavaScriptHandler } from './javascript.js';
import { getNodeText } from '../astAnalyzer.js';
import logger from '../../../logger.js';
export class TypeScriptHandler extends JavaScriptHandler {
getFunctionQueryPatterns() {
return [
...super.getFunctionQueryPatterns(),
'function_signature',
'method_signature',
'constructor_signature'
];
}
getClassQueryPatterns() {
return [
...super.getClassQueryPatterns(),
'interface_declaration',
'type_alias_declaration',
'enum_declaration'
];
}
getImportQueryPatterns() {
return [
...super.getImportQueryPatterns(),
'import_type_clause'
];
}
extractFunctionName(node, sourceCode, options) {
try {
if (node.type === 'function_signature' || node.type === 'method_signature') {
const nameNode = node.childForFieldName('name');
return nameNode ? getNodeText(nameNode, sourceCode) : 'anonymous';
}
if (node.type === 'constructor_signature') {
return 'constructor';
}
return super.extractFunctionName(node, sourceCode, options);
}
catch (error) {
logger.warn({ err: error, nodeType: node.type }, 'Error extracting TypeScript function name');
return 'anonymous';
}
}
extractClassName(node, sourceCode) {
try {
if (node.type === 'interface_declaration' ||
node.type === 'type_alias_declaration' ||
node.type === 'enum_declaration') {
const nameNode = node.childForFieldName('name');
return nameNode ? getNodeText(nameNode, sourceCode) : 'Anonymous';
}
return super.extractClassName(node, sourceCode);
}
catch (error) {
logger.warn({ err: error, nodeType: node.type }, 'Error extracting TypeScript class name');
return 'AnonymousClass';
}
}
extractParentClass(node, sourceCode) {
try {
if (node.type === 'class_declaration') {
const extendsClause = node.childForFieldName('extends_clause');
if (extendsClause) {
const typeNode = extendsClause.childForFieldName('type');
if (typeNode) {
return getNodeText(typeNode, sourceCode);
}
}
}
return undefined;
}
catch (error) {
logger.warn({ err: error, nodeType: node.type }, 'Error extracting TypeScript parent class');
return undefined;
}
}
extractImplementedInterfaces(node, sourceCode) {
try {
if (node.type === 'class_declaration') {
const implementsClause = node.childForFieldName('implements_clause');
if (implementsClause) {
const interfaces = [];
implementsClause.descendantsOfType('type_reference').forEach(typeRef => {
interfaces.push(getNodeText(typeRef, sourceCode));
});
return interfaces.length > 0 ? interfaces : undefined;
}
}
return undefined;
}
catch (error) {
logger.warn({ err: error, nodeType: node.type }, 'Error extracting TypeScript implemented interfaces');
return undefined;
}
}
extractFunctionComment(node, sourceCode) {
try {
if (node.type === 'function_signature' || node.type === 'method_signature' || node.type === 'constructor_signature') {
const current = node;
const lineStart = sourceCode.lastIndexOf('\n', current.startIndex) + 1;
const textBeforeNode = sourceCode.substring(0, lineStart).trim();
const tsdocEnd = textBeforeNode.lastIndexOf('*/');
if (tsdocEnd !== -1) {
const tsdocStart = textBeforeNode.lastIndexOf('/**', tsdocEnd);
if (tsdocStart !== -1) {
const comment = textBeforeNode.substring(tsdocStart + 3, tsdocEnd).trim();
const lines = comment.split('\n');
const description = lines
.map(line => line.trim().replace(/^\* ?/, ''))
.filter(line => !line.startsWith('@'))
.join(' ')
.trim();
return description;
}
}
return undefined;
}
return super.extractFunctionComment(node, sourceCode);
}
catch (error) {
logger.warn({ err: error, nodeType: node.type }, 'Error extracting TypeScript function comment');
return undefined;
}
}
extractClassProperties(node, sourceCode) {
const jsProperties = super.extractClassProperties(node, sourceCode);
try {
if (node.type === 'interface_declaration' || node.type === 'type_alias_declaration') {
const bodyNode = node.childForFieldName('body');
if (bodyNode) {
bodyNode.descendantsOfType(['property_signature']).forEach(propNode => {
const nameNode = propNode.childForFieldName('name');
if (nameNode) {
const name = getNodeText(nameNode, sourceCode);
let type;
const typeNode = propNode.childForFieldName('type');
if (typeNode) {
type = getNodeText(typeNode, sourceCode);
}
const comment = super.extractPropertyComment(propNode, sourceCode);
const isOptional = propNode.text.includes('?:');
jsProperties.push({
name,
type: type ? (isOptional ? `${type} | undefined` : type) : undefined,
comment: comment ? (isOptional ? `${comment} (Optional)` : comment) : (isOptional ? 'Optional property' : undefined),
startLine: propNode.startPosition.row + 1,
endLine: propNode.endPosition.row + 1,
accessModifier: 'public',
isStatic: false
});
}
});
}
}
else if (node.type === 'enum_declaration') {
const bodyNode = node.childForFieldName('body');
if (bodyNode) {
bodyNode.descendantsOfType(['enum_member']).forEach(memberNode => {
const nameNode = memberNode.childForFieldName('name');
if (nameNode) {
const name = getNodeText(nameNode, sourceCode);
let type = 'enum';
const valueNode = memberNode.childForFieldName('value');
if (valueNode) {
const value = getNodeText(valueNode, sourceCode);
type = `enum (${value})`;
}
const comment = super.extractPropertyComment(memberNode, sourceCode);
jsProperties.push({
name,
type,
comment: comment || `Enum member ${name}`,
startLine: memberNode.startPosition.row + 1,
endLine: memberNode.endPosition.row + 1,
accessModifier: 'public',
isStatic: true
});
}
});
}
}
return jsProperties;
}
catch (error) {
logger.warn({ err: error, nodeType: node.type }, 'Error extracting TypeScript class properties');
return jsProperties;
}
}
detectFramework(sourceCode) {
try {
if (sourceCode.includes('@angular/core') || sourceCode.includes('@Component')) {
return 'angular';
}
if (sourceCode.includes('@nestjs/common') || sourceCode.includes('@Controller')) {
return 'nestjs';
}
if (sourceCode.includes('next/app') || sourceCode.includes('NextPage')) {
return 'nextjs';
}
return super.detectFramework(sourceCode);
}
catch (error) {
logger.warn({ err: error }, 'Error detecting TypeScript framework');
return null;
}
}
}