sicua
Version:
A tool for analyzing project structure and dependencies
1,300 lines (1,299 loc) • 51.6 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.BusinessLogicExtractor = void 0;
const ImportExtractor_1 = require("./ImportExtractor");
const FunctionExtractor_1 = require("./FunctionExtractor");
const ComponentExtractor_1 = require("./ComponentExtractor");
const TypeExtractor_1 = require("./TypeExtractor");
class BusinessLogicExtractor {
constructor(sourceFile, content, filePath, srcDir, typeChecker) {
this.sourceFile = sourceFile;
this.content = content;
this.filePath = filePath;
this.importExtractor = new ImportExtractor_1.ImportExtractor(srcDir);
this.functionExtractor = new FunctionExtractor_1.FunctionExtractor(sourceFile, content);
this.componentExtractor = new ComponentExtractor_1.ComponentExtractor(sourceFile, content, filePath, srcDir, typeChecker);
this.typeExtractor = new TypeExtractor_1.TypeExtractor(typeChecker);
}
/**
* Extracts business logic context from the source file
*/
extractBusinessLogicContext() {
const domain = this.identifyDomain();
const operations = this.extractBusinessOperations();
const dataFlow = this.extractDataFlowPatterns();
const sideEffects = this.extractSideEffects();
return {
domain,
operations,
dataFlow,
sideEffects,
};
}
/**
* Extracts complete business logic definition
*/
extractBusinessLogicDefinition() {
const functionContext = this.functionExtractor.extractFunctionContext();
const componentContext = this.componentExtractor.extractComponentContext();
const typeContext = this.typeExtractor.extractTypeContext(this.sourceFile);
const dependencyContext = this.importExtractor.extractDependencies(this.sourceFile, this.filePath);
const domain = this.identifyDomain();
const operations = this.extractBusinessOperations();
const dataFlow = this.extractDataFlowPatterns();
const sideEffects = this.extractSideEffects();
const complexity = this.calculateBusinessComplexity(functionContext, operations, dataFlow);
const patterns = this.analyzeBusinessPatterns(functionContext, componentContext, operations);
const quality = this.assessBusinessQuality(operations, complexity, patterns);
const dependencies = this.extractBusinessDependencies(dependencyContext);
const rules = this.extractBusinessRules();
const workflows = this.extractWorkflows();
const validations = this.extractValidations();
const transformations = this.extractDataTransformations();
return {
domain,
operations,
dataFlow,
sideEffects,
complexity,
patterns,
quality,
dependencies,
rules,
workflows,
validations,
transformations,
};
}
/**
* **FIXED: Enhanced domain identification with better logic and priority**
* Identifies the business domain based on file content and structure
*/
identifyDomain() {
const fileName = this.filePath.toLowerCase();
const content = this.content.toLowerCase();
// **PRIORITY 1: File path and name analysis (most reliable)**
const pathSegments = this.filePath.toLowerCase().split(/[/\\]/);
// Check directory structure for domain hints
for (const segment of pathSegments) {
if (segment === "auth" || segment === "authentication")
return "auth";
if (segment === "payment" || segment === "billing")
return "payment";
if (segment === "report" || segment === "reports")
return "report-management";
if (segment === "diagram" || segment === "diagrams")
return "diagram-analysis";
if (segment === "analytics" || segment === "analysis")
return "analytics";
if (segment === "project" || segment === "projects")
return "project-management";
if (segment === "file" || segment === "files")
return "file-management";
if (segment === "user" || segment === "users")
return "user-management";
if (segment === "notification" || segment === "notifications")
return "communication";
}
// **PRIORITY 2: Filename analysis with weighted scoring**
const fileNameBase = fileName.replace(/\.(tsx?|jsx?)$/, "");
// Domain patterns with confidence scores
const domainPatterns = {
"diagram-analysis": {
keywords: ["diagram", "chart", "graph", "visual", "viewer", "analysis"],
weight: 3,
},
"report-management": {
keywords: [
"report",
"analytics",
"metrics",
"data",
"score",
"breakdown",
],
weight: 3,
},
"project-management": {
keywords: ["project", "slot", "workspace", "portfolio"],
weight: 3,
},
"file-management": {
keywords: ["upload", "download", "file", "storage", "document"],
weight: 3,
},
auth: {
keywords: ["auth", "login", "signup", "user", "account", "session"],
weight: 2, // Lower weight unless very specific
},
payment: {
keywords: [
"payment",
"billing",
"invoice",
"checkout",
"order",
"stripe",
"paypal",
],
weight: 3,
},
inventory: {
keywords: ["inventory", "product", "catalog", "stock", "item"],
weight: 3,
},
communication: {
keywords: ["notification", "email", "message", "chat", "alert"],
weight: 2,
},
workflow: {
keywords: ["workflow", "process", "step", "approval", "pipeline"],
weight: 2,
},
configuration: {
keywords: ["config", "setting", "preference", "option", "setup"],
weight: 2,
},
search: {
keywords: ["search", "filter", "query", "index", "find"],
weight: 2,
},
};
// **PRIORITY 3: Content analysis with context**
const domainScores = {};
for (const [domain, config] of Object.entries(domainPatterns)) {
let score = 0;
// Filename matches
for (const keyword of config.keywords) {
if (fileNameBase.includes(keyword)) {
score += config.weight * 2; // Filename matches are strong indicators
}
}
// Content matches (but with context)
for (const keyword of config.keywords) {
const regex = new RegExp(`\\b${keyword}\\b`, "gi");
const matches = content.match(regex);
if (matches) {
// Weight by frequency but cap to avoid false positives
score += Math.min(matches.length * config.weight * 0.5, config.weight * 3);
}
}
domainScores[domain] = score;
}
// **PRIORITY 4: Context-aware analysis**
// Look for specific patterns that indicate domain
// For DiagramViewer specifically - look for component orchestration patterns
if (fileNameBase.includes("viewer") ||
fileNameBase.includes("controller")) {
if (content.includes("diagram") ||
content.includes("chart") ||
content.includes("analysis")) {
domainScores["diagram-analysis"] =
(domainScores["diagram-analysis"] || 0) + 10;
}
if (content.includes("report") ||
content.includes("score") ||
content.includes("metrics")) {
domainScores["report-management"] =
(domainScores["report-management"] || 0) + 10;
}
}
// API integration patterns
if (content.includes("usesavereport") ||
content.includes("reportmutation")) {
domainScores["report-management"] =
(domainScores["report-management"] || 0) + 8;
}
if (content.includes("uploadfile") || content.includes("fileupload")) {
domainScores["file-management"] =
(domainScores["file-management"] || 0) + 8;
}
if (content.includes("projectslot") || content.includes("projectname")) {
domainScores["project-management"] =
(domainScores["project-management"] || 0) + 8;
}
// **PRIORITY 5: Business logic pattern analysis**
if (content.includes("validate") &&
content.includes("rule") &&
content.includes("policy")) {
domainScores["validation"] = (domainScores["validation"] || 0) + 5;
}
if (content.includes("calculate") &&
content.includes("compute") &&
content.includes("formula")) {
domainScores["calculation"] = (domainScores["calculation"] || 0) + 5;
}
if (content.includes("workflow") &&
content.includes("process") &&
content.includes("step")) {
domainScores["workflow"] = (domainScores["workflow"] || 0) + 5;
}
// **FIND HIGHEST SCORING DOMAIN**
let bestDomain = "general";
let bestScore = 0;
for (const [domain, score] of Object.entries(domainScores)) {
if (score > bestScore && score >= 3) {
// Minimum threshold
bestScore = score;
bestDomain = domain;
}
}
// **FALLBACK ANALYSIS**
if (bestDomain === "general") {
// If no clear domain, try to infer from component type
if (fileNameBase.includes("component") || fileNameBase.includes("view")) {
if (content.includes("user") && content.includes("interface")) {
return "user-interface";
}
if (content.includes("data") && content.includes("display")) {
return "data-presentation";
}
}
// Generic business logic patterns
if (content.includes("business") && content.includes("logic")) {
return "business-logic";
}
}
return bestDomain;
}
/**
* Extracts business operations from functions
*/
extractBusinessOperations() {
const functionContext = this.functionExtractor.extractFunctionContext();
const operations = [];
// Add defensive check
const functions = functionContext?.functions || [];
functions.forEach((func) => {
if (this.isBusinessOperation(func)) {
const operation = this.buildBusinessOperation(func);
operations.push(operation);
}
});
return operations;
}
/**
* Determines if a function represents a business operation
*/
isBusinessOperation(func) {
// Skip simple utility functions
if (func.complexity.level === "low" &&
func.signature.parameters.length === 0) {
return false;
}
// Skip React-specific functions
if (func.reactSpecific?.isComponent || func.reactSpecific?.isHook) {
return false;
}
// Look for business logic patterns
const businessPatterns = [
"business-logic",
"data-transformation",
"validation",
"api-integration",
];
return func.patterns.some((pattern) => businessPatterns.includes(pattern));
}
/**
* Builds a business operation from a function definition
*/
buildBusinessOperation(func) {
const name = func.name;
const purpose = this.determinePurpose(func);
const complexity = this.mapComplexityLevel(func.complexity.level);
const inputs = func.signature.parameters.map((p) => p.name);
const outputs = [func.signature.returnType];
return {
name,
purpose,
complexity,
inputs,
outputs,
};
}
/**
* Extracts data flow patterns
*/
extractDataFlowPatterns() {
const patterns = [];
const content = this.content;
// State management patterns
if (content.includes("useState") ||
content.includes("useReducer") ||
content.includes("redux")) {
patterns.push({
pattern: "state-management",
description: "Manages application state",
triggers: this.extractStateManagementTriggers(),
});
}
// Data fetching patterns
if (content.includes("fetch") ||
content.includes("axios") ||
content.includes("useSWR") ||
content.includes("useQuery")) {
patterns.push({
pattern: "data-fetching",
description: "Fetches data from external sources",
triggers: this.extractDataFetchingTriggers(),
});
}
// Event handling patterns
if (content.includes("onClick") ||
content.includes("onChange") ||
content.includes("addEventListener")) {
patterns.push({
pattern: "event-handling",
description: "Handles user interactions and events",
triggers: this.extractEventHandlingTriggers(),
});
}
// Side effect patterns
if (content.includes("useEffect") || content.includes("useLayoutEffect")) {
patterns.push({
pattern: "side-effect",
description: "Manages side effects and lifecycle",
triggers: this.extractSideEffectTriggers(),
});
}
// Computation patterns
if (content.includes("useMemo") ||
content.includes("calculate") ||
content.includes("compute")) {
patterns.push({
pattern: "computation",
description: "Performs calculations and data processing",
triggers: this.extractComputationTriggers(),
});
}
return patterns;
}
/**
* Extracts side effects
*/
extractSideEffects() {
const functionContext = this.functionExtractor.extractFunctionContext();
const sideEffects = [];
functionContext.functions.forEach((func) => {
func.sideEffects.forEach((effect) => {
// Map function side effect types to business logic side effect types
let mappedType;
switch (effect.type) {
case "console":
mappedType = "external-service"; // Map console to external-service
break;
case "file-system":
mappedType = "external-service"; // Map file-system to external-service
break;
default:
mappedType = effect.type;
}
sideEffects.push({
type: mappedType,
description: effect.description,
conditions: ["function execution"],
});
});
});
// Additional side effect detection
if (this.content.includes("localStorage") ||
this.content.includes("sessionStorage")) {
sideEffects.push({
type: "storage",
description: "Accesses browser storage",
conditions: ["user interaction", "data persistence"],
});
}
if (this.content.includes("window.location") ||
this.content.includes("router.push")) {
sideEffects.push({
type: "navigation",
description: "Navigates to different routes",
conditions: ["user action", "business logic"],
});
}
return sideEffects;
}
/**
* Calculates business complexity
*/
calculateBusinessComplexity(functionContext, operations, dataFlow) {
const operationalComplexity = this.calculateOperationalComplexity(operations);
const dataComplexity = this.calculateDataComplexity(dataFlow);
const logicalComplexity = this.calculateLogicalComplexity(functionContext);
const integrationComplexity = this.calculateIntegrationComplexity();
const totalComplexity = operationalComplexity +
dataComplexity +
logicalComplexity +
integrationComplexity;
let overallComplexity;
if (totalComplexity > 15)
overallComplexity = "very-high";
else if (totalComplexity > 10)
overallComplexity = "high";
else if (totalComplexity > 5)
overallComplexity = "medium";
else
overallComplexity = "low";
const complexityFactors = this.identifyComplexityFactors(operationalComplexity, dataComplexity, logicalComplexity, integrationComplexity);
return {
operationalComplexity,
dataComplexity,
logicalComplexity,
integrationComplexity,
overallComplexity,
complexityFactors,
};
}
/**
* Analyzes business patterns
*/
analyzeBusinessPatterns(functionContext, componentContext, operations) {
const architecturalPatterns = this.identifyArchitecturalPatterns();
const domainPatterns = this.identifyDomainPatterns(operations);
const dataPatterns = this.identifyDataPatterns();
const integrationPatterns = this.identifyIntegrationPatterns();
const antiPatterns = this.identifyBusinessAntiPatterns(functionContext, operations);
return {
architecturalPatterns,
domainPatterns,
dataPatterns,
integrationPatterns,
antiPatterns,
};
}
/**
* Assesses business quality
*/
assessBusinessQuality(operations, complexity, patterns) {
const maintainability = this.calculateMaintainability(complexity, patterns);
const testability = this.calculateTestability(operations);
const reusability = this.calculateReusability(operations, patterns);
const reliability = this.calculateReliability(patterns);
const performance = this.calculatePerformance(complexity, patterns);
const security = this.calculateSecurity(patterns);
const overallScore = (maintainability +
testability +
reusability +
reliability +
performance +
security) /
6;
const qualityIssues = this.identifyQualityIssues(complexity, patterns);
return {
maintainability,
testability,
reusability,
reliability,
performance,
security,
overallScore,
qualityIssues,
};
}
/**
* Extracts business dependencies
*/
extractBusinessDependencies(dependencyContext) {
const externalServices = this.identifyExternalServices(dependencyContext);
const databases = this.identifyDatabaseDependencies();
const apis = this.identifyApiDependencies();
const libraries = this.identifyLibraryDependencies(dependencyContext);
const configurations = this.identifyConfigurationDependencies();
const resources = this.identifyResourceDependencies();
return {
externalServices,
databases,
apis,
libraries,
configurations,
resources,
};
}
/**
* Extracts business rules
*/
extractBusinessRules() {
const rules = [];
const content = this.content;
// Look for validation rules
const validationPattern = /if\s*\([^)]*(?:validate|check|verify)[^)]*\)/gi;
let match;
let ruleId = 1;
while ((match = validationPattern.exec(content)) !== null) {
rules.push({
id: `rule_${ruleId++}`,
name: `Validation Rule ${ruleId - 1}`,
type: "validation",
condition: match[0],
action: "Validate input",
priority: "medium",
domain: this.identifyDomain(),
implementation: {
method: "imperative",
location: this.filePath,
testable: true,
configurable: false,
},
validation: {
hasTests: false,
coverage: 0,
scenarios: [],
},
});
}
// Look for calculation rules
const calculationPattern = /(?:calculate|compute|total|sum|price|cost|tax)/gi;
if (calculationPattern.test(content)) {
rules.push({
id: `rule_${ruleId++}`,
name: "Calculation Rule",
type: "calculation",
condition: "When calculation is needed",
action: "Perform calculation",
priority: "high",
domain: this.identifyDomain(),
implementation: {
method: "imperative",
location: this.filePath,
testable: true,
configurable: false,
},
validation: {
hasTests: false,
coverage: 0,
scenarios: [],
},
});
}
return rules;
}
/**
* Extracts workflows
*/
extractWorkflows() {
const workflows = [];
// Look for async workflow patterns
if (this.content.includes("async") && this.content.includes("await")) {
const steps = this.extractWorkflowSteps();
const triggers = this.extractWorkflowTriggers();
const conditions = this.extractWorkflowConditions();
const outcomes = this.extractWorkflowOutcomes();
const errorHandling = this.extractErrorHandlingStrategies();
workflows.push({
name: "Async Workflow",
steps,
triggers,
conditions,
outcomes,
complexity: steps.length > 5
? "complex"
: steps.length > 2
? "moderate"
: "simple",
async: true,
errorHandling,
});
}
return workflows;
}
/**
* Extracts validations
*/
extractValidations() {
const validations = [];
const content = this.content;
// Look for form validation patterns
const fieldPattern = /(\w+):\s*(?:yup|joi|z)\./g;
let match;
while ((match = fieldPattern.exec(content)) !== null) {
const field = match[1];
const rules = this.extractValidationRules(field);
const messages = this.extractValidationMessages(field);
const dependencies = this.extractValidationDependencies(field);
const customValidators = this.extractCustomValidators(field);
validations.push({
field,
rules,
messages,
async: content.includes(`${field}Async`) ||
content.includes(`async.*${field}`),
dependencies,
customValidators,
});
}
return validations;
}
/**
* Extracts data transformations
*/
extractDataTransformations() {
const transformations = [];
const content = this.content;
// Look for transformation patterns
const transformPatterns = [
{ pattern: /\.map\(/g, type: "mapping" },
{ pattern: /\.filter\(/g, type: "filtering" },
{ pattern: /\.reduce\(/g, type: "aggregation" },
{ pattern: /\.sort\(/g, type: "sorting" },
{
pattern: /normalize|transform/gi,
type: "normalization",
},
];
transformPatterns.forEach(({ pattern, type }) => {
const matches = content.match(pattern);
if (matches && matches.length > 0) {
transformations.push({
name: `${type} transformation`,
input: this.createGenericDataStructure("input"),
output: this.createGenericDataStructure("output"),
transformationType: type,
complexity: this.determineTransformationComplexity(type, matches.length),
performance: this.analyzeTransformationPerformance(type),
validation: this.analyzeTransformationValidation(type),
});
}
});
return transformations;
}
// Helper methods for business logic analysis
determinePurpose(func) {
const name = func.name.toLowerCase();
const content = this.content.toLowerCase();
if (name.includes("validate") || name.includes("check"))
return "Validates input data";
if (name.includes("calculate") || name.includes("compute"))
return "Performs calculations";
if (name.includes("transform") || name.includes("convert"))
return "Transforms data";
if (name.includes("process") || name.includes("handle"))
return "Processes business logic";
if (name.includes("save") || name.includes("update"))
return "Persists data";
if (name.includes("fetch") || name.includes("get"))
return "Retrieves data";
if (name.includes("send") || name.includes("notify"))
return "Sends notifications";
return "Handles business operations";
}
mapComplexityLevel(level) {
if (level === "very-high" || level === "high")
return "high";
if (level === "medium")
return "medium";
return "low";
}
extractStateManagementTriggers() {
const triggers = [];
if (this.content.includes("onClick"))
triggers.push("user click");
if (this.content.includes("onChange"))
triggers.push("input change");
if (this.content.includes("useEffect"))
triggers.push("component lifecycle");
if (this.content.includes("dispatch"))
triggers.push("action dispatch");
return triggers;
}
extractDataFetchingTriggers() {
const triggers = [];
if (this.content.includes("useEffect"))
triggers.push("component mount");
if (this.content.includes("onClick"))
triggers.push("user interaction");
if (this.content.includes("onSubmit"))
triggers.push("form submission");
if (this.content.includes("interval"))
triggers.push("timer");
return triggers;
}
extractEventHandlingTriggers() {
const triggers = [];
const eventPatterns = this.content.match(/on[A-Z]\w+/g) || [];
return eventPatterns.map((pattern) => pattern.replace(/^on/, "").toLowerCase());
}
extractSideEffectTriggers() {
const triggers = [];
if (this.content.includes("[]"))
triggers.push("component mount");
if (this.content.includes("["))
triggers.push("dependency change");
return triggers;
}
extractComputationTriggers() {
const triggers = [];
if (this.content.includes("useMemo"))
triggers.push("dependency change");
if (this.content.includes("calculate"))
triggers.push("data change");
return triggers;
}
calculateOperationalComplexity(operations) {
return operations.reduce((total, op) => {
const complexityScores = { low: 1, medium: 2, high: 3, "very-high": 4 };
return total + (complexityScores[op.complexity] || 1);
}, 0);
}
calculateDataComplexity(dataFlow) {
const complexityMap = {
"state-management": 3,
"data-fetching": 2,
"event-handling": 1,
"side-effect": 2,
computation: 2,
};
return dataFlow.reduce((total, pattern) => {
return total + (complexityMap[pattern.pattern] || 1);
}, 0);
}
calculateLogicalComplexity(functionContext) {
if (!functionContext.functions)
return 0;
return functionContext.functions.reduce((total, func) => {
return total + func.complexity.cyclomaticComplexity;
}, 0);
}
calculateIntegrationComplexity() {
let complexity = 0;
const content = this.content;
// External API calls
if (content.includes("fetch") || content.includes("axios"))
complexity += 2;
// Database operations
if (content.includes("query") || content.includes("sql"))
complexity += 2;
// Third-party services
if (content.includes("stripe") || content.includes("paypal"))
complexity += 1;
// Authentication services
if (content.includes("auth") || content.includes("jwt"))
complexity += 1;
return complexity;
}
identifyComplexityFactors(operational, data, logical, integration) {
const factors = [];
if (operational > 5) {
factors.push({
factor: "High operational complexity",
impact: operational,
description: "Multiple complex business operations",
mitigation: "Consider breaking down operations into smaller functions",
});
}
if (data > 5) {
factors.push({
factor: "Complex data flow",
impact: data,
description: "Multiple data flow patterns and transformations",
mitigation: "Implement data flow optimization and caching",
});
}
if (logical > 10) {
factors.push({
factor: "High logical complexity",
impact: logical,
description: "High cyclomatic complexity in functions",
mitigation: "Refactor complex functions and reduce branching",
});
}
if (integration > 3) {
factors.push({
factor: "Multiple integrations",
impact: integration,
description: "Dependencies on multiple external services",
mitigation: "Implement circuit breakers and fallback mechanisms",
});
}
return factors;
}
identifyArchitecturalPatterns() {
const patterns = [];
const content = this.content;
// Repository pattern
if (content.includes("repository") || content.includes("Repository")) {
patterns.push({
name: "Repository Pattern",
confidence: 0.8,
evidence: ["Repository class or interface found"],
benefits: ["Data access abstraction", "Testability"],
drawbacks: ["Additional complexity layer"],
});
}
// Strategy pattern
if (content.includes("strategy") || content.includes("Strategy")) {
patterns.push({
name: "Strategy Pattern",
confidence: 0.7,
evidence: ["Strategy interface or implementation"],
benefits: ["Runtime algorithm selection", "Extensibility"],
drawbacks: ["Increased number of classes"],
});
}
// Observer pattern
if (content.includes("observer") || content.includes("subscribe")) {
patterns.push({
name: "Observer Pattern",
confidence: 0.7,
evidence: ["Observer or subscription mechanism"],
benefits: ["Loose coupling", "Event-driven architecture"],
drawbacks: ["Potential memory leaks", "Complex debugging"],
});
}
return patterns;
}
identifyDomainPatterns(operations) {
const patterns = [];
const domain = this.identifyDomain();
// CRUD pattern
const crudOperations = operations.filter((op) => ["create", "read", "update", "delete"].some((crud) => op.name.toLowerCase().includes(crud)));
if (crudOperations.length >= 3) {
patterns.push({
name: "CRUD Pattern",
domain,
usage: `${crudOperations.length} CRUD operations implemented`,
effectiveness: crudOperations.length === 4 ? "high" : "medium",
});
}
// Validation pattern
const validationOperations = operations.filter((op) => op.name.toLowerCase().includes("validate") ||
op.purpose.includes("validate"));
if (validationOperations.length > 0) {
patterns.push({
name: "Validation Pattern",
domain,
usage: `${validationOperations.length} validation operations`,
effectiveness: validationOperations.length > 2 ? "high" : "medium",
});
}
return patterns;
}
identifyDataPatterns() {
const patterns = [];
const content = this.content;
// Caching pattern
if (content.includes("cache") ||
content.includes("useMemo") ||
content.includes("useCallback")) {
patterns.push({
pattern: "Caching",
usage: {
reads: this.countOccurrences(content, /\.get\(/g),
writes: this.countOccurrences(content, /\.set\(/g),
transforms: this.countOccurrences(content, /\.map\(|\.filter\(|\.reduce\(/g),
caching: true,
},
optimization: ["Memory optimization", "Performance improvement"],
issues: [],
});
}
// Transformation pattern
const transformCount = this.countOccurrences(content, /\.map\(|\.filter\(|\.reduce\(/g);
if (transformCount > 0) {
patterns.push({
pattern: "Data Transformation",
usage: {
reads: transformCount,
writes: 0,
transforms: transformCount,
caching: false,
},
optimization: transformCount > 5 ? ["Consider memoization"] : [],
issues: transformCount > 10 ? ["High transformation complexity"] : [],
});
}
return patterns;
}
identifyIntegrationPatterns() {
const patterns = [];
const content = this.content;
// REST API pattern
if (content.includes("fetch") ||
content.includes("axios") ||
content.includes("api")) {
patterns.push({
pattern: "REST API Integration",
services: this.extractApiEndpoints(),
reliability: this.assessApiReliability(),
performance: this.assessApiPerformance(),
});
}
// WebSocket pattern
if (content.includes("websocket") || content.includes("socket.io")) {
patterns.push({
pattern: "WebSocket Integration",
services: ["Real-time service"],
reliability: "medium",
performance: "fast",
});
}
return patterns;
}
identifyBusinessAntiPatterns(functionContext, operations) {
const antiPatterns = [];
// God function anti-pattern
if (functionContext.functions) {
const complexFunctions = functionContext.functions.filter((f) => f.complexity.cyclomaticComplexity > 10);
complexFunctions.forEach((func) => {
antiPatterns.push({
name: "God Function",
severity: "high",
description: `Function ${func.name} has high cyclomatic complexity (${func.complexity.cyclomaticComplexity})`,
impact: "Reduced maintainability and testability",
solution: "Break down into smaller, focused functions",
location: this.filePath,
});
});
}
// Duplicate business logic
const operationNames = operations.map((op) => op.name.toLowerCase());
const duplicates = operationNames.filter((name, index) => operationNames.indexOf(name) !== index);
if (duplicates.length > 0) {
antiPatterns.push({
name: "Duplicate Business Logic",
severity: "medium",
description: "Similar operations found that could be consolidated",
impact: "Code duplication and maintenance overhead",
solution: "Extract common logic into reusable functions",
location: this.filePath,
});
}
return antiPatterns;
}
calculateMaintainability(complexity, patterns) {
let score = 100;
// Deduct for complexity
const complexityPenalty = {
low: 0,
medium: 10,
high: 25,
"very-high": 40,
};
score -= complexityPenalty[complexity.overallComplexity];
// Deduct for anti-patterns
patterns.antiPatterns.forEach((antiPattern) => {
const penalties = { low: 5, medium: 10, high: 20, critical: 30 };
score -= penalties[antiPattern.severity];
});
return Math.max(0, score);
}
calculateTestability(operations) {
let score = 100;
// Deduct for complex operations
const complexOperations = operations.filter((op) => op.complexity === "high").length;
score -= complexOperations * 15;
// Deduct for side effects
if (this.content.includes("localStorage") ||
this.content.includes("window.")) {
score -= 20;
}
return Math.max(0, score);
}
calculateReusability(operations, patterns) {
let score = 50; // Base score
// Add for generic operations
const genericOperations = operations.filter((op) => !op.name.includes("specific") && !op.name.includes("custom")).length;
score += genericOperations * 10;
// Add for good patterns
score += patterns.architecturalPatterns.length * 5;
return Math.min(100, score);
}
calculateReliability(patterns) {
let score = 80; // Base score
// Add for error handling patterns
if (this.content.includes("try") && this.content.includes("catch")) {
score += 10;
}
// Deduct for anti-patterns
patterns.antiPatterns.forEach((antiPattern) => {
if (antiPattern.severity === "high" ||
antiPattern.severity === "critical") {
score -= 15;
}
});
return Math.max(0, Math.min(100, score));
}
calculatePerformance(complexity, patterns) {
let score = 80; // Base score
// Deduct for high complexity
if (complexity.overallComplexity === "very-high")
score -= 30;
else if (complexity.overallComplexity === "high")
score -= 20;
// Add for optimization patterns
if (this.content.includes("useMemo") ||
this.content.includes("useCallback")) {
score += 10;
}
return Math.max(0, Math.min(100, score));
}
calculateSecurity(patterns) {
let score = 70; // Base score
// Add for security patterns
if (this.content.includes("sanitize") ||
this.content.includes("validate")) {
score += 15;
}
// Deduct for security issues
if (this.content.includes("eval(") || this.content.includes("innerHTML")) {
score -= 30;
}
return Math.max(0, Math.min(100, score));
}
identifyQualityIssues(complexity, patterns) {
const issues = [];
// Complexity issues
if (complexity.overallComplexity === "very-high") {
issues.push({
type: "complexity",
severity: "high",
description: "Very high business logic complexity",
location: this.filePath,
suggestion: "Break down complex operations into smaller functions",
impact: "Reduced maintainability and increased bug risk",
});
}
// Performance issues
const transformCount = this.countOccurrences(this.content, /\.map\(|\.filter\(|\.reduce\(/g);
if (transformCount > 10) {
issues.push({
type: "performance",
severity: "medium",
description: "High number of data transformations",
location: this.filePath,
suggestion: "Consider memoization or data structure optimization",
impact: "Potential performance bottlenecks",
});
}
return issues;
}
identifyExternalServices(dependencyContext) {
const services = [];
dependencyContext.external.forEach((dep) => {
if (this.isExternalService(dep.name)) {
services.push({
name: dep.name,
type: this.determineServiceType(dep.name),
reliability: "medium",
performance: "moderate",
security: "medium",
cost: "medium",
alternatives: this.findServiceAlternatives(dep.name),
});
}
});
return services;
}
identifyDatabaseDependencies() {
const dependencies = [];
const content = this.content;
if (content.includes("sql") || content.includes("query")) {
dependencies.push({
type: "sql",
operations: this.extractDatabaseOperations(),
performance: this.assessDatabasePerformance(),
reliability: "high",
scalability: "medium",
});
}
return dependencies;
}
identifyApiDependencies() {
const dependencies = [];
const endpoints = this.extractApiEndpoints();
endpoints.forEach((endpoint) => {
dependencies.push({
endpoint,
method: this.extractHttpMethod(endpoint),
authentication: this.determineAuthType(),
reliability: "medium",
errorHandling: this.assessApiErrorHandling(),
});
});
return dependencies;
}
identifyLibraryDependencies(dependencyContext) {
const libraries = [];
dependencyContext.external.forEach((dep) => {
libraries.push({
name: dep.name,
purpose: this.mapToLibraryPurpose(dep.purpose),
version: "unknown",
security: this.assessLibrarySecurity(dep.name),
maintenance: this.assessLibraryMaintenance(dep.name),
alternatives: this.findLibraryAlternatives(dep.name),
});
});
return libraries;
}
identifyConfigurationDependencies() {
const dependencies = [];
const content = this.content;
// Environment variables
const envMatches = content.match(/process\.env\.(\w+)/g) || [];
envMatches.forEach((envVar) => {
const name = envVar.replace("process.env.", "");
dependencies.push({
name,
type: "environment",
required: true,
sensitive: name.includes("SECRET") || name.includes("KEY"),
validation: { required: true },
});
});
return dependencies;
}
identifyResourceDependencies() {
const dependencies = [];
const content = this.content;
// Image imports
const imageMatches = content.match(/import.*\.(png|jpg|jpeg|gif|svg)/g) || [];
imageMatches.forEach((imageImport) => {
dependencies.push({
name: imageImport,
type: "image",
availability: "local",
optimization: this.assessResourceOptimization("image"),
});
});
return dependencies;
}
// Utility helper methods
countOccurrences(text, pattern) {
const matches = text.match(pattern);
return matches ? matches.length : 0;
}
extractApiEndpoints() {
const content = this.content;
const urlPattern = /['"`]([^'"`]*\/api\/[^'"`]*)['"`]/g;
const endpoints = [];
let match;
while ((match = urlPattern.exec(content)) !== null) {
endpoints.push(match[1]);
}
return endpoints;
}
assessApiReliability() {
return this.content.includes("retry") || this.content.includes("catch")
? "high"
: "medium";
}
assessApiPerformance() {
return this.content.includes("cache") || this.content.includes("memo")
? "fast"
: "moderate";
}
isExternalService(name) {
const servicePatterns = [
"stripe",
"paypal",
"auth0",
"firebase",
"aws",
"google",
];
return servicePatterns.some((pattern) => name.toLowerCase().includes(pattern));
}
determineServiceType(name) {
if (name.includes("auth"))
return "auth";
if (name.includes("pay") || name.includes("stripe"))
return "payment";
if (name.includes("firebase") || name.includes("aws"))
return "database";
return "rest-api";
}
findServiceAlternatives(serviceName) {
const alternatives = {
stripe: ["PayPal", "Square", "Braintree"],
auth0: ["Firebase Auth", "AWS Cognito", "Okta"],
firebase: ["AWS", "Supabase", "MongoDB Atlas"],
};
return alternatives[serviceName.toLowerCase()] || [];
}
extractDatabaseOperations() {
return [
{
type: "query",
frequency: "medium",
complexity: "moderate",
},
];
}
assessDatabasePerformance() {
return {
queryOptimization: false,
indexing: false,
caching: this.content.includes("cache"),
connectionPooling: false,
};
}
extractHttpMethod(endpoint) {
const content = this.content;
if (content.includes(`post`))
return "POST";
if (content.includes(`put`))
return "PUT";
if (content.includes(`delete`))
return "DELETE";
return "GET";
}
determineAuthType() {
if (this.content.includes("bearer") || this.content.includes("jwt"))
return "bearer";
if (this.content.includes("api-key") || this.content.includes("apikey"))
return "api-key";
if (this.content.includes("oauth"))
return "oauth";
return "none";
}
assessApiErrorHandling() {
return {
retries: this.content.includes("retry") ? 3 : 0,
timeout: this.content.includes("timeout") ? 5000 : 0,
fallback: this.content.includes("fallback"),
circuitBreaker: this.content.includes("circuit"),
};
}
mapToLibraryPurpose(purpose) {
const mapping = {
"ui-library": "ui",
"state-management": "state-management",
"data-fetching": "data-fetching",
validation: "validation",
testing: "testing",
utility: "utility",
};
return mapping[purpose] || "utility";
}
assessLibrarySecurity(name) {
return {
vulnerabilities: [],
lastAudit: "unknown",
riskLevel: "medium",
};
}
assessLibraryMaintenance(name) {
return {
lastUpdate: "unknown",
activelyMaintained: true,
communitySupport: "medium",
};
}
findLibraryAlternatives(name) {
return [];
}
assessResourceOptimization(type) {
return {
compressed: false,
cached: false,
lazyLoaded: this.content.includes("lazy"),
optimized: false,
};
}
extractWorkflowSteps() {
return [];
}
extractWorkflowTriggers() {
return [];
}