vibe-coder-mcp
Version:
Production-ready MCP server with complete agent integration, multi-transport support, and comprehensive development automation tools for AI-assisted workflows.
247 lines (246 loc) • 9.37 kB
JavaScript
import { BaseLanguageHandler } from './base.js';
import { getNodeText } from '../astAnalyzer.js';
import logger from '../../../logger.js';
export class GraphQLHandler extends BaseLanguageHandler {
getFunctionQueryPatterns() {
return [
'field_definition',
'operation_definition',
'fragment_definition',
'directive_definition'
];
}
getClassQueryPatterns() {
return [
'type_definition',
'interface_definition',
'union_definition',
'enum_definition',
'input_object_type_definition',
'scalar_type_definition'
];
}
getImportQueryPatterns() {
return [
'import_declaration',
'include_directive',
'import_statement',
'call_expression'
];
}
extractFunctionName(node, sourceCode, _options) {
try {
if (node.type === 'field_definition') {
const nameNode = node.childForFieldName('name');
if (nameNode) {
const name = getNodeText(nameNode, sourceCode);
if (this.hasArguments(node)) {
return `resolver_${name}`;
}
return name;
}
}
if (node.type === 'operation_definition') {
const operationNode = node.childForFieldName('operation_type');
const nameNode = node.childForFieldName('name');
if (operationNode) {
const operationType = getNodeText(operationNode, sourceCode);
if (nameNode) {
return `${operationType}_${getNodeText(nameNode, sourceCode)}`;
}
return `anonymous_${operationType}`;
}
}
if (node.type === 'fragment_definition') {
const nameNode = node.childForFieldName('name');
if (nameNode) {
return `fragment_${getNodeText(nameNode, sourceCode)}`;
}
}
if (node.type === 'directive_definition') {
const nameNode = node.childForFieldName('name');
if (nameNode) {
return `directive_${getNodeText(nameNode, sourceCode)}`;
}
}
return 'anonymous';
}
catch (error) {
logger.warn({ err: error, nodeType: node.type }, 'Error extracting GraphQL/Schema function name');
return 'anonymous';
}
}
hasArguments(node) {
try {
const argsNode = node.childForFieldName('arguments');
return !!argsNode && argsNode.childCount > 0;
}
catch (error) {
logger.warn({ err: error, nodeType: node.type }, 'Error checking if GraphQL field has arguments');
return false;
}
}
extractClassName(node, sourceCode) {
try {
if (node.type === 'type_definition' ||
node.type === 'interface_definition' ||
node.type === 'union_definition' ||
node.type === 'enum_definition' ||
node.type === 'input_object_type_definition' ||
node.type === 'scalar_type_definition') {
const nameNode = node.childForFieldName('name');
if (nameNode) {
return getNodeText(nameNode, sourceCode);
}
}
return 'AnonymousType';
}
catch (error) {
logger.warn({ err: error, nodeType: node.type }, 'Error extracting GraphQL/Schema class name');
return 'AnonymousType';
}
}
extractImplementedInterfaces(node, sourceCode) {
try {
if (node.type === 'type_definition') {
const implementsNode = node.childForFieldName('implements');
if (implementsNode) {
const interfaces = [];
const namedTypes = implementsNode.descendantsOfType('named_type');
for (const namedType of namedTypes) {
interfaces.push(getNodeText(namedType, sourceCode));
}
return interfaces.length > 0 ? interfaces : undefined;
}
}
return undefined;
}
catch (error) {
logger.warn({ err: error, nodeType: node.type }, 'Error extracting GraphQL/Schema 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 argumentNode = node.childForFieldName('argument');
if (argumentNode) {
return getNodeText(argumentNode, sourceCode);
}
}
if (node.type === 'import_statement' || node.type === 'import_declaration') {
const source = node.childForFieldName('source');
if (source && source.text) {
return source.text.replace(/['"`]/g, '');
}
}
if (node.type === 'call_expression' && node.childForFieldName('function')?.text === 'require') {
const args = node.childForFieldName('arguments');
const firstArg = args?.firstChild;
if (firstArg && firstArg.text) {
return firstArg.text.replace(/['"`]/g, '');
}
}
return 'unknown';
}
catch (error) {
logger.warn({ err: error, nodeType: node.type }, 'Error extracting GraphQL/Schema import path');
return 'unknown';
}
}
extractFunctionComment(node, sourceCode) {
try {
const descriptionNode = node.childForFieldName('description');
if (descriptionNode) {
return this.parseGraphQLDescription(descriptionNode.text);
}
const current = node;
let prev = current.previousNamedSibling;
while (prev && prev.type !== 'comment') {
prev = prev.previousNamedSibling;
}
if (prev && prev.type === 'comment') {
const commentText = getNodeText(prev, sourceCode);
return commentText
.replace(/^#\s*/mg, '')
.trim();
}
return undefined;
}
catch (error) {
logger.warn({ err: error, nodeType: node.type }, 'Error extracting GraphQL/Schema function comment');
return undefined;
}
}
extractClassComment(node, sourceCode) {
try {
const descriptionNode = node.childForFieldName('description');
if (descriptionNode) {
return this.parseGraphQLDescription(descriptionNode.text);
}
const current = node;
let prev = current.previousNamedSibling;
while (prev && prev.type !== 'comment') {
prev = prev.previousNamedSibling;
}
if (prev && prev.type === 'comment') {
const commentText = getNodeText(prev, sourceCode);
return commentText
.replace(/^#\s*/mg, '')
.trim();
}
return undefined;
}
catch (error) {
logger.warn({ err: error, nodeType: node.type }, 'Error extracting GraphQL/Schema class comment');
return undefined;
}
}
parseGraphQLDescription(description) {
try {
return description
.replace(/^"""|"""$/g, '')
.replace(/^"|"$/g, '')
.trim();
}
catch (error) {
logger.warn({ err: error }, 'Error parsing GraphQL description');
return description;
}
}
detectFramework(sourceCode) {
try {
if (sourceCode.includes('ApolloServer') ||
sourceCode.includes('gql`') ||
sourceCode.includes('apollo-server')) {
return 'apollo';
}
if (sourceCode.includes('Relay') ||
sourceCode.includes('graphql-relay') ||
sourceCode.includes('relay-runtime')) {
return 'relay';
}
if (sourceCode.includes('GraphQLYoga') ||
sourceCode.includes('createYoga') ||
sourceCode.includes('graphql-yoga')) {
return 'yoga';
}
if (sourceCode.includes('Prisma') ||
sourceCode.includes('prisma') ||
sourceCode.includes('@prisma/client')) {
return 'prisma';
}
return null;
}
catch (error) {
logger.warn({ err: error }, 'Error detecting GraphQL/Schema framework');
return null;
}
}
}