UNPKG

agentsqripts

Version:

Comprehensive static code analysis toolkit for identifying technical debt, security vulnerabilities, performance issues, and code quality problems

148 lines (132 loc) 4.98 kB
/** * @file Frontend-Backend Integration Analysis orchestrator * @description Single responsibility: Coordinate comprehensive integration mismatch detection * * This analyzer identifies integration issues between frontend and backend code by comparing * API endpoint definitions with frontend API calls. It detects missing endpoints, unused * endpoints, and route mismatches to prevent integration failures in production. * * Design rationale: * - Cross-layer analysis prevents runtime integration failures * - Route normalization enables consistent comparison across different coding styles * - Specialized extractors handle framework-specific patterns (Express, React, etc.) * - Comprehensive detection covers both unused and missing endpoint scenarios */ const fs = require('fs'); const path = require('path'); const { analyzeProjectIntegration } = require('./frontendBackendProjectAnalyzer'); const { extractBackendEndpoints } = require('./backendEndpointExtractor'); const { extractFrontendCalls } = require('./frontendApiCallExtractor'); const { detectMissingEndpoints } = require('./missingEndpointDetector'); const { detectUnusedEndpoints } = require('./unusedEndpointDetector'); /** * Normalize route paths for consistent comparison across frontend and backend * * Technical function: Standardizes route formats for accurate integration analysis * * Implementation rationale: * - Query parameter removal focuses comparison on route structure * - Trailing slash normalization handles different framework conventions * - Case normalization prevents false mismatches due to casing differences * - Parameter replacement enables matching dynamic routes * * Normalization strategy: * - Remove query parameters (?key=value) to focus on route structure * - Remove trailing slashes except for root route * - Convert to lowercase for case-insensitive comparison * - Replace dynamic parameters (/users/:id) with generic placeholder * * @param {string} route - Route path to normalize * @returns {string} Normalized route */ function normalizeRoute(route) { if (!route || typeof route !== 'string') { return '/'; } // Remove query parameters const cleanRoute = route.split('?')[0]; // Remove trailing slash const noTrailingSlash = cleanRoute.replace(/\/$/, '') || '/'; // Convert to lowercase const lowercase = noTrailingSlash.toLowerCase(); // Replace dynamic parameters with :param const normalized = lowercase.replace(/\/:[^\/]+/g, '/:param'); return normalized; } /** * Analyze frontend-backend integration issues * @param {string} target - Project directory path * @param {Object} options - Analysis options * @returns {Object} Integration analysis results */ function analyzeFrontendBackend(target, options = {}) { return analyzeProjectIntegration(target, options); } /** * Extract frontend API calls from file paths * @param {Array<string>} filePaths - Array of frontend file paths to analyze * @returns {Array<Object>} Array of frontend API calls */ async function extractFrontendCallsFromFiles(filePaths) { const calls = []; for (const filePath of filePaths) { try { const content = await fs.promises.readFile(filePath, 'utf8'); const lines = content.split('\n'); lines.forEach((line, index) => { // Look for fetch() calls const fetchMatch = line.match(/fetch\s*\(\s*['"`]([^'"`]+)['"`]/); if (fetchMatch) { calls.push({ type: 'fetch', route: fetchMatch[1], url: fetchMatch[1], method: extractMethodFromFetch(line), line: index + 1, file: filePath }); } // Look for axios calls const axiosMatch = line.match(/axios\.(\w+)\s*\(\s*['"`]([^'"`]+)['"`]/); if (axiosMatch) { calls.push({ type: 'axios', method: axiosMatch[1].toUpperCase(), route: axiosMatch[2], url: axiosMatch[2], line: index + 1, file: filePath }); } // Look for XMLHttpRequest calls const xhrMatch = line.match(/\.open\s*\(\s*['"`](\w+)['"`]\s*,\s*['"`]([^'"`]+)['"`]/); if (xhrMatch) { calls.push({ type: 'xhr', method: xhrMatch[1].toUpperCase(), route: xhrMatch[2], url: xhrMatch[2], line: index + 1, file: filePath }); } }); } catch (error) { // Skip files that can't be read } } return calls; } function extractMethodFromFetch(line) { const methodMatch = line.match(/method\s*:\s*['"`](\w+)['"`]/); return methodMatch ? methodMatch[1].toUpperCase() : 'GET'; } module.exports = { analyzeFrontendBackend, analyzeProjectIntegration, extractBackendEndpoints, extractFrontendCalls, detectMissingEndpoints, detectUnusedEndpoints, normalizeRoute };