@paulohenriquevn/m2js
Version:
Transform TypeScript/JavaScript code into LLM-friendly Markdown summaries + Smart Dead Code Detection + Graph-Deep Diff Analysis. Extract exported functions, classes, and JSDoc comments for better AI context with 60%+ token reduction. Intelligent dead cod
319 lines • 12.8 kB
JavaScript
"use strict";
/**
* Architecture Insights Analyzer for M2JS
* Analyzes architectural patterns, decisions, and code organization
*/
Object.defineProperty(exports, "__esModule", { value: true });
exports.analyzeArchitecture = analyzeArchitecture;
/**
* Analyzes architectural patterns from parsed files and dependencies
*/
function analyzeArchitecture(parsedFiles, dependencyGraph) {
return {
layerArchitecture: analyzeLayerArchitecture(parsedFiles, dependencyGraph),
dataFlow: analyzeDataFlowPatterns(parsedFiles, dependencyGraph),
errorStrategy: analyzeErrorHandling(parsedFiles),
securityPatterns: analyzeSecurityPatterns(parsedFiles),
testingStrategy: analyzeTestingStrategy(parsedFiles),
performancePatterns: analyzePerformancePatterns(parsedFiles),
designPrinciples: analyzeDesignPrinciples(parsedFiles, dependencyGraph),
};
}
/**
* Analyzes layer architecture patterns
*/
function analyzeLayerArchitecture(parsedFiles, dependencyGraph) {
const layers = [];
// Categorize files into architectural layers
const controllerFiles = parsedFiles.filter(f => f.fileName.toLowerCase().includes('controller') ||
f.fileName.toLowerCase().includes('route') ||
f.fileName.toLowerCase().includes('endpoint'));
const serviceFiles = parsedFiles.filter(f => f.fileName.toLowerCase().includes('service') ||
f.fileName.toLowerCase().includes('business') ||
f.fileName.toLowerCase().includes('logic'));
const modelFiles = parsedFiles.filter(f => f.fileName.toLowerCase().includes('model') ||
f.fileName.toLowerCase().includes('entity') ||
f.fileName.toLowerCase().includes('schema'));
const utilFiles = parsedFiles.filter(f => f.fileName.toLowerCase().includes('util') ||
f.fileName.toLowerCase().includes('helper') ||
f.fileName.toLowerCase().includes('validator'));
// Build layer structure
if (controllerFiles.length > 0) {
layers.push({
name: 'Presentation Layer',
responsibility: 'HTTP request handling, input validation, response formatting',
files: controllerFiles.map(f => f.fileName),
dependencies: getLayerDependencies(controllerFiles, dependencyGraph),
});
}
if (serviceFiles.length > 0) {
layers.push({
name: 'Business Logic Layer',
responsibility: 'Core business rules, workflows, and domain operations',
files: serviceFiles.map(f => f.fileName),
dependencies: getLayerDependencies(serviceFiles, dependencyGraph),
});
}
if (modelFiles.length > 0) {
layers.push({
name: 'Data Layer',
responsibility: 'Data structures, entities, and persistence logic',
files: modelFiles.map(f => f.fileName),
dependencies: getLayerDependencies(modelFiles, dependencyGraph),
});
}
if (utilFiles.length > 0) {
layers.push({
name: 'Utility Layer',
responsibility: 'Cross-cutting concerns, helpers, and shared functionality',
files: utilFiles.map(f => f.fileName),
dependencies: getLayerDependencies(utilFiles, dependencyGraph),
});
}
// Determine architecture pattern
let pattern = 'Custom Architecture';
let rationale = 'Architecture pattern determined by file organization and dependencies';
if (controllerFiles.length > 0 &&
serviceFiles.length > 0 &&
modelFiles.length > 0) {
pattern = 'Layered Architecture (MVC-style)';
rationale =
'Clear separation between presentation, business logic, and data layers';
}
else if (serviceFiles.length > 0 && modelFiles.length > 0) {
pattern = 'Service-Oriented Architecture';
rationale = 'Business logic encapsulated in services with domain models';
}
else if (utilFiles.length > parsedFiles.length * 0.5) {
pattern = 'Utility-First Architecture';
rationale =
'Functional approach with emphasis on reusable utility functions';
}
return { pattern, layers, rationale };
}
/**
* Gets dependencies for a layer of files
*/
function getLayerDependencies(layerFiles, dependencyGraph) {
const dependencies = new Set();
layerFiles.forEach(file => {
const edges = dependencyGraph.edges.filter(edge => edge.from === file.filePath && !edge.isExternal);
edges.forEach(edge => {
dependencies.add(edge.to);
});
});
return Array.from(dependencies);
}
/**
* Analyzes data flow patterns
*/
function analyzeDataFlowPatterns(parsedFiles, _dependencyGraph) {
const patterns = [];
// Analyze common data flow patterns
const hasControllers = parsedFiles.some(f => f.fileName.includes('controller'));
const hasServices = parsedFiles.some(f => f.fileName.includes('service'));
const hasModels = parsedFiles.some(f => f.fileName.includes('model'));
const hasValidators = parsedFiles.some(f => f.fileName.includes('validator'));
if (hasControllers && hasServices && hasModels) {
patterns.push({
name: 'Request-Response Flow',
steps: [
'HTTP Request → Controller',
'Controller → Input Validation',
'Controller → Service Layer',
'Service → Business Logic',
'Service → Data Layer',
'Response ← Controller',
],
description: 'Standard web application request processing flow',
files: ['Controllers', 'Services', 'Models'],
});
}
if (hasValidators) {
patterns.push({
name: 'Validation Pipeline',
steps: [
'Input Data → Validation Functions',
'Validation → Error Collection',
'Valid Data → Business Logic',
'Invalid Data → Error Response',
],
description: 'Input validation and error handling workflow',
files: ['Validators', 'Controllers'],
});
}
// Analyze async patterns
const hasAsyncFunctions = parsedFiles.some(file => file.functions.some(func => func.signature.includes('async') || func.returnType?.includes('Promise')));
if (hasAsyncFunctions) {
patterns.push({
name: 'Async Operation Flow',
steps: [
'Async Function Call',
'Promise Creation',
'Await Resolution',
'Error Handling (try/catch)',
'Result Processing',
],
description: 'Asynchronous operation handling pattern',
files: ['Services', 'Controllers'],
});
}
return patterns;
}
/**
* Analyzes error handling strategies
*/
function analyzeErrorHandling(parsedFiles) {
const patterns = [];
const customErrors = [];
const examples = [];
// Look for error-related patterns in function names and JSDoc
parsedFiles.forEach(file => {
file.functions.forEach(func => {
if (func.name.includes('validate') || func.name.includes('check')) {
patterns.push('Input Validation');
examples.push(`${func.name}() validates input and throws on failure`);
}
if (func.jsDoc?.includes('throw') || func.jsDoc?.includes('error')) {
patterns.push('Explicit Error Throwing');
}
if (func.returnType?.includes('boolean')) {
patterns.push('Boolean Return Pattern');
examples.push(`${func.name}() returns boolean for success/failure`);
}
});
// Look for custom error classes
file.classes.forEach(cls => {
if (cls.name.includes('Error') || cls.name.includes('Exception')) {
customErrors.push(cls.name);
}
});
});
// Determine overall strategy
let strategy = 'Mixed Error Handling';
if (patterns.includes('Boolean Return Pattern') &&
!patterns.includes('Explicit Error Throwing')) {
strategy = 'Return Value Error Handling';
}
else if (patterns.includes('Explicit Error Throwing')) {
strategy = 'Exception-Based Error Handling';
}
return {
strategy,
patterns: Array.from(new Set(patterns)),
customErrors,
examples: examples.slice(0, 3),
};
}
/**
* Analyzes security patterns
*/
function analyzeSecurityPatterns(parsedFiles) {
const patterns = [];
// Look for security-related functions
const securityFunctions = parsedFiles.flatMap(file => file.functions.filter(func => func.name.includes('validate') ||
func.name.includes('auth') ||
func.name.includes('encrypt') ||
func.name.includes('hash') ||
func.name.includes('token') ||
func.name.includes('permission')));
if (securityFunctions.length > 0) {
patterns.push({
pattern: 'Input Validation',
description: 'Systematic input validation to prevent injection attacks',
implementation: `${securityFunctions.length} validation functions found`,
});
}
// Look for authentication patterns
const authFunctions = securityFunctions.filter(func => func.name.includes('auth') ||
func.name.includes('login') ||
func.name.includes('token'));
if (authFunctions.length > 0) {
patterns.push({
pattern: 'Authentication Layer',
description: 'User authentication and authorization mechanisms',
implementation: 'Token-based or session-based authentication',
});
}
return patterns;
}
/**
* Analyzes testing strategy
*/
function analyzeTestingStrategy(parsedFiles) {
// This is a simplified analysis
// In practice, you'd analyze test files separately
const hasComplexLogic = parsedFiles.some(file => file.functions.length > 5 ||
file.classes.some(cls => cls.methods.length > 5));
return {
approach: hasComplexLogic
? 'Unit Testing Recommended'
: 'Integration Testing Focus',
frameworks: ['Jest', 'Mocha', 'Vitest'], // Common frameworks
patterns: ['Arrange-Act-Assert', 'Given-When-Then'],
coverage: 'Target 80%+ for business logic',
};
}
/**
* Analyzes performance patterns
*/
function analyzePerformancePatterns(parsedFiles) {
const patterns = [];
// Look for async patterns
const asyncFunctions = parsedFiles.flatMap(file => file.functions.filter(func => func.returnType?.includes('Promise')));
if (asyncFunctions.length > 0) {
patterns.push({
pattern: 'Asynchronous Processing',
description: 'Non-blocking operations for better performance',
evidence: [`${asyncFunctions.length} async functions`],
});
}
// Look for caching patterns
const cachingFunctions = parsedFiles.flatMap(file => file.functions.filter(func => func.name.includes('cache') || func.name.includes('memo')));
if (cachingFunctions.length > 0) {
patterns.push({
pattern: 'Caching Strategy',
description: 'Data caching for improved response times',
evidence: [`${cachingFunctions.length} caching functions`],
});
}
return patterns;
}
/**
* Analyzes adherence to design principles
*/
function analyzeDesignPrinciples(parsedFiles, dependencyGraph) {
const principles = [];
// Single Responsibility Principle
const violations = [];
const evidence = [];
parsedFiles.forEach(file => {
if (file.functions.length > 10) {
violations.push(`${file.fileName} has ${file.functions.length} functions`);
}
else {
evidence.push(`${file.fileName} has focused responsibility`);
}
});
principles.push({
principle: 'Single Responsibility Principle',
evidence: evidence.slice(0, 3),
violations: violations.slice(0, 3),
});
// Dependency Inversion (check for dependency directions)
const hasProperLayering = dependencyGraph.edges.every(edge => {
const fromIsController = edge.from.includes('controller');
const toIsModel = edge.to.includes('model');
// Controllers should not directly depend on models (should go through services)
return !(fromIsController && toIsModel);
});
if (hasProperLayering) {
principles.push({
principle: 'Dependency Inversion Principle',
evidence: ['Proper dependency flow through layers'],
violations: [],
});
}
return principles;
}
//# sourceMappingURL=architecture-analyzer.js.map