22 * Serializes the graph.
33 */
44import { Graph } from '../Graph.js' ;
5- import { Edge , Serialized } from '../types.js' ;
5+ import { NoInfer , Edge , Serialized } from '../types.js' ;
66
77type SerializeGraphOptions < IncludeDefaultWeight extends boolean = false > = {
88 /**
@@ -17,30 +17,57 @@ type SerializeGraphOptions<IncludeDefaultWeight extends boolean = false> = {
1717
1818/**
1919 * 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.
2223 */
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+ > (
2430 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 ] ;
2840
29- const serialized : Serialized < Node , LinkProps > = {
41+ const { includeDefaultWeight = false } = opts ?? { } ;
42+
43+ const serialized : Serialized < Node , LinkProps , NodeIdentity > = {
3044 nodes : Array . from ( graph . nodes ) ,
3145 links : [ ] ,
3246 } ;
3347
48+ const nodeIdentityMap = new Map < Node , NodeIdentity > ( ) ;
49+
3450 serialized . nodes . forEach ( ( node ) => {
3551 const source = node ;
3652 graph . adjacent ( source ) ?. forEach ( ( target ) => {
3753 const edgeWeight = graph . getEdgeWeight ( source , target ) ;
3854 const edgeProps = graph . getEdgeProperties ( source , target ) ;
3955
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+
4067 const link = {
41- source : source ,
42- target : target ,
43- } as Edge < Node , LinkProps > ;
68+ source : sourceIdentity ,
69+ target : targetIdentity ,
70+ } as Edge < NodeIdentity , LinkProps > ;
4471
4572 if ( edgeWeight != 1 || includeDefaultWeight ) {
4673 link . weight = edgeWeight ;
0 commit comments