完成世界书、骰子、apiconfig页面处理

This commit is contained in:
2026-04-30 01:35:10 +08:00
parent a3e3711b2b
commit ba9b925c32
4602 changed files with 785225 additions and 23 deletions

View File

@@ -0,0 +1,82 @@
import * as util from './util.js';
export { arrows, setArrows };
var arrows = {
normal,
vee,
undirected,
};
function setArrows(value) {
arrows = value;
}
function normal(parent, id, edge, type) {
var marker = parent
.append('marker')
.attr('id', id)
.attr('viewBox', '0 0 10 10')
.attr('refX', 9)
.attr('refY', 5)
.attr('markerUnits', 'strokeWidth')
.attr('markerWidth', 8)
.attr('markerHeight', 6)
.attr('orient', 'auto');
var path = marker
.append('path')
.attr('d', 'M 0 0 L 10 5 L 0 10 z')
.style('stroke-width', 1)
.style('stroke-dasharray', '1,0');
util.applyStyle(path, edge[type + 'Style']);
if (edge[type + 'Class']) {
path.attr('class', edge[type + 'Class']);
}
}
function vee(parent, id, edge, type) {
var marker = parent
.append('marker')
.attr('id', id)
.attr('viewBox', '0 0 10 10')
.attr('refX', 9)
.attr('refY', 5)
.attr('markerUnits', 'strokeWidth')
.attr('markerWidth', 8)
.attr('markerHeight', 6)
.attr('orient', 'auto');
var path = marker
.append('path')
.attr('d', 'M 0 0 L 10 5 L 0 10 L 4 5 z')
.style('stroke-width', 1)
.style('stroke-dasharray', '1,0');
util.applyStyle(path, edge[type + 'Style']);
if (edge[type + 'Class']) {
path.attr('class', edge[type + 'Class']);
}
}
function undirected(parent, id, edge, type) {
var marker = parent
.append('marker')
.attr('id', id)
.attr('viewBox', '0 0 10 10')
.attr('refX', 9)
.attr('refY', 5)
.attr('markerUnits', 'strokeWidth')
.attr('markerWidth', 8)
.attr('markerHeight', 6)
.attr('orient', 'auto');
var path = marker
.append('path')
.attr('d', 'M 0 5 L 10 5')
.style('stroke-width', 1)
.style('stroke-dasharray', '1,0');
util.applyStyle(path, edge[type + 'Style']);
if (edge[type + 'Class']) {
path.attr('class', edge[type + 'Class']);
}
}

View File

@@ -0,0 +1,49 @@
import * as d3 from 'd3';
import { addLabel } from './label/add-label.js';
import * as util from './util.js';
export { createClusters, setCreateClusters };
var createClusters = function (selection, g) {
var clusters = g.nodes().filter(function (v) {
return util.isSubgraph(g, v);
});
var svgClusters = selection.selectAll('g.cluster').data(clusters, function (v) {
return v;
});
util.applyTransition(svgClusters.exit(), g).style('opacity', 0).remove();
var enterSelection = svgClusters
.enter()
.append('g')
.attr('class', 'cluster')
.attr('id', function (v) {
var node = g.node(v);
return node.id;
})
.style('opacity', 0)
.each(function (v) {
var node = g.node(v);
var thisGroup = d3.select(this);
d3.select(this).append('rect');
var labelGroup = thisGroup.append('g').attr('class', 'label');
addLabel(labelGroup, node, node.clusterLabelPos);
});
svgClusters = svgClusters.merge(enterSelection);
svgClusters = util.applyTransition(svgClusters, g).style('opacity', 1);
svgClusters.selectAll('rect').each(function (c) {
var node = g.node(c);
var domCluster = d3.select(this);
util.applyStyle(domCluster, node.style);
});
return svgClusters;
};
function setCreateClusters(value) {
createClusters = value;
}

View File

@@ -0,0 +1,2 @@
export function createEdgeLabels(selection: any, g: any): any;
export function setCreateEdgeLabels(value: any): void;

View File

@@ -0,0 +1,53 @@
import * as d3 from 'd3';
import { addLabel } from './label/add-label.js';
import * as util from './util.js';
export { createEdgeLabels, setCreateEdgeLabels };
let createEdgeLabels = function (selection, g) {
var svgEdgeLabels = selection
.selectAll('g.edgeLabel')
.data(g.edges(), function (e) {
return util.edgeToId(e);
})
.classed('update', true);
svgEdgeLabels.exit().remove();
svgEdgeLabels.enter().append('g').classed('edgeLabel', true).style('opacity', 0);
svgEdgeLabels = selection.selectAll('g.edgeLabel');
svgEdgeLabels.each(function (e) {
var root = d3.select(this);
root.select('.label').remove();
var edge = g.edge(e);
var label = addLabel(root, g.edge(e), 0).classed('label', true);
var bbox = label.node().getBBox();
if (edge.labelId) {
label.attr('id', edge.labelId);
}
if (!Object.prototype.hasOwnProperty.call(edge, 'width')) {
edge.width = bbox.width;
}
if (!Object.prototype.hasOwnProperty.call(edge, 'height')) {
edge.height = bbox.height;
}
});
var exitSelection;
if (svgEdgeLabels.exit) {
exitSelection = svgEdgeLabels.exit();
} else {
exitSelection = svgEdgeLabels.selectAll(null); // empty selection
}
util.applyTransition(exitSelection, g).style('opacity', 0).remove();
return svgEdgeLabels;
};
function setCreateEdgeLabels(value) {
createEdgeLabels = value;
}

View File

@@ -0,0 +1,132 @@
import * as d3 from 'd3';
import * as _ from 'lodash-es';
import { intersectNode } from './intersect/intersect-node.js';
import * as util from './util.js';
export { createEdgePaths, setCreateEdgePaths };
var createEdgePaths = function (selection, g, arrows) {
var previousPaths = selection
.selectAll('g.edgePath')
.data(g.edges(), function (e) {
return util.edgeToId(e);
})
.classed('update', true);
var newPaths = enter(previousPaths, g);
exit(previousPaths, g);
var svgPaths = previousPaths.merge !== undefined ? previousPaths.merge(newPaths) : previousPaths;
util.applyTransition(svgPaths, g).style('opacity', 1);
// Save DOM element in the path group, and set ID and class
svgPaths.each(function (e) {
var domEdge = d3.select(this);
var edge = g.edge(e);
edge.elem = this;
if (edge.id) {
domEdge.attr('id', edge.id);
}
util.applyClass(
domEdge,
edge['class'],
(domEdge.classed('update') ? 'update ' : '') + 'edgePath',
);
});
svgPaths.selectAll('path.path').each(function (e) {
var edge = g.edge(e);
edge.arrowheadId = _.uniqueId('arrowhead');
var domEdge = d3
.select(this)
.attr('marker-end', function () {
return 'url(' + makeFragmentRef(location.href, edge.arrowheadId) + ')';
})
.style('fill', 'none');
util.applyTransition(domEdge, g).attr('d', function (e) {
return calcPoints(g, e);
});
util.applyStyle(domEdge, edge.style);
});
svgPaths.selectAll('defs *').remove();
svgPaths.selectAll('defs').each(function (e) {
var edge = g.edge(e);
var arrowhead = arrows[edge.arrowhead];
arrowhead(d3.select(this), edge.arrowheadId, edge, 'arrowhead');
});
return svgPaths;
};
function setCreateEdgePaths(value) {
createEdgePaths = value;
}
function makeFragmentRef(url, fragmentId) {
var baseUrl = url.split('#')[0];
return baseUrl + '#' + fragmentId;
}
function calcPoints(g, e) {
var edge = g.edge(e);
var tail = g.node(e.v);
var head = g.node(e.w);
var points = edge.points.slice(1, edge.points.length - 1);
points.unshift(intersectNode(tail, points[0]));
points.push(intersectNode(head, points[points.length - 1]));
return createLine(edge, points);
}
function createLine(edge, points) {
// @ts-expect-error
var line = (d3.line || d3.svg.line)()
.x(function (d) {
return d.x;
})
.y(function (d) {
return d.y;
});
(line.curve || line.interpolate)(edge.curve);
return line(points);
}
function getCoords(elem) {
var bbox = elem.getBBox();
var matrix = elem.ownerSVGElement
.getScreenCTM()
.inverse()
.multiply(elem.getScreenCTM())
.translate(bbox.width / 2, bbox.height / 2);
return { x: matrix.e, y: matrix.f };
}
function enter(svgPaths, g) {
var svgPathsEnter = svgPaths.enter().append('g').attr('class', 'edgePath').style('opacity', 0);
svgPathsEnter
.append('path')
.attr('class', 'path')
.attr('d', function (e) {
var edge = g.edge(e);
var sourceElem = g.node(e.v).elem;
var points = _.range(edge.points.length).map(function () {
return getCoords(sourceElem);
});
return createLine(edge, points);
});
svgPathsEnter.append('defs');
return svgPathsEnter;
}
function exit(svgPaths, g) {
var svgPathExit = svgPaths.exit();
util.applyTransition(svgPathExit, g).style('opacity', 0).remove();
}

View File

@@ -0,0 +1,4 @@
export function intersectCircle(node: any, rx: any, point: any): {
x: any;
y: any;
};

View File

@@ -0,0 +1,7 @@
import { intersectEllipse } from './intersect-ellipse.js';
export { intersectCircle };
function intersectCircle(node, rx, point) {
return intersectEllipse(node, rx, rx, point);
}

View File

@@ -0,0 +1,4 @@
export function intersectEllipse(node: any, rx: any, ry: any, point: any): {
x: any;
y: any;
};

View File

@@ -0,0 +1,5 @@
export { intersectNode };
function intersectNode(node, point) {
return node.intersect(point);
}

View File

@@ -0,0 +1,13 @@
import * as util from '../util.js';
export { addSVGLabel };
function addSVGLabel(root, node) {
var domNode = root;
domNode.node().appendChild(node.label);
util.applyStyle(domNode, node.labelStyle);
return domNode;
}

View File

@@ -0,0 +1,48 @@
import * as util from '../util.js';
export { addTextLabel };
/*
* Attaches a text label to the specified root. Handles escape sequences.
*/
function addTextLabel(root, node) {
var domNode = root.append('text');
var lines = processEscapeSequences(node.label).split('\n');
for (var i = 0; i < lines.length; i++) {
domNode
.append('tspan')
.attr('xml:space', 'preserve')
.attr('dy', '1em')
.attr('x', '1')
.text(lines[i]);
}
util.applyStyle(domNode, node.labelStyle);
return domNode;
}
function processEscapeSequences(text) {
var newText = '';
var escaped = false;
var ch;
for (var i = 0; i < text.length; ++i) {
ch = text[i];
if (escaped) {
switch (ch) {
case 'n':
newText += '\n';
break;
default:
newText += ch;
}
escaped = false;
} else if (ch === '\\') {
escaped = true;
} else {
newText += ch;
}
}
return newText;
}

