UNPKG

@notjustcoders/ioc-arise

Version:

Arise type-safe IoC containers from your code. Zero overhead, zero coupling.

90 lines 4.63 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.ProjectAnalyzer = void 0; const class_analyzer_1 = require("./class-analyzer"); const file_discovery_1 = require("./file-discovery"); const index_js_1 = require("../errors/index.js"); class ProjectAnalyzer { constructor(options) { this.fileDiscovery = new file_discovery_1.FileDiscovery(options.sourceDir, options.excludePatterns); this.classAnalyzer = new class_analyzer_1.ClassAnalyzer(options.sourceDir, options.interfacePattern); } async analyzeProject() { const tsFiles = await this.fileDiscovery.findTypeScriptFiles(); // Analyze all files in a single batch operation for better performance const allClasses = await this.classAnalyzer.analyzeFiles(tsFiles); // Validate that no interface is implemented by multiple classes this.validateUniqueInterfaceImplementations(allClasses); // Validate that no abstract class is extended by multiple classes this.validateUniqueAbstractClassExtensions(allClasses); return allClasses; } validateUniqueInterfaceImplementations(classes) { const interfaceToClassMap = new Map(); // Group classes by their interface names for (const classInfo of classes) { if (classInfo.interfaceName) { if (!interfaceToClassMap.has(classInfo.interfaceName)) { interfaceToClassMap.set(classInfo.interfaceName, []); } interfaceToClassMap.get(classInfo.interfaceName).push(classInfo); } } // Check for duplicate implementations const duplicateInterfaces = []; for (const [interfaceName, implementingClasses] of interfaceToClassMap) { if (implementingClasses.length > 1) { duplicateInterfaces.push(interfaceName); const error = index_js_1.ErrorFactory.duplicateInterfaceImplementation(interfaceName, implementingClasses.map(c => c.name)); console.error(`❌ ${index_js_1.ErrorUtils.formatForConsole(error)}`); for (const classInfo of implementingClasses) { console.error(` • ${classInfo.name} (${classInfo.filePath})`); } } } if (duplicateInterfaces.length > 0) { const allClassNames = []; for (const [interfaceName, implementingClasses] of interfaceToClassMap) { if (implementingClasses.length > 1) { allClassNames.push(...implementingClasses.map(c => c.name)); } } throw index_js_1.ErrorFactory.duplicateInterfaceImplementation(duplicateInterfaces.join(', '), allClassNames); } } validateUniqueAbstractClassExtensions(classes) { const abstractClassToClassMap = new Map(); // Group classes by their abstract class names for (const classInfo of classes) { if (classInfo.abstractClassName) { if (!abstractClassToClassMap.has(classInfo.abstractClassName)) { abstractClassToClassMap.set(classInfo.abstractClassName, []); } abstractClassToClassMap.get(classInfo.abstractClassName).push(classInfo); } } // Check for duplicate extensions const duplicateAbstractClasses = []; for (const [abstractClassName, extendingClasses] of abstractClassToClassMap) { if (extendingClasses.length > 1) { duplicateAbstractClasses.push(abstractClassName); const error = index_js_1.ErrorFactory.duplicateAbstractClassExtension(abstractClassName, extendingClasses.map(c => c.name)); console.error(`❌ Multiple classes extending abstract class: ${abstractClassName}`); for (const classInfo of extendingClasses) { console.error(` • ${classInfo.name} (${classInfo.filePath})`); } } } if (duplicateAbstractClasses.length > 0) { const allClassNames = []; for (const [abstractClassName, extendingClasses] of abstractClassToClassMap) { if (extendingClasses.length > 1) { allClassNames.push(...extendingClasses.map(c => c.name)); } } throw index_js_1.ErrorFactory.duplicateAbstractClassExtension(duplicateAbstractClasses.join(', '), allClassNames); } } } exports.ProjectAnalyzer = ProjectAnalyzer; //# sourceMappingURL=project-analyzer.js.map