mirror of
https://github.com/MeshEnvy/mesh-forge.git
synced 2026-08-10 19:03:26 +02:00
feat: enhance PluginToggle and BuildNew components with support for implicit dependencies and dynamic labeling
This commit is contained in:
@@ -44,3 +44,84 @@ export function humanizeStatus(status: string): string {
|
||||
.map((word) => word.charAt(0).toUpperCase() + word.slice(1).toLowerCase())
|
||||
.join(' ')
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolves plugin dependencies recursively from registry.
|
||||
* Returns all plugins that should be enabled (selected plugins + their dependencies).
|
||||
* Filters out "meshtastic" as it's a firmware version requirement, not a plugin.
|
||||
*/
|
||||
export function getDependedPlugins(
|
||||
selectedPlugins: string[],
|
||||
registry: Record<string, { dependencies?: Record<string, string> }>
|
||||
): string[] {
|
||||
const result = new Set<string>()
|
||||
const visited = new Set<string>()
|
||||
|
||||
function resolveDependencies(pluginId: string) {
|
||||
// Prevent circular dependencies
|
||||
if (visited.has(pluginId)) return
|
||||
visited.add(pluginId)
|
||||
|
||||
const plugin = registry[pluginId]
|
||||
if (!plugin || !plugin.dependencies) return
|
||||
|
||||
// Process each dependency
|
||||
for (const [depId] of Object.entries(plugin.dependencies)) {
|
||||
// Skip "meshtastic" - it's a firmware version requirement, not a plugin
|
||||
if (depId === 'meshtastic') continue
|
||||
|
||||
// Only include dependencies that exist in the registry
|
||||
if (depId in registry) {
|
||||
result.add(depId)
|
||||
// Recursively resolve transitive dependencies
|
||||
resolveDependencies(depId)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Start with selected plugins
|
||||
for (const pluginId of selectedPlugins) {
|
||||
if (pluginId in registry) {
|
||||
result.add(pluginId)
|
||||
resolveDependencies(pluginId)
|
||||
}
|
||||
}
|
||||
|
||||
return Array.from(result)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets only the implicit dependencies (dependencies that are not explicitly selected).
|
||||
* Returns a set of plugin IDs that are dependencies but not in the explicitly selected list.
|
||||
*/
|
||||
export function getImplicitDependencies(
|
||||
explicitlySelectedPlugins: string[],
|
||||
registry: Record<string, { dependencies?: Record<string, string> }>
|
||||
): Set<string> {
|
||||
const allDependencies = getDependedPlugins(explicitlySelectedPlugins, registry)
|
||||
const explicitSet = new Set(explicitlySelectedPlugins)
|
||||
return new Set(allDependencies.filter((id) => !explicitSet.has(id)))
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if a plugin is required by any other explicitly selected plugin.
|
||||
* Returns true if the plugin is a dependency (direct or transitive) of at least one explicitly selected plugin.
|
||||
*/
|
||||
export function isRequiredByOther(
|
||||
pluginId: string,
|
||||
explicitlySelectedPlugins: string[],
|
||||
registry: Record<string, { dependencies?: Record<string, string> }>
|
||||
): boolean {
|
||||
// Check if any explicitly selected plugin depends on this plugin
|
||||
for (const selectedId of explicitlySelectedPlugins) {
|
||||
if (selectedId === pluginId) continue // Skip self
|
||||
|
||||
// Get all dependencies (including transitive) of this selected plugin
|
||||
const allDeps = getDependedPlugins([selectedId], registry)
|
||||
if (allDeps.includes(pluginId)) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user