@statelyai/graph 0.7.0 → 0.9.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +100 -1
- package/dist/{algorithms-Dw5jEwDK.mjs → algorithms-3xvCxHzo.mjs} +799 -11
- package/dist/algorithms-g2uWmPrb.d.mts +786 -0
- package/dist/algorithms.d.mts +2 -647
- package/dist/algorithms.mjs +2 -2
- package/dist/formats/adjacency-list/index.d.mts +1 -1
- package/dist/formats/converter/index.d.mts +1 -1
- package/dist/formats/cytoscape/index.d.mts +1 -1
- package/dist/formats/d3/index.d.mts +1 -1
- package/dist/formats/dot/index.d.mts +1 -1
- package/dist/formats/edge-list/index.d.mts +1 -1
- package/dist/formats/elk/index.d.mts +1 -1
- package/dist/formats/elk/index.mjs +41 -7
- package/dist/formats/gexf/index.d.mts +1 -1
- package/dist/formats/gml/index.d.mts +1 -1
- package/dist/formats/graphml/index.d.mts +1 -1
- package/dist/formats/jgf/index.d.mts +1 -1
- package/dist/formats/mermaid/index.d.mts +1 -1
- package/dist/formats/tgf/index.d.mts +1 -1
- package/dist/formats/xyflow/index.d.mts +1 -1
- package/dist/formats/xyflow/index.mjs +4 -0
- package/dist/index.d.mts +81 -20
- package/dist/index.mjs +95 -3
- package/dist/queries.d.mts +59 -2
- package/dist/queries.mjs +78 -1
- package/dist/{types-DkKjaQW3.d.mts → types-BzckPChi.d.mts} +61 -38
- package/package.json +4 -1
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { F as VisualGraphFormatConverter, M as VisualGraph } from "../../types-BzckPChi.mjs";
|
|
2
2
|
import { ElkEdge, ElkEdgeSection, ElkExtendedEdge, ElkGraphElement, ElkLabel, ElkNode, ElkNode as ElkNode$1, ElkPoint, ElkPort, ElkPrimitiveEdge, ElkShape, LayoutOptions } from "elkjs/lib/elk-api";
|
|
3
3
|
|
|
4
4
|
//#region src/formats/elk/index.d.ts
|
|
@@ -16,12 +16,24 @@ const ELK_TO_DIRECTION = {
|
|
|
16
16
|
function convertEdge(edge) {
|
|
17
17
|
const elkEdge = {
|
|
18
18
|
id: edge.id,
|
|
19
|
-
sources: [edge.sourceId],
|
|
20
|
-
targets: [edge.targetId]
|
|
19
|
+
sources: [edge.sourcePort ?? edge.sourceId],
|
|
20
|
+
targets: [edge.targetPort ?? edge.targetId]
|
|
21
21
|
};
|
|
22
22
|
if (edge.label) elkEdge.labels = [{ text: edge.label }];
|
|
23
23
|
return elkEdge;
|
|
24
24
|
}
|
|
25
|
+
function convertPort(port) {
|
|
26
|
+
const elkPort = {
|
|
27
|
+
id: port.name,
|
|
28
|
+
x: port.x,
|
|
29
|
+
y: port.y,
|
|
30
|
+
width: port.width,
|
|
31
|
+
height: port.height
|
|
32
|
+
};
|
|
33
|
+
if (port.label) elkPort.labels = [{ text: port.label }];
|
|
34
|
+
if (port.direction !== "inout") elkPort.layoutOptions = { "org.eclipse.elk.port.side": port.direction === "in" ? "WEST" : "EAST" };
|
|
35
|
+
return elkPort;
|
|
36
|
+
}
|
|
25
37
|
function convertNode(graph, node) {
|
|
26
38
|
const elkNode = {
|
|
27
39
|
id: node.id,
|
|
@@ -31,6 +43,7 @@ function convertNode(graph, node) {
|
|
|
31
43
|
height: node.height
|
|
32
44
|
};
|
|
33
45
|
if (node.label) elkNode.labels = [{ text: node.label }];
|
|
46
|
+
if (node.ports && node.ports.length > 0) elkNode.ports = node.ports.map(convertPort);
|
|
34
47
|
const children = getChildren(graph, node.id);
|
|
35
48
|
if (children.length > 0) {
|
|
36
49
|
elkNode.children = children.map((child) => convertNode(graph, child));
|
|
@@ -84,7 +97,7 @@ function toELK(graph) {
|
|
|
84
97
|
if (rootEdges.length > 0) root.edges = rootEdges.map(convertEdge);
|
|
85
98
|
return root;
|
|
86
99
|
}
|
|
87
|
-
function flattenElkNodes(elkNode, parentId, nodes, edges, edgeIdx) {
|
|
100
|
+
function flattenElkNodes(elkNode, parentId, nodes, edges, edgeIdx, portOwner) {
|
|
88
101
|
if (elkNode.children) for (const child of elkNode.children) {
|
|
89
102
|
const label = child.labels?.[0]?.text ?? "";
|
|
90
103
|
const node = {
|
|
@@ -99,15 +112,34 @@ function flattenElkNodes(elkNode, parentId, nodes, edges, edgeIdx) {
|
|
|
99
112
|
width: child.width ?? 0,
|
|
100
113
|
height: child.height ?? 0
|
|
101
114
|
};
|
|
115
|
+
if (child.ports && child.ports.length > 0) node.ports = child.ports.map((elkPort) => {
|
|
116
|
+
portOwner.set(elkPort.id, child.id);
|
|
117
|
+
const sideOpt = elkPort.layoutOptions?.["org.eclipse.elk.port.side"];
|
|
118
|
+
let direction = "inout";
|
|
119
|
+
if (sideOpt === "WEST") direction = "in";
|
|
120
|
+
else if (sideOpt === "EAST") direction = "out";
|
|
121
|
+
return {
|
|
122
|
+
name: elkPort.id,
|
|
123
|
+
direction,
|
|
124
|
+
label: elkPort.labels?.[0]?.text,
|
|
125
|
+
data: void 0,
|
|
126
|
+
x: elkPort.x ?? 0,
|
|
127
|
+
y: elkPort.y ?? 0,
|
|
128
|
+
width: elkPort.width ?? 0,
|
|
129
|
+
height: elkPort.height ?? 0
|
|
130
|
+
};
|
|
131
|
+
});
|
|
102
132
|
nodes.push(node);
|
|
103
|
-
flattenElkNodes(child, child.id, nodes, edges, edgeIdx);
|
|
133
|
+
flattenElkNodes(child, child.id, nodes, edges, edgeIdx, portOwner);
|
|
104
134
|
}
|
|
105
135
|
if (elkNode.edges) for (const elkEdge of elkNode.edges) for (const source of elkEdge.sources) for (const target of elkEdge.targets) {
|
|
136
|
+
const sourceNodeId = portOwner.get(source);
|
|
137
|
+
const targetNodeId = portOwner.get(target);
|
|
106
138
|
const edge = {
|
|
107
139
|
type: "edge",
|
|
108
140
|
id: elkEdge.id ?? `e${edgeIdx.value++}`,
|
|
109
|
-
sourceId: source,
|
|
110
|
-
targetId: target,
|
|
141
|
+
sourceId: sourceNodeId ?? source,
|
|
142
|
+
targetId: targetNodeId ?? target,
|
|
111
143
|
label: elkEdge.labels?.[0]?.text ?? "",
|
|
112
144
|
data: void 0,
|
|
113
145
|
x: 0,
|
|
@@ -115,6 +147,8 @@ function flattenElkNodes(elkNode, parentId, nodes, edges, edgeIdx) {
|
|
|
115
147
|
width: 0,
|
|
116
148
|
height: 0
|
|
117
149
|
};
|
|
150
|
+
if (sourceNodeId) edge.sourcePort = source;
|
|
151
|
+
if (targetNodeId) edge.targetPort = target;
|
|
118
152
|
edges.push(edge);
|
|
119
153
|
}
|
|
120
154
|
}
|
|
@@ -141,7 +175,7 @@ function flattenElkNodes(elkNode, parentId, nodes, edges, edgeIdx) {
|
|
|
141
175
|
function fromELK(elkRoot) {
|
|
142
176
|
const nodes = [];
|
|
143
177
|
const edges = [];
|
|
144
|
-
flattenElkNodes(elkRoot, null, nodes, edges, { value: 0 });
|
|
178
|
+
flattenElkNodes(elkRoot, null, nodes, edges, { value: 0 }, /* @__PURE__ */ new Map());
|
|
145
179
|
const seenEdges = /* @__PURE__ */ new Map();
|
|
146
180
|
for (const edge of edges) if (!seenEdges.has(edge.id)) seenEdges.set(edge.id, edge);
|
|
147
181
|
const elkDir = elkRoot.layoutOptions?.["elk.direction"];
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { F as VisualGraphFormatConverter, M as VisualGraph } from "../../types-BzckPChi.mjs";
|
|
2
2
|
import { EdgeBase, NodeBase } from "@xyflow/system";
|
|
3
3
|
|
|
4
4
|
//#region src/formats/xyflow/index.d.ts
|
|
@@ -42,6 +42,8 @@ function toXYFlow(graph) {
|
|
|
42
42
|
source: e.sourceId,
|
|
43
43
|
target: e.targetId
|
|
44
44
|
};
|
|
45
|
+
if (e.sourcePort) edge.sourceHandle = e.sourcePort;
|
|
46
|
+
if (e.targetPort) edge.targetHandle = e.targetPort;
|
|
45
47
|
if (e.data !== void 0) edge.data = e.data;
|
|
46
48
|
if (e.label) edge.data = {
|
|
47
49
|
...edge.data,
|
|
@@ -96,6 +98,8 @@ function fromXYFlow(flow) {
|
|
|
96
98
|
sourceId: e.source,
|
|
97
99
|
targetId: e.target,
|
|
98
100
|
label: e.data?.label?.toString() ?? "",
|
|
101
|
+
...e.sourceHandle && { sourcePort: e.sourceHandle },
|
|
102
|
+
...e.targetHandle && { targetPort: e.targetHandle },
|
|
99
103
|
data: e.data,
|
|
100
104
|
x: 0,
|
|
101
105
|
y: 0,
|
package/dist/index.d.mts
CHANGED
|
@@ -1,10 +1,20 @@
|
|
|
1
|
-
import { A as
|
|
2
|
-
import {
|
|
1
|
+
import { A as TraversalOptions, B as WeightedWalkOptions, C as NodeChange, D as PortDirection, E as PortConfig, I as VisualNode, L as VisualPort, M as VisualGraph, N as VisualGraphConfig, O as SinglePathOptions, P as VisualGraphEntity, R as WalkContext, S as MSTOptions, T as PathOptions, _ as GraphNode, a as EdgeChange, b as GraphPort, c as EntitiesUpdate, d as GraphConfig, f as GraphDiff, g as GraphFormatConverter, h as GraphEntityConfig, i as DeleteNodeOptions, j as VisualEdge, k as TransitionOptions, l as EntityRect, m as GraphEntity, n as AllPairsShortestPathsOptions, o as EdgeConfig, p as GraphEdge, r as CoverageStats, s as EntitiesConfig, t as AStarOptions, u as Graph, v as GraphPatch, w as NodeConfig, x as GraphStep, y as GraphPath, z as WalkOptions } from "./types-BzckPChi.mjs";
|
|
2
|
+
import { A as getArticulationPoints, B as HITSResult, C as hasPath, D as joinPaths, E as isTree, F as genGirvanNewmanCommunities, G as getEigenvectorCentrality, H as getBetweennessCentrality, I as getGirvanNewmanCommunities, J as getOutDegreeCentrality, K as getHITS, L as getGreedyModularityCommunities, M as getBridges, N as GirvanNewmanOptions, O as IsomorphismOptions, P as LabelPropagationOptions, R as getLabelPropagationCommunities, S as getTopologicalSort, T as isConnected, U as getClosenessCentrality, V as IterativeCentralityOptions, W as getDegreeCentrality, Y as getPageRank, _ as getShortestPath, a as genPreorders, b as getSimplePaths, c as getAStarPath, d as getCycles, f as getMinimumSpanningTree, g as getPreorders, h as getPreorder, i as genPostorders, j as getBiconnectedComponents, k as isIsomorphic, l as getAllPairsShortestPaths, m as getPostorders, n as dfs, o as genShortestPaths, p as getPostorder, q as getInDegreeCentrality, r as genCycles, s as genSimplePaths, t as bfs, u as getConnectedComponents, v as getShortestPaths, w as isAcyclic, x as getStronglyConnectedComponents, y as getSimplePath, z as getModularity } from "./algorithms-g2uWmPrb.mjs";
|
|
3
3
|
import { createFormatConverter } from "./formats/converter/index.mjs";
|
|
4
|
-
import { getAncestors, getChildren, getDegree, getDepth, getDescendants, getEdgeBetween, getEdgesOf, getInDegree, getInEdges, getLCA, getNeighbors, getOutDegree, getOutEdges, getParent, getPredecessors, getRelativeDistance, getRelativeDistanceMap, getRoots, getSiblings, getSinks, getSources, getSuccessors, isCompound, isLeaf } from "./queries.mjs";
|
|
4
|
+
import { getAncestors, getChildren, getDegree, getDepth, getDescendants, getEdgeBetween, getEdgesByPort, getEdgesOf, getInDegree, getInEdges, getLCA, getNeighbors, getOutDegree, getOutEdges, getParent, getPort, getPorts, getPredecessors, getRelativeDistance, getRelativeDistanceMap, getRoots, getSiblings, getSinks, getSources, getSuccessors, isCompound, isLeaf } from "./queries.mjs";
|
|
5
5
|
|
|
6
6
|
//#region src/graph.d.ts
|
|
7
7
|
|
|
8
|
+
/**
|
|
9
|
+
* Create a resolved graph port from a config. Fills in defaults.
|
|
10
|
+
*
|
|
11
|
+
* @example
|
|
12
|
+
* ```ts
|
|
13
|
+
* const port = createGraphPort({ name: 'output', direction: 'out' });
|
|
14
|
+
* // { name: 'output', direction: 'out', data: undefined }
|
|
15
|
+
* ```
|
|
16
|
+
*/
|
|
17
|
+
declare function createGraphPort<P = any>(config: PortConfig<P>): GraphPort<P>;
|
|
8
18
|
/**
|
|
9
19
|
* Create a resolved graph node from a config. Fills in defaults.
|
|
10
20
|
*
|
|
@@ -14,7 +24,7 @@ import { getAncestors, getChildren, getDegree, getDepth, getDescendants, getEdge
|
|
|
14
24
|
* // { type: 'node', id: 'a', label: '', data: { label: 'hi' } }
|
|
15
25
|
* ```
|
|
16
26
|
*/
|
|
17
|
-
declare function createGraphNode<
|
|
27
|
+
declare function createGraphNode<N = any, P = any>(config: NodeConfig<N, P>): GraphNode<N, P>;
|
|
18
28
|
/**
|
|
19
29
|
* Create a resolved graph edge from a config. Fills in defaults.
|
|
20
30
|
*
|
|
@@ -36,7 +46,7 @@ declare function createGraphEdge<T = any>(config: EdgeConfig<T>): GraphEdge<T>;
|
|
|
36
46
|
* });
|
|
37
47
|
* ```
|
|
38
48
|
*/
|
|
39
|
-
declare function createGraph<N = any, E = any, G = any>(config?: GraphConfig<N, E, G>): Graph<N, E, G>;
|
|
49
|
+
declare function createGraph<N = any, E = any, G = any, P = any>(config?: GraphConfig<N, E, G, P>): Graph<N, E, G, P>;
|
|
40
50
|
/**
|
|
41
51
|
* Create a visual graph with required position/size on all nodes and edges.
|
|
42
52
|
*
|
|
@@ -49,7 +59,7 @@ declare function createGraph<N = any, E = any, G = any>(config?: GraphConfig<N,
|
|
|
49
59
|
* // graph.nodes[0].x === 0
|
|
50
60
|
* ```
|
|
51
61
|
*/
|
|
52
|
-
declare function createVisualGraph<N = any, E = any, G = any>(config?: VisualGraphConfig<N, E, G>): VisualGraph<N, E, G>;
|
|
62
|
+
declare function createVisualGraph<N = any, E = any, G = any, P = any>(config?: VisualGraphConfig<N, E, G, P>): VisualGraph<N, E, G, P>;
|
|
53
63
|
/**
|
|
54
64
|
* Create a graph by BFS exploration of a transition function.
|
|
55
65
|
* Each unique state becomes a node; each (state, event) -> nextState becomes an edge.
|
|
@@ -139,7 +149,7 @@ declare function hasEdge(graph: Graph, id: string): boolean;
|
|
|
139
149
|
* // graph.nodes.length === 1
|
|
140
150
|
* ```
|
|
141
151
|
*/
|
|
142
|
-
declare function addNode<N>(graph: Graph<N>, config: NodeConfig<N>): GraphNode<N>;
|
|
152
|
+
declare function addNode<N, P = any>(graph: Graph<N, any, any, P>, config: NodeConfig<N, P>): GraphNode<N, P>;
|
|
143
153
|
/**
|
|
144
154
|
* **Mutable.** Add an edge to the graph. Mutates `graph.edges` in place.
|
|
145
155
|
* @returns The resolved edge that was added.
|
|
@@ -195,7 +205,7 @@ declare function deleteEdge(graph: Graph, id: string): void;
|
|
|
195
205
|
* // updated.label === 'new'
|
|
196
206
|
* ```
|
|
197
207
|
*/
|
|
198
|
-
declare function updateNode<N>(graph: Graph<N>, id: string, update: Partial<Omit<NodeConfig<N>, 'id'>>): GraphNode<N>;
|
|
208
|
+
declare function updateNode<N, P = any>(graph: Graph<N, any, any, P>, id: string, update: Partial<Omit<NodeConfig<N, P>, 'id'>>): GraphNode<N, P>;
|
|
199
209
|
/**
|
|
200
210
|
* **Mutable.** Update an edge in place.
|
|
201
211
|
* @returns The updated edge.
|
|
@@ -273,9 +283,9 @@ declare function updateEntities<N, E>(graph: Graph<N, E>, updates: EntitiesUpdat
|
|
|
273
283
|
* instance.toJSON(); // plain Graph object
|
|
274
284
|
* ```
|
|
275
285
|
*/
|
|
276
|
-
declare class GraphInstance<N = any, E = any, G = any> {
|
|
277
|
-
graph: Graph<N, E, G>;
|
|
278
|
-
constructor(config?: GraphConfig<N, E, G>);
|
|
286
|
+
declare class GraphInstance<N = any, E = any, G = any, P = any> {
|
|
287
|
+
graph: Graph<N, E, G, P>;
|
|
288
|
+
constructor(config?: GraphConfig<N, E, G, P>);
|
|
279
289
|
/**
|
|
280
290
|
* Wrap an existing plain graph object.
|
|
281
291
|
*
|
|
@@ -286,26 +296,26 @@ declare class GraphInstance<N = any, E = any, G = any> {
|
|
|
286
296
|
* instance.hasNode('a'); // true
|
|
287
297
|
* ```
|
|
288
298
|
*/
|
|
289
|
-
static from<N = any, E = any, G = any>(graph: Graph<N, E, G>): GraphInstance<N, E, G>;
|
|
299
|
+
static from<N = any, E = any, G = any, P = any>(graph: Graph<N, E, G, P>): GraphInstance<N, E, G, P>;
|
|
290
300
|
get id(): string;
|
|
291
301
|
get type(): "directed" | "undirected";
|
|
292
|
-
get nodes(): GraphNode<N>[];
|
|
302
|
+
get nodes(): GraphNode<N, P>[];
|
|
293
303
|
get edges(): GraphEdge<E>[];
|
|
294
304
|
get data(): G;
|
|
295
|
-
getNode(id: string): GraphNode<N> | undefined;
|
|
305
|
+
getNode(id: string): GraphNode<N, any> | undefined;
|
|
296
306
|
getEdge(id: string): GraphEdge<E> | undefined;
|
|
297
307
|
hasNode(id: string): boolean;
|
|
298
308
|
hasEdge(id: string): boolean;
|
|
299
|
-
addNode(config: NodeConfig<N>): GraphNode<N>;
|
|
309
|
+
addNode(config: NodeConfig<N, P>): GraphNode<N, P>;
|
|
300
310
|
addEdge(config: EdgeConfig<E>): GraphEdge<E>;
|
|
301
311
|
deleteNode(id: string, opts?: DeleteNodeOptions): void;
|
|
302
312
|
deleteEdge(id: string): void;
|
|
303
|
-
updateNode(id: string, update: Partial<Omit<NodeConfig<N>, 'id'>>): GraphNode<N>;
|
|
313
|
+
updateNode(id: string, update: Partial<Omit<NodeConfig<N, P>, 'id'>>): GraphNode<N, P>;
|
|
304
314
|
updateEdge(id: string, update: Partial<Omit<EdgeConfig<E>, 'id'>>): GraphEdge<E>;
|
|
305
|
-
addEntities(entities: EntitiesConfig<N, E>): void;
|
|
315
|
+
addEntities(entities: EntitiesConfig<N, E, P>): void;
|
|
306
316
|
deleteEntities(ids: string | string[], opts?: DeleteNodeOptions): void;
|
|
307
|
-
updateEntities(updates: EntitiesUpdate<N, E>): void;
|
|
308
|
-
toJSON(): Graph<N, E, G>;
|
|
317
|
+
updateEntities(updates: EntitiesUpdate<N, E, P>): void;
|
|
318
|
+
toJSON(): Graph<N, E, G, P>;
|
|
309
319
|
}
|
|
310
320
|
//#endregion
|
|
311
321
|
//#region src/indexing.d.ts
|
|
@@ -324,6 +334,57 @@ declare class GraphInstance<N = any, E = any, G = any> {
|
|
|
324
334
|
*/
|
|
325
335
|
declare function invalidateIndex(graph: Graph): void;
|
|
326
336
|
//#endregion
|
|
337
|
+
//#region src/equivalence.d.ts
|
|
338
|
+
declare const LAYOUT_KEYS: {
|
|
339
|
+
node: readonly ["x", "y", "width", "height", "style", "color", "shape"];
|
|
340
|
+
edge: readonly ["x", "y", "width", "height", "style", "color"];
|
|
341
|
+
};
|
|
342
|
+
/**
|
|
343
|
+
* Compare two entities on a given set of keys.
|
|
344
|
+
* If `keys` is omitted or empty, compares all own keys of `a`.
|
|
345
|
+
*
|
|
346
|
+
* @example
|
|
347
|
+
* ```ts
|
|
348
|
+
* import { createGraphNode, areEntitiesEqual, LAYOUT_KEYS } from '@statelyai/graph';
|
|
349
|
+
*
|
|
350
|
+
* const a = createGraphNode({ id: 'n1', label: 'hello', x: 0 });
|
|
351
|
+
* const b = createGraphNode({ id: 'n1', label: 'hello', x: 100 });
|
|
352
|
+
*
|
|
353
|
+
* areEntitiesEqual(a, b, LAYOUT_KEYS.node); // false (x differs)
|
|
354
|
+
* areEntitiesEqual(a, b, NON_LAYOUT_KEYS.node); // true
|
|
355
|
+
* areEntitiesEqual(a, b); // false (compares all keys)
|
|
356
|
+
* ```
|
|
357
|
+
*/
|
|
358
|
+
declare function areEntitiesEqual<T extends GraphNode | GraphEdge>(a: T, b: T, keys?: readonly (keyof T)[]): boolean;
|
|
359
|
+
/**
|
|
360
|
+
* Compare two entities on layout keys only (position, size, style, color, shape).
|
|
361
|
+
*
|
|
362
|
+
* @example
|
|
363
|
+
* ```ts
|
|
364
|
+
* import { createGraphNode, isLayoutEqual } from '@statelyai/graph';
|
|
365
|
+
*
|
|
366
|
+
* const a = createGraphNode({ id: 'n1', x: 0, y: 0 });
|
|
367
|
+
* const b = createGraphNode({ id: 'n1', x: 100, y: 200 });
|
|
368
|
+
*
|
|
369
|
+
* isLayoutEqual(a, b); // false
|
|
370
|
+
* ```
|
|
371
|
+
*/
|
|
372
|
+
declare function isLayoutEqual<T extends GraphNode | GraphEdge>(a: T, b: T): boolean;
|
|
373
|
+
/**
|
|
374
|
+
* Compare two entities on non-layout keys only (id, data, connections, labels, etc.).
|
|
375
|
+
*
|
|
376
|
+
* @example
|
|
377
|
+
* ```ts
|
|
378
|
+
* import { createGraphNode, isNonLayoutEqual } from '@statelyai/graph';
|
|
379
|
+
*
|
|
380
|
+
* const a = createGraphNode({ id: 'n1', label: 'hello', x: 0 });
|
|
381
|
+
* const b = createGraphNode({ id: 'n1', label: 'hello', x: 100 });
|
|
382
|
+
*
|
|
383
|
+
* isNonLayoutEqual(a, b); // true (layout changed, but non-layout didn't)
|
|
384
|
+
* ```
|
|
385
|
+
*/
|
|
386
|
+
declare function isNonLayoutEqual<T extends GraphNode | GraphEdge>(a: T, b: T): boolean;
|
|
387
|
+
//#endregion
|
|
327
388
|
//#region src/diff.d.ts
|
|
328
389
|
/**
|
|
329
390
|
* Compute a structured diff from graph `a` to graph `b` by matching IDs.
|
|
@@ -567,4 +628,4 @@ declare function getCoverage<N, E>(graph: Graph<N, E>, steps: GraphStep<N, E>[],
|
|
|
567
628
|
from?: string;
|
|
568
629
|
}): CoverageStats;
|
|
569
630
|
//#endregion
|
|
570
|
-
export { type AStarOptions, type AllPairsShortestPathsOptions, type CoverageStats, type DeleteNodeOptions, type EdgeChange, type EdgeConfig, type EntitiesConfig, type EntitiesUpdate, type Graph, type GraphConfig, type GraphDiff, type GraphEdge, type GraphFormatConverter, GraphInstance, type GraphNode, type GraphPatch, type GraphPath, type GraphStep, type MSTOptions, type NodeChange, type NodeConfig, type PathOptions, type EntityRect as Positioned, type SinglePathOptions, type TransitionOptions, type TraversalOptions, type VisualEdge, type VisualGraph, type VisualGraphConfig, type VisualNode, type WalkContext, type WalkOptions, type WeightedWalkOptions, addEdge, addEntities, addNode, applyPatches, bfs, createFormatConverter, createGraph, createGraphEdge, createGraphFromTransition, createGraphNode, createVisualGraph, deleteEdge, deleteEntities, deleteNode, dfs, flatten, genCycles, genPostorders, genPredefinedWalk, genPreorders, genQuickRandomWalk, genRandomWalk, genShortestPaths, genSimplePaths, genWeightedRandomWalk, getAStarPath, getAllPairsShortestPaths, getAncestors, getChildren, getConnectedComponents, getCoverage, getCycles, getDegree, getDepth, getDescendants, getDiff, getEdge, getEdgeBetween, getEdgesOf, getInDegree, getInEdges, getLCA, getMinimumSpanningTree, getNeighbors, getNode, getOutDegree, getOutEdges, getParent, getPatches, getPostorder, getPostorders, getPredecessors, getPreorder, getPreorders, getRelativeDistance, getRelativeDistanceMap, getRoots, getShortestPath, getShortestPaths, getSiblings, getSimplePath, getSimplePaths, getSinks, getSources, getStronglyConnectedComponents, getSubgraph, getSuccessors, getTopologicalSort, hasEdge, hasNode, hasPath, invalidateIndex, invertDiff, isAcyclic, isCompound, isConnected, isEmptyDiff, isLeaf, isTree, joinPaths, reverseGraph, takeSteps, takeUntilEdge, takeUntilEdgeCoverage, takeUntilNode, takeUntilNodeCoverage, toDiff, toPatches, updateEdge, updateEntities, updateNode };
|
|
631
|
+
export { type AStarOptions, type AllPairsShortestPathsOptions, type CoverageStats, type DeleteNodeOptions, type EdgeChange, type EdgeConfig, type EntitiesConfig, type EntitiesUpdate, type GirvanNewmanOptions, type Graph, type GraphConfig, type GraphDiff, type GraphEdge, type GraphEntity, type GraphEntityConfig, type GraphFormatConverter, GraphInstance, type GraphNode, type GraphPatch, type GraphPath, type GraphPort, type GraphStep, type HITSResult, type IsomorphismOptions, type IterativeCentralityOptions, LAYOUT_KEYS, type LabelPropagationOptions, type MSTOptions, type NodeChange, type NodeConfig, type PathOptions, type PortConfig, type PortDirection, type EntityRect as Positioned, type SinglePathOptions, type TransitionOptions, type TraversalOptions, type VisualEdge, type VisualGraph, type VisualGraphConfig, type VisualGraphEntity, type VisualNode, type VisualPort, type WalkContext, type WalkOptions, type WeightedWalkOptions, addEdge, addEntities, addNode, applyPatches, areEntitiesEqual, bfs, createFormatConverter, createGraph, createGraphEdge, createGraphFromTransition, createGraphNode, createGraphPort, createVisualGraph, deleteEdge, deleteEntities, deleteNode, dfs, flatten, genCycles, genGirvanNewmanCommunities, genPostorders, genPredefinedWalk, genPreorders, genQuickRandomWalk, genRandomWalk, genShortestPaths, genSimplePaths, genWeightedRandomWalk, getAStarPath, getAllPairsShortestPaths, getAncestors, getArticulationPoints, getBetweennessCentrality, getBiconnectedComponents, getBridges, getChildren, getClosenessCentrality, getConnectedComponents, getCoverage, getCycles, getDegree, getDegreeCentrality, getDepth, getDescendants, getDiff, getEdge, getEdgeBetween, getEdgesByPort, getEdgesOf, getEigenvectorCentrality, getGirvanNewmanCommunities, getGreedyModularityCommunities, getHITS, getInDegree, getInDegreeCentrality, getInEdges, getLCA, getLabelPropagationCommunities, getMinimumSpanningTree, getModularity, getNeighbors, getNode, getOutDegree, getOutDegreeCentrality, getOutEdges, getPageRank, getParent, getPatches, getPort, getPorts, getPostorder, getPostorders, getPredecessors, getPreorder, getPreorders, getRelativeDistance, getRelativeDistanceMap, getRoots, getShortestPath, getShortestPaths, getSiblings, getSimplePath, getSimplePaths, getSinks, getSources, getStronglyConnectedComponents, getSubgraph, getSuccessors, getTopologicalSort, hasEdge, hasNode, hasPath, invalidateIndex, invertDiff, isAcyclic, isCompound, isConnected, isEmptyDiff, isIsomorphic, isLayoutEqual, isLeaf, isNonLayoutEqual, isTree, joinPaths, reverseGraph, takeSteps, takeUntilEdge, takeUntilEdgeCoverage, takeUntilNode, takeUntilNodeCoverage, toDiff, toPatches, updateEdge, updateEntities, updateNode };
|
package/dist/index.mjs
CHANGED
|
@@ -1,8 +1,100 @@
|
|
|
1
1
|
import { o as invalidateIndex, t as getIndex } from "./indexing-DyfgLuzw.mjs";
|
|
2
|
-
import { A as
|
|
3
|
-
import { getAncestors, getChildren, getDegree, getDepth, getDescendants, getEdgeBetween, getEdgesOf, getInDegree, getInEdges, getLCA, getNeighbors, getOutDegree, getOutEdges, getParent, getPredecessors, getRelativeDistance, getRelativeDistanceMap, getRoots, getSiblings, getSinks, getSources, getSuccessors, isCompound, isLeaf } from "./queries.mjs";
|
|
2
|
+
import { $ as createGraphPort, A as getBiconnectedComponents, B as getEigenvectorCentrality, C as hasPath, D as joinPaths, E as isTree, F as getLabelPropagationCommunities, G as GraphInstance, H as getInDegreeCentrality, I as getModularity, J as addNode, K as addEdge, L as getBetweennessCentrality, M as genGirvanNewmanCommunities, N as getGirvanNewmanCommunities, O as isIsomorphic, P as getGreedyModularityCommunities, Q as createGraphNode, R as getClosenessCentrality, S as getTopologicalSort, T as isConnected, U as getOutDegreeCentrality, V as getHITS, W as getPageRank, X as createGraphEdge, Y as createGraph, Z as createGraphFromTransition, _ as getShortestPath, a as genPreorders, at as getNode, b as getSimplePaths, c as getAStarPath, ct as updateEdge, d as getCycles, et as createVisualGraph, f as getMinimumSpanningTree, g as getPreorders, h as getPreorder, i as genPostorders, it as getEdge, j as getBridges, k as getArticulationPoints, l as getAllPairsShortestPaths, lt as updateEntities, m as getPostorders, n as dfs, nt as deleteEntities, o as genShortestPaths, ot as hasEdge, p as getPostorder, q as addEntities, r as genCycles, rt as deleteNode, s as genSimplePaths, st as hasNode, t as bfs, tt as deleteEdge, u as getConnectedComponents, ut as updateNode, v as getShortestPaths, w as isAcyclic, x as getStronglyConnectedComponents, y as getSimplePath, z as getDegreeCentrality } from "./algorithms-3xvCxHzo.mjs";
|
|
3
|
+
import { getAncestors, getChildren, getDegree, getDepth, getDescendants, getEdgeBetween, getEdgesByPort, getEdgesOf, getInDegree, getInEdges, getLCA, getNeighbors, getOutDegree, getOutEdges, getParent, getPort, getPorts, getPredecessors, getRelativeDistance, getRelativeDistanceMap, getRoots, getSiblings, getSinks, getSources, getSuccessors, isCompound, isLeaf } from "./queries.mjs";
|
|
4
4
|
import { n as createFormatConverter } from "./converter-B5CUD0r9.mjs";
|
|
5
5
|
|
|
6
|
+
//#region src/equivalence.ts
|
|
7
|
+
/** Shallow-compare two values, returning true if they differ. */
|
|
8
|
+
function differs$1(a, b) {
|
|
9
|
+
if (a === b) return false;
|
|
10
|
+
if (a == null || b == null) return a !== b;
|
|
11
|
+
if (typeof a === "object" && typeof b === "object") return JSON.stringify(a) !== JSON.stringify(b);
|
|
12
|
+
return true;
|
|
13
|
+
}
|
|
14
|
+
const LAYOUT_KEYS = {
|
|
15
|
+
node: [
|
|
16
|
+
"x",
|
|
17
|
+
"y",
|
|
18
|
+
"width",
|
|
19
|
+
"height",
|
|
20
|
+
"style",
|
|
21
|
+
"color",
|
|
22
|
+
"shape"
|
|
23
|
+
],
|
|
24
|
+
edge: [
|
|
25
|
+
"x",
|
|
26
|
+
"y",
|
|
27
|
+
"width",
|
|
28
|
+
"height",
|
|
29
|
+
"style",
|
|
30
|
+
"color"
|
|
31
|
+
]
|
|
32
|
+
};
|
|
33
|
+
const LAYOUT_KEY_SET = {
|
|
34
|
+
node: new Set(LAYOUT_KEYS.node),
|
|
35
|
+
edge: new Set(LAYOUT_KEYS.edge)
|
|
36
|
+
};
|
|
37
|
+
/**
|
|
38
|
+
* Compare two entities on a given set of keys.
|
|
39
|
+
* If `keys` is omitted or empty, compares all own keys of `a`.
|
|
40
|
+
*
|
|
41
|
+
* @example
|
|
42
|
+
* ```ts
|
|
43
|
+
* import { createGraphNode, areEntitiesEqual, LAYOUT_KEYS } from '@statelyai/graph';
|
|
44
|
+
*
|
|
45
|
+
* const a = createGraphNode({ id: 'n1', label: 'hello', x: 0 });
|
|
46
|
+
* const b = createGraphNode({ id: 'n1', label: 'hello', x: 100 });
|
|
47
|
+
*
|
|
48
|
+
* areEntitiesEqual(a, b, LAYOUT_KEYS.node); // false (x differs)
|
|
49
|
+
* areEntitiesEqual(a, b, NON_LAYOUT_KEYS.node); // true
|
|
50
|
+
* areEntitiesEqual(a, b); // false (compares all keys)
|
|
51
|
+
* ```
|
|
52
|
+
*/
|
|
53
|
+
function areEntitiesEqual(a, b, keys) {
|
|
54
|
+
const compareKeys = keys && keys.length > 0 ? keys : Object.keys(a);
|
|
55
|
+
for (const key of compareKeys) if (differs$1(a[key], b[key])) return false;
|
|
56
|
+
return true;
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Compare two entities on layout keys only (position, size, style, color, shape).
|
|
60
|
+
*
|
|
61
|
+
* @example
|
|
62
|
+
* ```ts
|
|
63
|
+
* import { createGraphNode, isLayoutEqual } from '@statelyai/graph';
|
|
64
|
+
*
|
|
65
|
+
* const a = createGraphNode({ id: 'n1', x: 0, y: 0 });
|
|
66
|
+
* const b = createGraphNode({ id: 'n1', x: 100, y: 200 });
|
|
67
|
+
*
|
|
68
|
+
* isLayoutEqual(a, b); // false
|
|
69
|
+
* ```
|
|
70
|
+
*/
|
|
71
|
+
function isLayoutEqual(a, b) {
|
|
72
|
+
return areEntitiesEqual(a, b, LAYOUT_KEYS[a.type]);
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* Compare two entities on non-layout keys only (id, data, connections, labels, etc.).
|
|
76
|
+
*
|
|
77
|
+
* @example
|
|
78
|
+
* ```ts
|
|
79
|
+
* import { createGraphNode, isNonLayoutEqual } from '@statelyai/graph';
|
|
80
|
+
*
|
|
81
|
+
* const a = createGraphNode({ id: 'n1', label: 'hello', x: 0 });
|
|
82
|
+
* const b = createGraphNode({ id: 'n1', label: 'hello', x: 100 });
|
|
83
|
+
*
|
|
84
|
+
* isNonLayoutEqual(a, b); // true (layout changed, but non-layout didn't)
|
|
85
|
+
* ```
|
|
86
|
+
*/
|
|
87
|
+
function isNonLayoutEqual(a, b) {
|
|
88
|
+
const skip = LAYOUT_KEY_SET[a.type];
|
|
89
|
+
const keys = Object.keys(a);
|
|
90
|
+
for (let i = 0; i < keys.length; i++) {
|
|
91
|
+
if (skip.has(keys[i])) continue;
|
|
92
|
+
if (differs$1(a[keys[i]], b[keys[i]])) return false;
|
|
93
|
+
}
|
|
94
|
+
return true;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
//#endregion
|
|
6
98
|
//#region src/diff.ts
|
|
7
99
|
function nodeToConfig$1(node) {
|
|
8
100
|
const config = { id: node.id };
|
|
@@ -813,4 +905,4 @@ function getCoverage(graph, steps, options) {
|
|
|
813
905
|
}
|
|
814
906
|
|
|
815
907
|
//#endregion
|
|
816
|
-
export { GraphInstance, addEdge, addEntities, addNode, applyPatches, bfs, createFormatConverter, createGraph, createGraphEdge, createGraphFromTransition, createGraphNode, createVisualGraph, deleteEdge, deleteEntities, deleteNode, dfs, flatten, genCycles, genPostorders, genPredefinedWalk, genPreorders, genQuickRandomWalk, genRandomWalk, genShortestPaths, genSimplePaths, genWeightedRandomWalk, getAStarPath, getAllPairsShortestPaths, getAncestors, getChildren, getConnectedComponents, getCoverage, getCycles, getDegree, getDepth, getDescendants, getDiff, getEdge, getEdgeBetween, getEdgesOf, getInDegree, getInEdges, getLCA, getMinimumSpanningTree, getNeighbors, getNode, getOutDegree, getOutEdges, getParent, getPatches, getPostorder, getPostorders, getPredecessors, getPreorder, getPreorders, getRelativeDistance, getRelativeDistanceMap, getRoots, getShortestPath, getShortestPaths, getSiblings, getSimplePath, getSimplePaths, getSinks, getSources, getStronglyConnectedComponents, getSubgraph, getSuccessors, getTopologicalSort, hasEdge, hasNode, hasPath, invalidateIndex, invertDiff, isAcyclic, isCompound, isConnected, isEmptyDiff, isLeaf, isTree, joinPaths, reverseGraph, takeSteps, takeUntilEdge, takeUntilEdgeCoverage, takeUntilNode, takeUntilNodeCoverage, toDiff, toPatches, updateEdge, updateEntities, updateNode };
|
|
908
|
+
export { GraphInstance, LAYOUT_KEYS, addEdge, addEntities, addNode, applyPatches, areEntitiesEqual, bfs, createFormatConverter, createGraph, createGraphEdge, createGraphFromTransition, createGraphNode, createGraphPort, createVisualGraph, deleteEdge, deleteEntities, deleteNode, dfs, flatten, genCycles, genGirvanNewmanCommunities, genPostorders, genPredefinedWalk, genPreorders, genQuickRandomWalk, genRandomWalk, genShortestPaths, genSimplePaths, genWeightedRandomWalk, getAStarPath, getAllPairsShortestPaths, getAncestors, getArticulationPoints, getBetweennessCentrality, getBiconnectedComponents, getBridges, getChildren, getClosenessCentrality, getConnectedComponents, getCoverage, getCycles, getDegree, getDegreeCentrality, getDepth, getDescendants, getDiff, getEdge, getEdgeBetween, getEdgesByPort, getEdgesOf, getEigenvectorCentrality, getGirvanNewmanCommunities, getGreedyModularityCommunities, getHITS, getInDegree, getInDegreeCentrality, getInEdges, getLCA, getLabelPropagationCommunities, getMinimumSpanningTree, getModularity, getNeighbors, getNode, getOutDegree, getOutDegreeCentrality, getOutEdges, getPageRank, getParent, getPatches, getPort, getPorts, getPostorder, getPostorders, getPredecessors, getPreorder, getPreorders, getRelativeDistance, getRelativeDistanceMap, getRoots, getShortestPath, getShortestPaths, getSiblings, getSimplePath, getSimplePaths, getSinks, getSources, getStronglyConnectedComponents, getSubgraph, getSuccessors, getTopologicalSort, hasEdge, hasNode, hasPath, invalidateIndex, invertDiff, isAcyclic, isCompound, isConnected, isEmptyDiff, isIsomorphic, isLayoutEqual, isLeaf, isNonLayoutEqual, isTree, joinPaths, reverseGraph, takeSteps, takeUntilEdge, takeUntilEdgeCoverage, takeUntilNode, takeUntilNodeCoverage, toDiff, toPatches, updateEdge, updateEntities, updateNode };
|
package/dist/queries.d.mts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { _ as GraphNode, b as GraphPort, p as GraphEdge, u as Graph } from "./types-BzckPChi.mjs";
|
|
2
2
|
|
|
3
3
|
//#region src/queries.d.ts
|
|
4
4
|
|
|
@@ -454,5 +454,62 @@ declare function getSources<N>(graph: Graph<N>): GraphNode<N>[];
|
|
|
454
454
|
* ```
|
|
455
455
|
*/
|
|
456
456
|
declare function getSinks<N>(graph: Graph<N>): GraphNode<N>[];
|
|
457
|
+
/**
|
|
458
|
+
* Get a port by name on a node, or `undefined` if not found.
|
|
459
|
+
*
|
|
460
|
+
* @example
|
|
461
|
+
* ```ts
|
|
462
|
+
* const graph = createGraph({
|
|
463
|
+
* nodes: [{
|
|
464
|
+
* id: 'a',
|
|
465
|
+
* ports: [{ name: 'out', direction: 'out' }],
|
|
466
|
+
* }],
|
|
467
|
+
* });
|
|
468
|
+
* getPort(graph, 'a', 'out'); // => { name: 'out', direction: 'out', ... }
|
|
469
|
+
* getPort(graph, 'a', 'missing'); // => undefined
|
|
470
|
+
* ```
|
|
471
|
+
*/
|
|
472
|
+
declare function getPort<P = any>(graph: Graph<any, any, any, P>, nodeId: string, portName: string): GraphPort<P> | undefined;
|
|
473
|
+
/**
|
|
474
|
+
* Get all ports on a node. Returns `[]` if the node has no ports or doesn't exist.
|
|
475
|
+
*
|
|
476
|
+
* @example
|
|
477
|
+
* ```ts
|
|
478
|
+
* const graph = createGraph({
|
|
479
|
+
* nodes: [{
|
|
480
|
+
* id: 'a',
|
|
481
|
+
* ports: [
|
|
482
|
+
* { name: 'in', direction: 'in' },
|
|
483
|
+
* { name: 'out', direction: 'out' },
|
|
484
|
+
* ],
|
|
485
|
+
* }],
|
|
486
|
+
* });
|
|
487
|
+
* getPorts(graph, 'a'); // => [port in, port out]
|
|
488
|
+
* ```
|
|
489
|
+
*/
|
|
490
|
+
declare function getPorts<P = any>(graph: Graph<any, any, any, P>, nodeId: string): GraphPort<P>[];
|
|
491
|
+
/**
|
|
492
|
+
* Get all edges connected to a specific port on a node.
|
|
493
|
+
*
|
|
494
|
+
* Returns edges where:
|
|
495
|
+
* - `sourceId === nodeId && sourcePort === portName`, or
|
|
496
|
+
* - `targetId === nodeId && targetPort === portName`
|
|
497
|
+
*
|
|
498
|
+
* @example
|
|
499
|
+
* ```ts
|
|
500
|
+
* const graph = createGraph({
|
|
501
|
+
* nodes: [
|
|
502
|
+
* { id: 'a', ports: [{ name: 'out', direction: 'out' }] },
|
|
503
|
+
* { id: 'b', ports: [{ name: 'in', direction: 'in' }] },
|
|
504
|
+
* ],
|
|
505
|
+
* edges: [{
|
|
506
|
+
* id: 'e1', sourceId: 'a', targetId: 'b',
|
|
507
|
+
* sourcePort: 'out', targetPort: 'in',
|
|
508
|
+
* }],
|
|
509
|
+
* });
|
|
510
|
+
* getEdgesByPort(graph, 'a', 'out'); // => [edge e1]
|
|
511
|
+
* ```
|
|
512
|
+
*/
|
|
513
|
+
declare function getEdgesByPort<E = any>(graph: Graph<any, E>, nodeId: string, portName: string): GraphEdge<E>[];
|
|
457
514
|
//#endregion
|
|
458
|
-
export { getAncestors, getChildren, getDegree, getDepth, getDescendants, getEdgeBetween, getEdgesOf, getInDegree, getInEdges, getLCA, getNeighbors, getOutDegree, getOutEdges, getParent, getPredecessors, getRelativeDistance, getRelativeDistanceMap, getRoots, getSiblings, getSinks, getSources, getSuccessors, isCompound, isLeaf };
|
|
515
|
+
export { getAncestors, getChildren, getDegree, getDepth, getDescendants, getEdgeBetween, getEdgesByPort, getEdgesOf, getInDegree, getInEdges, getLCA, getNeighbors, getOutDegree, getOutEdges, getParent, getPort, getPorts, getPredecessors, getRelativeDistance, getRelativeDistanceMap, getRoots, getSiblings, getSinks, getSources, getSuccessors, isCompound, isLeaf };
|
package/dist/queries.mjs
CHANGED
|
@@ -679,6 +679,83 @@ function getSinks(graph) {
|
|
|
679
679
|
const idx = getIndex(graph);
|
|
680
680
|
return graph.nodes.filter((n) => (idx.outEdges.get(n.id)?.length ?? 0) === 0);
|
|
681
681
|
}
|
|
682
|
+
/**
|
|
683
|
+
* Get a port by name on a node, or `undefined` if not found.
|
|
684
|
+
*
|
|
685
|
+
* @example
|
|
686
|
+
* ```ts
|
|
687
|
+
* const graph = createGraph({
|
|
688
|
+
* nodes: [{
|
|
689
|
+
* id: 'a',
|
|
690
|
+
* ports: [{ name: 'out', direction: 'out' }],
|
|
691
|
+
* }],
|
|
692
|
+
* });
|
|
693
|
+
* getPort(graph, 'a', 'out'); // => { name: 'out', direction: 'out', ... }
|
|
694
|
+
* getPort(graph, 'a', 'missing'); // => undefined
|
|
695
|
+
* ```
|
|
696
|
+
*/
|
|
697
|
+
function getPort(graph, nodeId, portName) {
|
|
698
|
+
const ni = getIndex(graph).nodeById.get(nodeId);
|
|
699
|
+
if (ni === void 0) return void 0;
|
|
700
|
+
return graph.nodes[ni].ports?.find((p) => p.name === portName);
|
|
701
|
+
}
|
|
702
|
+
/**
|
|
703
|
+
* Get all ports on a node. Returns `[]` if the node has no ports or doesn't exist.
|
|
704
|
+
*
|
|
705
|
+
* @example
|
|
706
|
+
* ```ts
|
|
707
|
+
* const graph = createGraph({
|
|
708
|
+
* nodes: [{
|
|
709
|
+
* id: 'a',
|
|
710
|
+
* ports: [
|
|
711
|
+
* { name: 'in', direction: 'in' },
|
|
712
|
+
* { name: 'out', direction: 'out' },
|
|
713
|
+
* ],
|
|
714
|
+
* }],
|
|
715
|
+
* });
|
|
716
|
+
* getPorts(graph, 'a'); // => [port in, port out]
|
|
717
|
+
* ```
|
|
718
|
+
*/
|
|
719
|
+
function getPorts(graph, nodeId) {
|
|
720
|
+
const ni = getIndex(graph).nodeById.get(nodeId);
|
|
721
|
+
if (ni === void 0) return [];
|
|
722
|
+
return graph.nodes[ni].ports ?? [];
|
|
723
|
+
}
|
|
724
|
+
/**
|
|
725
|
+
* Get all edges connected to a specific port on a node.
|
|
726
|
+
*
|
|
727
|
+
* Returns edges where:
|
|
728
|
+
* - `sourceId === nodeId && sourcePort === portName`, or
|
|
729
|
+
* - `targetId === nodeId && targetPort === portName`
|
|
730
|
+
*
|
|
731
|
+
* @example
|
|
732
|
+
* ```ts
|
|
733
|
+
* const graph = createGraph({
|
|
734
|
+
* nodes: [
|
|
735
|
+
* { id: 'a', ports: [{ name: 'out', direction: 'out' }] },
|
|
736
|
+
* { id: 'b', ports: [{ name: 'in', direction: 'in' }] },
|
|
737
|
+
* ],
|
|
738
|
+
* edges: [{
|
|
739
|
+
* id: 'e1', sourceId: 'a', targetId: 'b',
|
|
740
|
+
* sourcePort: 'out', targetPort: 'in',
|
|
741
|
+
* }],
|
|
742
|
+
* });
|
|
743
|
+
* getEdgesByPort(graph, 'a', 'out'); // => [edge e1]
|
|
744
|
+
* ```
|
|
745
|
+
*/
|
|
746
|
+
function getEdgesByPort(graph, nodeId, portName) {
|
|
747
|
+
const idx = getIndex(graph);
|
|
748
|
+
const result = [];
|
|
749
|
+
for (const eid of idx.outEdges.get(nodeId) ?? []) {
|
|
750
|
+
const ai = idx.edgeById.get(eid);
|
|
751
|
+
if (ai !== void 0 && graph.edges[ai].sourcePort === portName) result.push(graph.edges[ai]);
|
|
752
|
+
}
|
|
753
|
+
for (const eid of idx.inEdges.get(nodeId) ?? []) {
|
|
754
|
+
const ai = idx.edgeById.get(eid);
|
|
755
|
+
if (ai !== void 0 && graph.edges[ai].targetPort === portName) result.push(graph.edges[ai]);
|
|
756
|
+
}
|
|
757
|
+
return result;
|
|
758
|
+
}
|
|
682
759
|
|
|
683
760
|
//#endregion
|
|
684
|
-
export { getAncestors, getChildren, getDegree, getDepth, getDescendants, getEdgeBetween, getEdgesOf, getInDegree, getInEdges, getLCA, getNeighbors, getOutDegree, getOutEdges, getParent, getPredecessors, getRelativeDistance, getRelativeDistanceMap, getRoots, getSiblings, getSinks, getSources, getSuccessors, isCompound, isLeaf };
|
|
761
|
+
export { getAncestors, getChildren, getDegree, getDepth, getDescendants, getEdgeBetween, getEdgesByPort, getEdgesOf, getInDegree, getInEdges, getLCA, getNeighbors, getOutDegree, getOutEdges, getParent, getPort, getPorts, getPredecessors, getRelativeDistance, getRelativeDistanceMap, getRoots, getSiblings, getSinks, getSources, getSuccessors, isCompound, isLeaf };
|