View File

@@ -0,0 +1 @@
export function positionEdgeLabels(selection: any, g: any): void;

View File

@@ -0,0 +1,48 @@
export type Node = {
/**
* - The label of the node.
*/
label: string;
/**
* - The horizontal padding of the node.
*/
paddingX?: number;
/**
* - The vertical padding of the node.
*/
paddingY?: number;
/**
* - The padding of the node for all directions. Overrides `paddingX` and `paddingY`.
*/
padding?: number;
/**
* - The left padding of the node.
*/
paddingLeft?: number;
/**
* - The right padding of the node.
*/
paddingRight?: number;
_prevWidth?: number;
width?: number;
_prevHeight?: number;
height?: number;
};
export function render(): {
(svg: any, g: any): void;
createNodes(value: any, ...args: any[]): (selection: any, g: any, shapes: any) => any;
createClusters(value: any, ...args: any[]): (selection: any, g: any) => any;
createEdgeLabels(value: any, ...args: any[]): (selection: any, g: any) => any;
createEdgePaths(value: any, ...args: any[]): (selection: any, g: any, arrows: any) => any;
shapes(value: any, ...args: any[]): {
rect: (parent: any, bbox: any, node: any) => any;
ellipse: (parent: any, bbox: any, node: any) => any;
circle: (parent: any, bbox: any, node: any) => any;
diamond: (parent: any, bbox: any, node: any) => any;
} | /*elided*/ any;
arrows(value: any, ...args: any[]): {
normal: (parent: any, id: any, edge: any, type: any) => void;
vee: (parent: any, id: any, edge: any, type: any) => void;
undirected: (parent: any, id: any, edge: any, type: any) => void;
} | /*elided*/ any;
};

View File

@@ -0,0 +1,5 @@
export function isSubgraph(g: any, v: any): boolean;
export function edgeToId(e: any): string;
export function applyStyle(dom: any, styleFn: any): void;
export function applyClass(dom: any, classFn: any, otherClasses: any): void;
export function applyTransition(selection: any, g: any): any;

60
frontend/node_modules/dagre-d3-es/src/dagre/acyclic.js generated vendored Normal file
View File

@@ -0,0 +1,60 @@
import * as _ from 'lodash-es';
import { greedyFAS } from './greedy-fas.js';
export { run, undo };
function run(g) {
var fas = g.graph().acyclicer === 'greedy' ? greedyFAS(g, weightFn(g)) : dfsFAS(g);
_.forEach(fas, function (e) {
var label = g.edge(e);
g.removeEdge(e);
label.forwardName = e.name;
label.reversed = true;
g.setEdge(e.w, e.v, label, _.uniqueId('rev'));
});
function weightFn(g) {
return function (e) {
return g.edge(e).weight;
};
}
}
function dfsFAS(g) {
var fas = [];
var stack = {};
var visited = {};
function dfs(v) {
if (Object.prototype.hasOwnProperty.call(visited, v)) {
return;
}
visited[v] = true;
stack[v] = true;
_.forEach(g.outEdges(v), function (e) {
if (Object.prototype.hasOwnProperty.call(stack, e.w)) {
fas.push(e);
} else {
dfs(e.w);
}
});
delete stack[v];
}
_.forEach(g.nodes(), dfs);
return fas;
}
function undo(g) {
_.forEach(g.edges(), function (e) {
var label = g.edge(e);
if (label.reversed) {
g.removeEdge(e);
var forwardName = label.forwardName;
delete label.reversed;
delete label.forwardName;
g.setEdge(e.w, e.v, label, forwardName);
}
});
}

View File

@@ -0,0 +1,2 @@
export function debugOrdering(g: any): Graph<any, any, any>;
import { Graph } from '../graphlib/index.js';

View File

@@ -0,0 +1,126 @@
import * as _ from 'lodash-es';
import { Graph } from '../graphlib/index.js';
import { List } from './data/list.js';
/*
* A greedy heuristic for finding a feedback arc set for a graph. A feedback
* arc set is a set of edges that can be removed to make a graph acyclic.
* The algorithm comes from: P. Eades, X. Lin, and W. F. Smyth, "A fast and
* effective heuristic for the feedback arc set problem." This implementation
* adjusts that from the paper to allow for weighted edges.
*/
export { greedyFAS };
var DEFAULT_WEIGHT_FN = _.constant(1);
function greedyFAS(g, weightFn) {
if (g.nodeCount() <= 1) {
return [];
}
var state = buildState(g, weightFn || DEFAULT_WEIGHT_FN);
var results = doGreedyFAS(state.graph, state.buckets, state.zeroIdx);
// Expand multi-edges
return _.flatten(
_.map(results, function (e) {
return g.outEdges(e.v, e.w);
}),
);
}
function doGreedyFAS(g, buckets, zeroIdx) {
var results = [];
var sources = buckets[buckets.length - 1];
var sinks = buckets[0];
var entry;
while (g.nodeCount()) {
while ((entry = sinks.dequeue())) {
removeNode(g, buckets, zeroIdx, entry);
}
while ((entry = sources.dequeue())) {
removeNode(g, buckets, zeroIdx, entry);
}
if (g.nodeCount()) {
for (var i = buckets.length - 2; i > 0; --i) {
entry = buckets[i].dequeue();
if (entry) {
results = results.concat(removeNode(g, buckets, zeroIdx, entry, true));
break;
}
}
}
}
return results;
}
function removeNode(g, buckets, zeroIdx, entry, collectPredecessors) {
var results = collectPredecessors ? [] : undefined;
_.forEach(g.inEdges(entry.v), function (edge) {
var weight = g.edge(edge);
var uEntry = g.node(edge.v);
if (collectPredecessors) {
results.push({ v: edge.v, w: edge.w });
}
uEntry.out -= weight;
assignBucket(buckets, zeroIdx, uEntry);
});
_.forEach(g.outEdges(entry.v), function (edge) {
var weight = g.edge(edge);
var w = edge.w;
var wEntry = g.node(w);
wEntry['in'] -= weight;
assignBucket(buckets, zeroIdx, wEntry);
});
g.removeNode(entry.v);
return results;
}
function buildState(g, weightFn) {
var fasGraph = new Graph();
var maxIn = 0;
var maxOut = 0;
_.forEach(g.nodes(), function (v) {
fasGraph.setNode(v, { v: v, in: 0, out: 0 });
});
// Aggregate weights on nodes, but also sum the weights across multi-edges
// into a single edge for the fasGraph.
_.forEach(g.edges(), function (e) {
var prevWeight = fasGraph.edge(e.v, e.w) || 0;
var weight = weightFn(e);
var edgeWeight = prevWeight + weight;
fasGraph.setEdge(e.v, e.w, edgeWeight);
maxOut = Math.max(maxOut, (fasGraph.node(e.v).out += weight));
maxIn = Math.max(maxIn, (fasGraph.node(e.w)['in'] += weight));
});
var buckets = _.range(maxOut + maxIn + 3).map(function () {
return new List();
});
var zeroIdx = maxIn + 1;
_.forEach(fasGraph.nodes(), function (v) {
assignBucket(buckets, zeroIdx, fasGraph.node(v));
});
return { graph: fasGraph, buckets: buckets, zeroIdx: zeroIdx };
}
function assignBucket(buckets, zeroIdx, entry) {
if (!entry.out) {
buckets[0].enqueue(entry);
} else if (!entry['in']) {
buckets[buckets.length - 1].enqueue(entry);
} else {
buckets[entry.out - entry['in'] + zeroIdx].enqueue(entry);
}
}

6
frontend/node_modules/dagre-d3-es/src/dagre/index.js generated vendored Normal file
View File

@@ -0,0 +1,6 @@
import * as acyclic from './acyclic.js';
import { layout } from './layout.js';
import * as normalize from './normalize.js';
import { rank } from './rank/index.js';
export { acyclic, normalize, rank, layout };

View File

@@ -0,0 +1,2 @@
export function run(g: any): void;
export function cleanup(g: any): void;

View File

@@ -0,0 +1,137 @@
import * as _ from 'lodash-es';
import * as util from './util.js';
export { run, cleanup };
/*
* A nesting graph creates dummy nodes for the tops and bottoms of subgraphs,
* adds appropriate edges to ensure that all cluster nodes are placed between
* these boundries, and ensures that the graph is connected.
*
* In addition we ensure, through the use of the minlen property, that nodes
* and subgraph border nodes to not end up on the same rank.
*
* Preconditions:
*
* 1. Input graph is a DAG
* 2. Nodes in the input graph has a minlen attribute
*
* Postconditions:
*
* 1. Input graph is connected.
* 2. Dummy nodes are added for the tops and bottoms of subgraphs.
* 3. The minlen attribute for nodes is adjusted to ensure nodes do not
* get placed on the same rank as subgraph border nodes.
*
* The nesting graph idea comes from Sander, "Layout of Compound Directed
* Graphs."
*/
function run(g) {
var root = util.addDummyNode(g, 'root', {}, '_root');
var depths = treeDepths(g);
var height = _.max(_.values(depths)) - 1; // Note: depths is an Object not an array
var nodeSep = 2 * height + 1;
g.graph().nestingRoot = root;
// Multiply minlen by nodeSep to align nodes on non-border ranks.
_.forEach(g.edges(), function (e) {
g.edge(e).minlen *= nodeSep;
});
// Calculate a weight that is sufficient to keep subgraphs vertically compact
var weight = sumWeights(g) + 1;
// Create border nodes and link them up
_.forEach(g.children(), function (child) {
dfs(g, root, nodeSep, weight, height, depths, child);
});
// Save the multiplier for node layers for later removal of empty border
// layers.
g.graph().nodeRankFactor = nodeSep;
}
function dfs(g, root, nodeSep, weight, height, depths, v) {
var children = g.children(v);
if (!children.length) {
if (v !== root) {
g.setEdge(root, v, { weight: 0, minlen: nodeSep });
}
return;
}
var top = util.addBorderNode(g, '_bt');
var bottom = util.addBorderNode(g, '_bb');
var label = g.node(v);
g.setParent(top, v);
label.borderTop = top;
g.setParent(bottom, v);
label.borderBottom = bottom;
_.forEach(children, function (child) {
dfs(g, root, nodeSep, weight, height, depths, child);
var childNode = g.node(child);
var childTop = childNode.borderTop ? childNode.borderTop : child;
var childBottom = childNode.borderBottom ? childNode.borderBottom : child;
var thisWeight = childNode.borderTop ? weight : 2 * weight;
var minlen = childTop !== childBottom ? 1 : height - depths[v] + 1;
g.setEdge(top, childTop, {
weight: thisWeight,
minlen: minlen,
nestingEdge: true,
});
g.setEdge(childBottom, bottom, {
weight: thisWeight,
minlen: minlen,
nestingEdge: true,
});
});
if (!g.parent(v)) {
g.setEdge(root, top, { weight: 0, minlen: height + depths[v] });
}
}
function treeDepths(g) {
var depths = {};
function dfs(v, depth) {
var children = g.children(v);
if (children && children.length) {
_.forEach(children, function (child) {
dfs(child, depth + 1);
});
}
depths[v] = depth;
}
_.forEach(g.children(), function (v) {
dfs(v, 1);
});
return depths;
}
function sumWeights(g) {
return _.reduce(
g.edges(),
function (acc, e) {
return acc + g.edge(e).weight;
},
0,
);
}
function cleanup(g) {
var graphLabel = g.graph();
g.removeNode(graphLabel.nestingRoot);
delete graphLabel.nestingRoot;
_.forEach(g.edges(), function (e) {
var edge = g.edge(e);
if (edge.nestingEdge) {
g.removeEdge(e);
}
});
}

