arela
Version:
AI-powered CTO with multi-agent orchestration, code summarization, visual testing (web + mobile) for blazing fast development.
145 lines • 5.41 kB
JavaScript
/**
* Multi-repo coordination - handles analysis across multiple repositories
* Particularly focuses on API contract matching between frontend and backend
*/
/**
* Detect API calls in frontend code (fetch, axios, etc.)
*/
export function detectApiCalls(imports, files) {
const apiCalls = [];
// Patterns for API calls
const apiPatterns = [
/fetch\s*\(\s*['"`]([^'"`]+)['")`]/g,
/axios\.(get|post|put|delete|patch)\s*\(\s*['"`]([^'"`]+)['")`]/g,
/\.get\s*\(\s*['"`]([^'"`]+)['")`]/g,
/\.post\s*\(\s*['"`]([^'"`]+)['")`]/g,
/\.request\s*\(\s*['"`]([^'"`]+)['")`]/g,
];
// This is a simplified detection - in production would use AST parsing
// For now, we'll return empty as actual implementation requires content scanning
return apiCalls;
}
/**
* Detect API endpoints in backend code (Express, Fastify, etc.)
*/
export function detectApiEndpoints(files) {
const endpoints = [];
// Patterns for common backend frameworks
const endpointPatterns = [
/app\.(get|post|put|delete|patch)\s*\(\s*['"`]([^'"`]+)['")`]/g,
/router\.(get|post|put|delete|patch)\s*\(\s*['"`]([^'"`]+)['")`]/g,
];
// This is a simplified detection - would use AST parsing in production
return endpoints;
}
/**
* Match API calls to endpoints and detect drift
*/
export function matchApiCalls(frontendCalls, backendEndpoints) {
const driftResults = [];
const matchedEndpoints = new Set();
for (const call of frontendCalls) {
const callSignature = `${call.method.toUpperCase()} ${call.url}`;
// Look for exact match
const exactMatch = backendEndpoints.find(ep => `${ep.method.toUpperCase()} ${ep.path}` === callSignature);
if (exactMatch) {
matchedEndpoints.add(`${exactMatch.method} ${exactMatch.path}`);
driftResults.push({
frontendCall: callSignature,
backendEndpoint: `${exactMatch.method} ${exactMatch.path}`,
match: "exact",
file: call.file,
line: call.line,
});
continue;
}
// Look for partial match (same path, different method or similar)
const partialMatch = backendEndpoints.find(ep => ep.path === call.url ||
ep.path === `/${call.url}` ||
ep.path === call.url.replace(/^\//, "") ||
normalizeUrl(ep.path) === normalizeUrl(call.url));
if (partialMatch) {
matchedEndpoints.add(`${partialMatch.method} ${partialMatch.path}`);
driftResults.push({
frontendCall: callSignature,
backendEndpoint: `${partialMatch.method} ${partialMatch.path}`,
match: "partial",
file: call.file,
line: call.line,
});
continue;
}
// No match found
driftResults.push({
frontendCall: callSignature,
backendEndpoint: undefined,
match: "missing",
file: call.file,
line: call.line,
});
}
return driftResults;
}
/**
* Normalize API URLs for comparison
*/
function normalizeUrl(url) {
return url
.toLowerCase()
.replace(/^\/+/, "") // Remove leading slashes
.replace(/\/+$/, "") // Remove trailing slashes
.replace(/\/:(\w+)/g, "/:id") // Normalize IDs
.replace(/\?.*$/, ""); // Remove query params
}
/**
* Calculate API drift percentage
*/
export function calculateApiDriftPercentage(driftResults) {
if (driftResults.length === 0) {
return 0;
}
const missingCount = driftResults.filter(d => d.match === "missing").length;
return Math.round((missingCount / driftResults.length) * 100);
}
/**
* Get unimplemented endpoints (backend endpoints not called by frontend)
*/
export function getUnimplementedEndpoints(frontendCalls, backendEndpoints) {
const calledEndpoints = new Set();
for (const call of frontendCalls) {
for (const endpoint of backendEndpoints) {
if (normalizeUrl(`${endpoint.method} ${endpoint.path}`) ===
normalizeUrl(call.url)) {
calledEndpoints.add(`${endpoint.method} ${endpoint.path}`);
}
}
}
return backendEndpoints.filter(ep => !calledEndpoints.has(`${ep.method} ${ep.path}`));
}
export function analyzeRepoRelationships(repoAnalyses) {
const relationships = [];
// Find frontend and backend repos
const frontendRepos = repoAnalyses.filter(r => r.name.includes("mobile") ||
r.name.includes("web") ||
r.name.includes("client") ||
r.name.includes("frontend"));
const backendRepos = repoAnalyses.filter(r => r.name.includes("backend") ||
r.name.includes("server") ||
r.name.includes("api") ||
r.name.includes("service"));
// Create relationships
for (const frontend of frontendRepos) {
for (const backend of backendRepos) {
relationships.push({
frontendRepo: frontend.name,
backendRepo: backend.name,
apiCallCount: 0, // Will be populated during analysis
matchedEndpoints: 0,
driftPercentage: 0,
criticalMismatches: 0,
});
}
}
return relationships;
}
//# sourceMappingURL=multi-repo.js.map