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.

207 lines (206 loc) 9.16 kB
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; } } }