Skip to main content
Glama
lua.js12.3 kB
/** * Lua language handler for the Code-Map Generator tool. * This file contains the language handler for Lua files. */ import { BaseLanguageHandler } from './base.js'; import { getNodeText } from '../astAnalyzer.js'; import logger from '../../../logger.js'; /** * Language handler for Lua. * Provides enhanced function name detection for Lua files. */ export class LuaHandler extends BaseLanguageHandler { /** * Gets the query patterns for function detection. */ getFunctionQueryPatterns() { return [ 'function_declaration', 'function_definition', 'local_function', 'function', 'anonymous_function' ]; } /** * Gets the query patterns for class detection. */ getClassQueryPatterns() { return [ 'table_constructor', 'assignment_statement', 'variable_declaration' ]; } /** * Gets the query patterns for import detection. */ getImportQueryPatterns() { return [ 'function_call', 'variable_declaration' ]; } /** * Extracts the function name from an AST node. */ extractFunctionName(node, sourceCode, options) { try { // Handle function declarations if (node.type === 'function_declaration' || node.type === 'function_definition' || node.type === 'local_function' || node.type === 'function') { const nameNode = node.childForFieldName('name'); if (nameNode) { const name = getNodeText(nameNode, sourceCode); // Check for method definitions (with colon) if (name.includes(':')) { const parts = name.split(':'); return `method_${parts[0]}_${parts[1]}`; } // Check for module functions (with dot) if (name.includes('.')) { const parts = name.split('.'); return `${parts[0]}_${parts[parts.length - 1]}`; } // Check for test functions if (name.startsWith('test')) { return `test_${name.substring(4)}`; } // Check for callback functions if (name.includes('Callback') || name.includes('_callback')) { return `callback_${name}`; } return name; } } // Handle anonymous functions if (node.type === 'anonymous_function') { // Check if assigned to a variable if (node.parent?.type === 'assignment_statement') { const variableNode = node.parent.childForFieldName('variables'); if (variableNode?.firstChild) { return getNodeText(variableNode.firstChild, sourceCode); } } // Check if used in a table constructor if (node.parent?.type === 'field' && node.parent.parent?.type === 'table_constructor') { const nameNode = node.parent.childForFieldName('name'); if (nameNode) { return getNodeText(nameNode, sourceCode); } } return 'anonymous_function'; } return 'anonymous'; } catch (error) { logger.warn({ err: error, nodeType: node.type }, 'Error extracting Lua function name'); return 'anonymous'; } } /** * Extracts the class name from an AST node. */ extractClassName(node, sourceCode) { try { // In Lua, "classes" are often implemented as tables if (node.type === 'table_constructor') { // Check if this table is being assigned to a variable if (node.parent?.type === 'assignment_statement') { const variableNode = node.parent.childForFieldName('variables'); if (variableNode?.firstChild) { return getNodeText(variableNode.firstChild, sourceCode); } } // Check if this table is being returned if (node.parent?.type === 'return_statement') { // Try to find a nearby variable declaration or assignment let current = node.parent.parent; while (current) { if (current.type === 'function_declaration' || current.type === 'function_definition' || current.type === 'local_function') { const nameNode = current.childForFieldName('name'); if (nameNode) { return `${getNodeText(nameNode, sourceCode)}_Class`; } } current = current.parent; } } } else if (node.type === 'assignment_statement') { // Check if this is a class-like pattern (e.g., MyClass = {}) const variableNode = node.childForFieldName('variables'); const valueNode = node.childForFieldName('values'); if (variableNode?.firstChild && valueNode?.firstChild?.type === 'table_constructor') { return getNodeText(variableNode.firstChild, sourceCode); } } else if (node.type === 'variable_declaration') { // Check if this is a local class-like pattern (e.g., local MyClass = {}) const nameNode = node.childForFieldName('name'); const valueNode = node.childForFieldName('value'); if (nameNode && valueNode?.type === 'table_constructor') { return getNodeText(nameNode, sourceCode); } } return 'AnonymousClass'; } catch (error) { logger.warn({ err: error, nodeType: node.type }, 'Error extracting Lua class name'); return 'AnonymousClass'; } } /** * Extracts the parent class from an AST node. */ extractParentClass(node, sourceCode) { try { // In Lua, inheritance is often implemented with setmetatable if (node.type === 'assignment_statement' || node.type === 'variable_declaration') { // Look for setmetatable calls in the body let current = node.nextNamedSibling; while (current) { if (current.type === 'function_call' && current.childForFieldName('name')?.text === 'setmetatable') { const argsNode = current.childForFieldName('arguments'); if (argsNode && argsNode.childCount && argsNode.childCount >= 2) { // The second argument is often the parent class const parentNode = argsNode.child(1); if (parentNode) { return getNodeText(parentNode, sourceCode); } } } current = current.nextNamedSibling; } } return undefined; } catch (error) { logger.warn({ err: error, nodeType: node.type }, 'Error extracting Lua parent class'); return undefined; } } /** * Extracts the import path from an AST node. */ extractImportPath(node, sourceCode) { try { // In Lua, imports are often done with require if (node.type === 'function_call' && node.childForFieldName('name')?.text === 'require') { const argsNode = node.childForFieldName('arguments'); if (argsNode?.firstChild) { return getNodeText(argsNode.firstChild, sourceCode); } } else if (node.type === 'variable_declaration') { // Check for local module = require("module") pattern const valueNode = node.childForFieldName('value'); if (valueNode?.type === 'function_call' && valueNode.childForFieldName('name')?.text === 'require') { const argsNode = valueNode.childForFieldName('arguments'); if (argsNode?.firstChild) { return getNodeText(argsNode.firstChild, sourceCode); } } } return 'unknown'; } catch (error) { logger.warn({ err: error, nodeType: node.type }, 'Error extracting Lua import path'); return 'unknown'; } } /** * Extracts the function comment from an AST node. */ extractFunctionComment(node, sourceCode) { try { // Look for comments before the function const current = node; let prev = current.previousNamedSibling; while (prev && prev.type !== 'comment') { prev = prev.previousNamedSibling; } if (prev && prev.type === 'comment') { // Extract the comment text const commentText = getNodeText(prev, sourceCode); // Remove comment markers and whitespace return commentText .replace(/^--\s*/mg, '') .trim(); } return undefined; } catch (error) { logger.warn({ err: error, nodeType: node.type }, 'Error extracting Lua function comment'); return undefined; } } /** * Extracts the class comment from an AST node. */ extractClassComment(node, sourceCode) { try { // Look for comments before the class const current = node; let prev = current.previousNamedSibling; while (prev && prev.type !== 'comment') { prev = prev.previousNamedSibling; } if (prev && prev.type === 'comment') { // Extract the comment text const commentText = getNodeText(prev, sourceCode); // Remove comment markers and whitespace return commentText .replace(/^--\s*/mg, '') .trim(); } return undefined; } catch (error) { logger.warn({ err: error, nodeType: node.type }, 'Error extracting Lua class comment'); return undefined; } } /** * Detects the framework used in the source code. */ detectFramework(sourceCode) { try { // Love2D detection if (sourceCode.includes('love.') || sourceCode.includes('function love.') || sourceCode.includes('love.graphics')) { return 'love2d'; } // Corona SDK detection if (sourceCode.includes('display.') || sourceCode.includes('physics.') || sourceCode.includes('transition.')) { return 'corona'; } // Lapis detection if (sourceCode.includes('lapis.') || sourceCode.includes('require("lapis")') || sourceCode.includes('app:get')) { return 'lapis'; } // Torch detection if (sourceCode.includes('torch.') || sourceCode.includes('nn.') || sourceCode.includes('require("torch")')) { return 'torch'; } return null; } catch (error) { logger.warn({ err: error }, 'Error detecting Lua framework'); return null; } } }

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