View File

@@ -0,0 +1,2 @@
export function run(g: any): void;
export function undo(g: any): void;

View File

@@ -0,0 +1 @@
export function addSubgraphConstraints(g: any, cg: any, vs: any): void;

View File

@@ -0,0 +1,76 @@
import * as _ from 'lodash-es';
import { Graph } from '../../graphlib/index.js';
export { buildLayerGraph };
/*
* Constructs a graph that can be used to sort a layer of nodes. The graph will
* contain all base and subgraph nodes from the request layer in their original
* hierarchy and any edges that are incident on these nodes and are of the type
* requested by the "relationship" parameter.
*
* Nodes from the requested rank that do not have parents are assigned a root
* node in the output graph, which is set in the root graph attribute. This
* makes it easy to walk the hierarchy of movable nodes during ordering.
*
* Pre-conditions:
*
* 1. Input graph is a DAG
* 2. Base nodes in the input graph have a rank attribute
* 3. Subgraph nodes in the input graph has minRank and maxRank attributes
* 4. Edges have an assigned weight
*
* Post-conditions:
*
* 1. Output graph has all nodes in the movable rank with preserved
* hierarchy.
* 2. Root nodes in the movable layer are made children of the node
* indicated by the root attribute of the graph.
* 3. Non-movable nodes incident on movable nodes, selected by the
* relationship parameter, are included in the graph (without hierarchy).
* 4. Edges incident on movable nodes, selected by the relationship
* parameter, are added to the output graph.
* 5. The weights for copied edges are aggregated as need, since the output
* graph is not a multi-graph.
*/
function buildLayerGraph(g, rank, relationship) {
var root = createRootNode(g),
result = new Graph({ compound: true })
.setGraph({ root: root })
.setDefaultNodeLabel(function (v) {
return g.node(v);
});
_.forEach(g.nodes(), function (v) {
var node = g.node(v),
parent = g.parent(v);
if (node.rank === rank || (node.minRank <= rank && rank <= node.maxRank)) {
result.setNode(v);
result.setParent(v, parent || root);
// This assumes we have only short edges!
_.forEach(g[relationship](v), function (e) {
var u = e.v === v ? e.w : e.v,
edge = result.edge(u, v),
weight = !_.isUndefined(edge) ? edge.weight : 0;
result.setEdge(u, v, { weight: g.edge(e).weight + weight });
});
if (Object.prototype.hasOwnProperty.call(node, 'minRank')) {
result.setNode(v, {
borderLeft: node.borderLeft[rank],
borderRight: node.borderRight[rank],
});
}
}
});
return result;
}
function createRootNode(g) {
var v;
while (g.hasNode((v = _.uniqueId('_root'))));
return v;
}

View File

@@ -0,0 +1,3 @@
export function sortSubgraph(g: any, v: any, cg: any, biasRight: any): {
vs: any[];
};

View File

@@ -0,0 +1,46 @@
export function positionX(g: any): {
[x: string]: any;
};
export function findType1Conflicts(g: any, layering: any): {
[nodeId: string]: {
[nodeId: string]: true;
[nodeId: number]: true;
};
[nodeId: number]: {
[nodeId: string]: true;
[nodeId: number]: true;
};
};
export function findType2Conflicts(g: any, layering: any): {
[nodeId: string]: {
[nodeId: string]: true;
[nodeId: number]: true;
};
[nodeId: number]: {
[nodeId: string]: true;
[nodeId: number]: true;
};
};
/**
* Sets `conflicts[v][w] = true`, creating objects if needed.
*
* @param {{[nodeId: string | number]: {[nodeId: string | number]: true}}} conflicts - Object to set.
* @param {string | number} v - First Node ID
* @param {string | number} w - Second Node ID
*/
export function addConflict(conflicts: {
[nodeId: string | number]: {
[nodeId: string | number]: true;
};
}, v: string | number, w: string | number): void;
export function hasConflict(conflicts: any, v: any, w: any): any;
export function verticalAlignment(g: any, layering: any, conflicts: any, neighborFn: any): {
root: {};
align: {};
};
export function horizontalCompaction(g: any, layering: any, root: any, align: any, reverseSep: any): Record<string, number>;
export function alignCoordinates(xss: any, alignTo: any): void;
export function findSmallestWidthAlignment(g: any, xss: any): any;
export function balance(xss: any, align: any): {
[x: string]: any;
};

View File

@@ -0,0 +1 @@
export function position(g: any): void;

View File

@@ -0,0 +1,31 @@
import * as _ from 'lodash-es';
import * as util from '../util.js';
import { positionX } from './bk.js';
export { position };
function position(g) {
g = util.asNonCompoundGraph(g);
positionY(g);
_.forOwn(positionX(g), function (x, v) {
g.node(v).x = x;
});
}
function positionY(g) {
var layering = util.buildLayerMatrix(g);
var rankSep = g.graph().ranksep;
var prevY = 0;
_.forEach(layering, function (layer) {
var maxHeight = _.max(
_.map(layer, function (v) {
return g.node(v).height;
}),
);
_.forEach(layer, function (v) {
g.node(v).y = prevY + maxHeight / 2;
});
prevY += maxHeight + rankSep;
});
}

View File

@@ -0,0 +1,87 @@
import * as _ from 'lodash-es';
import { Graph } from '../../graphlib/index.js';
import { slack } from './util.js';
export { feasibleTree };
/*
* Constructs a spanning tree with tight edges and adjusted the input node's
* ranks to achieve this. A tight edge is one that is has a length that matches
* its "minlen" attribute.
*
* The basic structure for this function is derived from Gansner, et al., "A
* Technique for Drawing Directed Graphs."
*
* Pre-conditions:
*
* 1. Graph must be a DAG.
* 2. Graph must be connected.
* 3. Graph must have at least one node.
* 5. Graph nodes must have been previously assigned a "rank" property that
* respects the "minlen" property of incident edges.
* 6. Graph edges must have a "minlen" property.
*
* Post-conditions:
*
* - Graph nodes will have their rank adjusted to ensure that all edges are
* tight.
*
* Returns a tree (undirected graph) that is constructed using only "tight"
* edges.
*/
function feasibleTree(g) {
var t = new Graph({ directed: false });
// Choose arbitrary node from which to start our tree
var start = g.nodes()[0];
var size = g.nodeCount();
t.setNode(start, {});
var edge, delta;
while (tightTree(t, g) < size) {
edge = findMinSlackEdge(t, g);
delta = t.hasNode(edge.v) ? slack(g, edge) : -slack(g, edge);
shiftRanks(t, g, delta);
}
return t;
}
/*
* Finds a maximal tree of tight edges and returns the number of nodes in the
* tree.
*/
function tightTree(t, g) {
function dfs(v) {
_.forEach(g.nodeEdges(v), function (e) {
var edgeV = e.v,
w = v === edgeV ? e.w : edgeV;
if (!t.hasNode(w) && !slack(g, e)) {
t.setNode(w, {});
t.setEdge(v, w, {});
dfs(w);
}
});
}
_.forEach(t.nodes(), dfs);
return t.nodeCount();
}
/*
* Finds the edge with the smallest slack that is incident on tree and returns
* it.
*/
function findMinSlackEdge(t, g) {
return _.minBy(g.edges(), function (e) {
if (t.hasNode(e.v) !== t.hasNode(e.w)) {
return slack(g, e);
}
});
}
function shiftRanks(t, g, delta) {
_.forEach(t.nodes(), function (v) {
g.node(v).rank += delta;
});
}

View File

@@ -0,0 +1,52 @@
import { feasibleTree } from './feasible-tree.js';
import { networkSimplex } from './network-simplex.js';
import { longestPath } from './util.js';
export { rank };
/*
* Assigns a rank to each node in the input graph that respects the "minlen"
* constraint specified on edges between nodes.
*
* This basic structure is derived from Gansner, et al., "A Technique for
* Drawing Directed Graphs."
*
* Pre-conditions:
*
* 1. Graph must be a connected DAG
* 2. Graph nodes must be objects
* 3. Graph edges must have "weight" and "minlen" attributes
*
* Post-conditions:
*
* 1. Graph nodes will have a "rank" attribute based on the results of the
* algorithm. Ranks can start at any index (including negative), we'll
* fix them up later.
*/
function rank(g) {
switch (g.graph().ranker) {
case 'network-simplex':
networkSimplexRanker(g);
break;
case 'tight-tree':
tightTreeRanker(g);
break;
case 'longest-path':
longestPathRanker(g);
break;
default:
networkSimplexRanker(g);
}
}
// A fast and simple ranker, but results are far from optimal.
var longestPathRanker = longestPath;
function tightTreeRanker(g) {
longestPath(g);
feasibleTree(g);
}
function networkSimplexRanker(g) {
networkSimplex(g);
}

View File

@@ -0,0 +1,2 @@
export function longestPath(g: any): void;
export function slack(g: any, e: any): number;

View File

