@@ -4,14 +4,12 @@ const { JSDOM } = jsdom;
4
4
const dom = new JSDOM ( ) ;
5
5
const jsonUtil = require ( "../resources/JsonUtil" ) ;
6
6
const iconMap = require ( "../resources/IconMap" ) ;
7
-
8
7
global . window = dom . window ;
9
8
global . document = window . document ;
10
9
global . XMLSerializer = window . XMLSerializer ;
11
10
global . navigator = window . navigator ;
12
11
13
12
const mxgraph = require ( "mxgraph" ) ( { } ) ;
14
-
15
13
const { mxGraph, mxCodec, mxUtils } = mxgraph ;
16
14
17
15
const layouts = [
@@ -21,120 +19,173 @@ const layouts = [
21
19
{ name : "Radial Tree" , value : "mxRadialTreeLayout" } ,
22
20
] ;
23
21
24
- function makeGraph ( template , resourceTypesToInclude , layoutChoice ) {
25
- const resources = Object . keys ( template . Resources ) ;
22
+ const graph = new mxGraph ( ) ;
23
+
24
+ let currentLayout = "mxHierarchicalLayout" ;
26
25
27
- const graph = new mxGraph ( ) ;
28
- const layout = new mxgraph [ layoutChoice || "mxFastOrganicLayout" ] ( graph ) ;
29
- layout . radius = 300 ;
30
- layout . forceConstant = 120 ;
31
- const parent = graph . getDefaultParent ( ) ;
32
- const vertices = [ ] ;
26
+ let vertices = [ ] ;
27
+ let forceLayoutRender = true ;
28
+ let locationCache = { } ;
29
+ const parent = graph . getDefaultParent ( ) ;
30
+ function makeGraph ( template , resourceTypesToInclude , resourceNamesToInclude ) {
31
+ let layout = new mxgraph [ currentLayout ] ( graph , true , 500 ) ;
32
+ const resources = Object . keys ( template . Resources ) ;
33
+ layout . orientation = "west" ;
34
+ layout . intraCellSpacing = 50 ;
35
+ layout . interRankCellSpacing = 200 ;
36
+ layout . interHierarchySpacing = 100 ;
37
+ layout . parallelEdgeSpacing = 20 ;
38
+ layout . leftMargin = 200 ;
39
+ layout . resizeParent = true ;
33
40
graph . getModel ( ) . beginUpdate ( ) ;
34
41
try {
35
42
for ( const resource of resources ) {
36
43
const type = template . Resources [ resource ] . Type ;
37
- if ( ! resourceTypesToInclude . includes ( type ) ) {
44
+ if (
45
+ ! resourceTypesToInclude . includes ( type ) ||
46
+ ! resourceNamesToInclude . includes ( resource )
47
+ ) {
48
+ updateFilters ( type , resource ) ;
38
49
continue ;
39
50
}
40
- const dependencies = [ ] ;
41
- jsonUtil . findAllValues ( template . Resources [ resource ] , dependencies , "Ref" ) ;
42
- jsonUtil . findAllValues (
43
- template . Resources [ resource ] ,
44
- dependencies ,
45
- "Fn::GetAtt"
46
- ) ;
47
51
48
- for ( const dependency of dependencies ) {
49
- dependency . value = dependency . value . filter (
50
- ( p ) =>
51
- template . Resources [ p ] &&
52
- resourceTypesToInclude . includes ( template . Resources [ p ] . Type )
53
- ) ;
54
- }
52
+ const dependencies = getDependencies (
53
+ template ,
54
+ resource ,
55
+ resourceTypesToInclude
56
+ ) ;
55
57
56
- vertices . push ( {
57
- name : resource ,
58
- dependencies : dependencies ,
59
- vertex : graph . insertVertex (
60
- parent ,
61
- null ,
62
- resource ,
63
- 70 ,
64
- 1 ,
65
- 50 ,
66
- 50 ,
67
- iconMap . getIcon ( type )
68
- ) ,
69
- } ) ;
58
+ addVertices ( resource , dependencies , type ) ;
70
59
}
71
60
72
- for ( const vertex of vertices ) {
73
- for ( const dependencyNode of vertex . dependencies ) {
61
+ for ( const sourceVertex of vertices ) {
62
+ for ( const dependencyNode of sourceVertex . dependencies ) {
74
63
for ( const dependency of dependencyNode . value ) {
75
- const target = vertices . filter ( ( p ) => p . name === dependency ) [ 0 ] ;
76
- let from = vertex . vertex ;
77
- let to = target . vertex ;
78
-
79
- if ( from && to ) {
80
- if ( dependencyNode . path . indexOf ( "Properties.Events" ) > 0 ) {
81
- graph . insertEdge (
82
- parent ,
83
- null ,
84
- "Event" ,
85
- to ,
86
- from ,
87
- "edgeStyle=orthogonalEdgeStyle;rounded=1;orthogonalLoop=1;jettySize=auto;html=1;fillColor=#1ba1e2;strokeColor=#006EAF;labelBackgroundColor=none;fontColor=#7EA6E0;"
88
- ) ;
89
- } else {
90
- const edges = graph . getEdges ( from ) ;
91
- const existing = edges . filter ( ( p ) => p . target . value === to . value ) ;
92
- if ( existing . length > 0 ) {
93
- const edgeValue = pathToDescriptor ( dependencyNode . path ) ;
94
- if ( edgeValue !== null ) {
95
- existing [ 0 ] . setValue (
96
- `${
97
- existing [ 0 ] . getValue ( )
98
- ? existing [ 0 ] . getValue ( ) + "\n"
99
- : ""
100
- } ${ edgeValue } `
101
- ) ;
102
- }
103
- } else {
104
- graph . insertEdge (
105
- parent ,
106
- null ,
107
- pathToDescriptor ( dependencyNode . path ) ,
108
- from ,
109
- to ,
110
- "edgeStyle=orthogonalEdgeStyle;rounded=1;orthogonalLoop=1;jettySize=auto;html=1;labelBackgroundColor=none;fontColor=#EA6B66;"
111
- ) ;
112
- }
113
- }
64
+ const targets = vertices . filter ( ( p ) => p . name === dependency ) ;
65
+ const targetVertex = targets [ 0 ] ;
66
+ if ( ! targetVertex ) {
67
+ continue ;
114
68
}
69
+ let from = sourceVertex . vertex ;
70
+ let to = targetVertex . vertex ;
71
+ addEdges ( from , to , dependencyNode ) ;
115
72
}
116
73
}
117
74
}
118
75
} catch ( err ) {
119
76
console . log ( err ) ;
120
77
} finally {
78
+ layout . execute ( parent ) ;
79
+ forceLayoutRender = false ;
121
80
graph . getModel ( ) . endUpdate ( ) ;
122
81
}
123
-
124
- layout . execute ( parent ) ;
125
82
return graph ;
126
83
}
127
84
85
+ function addEdges ( from , to , dependencyNode ) {
86
+ if ( from && to ) {
87
+ const existingEdges = Object . keys ( graph . model . cells ) . filter (
88
+ ( c ) => c === edgeId ( to , from )
89
+ ) ;
90
+ if ( existingEdges . length > 0 ) {
91
+ const existingEdge = graph . model . cells [ existingEdges [ 0 ] ] ;
92
+ if ( ! existingEdge . value . includes ( pathToDescriptor ( dependencyNode . path ) ) ) {
93
+ existingEdge . value += `\n${ pathToDescriptor ( dependencyNode . path ) } ` ;
94
+ }
95
+ return ;
96
+ }
97
+ if ( dependencyNode . path . indexOf ( "Properties.Events" ) > 0 ) {
98
+ graph . insertEdge (
99
+ parent ,
100
+ edgeId ( to , from ) ,
101
+ "Invoke" ,
102
+ to ,
103
+ from ,
104
+ "edgeStyle=orthogonalEdgeStyle;rounded=1;orthogonalLoop=1;jettySize=auto;html=1;fillColor=#1ba1e2;strokeColor=#006EAF;labelBackgroundColor=none;fontColor=#7EA6E0;"
105
+ ) ;
106
+ } else {
107
+ graph . insertEdge (
108
+ parent ,
109
+ edgeId ( to , from ) ,
110
+ pathToDescriptor ( dependencyNode . path ) ,
111
+ from ,
112
+ to ,
113
+ "edgeStyle=orthogonalEdgeStyle;rounded=1;orthogonalLoop=1;jettySize=auto;html=1;labelBackgroundColor=none;fontColor=#EA6B66;"
114
+ ) ;
115
+ }
116
+ }
117
+ }
118
+
119
+ function addVertices ( resource , dependencies , type ) {
120
+ if ( vertices . filter ( ( p ) => p . name === resource ) . length === 0 ) {
121
+ vertices . push ( {
122
+ name : resource ,
123
+ dependencies : dependencies ,
124
+ type : type ,
125
+ vertex : graph . insertVertex (
126
+ parent ,
127
+ null ,
128
+ resource ,
129
+ locationCache [ resource ] ? locationCache [ resource ] . x : 70 ,
130
+ locationCache [ resource ] ? locationCache [ resource ] . y : 0 ,
131
+ 50 ,
132
+ 50 ,
133
+ iconMap . getIcon ( type )
134
+ ) ,
135
+ } ) ;
136
+ }
137
+ }
138
+
139
+ function getDependencies ( template , resource , resourceTypesToInclude ) {
140
+ const dependencies = [ ] ;
141
+ jsonUtil . findAllValues ( template . Resources [ resource ] , dependencies , "Ref" ) ;
142
+ jsonUtil . findAllValues (
143
+ template . Resources [ resource ] ,
144
+ dependencies ,
145
+ "Fn::GetAtt"
146
+ ) ;
147
+ for ( const dependency of dependencies ) {
148
+ dependency . value = dependency . value . filter (
149
+ ( p ) =>
150
+ template . Resources [ p ] &&
151
+ resourceTypesToInclude . includes ( template . Resources [ p ] . Type )
152
+ ) ;
153
+ }
154
+ return dependencies ;
155
+ }
156
+
157
+ function updateFilters ( type , resource ) {
158
+ const cells = graph . model . cells ;
159
+ const keys = Object . keys ( cells ) ;
160
+ keys . map (
161
+ ( p ) =>
162
+ ( locationCache [ cells [ p ] . value ] = cells [ p ] . geometry
163
+ ? { x : cells [ p ] . geometry . x , y : cells [ p ] . geometry . y }
164
+ : null )
165
+ ) ;
166
+ if ( vertices . filter ( ( p ) => p . type === type ) . length ) {
167
+ const item = vertices . filter ( ( p ) => p . name === resource ) [ 0 ] ;
168
+ if ( item ) {
169
+ graph . removeCells ( [ item . vertex ] , true ) ;
170
+ }
171
+ vertices = vertices . filter ( ( p ) => p . name != resource ) ;
172
+ }
173
+ }
174
+
175
+ function edgeId ( to , from ) {
176
+ return `${ to . value } |${ from . value } ` ; //|${pathToDescriptor(dependencyNode.path)}`;
177
+ }
178
+
128
179
function pathToDescriptor ( path ) {
129
180
if ( path . startsWith ( "$.Properties.Environment" ) ) {
130
- // return "Variable" ;
181
+ return path . split ( "." ) . slice ( - 1 ) [ 0 ] ;
131
182
}
132
183
133
184
if ( path . startsWith ( "$.Properties.Policies" ) ) {
134
185
const split = path . split ( "." ) ;
135
186
return split [ 3 ] ;
136
187
}
137
- return null ;
188
+ return "" ;
138
189
}
139
190
140
191
function graphToXML ( graph ) {
@@ -143,8 +194,8 @@ function graphToXML(graph) {
143
194
return mxUtils . getXml ( result ) ;
144
195
}
145
196
146
- function renderTemplate ( template , resources , layout ) {
147
- const xml = graphToXML ( makeGraph ( template , resources , layout ) ) ;
197
+ function renderTemplate ( template , resourceTypes , resourceNames ) {
198
+ const xml = graphToXML ( makeGraph ( template , resourceTypes , resourceNames ) ) ;
148
199
return xml ;
149
200
}
150
201
0 commit comments