summaryrefslogtreecommitdiffhomepage
path: root/src/features/plugins/logic/prereqs.ts
diff options
context:
space:
mode:
authorAdam Malczewski <[email protected]>2026-09-03 18:05:29 +0900
committerAdam Malczewski <[email protected]>2026-09-03 18:05:29 +0900
commit3a4922a05930b0dc22740bf5621910803e8f275e (patch)
treed5f831c3d3838cfff346e378f5370a9c58bc2ed3 /src/features/plugins/logic/prereqs.ts
parent33c7245f18346553f660434bc3ac589cff3e80c2 (diff)
downloaddispatch-web-3a4922a05930b0dc22740bf5621910803e8f275e.tar.gz
dispatch-web-3a4922a05930b0dc22740bf5621910803e8f275e.zip
feat(plugin-system): plan 07 frontend plugin manager ui
Diffstat (limited to 'src/features/plugins/logic/prereqs.ts')
-rw-r--r--src/features/plugins/logic/prereqs.ts45
1 files changed, 45 insertions, 0 deletions
diff --git a/src/features/plugins/logic/prereqs.ts b/src/features/plugins/logic/prereqs.ts
new file mode 100644
index 0000000..9066413
--- /dev/null
+++ b/src/features/plugins/logic/prereqs.ts
@@ -0,0 +1,45 @@
+import type { PluginNode } from "./types";
+
+/**
+ * When CHECKING (loading) `targetId`, the transitive set of its dependencies
+ * that are NOT currently loaded — the plugins that must be auto-checked
+ * (loaded) first (§8: "Checking a frontend plugin auto-checks its required
+ * backend plugins (transitively)").
+ *
+ * One-directional by construction: only `dependsOn` edges FROM the target are
+ * followed (frontend→backend / backend→backend). The reverse direction is
+ * NEVER traversed here — backend plugins never depend on frontend ones (§8),
+ * so a dependency auto-check never pulls the other way.
+ *
+ * Returns the ids in deterministic load order (dependencies before their
+ * dependents — alphabetical within a level) so the caller can issue the load
+ * requests in a safe sequence. Pure input → output.
+ */
+export function autoCheckBackendPrereqs(
+ targetId: string,
+ nodes: readonly PluginNode[],
+): readonly string[] {
+ const byId = new Map(nodes.map((n) => [n.id, n]));
+
+ // BFS over dependency edges (target → deps), collecting UNLOADED deps.
+ const out: string[] = [];
+ const seen = new Set<string>([targetId]);
+ // Queue of [id, depth] — sorted per level so ties resolve alphabetically.
+ let frontier: string[] = [targetId];
+ while (frontier.length > 0) {
+ const next: string[] = [];
+ for (const id of frontier) {
+ const node = byId.get(id);
+ for (const dep of node?.dependsOn ?? []) {
+ if (seen.has(dep)) continue;
+ seen.add(dep);
+ next.push(dep);
+ if (!byId.get(dep)?.loaded) out.push(dep);
+ }
+ }
+ frontier = next.sort((a, b) => a.localeCompare(b));
+ }
+ // Load order: dependencies before dependents (BFS level order already is),
+ // alphabetical within a level.
+ return out;
+}