@@ -0,0 +1,63 @@
import * as _ from 'lodash-es';
export { longestPath, slack };
/*
* Initializes ranks for the input graph using the longest path algorithm. This
* algorithm scales well and is fast in practice, it yields rather poor
* solutions. Nodes are pushed to the lowest layer possible, leaving the bottom
* ranks wide and leaving edges longer than necessary. However, due to its
* speed, this algorithm is good for getting an initial ranking that can be fed
* into other algorithms.
*
* This algorithm does not normalize layers because it will be used by other
* algorithms in most cases. If using this algorithm directly, be sure to
* run normalize at the end.
*
* Pre-conditions:
*
* 1. Input graph is a DAG.
* 2. Input graph node labels can be assigned properties.
*
* Post-conditions:
*
* 1. Each node will be assign an (unnormalized) "rank" property.
*/
function longestPath(g) {
var visited = {};
function dfs(v) {
var label = g.node(v);
if (Object.prototype.hasOwnProperty.call(visited, v)) {
return label.rank;
}
visited[v] = true;
var rank = _.min(
_.map(g.outEdges(v), function (e) {
return dfs(e.w) - g.edge(e).minlen;
}),
);
if (
rank === Number.POSITIVE_INFINITY || // return value of _.map([]) for Lodash 3
rank === undefined || // return value of _.map([]) for Lodash 4
rank === null
) {
// return value of _.map([null])
rank = 0;
}
return (label.rank = rank);
}
_.forEach(g.sources(), dfs);
}
/*
* Returns the amount of slack for the given edge. The slack is defined as the
* difference between the length of the edge and its minimum length.
*/
function slack(g, e) {
return g.node(e.w).rank - g.node(e.v).rank - g.edge(e).minlen;
}

21
frontend/node_modules/dagre-d3-es/src/dagre/util.d.ts generated vendored Normal file
View File

@@ -0,0 +1,21 @@
export function addDummyNode(g: any, type: any, attrs: any, name: any): string;
export function simplify(g: any): Graph<any, any, any>;
export function asNonCompoundGraph(g: any): Graph<any, any, any>;
export function successorWeights(g: any): import("lodash").Dictionary<{}>;
export function predecessorWeights(g: any): import("lodash").Dictionary<{}>;
export function intersectRect(rect: any, point: any): {
x: any;
y: any;
};
export function buildLayerMatrix(g: any): any[][];
export function normalizeRanks(g: any): void;
export function removeEmptyRanks(g: any): void;
export function addBorderNode(g: any, prefix: any, rank: any, order: any, ...args: any[]): string;
export function maxRank(g: any): any;
export function partition(collection: any, fn: any): {
lhs: any[];
rhs: any[];
};
export function time(name: any, fn: any): any;
export function notime(name: any, fn: any): any;
import { Graph } from '../graphlib/index.js';

View File

@@ -0,0 +1,66 @@
export type PathEntry = {
/**
* The sum of the weights from `source` to `v`
* along the shortest path or `Number.POSITIVE_INFINITY` if there is no path
* from `source`.
*/
distance: number;
/**
* Can be used to walk the individual
* elements of the path from `source` to `v` in reverse order.
*/
predecessor?: NodeID;
};
/**
* @typedef {Object} PathEntry
* @property {number} distance The sum of the weights from `source` to `v`
* along the shortest path or `Number.POSITIVE_INFINITY` if there is no path
* from `source`.
* @property {NodeID} [predecessor] Can be used to walk the individual
* elements of the path from `source` to `v` in reverse order.
*/
/**
* This function is an implementation of [Dijkstra's algorithm][] which finds
* the shortest path from `source` to all other nodes in `g`. This
* function returns
*
* [Dijkstra's algorithm]: http://en.wikipedia.org/wiki/Dijkstra%27s_algorithm
*
* @example
*
* ![](https://github.com/dagrejs/graphlib/wiki/images/dijkstra-source.png)
* <!-- SOURCE:
* http://dagrejs.github.io/project/dagre-d3/latest/demo/interactive-demo.html?graph=digraph%20%7B%0Anode%20%5Bshape%3Dcircle%2C%20style%3D%22fill%3Awhite%3Bstroke%3A%23333%3Bstroke-width%3A1.5px%22%5D%0Aedge%20%5Blabeloffset%3D2%20labelpos%3Dr%5D%0Arankdir%3Dlr%0A%20%20A%20-%3E%20B%5Blabel%3D10%5D%0A%20%20A%20-%3E%20C%5Blabel%3D4%5D%0A%20%20A%20-%3E%20D%5Blabel%3D2%5D%0A%20%20C%20-%3E%20B%5Blabel%3D2%5D%0A%20%20C%20-%3E%20D%5Blabel%3D8%5D%0A%20%20B%20-%3E%20E%5Blabel%3D6%5D%0A%20%20D%20-%3E%20F%5Blabel%3D2%5D%0A%20%20F%20-%3E%20E%5Blabel%3D4%5D%0A%7D
* -->
*
* ```js
* function weight(e) { return g.edge(e); }
*
* graphlib.alg.dijkstra(g, "A", weight);
* // => { A: { distance: 0 },
* // B: { distance: 6, predecessor: 'C' },
* // C: { distance: 4, predecessor: 'A' },
* // D: { distance: 2, predecessor: 'A' },
* // E: { distance: 8, predecessor: 'F' },
* // F: { distance: 4, predecessor: 'D' } }
* ```
*
* @remarks It takes `O((|E| + |V|) * log |V|)` time.
*
* @param {Graph} g - Input graph.
* @param {NodeID | number} source - The source node id. Converted to a string.
* @param {(e: EdgeObj) => number} [weightFn] - Optional function that returns
* the weight for edge `e`. If no `weightFn` is supplied then each edge is
* assumed to have a weight of 1.
* @param {(v: NodeID) => EdgeObj[]} [edgeFn] - Optional function that returns
* the ids of all edges incident to the node `v` for the purposes of shortest
* path traversal.
* By default this function uses the {@link Graph.outEdges} function on the
* supplied graph.
* @returns {Record<NodeID, PathEntry>} a map of `v -> { distance, predecessor }`.
* @throws {Error} If any of the traversed edges has a negative edge weight.
*/
export function dijkstra(g: Graph, source: NodeID | number, weightFn?: (e: EdgeObj) => number, edgeFn?: (v: NodeID) => EdgeObj[]): Record<NodeID, PathEntry>;
import type { NodeID } from '../graph.js';
import type { Graph } from '../graph.js';
import type { EdgeObj } from '../graph.js';

View File

@@ -0,0 +1,43 @@
/**
* Given a Graph, `g`, this function returns all nodes that
* are part of a cycle. As there may be more than one cycle in a graph this
* function return an array of these cycles, where each cycle is itself
* represented by an array of ids for each node involved in that cycle.
*
* @remarks
*
* {@link isAcyclic} is more efficient if you only need to
* determine whether a graph has a cycle or not.
*
* @example
*
* ```js
* var g = new graphlib.Graph();
* g.setNode(1);
* g.setNode(2);
* g.setNode(3);
* g.setEdge(1, 2);
* g.setEdge(2, 3);
*
* graphlib.alg.findCycles(g);
* // => []
*
* g.setEdge(3, 1);
* graphlib.alg.findCycles(g);
* // => [ [ '3', '2', '1' ] ]
*
* g.setNode(4);
* g.setNode(5);
* g.setEdge(4, 5);
* g.setEdge(5, 4);
* graphlib.alg.findCycles(g);
* // => [ [ '3', '2', '1' ], [ '5', '4' ] ]
* ```
*
* @param {Graph} g - The graph to analyze.
* @returns {NodeID[][]} An array of cycles. Each cycle is itself an array
* that contains the ids of all nodes in the cycle.
*/
export function findCycles(g: Graph): NodeID[][];
import type { Graph } from '../graph.js';
import type { NodeID } from '../graph.js';

View File

@@ -0,0 +1,57 @@
/**
* This function is an implementation of the [Floyd-Warshall algorithm][],
* which finds the shortest path from each node to every other reachable node
* in the graph. It is similar to {@link dijkstraAll}, but
* it handles negative edge weights and is more efficient for some types of
* graphs.
*
* [Floyd-Warshall algorithm]: https://en.wikipedia.org/wiki/Floyd-Warshall_algorithm
*
* @remarks This algorithm takes `O(|V|^3)` time.
*
* @example
*
* ![](https://github.com/dagrejs/graphlib/wiki/images/dijkstra-source.png)
*
* ```js
* function weight(e) { return g.edge(e); }
*
* graphlib.alg.floydWarshall(g, function(e) { return g.edge(e); });
*
* // => { A:
* // { A: { distance: 0 },
* // B: { distance: 6, predecessor: 'C' },
* // C: { distance: 4, predecessor: 'A' },
* // D: { distance: 2, predecessor: 'A' },
* // E: { distance: 8, predecessor: 'F' },
* // F: { distance: 4, predecessor: 'D' } },
* // B:
* // { A: { distance: Infinity },
* // B: { distance: 0 },
* // C: { distance: Infinity },
* // D: { distance: Infinity },
* // E: { distance: 6, predecessor: 'B' },
* // F: { distance: Infinity } },
* // C: { ... },
* // D: { ... },
* // E: { ... },
* // F: { ... } }
* ```
*
* @param {Graph} g - The graph to analyze.
* @param {(e: EdgeObj) => number} [weightFn] - Optional function that returns
* the weight for edge `e`. If no `weightFn` is supplied then each edge is
* assumed to have a weight of 1.
* @param {(v: NodeID) => EdgeObj[]} [edgeFn] - Optional function that returns
* the ids of all edges incident to the node `v` for the purposes of shortest
* path traversal.
* By default this function uses the {@link Graph.outEdges} function on the
* supplied graph.
* @returns {Record<NodeID, Record<NodeID, PathEntry>>} a map of
* `source -> { target -> { distance, predecessor }`.
*/
export function floydWarshall(g: Graph, weightFn?: (e: EdgeObj) => number, edgeFn?: (v: NodeID) => EdgeObj[]): Record<NodeID, Record<NodeID, PathEntry>>;
import type { Graph } from '../graph.js';
import type { EdgeObj } from '../graph.js';
import type { NodeID } from '../graph.js';
import type { PathEntry } from './dijkstra.js';

View File

