Press n or j to go to the next uncovered block, b, p or k for the previous block.
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 | 63x 63x 63x 9x 54x 54x 54x 54x 54x 54x 54x 54x 54x 168x 168x 168x 60x 14x 46x 46x 3x 43x 43x 43x 13x 4x 12x 12x 34x 34x 33x 15x 11x 8x 10x 10x 8x 1x | /**
* Provider Registry
*
* Central registry for all SSG providers (built-in and plugins).
* Handles provider discovery, registration, and lifecycle.
*/
import type { SSGProvider, ProviderMetadata, SSGProviderDependencies } from './types.js';
import type { AppContainer } from '../config/container.js';
/**
* Provider constructor type
*/
export type ProviderConstructor = new (dependencies: SSGProviderDependencies) => SSGProvider;
/**
* Provider registration info
*/
export interface ProviderRegistration {
constructor: ProviderConstructor;
metadata: ProviderMetadata;
isBuiltIn: boolean;
pluginPath?: string;
}
/**
* Provider Registry manages all available SSG providers
*/
export class ProviderRegistry {
private providers = new Map<string, ProviderRegistration>();
private instances = new Map<string, SSGProvider>();
private dependencies: SSGProviderDependencies;
constructor(dependencies: SSGProviderDependencies) {
this.dependencies = dependencies;
}
/**
* Set container reference after construction (to break circular dependency)
*/
setContainer(container: AppContainer): void {
this.dependencies.container = container;
}
/**
* Register built-in providers
* This is called after construction to avoid circular dependencies
*/
async registerBuiltInProviders(): Promise<void> {
try {
// Dynamically import Hugo provider to avoid circular dependencies
const { HugoProvider } = await import('./hugo/hugo-provider.js');
this.registerProvider(HugoProvider, true);
} catch (error) {
this.dependencies.outputConsole.appendLine(
`Failed to register Hugo provider: ${error instanceof Error ? error.message : String(error)}`
);
}
try {
// Dynamically import Eleventy provider
const { EleventyProvider } = await import('./eleventy/eleventy-provider.js');
this.registerProvider(EleventyProvider, true);
} catch (error) {
this.dependencies.outputConsole.appendLine(
`Failed to register Eleventy provider: ${error instanceof Error ? error.message : String(error)}`
);
}
try {
// Dynamically import Jekyll provider
const { JekyllProvider } = await import('./jekyll/jekyll-provider.js');
this.registerProvider(JekyllProvider, true);
} catch (error) {
this.dependencies.outputConsole.appendLine(
`Failed to register Jekyll provider: ${error instanceof Error ? error.message : String(error)}`
);
}
}
/**
* Register a provider
*/
registerProvider(
providerConstructor: ProviderConstructor,
isBuiltIn: boolean = false,
pluginPath?: string
): void {
// Create temporary instance to get metadata
const tempInstance = new providerConstructor(this.dependencies);
const metadata = tempInstance.getMetadata();
this.providers.set(metadata.type, {
constructor: providerConstructor,
metadata,
isBuiltIn,
pluginPath,
});
}
/**
* Get or create a provider instance
*/
getProvider(type: string): SSGProvider {
// Return cached instance if available
if (this.instances.has(type)) {
return this.instances.get(type)!;
}
// Get registration
const registration = this.providers.get(type);
if (!registration) {
throw new Error(
`SSG provider '${type}' not found. Available: ${Array.from(this.providers.keys()).join(', ')}`
);
}
// Create and cache instance
const instance = new registration.constructor(this.dependencies);
this.instances.set(type, instance);
return instance;
}
/**
* Check if a provider is registered
*/
hasProvider(type: string): boolean {
return this.providers.has(type);
}
/**
* Get all registered provider metadata
*/
getAllProviderMetadata(): ProviderMetadata[] {
return Array.from(this.providers.values()).map((reg) => reg.metadata);
}
/**
* Auto-detect SSG type from workspace directory
*/
async detectSSGType(workspacePath: string): Promise<string | null> {
const results: Array<{ type: string; result: SSGDetectionResult }> = [];
// Try all registered providers
for (const [type] of this.providers) {
const provider = this.getProvider(type);
const detectionResult = await provider.detectSite(workspacePath);
if (detectionResult.isDetected) {
results.push({ type, result: detectionResult });
}
}
// Sort by confidence and return best match
if (results.length === 0) return null;
results.sort((a, b) => {
const confidenceScore = { high: 3, medium: 2, low: 1 };
return confidenceScore[b.result.confidence] - confidenceScore[a.result.confidence];
});
return results[0].type;
}
/**
* Discover and register plugin providers from filesystem
* For Phase 7 - Plugin System implementation
*/
async discoverPlugins(pluginDir: string): Promise<void> {
// TODO: Implement in Phase 7
// This will scan pluginDir for provider plugins and register them
this.dependencies.outputConsole.appendLine(
`Plugin discovery not yet implemented. Plugin directory: ${pluginDir}`
);
}
}
/**
* Type for SSGDetectionResult (imported from provider detection)
*/
interface SSGDetectionResult {
isDetected: boolean;
confidence: 'high' | 'medium' | 'low';
version?: string;
configFiles?: string[];
metadata?: Record<string, unknown>;
}
|