@statelyai/graph 1.0.0 → 2.1.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 +121 -44
- package/dist/{adjacency-list-VsUaH9SJ.mjs → adjacency-list-DQ32Mmhx.mjs} +3 -1
- package/dist/algorithms-D1cgly0g.d.mts +452 -0
- package/dist/algorithms-DBpH74hR.mjs +3309 -0
- package/dist/algorithms.d.mts +2 -2
- package/dist/algorithms.mjs +2 -2
- package/dist/config-Dt5u1gSf.mjs +793 -0
- package/dist/{converter-udLITX36.mjs → converter-DB6Rg6Vd.mjs} +2 -2
- package/dist/format-support.mjs +38 -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 -1
- package/dist/formats/converter/index.mjs +1 -1
- package/dist/formats/cytoscape/index.d.mts +4 -4
- package/dist/formats/cytoscape/index.mjs +10 -4
- package/dist/formats/d2/index.d.mts +1 -1
- package/dist/formats/d2/index.mjs +26 -12
- package/dist/formats/d3/index.d.mts +4 -4
- package/dist/formats/d3/index.mjs +10 -4
- package/dist/formats/dot/index.d.mts +1 -1
- package/dist/formats/dot/index.mjs +22 -6
- 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 +63 -24
- package/dist/formats/gexf/index.d.mts +1 -1
- package/dist/formats/gexf/index.mjs +43 -16
- package/dist/formats/gml/index.d.mts +4 -4
- package/dist/formats/gml/index.mjs +28 -15
- package/dist/formats/graphml/index.d.mts +1 -1
- package/dist/formats/graphml/index.mjs +96 -23
- package/dist/formats/jgf/index.d.mts +4 -4
- package/dist/formats/jgf/index.mjs +12 -5
- package/dist/formats/mermaid/index.d.mts +1 -1
- package/dist/formats/mermaid/index.mjs +49 -12
- package/dist/formats/tgf/index.d.mts +4 -4
- package/dist/formats/tgf/index.mjs +4 -4
- package/dist/formats/xyflow/index.d.mts +12 -6
- package/dist/formats/xyflow/index.mjs +42 -10
- package/dist/{index-D9Kj6Fe3.d.mts → index-BlbSWUvH.d.mts} +1 -1
- package/dist/{index-CHoriXZD.d.mts → index-CNvqxPLJ.d.mts} +157 -30
- package/dist/index.d.mts +6 -6
- package/dist/index.mjs +290 -307
- package/dist/layout/cytoscape.d.mts +66 -0
- package/dist/layout/cytoscape.mjs +114 -0
- package/dist/layout/d3-force.d.mts +52 -0
- package/dist/layout/d3-force.mjs +127 -0
- package/dist/layout/d3-hierarchy.d.mts +39 -0
- package/dist/layout/d3-hierarchy.mjs +135 -0
- package/dist/layout/dagre.d.mts +32 -0
- package/dist/layout/dagre.mjs +99 -0
- package/dist/layout/elk.d.mts +47 -0
- package/dist/layout/elk.mjs +73 -0
- package/dist/layout/forceatlas2.d.mts +48 -0
- package/dist/layout/forceatlas2.mjs +100 -0
- package/dist/layout/graphviz.d.mts +50 -0
- package/dist/layout/graphviz.mjs +179 -0
- package/dist/layout/index.d.mts +185 -0
- package/dist/layout/index.mjs +181 -0
- package/dist/layout/webcola.d.mts +40 -0
- package/dist/layout/webcola.mjs +104 -0
- package/dist/{queries-BlkA1HAN.d.mts → queries-B6quF529.d.mts} +43 -12
- package/dist/queries-BMM0XAv_.mjs +986 -0
- package/dist/queries.d.mts +1 -1
- package/dist/queries.mjs +1 -768
- package/dist/schemas.d.mts +19 -1
- package/dist/schemas.mjs +32 -84
- package/dist/{types-3-FS9NV2.d.mts → types-BAEQTwK_.d.mts} +99 -7
- package/dist/validate-BsfSOv0S.mjs +190 -0
- package/package.json +59 -7
- package/schemas/edge.schema.json +27 -0
- package/schemas/graph.schema.json +27 -0
- package/dist/algorithms-Ba7o7niK.mjs +0 -2394
- package/dist/algorithms-fTqmvhzP.d.mts +0 -178
- package/dist/indexing-DR8M1vBy.mjs +0 -137
- /package/dist/{edge-list-DP4otyPU.mjs → edge-list-CA9UTvn2.mjs} +0 -0
- /package/dist/{mode-D8OnHFBk.mjs → mode-gu_mhKKs.mjs} +0 -0
package/README.md
CHANGED
|
@@ -14,14 +14,19 @@ Optional peers are only needed for specific adapters:
|
|
|
14
14
|
|
|
15
15
|
<!-- optional peer dependencies derived from package.json#peerDependencies -->
|
|
16
16
|
|
|
17
|
-
| Package
|
|
18
|
-
|
|
|
19
|
-
| `fast-xml-parser`
|
|
20
|
-
| `dotparser`
|
|
21
|
-
| `
|
|
22
|
-
| `
|
|
23
|
-
| `
|
|
24
|
-
| `
|
|
17
|
+
| Package | Needed for |
|
|
18
|
+
| ------------------------------------------- | --------------------------------------------------- |
|
|
19
|
+
| `fast-xml-parser` | `@statelyai/graph/gexf`, `@statelyai/graph/graphml` |
|
|
20
|
+
| `dotparser` | `@statelyai/graph/dot` parsing |
|
|
21
|
+
| `zod` | `@statelyai/graph/schemas` |
|
|
22
|
+
| `elkjs` | `@statelyai/graph/elk`, `@statelyai/graph/layout/elk` |
|
|
23
|
+
| `@dagrejs/dagre` | `@statelyai/graph/layout/dagre` |
|
|
24
|
+
| `@hpcc-js/wasm-graphviz` | `@statelyai/graph/layout/graphviz` |
|
|
25
|
+
| `d3-force` | `@statelyai/graph/layout/d3-force` |
|
|
26
|
+
| `graphology`, `graphology-layout-forceatlas2` | `@statelyai/graph/layout/forceatlas2` |
|
|
27
|
+
| `d3-hierarchy` | `@statelyai/graph/layout/d3-hierarchy` |
|
|
28
|
+
| `webcola` | `@statelyai/graph/layout/webcola` |
|
|
29
|
+
| `cytoscape` | `@statelyai/graph/layout/cytoscape`, Cytoscape format typing |
|
|
25
30
|
|
|
26
31
|
## Highlights
|
|
27
32
|
|
|
@@ -29,7 +34,8 @@ Optional peers are only needed for specific adapters:
|
|
|
29
34
|
- Standalone functions with a consistent `get*`/`gen*`/`is*`/`add*` naming model
|
|
30
35
|
- Directed, undirected, hierarchical, and visual graph support
|
|
31
36
|
- Ports for node-editor and dataflow-style graphs
|
|
32
|
-
- Algorithms for traversal, paths, centrality, communities, connectivity, isomorphism, ordering, MST, and walks
|
|
37
|
+
- Algorithms for traversal, paths, centrality, communities, connectivity, flow/cuts, matching, cores, isomorphism, ordering, MST, and walks
|
|
38
|
+
- Pluggable layout over eight external engines (ELK, Graphviz, dagre, d3-force, ForceAtlas2, tidy tree, WebCola, cytoscape) — pure functions, optional peers
|
|
33
39
|
- Diff/patch utilities for graph state changes
|
|
34
40
|
- Multi-format conversion via package subpaths, with fidelity claims tested against fixtures
|
|
35
41
|
- Small, fast test suite with broad format coverage
|
|
@@ -86,12 +92,20 @@ const roots = getSources(graph); // nodes with no incoming edges
|
|
|
86
92
|
|
|
87
93
|
Batch operations (`addEntities`, `deleteEntities`, `updateEntities`) let you apply multiple changes at once.
|
|
88
94
|
|
|
95
|
+
`updateNode`/`updateEdge` accept any config field. Optional fields (position, size, `shape`, `color`, `style`, edge `weight`/`mode`/ports) can be **unset** by passing `null`; `undefined` leaves them unchanged:
|
|
96
|
+
|
|
97
|
+
```ts
|
|
98
|
+
updateNode(graph, 'a', { x: 100, color: 'red' }); // set
|
|
99
|
+
updateEdge(graph, 'e1', { weight: 2, mode: 'undirected' });
|
|
100
|
+
updateNode(graph, 'a', { color: null }); // unset
|
|
101
|
+
```
|
|
102
|
+
|
|
89
103
|
## Hierarchy
|
|
90
104
|
|
|
91
|
-
Nodes support parent-child relationships for compound/nested graphs. Query children, ancestors, descendants, depth, and least common ancestor. Use `
|
|
105
|
+
Nodes support parent-child relationships for compound/nested graphs. Query children, ancestors, descendants, depth, and least common ancestor. Use `getFlattenedGraph()` to decompose into a flat leaf-node graph.
|
|
92
106
|
|
|
93
107
|
```ts
|
|
94
|
-
import { createGraph, getChildren, getLCA,
|
|
108
|
+
import { createGraph, getChildren, getLCA, getFlattenedGraph } from '@statelyai/graph';
|
|
95
109
|
|
|
96
110
|
const graph = createGraph({
|
|
97
111
|
nodes: [
|
|
@@ -109,7 +123,7 @@ const graph = createGraph({
|
|
|
109
123
|
});
|
|
110
124
|
|
|
111
125
|
const children = getChildren(graph, 'b'); // [b1, b2]
|
|
112
|
-
const flat =
|
|
126
|
+
const flat = getFlattenedGraph(graph); // only leaf nodes, edges resolved
|
|
113
127
|
```
|
|
114
128
|
|
|
115
129
|
## Ports
|
|
@@ -149,7 +163,18 @@ getEdgesByPort(graph, 'render', 'input'); // [e1]
|
|
|
149
163
|
|
|
150
164
|
<!-- validation helpers exported from src/schemas.ts -->
|
|
151
165
|
|
|
152
|
-
|
|
166
|
+
For structural invariant checking without zod, the core export `getGraphIssues(graph)` returns machine-readable issues (duplicate ids, dangling edge endpoints, missing parents, parent cycles, missing initial nodes, duplicate or invalid port references) — the recommended gate for untrusted or imported graphs:
|
|
167
|
+
|
|
168
|
+
```ts
|
|
169
|
+
import { getGraphIssues } from '@statelyai/graph';
|
|
170
|
+
|
|
171
|
+
const issues = getGraphIssues(importedGraph);
|
|
172
|
+
if (issues.length > 0) {
|
|
173
|
+
console.error(issues.map((issue) => issue.message));
|
|
174
|
+
}
|
|
175
|
+
```
|
|
176
|
+
|
|
177
|
+
Use the `@statelyai/graph/schemas` subpath when you want full runtime shape validation or JSON Schema generation. `validateGraph()` combines zod shape checks with the same graph invariants.
|
|
153
178
|
|
|
154
179
|
```ts
|
|
155
180
|
import { GraphSchema, isGraph, validateGraph } from '@statelyai/graph/schemas';
|
|
@@ -169,12 +194,14 @@ const parsed = GraphSchema.parse(unknownValue);
|
|
|
169
194
|
|
|
170
195
|
<!-- algorithm functions exported from src/algorithms.ts -->
|
|
171
196
|
|
|
172
|
-
Includes traversal (BFS, DFS, preorder/postorder), pathfinding (shortest path, simple paths, all-pairs shortest paths, A
|
|
197
|
+
Includes traversal (BFS, DFS, preorder/postorder), pathfinding (shortest path, simple paths, all-pairs shortest paths, A*, bidirectional Dijkstra), centrality/link analysis (degree, closeness, betweenness, PageRank, HITS, eigenvector, Katz), community detection (Louvain, label propagation, Girvan-Newman, greedy modularity, modularity scoring), flow & cuts (`getMaxFlow`, `getMinCut`), bipartite analysis (`isBipartite`, Hopcroft–Karp `getMaximumBipartiteMatching`), k-cores (`getCoreNumbers`, `getKCore`), cycle detection, connected/strongly-connected components, bridges, articulation points, biconnected components, dominator trees, transitive reduction, isomorphism, topological sort, minimum spanning tree, and seeded graph generators (`createCompleteGraph`, `createGridGraph`, `createRandomGraph`). Many algorithms have lazy generator variants (`gen*`) for early exit. See [docs/algorithms.md](./docs/algorithms.md) for the full reference.
|
|
198
|
+
|
|
199
|
+
Hot algorithm loops (centrality, components) run on an internal compressed-sparse-row snapshot — cached and invalidated transparently like the rest of the index — so they stay fast on large graphs without changing the plain-JSON model. Algorithm results are differential-tested against graphology on seeded random graphs.
|
|
173
200
|
|
|
174
201
|
```ts
|
|
175
202
|
import {
|
|
176
|
-
|
|
177
|
-
|
|
203
|
+
genBFS,
|
|
204
|
+
genDFS,
|
|
178
205
|
hasPath,
|
|
179
206
|
isAcyclic,
|
|
180
207
|
getShortestPath,
|
|
@@ -183,16 +210,20 @@ import {
|
|
|
183
210
|
getConnectedComponents,
|
|
184
211
|
getMinimumSpanningTree,
|
|
185
212
|
getPageRank,
|
|
213
|
+
getLouvainCommunities,
|
|
186
214
|
getLabelPropagationCommunities,
|
|
187
215
|
genGirvanNewmanCommunities,
|
|
188
216
|
getBridges,
|
|
217
|
+
getMaxFlow,
|
|
218
|
+
getDominatorTree,
|
|
219
|
+
getTransitiveReduction,
|
|
189
220
|
isIsomorphic,
|
|
190
221
|
} from '@statelyai/graph';
|
|
191
222
|
|
|
192
|
-
for (const node of
|
|
223
|
+
for (const node of genBFS(graph, 'a')) {
|
|
193
224
|
/* breadth-first */
|
|
194
225
|
}
|
|
195
|
-
for (const node of
|
|
226
|
+
for (const node of genDFS(graph, 'a')) {
|
|
196
227
|
/* depth-first */
|
|
197
228
|
}
|
|
198
229
|
|
|
@@ -201,21 +232,56 @@ isAcyclic(graph); // cycle check
|
|
|
201
232
|
getShortestPath(graph, { from: 'a', to: 'c' }); // single shortest path
|
|
202
233
|
getTopologicalSort(graph); // topological order (or null)
|
|
203
234
|
getConnectedComponents(graph); // connected components
|
|
204
|
-
getMinimumSpanningTree(graph, {
|
|
235
|
+
getMinimumSpanningTree(graph, { getWeight: (e) => e.weight ?? 1 }); // MST
|
|
205
236
|
getPageRank(graph); // link analysis scores
|
|
237
|
+
getLouvainCommunities(graph); // community detection (Louvain)
|
|
206
238
|
getLabelPropagationCommunities(graph); // community detection
|
|
207
239
|
[...genGirvanNewmanCommunities(graph)]; // lazy community splits
|
|
208
240
|
getBridges(graph); // bridge edges
|
|
241
|
+
getMaxFlow(graph, { from: 'a', to: 'c' }); // max flow + min cut
|
|
242
|
+
getDominatorTree(graph, { from: 'a' }); // immediate dominators
|
|
243
|
+
getTransitiveReduction(graph); // minimal equivalent DAG
|
|
209
244
|
isIsomorphic(graph, otherGraph); // structural equivalence
|
|
210
245
|
```
|
|
211
246
|
|
|
247
|
+
## Layout
|
|
248
|
+
|
|
249
|
+
<!-- layout adapters under src/layout/*.ts and helpers exported from src/layout/index.ts -->
|
|
250
|
+
|
|
251
|
+
Plug-and-play layout over external engines — pure functions in, positioned `VisualGraph` out. No layout algorithms of our own; each adapter is a subpath with an optional peer dependency. The hierarchical engines (ELK, dagre, Graphviz) also produce routed edge `points` and computed edge-label rects; the physics/tree/cytoscape engines position nodes only.
|
|
252
|
+
|
|
253
|
+
```ts
|
|
254
|
+
import { getElkLayout } from '@statelyai/graph/layout/elk'; // elkjs
|
|
255
|
+
import { getDagreLayout } from '@statelyai/graph/layout/dagre'; // @dagrejs/dagre
|
|
256
|
+
import { getGraphvizLayout } from '@statelyai/graph/layout/graphviz'; // @hpcc-js/wasm-graphviz (8 engines)
|
|
257
|
+
import { genForceLayout } from '@statelyai/graph/layout/d3-force'; // d3-force
|
|
258
|
+
import { getForceAtlas2Layout } from '@statelyai/graph/layout/forceatlas2'; // graphology FA2
|
|
259
|
+
import { getTidyTreeLayout } from '@statelyai/graph/layout/d3-hierarchy'; // d3-hierarchy
|
|
260
|
+
import { getColaLayout } from '@statelyai/graph/layout/webcola'; // webcola (constraints)
|
|
261
|
+
import { getCytoscapeLayout } from '@statelyai/graph/layout/cytoscape'; // cytoscape ecosystem
|
|
262
|
+
import { applyLayoutFrame, getLayoutBounds, centerGraph } from '@statelyai/graph/layout';
|
|
263
|
+
|
|
264
|
+
const laidOut = await getElkLayout(graph, {
|
|
265
|
+
measure: (node) => measureText(node.label), // text measurement stays yours
|
|
266
|
+
constraints: { layer: (node) => node.data?.tier }, // portable layer constraint
|
|
267
|
+
});
|
|
268
|
+
|
|
269
|
+
// Physics layouts are generators — one tick per frame, cancel by stopping
|
|
270
|
+
for (const frame of genForceLayout(graph, { seed: 42 })) {
|
|
271
|
+
applyLayoutFrame(graph, frame);
|
|
272
|
+
render(graph);
|
|
273
|
+
}
|
|
274
|
+
```
|
|
275
|
+
|
|
276
|
+
Edge `x`/`y`/`width`/`height` are canonically the edge-label rect; routes live in `edge.points` (`routing` says how to interpret them). Layouts are plain JSON — tween between engines with `genLayoutTransition`, or diff them with `getPatches`. See [docs/layout.md](./docs/layout.md) and [docs/layout-transitions.md](./docs/layout-transitions.md).
|
|
277
|
+
|
|
212
278
|
## Diff & Walks
|
|
213
279
|
|
|
214
280
|
Beyond classic graph algorithms, the library also includes utilities for evolving and exploring graph state:
|
|
215
281
|
|
|
216
|
-
- `getDiff()`, `getPatches()`, `
|
|
282
|
+
- `getDiff()`, `getPatches()`, `updateGraphWithPatches()` for graph change tracking
|
|
217
283
|
- `genRandomWalk()`, `genWeightedRandomWalk()`, and coverage helpers for model-based testing and simulation
|
|
218
|
-
- `getSubgraph()` and `
|
|
284
|
+
- `getSubgraph()` and `getReversedGraph()` for structural transforms
|
|
219
285
|
|
|
220
286
|
## Visual Graphs
|
|
221
287
|
|
|
@@ -272,29 +338,29 @@ source information instead of preserving it as metadata.
|
|
|
272
338
|
|
|
273
339
|
<!-- format support matrix derived from src/formats/support.ts -->
|
|
274
340
|
|
|
275
|
-
| Format | Hierarchy | Ports | Visual | Round-trip | Notes
|
|
276
|
-
| ------------------- | --------- | ------- | ------- | ---------- |
|
|
277
|
-
| `adjacency-list` | none | none | none | partial | Connectivity only; edge metadata is lost.
|
|
278
|
-
| `cytoscape` | full | full | full | full | Graph
|
|
279
|
-
| `d3` | full | full | full | full | Graph
|
|
280
|
-
| `d2` | full | full | full | full |
|
|
281
|
-
| `dot` | partial | partial | partial | partial | Edge port ids round-trip, but `:port:compass` mapping is still incomplete.
|
|
282
|
-
| `edge-list` | none | none | none | partial | Endpoints only.
|
|
283
|
-
| `elk` | full | full | full | full | Metadata round-trips through reserved layout options.
|
|
284
|
-
| `gexf` | full | full | full | full | Custom attributes preserve metadata
|
|
285
|
-
| `gml` | full | full | full | full |
|
|
286
|
-
| `graphml` | full | full | partial |
|
|
287
|
-
| `jgf` | full | full | full | full |
|
|
288
|
-
| `tgf` | none | none | none | partial | Minimal ids and labels only.
|
|
289
|
-
| `xyflow` | full | full | full | full | Metadata round-trips through reserved data fields.
|
|
290
|
-
| `mermaid/block` | partial | none | partial | partial | Syntax-driven, not port-aware.
|
|
291
|
-
| `mermaid/class` | none | none | none | partial | Class syntax is stored conservatively.
|
|
292
|
-
| `mermaid/er` | none | none | none | partial | Focuses on entities and cardinality.
|
|
293
|
-
| `mermaid/flowchart` | partial | none | partial | partial | `linkStyle` indices are fragile.
|
|
294
|
-
| `mermaid/ishikawa` | full | none | none | partial | Preserves hierarchy, not fishbone layout.
|
|
295
|
-
| `mermaid/mindmap` | full | none | partial | partial | Icon syntax is not fully re-emitted.
|
|
296
|
-
| `mermaid/sequence` | partial | none | none | partial | Actor links and menu syntax are incomplete.
|
|
297
|
-
| `mermaid/state` | full | none | partial |
|
|
341
|
+
| Format | Hierarchy | Ports | Visual | Round-trip | Notes |
|
|
342
|
+
| ------------------- | --------- | ------- | ------- | ---------- | -------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
343
|
+
| `adjacency-list` | none | none | none | partial | Connectivity only; edge metadata is lost. |
|
|
344
|
+
| `cytoscape` | full | full | full | full | Graph/node/edge metadata (incl. per-edge `mode`) round-trips through element data. |
|
|
345
|
+
| `d3` | full | full | full | full | Graph/node/edge metadata (incl. per-edge `mode`) round-trips through the loose JSON shape. |
|
|
346
|
+
| `d2` | full | full | full | full | Hierarchy, ports, styles, and connector modes round-trip; nested `vars` sub-blocks are dropped. |
|
|
347
|
+
| `dot` | partial | partial | partial | partial | Edge port ids round-trip, but `:port:compass` mapping is still incomplete. |
|
|
348
|
+
| `edge-list` | none | none | none | partial | Endpoints only. |
|
|
349
|
+
| `elk` | full | full | full | full | Metadata round-trips through reserved layout options; port ids are emitted as `nodeId__portName` (document-unique, as ELK requires). |
|
|
350
|
+
| `gexf` | full | full | full | full | Custom attributes preserve metadata; `bidirectional` maps to directed. |
|
|
351
|
+
| `gml` | full | full | full | full | Metadata round-trips through direct and JSON fields; per-edge/graph `mode` via a dialect key. |
|
|
352
|
+
| `graphml` | full | full | partial | full | Emit is own-dialect (`<data>` fields, flat); import handles both dialects incl. standard nested `<graph>`, native `<port>` elements, and `sourceport`/`targetport` attributes. Multi-graph files import the first graph. |
|
|
353
|
+
| `jgf` | full | full | full | full | Metadata (incl. per-edge/graph `mode`) round-trips through `metadata` objects. |
|
|
354
|
+
| `tgf` | none | none | none | partial | Minimal ids and labels only. |
|
|
355
|
+
| `xyflow` | full | full | full | full | Metadata (incl. weight, ports, per-edge `mode`) round-trips through reserved data fields; parents are ordered before children for React Flow. |
|
|
356
|
+
| `mermaid/block` | partial | none | partial | partial | Syntax-driven, not port-aware. |
|
|
357
|
+
| `mermaid/class` | none | none | none | partial | Class syntax is stored conservatively. |
|
|
358
|
+
| `mermaid/er` | none | none | none | partial | Focuses on entities and cardinality. |
|
|
359
|
+
| `mermaid/flowchart` | partial | none | partial | partial | `linkStyle` indices are fragile. |
|
|
360
|
+
| `mermaid/ishikawa` | full | none | none | partial | Preserves hierarchy, not fishbone layout. |
|
|
361
|
+
| `mermaid/mindmap` | full | none | partial | partial | Icon syntax is not fully re-emitted. |
|
|
362
|
+
| `mermaid/sequence` | partial | none | none | partial | Actor links and menu syntax are incomplete. |
|
|
363
|
+
| `mermaid/state` | full | none | partial | partial | Isolated states and labels now emit (labels via the description form); `initialNodeId` round-trips as `[*] -->`. |
|
|
298
364
|
|
|
299
365
|
Some formats have optional peer dependencies: `fast-xml-parser` (GEXF, GraphML) and `dotparser` (DOT). All other formats are dependency-free.
|
|
300
366
|
|
|
@@ -318,6 +384,17 @@ Format-specific docs live alongside the source:
|
|
|
318
384
|
- [xyflow](./src/formats/xyflow/README.md)
|
|
319
385
|
- [Converter helpers](./src/formats/converter/README.md)
|
|
320
386
|
|
|
387
|
+
## Guides
|
|
388
|
+
|
|
389
|
+
<!-- guide documents under docs/*.md -->
|
|
390
|
+
|
|
391
|
+
- [Layout guide](./docs/layout.md) — the adapter contract, all eight engines, constraints, sizing, web workers
|
|
392
|
+
- [Layout transitions](./docs/layout-transitions.md) — tween between engines; layouts are just data
|
|
393
|
+
- [Algorithms reference](./docs/algorithms.md) — every algorithm with complexity and semantics notes
|
|
394
|
+
- [Benchmarks](./docs/benchmarks.md) — measured against graphology, ngraph, graphlib, and cytoscape
|
|
395
|
+
- [Migrating from graphlib](./docs/migrating-from-graphlib.md)
|
|
396
|
+
- [React Flow + ELK pipeline](./docs/react-flow-elk-pipeline.md) — measured nodes, worker layout, live re-layout
|
|
397
|
+
|
|
321
398
|
## Examples
|
|
322
399
|
|
|
323
400
|
<!-- runnable example files under examples/ -->
|
|
@@ -44,7 +44,9 @@ function toAdjacencyList(graph) {
|
|
|
44
44
|
function fromAdjacencyList(adj, options) {
|
|
45
45
|
const directed = options?.directed ?? true;
|
|
46
46
|
const seen = /* @__PURE__ */ new Set();
|
|
47
|
-
const
|
|
47
|
+
const nodeIds = new Set(Object.keys(adj));
|
|
48
|
+
for (const targets of Object.values(adj)) for (const targetId of targets) nodeIds.add(targetId);
|
|
49
|
+
const nodes = [...nodeIds].map((id) => ({
|
|
48
50
|
type: "node",
|
|
49
51
|
id,
|
|
50
52
|
parentId: null,
|