@@ -0,0 +1,31 @@
import { dfs } from './dfs.js';
export { postorder };
/**
* This function performs a [postorder traversal][] of the graph `g` starting
* at the nodes `vs`. For each node visited, `v`, the function `callback(v)`
* is called.
*
* [postorder traversal]: https://en.wikipedia.org/wiki/Tree_traversal#Depth-first
*
* @example
*
* ![](https://github.com/dagrejs/graphlib/wiki/images/preorder.png)
*
* ```js
* graphlib.alg.postorder(g, "A");
* // => One of:
* // [ "B", "D", "E", C", "A" ]
* // [ "B", "E", "D", C", "A" ]
* // [ "D", "E", "C", B", "A" ]
* // [ "E", "D", "C", B", "A" ]
* ```
*
* @param {Parameters<typeof dfs>[0]} g - The graph to traverse.
* @param {Parameters<typeof dfs>[1]} vs - Nodes to start the traversal from.
* @returns {ReturnType<typeof dfs>} The nodes in the order they were visited.
*/
function postorder(g, vs) {
return dfs(g, vs, 'post');
}

View File

@@ -0,0 +1,118 @@
import * as _ from 'lodash-es';
import { PriorityQueue } from '../data/priority-queue.js';
import { Graph } from '../graph.js';
/**
* @import { EdgeObj, NodeID } from '../graph.js';
*/
export { prim };
/**
* [Prim's algorithm][] takes a connected undirected graph and generates a
* [minimum spanning tree][]. This function returns the minimum spanning
* tree as an undirected graph. This algorithm is derived from the description
* in "Introduction to Algorithms", Third Edition, Cormen, et al., Pg 634.
*
* [Prim's algorithm]: https://en.wikipedia.org/wiki/Prim's_algorithm
* [minimum spanning tree]: https://en.wikipedia.org/wiki/Minimum_spanning_tree
*
* @remarks This function takes `O(|E| log |V|)` time.
*
* @example
*
* ![](https://github.com/dagrejs/graphlib/wiki/images/prim-input.png)
* <!-- SOURCE:
* digraph {
* node [shape=circle, style="fill:white;stroke:#333;stroke-width:1.5px"]
* edge [labeloffset=2 labelpos=r arrowhead="none"]
* rankdir=lr
* A -> B [label=3]
* A -> D [label=12]
* B -> C [label=6]
* B -> D [label=1]
* C -> D [label=1]
* D -> E [label=2]
* C -> E [label=9]
* }
* -->
*
* ```js
* function weight(e) { return g(e); }
* graphlib.alg.prim(g, weight);
* ```
*
* Returns a tree (represented as a Graph) of the following form:
*
* ![](https://github.com/dagrejs/graphlib/wiki/images/prim-output.png)
* <!-- SOURCE:
* digraph {
* node [shape=circle, style="fill:white;stroke:#333;stroke-width:1.5px"]
* edge [labeloffset=2 labelpos=r arrowhead="none"]
* rankdir=lr
* A -> B
* B -> D
* C -> D
* D -> E
* }
* -->
*
* @param {Graph} g - The input undirected connected graph.
* @param {(e: EdgeObj) => number} weightFunc - Function that returns
* the weight for edge `e`.
* @returns {Graph<undefined, undefined, undefined>} The minimum spanning tree
* as an undirected graph.
* @throws {Error} If the input graph is not connected.
*/
function prim(g, weightFunc) {
var result = new Graph();
/** @type {Record<NodeID, NodeID>} */
var parents = {};
var pq = new PriorityQueue();
/** @type {NodeID} */
var v;
/**
* @param {EdgeObj} edge - Edge to examine for possible inclusion in the
* minimum spanning tree.
*/
function updateNeighbors(edge) {
var w = edge.v === v ? edge.w : edge.v;
var pri = pq.priority(w);
if (pri !== undefined) {
var edgeWeight = weightFunc(edge);
if (edgeWeight < pri) {
parents[w] = v;
pq.decrease(w, edgeWeight);
}
}
}
if (g.nodeCount() === 0) {
return result;
}
_.each(g.nodes(), function (v) {
pq.add(v, Number.POSITIVE_INFINITY);
result.setNode(v);
});
// Start from an arbitrary node
pq.decrease(g.nodes()[0], 0);
var init = false;
while (pq.size() > 0) {
v = pq.removeMin();
if (Object.prototype.hasOwnProperty.call(parents, v)) {
result.setEdge(v, parents[v]);
} else if (init) {
throw new Error('Input graph is not connected: ' + g);
} else {
init = true;
}
g.nodeEdges(v).forEach(updateNeighbors);
}
return result;
}

View File

@@ -0,0 +1,44 @@
/**
* This function is an implementation of [Tarjan's algorithm][] which finds
* all [strongly connected components][] in the directed graph `g`. Each
* strongly connected component is composed of nodes that can reach all other
* nodes in the component via directed edges. A strongly connected component
* can consist of a single node if that node cannot both reach and be reached
* by any other specific node in the graph. Components of more than one node
* are guaranteed to have at least one cycle.
*
* [Tarjan's algorithm]: http://en.wikipedia.org/wiki/Tarjan's_strongly_connected_components_algorithm
* [strongly connected components]: http://en.wikipedia.org/wiki/Strongly_connected_component
*
* @example
*
* ![](https://github.com/dagrejs/graphlib/wiki/images/tarjan.png)
* <!-- SOURCE:
* digraph {
* node [shape=circle, style="fill:white;stroke:#333;stroke-width:1.5px"]
* edge [lineInterpolate=bundle]
* rankdir=lr
*
* A -> B -> C -> D -> H -> G -> F
* F -> G
* D -> C
* H -> D
* B -> E -> G
* E -> A
* }
* -->
*
* ```js
* graphlib.alg.tarjan(g);
* // => [ [ 'F', 'G' ],
* // [ 'H', 'D', 'C' ],
* // [ 'E', 'B', 'A' ] ]
* ```
*
* @param {Graph} g - The directed graph to analyze.
* @returns {NodeID[][]} an array of components. Each component is itself an
* array that contains the ids of all nodes in the component.
*/
export function tarjan(g: Graph): NodeID[][];
import type { Graph } from '../graph.js';
import type { NodeID } from '../graph.js';

View File

@@ -0,0 +1,100 @@
/**
* @import { Graph, NodeID } from '../graph.js';
*/
export { tarjan };
/**
* This function is an implementation of [Tarjan's algorithm][] which finds
* all [strongly connected components][] in the directed graph `g`. Each
* strongly connected component is composed of nodes that can reach all other
* nodes in the component via directed edges. A strongly connected component
* can consist of a single node if that node cannot both reach and be reached
* by any other specific node in the graph. Components of more than one node
* are guaranteed to have at least one cycle.
*
* [Tarjan's algorithm]: http://en.wikipedia.org/wiki/Tarjan's_strongly_connected_components_algorithm
* [strongly connected components]: http://en.wikipedia.org/wiki/Strongly_connected_component
*
* @example
*
* ![](https://github.com/dagrejs/graphlib/wiki/images/tarjan.png)
* <!-- SOURCE:
* digraph {
* node [shape=circle, style="fill:white;stroke:#333;stroke-width:1.5px"]
* edge [lineInterpolate=bundle]
* rankdir=lr
*
* A -> B -> C -> D -> H -> G -> F
* F -> G
* D -> C
* H -> D
* B -> E -> G
* E -> A
* }
* -->
*
* ```js
* graphlib.alg.tarjan(g);
* // => [ [ 'F', 'G' ],
* // [ 'H', 'D', 'C' ],
* // [ 'E', 'B', 'A' ] ]
* ```
*
* @param {Graph} g - The directed graph to analyze.
* @returns {NodeID[][]} an array of components. Each component is itself an
* array that contains the ids of all nodes in the component.
*/
function tarjan(g) {
var index = 0;
/** @type {NodeID[]} */
var stack = [];
/**
* @type {Record<NodeID, { onStack: boolean, lowlink: number, index: number }>}
*/
var visited = {};
/** @type {NodeID[][]} */
var results = [];
/**
* @param {NodeID} v - Node to recursively visit
*/
function dfs(v) {
var entry = (visited[v] = {
onStack: true,
lowlink: index,
index: index++,
});
stack.push(v);
g.successors(v).forEach(function (w) {
if (!Object.prototype.hasOwnProperty.call(visited, w)) {
dfs(w);
entry.lowlink = Math.min(entry.lowlink, visited[w].lowlink);
} else if (visited[w].onStack) {
entry.lowlink = Math.min(entry.lowlink, visited[w].index);
}
});
if (entry.lowlink === entry.index) {
/** @type {NodeID[]} */
var cmpt = [];
/** @type {NodeID} */
var w;
do {
w = stack.pop();
visited[w].onStack = false;
cmpt.push(w);
} while (v !== w);
results.push(cmpt);
}
}
g.nodes().forEach(function (v) {
if (!Object.prototype.hasOwnProperty.call(visited, v)) {
dfs(v);
}
});
return results;
}

View File

