4040 gen_link_text ,
4141 gen_struct_element ,
4242 get_impl_comp_from_real_iface ,
43- get_interface ,
43+ get_interface_from_component ,
44+ get_interface_from_int ,
4445 get_logical_interface_real ,
46+ get_module ,
4547 get_real_interface_logical ,
4648)
4749
@@ -81,12 +83,83 @@ def scripts_directory_hash():
8183# ╰──────────────────────────────────────────────────────────────────────────────╯
8284
8385
84- def draw_component (
85- need : dict ,
86- all_needs : dict ,
87- proc_real_interfaces : dict [str , str ] | None = None ,
88- proc_logical_interfaces : dict [str , str ] | None = None ,
89- ) -> tuple [str , str , dict [str , str ], dict [str , str ]]:
86+ def draw_comp_incl_impl_int (
87+ need : dict [str , str ],
88+ all_needs : dict [str , dict ],
89+ proc_impl_interfaces : dict [str , str ],
90+ proc_used_interfaces : dict [str , list ],
91+ ) -> tuple [str , str , dict [str , str ], dict [str , list ]]:
92+ # Draw outer component
93+ structure_text = f"{ gen_struct_element ('component' , need )} {{\n "
94+ linkage_text = ""
95+
96+ # Draw inner (sub)components recursively
97+ for need_inc in need .get ("includes" , []):
98+ curr_need = all_needs .get (need_inc , {})
99+
100+ # check for misspelled include
101+ if not curr_need :
102+ logger .info (f"{ need } : include { need_inc } could not be found" )
103+ continue
104+
105+ if curr_need ["type" ] != "comp_arc_sta" :
106+ continue
107+
108+ sub_structure , sub_linkage , proc_impl_interfaces , proc_used_interfaces = (
109+ draw_comp_incl_impl_int (
110+ curr_need , all_needs , proc_impl_interfaces , proc_used_interfaces
111+ )
112+ )
113+
114+ structure_text += sub_structure
115+ linkage_text += sub_linkage
116+
117+ # close outer component
118+ structure_text += f"}} /' { need ['title' ]} '/ \n \n "
119+
120+ # Find implemented real interfaces inside the module/component
121+ local_impl_interfaces = get_interface_from_component (need , "implements" , all_needs )
122+ local_used_interfaces = get_interface_from_component (need , "uses" , all_needs )
123+
124+ # Add all interfaces which are implemented by component to global list
125+ # and provide implementation
126+ for iface in local_impl_interfaces :
127+ # check for misspelled implements
128+ if not all_needs .get (iface , []):
129+ logger .info (f"{ need } : implements { iface } could not be found" )
130+ continue
131+
132+ if not (interface := proc_impl_interfaces .get (iface , [])):
133+ structure_text += gen_interface_element (iface , all_needs , True )
134+ linkage_text += f"{
135+ gen_link_text (
136+ need ,
137+ '-u->' ,
138+ all_needs [iface ],
139+ 'implements' ,
140+ )
141+ } \n "
142+ proc_impl_interfaces [iface ] = need ["id" ]
143+
144+ # Add all elements which are used by component to global list
145+ for iface in local_used_interfaces :
146+ # check for misspelled used
147+ if not all_needs .get (iface , []):
148+ logger .info (f"{ need } : uses { iface } could not be found" )
149+ continue
150+
151+ if not (interface := proc_used_interfaces .get (iface , [])):
152+ proc_used_interfaces [iface ] = [need ["id" ]]
153+ else :
154+ proc_used_interfaces [iface ].append (need ["id" ])
155+
156+ return structure_text , linkage_text , proc_impl_interfaces , proc_used_interfaces
157+
158+
159+ def draw_module (
160+ need : dict [str , str ],
161+ all_needs : dict [str , dict ],
162+ ) -> tuple [str , str ]:
90163 """
91164 Drawing and parsing function of a component.
92165
@@ -139,76 +212,99 @@ def draw_component(
139212 (Structure Text, Linkage Text, Processed (Real Interfaces),
140213 Processed Logical Interfaces)
141214 """
142- proc_real_interfaces = proc_real_interfaces or dict ()
143- proc_logical_interfaces = proc_logical_interfaces or dict ()
215+ # Store all Elements which have already been processed
216+ proc_impl_interfaces = dict ()
217+ proc_used_interfaces = dict ()
218+ proc_logical_interfaces = dict ()
219+
144220 linkage_text = ""
145221
146- # Draw outer component
147- structure_text = f"{ gen_struct_element ('component ' , need )} {{\n "
222+ # Draw outer module
223+ structure_text = f"{ gen_struct_element ('package ' , need )} {{\n "
148224
149- # Process includes: Draw inner (sub) components recursively
225+ # Draw inner components recursively
150226 for need_inc in need .get ("includes" , []):
151- curr_need = all_needs [ need_inc ]
227+ curr_need = all_needs . get ( need_inc , {})
152228
153- if "comp_arc_sta" in curr_need ["type" ]:
154- sub_structure , sub_links , proc_real_interfaces , proc_logical_interfaces = (
155- draw_component (
156- curr_need , all_needs , proc_real_interfaces , proc_logical_interfaces
157- )
158- )
159- else :
229+ # check for misspelled include
230+ if not curr_need :
231+ logger .info (f"{ need } : include { need_inc } could not be found" )
160232 continue
161233
234+ if curr_need ["type" ] not in ["comp_arc_sta" , "mod_view_sta" ]:
235+ continue
236+
237+ sub_structure , sub_linkage , proc_impl_interfaces , proc_used_interfaces = (
238+ draw_comp_incl_impl_int (
239+ curr_need , all_needs , proc_impl_interfaces , proc_used_interfaces
240+ )
241+ )
242+
162243 structure_text += sub_structure
163- linkage_text += sub_links
244+ linkage_text += sub_linkage
164245
165- # close component
246+ # close outer component
166247 structure_text += f"}} /' { need ['title' ]} '/ \n \n "
167248
168- local_interfaces = dict ()
169- # Fill proc_real_interfaces with relation to implements and uses
170- for interface in need .get ("implements" , []):
171- iface = get_interface (interface , all_needs )
172- if iface not in local_interfaces :
173- local_interfaces [iface ] = "implements"
174-
175- for interface in need .get ("uses" , []):
176- iface = get_interface (interface , all_needs )
177- if iface not in local_interfaces :
178- local_interfaces [iface ] = "uses"
179-
180- for iface in local_interfaces :
181- # Draw interfaces
182- if iface not in proc_real_interfaces :
183- structure_text += gen_interface_element (iface , all_needs , True )
184- proc_logical_interfaces [iface ] = get_logical_interface_real (
185- iface , all_needs
186- )
187- proc_real_interfaces [iface ] = local_interfaces [iface ]
249+ # Add logical interfaces only to implemented interfaces
250+ for iface , component in proc_impl_interfaces .items ():
251+ if not (proc_logical_interfaces .get (iface , [])):
252+ # Currently only one Logical Interface per Real Interface supported
253+ logical_iface_tmp = get_logical_interface_real (iface , all_needs )
254+ assert (
255+ len (logical_iface_tmp ) == 1
256+ ), "only one logical interface per real interface supported"
257+ if logical_iface_tmp :
258+ logical_iface = logical_iface_tmp [0 ]
259+ proc_logical_interfaces [logical_iface ] = iface
260+
261+ structure_text += gen_interface_element (logical_iface , all_needs , True )
262+
263+ linkage_text += f"{
264+ gen_link_text (
265+ all_needs [iface ],
266+ '-u->' ,
267+ all_needs [logical_iface ],
268+ 'implements' ,
269+ )
270+ } \n "
271+ else :
272+ print (f"{ iface } : Not connected to any virtual interface" )
188273
189- # Draw connection between real components and interfaces
190- linkage_text += f"{
191- gen_link_text (
192- need ['title' ], '-->' , all_needs [iface ]['title' ], local_interfaces [iface ]
193- )
194- } \n "
274+ # Add all interfaces which are used by component
275+ for iface , comps in proc_used_interfaces .items ():
276+ if iface not in proc_impl_interfaces :
277+ # Add implementing components and modules
278+ impl_comp_str = get_impl_comp_from_real_iface (iface , all_needs )
195279
196- # Draw connection between real interfaces and logical interfaces
197- # if link exists
198- if interfaces := proc_logical_interfaces [iface ]:
199- linkage_text += f"{
200- gen_link_text (
201- all_needs [iface ]['title' ],
202- '-->' ,
203- all_needs [interfaces ]['title' ],
204- 'implements' ,
205- )
206- } \n "
280+ impl_comp = all_needs .get (impl_comp_str , {}) if impl_comp_str else ""
281+
282+ if impl_comp :
283+ retval = get_module (impl_comp_str , all_needs )
284+ structure_text += retval [2 ] # module open
285+ structure_text += retval [0 ] # rest open
286+
287+ structure_text += retval [1 ] # rest close
288+ structure_text += gen_interface_element (iface , all_needs , True )
289+ structure_text += retval [3 ] # module close
290+
291+ # Draw connection between implementing components and interface
292+ linkage_text += f"{ gen_link_text (impl_comp , '-u->' , all_needs [iface ], 'implements' )} \n "
293+
294+ else :
295+ # Add only interface if component not defined
296+ print (f"{ iface } : No implementing component defined" )
297+ structure_text += gen_interface_element (iface , all_needs , True )
298+
299+ # Interface can be used by multiple components
300+ for comp in comps :
301+ # Draw connection between used interfaces and components
302+ linkage_text += f"{ gen_link_text (all_needs [comp ], '-d[#green]->' , all_needs [iface ], 'uses' )} \n "
207303
208304 # Remove duplicate links
209305 linkage_text = "\n " .join (set (linkage_text .split ("\n " ))) + "\n "
210306
211- return structure_text , linkage_text , proc_real_interfaces , proc_logical_interfaces
307+ return structure_text , linkage_text
212308
213309
214310# ╭──────────────────────────────────────────────────────────────────────────────╮
@@ -224,49 +320,55 @@ def __call__(self, need, all_needs: dict) -> str:
224320 interfacelist = []
225321 impl_comp = dict ()
226322
227- structure_text = "allowmixing\n "
228- structure_text += f'actor "Feature User" as { gen_alias ("Feature User" )} \n '
323+ structure_text = (
324+ f'actor "Feature User" as { gen_alias ({"id" : "Feature_User" })} \n '
325+ )
229326
230327 # Define Feature as a package
231- structure_text += f"{ gen_struct_element ('package' , need )} {{\n "
328+ # structure_text += f"{gen_struct_element('package', need)} {{\n"
232329
233330 # Add logical Interfaces / Interface Operations (aka includes)
234331 for need_inc in need .get ("includes" , []):
235332 # Generate list of interfaces since both interfaces
236333 # and interface operations can be included
237- iface = get_interface (need_inc , all_needs )
238- interfacelist .append (iface ) if iface not in interfacelist else None
334+ iface = get_interface_from_int (need_inc , all_needs )
335+ if iface not in interfacelist :
336+ interfacelist .append (iface )
239337
240338 for iface in interfacelist :
241339 structure_text += gen_interface_element (iface , all_needs , True )
242340
243341 # Determine Components which implement the interfaces
244342 real_iface = get_real_interface_logical (iface , all_needs )
245- impl_comp [iface ] = get_impl_comp_from_real_iface (real_iface [0 ], all_needs )
343+ if real_iface :
344+ comps = get_impl_comp_from_real_iface (real_iface [0 ], all_needs )
246345
247- if imcomp := impl_comp [iface ]:
346+ if comps :
347+ impl_comp [iface ] = comps
348+
349+ if imcomp := impl_comp .get (iface ):
248350 structure_text += (
249- f"{ gen_struct_element ('component' , all_needs [imcomp [ 0 ] ])} \n "
351+ f"{ gen_struct_element ('component' , all_needs [imcomp ])} \n "
250352 )
251353
252354 # Close Package
253- structure_text += f"}} /' { need ['title' ]} '/ \n \n "
355+ # structure_text += f"}} /' {need['title']} '/ \n\n"
254356
255357 link_text = ""
256358
257359 for iface in interfacelist :
258360 # Add relation between Actor and Interfaces
259361 link_text += f"{
260- gen_link_text ('Feature User' , '-d->' , all_needs [iface ][ 'title' ], 'use' )
362+ gen_link_text ({ 'id' : 'Feature_User' } , '-d->' , all_needs [iface ], 'use' )
261363 } \n "
262364
263365 # Add relation between interface and component
264- if imcomp := impl_comp [ iface ] :
366+ if imcomp := impl_comp . get ( iface ) :
265367 link_text += f"{
266368 gen_link_text (
267- all_needs [imcomp [ 0 ]][ 'title' ],
268- '-->' ,
269- all_needs [iface ][ 'title' ] ,
369+ all_needs [imcomp ],
370+ '-u ->' ,
371+ all_needs [iface ],
270372 'implements' ,
271373 )
272374 } \n "
@@ -276,20 +378,25 @@ def __call__(self, need, all_needs: dict) -> str:
276378 return gen_header () + structure_text + link_text
277379
278380
381+ class draw_full_module :
382+ def __repr__ (self ):
383+ return "draw_full_module" + " in " + scripts_directory_hash ()
384+
385+ def __call__ (self , need , all_needs ) -> str :
386+ structure_text , linkage_text = draw_module (need , all_needs )
387+
388+ return gen_header () + structure_text + linkage_text
389+
390+
279391class draw_full_component :
280392 def __repr__ (self ):
281393 return "draw_full_component" + " in " + scripts_directory_hash ()
282394
283395 def __call__ (self , need , all_needs ) -> str :
284396 structure_text , linkage_text , processed_interfaces , logical_interfacelist = (
285- draw_component (need , all_needs , dict (), dict ())
397+ draw_comp_incl_impl_int (need , all_needs , dict (), dict ())
286398 )
287399
288- # Draw Logical Interfaces
289- for iface in logical_interfacelist :
290- if log_int := logical_interfacelist [iface ]:
291- structure_text += gen_interface_element (log_int , all_needs , True )
292-
293400 return gen_header () + structure_text + linkage_text
294401
295402
@@ -305,6 +412,7 @@ def __call__(self, need, all_needs) -> str:
305412
306413draw_uml_function_context = {
307414 "draw_interface" : draw_full_interface (),
415+ "draw_module" : draw_full_module (),
308416 "draw_component" : draw_full_component (),
309417 "draw_feature" : draw_full_feature (),
310418}
0 commit comments