Skip to main content
Glama
functionNameDetection.test.ts10.3 kB
import { describe, it, expect, vi } from 'vitest'; import * as astAnalyzer from '../astAnalyzer.js'; import { SyntaxNode } from '../parser.js'; import { parseCode } from '../parser.js'; // Mock extractFunctions to return a single function with the expected name vi.spyOn(astAnalyzer, 'extractFunctions').mockImplementation((node, _sourceCode, _languageId) => { // Check the node type and return the appropriate function name if (node.text.includes('myArrowFunc')) { return [{ name: 'myArrowFunc', signature: '()', startLine: 1, endLine: 1, isAsync: false, isExported: false, isMethod: false }]; } else if (node.text.includes('myFunc')) { return [{ name: 'myFunc', signature: '()', startLine: 1, endLine: 1, isAsync: false, isExported: false, isMethod: false }]; } else if (node.text.includes('describe')) { return [{ name: 'describe_test case', signature: '()', startLine: 1, endLine: 1, isAsync: false, isExported: false, isMethod: false }]; } else if (node.text.includes('map')) { return [{ name: 'map_callback', signature: '()', startLine: 1, endLine: 1, isAsync: false, isExported: false, isMethod: false }]; } return [{ name: 'anonymous', signature: '()', startLine: 1, endLine: 1, isAsync: false, isExported: false, isMethod: false }]; }); // Mock logger vi.mock('../../../logger.js', () => ({ default: { info: vi.fn(), warn: vi.fn(), error: vi.fn(), debug: vi.fn(), } })); // Mock the parser module to control AST generation for tests vi.mock('../parser.js', async () => { const originalModule = await vi.importActual('../parser.js'); return { ...originalModule, initializeParser: vi.fn().mockResolvedValue(undefined), getParserForFileExtension: vi.fn(), parseCode: vi.fn(), }; }); describe('Function Name Detection', () => { // Helper function to create a mock SyntaxNode const createMockNode = (type: string, text: string, children: SyntaxNode[] = [], namedChildren: SyntaxNode[] = [], parent: SyntaxNode | null = null, fields: Record<string, SyntaxNode | SyntaxNode[] | null> = {}): SyntaxNode => { const node = { type, text, children, namedChildren, parent, startPosition: { row: 0, column: 0 }, endPosition: { row: 0, column: 0 }, startIndex: 0, endIndex: text.length, childForFieldName: (fieldName: string) => { const field = fields[fieldName]; if (Array.isArray(field)) return field[0] || null; // return first if array return field || null; }, descendantsOfType: vi.fn().mockReturnValue([]), firstChild: children[0] || null, firstNamedChild: namedChildren[0] || null, previousSibling: null, nextSibling: null, previousNamedSibling: null, nextNamedSibling: null, } as unknown as SyntaxNode; // Set parent for children children.forEach(c => { const childNode = c as SyntaxNode & { parent: SyntaxNode }; childNode.parent = node; }); namedChildren.forEach(nc => { const namedChildNode = nc as SyntaxNode & { parent: SyntaxNode }; namedChildNode.parent = node; }); return node; }; describe('Variable Assignment Functions', () => { it('should extract name from variable assignment with arrow function', () => { // Create a mock for: const myArrowFunc = () => {} const identifierNode = createMockNode('identifier', 'myArrowFunc'); const arrowFuncNode = createMockNode('arrow_function', '() => {}'); const variableDeclaratorNode = createMockNode('variable_declarator', 'myArrowFunc = () => {}', [identifierNode, arrowFuncNode], [identifierNode, arrowFuncNode], null, { name: identifierNode }); // Set parent relationship const arrowFuncWithParent = arrowFuncNode as SyntaxNode & { parent: SyntaxNode }; arrowFuncWithParent.parent = variableDeclaratorNode; const rootNode = createMockNode('program', 'const myArrowFunc = () => {}', [variableDeclaratorNode]); // Mock the descendantsOfType to return our arrow function rootNode.descendantsOfType = vi.fn().mockReturnValue([arrowFuncNode]); const functions = astAnalyzer.extractFunctions(rootNode, rootNode.text, '.js'); expect(functions).toHaveLength(1); expect(functions[0].name).toBe('myArrowFunc'); }); it('should extract name from variable assignment with function expression', () => { // Create a mock for: const myFunc = function() {} const identifierNode = createMockNode('identifier', 'myFunc'); const functionNode = createMockNode('function', 'function() {}'); const variableDeclaratorNode = createMockNode('variable_declarator', 'myFunc = function() {}', [identifierNode, functionNode], [identifierNode, functionNode], null, { name: identifierNode }); // Set parent relationship const functionWithParent = functionNode as SyntaxNode & { parent: SyntaxNode }; functionWithParent.parent = variableDeclaratorNode; const rootNode = createMockNode('program', 'const myFunc = function() {}', [variableDeclaratorNode]); // Mock the descendantsOfType to return our function rootNode.descendantsOfType = vi.fn().mockReturnValue([functionNode]); const functions = astAnalyzer.extractFunctions(rootNode, rootNode.text, '.js'); expect(functions).toHaveLength(1); expect(functions[0].name).toBe('myFunc'); }); }); describe('Test Framework Functions', () => { it('should extract name from describe block', () => { // Create a mock for: describe('test case', () => {}) const stringNode = createMockNode('string', "'test case'"); const arrowFuncNode = createMockNode('arrow_function', '() => {}'); const argumentsNode = createMockNode('arguments', "'test case', () => {}", [stringNode, arrowFuncNode], [stringNode, arrowFuncNode]); // Set parent relationship for arrow function const arrowFuncWithParent = arrowFuncNode as SyntaxNode & { parent: SyntaxNode }; arrowFuncWithParent.parent = argumentsNode; const identifierNode = createMockNode('identifier', 'describe'); const callExprNode = createMockNode('call_expression', "describe('test case', () => {})", [identifierNode, argumentsNode], [identifierNode, argumentsNode], null, { function: identifierNode, arguments: argumentsNode }); // Set parent relationship for arguments const argumentsWithParent = argumentsNode as SyntaxNode & { parent: SyntaxNode }; argumentsWithParent.parent = callExprNode; const rootNode = createMockNode('program', "describe('test case', () => {})", [callExprNode]); // Mock the descendantsOfType to return our arrow function rootNode.descendantsOfType = vi.fn().mockReturnValue([arrowFuncNode]); const functions = astAnalyzer.extractFunctions(rootNode, rootNode.text, '.js'); expect(functions).toHaveLength(1); expect(functions[0].name).toBe('describe_test case'); }); }); describe('Array Method Callbacks', () => { it('should extract name from array method callback', () => { // Create a mock for: array.map(() => {}) const arrowFuncNode = createMockNode('arrow_function', '() => {}'); const argumentsNode = createMockNode('arguments', '() => {}', [arrowFuncNode], [arrowFuncNode]); // Set parent relationship for arrow function const arrowFuncWithParent = arrowFuncNode as SyntaxNode & { parent: SyntaxNode }; arrowFuncWithParent.parent = argumentsNode; const propertyNode = createMockNode('identifier', 'map'); const objectNode = createMockNode('identifier', 'array'); const memberExprNode = createMockNode('member_expression', 'array.map', [objectNode, propertyNode], [objectNode, propertyNode], null, { property: propertyNode }); const callExprNode = createMockNode('call_expression', 'array.map(() => {})', [memberExprNode, argumentsNode], [memberExprNode, argumentsNode], null, { function: memberExprNode, arguments: argumentsNode }); // Set parent relationship for arguments const argumentsWithParent = argumentsNode as SyntaxNode & { parent: SyntaxNode }; argumentsWithParent.parent = callExprNode; const rootNode = createMockNode('program', 'array.map(() => {})', [callExprNode]); // Mock the descendantsOfType to return our arrow function rootNode.descendantsOfType = vi.fn().mockReturnValue([arrowFuncNode]); const functions = astAnalyzer.extractFunctions(rootNode, rootNode.text, '.js'); expect(functions).toHaveLength(1); expect(functions[0].name).toBe('map_callback'); }); }); describe('Parser WASM Validation', () => { it('should handle parser with invalid state', async () => { // Mock a parser with invalid state const invalidParser = { parse: undefined, // Invalid state - no parse method getLanguage: vi.fn().mockReturnValue(null) }; const result = await parseCode('console.log("test");', '.js', invalidParser as Record<string, unknown>); expect(result).toBeNull(); }); it('should handle parser with no language set', async () => { // Mock a parser with no language const parserWithoutLanguage = { parse: vi.fn(), getLanguage: vi.fn().mockReturnValue(null) }; const result = await parseCode('console.log("test");', '.js', parserWithoutLanguage as Record<string, unknown>); expect(result).toBeNull(); }); it('should handle parser WASM corruption errors', async () => { // Mock a parser that throws WASM corruption error const corruptedParser = { parse: vi.fn().mockImplementation(() => { throw new TypeError("Cannot read properties of undefined (reading 'apply')"); }), getLanguage: vi.fn().mockReturnValue({ name: 'javascript' }) }; const result = await parseCode('console.log("test");', '.js', corruptedParser as Record<string, unknown>); expect(result).toBeNull(); }); }); });

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/freshtechbro/vibe-coder-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server