@statelyai/graph 0.13.0 → 2.0.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 +57 -26
- package/dist/{adjacency-list-Ca0VjKIf.mjs → adjacency-list-GeL1Cu-L.mjs} +5 -3
- package/dist/{algorithms-BlM-qoJb.d.mts → algorithms-CsGNehct.d.mts} +137 -2
- package/dist/{algorithms-BNDQcHU3.mjs → algorithms-DF1pSQGv.mjs} +1494 -357
- package/dist/algorithms.d.mts +2 -2
- package/dist/algorithms.mjs +2 -2
- package/dist/{converter-Dspillnn.mjs → converter-DyCJJfTe.mjs} +2 -2
- package/dist/{edge-list-gKe8-iRa.mjs → edge-list-BcZ0h6zz.mjs} +1 -1
- package/dist/format-support.mjs +67 -11
- package/dist/formats/adjacency-list/index.d.mts +1 -1
- package/dist/formats/adjacency-list/index.mjs +1 -1
- package/dist/formats/converter/index.d.mts +1 -60
- package/dist/formats/converter/index.mjs +1 -1
- package/dist/formats/cytoscape/index.d.mts +1 -1
- package/dist/formats/cytoscape/index.mjs +5 -3
- package/dist/formats/d2/index.d.mts +109 -0
- package/dist/formats/d2/index.mjs +1100 -0
- package/dist/formats/d3/index.d.mts +2 -2
- package/dist/formats/d3/index.mjs +5 -3
- package/dist/formats/dot/index.d.mts +1 -1
- package/dist/formats/dot/index.mjs +24 -8
- package/dist/formats/edge-list/index.d.mts +1 -1
- package/dist/formats/edge-list/index.mjs +1 -1
- package/dist/formats/elk/index.d.mts +1 -1
- package/dist/formats/elk/index.mjs +23 -16
- package/dist/formats/gexf/index.d.mts +1 -1
- package/dist/formats/gexf/index.mjs +30 -17
- package/dist/formats/gml/index.d.mts +1 -1
- package/dist/formats/gml/index.mjs +22 -13
- package/dist/formats/graphml/index.d.mts +1 -1
- package/dist/formats/graphml/index.mjs +83 -25
- package/dist/formats/jgf/index.d.mts +1 -1
- package/dist/formats/jgf/index.mjs +6 -3
- package/dist/formats/mermaid/index.d.mts +1 -1
- package/dist/formats/mermaid/index.mjs +57 -20
- package/dist/formats/tgf/index.d.mts +1 -1
- package/dist/formats/tgf/index.mjs +2 -2
- package/dist/formats/xyflow/index.d.mts +1 -1
- package/dist/formats/xyflow/index.mjs +33 -6
- package/dist/index-D51lJnt2.d.mts +61 -0
- package/dist/index-DWmo1mIp.d.mts +697 -0
- package/dist/index.d.mts +6 -631
- package/dist/index.mjs +144 -295
- package/dist/mode-D8OnHFBk.mjs +15 -0
- package/dist/queries-BfXeTXRf.d.mts +547 -0
- package/dist/queries-KirMDR7e.mjs +980 -0
- package/dist/queries.d.mts +1 -514
- package/dist/queries.mjs +1 -766
- package/dist/schemas.d.mts +21 -10
- package/dist/schemas.mjs +35 -86
- package/dist/{types-CnZ01raw.d.mts → types-DNYdIU21.d.mts} +83 -11
- package/dist/validate-TtH-x3JV.mjs +190 -0
- package/package.json +14 -3
- package/schemas/edge.schema.json +11 -0
- package/schemas/graph.schema.json +24 -3
- package/schemas/node.schema.json +6 -0
- package/dist/indexing-DUl3kTqm.mjs +0 -137
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@statelyai/graph",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "0.
|
|
4
|
+
"version": "2.0.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",
|
|
@@ -28,6 +28,7 @@
|
|
|
28
28
|
"./adjacency-list": "./dist/formats/adjacency-list/index.mjs",
|
|
29
29
|
"./converter": "./dist/formats/converter/index.mjs",
|
|
30
30
|
"./cytoscape": "./dist/formats/cytoscape/index.mjs",
|
|
31
|
+
"./d2": "./dist/formats/d2/index.mjs",
|
|
31
32
|
"./d3": "./dist/formats/d3/index.mjs",
|
|
32
33
|
"./dot": "./dist/formats/dot/index.mjs",
|
|
33
34
|
"./edge-list": "./dist/formats/edge-list/index.mjs",
|
|
@@ -51,12 +52,13 @@
|
|
|
51
52
|
"schemas"
|
|
52
53
|
],
|
|
53
54
|
"devDependencies": {
|
|
54
|
-
"publint": "^0.3.15",
|
|
55
55
|
"@changesets/changelog-github": "^0.5.2",
|
|
56
56
|
"@changesets/cli": "^2.29.8",
|
|
57
|
+
"@dagrejs/graphlib": "^4.0.1",
|
|
57
58
|
"@types/d3-array": "^3.2.2",
|
|
58
59
|
"@types/d3-force": "^3.0.10",
|
|
59
60
|
"@types/node": "^25.0.3",
|
|
61
|
+
"@vitest/coverage-v8": "^4.0.18",
|
|
60
62
|
"@xyflow/system": "^0.0.75",
|
|
61
63
|
"bumpp": "^10.3.2",
|
|
62
64
|
"cytoscape": "^3.33.1",
|
|
@@ -65,6 +67,14 @@
|
|
|
65
67
|
"dotparser": "^1.1.1",
|
|
66
68
|
"elkjs": "^0.11.1",
|
|
67
69
|
"fast-xml-parser": "^5.3.4",
|
|
70
|
+
"graphology": "^0.26.0",
|
|
71
|
+
"graphology-components": "^1.5.4",
|
|
72
|
+
"graphology-metrics": "^2.4.0",
|
|
73
|
+
"graphology-shortest-path": "^2.1.0",
|
|
74
|
+
"graphology-types": "^0.24.8",
|
|
75
|
+
"ngraph.graph": "^20.1.2",
|
|
76
|
+
"ngraph.path": "^1.6.1",
|
|
77
|
+
"publint": "^0.3.15",
|
|
68
78
|
"tsdown": "^0.18.1",
|
|
69
79
|
"tsx": "^4.21.0",
|
|
70
80
|
"typescript": "^5.9.3",
|
|
@@ -113,6 +123,7 @@
|
|
|
113
123
|
"generate-schema": "tsx scripts/generate-json-schema.ts",
|
|
114
124
|
"changeset": "changeset",
|
|
115
125
|
"version": "changeset version",
|
|
116
|
-
"release": "pnpm run build && changeset publish"
|
|
126
|
+
"release": "pnpm run build && changeset publish",
|
|
127
|
+
"bench:compare": "tsx bench/compare/run.ts"
|
|
117
128
|
}
|
|
118
129
|
}
|
package/schemas/edge.schema.json
CHANGED
|
@@ -34,6 +34,14 @@
|
|
|
34
34
|
"targetPort": {
|
|
35
35
|
"type": "string"
|
|
36
36
|
},
|
|
37
|
+
"mode": {
|
|
38
|
+
"type": "string",
|
|
39
|
+
"enum": [
|
|
40
|
+
"directed",
|
|
41
|
+
"undirected",
|
|
42
|
+
"bidirectional"
|
|
43
|
+
]
|
|
44
|
+
},
|
|
37
45
|
"data": {},
|
|
38
46
|
"x": {
|
|
39
47
|
"type": "number"
|
|
@@ -62,6 +70,9 @@
|
|
|
62
70
|
},
|
|
63
71
|
{
|
|
64
72
|
"type": "number"
|
|
73
|
+
},
|
|
74
|
+
{
|
|
75
|
+
"type": "boolean"
|
|
65
76
|
}
|
|
66
77
|
]
|
|
67
78
|
}
|
|
@@ -5,11 +5,12 @@
|
|
|
5
5
|
"id": {
|
|
6
6
|
"type": "string"
|
|
7
7
|
},
|
|
8
|
-
"
|
|
8
|
+
"mode": {
|
|
9
9
|
"type": "string",
|
|
10
10
|
"enum": [
|
|
11
11
|
"directed",
|
|
12
|
-
"undirected"
|
|
12
|
+
"undirected",
|
|
13
|
+
"bidirectional"
|
|
13
14
|
]
|
|
14
15
|
},
|
|
15
16
|
"initialNodeId": {
|
|
@@ -95,6 +96,9 @@
|
|
|
95
96
|
},
|
|
96
97
|
{
|
|
97
98
|
"type": "number"
|
|
99
|
+
},
|
|
100
|
+
{
|
|
101
|
+
"type": "boolean"
|
|
98
102
|
}
|
|
99
103
|
]
|
|
100
104
|
}
|
|
@@ -143,6 +147,9 @@
|
|
|
143
147
|
},
|
|
144
148
|
{
|
|
145
149
|
"type": "number"
|
|
150
|
+
},
|
|
151
|
+
{
|
|
152
|
+
"type": "boolean"
|
|
146
153
|
}
|
|
147
154
|
]
|
|
148
155
|
}
|
|
@@ -202,6 +209,14 @@
|
|
|
202
209
|
"targetPort": {
|
|
203
210
|
"type": "string"
|
|
204
211
|
},
|
|
212
|
+
"mode": {
|
|
213
|
+
"type": "string",
|
|
214
|
+
"enum": [
|
|
215
|
+
"directed",
|
|
216
|
+
"undirected",
|
|
217
|
+
"bidirectional"
|
|
218
|
+
]
|
|
219
|
+
},
|
|
205
220
|
"data": {},
|
|
206
221
|
"x": {
|
|
207
222
|
"type": "number"
|
|
@@ -230,6 +245,9 @@
|
|
|
230
245
|
},
|
|
231
246
|
{
|
|
232
247
|
"type": "number"
|
|
248
|
+
},
|
|
249
|
+
{
|
|
250
|
+
"type": "boolean"
|
|
233
251
|
}
|
|
234
252
|
]
|
|
235
253
|
}
|
|
@@ -267,6 +285,9 @@
|
|
|
267
285
|
},
|
|
268
286
|
{
|
|
269
287
|
"type": "number"
|
|
288
|
+
},
|
|
289
|
+
{
|
|
290
|
+
"type": "boolean"
|
|
270
291
|
}
|
|
271
292
|
]
|
|
272
293
|
}
|
|
@@ -274,7 +295,7 @@
|
|
|
274
295
|
},
|
|
275
296
|
"required": [
|
|
276
297
|
"id",
|
|
277
|
-
"
|
|
298
|
+
"mode",
|
|
278
299
|
"nodes",
|
|
279
300
|
"edges",
|
|
280
301
|
"data"
|
package/schemas/node.schema.json
CHANGED
|
@@ -1,137 +0,0 @@
|
|
|
1
|
-
//#region src/indexing.ts
|
|
2
|
-
const indexes = /* @__PURE__ */ new WeakMap();
|
|
3
|
-
/**
|
|
4
|
-
* Get or lazily build the index for a graph.
|
|
5
|
-
* Auto-rebuilds when node/edge count changes.
|
|
6
|
-
*
|
|
7
|
-
* @example
|
|
8
|
-
* ```ts
|
|
9
|
-
* import { createGraph, getIndex } from '@statelyai/graph';
|
|
10
|
-
*
|
|
11
|
-
* const graph = createGraph({
|
|
12
|
-
* nodes: [{ id: 'a' }, { id: 'b' }],
|
|
13
|
-
* edges: [{ id: 'e1', sourceId: 'a', targetId: 'b' }],
|
|
14
|
-
* });
|
|
15
|
-
*
|
|
16
|
-
* const idx = getIndex(graph);
|
|
17
|
-
* idx.nodeById.get('a'); // 0
|
|
18
|
-
* idx.outEdges.get('a'); // ['e1']
|
|
19
|
-
* ```
|
|
20
|
-
*/
|
|
21
|
-
function getIndex(graph) {
|
|
22
|
-
let idx = indexes.get(graph);
|
|
23
|
-
const sameStructure = idx && idx.nodeCount === graph.nodes.length && idx.edgeCount === graph.edges.length;
|
|
24
|
-
const signature = idx !== void 0 && sameStructure && idx.nodesRef === graph.nodes && idx.edgesRef === graph.edges ? getIndexSignature(graph) : void 0;
|
|
25
|
-
if (!idx || idx.nodeCount !== graph.nodes.length || idx.edgeCount !== graph.edges.length || signature !== void 0 && idx.signature !== signature) {
|
|
26
|
-
idx = buildIndex(graph, signature ?? getIndexSignature(graph));
|
|
27
|
-
indexes.set(graph, idx);
|
|
28
|
-
}
|
|
29
|
-
return idx;
|
|
30
|
-
}
|
|
31
|
-
/**
|
|
32
|
-
* Clear the cached index. Call this if you mutate graph.nodes/edges directly.
|
|
33
|
-
*
|
|
34
|
-
* @example
|
|
35
|
-
* ```ts
|
|
36
|
-
* import { createGraph, invalidateIndex, getIndex } from '@statelyai/graph';
|
|
37
|
-
*
|
|
38
|
-
* const graph = createGraph({ nodes: [{ id: 'a' }], edges: [] });
|
|
39
|
-
* // manually mutate nodes array
|
|
40
|
-
* graph.nodes.push({ type: 'node', id: 'b', parentId: null, initialNodeId: null, label: '', data: undefined });
|
|
41
|
-
* invalidateIndex(graph); // forces rebuild on next getIndex()
|
|
42
|
-
* ```
|
|
43
|
-
*/
|
|
44
|
-
function invalidateIndex(graph) {
|
|
45
|
-
indexes.delete(graph);
|
|
46
|
-
}
|
|
47
|
-
function getIndexSignature(graph) {
|
|
48
|
-
const nodeParts = graph.nodes.map((node) => `${node.id}\u0000${node.parentId ?? ""}`);
|
|
49
|
-
const edgeParts = graph.edges.map((edge) => `${edge.id}\u0000${edge.sourceId}\u0000${edge.targetId}`);
|
|
50
|
-
return `${nodeParts.join("")}\u0002${edgeParts.join("")}`;
|
|
51
|
-
}
|
|
52
|
-
function buildIndex(graph, signature) {
|
|
53
|
-
const nodeById = /* @__PURE__ */ new Map();
|
|
54
|
-
const edgeById = /* @__PURE__ */ new Map();
|
|
55
|
-
const outEdges = /* @__PURE__ */ new Map();
|
|
56
|
-
const inEdges = /* @__PURE__ */ new Map();
|
|
57
|
-
const childNodes = /* @__PURE__ */ new Map();
|
|
58
|
-
for (let i = 0; i < graph.nodes.length; i++) {
|
|
59
|
-
const n = graph.nodes[i];
|
|
60
|
-
nodeById.set(n.id, i);
|
|
61
|
-
outEdges.set(n.id, []);
|
|
62
|
-
inEdges.set(n.id, []);
|
|
63
|
-
const parent = n.parentId ?? null;
|
|
64
|
-
if (!childNodes.has(parent)) childNodes.set(parent, []);
|
|
65
|
-
childNodes.get(parent).push(n.id);
|
|
66
|
-
}
|
|
67
|
-
for (let i = 0; i < graph.edges.length; i++) {
|
|
68
|
-
const e = graph.edges[i];
|
|
69
|
-
edgeById.set(e.id, i);
|
|
70
|
-
outEdges.get(e.sourceId)?.push(e.id);
|
|
71
|
-
inEdges.get(e.targetId)?.push(e.id);
|
|
72
|
-
}
|
|
73
|
-
return {
|
|
74
|
-
nodeById,
|
|
75
|
-
edgeById,
|
|
76
|
-
outEdges,
|
|
77
|
-
inEdges,
|
|
78
|
-
childNodes,
|
|
79
|
-
nodeCount: graph.nodes.length,
|
|
80
|
-
edgeCount: graph.edges.length,
|
|
81
|
-
signature,
|
|
82
|
-
nodesRef: graph.nodes,
|
|
83
|
-
edgesRef: graph.edges
|
|
84
|
-
};
|
|
85
|
-
}
|
|
86
|
-
function indexAddNode(idx, node, arrayIndex) {
|
|
87
|
-
idx.nodeById.set(node.id, arrayIndex);
|
|
88
|
-
idx.outEdges.set(node.id, []);
|
|
89
|
-
idx.inEdges.set(node.id, []);
|
|
90
|
-
const parent = node.parentId ?? null;
|
|
91
|
-
if (!idx.childNodes.has(parent)) idx.childNodes.set(parent, []);
|
|
92
|
-
idx.childNodes.get(parent).push(node.id);
|
|
93
|
-
idx.nodeCount++;
|
|
94
|
-
idx.signature = "";
|
|
95
|
-
}
|
|
96
|
-
function indexAddEdge(idx, edge, arrayIndex) {
|
|
97
|
-
idx.edgeById.set(edge.id, arrayIndex);
|
|
98
|
-
idx.outEdges.get(edge.sourceId)?.push(edge.id);
|
|
99
|
-
idx.inEdges.get(edge.targetId)?.push(edge.id);
|
|
100
|
-
idx.edgeCount++;
|
|
101
|
-
idx.signature = "";
|
|
102
|
-
}
|
|
103
|
-
/** Update childNodes index when a node's parentId changes. */
|
|
104
|
-
function indexReparentNode(idx, nodeId, oldParentId, newParentId) {
|
|
105
|
-
const oldSiblings = idx.childNodes.get(oldParentId ?? null);
|
|
106
|
-
if (oldSiblings) {
|
|
107
|
-
const pos = oldSiblings.indexOf(nodeId);
|
|
108
|
-
if (pos !== -1) oldSiblings.splice(pos, 1);
|
|
109
|
-
}
|
|
110
|
-
const np = newParentId ?? null;
|
|
111
|
-
if (!idx.childNodes.has(np)) idx.childNodes.set(np, []);
|
|
112
|
-
idx.childNodes.get(np).push(nodeId);
|
|
113
|
-
idx.signature = "";
|
|
114
|
-
}
|
|
115
|
-
/** Update adjacency lists when an edge's sourceId/targetId changes. */
|
|
116
|
-
function indexUpdateEdgeEndpoints(idx, edgeId, oldSourceId, oldTargetId, newSourceId, newTargetId) {
|
|
117
|
-
if (oldSourceId !== newSourceId) {
|
|
118
|
-
const oldOut = idx.outEdges.get(oldSourceId);
|
|
119
|
-
if (oldOut) {
|
|
120
|
-
const pos = oldOut.indexOf(edgeId);
|
|
121
|
-
if (pos !== -1) oldOut.splice(pos, 1);
|
|
122
|
-
}
|
|
123
|
-
idx.outEdges.get(newSourceId)?.push(edgeId);
|
|
124
|
-
}
|
|
125
|
-
if (oldTargetId !== newTargetId) {
|
|
126
|
-
const oldIn = idx.inEdges.get(oldTargetId);
|
|
127
|
-
if (oldIn) {
|
|
128
|
-
const pos = oldIn.indexOf(edgeId);
|
|
129
|
-
if (pos !== -1) oldIn.splice(pos, 1);
|
|
130
|
-
}
|
|
131
|
-
idx.inEdges.get(newTargetId)?.push(edgeId);
|
|
132
|
-
}
|
|
133
|
-
idx.signature = "";
|
|
134
|
-
}
|
|
135
|
-
|
|
136
|
-
//#endregion
|
|
137
|
-
export { indexUpdateEdgeEndpoints as a, indexReparentNode as i, indexAddEdge as n, invalidateIndex as o, indexAddNode as r, getIndex as t };
|