UNPKG

@tdi2/di-core

Version:

TypeScript Dependency Injection 2 - Core DI framework

813 lines (799 loc) 24.6 kB
import { ClassDeclaration, SourceFile, FunctionDeclaration, ArrowFunction } from 'ts-morph'; interface DIConfigOptions { srcDir: string; outputDir: string; enableFunctionalDI: boolean; verbose: boolean; nodeEnv?: string; customSuffix?: string; } declare class ConfigManager { private configHash; private configDir; private bridgeDir; private options; private packageName; constructor(options: DIConfigOptions); private getPackageName; private generateConfigHash; findExistingConfig(): string | null; private ensureDirectories; private writeConfigMetadata; generateBridgeFiles(): void; private generateDIConfigBridge; private generateRegistryBridge; private generateBridgeGitignore; isConfigValid(): boolean; forceRegenerate(): void; getConfigDir(): string; getBridgeDir(): string; getConfigHash(): string; getTransformedDir(): string; static cleanOldConfigs(keepCount?: number): void; static listConfigs(): void; } /** * Common interface for all resolver implementations */ interface InterfaceResolverInterface { scanProject(): Promise<void>; resolveImplementation(interfaceType: string): InterfaceImplementation | undefined; getInterfaceImplementations(): Map<string, InterfaceImplementation>; getServiceDependencies(): Map<string, ServiceDependency>; validateDependencies(): ValidationResult; getDependencyTree(): DependencyNode[]; } interface InterfaceImplementation { interfaceName: string; implementationClass: string; filePath: string; isGeneric: boolean; typeParameters: string[]; sanitizedKey: string; isClassBased?: boolean; isInheritanceBased?: boolean; isStateBased?: boolean; inheritanceChain?: string[]; baseClass?: string; baseClassGeneric?: string; stateType?: string; serviceInterface?: string; } interface ServiceDependency { serviceClass: string; interfaceDependencies: string[]; filePath: string; constructorParams: ConstructorParam[]; } interface ConstructorParam { paramName: string; interfaceType: string; isOptional: boolean; sanitizedKey: string; } interface ValidationResult { isValid: boolean; missingImplementations: string[]; circularDependencies: string[]; } interface DependencyNode { id: string; dependencies: string[]; resolved: string[]; } interface TypeResolutionRequest { interfaceType: string; context: 'class-constructor' | 'function-parameter'; isOptional: boolean; sourceLocation: string; sourceFile?: string; } interface TypeResolutionResult { interfaceType: string; implementation?: InterfaceImplementation; sanitizedKey: string; resolutionStrategy: 'interface' | 'inheritance' | 'state' | 'class' | 'not-found'; error?: string; } declare class SharedTypeResolver { private interfaceResolver; private options; private keySanitizer; private resolutionCache; constructor(interfaceResolver: InterfaceResolverInterface, options?: { verbose?: boolean; }); /** * Resolve a single interface type to its implementation */ resolveType(request: TypeResolutionRequest): TypeResolutionResult; /** * Resolve multiple types efficiently (batch operation) */ resolveMultipleTypes(requests: TypeResolutionRequest[]): Map<string, TypeResolutionResult>; /** * Core resolution logic - tries multiple strategies */ private performResolution; /** * Determine which strategy was used for resolution */ private determineStrategy; /** * Check if a type is resolvable without actually resolving it */ canResolve(interfaceType: string): boolean; /** * Get all available interface types that can be resolved */ getAvailableTypes(): string[]; /** * Normalize type strings for consistent comparison */ normalizeType(interfaceType: string): string; /** * Extract generic type parameters from interface type */ extractGenericParameters(interfaceType: string): string[]; /** * Check if interface type is generic */ isGenericType(interfaceType: string): boolean; /** * Get base interface name without generics */ getBaseInterfaceName(interfaceType: string): string; /** * Clear resolution cache (useful for testing or dynamic updates) */ clearCache(): void; /** * Get cache statistics for debugging */ getCacheStats(): { size: number; hitRate: number; }; /** * Validate that a resolution result is usable */ validateResolution(result: TypeResolutionResult): boolean; /** * Log resolution for debugging */ private logResolution; /** * Create resolution suggestions for failed resolutions */ createResolutionSuggestions(failedType: string): string[]; } interface ExtractedDependency { serviceKey: string; interfaceType: string; sanitizedKey: string; isOptional: boolean; resolvedImplementation?: InterfaceImplementation; extractionSource: 'decorator' | 'marker-type' | 'parameter-type'; sourceLocation: string; propertyPath?: string[]; metadata?: { parameterIndex?: number; propertyName?: string; hasQualifier?: boolean; qualifier?: string; }; } interface SharedDependencyExtractorOptions { verbose?: boolean; srcDir?: string; } declare class SharedDependencyExtractor { private typeResolver; private options; private recursiveExtractor; constructor(typeResolver: SharedTypeResolver, options?: SharedDependencyExtractorOptions); /** * Extract dependencies from class constructor with @Inject decorators */ extractFromClassConstructor(classDecl: ClassDeclaration, sourceFile: SourceFile): ExtractedDependency[]; /** * Extract dependencies from function parameter with Inject<T> markers */ extractFromFunctionParameter(func: FunctionDeclaration, sourceFile: SourceFile): ExtractedDependency[]; /** * Extract dependencies from arrow function parameter with Inject<T> markers */ extractFromArrowFunction(arrowFunc: ArrowFunction, sourceFile: SourceFile): ExtractedDependency[]; /** * Extract from constructor parameter with @Inject decorator */ private extractFromConstructorParameter; /** * Extract dependencies from Inject<T> marker types in function parameters using recursive extraction */ private extractFromTypeMarkers; /** * Convert an inject marker to an extracted dependency with proper property path handling */ private convertInjectMarkerToDependency; /** * Extract from type reference (external interface) using recursive extraction */ private extractFromTypeReference; /** * Extract from interface declaration using recursive extraction */ private extractFromInterfaceDeclaration; /** * Extract from type alias declaration using recursive extraction */ private extractFromTypeAliasDeclaration; /** * Check if parameter has @Inject decorator */ private hasInjectDecorator; /** * Check if decorator name indicates injection */ private isInjectDecoratorName; /** * Extract qualifier from parameter decorators */ private extractQualifier; /** * Validate extracted dependencies */ validateDependencies(dependencies: ExtractedDependency[]): { isValid: boolean; errors: string[]; warnings: string[]; }; /** * Group dependencies by resolution strategy */ groupByResolutionStrategy(dependencies: ExtractedDependency[]): { interface: ExtractedDependency[]; inheritance: ExtractedDependency[]; state: ExtractedDependency[]; class: ExtractedDependency[]; notFound: ExtractedDependency[]; }; /** * Get dependency statistics */ getDependencyStats(dependencies: ExtractedDependency[]): { total: number; resolved: number; optional: number; missing: number; bySource: Record<string, number>; }; } interface ServiceRegistration { token: string; interfaceName: string; implementationClass: string; scope: 'singleton' | 'transient' | 'scoped'; dependencies: string[]; factory: string; filePath: string; registrationType: 'interface' | 'inheritance' | 'state' | 'class'; metadata: { isGeneric: boolean; typeParameters: string[]; sanitizedKey: string; baseClass?: string; baseClassGeneric?: string; stateType?: string; serviceInterface?: string; isAutoResolved: boolean; }; } interface RegistryConfiguration { services: Map<string, ServiceRegistration>; interfaceMapping: Map<string, string[]>; classMapping: Map<string, string>; dependencyGraph: Map<string, string[]>; } interface RegistryStats { totalServices: number; byType: Record<string, number>; byScope: Record<string, number>; withDependencies: number; orphanedServices: number; } declare class SharedServiceRegistry { private configManager; private options; private services; private interfaceMapping; private classMapping; private dependencyGraph; constructor(configManager: ConfigManager, options?: { verbose?: boolean; }); /** * Register a service implementation */ registerService(implementation: InterfaceImplementation, dependencies: ExtractedDependency[]): void; /** * Register multiple services efficiently */ registerServices(implementations: InterfaceImplementation[], dependencyMap: Map<string, ExtractedDependency[]>): void; /** * Get service registration by token */ getService(token: string): ServiceRegistration | undefined; /** * Get all services implementing an interface */ getServicesByInterface(interfaceName: string): ServiceRegistration[]; /** * Get service by implementation class name */ getServiceByClass(className: string): ServiceRegistration | undefined; /** * Get all registered services */ getAllServices(): ServiceRegistration[]; /** * Get dependency graph for a service */ getDependencies(serviceToken: string): string[]; /** * Generate DI configuration file */ generateDIConfiguration(): Promise<void>; /** * Generate service registry file */ generateServiceRegistry(): Promise<void>; /** * Validate registry configuration */ validateRegistry(): { isValid: boolean; errors: string[]; warnings: string[]; stats: RegistryStats; }; /** * Create service registration from implementation and dependencies */ private createServiceRegistration; /** * Update interface mapping */ private updateInterfaceMapping; /** * Update dependency graph */ private updateDependencyGraph; /** * Determine registration type from implementation */ private determineRegistrationType; /** * Generate factory function name */ private generateFactoryName; /** * Generate DI configuration content */ private generateConfigContent; /** * Generate service registry content */ private generateRegistryContent; /** * Generate factory function for service */ private generateFactoryFunction; /** * Find circular dependencies */ private findCircularDependencies; /** * Find interfaces with multiple implementations */ private findAmbiguousRegistrations; /** * Generate registry statistics */ private generateStats; /** * Find services that are never used as dependencies */ private findOrphanedServices; /** * Clear all registrations */ clear(): void; /** * Get registry configuration for external use */ getConfiguration(): RegistryConfiguration; } interface DISourceConfiguration { decoratorSources: string[]; markerSources: string[]; validateSources: boolean; } interface IntegratedResolverOptions { verbose?: boolean; srcDir?: string; enableInheritanceDI?: boolean; enableStateDI?: boolean; sourceConfig?: Partial<DISourceConfiguration>; } declare class IntegratedInterfaceResolver { private project; private interfaces; private dependencies; private options; private interfaceExtractor; private serviceValidator; private inheritanceAnalyzer; private stateTypeExtractor; private dependencyAnalyzer; private keySanitizer; constructor(options?: IntegratedResolverOptions); scanProject(): Promise<void>; private collectInterfaceImplementationsEnhanced; private processClassWithEnhancedExtraction; private registerInterfaceImplementation; private registerInheritanceImplementation; private registerStateImplementation; private registerClassImplementation; private collectServiceDependenciesEnhanced; private shouldSkipFile; private logRegistrationSummary; resolveImplementation(interfaceType: string): InterfaceImplementation | undefined; private getRegistrationType; validateDependencies(): ValidationResult; getImplementationsByInterface(interfaceName: string): InterfaceImplementation[]; getImplementationByClass(className: string): InterfaceImplementation | undefined; getInterfaceImplementations(): Map<string, InterfaceImplementation>; getServiceDependencies(): Map<string, ServiceDependency>; getDependencyTree(): DependencyNode[]; updateSourceConfiguration(config: Partial<DISourceConfiguration>): void; getSourceConfiguration(): DISourceConfiguration; clearCaches(): void; getEnhancedDebugInfo(): { interfaceCount: number; dependencyCount: number; registrationTypes: Record<string, number>; validationStats: any; sourceConfig: DISourceConfiguration; resolutionSamples: Array<{ input: string; result: string | null; }>; }; } interface DIConfiguration { token: string; implementation: InterfaceImplementation; dependencies: string[]; factory: string; scope: string; } interface ServiceClass { className: string; filePath: string; dependencies: string[]; factory: string; registrations: Array<{ token: string; type: "interface" | "class" | "inheritance" | "state"; interfaceName: string; metadata?: any; }>; } declare class DependencyTreeBuilder { private configManager; private configurations; private serviceClasses; private options; private interfaceResolver; private dependencyExtractor; private serviceRegistry; private typeResolver; constructor(configManager: ConfigManager, options?: { verbose?: boolean; srcDir?: string; enableInheritanceDI?: boolean; }); buildDependencyTree(): Promise<void>; private buildConfigurationsWithSharedLogic; private generateDIConfiguration; private generateImportFile; private generateFactoryName; private topologicalSort; getDependencyTree(): any[]; getConfigurations(): Map<string, DIConfiguration>; getInterfaceResolver(): IntegratedInterfaceResolver; getServiceClasses(): Map<string, ServiceClass>; getServiceRegistry(): SharedServiceRegistry; getTypeResolver(): SharedTypeResolver; getDependencyExtractor(): SharedDependencyExtractor; getInheritanceInfo(): { baseClasses: string[]; implementations: Map<string, string[]>; chains: Map<string, string[]>; }; validateDependencyTree(): Promise<{ isValid: boolean; errors: string[]; warnings: string[]; stats: any; }>; } /** * Transformation candidate represents a code element that can be transformed */ interface TransformationCandidate { type: 'class' | 'function' | 'arrow-function'; node: ClassDeclaration | FunctionDeclaration | ArrowFunction; filePath: string; sourceFile: SourceFile; metadata?: { hasServiceDecorator?: boolean; hasInjectMarkers?: boolean; componentName?: string; isReactComponent?: boolean; }; } /** * Result of a transformation operation */ interface TransformationResult { transformedFiles: Map<string, TransformedContent>; summary: TransformationSummary; errors: TransformationError[]; warnings: TransformationWarning[]; } /** * Content that has been transformed */ interface TransformedContent { originalContent: string; transformedContent: string; imports: string[]; statements: string[]; removedElements: string[]; addedElements: string[]; filePath: string; transformationType: 'class-injection' | 'function-hooks'; } /** * Summary of transformation operation */ interface TransformationSummary { totalCandidates: number; successfulTransformations: number; failedTransformations: number; skippedTransformations: number; dependenciesResolved: number; dependenciesUnresolved: number; byType: { class: number; function: number; arrowFunction: number; }; byResolutionStrategy: { interface: number; inheritance: number; state: number; class: number; notFound: number; }; performance: { startTime: number; endTime: number; duration: number; }; } /** * Transformation error */ interface TransformationError { type: 'resolution-error' | 'generation-error' | 'validation-error' | 'file-error'; message: string; sourceLocation?: string; candidate?: TransformationCandidate; details?: any; } /** * Transformation warning */ interface TransformationWarning { type: 'optional-missing' | 'multiple-implementations' | 'deprecated-pattern' | 'performance'; message: string; sourceLocation?: string; suggestion?: string; } interface TransformerOptions$1 { srcDir?: string; outputDir?: string; verbose?: boolean; generateRegistry?: boolean; enableInterfaceResolution?: boolean; customSuffix?: string; } declare class EnhancedDITransformer { private project; private options; private configManager; private interfaceResolver; private dependencyExtractor; private serviceRegistry; private typeResolver; private transformationCandidates; private transformedFiles; private errors; private warnings; constructor(options?: TransformerOptions$1); transform(): Promise<TransformationResult>; private scanAndResolveInterfaces; private findTransformationCandidates; private createClassCandidate; private extractDependencies; private registerServices; private generateConfiguration; private shouldSkipFile; private hasServiceDecorator; private isServiceDecoratorName; private createTransformationResult; private getResolutionStatistics; save(): Promise<void>; getConfigManager(): ConfigManager; getInterfaceResolver(): IntegratedInterfaceResolver; getServiceRegistry(): SharedServiceRegistry; getTypeResolver(): SharedTypeResolver; getDebugInfo(): Promise<any>; validateConfiguration(): Promise<boolean>; getTransformationSummary(): { configHash: string; implementationCount: number; dependencyCount: number; hasValidConfiguration: boolean; hasErrors: boolean; }; } interface TransformationPipelineOptions { verbose?: boolean; generateFallbacks?: boolean; preserveTypeAnnotations?: boolean; } declare class TransformationPipeline { private options; private propertyUpdater; constructor(options?: TransformationPipelineOptions); /** * FIXED: Complete transformation pipeline that preserves non-DI destructuring */ transformComponent(func: FunctionDeclaration | ArrowFunction, dependencies: ExtractedDependency[], sourceFile: SourceFile): void; /** * Step 1: Normalize parameters to always use 'props' parameter */ private normalizeParameters; /** * FIXED: Step 2 - Generate DI hook calls AND preserve non-DI destructuring */ private generateDIHookCallsAndPreserveDestructuring; /** * FIXED: Extract non-DI destructuring that should be preserved using actual dependency paths */ private extractNonDIDestructuring; /** * FIXED: Extract non-DI properties from object binding pattern using actual dependency paths */ private extractNonDIPropertiesFromDestructuring; /** * Check if a property path is DI-related by comparing against actual dependency paths */ private isPathDIRelated; /** * Helper method to extract nested non-DI properties recursively */ private extractNestedNonDIProperties; /** * Generate DI hook statement with proper optional chaining */ private generateDIHookStatementWithOptionalChaining; /** * Determine property path with proper optional chaining */ private determineOptionalPropertyPath; /** * FIXED: Step 4 - Remove ALL original destructuring that contains ANY DI properties */ private removeOnlyDIDestructuring; /** * FIXED: Check if destructuring contains ANY DI-related properties (not just only DI) */ private containsAnyDIProperties; /** * Recursively search for ANY DI-related properties in destructuring pattern */ private findAnyDIInDestructuring; /** * Update property access expressions to use the new direct variables */ private updatePropertyAccessExpressions; /** * Simplify property access patterns */ private simplifyPropertyAccess; /** * Check if a variable is used in the function body (excluding the declaration statement) */ private isVariableUsedInFunction; /** * Update all references to a renamed variable in function body */ private updateReferencesInBody; /** * Get function body regardless of function type */ private getFunctionBody; } interface TransformerOptions { srcDir?: string; outputDir?: string; generateDebugFiles?: boolean; verbose?: boolean; customSuffix?: string; enableParameterNormalization?: boolean; generateFallbacks?: boolean; } declare class FunctionalDIEnhancedTransformer { private project; private options; private configManager; private interfaceResolver; private dependencyExtractor; private serviceRegistry; private typeResolver; private transformationPipeline; private importManager; private debugFileGenerator; private transformationCandidates; private transformedFiles; private transformationCount; private errors; private warnings; constructor(options?: TransformerOptions); transformForBuild(): Promise<Map<string, string>>; transform(): Promise<TransformationResult>; private scanAndResolveInterfaces; private findFunctionalComponents; private createFunctionCandidate; private createArrowFunctionCandidate; private transformComponentsWithPipeline; private transformSingleComponentWithPipeline; private registerDiscoveredServices; private shouldSkipFile; private hasInjectMarkers; private isReactComponent; private logTransformationStatistics; private createTransformationResult; private getResolutionStatistics; getTransformationSummary(): { count: number; functions: string[]; transformedFiles: string[]; resolvedDependencies: number; pipelineEnabled: boolean; normalizationPerformed: boolean; }; getDebugInfo(): Promise<any>; validateConfiguration(): Promise<boolean>; getConfigManager(): ConfigManager; getInterfaceResolver(): IntegratedInterfaceResolver; getServiceRegistry(): SharedServiceRegistry; getTypeResolver(): SharedTypeResolver; getTransformationPipeline(): TransformationPipeline; } export { ConfigManager, DependencyTreeBuilder, EnhancedDITransformer, FunctionalDIEnhancedTransformer, IntegratedInterfaceResolver, type IntegratedResolverOptions };