@@ -0,0 +1,179 @@
export { PriorityQueue };
/**
* A min-priority queue data structure. This algorithm is derived from Cormen,
* et al., "Introduction to Algorithms". The basic idea of a min-priority
* queue is that you can efficiently (in O(1) time) get the smallest key in
* the queue. Adding and removing elements takes O(log n) time. A key can
* have its priority decreased in O(log n) time.
*/
class PriorityQueue {
constructor() {
/**
* @private
* @type {Array<{key: string, priority: number}>}
*/
this._arr = [];
/**
* @private
* @type {Record<string, number>}
*/
this._keyIndices = {};
}
/**
* @returns {number} the number of elements in the queue.
* @remarks Takes `O(1)` time.
*/
size() {
return this._arr.length;
}
/**
* @returns {string[]} the keys that are in the queue.
* @remarks Takes `O(n)` time.
*/
keys() {
return this._arr.map(function (x) {
return x.key;
});
}
/**
* @param {Object} key - The key to check for presence in the queue.
* @returns {boolean} `true` if **key** is in the queue and `false` if not.
*/
has(key) {
return Object.prototype.hasOwnProperty.call(this._keyIndices, key);
}
/**
* @param {Object} key - The key to get the priority for.
* @returns {number | undefined} the priority for **key**.
* If **key** is not present in the queue then this function returns `undefined`.
* @remarks Takes `O(1)` time.
*/
priority(key) {
var index = this._keyIndices[key];
if (index !== undefined) {
return this._arr[index].priority;
}
}
/**
* @returns {string} the key for the minimum element in this queue.
* @throws {Error} if the queue is empty.
* @remarks Takes `O(1)` time.
*/
min() {
if (this.size() === 0) {
throw new Error('Queue underflow');
}
return this._arr[0].key;
}
/**
* Inserts a new key into the priority queue.
*
* @remarks Takes `O(n)` time.
*
* @param {Object} key the key to add. This will be coerced to a `string`.
* @param {Number} priority the initial priority for the key
* @returns {boolean} `true` if the key was added and `false` if it was already
* present in the queue.
*/
add(key, priority) {
var keyIndices = this._keyIndices;
key = String(key);
if (!Object.prototype.hasOwnProperty.call(keyIndices, key)) {
var arr = this._arr;
var index = arr.length;
keyIndices[key] = index;
arr.push({ key: key, priority: priority });
this._decrease(index);
return true;
}
return false;
}
/**
* Removes and returns the smallest key in the queue.
* @returns {string} the key with the smallest priority
* @remarks Takes `O(log n)` time.
*/
removeMin() {
this._swap(0, this._arr.length - 1);
var min = this._arr.pop();
delete this._keyIndices[min.key];
this._heapify(0);
return min.key;
}
/**
* Decreases the priority for **key** to **priority**.
*
* @param {Object} key the key for which to raise priority
* @param {Number} priority the new priority for the key
* @throws {Error} if the new priority is greater than the previous priority.
*/
decrease(key, priority) {
var index = this._keyIndices[key];
if (priority > this._arr[index].priority) {
throw new Error(
'New priority is greater than current priority. ' +
'Key: ' +
key +
' Old: ' +
this._arr[index].priority +
' New: ' +
priority,
);
}
this._arr[index].priority = priority;
this._decrease(index);
}
/**
* @param {number} i - Lower index.
* @private
*/
_heapify(i) {
var arr = this._arr;
var l = 2 * i;
var r = l + 1;
var largest = i;
if (l < arr.length) {
largest = arr[l].priority < arr[largest].priority ? l : largest;
if (r < arr.length) {
largest = arr[r].priority < arr[largest].priority ? r : largest;
}
if (largest !== i) {
this._swap(i, largest);
this._heapify(largest);
}
}
}
/**
* @param {number} index - Index to decrease.
* @private
*/
_decrease(index) {
var arr = this._arr;
var priority = arr[index].priority;
var parent;
while (index !== 0) {
parent = index >> 1;
if (arr[parent].priority < priority) {
break;
}
this._swap(index, parent);
index = parent;
}
}
/**
* @param {number} i - First index
* @param {number} j - Second index
* @private
*/
_swap(i, j) {
var arr = this._arr;
var keyIndices = this._keyIndices;
var origArrI = arr[i];
var origArrJ = arr[j];
arr[i] = origArrJ;
arr[j] = origArrI;
keyIndices[origArrJ.key] = i;
keyIndices[origArrI.key] = j;
}
}

View File

