From 786a95d8b62a9aca5d802c0f959d1c9f319ab91a Mon Sep 17 00:00:00 2001 From: Shigma Date: Sat, 18 Jun 2022 00:39:05 +0800 Subject: [PATCH] fix(insight): enhance dependency display, fix #724 --- packages/core/package.json | 2 +- plugins/frontend/insight/src/index.ts | 57 +++++++++++++++------------ 2 files changed, 32 insertions(+), 27 deletions(-) diff --git a/packages/core/package.json b/packages/core/package.json index 12079c53a5..9b9e2364c1 100644 --- a/packages/core/package.json +++ b/packages/core/package.json @@ -36,7 +36,7 @@ }, "dependencies": { "@koishijs/utils": "^5.4.5", - "cordis": "^1.5.1", + "cordis": "^1.5.2", "fastest-levenshtein": "^1.0.12", "minato": "^1.2.0" } diff --git a/plugins/frontend/insight/src/index.ts b/plugins/frontend/insight/src/index.ts index 290bb465f7..85abadebf3 100644 --- a/plugins/frontend/insight/src/index.ts +++ b/plugins/frontend/insight/src/index.ts @@ -73,34 +73,33 @@ class Insight extends DataService { async get() { const nodes: Insight.Node[] = [] const edges: Insight.Link[] = [] - for (const runtime of this.ctx.app.registry.values()) { - // exclude plugins that don't work due to missing dependencies - const services = runtime.using.map(name => this.ctx[name]) - if (services.some(x => !x)) continue - const rid = runtime.uid - const name = getName(runtime.plugin) - const deps = new Set(services.map(({ ctx }) => { - if (!ctx || ctx === ctx.app) return - return ctx.state.uid - }).filter(x => x)) + for (const runtime of this.ctx.app.registry.values()) { + // Suppose we have the following types of nodes: + // - A, B: parent plugin states + // - X, Y: target fork states + // - M: target main state + // - S: service dependencies - // We divide plugins into three categories: + // We can divide plugins into three categories: // 1. fully reusable plugins - // will be displayed as A -> X, B -> Y + // will be displayed as A -> X -> S, B -> Y -> S // 2. partially reusable plugins - // will be displayed as A -> X -> M, B -> Y -> M + // will be displayed as A -> X -> M -> S, B -> Y -> M -> S // 3. non-reusable plugins - // will be displayed as A -> M, B -> M - // where A, B: parent plugin states - // X, Y: target fork states - // M: target main state - // Service dependencies will be connected from the last node of each path + // will be displayed as A -> M -> S, B -> M -> S + + function isActive(state: State) { + // exclude plugins that don't work due to missing dependencies + return runtime.using.every(name => state.context[name]) + } + + const name = getName(runtime.plugin) function addNode(state: State) { const { uid, alias, disposables } = state const weight = disposables.length - const node = { uid, rid, name, weight } + const node = { uid, name, weight } if (alias) node.name += ` <${format(alias)}>` nodes.push(node) } @@ -109,24 +108,31 @@ class Insight extends DataService { edges.push({ type, source, target }) } + function addDeps(state: State) { + for (const name of runtime.using) { + const ctx = state.context[name][Context.source] + const uid = ctx?.state.uid + if (!uid) continue + addEdge('dashed', state.uid, uid) + } + } + const isReusable = runtime.plugin?.['reusable'] if (!isReusable) { + if (!isActive(runtime)) continue addNode(runtime) - for (const target of deps) { - addEdge('dashed', runtime.uid, target) - } + addDeps(runtime) } for (const fork of runtime.children) { if (runtime.isForkable) { + if (!isActive(fork)) continue addNode(fork) addEdge('solid', getSourceId(fork), fork.uid) if (!isReusable) { addEdge('solid', fork.uid, runtime.uid) } else { - for (const target of deps) { - addEdge('dashed', fork.uid, target) - } + addDeps(fork) } } else { nodes[nodes.length - 1].weight += fork.disposables.length @@ -147,7 +153,6 @@ namespace Insight { export interface Node { uid: number - rid: number name: string weight: number }