@notjustcoders/ioc-arise
Version:
Arise type-safe IoC containers from your code. Zero overhead, zero coupling.
116 lines • 5.15 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.MockClassResolver = void 0;
/**
* Utility class for resolving mock classes based on configuration
*/
class MockClassResolver {
/**
* Resolves a mock class for the given target class if mock mode is enabled
* @param targetClass The class name to find a mock for
* @param availableClasses All available classes in the project
* @param mockConfig Mock configuration from ioc.config.json
* @returns Mock class name if found, null otherwise
*/
static resolveMockClass(targetClass, availableClasses, mockConfig) {
if (!mockConfig?.enabled || !mockConfig?.mockMode) {
return null;
}
// Priority 1: Explicit mock mappings
if (mockConfig.explicitMocks?.[targetClass]) {
const explicitMock = mockConfig.explicitMocks[targetClass];
// Verify the explicit mock class exists
const mockExists = availableClasses.some(c => c.name === explicitMock);
if (mockExists) {
return explicitMock;
}
}
// Priority 2: Find mock classes using glob patterns
if (mockConfig.mockClassGlobs && mockConfig.mockClassGlobs.length > 0) {
for (const globPattern of mockConfig.mockClassGlobs) {
const mockCandidates = availableClasses.filter(classInfo => this.matchesGlobPattern(classInfo.name, globPattern) &&
this.isMockForTarget(classInfo.name, targetClass));
if (mockCandidates.length > 0) {
return mockCandidates[0]?.name || null; // Return first match
}
}
}
return null; // No mock found, use original class
}
/**
* Checks if a class name matches a glob pattern
* @param className The class name to check
* @param globPattern The glob pattern (e.g., "*Mock*", "Mock*")
* @returns true if the class name matches the pattern
*/
static matchesGlobPattern(className, globPattern) {
// Convert glob pattern to regex
const regexPattern = globPattern
.replace(/\*/g, '.*')
.replace(/\?/g, '.');
const regex = new RegExp(`^${regexPattern}$`, 'i');
return regex.test(className);
}
/**
* Determines if a mock class name is intended for the target class
* @param mockClassName The potential mock class name
* @param targetClassName The target class name
* @returns true if the mock is for the target
*/
static isMockForTarget(mockClassName, targetClassName) {
// Remove common mock prefixes/suffixes to get the core name
const cleanMockName = mockClassName
.replace(/^Mock/i, '')
.replace(/Mock$/i, '')
.replace(/^Test/i, '')
.replace(/Test$/i, '');
// Check various matching strategies
return (cleanMockName === targetClassName ||
targetClassName.includes(cleanMockName) ||
cleanMockName.includes(targetClassName) ||
this.fuzzyMatch(cleanMockName, targetClassName));
}
/**
* Performs fuzzy matching between mock and target class names
* @param mockName Cleaned mock class name
* @param targetName Target class name
* @returns true if names are similar enough
*/
static fuzzyMatch(mockName, targetName) {
// Simple fuzzy matching - check if they share significant common parts
const mockParts = mockName.toLowerCase().split(/(?=[A-Z])/);
const targetParts = targetName.toLowerCase().split(/(?=[A-Z])/);
// If they share at least 50% of parts, consider it a match
const commonParts = mockParts.filter(part => targetParts.some(targetPart => targetPart.includes(part) || part.includes(targetPart)));
return commonParts.length >= Math.min(mockParts.length, targetParts.length) * 0.5;
}
/**
* Gets all available mock classes based on configuration
* @param availableClasses All available classes
* @param mockConfig Mock configuration
* @returns Array of mock class names
*/
static getAllMockClasses(availableClasses, mockConfig) {
if (!mockConfig?.enabled || !mockConfig.mockClassGlobs) {
return [];
}
const mockClasses = new Set();
// Add explicit mocks
if (mockConfig.explicitMocks) {
Object.values(mockConfig.explicitMocks).forEach(mockClass => {
if (availableClasses.some(c => c.name === mockClass)) {
mockClasses.add(mockClass);
}
});
}
// Add classes matching glob patterns
for (const globPattern of mockConfig.mockClassGlobs) {
availableClasses
.filter(classInfo => this.matchesGlobPattern(classInfo.name, globPattern))
.forEach(classInfo => mockClasses.add(classInfo.name));
}
return Array.from(mockClasses);
}
}
exports.MockClassResolver = MockClassResolver;
//# sourceMappingURL=mock-class-resolver.js.map