Fix TTS module initialization and dependency issues. Update module IDs for consistency, improve circular dependency detection, and fix UI Controller event handling.

This commit is contained in:
2025-04-04 19:15:28 +00:00
parent 02c7b9ef28
commit 49a5af252c
33 changed files with 7227 additions and 4060 deletions
+133 -1
View File
@@ -6,20 +6,52 @@ export class ModuleRegistry {
constructor() {
this.modules = {};
this.readyPromises = {};
this.moduleDependencies = new Map(); // Track module dependencies
this.visitedModules = new Set(); // For circular dependency detection
this.recursionStack = new Set(); // For circular dependency detection
this.untrackedDependencies = new Map(); // Track unregistered dependencies
}
/**
* Register a module
* @param {BaseModule} module - Module to register
* @param {Array<string>} [dependencies] - Optional array of module dependencies
*/
register(module) {
register(module, dependencies = null) {
if (!module || !module.id) {
console.error('Invalid module - must have an id property');
return;
}
// Store the module
this.modules[module.id] = module;
// Store dependencies if provided, otherwise use module.dependencies
if (dependencies) {
this.moduleDependencies.set(module.id, dependencies);
// Also set them on the module itself for backwards compatibility
if (module.dependencies === undefined) {
module.dependencies = [...dependencies];
}
} else if (module.dependencies) {
// Use the module's own dependencies property
this.moduleDependencies.set(module.id, [...module.dependencies]);
} else {
// No dependencies
this.moduleDependencies.set(module.id, []);
}
// Check for circular dependencies
this.visitedModules.clear();
this.recursionStack.clear();
const circularDependency = this.detectCircularDependency(module.id);
if (circularDependency) {
const errorMsg = `Circular dependency detected: ${circularDependency.join(' -> ')} -> ${circularDependency[0]}`;
console.error(errorMsg);
throw new Error(errorMsg);
}
// Create a promise that will resolve when this module is ready
this.readyPromises[module.id] = new Promise((resolve) => {
// Set up a state change listener for this module
@@ -39,6 +71,76 @@ export class ModuleRegistry {
});
}
/**
* Detect circular dependencies using DFS algorithm
* @param {string} moduleId - Starting module ID
* @param {Array<string>} [path=[]] - Current dependency path
* @returns {Array<string>|null} - Array representing the circular dependency path, or null if none
*/
detectCircularDependency(moduleId, path = []) {
// If we've already checked this module completely, no need to check again
if (this.visitedModules.has(moduleId)) {
return null;
}
// If we're already visiting this module in the current path, we found a cycle
if (this.recursionStack.has(moduleId)) {
// Return the path that forms the cycle
const cycleStartIndex = path.indexOf(moduleId);
if (cycleStartIndex >= 0) {
return path.slice(cycleStartIndex);
}
return path;
}
// Add to recursion stack to mark as being visited
this.recursionStack.add(moduleId);
path.push(moduleId);
// Get dependencies for this module
const dependencies = this.getDependencies(moduleId);
// Check each dependency
for (const depId of dependencies) {
// Even if the dependency isn't registered yet, we need to track it
// for potential circular dependencies that will manifest later
// Create a temporary placeholder in the path for unregistered dependencies
const depPath = [...path];
if (!this.modules[depId]) {
// Log that we're tracking an unregistered dependency
console.log(`Module Registry: Tracking potential circular dependency with unregistered module: ${depId}`);
// Add to the dependency tracking for future checks
this.trackDependency(moduleId, depId);
continue;
}
const result = this.detectCircularDependency(depId, depPath);
if (result) {
return result;
}
}
// Remove from recursion stack as we're done with this module
this.recursionStack.delete(moduleId);
// Mark as fully visited
this.visitedModules.add(moduleId);
return null;
}
/**
* Track an unregistered dependency
* @param {string} moduleId - Module ID
* @param {string} depId - Unregistered dependency ID
*/
trackDependency(moduleId, depId) {
if (!this.untrackedDependencies.has(moduleId)) {
this.untrackedDependencies.set(moduleId, new Set());
}
this.untrackedDependencies.get(moduleId).add(depId);
}
/**
* Get a module by id
* @param {string} id - Module id
@@ -56,6 +158,33 @@ export class ModuleRegistry {
return this.modules;
}
/**
* Get dependencies for a module
* @param {string} id - Module id
* @returns {Array<string>} - Array of dependencies
*/
getDependencies(id) {
return this.moduleDependencies.get(id) || [];
}
/**
* Check if the dependency graph has any circular dependencies
* @returns {Array<string>|null} - Array representing the circular dependency path, or null if none
*/
checkForCircularDependencies() {
this.visitedModules.clear();
for (const moduleId in this.modules) {
this.recursionStack.clear();
const result = this.detectCircularDependency(moduleId);
if (result) {
return result;
}
}
return null;
}
/**
* Wait for a module to be ready (in FINISHED state)
* @param {string} id - Module id to wait for
@@ -92,3 +221,6 @@ export class ModuleRegistry {
// Create and export a singleton instance
export const moduleRegistry = new ModuleRegistry();
// Make registry accessible globally
window.moduleRegistry = moduleRegistry;