arela
Version:
AI-powered CTO with multi-agent orchestration, code summarization, visual testing (web + mobile) for blazing fast development.
328 lines • 10.6 kB
JavaScript
/**
* Universal Language Analyzer - Supports TypeScript, JavaScript, Python, Go, Rust, etc.
* Uses regex patterns for universal parsing across languages
*/
import fs from "fs-extra";
import path from "path";
import { determineFileType, getLineCount } from "./file-scanner.js";
/**
* Language-specific patterns for imports/requires
*/
const IMPORT_PATTERNS = {
// JavaScript/TypeScript
javascript: [
/import\s+(?:{[^}]+}|[\w*]+)\s+from\s+['"]([^'"]+)['"]/g,
/import\s+['"]([^'"]+)['"]/g,
/require\s*\(['"]([^'"]+)['"]\)/g,
/import\s*\(\s*['"]([^'"]+)['"]\s*\)/g, // Dynamic imports
],
typescript: [
/import\s+(?:{[^}]+}|[\w*]+)\s+from\s+['"]([^'"]+)['"]/g,
/import\s+['"]([^'"]+)['"]/g,
/require\s*\(['"]([^'"]+)['"]\)/g,
/import\s*\(\s*['"]([^'"]+)['"]\s*\)/g,
],
// Python
python: [
/^import\s+([\w.]+)/gm,
/^from\s+([\w.]+)\s+import/gm,
],
// Go
go: [
/import\s+['"]([^'"]+)['"]/g,
/import\s+\(\s*([^)]+)\s*\)/gs, // Multi-line imports
],
// Rust
rust: [
/use\s+([\w:]+)/g,
/extern\s+crate\s+(\w+)/g,
],
// Ruby
ruby: [
/require\s+['"]([^'"]+)['"]/g,
/require_relative\s+['"]([^'"]+)['"]/g,
],
// PHP
php: [
/require\s+['"]([^'"]+)['"]/g,
/require_once\s+['"]([^'"]+)['"]/g,
/include\s+['"]([^'"]+)['"]/g,
/use\s+([\w\\]+)/g,
],
// Java
java: [
/import\s+([\w.]+)/g,
],
// C#
csharp: [
/using\s+([\w.]+)/g,
],
};
/**
* Language-specific patterns for function definitions
*/
const FUNCTION_PATTERNS = {
javascript: [
/function\s+(\w+)\s*\(/g,
/const\s+(\w+)\s*=\s*(?:async\s+)?\([^)]*\)\s*=>/g,
/(?:export\s+)?(?:async\s+)?function\s+(\w+)/g,
],
typescript: [
/function\s+(\w+)\s*\(/g,
/const\s+(\w+)\s*=\s*(?:async\s+)?\([^)]*\)\s*=>/g,
/(?:export\s+)?(?:async\s+)?function\s+(\w+)/g,
],
python: [
/def\s+(\w+)\s*\(/g,
/async\s+def\s+(\w+)\s*\(/g,
],
go: [
/func\s+(\w+)\s*\(/g,
/func\s+\(\w+\s+\*?\w+\)\s+(\w+)\s*\(/g, // Methods
],
rust: [
/fn\s+(\w+)\s*\(/g,
/pub\s+fn\s+(\w+)\s*\(/g,
],
ruby: [
/def\s+(\w+)/g,
],
php: [
/function\s+(\w+)\s*\(/g,
/(?:public|private|protected)\s+function\s+(\w+)\s*\(/g,
],
java: [
/(?:public|private|protected)\s+(?:static\s+)?(?:\w+\s+)?(\w+)\s*\([^)]*\)\s*{/g,
],
csharp: [
/(?:public|private|protected)\s+(?:static\s+)?(?:\w+\s+)?(\w+)\s*\([^)]*\)/g,
],
};
/**
* Language-specific patterns for API endpoints
*/
const API_ENDPOINT_PATTERNS = {
javascript: [
/app\.(get|post|put|delete|patch)\s*\(['"]([^'"]+)['"]/g,
/router\.(get|post|put|delete|patch)\s*\(['"]([^'"]+)['"]/g,
/@(Get|Post|Put|Delete|Patch)\s*\(['"]([^'"]+)['"]/g, // NestJS
],
typescript: [
/app\.(get|post|put|delete|patch)\s*\(['"]([^'"]+)['"]/g,
/router\.(get|post|put|delete|patch)\s*\(['"]([^'"]+)['"]/g,
/@(Get|Post|Put|Delete|Patch)\s*\(['"]([^'"]+)['"]/g,
],
python: [
/@app\.(get|post|put|delete|patch)\s*\(['"]([^'"]+)['"]/g, // FastAPI
/@router\.(get|post|put|delete|patch)\s*\(['"]([^'"]+)['"]/g,
/@route\s*\(['"]([^'"]+)['"],?\s*methods\s*=\s*\[['"](\w+)['"]\]/g, // Flask
],
go: [
// Gin framework
/\b\w+\.(GET|POST|PUT|DELETE|PATCH|HEAD|OPTIONS)\s*\(\s*["']([^"']+)["']/g,
// Standard library
/http\.HandleFunc\s*\(\s*["']([^"']+)["']/g,
// Gorilla mux
/router\.(GET|POST|PUT|DELETE|PATCH|HEAD|OPTIONS)\s*\(\s*["']([^"']+)["']/g,
],
rust: [
/#\[get\s*\(['"]([^'"]+)['"]\)\]/g,
/#\[post\s*\(['"]([^'"]+)['"]\)\]/g,
/#\[put\s*\(['"]([^'"]+)['"]\)\]/g,
/#\[delete\s*\(['"]([^'"]+)['"]\)\]/g,
],
ruby: [
/(get|post|put|delete|patch)\s+['"]([^'"]+)['"]/g,
],
php: [
/Route::(get|post|put|delete|patch)\s*\(['"]([^'"]+)['"]/g, // Laravel
],
java: [
/@(Get|Post|Put|Delete|Patch)Mapping\s*\(['"]([^'"]+)['"]/g, // Spring
],
csharp: [
/\[Http(Get|Post|Put|Delete|Patch)\s*\(['"]([^'"]+)['"]\)\]/g, // ASP.NET
],
};
/**
* Language-specific patterns for API calls
*/
const API_CALL_PATTERNS = [
/fetch\s*\(['"]([^'"]+)['"]/g,
/axios\.(get|post|put|delete|patch)\s*\(['"]([^'"]+)['"]/g,
/requests\.(get|post|put|delete|patch)\s*\(['"]([^'"]+)['"]/g, // Python
/http\.(Get|Post|Put|Delete|Patch)\s*\(['"]([^'"]+)['"]/g, // Go
/HttpClient\.(GetAsync|PostAsync|PutAsync|DeleteAsync)\s*\(['"]([^'"]+)['"]/g, // C#
];
/**
* Detect language from file extension
*/
function detectLanguage(filePath) {
const ext = path.extname(filePath).toLowerCase();
const languageMap = {
'.js': 'javascript',
'.jsx': 'javascript',
'.ts': 'typescript',
'.tsx': 'typescript',
'.py': 'python',
'.go': 'go',
'.rs': 'rust',
'.rb': 'ruby',
'.php': 'php',
'.java': 'java',
'.cs': 'csharp',
};
return languageMap[ext] || 'unknown';
}
/**
* Extract imports using regex patterns
*/
function extractImports(content, language) {
const imports = [];
const patterns = IMPORT_PATTERNS[language] || [];
for (const pattern of patterns) {
let match;
while ((match = pattern.exec(content)) !== null) {
let modulePath = match[1];
const lineNumber = content.substring(0, match.index).split('\n').length;
// Special handling for Go multi-line imports
if (language === 'go' && modulePath.includes('\n')) {
// Split multi-line import block into individual imports
const lines = modulePath.split('\n');
for (const line of lines) {
const trimmed = line.trim();
// Extract quoted string from each line
const importMatch = trimmed.match(/^["']([^"']+)["']$/);
if (importMatch) {
const importPath = importMatch[1];
if (importPath && !imports.find(i => i.from === importPath)) {
imports.push({
from: importPath,
type: 'named',
names: [],
line: lineNumber,
});
}
}
}
}
else if (modulePath && !imports.find(i => i.from === modulePath)) {
imports.push({
from: modulePath,
type: 'named', // Simplified
names: [],
line: lineNumber,
});
}
}
}
return imports;
}
/**
* Extract function definitions using regex patterns
*/
function extractFunctions(content, language) {
const functions = [];
const patterns = FUNCTION_PATTERNS[language] || [];
const lines = content.split('\n');
for (const pattern of patterns) {
let match;
while ((match = pattern.exec(content)) !== null) {
const name = match[1];
if (name) {
// Find line number
const beforeMatch = content.substring(0, match.index);
const lineNumber = beforeMatch.split('\n').length;
// Check if exported (simple heuristic)
const lineContent = lines[lineNumber - 1] || '';
const isExported = /export|public/.test(lineContent);
functions.push({
name,
isExported,
lineStart: lineNumber,
lineEnd: lineNumber + 10, // Estimate
});
}
}
}
return functions;
}
/**
* Extract API endpoints using regex patterns
*/
function extractApiEndpoints(content, language) {
const endpoints = [];
const patterns = API_ENDPOINT_PATTERNS[language] || [];
for (const pattern of patterns) {
let match;
while ((match = pattern.exec(content)) !== null) {
const method = (match[1] || 'GET').toUpperCase();
const path = match[2] || match[1];
if (path && !path.startsWith('@')) {
endpoints.push({
method,
path,
line: content.substring(0, match.index).split('\n').length,
fileId: 0, // Will be set during storage
});
}
}
}
return endpoints;
}
/**
* Extract API calls using regex patterns
*/
function extractApiCalls(content) {
const calls = [];
for (const pattern of API_CALL_PATTERNS) {
let match;
while ((match = pattern.exec(content)) !== null) {
const method = (match[1] || 'GET').toUpperCase();
const url = match[2] || match[1];
if (url) {
calls.push({
method,
url,
line: content.substring(0, match.index).split('\n').length,
});
}
}
}
return calls;
}
/**
* Analyze a file using universal regex-based parsing
*/
export async function analyzeFileUniversal(filePath, fileType) {
try {
const content = await fs.readFile(filePath, 'utf-8');
const language = detectLanguage(filePath);
const lines = getLineCount(filePath);
const type = fileType || determineFileType(filePath, content);
return {
filePath,
type,
lines,
imports: extractImports(content, language),
exports: [], // Simplified for universal parsing
functions: extractFunctions(content, language),
apiEndpoints: extractApiEndpoints(content, language),
apiCalls: extractApiCalls(content),
};
}
catch (error) {
// Return empty analysis on error
return {
filePath,
type: 'other',
lines: 0,
imports: [],
exports: [],
functions: [],
apiEndpoints: [],
apiCalls: [],
};
}
}
//# sourceMappingURL=universal-analyzer.js.map