@tdi2/di-core
Version:
TypeScript Dependency Injection 2 - Core DI framework
813 lines (799 loc) • 24.6 kB
TypeScript
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 };