@@ -0,0 +1,717 @@
/**
* @typedef {string} NodeID ID of a node.
*/
/**
* @typedef {`${string}${typeof EDGE_KEY_DELIM}${string}${typeof EDGE_KEY_DELIM}${string}`} EdgeID ID of an edge.
* @internal - All public APIs use {@link EdgeObj} instead to refer to edges.
*/
/**
* @typedef {object} EdgeObj
* @property {NodeID} v the id of the source or tail node of an edge
* @property {NodeID} w the id of the target or head node of an edge
* @property {string | number} [name] Name of the edge. Needed to uniquely identify
* multiple edges between the same pair of nodes in a multigraph.
*/
/**
* @template {unknown} T
* @typedef {T[] | Record<any, T>} Collection
* Lodash object that can be iterated over with `_.each`.
*
* Beware, objects with `.length` are treated as arrays, see
* https://lodash.com/docs/4.17.15#forEach
*/
/**
* @typedef {object} GraphOptions
* @property {boolean | undefined} [directed] - set to `true` to get a
* directed graph and `false` to get an undirected graph.
* An undirected graph does not treat the order of nodes in an edge as
* significant.
* In other words, `g.edge("a", "b") === g.edge("b", "a")` for
* an undirected graph.
* Default: `true`
* @property {boolean | undefined} [multigraph] - set to `true` to allow a
* graph to have multiple edges between the same pair of nodes.
* Default: `false`.
* @property {boolean | undefined} [compound] - set to `true` to allow a
* graph to have compound nodes - nodes which can be the parent of other
* nodes.
* Default: `false`.
*/
/**
* Graphlib has a single graph type: {@link Graph}. To create a new instance:
*
* ```js
* var g = new Graph();
* ```
*
* By default this will create a directed graph that does not allow multi-edges
* or compound nodes.
* The following options can be used when constructing a new graph:
*
* * {@link GraphOptions#directed}: set to `true` to get a directed graph and `false` to get an
* undirected graph.
* An undirected graph does not treat the order of nodes in an edge as
* significant. In other words,
* `g.edge("a", "b") === g.edge("b", "a")` for an undirected graph.
* Default: `true`.
* * {@link GraphOptions#multigraph}: set to `true` to allow a graph to have multiple edges
* between the same pair of nodes. Default: `false`.
* * {@link GraphOptions#compound}: set to `true` to allow a graph to have compound nodes -
* nodes which can be the parent of other nodes. Default: `false`.
*
* To set the options, pass in an options object to the `Graph` constructor.
* For example, to create a directed compound multigraph:
*
* ```js
* var g = new Graph({ directed: true, compound: true, multigraph: true });
* ```
*
* ### Node and Edge Representation
*
* In graphlib, a node is represented by a user-supplied String id.
* All node related functions use this String id as a way to uniquely identify
* the node. Here is an example of interacting with nodes:
*
* ```js
* var g = new Graph();
* g.setNode("my-id", "my-label");
* g.node("my-id"); // returns "my-label"
* ```
*
* Edges in graphlib are identified by the nodes they connect. For example:
*
* ```js
* var g = new Graph();
* g.setEdge("source", "target", "my-label");
* g.edge("source", "target"); // returns "my-label"
* ```
*
* However, we need a way to uniquely identify an edge in a single object for
* various edge queries (e.g. {@link Graph#outEdges}).
* We use {@link EdgeObj}s for this purpose.
* They consist of the following properties:
*
* * {@link EdgeObj#v}: the id of the source or tail node of an edge
* * {@link EdgeObj#w}: the id of the target or head node of an edge
* * {@link EdgeObj#name} (optional): the name that uniquely identifies a multiedge.
*
* Any edge function that takes an edge id will also work with an {@link EdgeObj}. For example:
*
* ```js
* var g = new Graph();
* g.setEdge("source", "target", "my-label");
* g.edge({ v: "source", w: "target" }); // returns "my-label"
* ```
*
* ### Multigraphs
*
* A [multigraph](https://en.wikipedia.org/wiki/Multigraph) is a graph that can
* have more than one edge between the same pair of nodes.
* By default graphlib graphs are not multigraphs, but a multigraph can be
* constructed by setting the {@link GraphOptions#multigraph} property to true:
*
* ```js
* var g = new Graph({ multigraph: true });
* ```
*
* With multiple edges between two nodes we need some way to uniquely identify
* each edge. We call this the {@link EdgeObj#name} property.
* Here's an example of creating a couple of edges between the same nodes:
*
* ```js
* var g = new Graph({ multigraph: true });
* g.setEdge("a", "b", "edge1-label", "edge1");
* g.setEdge("a", "b", "edge2-label", "edge2");
* g.edge("a", "b", "edge1"); // returns "edge1-label"
* g.edge("a", "b", "edge2"); // returns "edge2-label"
* g.edges(); // returns [{ v: "a", w: "b", name: "edge1" },
* // { v: "a", w: "b", name: "edge2" }]
* ```
*
* A multigraph still allows an edge with no name to be created:
*
* ```js
* var g = new Graph({ multigraph: true });
* g.setEdge("a", "b", "my-label");
* g.edge({ v: "a", w: "b" }); // returns "my-label"
* ```
*
* ### Compound Graphs
*
* A compound graph is one where a node can be the parent of other nodes.
* The child nodes form a "subgraph".
* Here's an example of constructing and interacting with a compound graph:
*
* ```js
* var g = new Graph({ compound: true });
* g.setParent("a", "parent");
* g.setParent("b", "parent");
* g.parent("a"); // returns "parent"
* g.parent("b"); // returns "parent"
* g.parent("parent"); // returns undefined
* ```
*
* ### Default Labels
*
* When a node or edge is created without a label, a default label can be assigned.
* See {@link setDefaultNodeLabel} and {@link setDefaultEdgeLabel}.
*
* @template [GraphLabel=any] - Label of the graph.
* @template [NodeLabel=any] - Label of a node.
* Even though this is a "label", this could be any type that the user requires
* (and may need to be an object for some layout/ranking algorithms in dagre).
* @template [EdgeLabel=any] - Label of an edge.
* Even though this is a "label", this could be any type that the user requires,
* (and may need to be a object for ranking in dagre).
*/
export class Graph<GraphLabel = any, NodeLabel = any, EdgeLabel = any> {
/**
* @param {GraphOptions} [opts] - Graph options.
*/
constructor(opts?: GraphOptions);
/**
* @type {boolean}
* @private
*/
private _isDirected;
/**
* @type {boolean}
* @private
*/
private _isMultigraph;
/**
* @type {boolean}
* @private
*/
private _isCompound;
/**
* @type {GraphLabel | undefined}
* Label for the graph itself
*/
_label: GraphLabel | undefined;
/**
* Default label to be set when creating a new node.
*
* @private
* @type {(v: NodeID | number) => NodeLabel}
*/
private _defaultNodeLabelFn;
/**
* Default label to be set when creating a new edge
*
* @private
* @type {(v: NodeID, w: NodeID, name: string | undefined) => EdgeLabel}
*/
private _defaultEdgeLabelFn;
/**
* @type {Record<NodeID, NodeLabel>}
* @private
*
* v -> label
*/
private _nodes;
/**
* @type {Record<NodeID, NodeID>}
* @private
* v -> parent
*/
private _parent;
/**
* @type {Record<NodeID, Record<NodeID, true>>}
* @private
* v -> children
*/
private _children;
/**
* @type {Record<NodeID, Record<EdgeID, EdgeObj>>}
* @private
* v -> edgeObj
*/
private _in;
/**
* @type {Record<NodeID, Record<NodeID, number>>}
* @private
* u -> v -> Number
*/
private _preds;
/**
* @type {Record<NodeID, Record<EdgeID, EdgeObj>>}
* @private
* v -> edgeObj
*/
private _out;
/**
* @type {Record<NodeID, Record<NodeID, number>>}
* @private
* v -> w -> Number
*/
private _sucs;
/**
* @type {Record<EdgeID, EdgeObj>}
* @private
* e -> edgeObj
*/
private _edgeObjs;
/**
* @type {Record<EdgeID, EdgeLabel>}
* @private
* e -> label
*/
private _edgeLabels;
/**
*
* @returns {boolean} `true` if the graph is [directed](https://en.wikipedia.org/wiki/Directed_graph).
* A directed graph treats the order of nodes in an edge as significant whereas an
* [undirected](https://en.wikipedia.org/wiki/Graph_(mathematics)#Undirected_graph)
* graph does not.
* This example demonstrates the difference:
*
* @example
*
* ```js
* var directed = new Graph({ directed: true });
* directed.setEdge("a", "b", "my-label");
* directed.edge("a", "b"); // returns "my-label"
* directed.edge("b", "a"); // returns undefined
*
* var undirected = new Graph({ directed: false });
* undirected.setEdge("a", "b", "my-label");
* undirected.edge("a", "b"); // returns "my-label"
* undirected.edge("b", "a"); // returns "my-label"
* ```
*/
isDirected(): boolean;
/**
* @returns {boolean} `true` if the graph is a multigraph.
*/
isMultigraph(): boolean;
/**
* @returns {boolean} `true` if the graph is compound.
*/
isCompound(): boolean;
/**
* Sets the label for the graph to `label`.
*
* @param {GraphLabel} label - Label for the graph.
* @returns {this}
*/
setGraph(label: GraphLabel): this;
/**
* @returns {GraphLabel | undefined} the currently assigned label for the graph.
* If no label has been assigned, returns `undefined`.
*
* @example
*
* ```js
* var g = new Graph();
* g.graph(); // returns undefined
* g.setGraph("graph-label");
* g.graph(); // returns "graph-label"
* ```
*/
graph(): GraphLabel | undefined;
/**
* Sets a new default value that is assigned to nodes that are created without
* a label.
*
* @param {typeof this._defaultNodeLabelFn | NodeLabel} newDefault - If a function,
* it is called with the id of the node being created.
* Otherwise, it is assigned as the label directly.
* @returns {this}
*/
setDefaultNodeLabel(newDefault: typeof this._defaultNodeLabelFn | NodeLabel): this;
/**
* @returns {number} the number of nodes in the graph.
*/
nodeCount(): number;
/**
* @returns {NodeID[]} the ids of the nodes in the graph.
*
* @remarks
* Use {@link node()} to get the label for each node.
* Takes `O(|V|)` time.
*/
nodes(): NodeID[];
/**
* @returns {NodeID[]} those nodes in the graph that have no in-edges.
* @remarks Takes `O(|V|)` time.
*/
sources(): NodeID[];
/**
* @returns {NodeID[]} those nodes in the graph that have no out-edges.
* @remarks Takes `O(|V|)` time.
*/
sinks(): NodeID[];
/**
* Invokes setNode method for each node in `vs` list.
*
* @param {Collection<NodeID | number>} vs - List of node IDs to create/set.
* @param {NodeLabel} [value] - If set, update all nodes with this value.
* @returns {this}
* @remarks Complexity: O(|names|).
*/
setNodes(vs: Collection<NodeID | number>, value?: NodeLabel, ...args: any[]): this;
/**
* Creates or updates the value for the node `v` in the graph.
*
* @param {NodeID | number} v - ID of the node to create/set.
* @param {NodeLabel} [value] - If supplied, it is set as the value for the node.
* If not supplied and the node was created by this call then
* {@link setDefaultNodeLabel} will be used to set the node's value.
* @returns {this} the graph, allowing this to be chained with other functions.
* @remarks Takes `O(1)` time.
*/
setNode(v: NodeID | number, value?: NodeLabel, ...args: any[]): this;
/**
* Gets the label of node with specified name.
*
* @param {NodeID | number} v - Node ID.
* @returns {NodeLabel | undefined} the label assigned to the node with the id `v`
* if it is in the graph.
* Otherwise returns `undefined`.
* @remarks Takes `O(1)` time.
*/
node(v: NodeID | number): NodeLabel | undefined;
/**
* Detects whether graph has a node with specified name or not.
*
* @param {NodeID | number} v - Node ID.
* @returns {boolean} Returns `true` the graph has a node with the id.
* @remarks Takes `O(1)` time.
*/
hasNode(v: NodeID | number): boolean;
/**
* Remove the node with the id `v` in the graph or do nothing if the node is
* not in the graph.
*
* If the node was removed this function also removes any incident edges.
*
* @param {NodeID | number} v - Node ID to remove.
* @returns {this} the graph, allowing this to be chained with other functions.
* @remarks Takes `O(|E|)` time.
*/
removeNode(v: NodeID | number): this;
/**
* Sets the parent for `v` to `parent` if it is defined or removes the parent
* for `v` if `parent` is undefined.
*
* @param {NodeID | number} v - Node ID to set the parent for.
* @param {NodeID | number} [parent] - Parent node ID. If not defined, removes the parent.
* @returns {this} the graph, allowing this to be chained with other functions.
* @throws if the graph is not compound.
* @throws if setting the parent would create a cycle.
* @remarks Takes `O(1)` time.
*/
setParent(v: NodeID | number, parent?: NodeID | number): this;
/**
* @private
* @param {NodeID | number} v - Node ID.
*/
private _removeFromParentsChildList;
/**
* Get parent node for node `v`.
*
* @param {NodeID | number} v - Node ID.
* @returns {NodeID | undefined} the node that is a parent of node `v`
* or `undefined` if node `v` does not have a parent or is not a member of
* the graph.
* Always returns `undefined` for graphs that are not compound.
* @remarks Takes `O(1)` time.
*/
parent(v: NodeID | number): NodeID | undefined;
/**
* Gets list of direct children of node v.
*
* @param {NodeID | number} [v] - Node ID. If not specified, gets nodes
* with no parent (top-level nodes).
* @returns {NodeID[] | undefined} all nodes that are children of node `v` or
* `undefined` if node `v` is not in the graph.
* Always returns `[]` for graphs that are not compound.
* @remarks Takes `O(|V|)` time.
*/
children(v?: NodeID | number): NodeID[] | undefined;
/**
* @param {NodeID | number} v - Node ID.
* @returns {NodeID[] | undefined} all nodes that are predecessors of the
* specified node or `undefined` if node `v` is not in the graph.
* @remarks
* Behavior is undefined for undirected graphs - use {@link neighbors} instead.
* Takes `O(|V|)` time.
*/
predecessors(v: NodeID | number): NodeID[] | undefined;
/**
* @param {NodeID | number} v - Node ID.
* @returns {NodeID[] | undefined} all nodes that are successors of the
* specified node or `undefined` if node `v` is not in the graph.
* @remarks
* Behavior is undefined for undirected graphs - use {@link neighbors} instead.
* Takes `O(|V|)` time.
*/
successors(v: NodeID | number): NodeID[] | undefined;
/**
* @param {NodeID | number} v - Node ID.
* @returns {NodeID[] | undefined} all nodes that are predecessors or
* successors of the specified node
* or `undefined` if node `v` is not in the graph.
* @remarks Takes `O(|V|)` time.
*/
neighbors(v: NodeID | number): NodeID[] | undefined;
/**
* @param {NodeID | number} v - Node ID.
* @returns {boolean} True if the node is a leaf (has no successors), false otherwise.
*/
isLeaf(v: NodeID | number): boolean;
/**
* Creates new graph with nodes filtered via `filter`.
* Edges incident to rejected node
* are also removed.
*
* In case of compound graph, if parent is rejected by `filter`,
* than all its children are rejected too.
* @param {(v: NodeID) => boolean} filter - Function that returns `true` for nodes to keep.
* @returns {Graph<GraphLabel, NodeLabel, EdgeLabel>} A new graph containing only the nodes for which `filter` returns `true`.
* @remarks Average-case complexity: O(|E|+|V|).
*/
filterNodes(filter: (v: NodeID) => boolean): Graph<GraphLabel, NodeLabel, EdgeLabel>;
/**
* Sets a new default value that is assigned to edges that are created without
* a label.
*
* @param {typeof this._defaultEdgeLabelFn | EdgeLabel} newDefault - If a function,
* it is called with the parameters `(v, w, name)`.
* Otherwise, it is assigned as the label directly.
* @returns {this}
*/
setDefaultEdgeLabel(newDefault: typeof this._defaultEdgeLabelFn | EdgeLabel): this;
/**
* @returns {number} the number of edges in the graph.
* @remarks Complexity: O(1).
*/
edgeCount(): number;
/**
* Gets edges of the graph.
*
* @returns {EdgeObj[]} the {@link EdgeObj} for each edge in the graph.
*
* @remarks
* In case of compound graph subgraphs are not considered.
* Use {@link edge()} to get the label for each edge.
* Takes `O(|E|)` time.
*/
edges(): EdgeObj[];
/**
* Establish an edges path over the nodes in nodes list.
*
* If some edge is already exists, it will update its label, otherwise it will
* create an edge between pair of nodes with label provided or default label
* if no label provided.
*
* @param {Collection<NodeID>} vs - List of node IDs to create edges between.
* @param {EdgeLabel} [value] - If set, update all edges with this value.
* @returns {this}
* @remarks Complexity: O(|nodes|).
*/
setPath(vs: Collection<NodeID>, value?: EdgeLabel, ...args: any[]): this;
/**
* Creates or updates the label for the edge (`v`, `w`) with the optionally
* supplied `name`.
*
* @overload
* @param {EdgeObj} arg0 - Edge object.
* @param {EdgeLabel} [value] - If supplied, it is set as the label for the edge.
* If not supplied and the edge was created by this call then
* {@link setDefaultEdgeLabel} will be used to assign the edge's label.
* @returns {this} the graph, allowing this to be chained with other functions.
* @remarks Takes `O(1)` time.
*/
setEdge(arg0: EdgeObj, value?: EdgeLabel): this;
/**
* Creates or updates the label for the edge (`v`, `w`) with the optionally
* supplied `name`.
*
* @overload
* @param {NodeID | number} v - Source node ID. Number values will be coerced to strings.
* @param {NodeID | number} w - Target node ID. Number values will be coerced to strings.
* @param {EdgeLabel} [value] - If supplied, it is set as the label for the edge.
* If not supplied and the edge was created by this call then
* {@link setDefaultEdgeLabel} will be used to assign the edge's label.
* @param {string | number} [name] - Edge name. Only useful with multigraphs.
* @returns {this} the graph, allowing this to be chained with other functions.
* @remarks Takes `O(1)` time.
*/
setEdge(v: NodeID | number, w: NodeID | number, value?: EdgeLabel, name?: string | number): this;
/**
* Gets the label for the specified edge.
*
* @overload
* @param {EdgeObj} v - Edge object.
* @returns {EdgeLabel | undefined} the label for the edge (`v`, `w`) if the
* graph has an edge between `v` and `w` with the optional `name`.
* Returned `undefined` if there is no such edge in the graph.
* @remarks
* `v` and `w` can be interchanged for undirected graphs.
* Takes `O(1)` time.
*/
edge(v: EdgeObj): EdgeLabel | undefined;
/**
* Gets the label for the specified edge.
*
* @overload
* @param {NodeID | number} v - Source node ID.
* @param {NodeID | number} w - Target node ID.
* @param {string | number} [name] - Edge name. Only useful with multigraphs.
* @returns {EdgeLabel | undefined} the label for the edge (`v`, `w`) if the
* graph has an edge between `v` and `w` with the optional `name`.
* Returned `undefined` if there is no such edge in the graph.
* @remarks
* `v` and `w` can be interchanged for undirected graphs.
* Takes `O(1)` time.
*/
edge(v: NodeID | number, w: NodeID | number, name?: string | number): EdgeLabel | undefined;
/**
* Detects whether the graph contains specified edge or not.
*
* @overload
* @param {EdgeObj} v - Edge object.
* @returns {boolean} `true` if the graph has an edge between `v` and `w`
* with the optional `name`.
* @remarks
* `v` and `w` can be interchanged for undirected graphs.
* No subgraphs are considered.
* Takes `O(1)` time.
*/
hasEdge(v: EdgeObj): boolean;
/**
* Detects whether the graph contains specified edge or not.
*
* @overload
* @param {NodeID | number} v - Source node ID.
* @param {NodeID | number} w - Target node ID.
* @param {string | number} [name] - Edge name. Only useful with multigraphs.
* @returns {boolean} `true` if the graph has an edge between `v` and `w`
* with the optional `name`.
* @remarks
* `v` and `w` can be interchanged for undirected graphs.
* No subgraphs are considered.
* Takes `O(1)` time.
*/
hasEdge(v: NodeID | number, w: NodeID | number, name?: string | number): boolean;
/**
* Removes the edge (`v`, `w`) if the graph has an edge between `v` and `w`
* with the optional `name`. If not this function does nothing.
*
* @overload
* @param {EdgeObj} v - Edge object.
* @returns {this}
* @remarks
* `v` and `w` can be interchanged for undirected graphs.
* No subgraphs are considered.
* Takes `O(1)` time.
*/
removeEdge(v: EdgeObj): this;
/**
* Removes the edge (`v`, `w`) if the graph has an edge between `v` and `w`
* with the optional `name`. If not this function does nothing.
*
* @overload
* @param {NodeID | number} v - Source node ID.
* @param {NodeID | number} w - Target node ID.
* @param {string | number} [name] - Edge name. Only useful with multigraphs.
* @returns {this}
* @remarks
* `v` and `w` can be interchanged for undirected graphs.
* Takes `O(1)` time.
*/
removeEdge(v: NodeID | number, w: NodeID | number, name?: string | number): this;
/**
* @param {NodeID | number} v - Target node ID.
* @param {NodeID | number} [u] - Optionally filters edges down to just those
* coming from node `u`.
* @returns {EdgeObj[] | undefined} all edges that point to the node `v`.
* Returns `undefined` if node `v` is not in the graph.
* @remarks
* Behavior is undefined for undirected graphs - use {@link nodeEdges} instead.
* Takes `O(|E|)` time.
*/
inEdges(v: NodeID | number, u?: NodeID | number): EdgeObj[] | undefined;
/**
* @param {NodeID | number} v - Target node ID.
* @param {NodeID | number} [w] - Optionally filters edges down to just those
* that point to `w`.
* @returns {EdgeObj[] | undefined} all edges that point to the node `v`.
* Returns `undefined` if node `v` is not in the graph.
* @remarks
* Behavior is undefined for undirected graphs - use {@link nodeEdges} instead.
* Takes `O(|E|)` time.
*/
outEdges(v: NodeID | number, w?: NodeID | number): EdgeObj[] | undefined;
/**
* @param {NodeID | number} v - Target Node ID.
* @param {NodeID | number} [w] - If set, filters those edges down to just
* those between nodes `v` and `w` regardless of direction
* @returns {EdgeObj[] | undefined} all edges to or from node `v` regardless
* of direction. Returns `undefined` if node `v` is not in the graph.
* @remarks Takes `O(|E|)` time.
*/
nodeEdges(v: NodeID | number, w?: NodeID | number): EdgeObj[] | undefined;
_nodeCount: number;
_edgeCount: number;
}
/**
* ID of a node.
*/
export type NodeID = string;
/**
* ID of an edge.
*/
export type EdgeID = `${string}${typeof EDGE_KEY_DELIM}${string}${typeof EDGE_KEY_DELIM}${string}`;
export type EdgeObj = {
/**
* the id of the source or tail node of an edge
*/
v: NodeID;
/**
* the id of the target or head node of an edge
*/
w: NodeID;
/**
* Name of the edge. Needed to uniquely identify
* multiple edges between the same pair of nodes in a multigraph.
*/
name?: string | number;
};
/**
* Lodash object that can be iterated over with `_.each`.
*
* Beware, objects with `.length` are treated as arrays, see
* https://lodash.com/docs/4.17.15#forEach
*/
export type Collection<T extends unknown> = T[] | Record<any, T>;
export type GraphOptions = {
/**
* - set to `true` to get a
* directed graph and `false` to get an undirected graph.
* An undirected graph does not treat the order of nodes in an edge as
* significant.
* In other words, `g.edge("a", "b") === g.edge("b", "a")` for
* an undirected graph.
* Default: `true`
*/
directed?: boolean | undefined;
/**
* - set to `true` to allow a
* graph to have multiple edges between the same pair of nodes.
* Default: `false`.
*/
multigraph?: boolean | undefined;
/**
* - set to `true` to allow a
* graph to have compound nodes - nodes which can be the parent of other
* nodes.
* Default: `false`.
*/
compound?: boolean | undefined;
};
declare var EDGE_KEY_DELIM: string;
export {};

