@@ -11,8 +11,10 @@ import (
11
11
)
12
12
13
13
type Node struct {
14
- ID string
15
- Label string
14
+ ID string
15
+ Label string
16
+ Count int
17
+ Provider string
16
18
}
17
19
18
20
type Edge struct {
@@ -21,114 +23,118 @@ type Edge struct {
21
23
}
22
24
23
25
type Graph struct {
24
- Nodes []Node
25
- Edges []Edge
26
+ Nodes []Node
27
+ Edges []Edge
28
+ NodeMap map [string ]int
26
29
}
27
30
28
- // Removes unnecessary parts from the label
31
+ var labelCleaner = regexp .MustCompile (`\s*\(expand\)|\s*\(close\)|\[root\]\s*|"` )
32
+
33
+ // CleanLabel removes unnecessary parts from the label
29
34
func CleanLabel (label string ) string {
30
- re := regexp .MustCompile (`\s*\(expand\)|\s*\(close\)|\[root\]\s*|"` )
31
- return re .ReplaceAllString (label , "" )
35
+ return labelCleaner .ReplaceAllString (label , "" )
32
36
}
33
37
34
- // Removes unnecessary parts from the ID
38
+ // CleanID removes unnecessary parts from the ID
35
39
func CleanID (id string ) string {
36
- re := regexp .MustCompile (`\s*\(expand\)|\s*\(close\)|\[root\]\s*|"` )
37
- return re .ReplaceAllString (id , "" )
40
+ return labelCleaner .ReplaceAllString (id , "" )
38
41
}
39
42
40
- // Extracts the provider for separate subgraph
43
+ // ExtractProvider extracts the provider for separate subgraph
41
44
func ExtractProvider (label string ) string {
42
- if strings .Contains (label , "provider" ) {
43
- parts := strings .Split (label , "/" )
44
- if len (parts ) > 2 {
45
- return parts [len (parts )- 2 ]
46
- }
45
+ parts := strings .Split (label , "_" )
46
+ if len (parts ) > 0 {
47
+ // Remove quotes from the provider name
48
+ return strings .ReplaceAll (parts [0 ], "\" " , "" )
47
49
}
48
50
return ""
49
51
}
50
52
51
- // Transforms the parsed graph into cleaned nodes and edges
53
+ // TransformGraph transforms the parsed graph into cleaned nodes and edges
52
54
func TransformGraph (graph * gographviz.Graph ) Graph {
53
55
nodes := []Node {}
54
56
edges := []Edge {}
57
+ nodeMap := make (map [string ]int )
55
58
56
59
for _ , node := range graph .Nodes .Nodes {
57
60
cleanedID := CleanID (node .Name )
58
61
cleanedLabel := CleanLabel (node .Attrs ["label" ])
59
- if cleanedLabel != "" && ! strings .Contains (cleanedLabel , "provider" ) {
60
- nodes = append (nodes , Node {ID : cleanedID , Label : cleanedLabel })
62
+ provider := ExtractProvider (cleanedLabel )
63
+ if cleanedLabel != "" {
64
+ nodeMap [cleanedLabel ]++
65
+ nodes = append (nodes , Node {ID : cleanedID , Label : cleanedLabel , Count : nodeMap [cleanedLabel ], Provider : provider })
61
66
}
62
67
}
63
68
64
69
for _ , edge := range graph .Edges .Edges {
65
70
fromLabel := CleanLabel (graph .Nodes .Lookup [edge .Src ].Attrs ["label" ])
66
71
toLabel := CleanLabel (graph .Nodes .Lookup [edge .Dst ].Attrs ["label" ])
67
- if fromLabel != "" && toLabel != "" && ! strings . Contains ( fromLabel , "provider" ) && ! strings . Contains ( toLabel , "provider" ) {
72
+ if fromLabel != "" && toLabel != "" {
68
73
edges = append (edges , Edge {From : CleanID (edge .Src ), To : CleanID (edge .Dst )})
69
74
}
70
75
}
71
76
72
- return Graph {Nodes : nodes , Edges : edges }
77
+ return Graph {Nodes : nodes , Edges : edges , NodeMap : nodeMap }
73
78
}
74
79
75
- // Converts a gographviz graph to a Mermaid.js compatible string.
80
+ // ConvertToMermaidFlowchart converts a gographviz graph to a Mermaid.js compatible string.
76
81
// It accepts a graph, direction, and an optional subgraph name.
77
82
func ConvertToMermaidFlowchart (graph * gographviz.Graph , direction string , subgraphName string ) (string , error ) {
78
83
var sb strings.Builder
79
84
80
- // Capitalize the provider name
81
85
caser := cases .Title (language .English )
82
- // Validate the direction of the flowchart. Valid options are: TB, TD, BT, RL, LR
83
86
validDirections := map [string ]bool {
84
87
"TB" : true , "TD" : true , "BT" : true , "RL" : true , "LR" : true ,
85
88
}
86
89
if ! validDirections [direction ] {
87
90
return "" , fmt .Errorf ("invalid direction %s: valid options are: TB, TD, BT, RL, LR" , direction )
88
91
}
89
- // Start Mermaid graph definition
92
+
90
93
sb .WriteString ("```mermaid\n " )
91
94
sb .WriteString ("flowchart " + direction + "\n " )
92
95
93
- // Add subgraph for providers
96
+ if subgraphName != "" {
97
+ sb .WriteString (fmt .Sprintf ("\t subgraph %s\n " , subgraphName ))
98
+ }
99
+
94
100
providerSubgraphs := make (map [string ]bool )
95
101
for _ , n := range graph .Nodes .Nodes {
96
- label := n .Attrs ["label" ]
97
- provider := ExtractProvider (label )
102
+ provider := ExtractProvider (n .Attrs ["label" ])
98
103
if provider != "" && ! providerSubgraphs [provider ] {
99
- sb .WriteString (fmt .Sprintf ("\t subgraph %s\n " , caser .String (provider )))
104
+ sb .WriteString (fmt .Sprintf ("\t \ t subgraph %s\n " , caser .String (provider )))
100
105
providerSubgraphs [provider ] = true
101
106
}
102
107
}
103
108
104
- if subgraphName != "" {
105
- sb .WriteString (fmt .Sprintf ("\t subgraph %s\n " , subgraphName ))
106
- }
107
-
108
- // Iterate over nodes to add them to the Mermaid graph
109
+ nodeMap := make (map [string ]int )
109
110
for _ , n := range graph .Nodes .Nodes {
110
111
label := CleanLabel (n .Attrs ["label" ])
111
112
nodeName := CleanID (n .Name )
112
- if label != "" && nodeName != "" && ! strings .Contains (label , "provider" ) {
113
- sb .WriteString (fmt .Sprintf ("\t \t %s[\" %s\" ]\n " , nodeName , label ))
113
+ if label != "" && nodeName != "" {
114
+ nodeMap [label ]++
115
+ count := nodeMap [label ]
116
+ if count > 1 {
117
+ sb .WriteString (fmt .Sprintf ("\t \t \t %s[\" %s\\ nCount: %d\" ]\n " , nodeName , label , count ))
118
+ } else {
119
+ sb .WriteString (fmt .Sprintf ("\t \t \t %s[\" %s\" ]\n " , nodeName , label ))
120
+ }
114
121
}
115
122
}
116
123
117
- // Iterate over edges to add them to the Mermaid graph
124
+ for range providerSubgraphs {
125
+ sb .WriteString ("\t \t end\n " )
126
+ }
127
+
118
128
for _ , edge := range graph .Edges .Edges {
119
129
srcLabel := CleanLabel (graph .Nodes .Lookup [edge .Src ].Attrs ["label" ])
120
130
dstLabel := CleanLabel (graph .Nodes .Lookup [edge .Dst ].Attrs ["label" ])
121
131
srcName := CleanID (edge .Src )
122
132
dstName := CleanID (edge .Dst )
123
- if srcLabel != "" && dstLabel != "" && ! strings . Contains ( srcLabel , "provider" ) && ! strings . Contains ( dstLabel , "provider" ) {
133
+ if srcLabel != "" && dstLabel != "" {
124
134
sb .WriteString (fmt .Sprintf ("\t \t %s --> %s\n " , srcName , dstName ))
125
135
}
126
136
}
127
137
128
- // Close all open subgraphs
129
- for range providerSubgraphs {
130
- sb .WriteString ("\t end\n " )
131
- }
132
138
if subgraphName != "" {
133
139
sb .WriteString ("\t end\n " )
134
140
}
0 commit comments