@loopback/context-explorer
Version:
Visualize context hierarchy, bindings, configurations, and dependencies
78 lines (72 loc) • 2.39 kB
JavaScript
// Copyright IBM Corp. 2020. All Rights Reserved.
// Node module: @loopback/context-explorer
// This file is licensed under the MIT License.
// License text available at https://opensource.org/licenses/MIT
/* eslint-disable no-undef */
/**
* Find dependencies of a set of starting nodes, including transitive ones
* @param graph - Graph object
* @param startingNodes - A set of nodes as starting ones
*/
function findDependencies(graph, startingNodes) {
const visited = new Set();
let nodesToBeAdded = new Set(startingNodes);
while (nodesToBeAdded.size !== 0) {
// Try to find nodes that are successors of starting nodes
const matched = new Set();
for (const node of nodesToBeAdded) {
visited.add(node);
const successors = graph.successors(node);
for (const s of successors) {
matched.add(s);
}
}
// Only include nodes found but not visited yet
nodesToBeAdded = new Set();
for (const node of matched) {
if (!visited.has(node)) {
nodesToBeAdded.add(node);
}
visited.add(node);
}
}
return visited;
}
/**
* Filter the graph with a set of starting nodes and their dependencies
* @param graph - Graph object
* @param startingNodes - A set of starting nodes
*/
function filterGraph(graph, startingNodes) {
const selected = findDependencies(graph, startingNodes);
const nodesToBeRemoved = graph
.nodes()
.filter(n => !selected.has(n) && graph.children(n).length === 0);
for (const node of nodesToBeRemoved) {
graph.removeNode(node);
}
removeEmptySubgraphs(graph);
}
function removeEmptySubgraphs(graph) {
// Remove empty subgraphs
// eslint-disable-next-line no-constant-condition
while (true) {
const emptySubgraphs = graph
.nodes()
.filter(n => n.startsWith('cluster_') && graph.children(n).length === 0);
if (emptySubgraphs.length === 0) break;
for (const node of emptySubgraphs) {
graph.removeNode(node);
}
}
}
// eslint-disable-next-line @typescript-eslint/no-unused-vars
function selectNodes(dotGraph, startingNodes) {
const graph = graphlibDot.read(normalizeDot(dotGraph));
filterGraph(graph, startingNodes);
return graphlibDot.write(graph);
}
function normalizeDot(dotGraph) {
// graphlib-dot does not support the trailing `,` after the last attribute
return dotGraph.replace(/,(\s+\];)/gm, '$1');
}