2
2
* Serializes the graph.
3
3
*/
4
4
import { Graph } from '../Graph.js' ;
5
- import { Edge , Serialized } from '../types.js' ;
5
+ import { NoInfer , Edge , Serialized } from '../types.js' ;
6
6
7
7
type SerializeGraphOptions < IncludeDefaultWeight extends boolean = false > = {
8
8
/**
@@ -17,30 +17,57 @@ type SerializeGraphOptions<IncludeDefaultWeight extends boolean = false> = {
17
17
18
18
/**
19
19
* Serialize the graph data set : nodes, edges, edges weight & properties.
20
- * @param graph
21
- * @param opts
20
+ *
21
+ * Optionally, you can pass a function that returns a unique value for a given node.
22
+ * When provided, the function will be used to avoid data duplication in the serialized object.
22
23
*/
23
- export function serializeGraph < Node , LinkProps , IncludeDefaultWeight extends boolean > (
24
+ export function serializeGraph <
25
+ Node ,
26
+ LinkProps ,
27
+ IncludeDefaultWeight extends boolean ,
28
+ NodeIdentity = Node ,
29
+ > (
24
30
graph : Graph < Node , LinkProps > ,
25
- opts : SerializeGraphOptions < IncludeDefaultWeight > = { } ,
26
- ) : Serialized < Node , LinkProps > {
27
- const { includeDefaultWeight = false } = opts ;
31
+ ...args :
32
+ | [
33
+ identityFn : ( node : NoInfer < Node > ) => NodeIdentity ,
34
+ SerializeGraphOptions < IncludeDefaultWeight > ?,
35
+ ]
36
+ | [ SerializeGraphOptions < IncludeDefaultWeight > ?]
37
+ ) : Serialized < Node , LinkProps , NodeIdentity > {
38
+ const identityFn = typeof args [ 0 ] === 'function' ? args [ 0 ] : undefined ;
39
+ const opts = typeof args [ 0 ] === 'function' ? args [ 1 ] : args [ 0 ] ;
28
40
29
- const serialized : Serialized < Node , LinkProps > = {
41
+ const { includeDefaultWeight = false } = opts ?? { } ;
42
+
43
+ const serialized : Serialized < Node , LinkProps , NodeIdentity > = {
30
44
nodes : Array . from ( graph . nodes ) ,
31
45
links : [ ] ,
32
46
} ;
33
47
48
+ const nodeIdentityMap = new Map < Node , NodeIdentity > ( ) ;
49
+
34
50
serialized . nodes . forEach ( ( node ) => {
35
51
const source = node ;
36
52
graph . adjacent ( source ) ?. forEach ( ( target ) => {
37
53
const edgeWeight = graph . getEdgeWeight ( source , target ) ;
38
54
const edgeProps = graph . getEdgeProperties ( source , target ) ;
39
55
56
+ if ( identityFn && ! nodeIdentityMap . has ( source ) ) {
57
+ nodeIdentityMap . set ( source , identityFn ( source ) ) ;
58
+ }
59
+
60
+ if ( identityFn && ! nodeIdentityMap . has ( target ) ) {
61
+ nodeIdentityMap . set ( target , identityFn ( target ) ) ;
62
+ }
63
+
64
+ const sourceIdentity = nodeIdentityMap . get ( source ) ?? source ;
65
+ const targetIdentity = nodeIdentityMap . get ( target ) ?? target ;
66
+
40
67
const link = {
41
- source : source ,
42
- target : target ,
43
- } as Edge < Node , LinkProps > ;
68
+ source : sourceIdentity ,
69
+ target : targetIdentity ,
70
+ } as Edge < NodeIdentity , LinkProps > ;
44
71
45
72
if ( edgeWeight != 1 || includeDefaultWeight ) {
46
73
link . weight = edgeWeight ;
0 commit comments