1165
frontend/node_modules/dagre-d3-es/src/graphlib/graph.js generated vendored Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,7 @@
// Includes only the "core" of graphlib
import { Graph } from './graph.js';
const version = '2.1.9-pre';
export { Graph, version };

View File

@@ -0,0 +1,104 @@
export type GraphJSON<GraphLabel = any, NodeLabel = any, EdgeLabel = any> = {
/**
* - The options used to create the graph.
*/
options: Required<GraphOptions>;
/**
* - The nodes in the graph.
*/
nodes: Array<{
v: NodeID;
value?: NodeLabel;
parent?: NodeID;
}>;
/**
* - The edges in the graph.
*/
edges: Array<EdgeObj & {
value?: EdgeLabel;
}>;
/**
* - The graph's value, if any.
*/
value?: GraphLabel;
};
/**
* @template [GraphLabel=any] - Label of the graph.
* @template [NodeLabel=any] - Label of a node.
* @template [EdgeLabel=any] - Label of an edge.
*
* @typedef {object} GraphJSON
* @property {Required<GraphOptions>} options - The options used to create the graph.
* @property {Array<{ v: NodeID; value?: NodeLabel; parent?: NodeID }>} nodes - The nodes in the graph.
* @property {Array<EdgeObj & { value?: EdgeLabel }>} edges - The edges in the graph.
* @property {GraphLabel} [value] - The graph's value, if any.
*/
/**
* Creates a JSON representation of the graph that can be serialized to a
* string with
* [JSON.stringify](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/JSON/stringify).
* The graph can later be restored using {@link read}.
*
* @example
*
* ```js
* var g = new graphlib.Graph();
* g.setNode("a", { label: "node a" });
* g.setNode("b", { label: "node b" });
* g.setEdge("a", "b", { label: "edge a->b" });
* graphlib.json.write(g);
* // Returns the object:
* //
* // {
* // "options": {
* // "directed": true,
* // "multigraph": false,
* // "compound": false
* // },
* // "nodes": [
* // { "v": "a", "value": { "label": "node a" } },
* // { "v": "b", "value": { "label": "node b" } }
* // ],
* // "edges": [
* // { "v": "a", "w": "b", "value": { "label": "edge a->b" } }
* // ]
* // }
* ```
*
* @template [GraphLabel=any] - Label of the graph.
* @template [NodeLabel=any] - Label of a node.
* @template [EdgeLabel=any] - Label of an edge.
* @param {Graph<GraphLabel, NodeLabel, EdgeLabel>} g - The graph to serialize.
* @returns {GraphJSON<GraphLabel, NodeLabel, EdgeLabel>} The JSON representation of the graph.
*/
export function write<GraphLabel = any, NodeLabel = any, EdgeLabel = any>(g: Graph<GraphLabel, NodeLabel, EdgeLabel>): GraphJSON<GraphLabel, NodeLabel, EdgeLabel>;
/**
* Takes JSON as input and returns the graph representation.
*
* @example
*
* For example, if we have serialized the graph in {@link write}
* to a string named `str`, we can restore it to a graph as follows:
*
* ```js
* var g2 = graphlib.json.read(JSON.parse(str));
* // or, in order to copy the graph
* var g3 = graphlib.json.read(graphlib.json.write(g))
*
* g2.nodes();
* // ['a', 'b']
* g2.edges()
* // [ { v: 'a', w: 'b' } ]
* ```
*
* @template [GraphLabel=any] - Label of the graph.
* @template [NodeLabel=any] - Label of a node.
* @template [EdgeLabel=any] - Label of an edge.
* @param {GraphJSON<GraphLabel, NodeLabel, EdgeLabel>} json - The JSON representation of the graph.
* @returns {Graph<GraphLabel, NodeLabel, EdgeLabel>} The restored graph.
*/
export function read<GraphLabel = any, NodeLabel = any, EdgeLabel = any>(json: GraphJSON<GraphLabel, NodeLabel, EdgeLabel>): Graph<GraphLabel, NodeLabel, EdgeLabel>;
import type { GraphOptions } from './graph.js';
import type { NodeID } from './graph.js';
import type { EdgeObj } from './graph.js';
import { Graph } from './graph.js';

6
frontend/node_modules/dagre-d3-es/src/index.js generated vendored Normal file
View File

@@ -0,0 +1,6 @@
import { render } from './dagre-js/render.js';
import * as graphlib from './graphlib/index.js';
import * as intersect from './dagre-js/intersect/index.js';
export { graphlib, intersect, render };