@statelyai/graph 0.1.0 → 0.3.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 +65 -15
- package/dist/{adjacency-list-CXpOCibq.mjs → adjacency-list-A4_Eiwj3.mjs} +1 -1
- package/dist/{algorithms-R35X6ro4.mjs → algorithms-DBU7nmIV.mjs} +83 -2
- package/dist/algorithms.d.mts +10 -2
- package/dist/algorithms.mjs +2 -2
- package/dist/converter-DnbeyE_p.mjs +33 -0
- package/dist/{edge-list-BRujEnnU.mjs → edge-list-DuHMz8hf.mjs} +1 -1
- package/dist/{adjacency-list-DW-lAUe8.d.mts → formats/adjacency-list/index.d.mts} +3 -3
- package/dist/formats/adjacency-list/index.mjs +3 -0
- package/dist/formats/converter/index.d.mts +27 -0
- package/dist/formats/converter/index.mjs +3 -0
- package/dist/formats/cytoscape/index.d.mts +35 -0
- package/dist/formats/cytoscape/index.mjs +87 -0
- package/dist/formats/d3/index.d.mts +22 -0
- package/dist/formats/d3/index.mjs +65 -0
- package/dist/formats/dot/index.d.mts +9 -0
- package/dist/formats/dot/index.mjs +235 -0
- package/dist/{edge-list-CJmfoNu2.d.mts → formats/edge-list/index.d.mts} +3 -3
- package/dist/formats/edge-list/index.mjs +3 -0
- package/dist/formats/gexf/index.d.mts +9 -0
- package/dist/formats/gexf/index.mjs +249 -0
- package/dist/formats/gml/index.d.mts +9 -0
- package/dist/formats/gml/index.mjs +236 -0
- package/dist/formats/graphml/index.d.mts +9 -0
- package/dist/{graphml-CUTNRXqd.mjs → formats/graphml/index.mjs} +18 -4
- package/dist/formats/jgf/index.d.mts +30 -0
- package/dist/formats/jgf/index.mjs +85 -0
- package/dist/formats/mermaid/index.d.mts +188 -0
- package/dist/formats/mermaid/index.mjs +1898 -0
- package/dist/formats/tgf/index.d.mts +9 -0
- package/dist/formats/tgf/index.mjs +67 -0
- package/dist/index.d.mts +14 -9
- package/dist/index.mjs +5 -9
- package/dist/queries.d.mts +78 -2
- package/dist/queries.mjs +121 -2
- package/dist/{types-XV3S5Jnh.d.mts → types-B6Tpeerk.d.mts} +36 -1
- package/package.json +43 -17
- package/dist/dot-BRtq3e3c.mjs +0 -59
- package/dist/dot-HmJeUMsj.d.mts +0 -6
- package/dist/formats/adjacency-list.d.mts +0 -2
- package/dist/formats/adjacency-list.mjs +0 -3
- package/dist/formats/dot.d.mts +0 -2
- package/dist/formats/dot.mjs +0 -3
- package/dist/formats/edge-list.d.mts +0 -2
- package/dist/formats/edge-list.mjs +0 -3
- package/dist/formats/graphml.d.mts +0 -2
- package/dist/formats/graphml.mjs +0 -3
- package/dist/graphml-CMjPzSfY.d.mts +0 -7
- /package/dist/{indexing-BHg1VhqN.mjs → indexing-BFFVMnjF.mjs} +0 -0
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { c as Graph, f as GraphFormatConverter } from "../../types-B6Tpeerk.mjs";
|
|
2
|
+
|
|
3
|
+
//#region src/formats/tgf/index.d.ts
|
|
4
|
+
declare function toTGF(graph: Graph): string;
|
|
5
|
+
declare function fromTGF(tgf: string): Graph;
|
|
6
|
+
/** Bidirectional converter for TGF (Trivial Graph Format). */
|
|
7
|
+
declare const tgfConverter: GraphFormatConverter<string>;
|
|
8
|
+
//#endregion
|
|
9
|
+
export { fromTGF, tgfConverter, toTGF };
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import { n as createFormatConverter } from "../../converter-DnbeyE_p.mjs";
|
|
2
|
+
|
|
3
|
+
//#region src/formats/tgf/index.ts
|
|
4
|
+
function toTGF(graph) {
|
|
5
|
+
const lines = [];
|
|
6
|
+
for (const node of graph.nodes) lines.push(node.label ? `${node.id} ${node.label}` : node.id);
|
|
7
|
+
lines.push("#");
|
|
8
|
+
for (const edge of graph.edges) {
|
|
9
|
+
const parts = [edge.sourceId, edge.targetId];
|
|
10
|
+
if (edge.label) parts.push(edge.label);
|
|
11
|
+
lines.push(parts.join(" "));
|
|
12
|
+
}
|
|
13
|
+
return lines.join("\n");
|
|
14
|
+
}
|
|
15
|
+
function fromTGF(tgf) {
|
|
16
|
+
if (typeof tgf !== "string") throw new Error("TGF: expected a string");
|
|
17
|
+
const lines = tgf.split("\n");
|
|
18
|
+
const sepIdx = lines.indexOf("#");
|
|
19
|
+
const nodeLines = sepIdx >= 0 ? lines.slice(0, sepIdx) : lines;
|
|
20
|
+
const edgeLines = sepIdx >= 0 ? lines.slice(sepIdx + 1) : [];
|
|
21
|
+
const nodes = [];
|
|
22
|
+
for (const line of nodeLines) {
|
|
23
|
+
const trimmed = line.trim();
|
|
24
|
+
if (!trimmed) continue;
|
|
25
|
+
const spaceIdx = trimmed.indexOf(" ");
|
|
26
|
+
const id = spaceIdx >= 0 ? trimmed.slice(0, spaceIdx) : trimmed;
|
|
27
|
+
const label = spaceIdx >= 0 ? trimmed.slice(spaceIdx + 1) : "";
|
|
28
|
+
nodes.push({
|
|
29
|
+
type: "node",
|
|
30
|
+
id,
|
|
31
|
+
parentId: null,
|
|
32
|
+
initialNodeId: null,
|
|
33
|
+
label,
|
|
34
|
+
data: void 0
|
|
35
|
+
});
|
|
36
|
+
}
|
|
37
|
+
const edges = [];
|
|
38
|
+
for (const line of edgeLines) {
|
|
39
|
+
const trimmed = line.trim();
|
|
40
|
+
if (!trimmed) continue;
|
|
41
|
+
const parts = trimmed.split(" ");
|
|
42
|
+
const sourceId = parts[0];
|
|
43
|
+
const targetId = parts[1];
|
|
44
|
+
const label = parts.slice(2).join(" ");
|
|
45
|
+
edges.push({
|
|
46
|
+
type: "edge",
|
|
47
|
+
id: `e${edges.length}`,
|
|
48
|
+
sourceId,
|
|
49
|
+
targetId,
|
|
50
|
+
label,
|
|
51
|
+
data: void 0
|
|
52
|
+
});
|
|
53
|
+
}
|
|
54
|
+
return {
|
|
55
|
+
id: "",
|
|
56
|
+
type: "directed",
|
|
57
|
+
initialNodeId: null,
|
|
58
|
+
nodes,
|
|
59
|
+
edges,
|
|
60
|
+
data: void 0
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
/** Bidirectional converter for TGF (Trivial Graph Format). */
|
|
64
|
+
const tgfConverter = createFormatConverter(toTGF, fromTGF);
|
|
65
|
+
|
|
66
|
+
//#endregion
|
|
67
|
+
export { fromTGF, tgfConverter, toTGF };
|
package/dist/index.d.mts
CHANGED
|
@@ -1,17 +1,22 @@
|
|
|
1
|
-
import { C as
|
|
2
|
-
import { bfs, dfs, genCycles, genPostorders, genPreorders, genShortestPaths, genSimplePaths, getAllPairsShortestPaths, getConnectedComponents, getCycles, getMinimumSpanningTree, getPostorder, getPostorders, getPreorder, getPreorders, getShortestPath, getShortestPaths, getSimplePath, getSimplePaths, getStronglyConnectedComponents, getTopologicalSort, hasPath, isAcyclic, isConnected, isTree } from "./algorithms.mjs";
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import { n as toEdgeList, t as fromEdgeList } from "./edge-list-CJmfoNu2.mjs";
|
|
6
|
-
import { n as toGraphML, t as fromGraphML } from "./graphml-CMjPzSfY.mjs";
|
|
7
|
-
import { EdgeSchema, GraphSchema, NodeSchema } from "./schemas.mjs";
|
|
8
|
-
import { getAncestors, getChildren, getDegree, getDepth, getDescendants, getEdgeBetween, getEdgesOf, getInDegree, getInEdges, getLCA, getNeighbors, getOutDegree, getOutEdges, getParent, getPredecessors, getRoots, getSiblings, getSinks, getSources, getSuccessors, isCompound, isLeaf } from "./queries.mjs";
|
|
1
|
+
import { C as TraversalOptions, D as VisualNode, E as VisualGraphConfig, S as TransitionOptions, T as VisualGraph, _ as MSTOptions, a as EntitiesConfig, b as PathOptions, c as Graph, d as GraphEdge, f as GraphFormatConverter, g as GraphStep, h as GraphPath, i as EdgeConfig, l as GraphConfig, m as GraphPatch, n as DeleteNodeOptions, o as EntitiesUpdate, p as GraphNode, r as EdgeChange, s as EntityRect, t as AllPairsShortestPathsOptions, u as GraphDiff, v as NodeChange, w as VisualEdge, x as SinglePathOptions, y as NodeConfig } from "./types-B6Tpeerk.mjs";
|
|
2
|
+
import { bfs, dfs, genCycles, genPostorders, genPreorders, genShortestPaths, genSimplePaths, getAllPairsShortestPaths, getConnectedComponents, getCycles, getMinimumSpanningTree, getPostorder, getPostorders, getPreorder, getPreorders, getShortestPath, getShortestPaths, getSimplePath, getSimplePaths, getStronglyConnectedComponents, getTopologicalSort, hasPath, isAcyclic, isConnected, isTree, joinPaths } from "./algorithms.mjs";
|
|
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";
|
|
9
5
|
|
|
10
6
|
//#region src/graph.d.ts
|
|
11
7
|
/** Create a graph from a config. Resolves defaults for all fields. */
|
|
12
8
|
declare function createGraph<N = any, E = any, G = any>(config?: GraphConfig<N, E, G>): Graph<N, E, G>;
|
|
13
9
|
/** Create a visual graph with required position/size on all nodes and edges. */
|
|
14
10
|
declare function createVisualGraph<N = any, E = any, G = any>(config?: VisualGraphConfig<N, E, G>): VisualGraph<N, E, G>;
|
|
11
|
+
/**
|
|
12
|
+
* Create a graph by BFS exploration of a transition function.
|
|
13
|
+
* Each unique state becomes a node; each (state, event) → nextState becomes an edge.
|
|
14
|
+
*
|
|
15
|
+
* - Node IDs are determined by `serializeState` (default: `JSON.stringify`).
|
|
16
|
+
* - Edge IDs use the format `sourceId|serializedEvent|targetId` for uniqueness
|
|
17
|
+
* and debuggability. Edge labels are just the serialized event string.
|
|
18
|
+
*/
|
|
19
|
+
declare function createGraphFromTransition<TState, TEvent>(transition: (state: TState, event: TEvent) => TState, options: TransitionOptions<TState, TEvent>): Graph<TState, TEvent>;
|
|
15
20
|
/** Get a node by id, or `undefined` if not found. */
|
|
16
21
|
declare function getNode<N>(graph: Graph<N>, id: string): GraphNode<N> | undefined;
|
|
17
22
|
/** Get an edge by id, or `undefined` if not found. */
|
|
@@ -139,4 +144,4 @@ declare function toDiff<N, E>(patches: GraphPatch<N, E>[]): GraphDiff<N, E>;
|
|
|
139
144
|
*/
|
|
140
145
|
declare function flatten<N, E, G>(graph: Graph<N, E, G>): Graph<N, E, G>;
|
|
141
146
|
//#endregion
|
|
142
|
-
export { type AllPairsShortestPathsOptions, type DeleteNodeOptions, type EdgeChange, type EdgeConfig,
|
|
147
|
+
export { type AllPairsShortestPathsOptions, 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, addEdge, addEntities, addNode, applyPatches, bfs, createFormatConverter, createGraph, createGraphFromTransition, createVisualGraph, deleteEdge, deleteEntities, deleteNode, dfs, flatten, genCycles, genPostorders, genPreorders, genShortestPaths, genSimplePaths, getAllPairsShortestPaths, getAncestors, getChildren, getConnectedComponents, 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, getSuccessors, getTopologicalSort, hasEdge, hasNode, hasPath, invalidateIndex, invertDiff, isAcyclic, isCompound, isConnected, isEmptyDiff, isLeaf, isTree, joinPaths, toDiff, toPatches, updateEdge, updateEntities, updateNode };
|
package/dist/index.mjs
CHANGED
|
@@ -1,11 +1,7 @@
|
|
|
1
|
-
import { o as invalidateIndex, t as getIndex } from "./indexing-
|
|
2
|
-
import { A as
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import { n as toGraphML, t as fromGraphML } from "./graphml-CUTNRXqd.mjs";
|
|
6
|
-
import { t as toDOT } from "./dot-BRtq3e3c.mjs";
|
|
7
|
-
import { n as toAdjacencyList, t as fromAdjacencyList } from "./adjacency-list-CXpOCibq.mjs";
|
|
8
|
-
import { n as toEdgeList, t as fromEdgeList } from "./edge-list-BRujEnnU.mjs";
|
|
1
|
+
import { o as invalidateIndex, t as getIndex } from "./indexing-BFFVMnjF.mjs";
|
|
2
|
+
import { A as addNode, B as hasNode, C as isAcyclic, D as GraphInstance, E as joinPaths, F as deleteEntities, H as updateEntities, I as deleteNode, L as getEdge, M as createGraphFromTransition, N as createVisualGraph, O as addEdge, P as deleteEdge, R as getNode, S as hasPath, T as isTree, U as updateNode, V as updateEdge, _ as getShortestPaths, a as genPreorders, b as getStronglyConnectedComponents, c as getAllPairsShortestPaths, d as getMinimumSpanningTree, f as getPostorder, g as getShortestPath, h as getPreorders, i as genPostorders, j as createGraph, k as addEntities, l as getConnectedComponents, m as getPreorder, n as dfs, o as genShortestPaths, p as getPostorders, r as genCycles, s as genSimplePaths, t as bfs, u as getCycles, v as getSimplePath, w as isConnected, x as getTopologicalSort, y as getSimplePaths, z as hasEdge } from "./algorithms-DBU7nmIV.mjs";
|
|
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";
|
|
4
|
+
import { n as createFormatConverter } from "./converter-DnbeyE_p.mjs";
|
|
9
5
|
|
|
10
6
|
//#region src/diff.ts
|
|
11
7
|
function nodeToConfig(node) {
|
|
@@ -353,4 +349,4 @@ function flatten(graph) {
|
|
|
353
349
|
}
|
|
354
350
|
|
|
355
351
|
//#endregion
|
|
356
|
-
export {
|
|
352
|
+
export { GraphInstance, addEdge, addEntities, addNode, applyPatches, bfs, createFormatConverter, createGraph, createGraphFromTransition, createVisualGraph, deleteEdge, deleteEntities, deleteNode, dfs, flatten, genCycles, genPostorders, genPreorders, genShortestPaths, genSimplePaths, getAllPairsShortestPaths, getAncestors, getChildren, getConnectedComponents, 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, getSuccessors, getTopologicalSort, hasEdge, hasNode, hasPath, invalidateIndex, invertDiff, isAcyclic, isCompound, isConnected, isEmptyDiff, isLeaf, isTree, joinPaths, toDiff, toPatches, updateEdge, updateEntities, updateNode };
|
package/dist/queries.d.mts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { c as Graph, d as GraphEdge,
|
|
1
|
+
import { c as Graph, d as GraphEdge, p as GraphNode } from "./types-B6Tpeerk.mjs";
|
|
2
2
|
|
|
3
3
|
//#region src/queries.d.ts
|
|
4
4
|
declare function getEdgesOf<E>(graph: Graph<any, E>, nodeId: string): GraphEdge<E>[];
|
|
@@ -29,9 +29,85 @@ declare function getSiblings<N>(graph: Graph<N>, nodeId: string): GraphNode<N>[]
|
|
|
29
29
|
* A proper ancestor excludes the input nodes themselves.
|
|
30
30
|
*/
|
|
31
31
|
declare function getLCA<N>(graph: Graph<N>, ...nodeIds: string[]): GraphNode<N> | undefined;
|
|
32
|
+
/**
|
|
33
|
+
* Returns a map of nodeId → shortest-path distance for all sibling nodes
|
|
34
|
+
* (same parentId). Distance is measured from the parent's `initialNodeId`
|
|
35
|
+
* (or `graph.initialNodeId` for root-level nodes).
|
|
36
|
+
*
|
|
37
|
+
* Only follows edges between siblings. Unreachable siblings are omitted.
|
|
38
|
+
*
|
|
39
|
+
* @example Root-level nodes (uses `graph.initialNodeId`):
|
|
40
|
+
* ```ts
|
|
41
|
+
* const graph = createGraph({
|
|
42
|
+
* initialNodeId: 'a',
|
|
43
|
+
* nodes: [{ id: 'a' }, { id: 'b' }, { id: 'c' }],
|
|
44
|
+
* edges: [
|
|
45
|
+
* { id: 'e1', sourceId: 'a', targetId: 'b' },
|
|
46
|
+
* { id: 'e2', sourceId: 'b', targetId: 'c' },
|
|
47
|
+
* ],
|
|
48
|
+
* });
|
|
49
|
+
* getRelativeDistanceMap(graph, null);
|
|
50
|
+
* // => { a: 0, b: 1, c: 2 }
|
|
51
|
+
* ```
|
|
52
|
+
*
|
|
53
|
+
* @example Nested nodes (uses parent's `initialNodeId`):
|
|
54
|
+
* ```ts
|
|
55
|
+
* const graph = createGraph({
|
|
56
|
+
* nodes: [
|
|
57
|
+
* { id: 'parent', initialNodeId: 's1' },
|
|
58
|
+
* { id: 's1', parentId: 'parent' },
|
|
59
|
+
* { id: 's2', parentId: 'parent' },
|
|
60
|
+
* { id: 's3', parentId: 'parent' },
|
|
61
|
+
* ],
|
|
62
|
+
* edges: [
|
|
63
|
+
* { id: 'e1', sourceId: 's1', targetId: 's2' },
|
|
64
|
+
* { id: 'e2', sourceId: 's2', targetId: 's3' },
|
|
65
|
+
* ],
|
|
66
|
+
* });
|
|
67
|
+
* getRelativeDistanceMap(graph, 'parent');
|
|
68
|
+
* // => { s1: 0, s2: 1, s3: 2 }
|
|
69
|
+
* ```
|
|
70
|
+
*/
|
|
71
|
+
declare function getRelativeDistanceMap(graph: Graph, parentId: string | null): Record<string, number>;
|
|
72
|
+
/**
|
|
73
|
+
* Returns the shortest-path distance of a node from its parent's initial node.
|
|
74
|
+
* Automatically scopes to the node's sibling group (same `parentId`).
|
|
75
|
+
*
|
|
76
|
+
* Returns `undefined` if the node is not found or unreachable.
|
|
77
|
+
*
|
|
78
|
+
* @example
|
|
79
|
+
* ```ts
|
|
80
|
+
* const graph = createGraph({
|
|
81
|
+
* initialNodeId: 'a',
|
|
82
|
+
* nodes: [{ id: 'a' }, { id: 'b' }, { id: 'c' }],
|
|
83
|
+
* edges: [
|
|
84
|
+
* { id: 'e1', sourceId: 'a', targetId: 'b' },
|
|
85
|
+
* { id: 'e2', sourceId: 'b', targetId: 'c' },
|
|
86
|
+
* ],
|
|
87
|
+
* });
|
|
88
|
+
* getRelativeDistance(graph, 'a'); // => 0
|
|
89
|
+
* getRelativeDistance(graph, 'b'); // => 1
|
|
90
|
+
* getRelativeDistance(graph, 'c'); // => 2
|
|
91
|
+
* ```
|
|
92
|
+
*
|
|
93
|
+
* @example Nested nodes:
|
|
94
|
+
* ```ts
|
|
95
|
+
* const graph = createGraph({
|
|
96
|
+
* nodes: [
|
|
97
|
+
* { id: 'parent', initialNodeId: 's1' },
|
|
98
|
+
* { id: 's1', parentId: 'parent' },
|
|
99
|
+
* { id: 's2', parentId: 'parent' },
|
|
100
|
+
* ],
|
|
101
|
+
* edges: [{ id: 'e1', sourceId: 's1', targetId: 's2' }],
|
|
102
|
+
* });
|
|
103
|
+
* getRelativeDistance(graph, 's1'); // => 0
|
|
104
|
+
* getRelativeDistance(graph, 's2'); // => 1
|
|
105
|
+
* ```
|
|
106
|
+
*/
|
|
107
|
+
declare function getRelativeDistance(graph: Graph, nodeId: string): number | undefined;
|
|
32
108
|
/** Nodes with no incoming edges (inDegree 0). */
|
|
33
109
|
declare function getSources<N>(graph: Graph<N>): GraphNode<N>[];
|
|
34
110
|
/** Nodes with no outgoing edges (outDegree 0). */
|
|
35
111
|
declare function getSinks<N>(graph: Graph<N>): GraphNode<N>[];
|
|
36
112
|
//#endregion
|
|
37
|
-
export { getAncestors, getChildren, getDegree, getDepth, getDescendants, getEdgeBetween, getEdgesOf, getInDegree, getInEdges, getLCA, getNeighbors, getOutDegree, getOutEdges, getParent, getPredecessors, getRoots, getSiblings, getSinks, getSources, getSuccessors, isCompound, isLeaf };
|
|
113
|
+
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 };
|
package/dist/queries.mjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { t as getIndex } from "./indexing-
|
|
1
|
+
import { t as getIndex } from "./indexing-BFFVMnjF.mjs";
|
|
2
2
|
|
|
3
3
|
//#region src/queries.ts
|
|
4
4
|
function getEdgesOf(graph, nodeId) {
|
|
@@ -206,6 +206,125 @@ function getLCA(graph, ...nodeIds) {
|
|
|
206
206
|
const ni = idx.nodeById.get(lcaId);
|
|
207
207
|
return ni !== void 0 ? graph.nodes[ni] : void 0;
|
|
208
208
|
}
|
|
209
|
+
/**
|
|
210
|
+
* Returns a map of nodeId → shortest-path distance for all sibling nodes
|
|
211
|
+
* (same parentId). Distance is measured from the parent's `initialNodeId`
|
|
212
|
+
* (or `graph.initialNodeId` for root-level nodes).
|
|
213
|
+
*
|
|
214
|
+
* Only follows edges between siblings. Unreachable siblings are omitted.
|
|
215
|
+
*
|
|
216
|
+
* @example Root-level nodes (uses `graph.initialNodeId`):
|
|
217
|
+
* ```ts
|
|
218
|
+
* const graph = createGraph({
|
|
219
|
+
* initialNodeId: 'a',
|
|
220
|
+
* nodes: [{ id: 'a' }, { id: 'b' }, { id: 'c' }],
|
|
221
|
+
* edges: [
|
|
222
|
+
* { id: 'e1', sourceId: 'a', targetId: 'b' },
|
|
223
|
+
* { id: 'e2', sourceId: 'b', targetId: 'c' },
|
|
224
|
+
* ],
|
|
225
|
+
* });
|
|
226
|
+
* getRelativeDistanceMap(graph, null);
|
|
227
|
+
* // => { a: 0, b: 1, c: 2 }
|
|
228
|
+
* ```
|
|
229
|
+
*
|
|
230
|
+
* @example Nested nodes (uses parent's `initialNodeId`):
|
|
231
|
+
* ```ts
|
|
232
|
+
* const graph = createGraph({
|
|
233
|
+
* nodes: [
|
|
234
|
+
* { id: 'parent', initialNodeId: 's1' },
|
|
235
|
+
* { id: 's1', parentId: 'parent' },
|
|
236
|
+
* { id: 's2', parentId: 'parent' },
|
|
237
|
+
* { id: 's3', parentId: 'parent' },
|
|
238
|
+
* ],
|
|
239
|
+
* edges: [
|
|
240
|
+
* { id: 'e1', sourceId: 's1', targetId: 's2' },
|
|
241
|
+
* { id: 'e2', sourceId: 's2', targetId: 's3' },
|
|
242
|
+
* ],
|
|
243
|
+
* });
|
|
244
|
+
* getRelativeDistanceMap(graph, 'parent');
|
|
245
|
+
* // => { s1: 0, s2: 1, s3: 2 }
|
|
246
|
+
* ```
|
|
247
|
+
*/
|
|
248
|
+
function getRelativeDistanceMap(graph, parentId) {
|
|
249
|
+
const idx = getIndex(graph);
|
|
250
|
+
let sourceId = null;
|
|
251
|
+
if (parentId !== null) {
|
|
252
|
+
const pi = idx.nodeById.get(parentId);
|
|
253
|
+
if (pi !== void 0) sourceId = graph.nodes[pi].initialNodeId;
|
|
254
|
+
} else sourceId = graph.initialNodeId;
|
|
255
|
+
if (!sourceId) return {};
|
|
256
|
+
const siblingSet = new Set(idx.childNodes.get(parentId) ?? []);
|
|
257
|
+
if (!siblingSet.has(sourceId)) return {};
|
|
258
|
+
const dist = /* @__PURE__ */ new Map();
|
|
259
|
+
dist.set(sourceId, 0);
|
|
260
|
+
const queue = [sourceId];
|
|
261
|
+
while (queue.length > 0) {
|
|
262
|
+
const id = queue.shift();
|
|
263
|
+
const d = dist.get(id);
|
|
264
|
+
for (const eid of idx.outEdges.get(id) ?? []) {
|
|
265
|
+
const ai = idx.edgeById.get(eid);
|
|
266
|
+
if (ai === void 0) continue;
|
|
267
|
+
const neighborId = graph.edges[ai].targetId;
|
|
268
|
+
if (siblingSet.has(neighborId) && !dist.has(neighborId)) {
|
|
269
|
+
dist.set(neighborId, d + 1);
|
|
270
|
+
queue.push(neighborId);
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
if (graph.type === "undirected") for (const eid of idx.inEdges.get(id) ?? []) {
|
|
274
|
+
const ai = idx.edgeById.get(eid);
|
|
275
|
+
if (ai === void 0) continue;
|
|
276
|
+
const neighborId = graph.edges[ai].sourceId;
|
|
277
|
+
if (siblingSet.has(neighborId) && !dist.has(neighborId)) {
|
|
278
|
+
dist.set(neighborId, d + 1);
|
|
279
|
+
queue.push(neighborId);
|
|
280
|
+
}
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
const result = {};
|
|
284
|
+
for (const [id, d] of dist) result[id] = d;
|
|
285
|
+
return result;
|
|
286
|
+
}
|
|
287
|
+
/**
|
|
288
|
+
* Returns the shortest-path distance of a node from its parent's initial node.
|
|
289
|
+
* Automatically scopes to the node's sibling group (same `parentId`).
|
|
290
|
+
*
|
|
291
|
+
* Returns `undefined` if the node is not found or unreachable.
|
|
292
|
+
*
|
|
293
|
+
* @example
|
|
294
|
+
* ```ts
|
|
295
|
+
* const graph = createGraph({
|
|
296
|
+
* initialNodeId: 'a',
|
|
297
|
+
* nodes: [{ id: 'a' }, { id: 'b' }, { id: 'c' }],
|
|
298
|
+
* edges: [
|
|
299
|
+
* { id: 'e1', sourceId: 'a', targetId: 'b' },
|
|
300
|
+
* { id: 'e2', sourceId: 'b', targetId: 'c' },
|
|
301
|
+
* ],
|
|
302
|
+
* });
|
|
303
|
+
* getRelativeDistance(graph, 'a'); // => 0
|
|
304
|
+
* getRelativeDistance(graph, 'b'); // => 1
|
|
305
|
+
* getRelativeDistance(graph, 'c'); // => 2
|
|
306
|
+
* ```
|
|
307
|
+
*
|
|
308
|
+
* @example Nested nodes:
|
|
309
|
+
* ```ts
|
|
310
|
+
* const graph = createGraph({
|
|
311
|
+
* nodes: [
|
|
312
|
+
* { id: 'parent', initialNodeId: 's1' },
|
|
313
|
+
* { id: 's1', parentId: 'parent' },
|
|
314
|
+
* { id: 's2', parentId: 'parent' },
|
|
315
|
+
* ],
|
|
316
|
+
* edges: [{ id: 'e1', sourceId: 's1', targetId: 's2' }],
|
|
317
|
+
* });
|
|
318
|
+
* getRelativeDistance(graph, 's1'); // => 0
|
|
319
|
+
* getRelativeDistance(graph, 's2'); // => 1
|
|
320
|
+
* ```
|
|
321
|
+
*/
|
|
322
|
+
function getRelativeDistance(graph, nodeId) {
|
|
323
|
+
const ni = getIndex(graph).nodeById.get(nodeId);
|
|
324
|
+
if (ni === void 0) return void 0;
|
|
325
|
+
const node = graph.nodes[ni];
|
|
326
|
+
return getRelativeDistanceMap(graph, node.parentId)[nodeId];
|
|
327
|
+
}
|
|
209
328
|
/** Nodes with no incoming edges (inDegree 0). */
|
|
210
329
|
function getSources(graph) {
|
|
211
330
|
const idx = getIndex(graph);
|
|
@@ -218,4 +337,4 @@ function getSinks(graph) {
|
|
|
218
337
|
}
|
|
219
338
|
|
|
220
339
|
//#endregion
|
|
221
|
-
export { getAncestors, getChildren, getDegree, getDepth, getDescendants, getEdgeBetween, getEdgesOf, getInDegree, getInEdges, getLCA, getNeighbors, getOutDegree, getOutEdges, getParent, getPredecessors, getRoots, getSiblings, getSinks, getSources, getSuccessors, isCompound, isLeaf };
|
|
340
|
+
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 };
|
|
@@ -215,5 +215,40 @@ type GraphPatch<TNodeData = any, TEdgeData = any> = {
|
|
|
215
215
|
id: string;
|
|
216
216
|
description?: string;
|
|
217
217
|
};
|
|
218
|
+
/**
|
|
219
|
+
* A bidirectional converter between `Graph` and a serialized format.
|
|
220
|
+
*
|
|
221
|
+
* Implement this interface to create a custom format converter.
|
|
222
|
+
*
|
|
223
|
+
* @example
|
|
224
|
+
* ```ts
|
|
225
|
+
* const myConverter: GraphFormatConverter<string> = {
|
|
226
|
+
* to(graph) { return JSON.stringify(graph); },
|
|
227
|
+
* from(input) { return JSON.parse(input); },
|
|
228
|
+
* };
|
|
229
|
+
* ```
|
|
230
|
+
*/
|
|
231
|
+
interface GraphFormatConverter<TSerial> {
|
|
232
|
+
/** Convert a Graph to the serialized format. */
|
|
233
|
+
to(graph: Graph): TSerial;
|
|
234
|
+
/** Convert from the serialized format to a Graph. */
|
|
235
|
+
from(input: TSerial): Graph;
|
|
236
|
+
}
|
|
237
|
+
interface TransitionOptions<TState, TEvent> {
|
|
238
|
+
/** Initial state to begin BFS exploration from. */
|
|
239
|
+
initialState: TState;
|
|
240
|
+
/** Events to try at each state. Array or function of state. */
|
|
241
|
+
events: TEvent[] | ((state: TState) => TEvent[]);
|
|
242
|
+
/** Serialize state to unique string for node dedup. Default: JSON.stringify */
|
|
243
|
+
serializeState?: (state: TState) => string;
|
|
244
|
+
/** Serialize event to string for edge labels/IDs. Default: JSON.stringify */
|
|
245
|
+
serializeEvent?: (event: TEvent) => string;
|
|
246
|
+
/** Max BFS iterations before throwing. Default: Infinity */
|
|
247
|
+
limit?: number;
|
|
248
|
+
/** When true, node is kept but outgoing transitions are not explored. */
|
|
249
|
+
stopWhen?: (state: TState) => boolean;
|
|
250
|
+
/** Optional graph ID. */
|
|
251
|
+
id?: string;
|
|
252
|
+
}
|
|
218
253
|
//#endregion
|
|
219
|
-
export {
|
|
254
|
+
export { TraversalOptions as C, VisualNode as D, VisualGraphConfig as E, TransitionOptions as S, VisualGraph as T, MSTOptions as _, EntitiesConfig as a, PathOptions as b, Graph as c, GraphEdge as d, GraphFormatConverter as f, GraphStep as g, GraphPath as h, EdgeConfig as i, GraphConfig as l, GraphPatch as m, DeleteNodeOptions as n, EntitiesUpdate as o, GraphNode as p, EdgeChange as r, EntityRect as s, AllPairsShortestPathsOptions as t, GraphDiff as u, NodeChange as v, VisualEdge as w, SinglePathOptions as x, NodeConfig as y };
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@statelyai/graph",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "0.
|
|
4
|
+
"version": "0.3.0",
|
|
5
5
|
"description": "A TypeScript-first graph library with plain JSON-serializable objects",
|
|
6
6
|
"author": "David Khourshid <david@stately.ai>",
|
|
7
7
|
"license": "MIT",
|
|
@@ -24,10 +24,18 @@
|
|
|
24
24
|
"exports": {
|
|
25
25
|
".": "./dist/index.mjs",
|
|
26
26
|
"./algorithms": "./dist/algorithms.mjs",
|
|
27
|
-
"./
|
|
28
|
-
"./
|
|
29
|
-
"./
|
|
30
|
-
"./
|
|
27
|
+
"./adjacency-list": "./dist/formats/adjacency-list/index.mjs",
|
|
28
|
+
"./converter": "./dist/formats/converter/index.mjs",
|
|
29
|
+
"./cytoscape": "./dist/formats/cytoscape/index.mjs",
|
|
30
|
+
"./d3": "./dist/formats/d3/index.mjs",
|
|
31
|
+
"./dot": "./dist/formats/dot/index.mjs",
|
|
32
|
+
"./edge-list": "./dist/formats/edge-list/index.mjs",
|
|
33
|
+
"./gexf": "./dist/formats/gexf/index.mjs",
|
|
34
|
+
"./gml": "./dist/formats/gml/index.mjs",
|
|
35
|
+
"./graphml": "./dist/formats/graphml/index.mjs",
|
|
36
|
+
"./jgf": "./dist/formats/jgf/index.mjs",
|
|
37
|
+
"./mermaid": "./dist/formats/mermaid/index.mjs",
|
|
38
|
+
"./tgf": "./dist/formats/tgf/index.mjs",
|
|
31
39
|
"./queries": "./dist/queries.mjs",
|
|
32
40
|
"./schemas": "./dist/schemas.mjs",
|
|
33
41
|
"./package.json": "./package.json"
|
|
@@ -39,39 +47,57 @@
|
|
|
39
47
|
"dist",
|
|
40
48
|
"schemas"
|
|
41
49
|
],
|
|
42
|
-
"scripts": {
|
|
43
|
-
"build": "tsdown",
|
|
44
|
-
"dev": "tsdown --watch",
|
|
45
|
-
"test": "vitest",
|
|
46
|
-
"typecheck": "tsc --noEmit",
|
|
47
|
-
"generate-schema": "tsx scripts/generate-json-schema.ts",
|
|
48
|
-
"changeset": "changeset",
|
|
49
|
-
"version": "changeset version",
|
|
50
|
-
"release": "pnpm run build && changeset publish",
|
|
51
|
-
"prepublishOnly": "pnpm run build"
|
|
52
|
-
},
|
|
53
50
|
"devDependencies": {
|
|
54
51
|
"@changesets/changelog-github": "^0.5.2",
|
|
55
52
|
"@changesets/cli": "^2.29.8",
|
|
53
|
+
"@types/d3-array": "^3.2.2",
|
|
54
|
+
"@types/d3-force": "^3.0.10",
|
|
56
55
|
"@types/node": "^25.0.3",
|
|
57
56
|
"bumpp": "^10.3.2",
|
|
57
|
+
"cytoscape": "^3.33.1",
|
|
58
|
+
"d3-array": "^3.2.4",
|
|
59
|
+
"d3-force": "^3.0.0",
|
|
60
|
+
"dotparser": "^1.1.1",
|
|
58
61
|
"fast-xml-parser": "^5.3.4",
|
|
59
62
|
"tsdown": "^0.18.1",
|
|
60
63
|
"tsx": "^4.21.0",
|
|
61
64
|
"typescript": "^5.9.3",
|
|
62
65
|
"vitest": "^4.0.16",
|
|
66
|
+
"xstate": "^5.28.0",
|
|
63
67
|
"zod": "^4.3.6"
|
|
64
68
|
},
|
|
65
69
|
"peerDependencies": {
|
|
70
|
+
"cytoscape": "^3.0.0",
|
|
71
|
+
"d3-force": "^3.0.0",
|
|
72
|
+
"dotparser": "^1.0.0",
|
|
66
73
|
"fast-xml-parser": "^5.0.0",
|
|
67
74
|
"zod": "^4.0.0"
|
|
68
75
|
},
|
|
69
76
|
"peerDependenciesMeta": {
|
|
77
|
+
"cytoscape": {
|
|
78
|
+
"optional": true
|
|
79
|
+
},
|
|
80
|
+
"d3-force": {
|
|
81
|
+
"optional": true
|
|
82
|
+
},
|
|
83
|
+
"dotparser": {
|
|
84
|
+
"optional": true
|
|
85
|
+
},
|
|
70
86
|
"fast-xml-parser": {
|
|
71
87
|
"optional": true
|
|
72
88
|
},
|
|
73
89
|
"zod": {
|
|
74
90
|
"optional": true
|
|
75
91
|
}
|
|
92
|
+
},
|
|
93
|
+
"scripts": {
|
|
94
|
+
"build": "tsdown",
|
|
95
|
+
"dev": "tsdown --watch",
|
|
96
|
+
"test": "vitest",
|
|
97
|
+
"typecheck": "tsc --noEmit",
|
|
98
|
+
"generate-schema": "tsx scripts/generate-json-schema.ts",
|
|
99
|
+
"changeset": "changeset",
|
|
100
|
+
"version": "changeset version",
|
|
101
|
+
"release": "pnpm run build && changeset publish"
|
|
76
102
|
}
|
|
77
|
-
}
|
|
103
|
+
}
|
package/dist/dot-BRtq3e3c.mjs
DELETED
|
@@ -1,59 +0,0 @@
|
|
|
1
|
-
//#region src/formats/dot.ts
|
|
2
|
-
/** Escape a DOT identifier */
|
|
3
|
-
function escapeId(id) {
|
|
4
|
-
if (/^[a-zA-Z_][a-zA-Z0-9_]*$/.test(id)) return id;
|
|
5
|
-
return `"${id.replace(/\\/g, "\\\\").replace(/"/g, "\\\"")}"`;
|
|
6
|
-
}
|
|
7
|
-
/** Escape a DOT label string */
|
|
8
|
-
function escapeLabel(label) {
|
|
9
|
-
return label.replace(/\\/g, "\\\\").replace(/"/g, "\\\"");
|
|
10
|
-
}
|
|
11
|
-
const DIRECTION_TO_RANKDIR = {
|
|
12
|
-
down: "TB",
|
|
13
|
-
up: "BT",
|
|
14
|
-
right: "LR",
|
|
15
|
-
left: "RL"
|
|
16
|
-
};
|
|
17
|
-
const SHAPE_TO_DOT = {
|
|
18
|
-
rectangle: "box",
|
|
19
|
-
ellipse: "ellipse",
|
|
20
|
-
circle: "circle",
|
|
21
|
-
diamond: "diamond",
|
|
22
|
-
hexagon: "hexagon",
|
|
23
|
-
cylinder: "cylinder",
|
|
24
|
-
parallelogram: "parallelogram"
|
|
25
|
-
};
|
|
26
|
-
function toDOT(graph) {
|
|
27
|
-
const isDirected = graph.type === "directed";
|
|
28
|
-
const keyword = isDirected ? "digraph" : "graph";
|
|
29
|
-
const edgeOp = isDirected ? "->" : "--";
|
|
30
|
-
const lines = [];
|
|
31
|
-
lines.push(`${keyword} ${escapeId(graph.id)} {`);
|
|
32
|
-
if (graph.direction) {
|
|
33
|
-
const rankdir = DIRECTION_TO_RANKDIR[graph.direction] ?? "TB";
|
|
34
|
-
lines.push(` rankdir=${rankdir};`);
|
|
35
|
-
}
|
|
36
|
-
for (const node of graph.nodes) {
|
|
37
|
-
const attrs = [];
|
|
38
|
-
if (node.label) attrs.push(`label="${escapeLabel(node.label)}"`);
|
|
39
|
-
if (node.shape) {
|
|
40
|
-
const dotShape = SHAPE_TO_DOT[node.shape] ?? node.shape;
|
|
41
|
-
attrs.push(`shape=${dotShape}`);
|
|
42
|
-
}
|
|
43
|
-
if (node.color) attrs.push(`fillcolor="${escapeLabel(node.color)}" style=filled`);
|
|
44
|
-
if (attrs.length > 0) lines.push(` ${escapeId(node.id)} [${attrs.join(", ")}];`);
|
|
45
|
-
else lines.push(` ${escapeId(node.id)};`);
|
|
46
|
-
}
|
|
47
|
-
for (const edge of graph.edges) {
|
|
48
|
-
const attrs = [];
|
|
49
|
-
if (edge.label) attrs.push(`label="${escapeLabel(edge.label)}"`);
|
|
50
|
-
if (edge.color) attrs.push(`color="${escapeLabel(edge.color)}"`);
|
|
51
|
-
const attrStr = attrs.length > 0 ? ` [${attrs.join(", ")}]` : "";
|
|
52
|
-
lines.push(` ${escapeId(edge.sourceId)} ${edgeOp} ${escapeId(edge.targetId)}${attrStr};`);
|
|
53
|
-
}
|
|
54
|
-
lines.push("}");
|
|
55
|
-
return lines.join("\n");
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
//#endregion
|
|
59
|
-
export { toDOT as t };
|
package/dist/dot-HmJeUMsj.d.mts
DELETED
package/dist/formats/dot.d.mts
DELETED
package/dist/formats/dot.mjs
DELETED
package/dist/formats/graphml.mjs
DELETED
|
File without changes
|