lutaml 0.10.4 → 0.10.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (119) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +8 -0
  3. data/.rubocop.yml +10 -0
  4. data/.rubocop_todo.yml +218 -94
  5. data/TODO.cleanups/01-resolve-production-todos.md +65 -0
  6. data/TODO.cleanups/02-reduce-metrics-offenses.md +37 -0
  7. data/TODO.cleanups/03-reduce-rspec-multiple-expectations.md +54 -0
  8. data/TODO.cleanups/04-reduce-rspec-example-length.md +45 -0
  9. data/TODO.cleanups/05-replace-marshal-load.md +37 -0
  10. data/TODO.cleanups/06-replace-eval-in-tests.md +41 -0
  11. data/TODO.cleanups/07-fix-lint-offenses.md +74 -0
  12. data/TODO.cleanups/08-reduce-memoized-helpers-and-nesting.md +43 -0
  13. data/TODO.cleanups/09-reduce-verified-doubles-and-rspec-style.md +57 -0
  14. data/TODO.cleanups/10-split-large-files.md +47 -0
  15. data/bin/console +0 -1
  16. data/exe/lutaml +1 -0
  17. data/lib/lutaml/cli/element_identifier.rb +3 -6
  18. data/lib/lutaml/cli/interactive_shell/bookmark_commands.rb +88 -0
  19. data/lib/lutaml/cli/interactive_shell/command_base.rb +32 -0
  20. data/lib/lutaml/cli/interactive_shell/export_handler.rb +67 -0
  21. data/lib/lutaml/cli/interactive_shell/help_display.rb +114 -0
  22. data/lib/lutaml/cli/interactive_shell/navigation_commands.rb +135 -0
  23. data/lib/lutaml/cli/interactive_shell/query_commands.rb +185 -0
  24. data/lib/lutaml/cli/interactive_shell.rb +116 -802
  25. data/lib/lutaml/cli/uml/build_command.rb +5 -5
  26. data/lib/lutaml/cli/uml/verify_command.rb +0 -1
  27. data/lib/lutaml/converter/xmi_to_uml.rb +3 -153
  28. data/lib/lutaml/converter/xmi_to_uml_generalization.rb +193 -0
  29. data/lib/lutaml/formatter/graphviz.rb +1 -2
  30. data/lib/lutaml/qea/database.rb +1 -47
  31. data/lib/lutaml/qea/factory/association_builder.rb +188 -0
  32. data/lib/lutaml/qea/factory/base_transformer.rb +0 -1
  33. data/lib/lutaml/qea/factory/class_transformer.rb +40 -590
  34. data/lib/lutaml/qea/factory/diagram_transformer.rb +0 -3
  35. data/lib/lutaml/qea/factory/generalization_builder.rb +211 -0
  36. data/lib/lutaml/qea/factory/package_transformer.rb +1 -2
  37. data/lib/lutaml/qea/factory/stereotype_loader.rb +34 -0
  38. data/lib/lutaml/qea/lookup_indexes.rb +54 -0
  39. data/lib/lutaml/qea/models/ea_datatype.rb +0 -2
  40. data/lib/lutaml/qea/validation/validation_engine.rb +0 -2
  41. data/lib/lutaml/uml/has_members.rb +0 -1
  42. data/lib/lutaml/uml/inheritance_walker.rb +92 -0
  43. data/lib/lutaml/uml/model_helpers.rb +129 -0
  44. data/lib/lutaml/uml/node/attribute.rb +3 -1
  45. data/lib/lutaml/uml/node/class_node.rb +3 -3
  46. data/lib/lutaml/uml/operation.rb +2 -0
  47. data/lib/lutaml/uml_repository/class_lookup_index.rb +40 -0
  48. data/lib/lutaml/uml_repository/exporters/markdown/class_page_builder.rb +179 -0
  49. data/lib/lutaml/uml_repository/exporters/markdown/formatting.rb +36 -0
  50. data/lib/lutaml/uml_repository/exporters/markdown/index_page_builder.rb +73 -0
  51. data/lib/lutaml/uml_repository/exporters/markdown/link_resolver.rb +40 -0
  52. data/lib/lutaml/uml_repository/exporters/markdown/package_page_builder.rb +107 -0
  53. data/lib/lutaml/uml_repository/exporters/markdown_exporter.rb +26 -538
  54. data/lib/lutaml/uml_repository/index_builder.rb +3 -271
  55. data/lib/lutaml/uml_repository/index_builders/association_index.rb +141 -0
  56. data/lib/lutaml/uml_repository/index_builders/class_index.rb +94 -0
  57. data/lib/lutaml/uml_repository/index_builders/package_index.rb +57 -0
  58. data/lib/lutaml/uml_repository/package_exporter.rb +10 -20
  59. data/lib/lutaml/uml_repository/package_loader.rb +37 -17
  60. data/lib/lutaml/uml_repository/repository/deprecated.rb +39 -0
  61. data/lib/lutaml/uml_repository/repository/loader.rb +112 -0
  62. data/lib/lutaml/uml_repository/repository.rb +7 -57
  63. data/lib/lutaml/uml_repository/static_site/association_serialization.rb +142 -0
  64. data/lib/lutaml/uml_repository/static_site/configuration.rb +0 -2
  65. data/lib/lutaml/uml_repository/static_site/data_transformer.rb +52 -873
  66. data/lib/lutaml/uml_repository/static_site/generator.rb +29 -8
  67. data/lib/lutaml/uml_repository/static_site/search_index_builder.rb +1 -4
  68. data/lib/lutaml/uml_repository/static_site/serializers/attribute_serializer.rb +78 -0
  69. data/lib/lutaml/uml_repository/static_site/serializers/class_serializer.rb +124 -0
  70. data/lib/lutaml/uml_repository/static_site/serializers/diagram_serializer.rb +60 -0
  71. data/lib/lutaml/uml_repository/static_site/serializers/inheritance_resolver.rb +258 -0
  72. data/lib/lutaml/uml_repository/static_site/serializers/metadata_builder.rb +48 -0
  73. data/lib/lutaml/uml_repository/static_site/serializers/operation_serializer.rb +57 -0
  74. data/lib/lutaml/uml_repository/static_site/serializers/package_serializer.rb +94 -0
  75. data/lib/lutaml/uml_repository/static_site/serializers/package_tree_builder.rb +93 -0
  76. data/lib/lutaml/version.rb +1 -1
  77. data/lib/lutaml/xmi/liquid_drops/association_drop.rb +13 -35
  78. data/lib/lutaml/xmi/liquid_drops/attribute_drop.rb +12 -18
  79. data/lib/lutaml/xmi/liquid_drops/cardinality_drop.rb +14 -6
  80. data/lib/lutaml/xmi/liquid_drops/connector_drop.rb +0 -3
  81. data/lib/lutaml/xmi/liquid_drops/constraint_drop.rb +1 -3
  82. data/lib/lutaml/xmi/liquid_drops/data_type_drop.rb +13 -70
  83. data/lib/lutaml/xmi/liquid_drops/dependency_drop.rb +2 -5
  84. data/lib/lutaml/xmi/liquid_drops/diagram_drop.rb +5 -11
  85. data/lib/lutaml/xmi/liquid_drops/enum_drop.rb +8 -16
  86. data/lib/lutaml/xmi/liquid_drops/enum_owned_literal_drop.rb +3 -9
  87. data/lib/lutaml/xmi/liquid_drops/generalization_attribute_drop.rb +11 -13
  88. data/lib/lutaml/xmi/liquid_drops/generalization_drop.rb +27 -85
  89. data/lib/lutaml/xmi/liquid_drops/klass_drop.rb +39 -91
  90. data/lib/lutaml/xmi/liquid_drops/operation_drop.rb +3 -9
  91. data/lib/lutaml/xmi/liquid_drops/package_drop.rb +16 -44
  92. data/lib/lutaml/xmi/liquid_drops/root_drop.rb +3 -11
  93. data/lib/lutaml/xmi/liquid_drops/source_target_drop.rb +2 -5
  94. data/lib/lutaml/xmi/parsers/xmi_base.rb +2 -749
  95. data/lib/lutaml/xmi/parsers/xmi_class_members.rb +45 -0
  96. data/lib/lutaml/xmi/parsers/xmi_connector.rb +251 -0
  97. data/lib/lutaml/xmi/parsers/xml.rb +7 -120
  98. data/lib/lutaml/xmi/xmi_lookup_service.rb +42 -0
  99. data/lib/lutaml.rb +0 -1
  100. metadata +48 -21
  101. data/lib/lutaml/cli/commands/base_command.rb +0 -118
  102. data/lib/lutaml/command_line.rb +0 -272
  103. data/lib/lutaml/sysml/allocate.rb +0 -9
  104. data/lib/lutaml/sysml/allocated.rb +0 -9
  105. data/lib/lutaml/sysml/binding_connector.rb +0 -9
  106. data/lib/lutaml/sysml/block.rb +0 -32
  107. data/lib/lutaml/sysml/constraint_block.rb +0 -14
  108. data/lib/lutaml/sysml/copy.rb +0 -8
  109. data/lib/lutaml/sysml/derive_requirement.rb +0 -9
  110. data/lib/lutaml/sysml/nested_connector_end.rb +0 -13
  111. data/lib/lutaml/sysml/refine.rb +0 -9
  112. data/lib/lutaml/sysml/requirement.rb +0 -44
  113. data/lib/lutaml/sysml/requirement_related.rb +0 -9
  114. data/lib/lutaml/sysml/satisfy.rb +0 -9
  115. data/lib/lutaml/sysml/test_case.rb +0 -25
  116. data/lib/lutaml/sysml/trace.rb +0 -9
  117. data/lib/lutaml/sysml/verify.rb +0 -8
  118. data/lib/lutaml/sysml/xmi_file.rb +0 -486
  119. data/lib/lutaml/sysml.rb +0 -11
@@ -4,6 +4,8 @@ require "nokogiri"
4
4
  require "htmlentities"
5
5
  require "xmi"
6
6
  require "digest"
7
+ require_relative "xmi_connector"
8
+ require_relative "xmi_class_members"
7
9
 
8
10
  module Lutaml
9
11
  module Xmi
@@ -46,74 +48,6 @@ module Lutaml
46
48
 
47
49
  private
48
50
 
49
- # @param xmi_model [Lutaml::Model::Serializable]
50
- # @param with_gen: [Boolean]
51
- # @param with_absolute_path: [Boolean]
52
- # @return [Hash]
53
- # @note xpath: //uml:Model[@xmi:type="uml:Model"]
54
- def serialize_to_hash(xmi_model,
55
- with_gen: false, with_absolute_path: false)
56
- model = xmi_model.model
57
- {
58
- name: model.name,
59
- packages: serialize_model_packages(
60
- model,
61
- with_gen: with_gen,
62
- with_absolute_path: with_absolute_path,
63
- ),
64
- }
65
- end
66
-
67
- # @param model [Lutaml::Model::Serializable]
68
- # @param with_gen: [Boolean]
69
- # @param with_absolute_path: [Boolean]
70
- # @param absolute_path: [String]
71
- # @return [Array<Hash>]
72
- # @note xpath ./packagedElement[@xmi:type="uml:Package"]
73
- def serialize_model_packages(model, # rubocop:disable Metrics/AbcSize,Metrics/MethodLength
74
- with_gen: false, with_absolute_path: false, absolute_path: "")
75
- packages = model.packaged_element.select do |e|
76
- e.type?("uml:Package")
77
- end
78
-
79
- if with_absolute_path
80
- absolute_path = "#{absolute_path}::#{model.name}"
81
- end
82
-
83
- packages.map do |package| # rubocop:disable Metrics/BlockLength
84
- h = {
85
- xmi_id: package.id,
86
- name: get_package_name(package),
87
- classes: serialize_model_classes(
88
- package, model,
89
- with_gen: with_gen,
90
- with_absolute_path: with_absolute_path,
91
- absolute_path: "#{absolute_path}::#{package.name}"
92
- ),
93
- enums: serialize_model_enums(package),
94
- data_types: serialize_model_data_types(package),
95
- diagrams: serialize_model_diagrams(
96
- package.id,
97
- with_package: with_gen,
98
- ),
99
- packages: serialize_model_packages(
100
- package,
101
- with_gen: with_gen,
102
- with_absolute_path: with_absolute_path,
103
- absolute_path: absolute_path,
104
- ),
105
- definition: doc_node_attribute_value(package.id, "documentation"),
106
- stereotype: doc_node_attribute_value(package.id, "stereotype"),
107
- }
108
-
109
- if with_absolute_path
110
- h[:absolute_path] = "#{absolute_path}::#{package.name}"
111
- end
112
-
113
- h
114
- end
115
- end
116
-
117
51
  # @param package [Lutaml::Model::Serializable]
118
52
  # @return [String]
119
53
  def get_package_name(package) # rubocop:disable Metrics/AbcSize
@@ -128,155 +62,6 @@ module Lutaml
128
62
  "unnamed"
129
63
  end
130
64
 
131
- # @param package [Lutaml::Model::Serializable]
132
- # @param model [Lutaml::Model::Serializable]
133
- # @param with_gen: [Boolean]
134
- # @param with_absolute_path: [Boolean]
135
- # @return [Array<Hash>]
136
- # @note xpath ./packagedElement[@xmi:type="uml:Class" or
137
- # @xmi:type="uml:AssociationClass"]
138
- def serialize_model_classes(package, model, # rubocop:disable Metrics/MethodLength
139
- with_gen: false, with_absolute_path: false, absolute_path: "")
140
- klasses = package.packaged_element.select do |e|
141
- e.type?("uml:Class") || e.type?("uml:AssociationClass") ||
142
- e.type?("uml:Interface")
143
- end
144
-
145
- klasses.map do |klass|
146
- build_klass_hash(
147
- klass, model,
148
- with_gen: with_gen,
149
- with_absolute_path: with_absolute_path,
150
- absolute_path: absolute_path
151
- )
152
- end
153
- end
154
-
155
- # @param klass [Lutaml::Model::Serializable]
156
- # @param model [Lutaml::Model::Serializable]
157
- # @param with_gen: [Boolean]
158
- # @param with_absolute_path: [Boolean]
159
- # @return [Hash]
160
- def build_klass_hash(klass, model, # rubocop:disable Metrics/AbcSize,Metrics/MethodLength,Metrics/CyclomaticComplexity
161
- with_gen: false, with_absolute_path: false, absolute_path: "")
162
- klass_hash = {
163
- xmi_id: klass.id,
164
- name: klass.name,
165
- package: model,
166
- type: klass.type.split(":").last,
167
- attributes: serialize_class_attributes(klass),
168
- associations: serialize_model_associations(klass.id),
169
- operations: serialize_class_operations(klass),
170
- constraints: serialize_class_constraints(klass.id),
171
- is_abstract: doc_node_attribute_value(klass.id, "isAbstract"),
172
- definition: doc_node_attribute_value(klass.id, "documentation"),
173
- stereotype: doc_node_attribute_value(klass.id, "stereotype"),
174
- }
175
-
176
- klass_hash[:absolute_path] = absolute_path if with_absolute_path
177
-
178
- if with_gen && klass.type?("uml:Class")
179
- klass_hash[:generalization] = serialize_generalization(klass)
180
- end
181
-
182
- if klass.generalization && !klass.generalization.empty?
183
- klass_hash[:association_generalization] = []
184
- klass.generalization.each do |gen|
185
- klass_hash[:association_generalization] << {
186
- id: gen.id,
187
- type: gen.type,
188
- general: gen.general,
189
- }
190
- end
191
- end
192
-
193
- klass_hash
194
- end
195
-
196
- # @param klass [Lutaml::Model::Serializable]
197
- # # @return [Hash]
198
- def serialize_generalization(klass, options = {})
199
- general_hash, next_general_node_id = get_top_level_general_hash(
200
- klass, options
201
- )
202
- return general_hash unless next_general_node_id
203
-
204
- general_hash[:general] = serialize_generalization_attributes(
205
- next_general_node_id, options
206
- )
207
-
208
- general_hash
209
- end
210
-
211
- # @param klass [Lutaml::Model::Serializable]
212
- # @return [Array<Hash>]
213
- def get_top_level_general_hash(klass, options = {}) # rubocop:disable Metrics/AbcSize,Metrics/MethodLength
214
- general_hash, next_general_node_id = get_general_hash(
215
- klass.id, options
216
- )
217
- general_hash[:name] = klass.name
218
- general_hash[:type] = klass.type
219
- general_hash[:definition] =
220
- lookup_element_prop_documentation(klass.id)
221
- general_hash[:stereotype] = doc_node_attribute_value(
222
- klass.id, "stereotype"
223
- )
224
-
225
- [general_hash, next_general_node_id]
226
- end
227
-
228
- # @param xmi_id [String]
229
- # @param model [Lutaml::Model::Serializable]
230
- # @return [Array<Hash>]
231
- # @note get generalization node and its owned attributes
232
- def serialize_generalization_attributes(general_id, options = {}) # rubocop:disable Metrics/AbcSize,Metrics/MethodLength
233
- general_hash, next_general_node_id = get_general_hash(general_id,
234
- options)
235
-
236
- if next_general_node_id
237
- general_hash[:general] = serialize_generalization_attributes(
238
- next_general_node_id, options
239
- )
240
- end
241
-
242
- general_hash
243
- end
244
-
245
- # @param general_node [Lutaml::Model::Serializable]
246
- # @return [Hash]
247
- def get_general_attributes(general_node)
248
- serialize_class_attributes(general_node, with_assoc: true)
249
- end
250
-
251
- # @param general_node [Lutaml::Model::Serializable]
252
- # @return [String]
253
- def get_next_general_node_id(general_node)
254
- general_node.generalization.first&.general
255
- end
256
-
257
- # @param general_id [String]
258
- # @return [Array<Hash>]
259
- def get_general_hash(general_id, options = {}) # rubocop:disable Metrics/AbcSize,Metrics/MethodLength
260
- general_node = find_packaged_element_by_id(general_id)
261
- return [] unless general_node
262
-
263
- general_node_attrs = get_general_attributes(general_node)
264
- general_upper_klass = find_upper_level_packaged_element(general_id)
265
- next_general_node_id = get_next_general_node_id(general_node)
266
-
267
- [
268
- {
269
- general_id: general_id,
270
- general_name: general_node.name,
271
- general_attributes: general_node_attrs,
272
- general_upper_klass: ::Lutaml::Xmi::LiquidDrops::PackageDrop
273
- .new(general_upper_klass, nil, options),
274
- general: {},
275
- },
276
- next_general_node_id,
277
- ]
278
- end
279
-
280
65
  # @param id [String]
281
66
  # @return [Lutaml::Model::Serializable]
282
67
  def find_packaged_element_by_id(id)
@@ -419,477 +204,6 @@ module Lutaml
419
204
  xmi_index.packaged_elements.find { |e| e.name == name }
420
205
  end
421
206
 
422
- # @param package [Lutaml::Model::Serializable]
423
- # @return [Array<Hash>]
424
- # @note xpath ./packagedElement[@xmi:type="uml:Enumeration"]
425
- def serialize_model_enums(package) # rubocop:disable Metrics/MethodLength
426
- enums = package.packaged_element.select do |e|
427
- e.type?("uml:Enumeration")
428
- end
429
-
430
- enums.map do |enum|
431
- {
432
- xmi_id: enum.id,
433
- name: enum.name,
434
- values: serialize_enum_owned_literal(enum),
435
- definition: doc_node_attribute_value(enum.id, "documentation"),
436
- stereotype: doc_node_attribute_value(enum.id, "stereotype"),
437
- }
438
- end
439
- end
440
-
441
- # @param model [Lutaml::Model::Serializable]
442
- # @return [Hash]
443
- # @note xpath .//ownedLiteral[@xmi:type="uml:EnumerationLiteral"]
444
- def serialize_enum_owned_literal(enum) # rubocop:disable Metrics/MethodLength
445
- owned_literals = enum.owned_literal.select do |owned_literal|
446
- owned_literal.type? "uml:EnumerationLiteral"
447
- end
448
-
449
- owned_literals.map do |owned_literal|
450
- # xpath .//type
451
- uml_type_id = owned_literal&.uml_type&.idref
452
-
453
- {
454
- name: owned_literal.name,
455
- type: lookup_entity_name(uml_type_id) || uml_type_id,
456
- definition: lookup_attribute_documentation(owned_literal.id),
457
- }
458
- end
459
- end
460
-
461
- # @param model [Lutaml::Model::Serializable]
462
- # @return [Array<Hash>]
463
- # @note xpath ./packagedElement[@xmi:type="uml:DataType"]
464
- def serialize_model_data_types(model) # rubocop:disable Metrics/AbcSize,Metrics/MethodLength
465
- all_data_type_elements = []
466
- select_all_packaged_elements(
467
- all_data_type_elements, model, "uml:DataType"
468
- )
469
- all_data_type_elements.map do |klass|
470
- {
471
- xmi_id: klass.id,
472
- name: klass.name,
473
- attributes: serialize_class_attributes(klass),
474
- operations: serialize_class_operations(klass),
475
- associations: serialize_model_associations(klass.id),
476
- constraints: serialize_class_constraints(klass.id),
477
- is_abstract: doc_node_attribute_value(klass.id, "isAbstract"),
478
- definition: doc_node_attribute_value(klass.id, "documentation"),
479
- stereotype: doc_node_attribute_value(klass.id, "stereotype"),
480
- }
481
- end
482
- end
483
-
484
- # @param node_id [String]
485
- # @return [Array<Hash>]
486
- # @note xpath %(//diagrams/diagram/model[@package="#{node['xmi:id']}"])
487
- def serialize_model_diagrams(node_id, with_package: false) # rubocop:disable Metrics/AbcSize,Metrics/MethodLength
488
- diagrams = diagram_lookup[node_id]
489
-
490
- diagrams.map do |diagram|
491
- h = {
492
- xmi_id: diagram.id,
493
- name: diagram.properties.name,
494
- definition: diagram.properties.documentation,
495
- }
496
-
497
- if with_package
498
- package_id = diagram.model.package
499
- h[:package_id] = package_id
500
- h[:package_name] = find_packaged_element_by_id(package_id)&.name
501
- end
502
-
503
- h
504
- end
505
- end
506
-
507
- # Lazy-built hash index for O(1) diagram lookups by package
508
- # @return [Hash] Mapping of package_id => [diagrams]
509
- def diagram_lookup
510
- @diagram_lookup ||= begin
511
- idx = Hash.new { |h, k| h[k] = [] }
512
- diagrams = @xmi_root_model.extension&.diagrams&.diagram || []
513
- diagrams.each { |d| idx[d.model.package] << d if d.model&.package }
514
- idx
515
- end
516
- end
517
-
518
- # @param xmi_id [String]
519
- # @return [Array<Hash>]
520
- # @note xpath %(//element[@xmi:idref="#{xmi_id}"]/links/*)
521
- def serialize_model_associations(xmi_id) # rubocop:disable Metrics/AbcSize,Metrics/CyclomaticComplexity,Metrics/MethodLength,Metrics/PerceivedComplexity
522
- matched_element = xmi_index.find_element(xmi_id)
523
-
524
- return unless matched_element&.links&.any?
525
-
526
- links = []
527
- matched_element.links.each do |link|
528
- links << link.association if link.association.any?
529
- end
530
-
531
- links.flatten.compact.map do |assoc|
532
- link_member = assoc.start == xmi_id ? "end" : "start"
533
- linke_owner_name = link_member == "start" ? "end" : "start"
534
-
535
- member_end, member_end_type, member_end_cardinality,
536
- member_end_attribute_name, member_end_xmi_id =
537
- serialize_member_type(xmi_id, assoc, link_member)
538
-
539
- owner_end = serialize_owned_type(xmi_id, assoc, linke_owner_name)
540
-
541
- if member_end && ((member_end_type != "aggregation") ||
542
- (member_end_type == "aggregation" && member_end_attribute_name))
543
-
544
- doc_node_name = (link_member == "start" ? "source" : "target")
545
- definition = fetch_definition_node_value(assoc.id, doc_node_name)
546
-
547
- {
548
- xmi_id: assoc.id,
549
- member_end: member_end,
550
- member_end_type: member_end_type,
551
- member_end_cardinality: member_end_cardinality,
552
- member_end_attribute_name: member_end_attribute_name,
553
- member_end_xmi_id: member_end_xmi_id,
554
- owner_end: owner_end,
555
- owner_end_xmi_id: xmi_id,
556
- definition: definition,
557
- }
558
- end
559
- end
560
- end
561
-
562
- # @param link_id [String]
563
- # @return [Lutaml::Model::Serializable]
564
- # @note xpath %(//connector[@xmi:idref="#{link_id}"])
565
- def fetch_connector(link_id)
566
- xmi_index.find_connector(link_id)
567
- end
568
-
569
- # @param link_id [String]
570
- # @param node_name [String] source or target
571
- # @return [String]
572
- # @note xpath
573
- # %(//connector[@xmi:idref="#{link_id}"]/#{node_name}/documentation)
574
- def fetch_definition_node_value(link_id, node_name)
575
- connector_node = fetch_connector(link_id)
576
- return nil unless connector_node
577
-
578
- node = connector_node.send(node_name.to_sym)
579
- return nil unless node
580
-
581
- documentation = node.documentation
582
-
583
- if documentation.is_a?(::Xmi::Sparx::Element::Documentation)
584
- documentation&.value
585
- else
586
- documentation
587
- end
588
- end
589
-
590
- # @param klass [Lutaml::Model::Serializable]
591
- # @return [Array<Hash>]
592
- # @note xpath .//ownedOperation
593
- def serialize_class_operations(klass) # rubocop:disable Metrics/MethodLength
594
- klass.owned_operation.filter_map do |operation|
595
- uml_type = operation.uml_type.first
596
- uml_type_idref = uml_type.idref if uml_type
597
-
598
- if operation.association.nil?
599
- {
600
- id: operation.id,
601
- xmi_id: uml_type_idref,
602
- name: operation.name,
603
- definition: lookup_attribute_documentation(operation.id),
604
- }
605
- end
606
- end
607
- end
608
-
609
- # @param klass_id [String]
610
- # @return [Array<Hash>]
611
- # @note xpath ./constraints/constraint
612
- def serialize_class_constraints(klass_id) # rubocop:disable Metrics/MethodLength
613
- connector_node = fetch_connector(klass_id)
614
-
615
- if connector_node
616
- # In ea-xmi-2.5.1, constraints are moved to source/target under
617
- # connectors
618
- constraints = %i[source target].map do |st|
619
- connector_node.send(st).constraints.constraint
620
- end.flatten
621
-
622
- constraints.map do |constraint|
623
- {
624
- name: HTMLEntities.new.decode(constraint.name),
625
- type: constraint.type,
626
- weight: constraint.weight,
627
- status: constraint.status,
628
- }
629
- end
630
- end
631
- end
632
-
633
- # @param owner_xmi_id [String]
634
- # @param link [Lutaml::Model::Serializable]
635
- # @param link_member_name [String]
636
- # @return [String]
637
- def serialize_owned_type(owner_xmi_id, link, linke_owner_name)
638
- case link
639
- when ::Xmi::Sparx::Element::NoteLink
640
- return
641
- when ::Xmi::Sparx::Element::Generalization
642
- owner_end, _owner_end_type, _owner_xmi_id =
643
- generalization_association(owner_xmi_id, link)
644
- return owner_end
645
- end
646
-
647
- xmi_id = link.send(linke_owner_name.to_sym)
648
- lookup_entity_name(xmi_id) || connector_source_name(xmi_id)
649
-
650
- # not necessary
651
- # if link.name == "Association"
652
- # owned_cardinality, owned_attribute_name =
653
- # fetch_assoc_connector(link.id, "source")
654
- # else
655
- # owned_cardinality, owned_attribute_name =
656
- # fetch_owned_attribute_node(xmi_id)
657
- # end
658
- # [owner_end, owned_cardinality, owned_attribute_name]
659
- # owner_end
660
- end
661
-
662
- # @param owner_xmi_id [String]
663
- # @param link [Lutaml::Model::Serializable]
664
- # @return [Array<String, String>]
665
- def serialize_member_end(owner_xmi_id, link) # rubocop:disable Metrics/MethodLength,Metrics/AbcSize,Metrics/CyclomaticComplexity
666
- case link.name
667
- when "NoteLink"
668
- return
669
- when "Generalization"
670
- return generalization_association(owner_xmi_id, link)
671
- end
672
-
673
- xmi_id = link.start
674
- source_or_target = :source
675
-
676
- if link.start == owner_xmi_id
677
- xmi_id = link.end
678
- source_or_target = :target
679
- end
680
-
681
- connector = fetch_connector(link.id)
682
- ea_type = connector&.properties&.ea_type
683
- member_end_type = ea_type&.downcase
684
-
685
- member_end = member_end_name(xmi_id, source_or_target, link)
686
- [member_end, member_end_type, xmi_id]
687
- end
688
-
689
- # @param xmi_id [String]
690
- # @param source_or_target [Symbol]
691
- # @return [String]
692
- def member_end_name(xmi_id, source_or_target, link) # rubocop:disable Metrics/MethodLength
693
- connector_label = connector_labels(xmi_id, source_or_target)
694
- entity_name = lookup_entity_name(xmi_id)
695
- connector_name = connector_name_by_source_or_target(
696
- xmi_id, source_or_target
697
- )
698
-
699
- case link
700
- when ::Xmi::Sparx::Element::Aggregation
701
- connector_label || entity_name || connector_name
702
- else
703
- entity_name || connector_name
704
- end
705
- end
706
-
707
- # @param owner_xmi_id [String]
708
- # @param link [Lutaml::Model::Serializable]
709
- # @param link_member_name [String]
710
- # @return [Array<String, String, Hash, String, String>]
711
- def serialize_member_type(owner_xmi_id, link, link_member_name) # rubocop:disable Metrics/MethodLength,Metrics/AbcSize
712
- member_end, member_end_type, xmi_id =
713
- serialize_member_end(owner_xmi_id, link)
714
-
715
- if link.is_a?(::Xmi::Sparx::Element::Association)
716
- connector_type = link_member_name == "start" ? "source" : "target"
717
- member_end_cardinality, member_end_attribute_name =
718
- fetch_assoc_connector(link.id, connector_type)
719
- else
720
- member_end_cardinality, member_end_attribute_name =
721
- fetch_owned_attribute_node(xmi_id)
722
- end
723
-
724
- if fetch_connector_name(link.id)
725
- member_end = fetch_connector_name(link.id)
726
- end
727
-
728
- [member_end, member_end_type, member_end_cardinality,
729
- member_end_attribute_name, xmi_id]
730
- end
731
-
732
- def fetch_connector_name(link_id)
733
- connector = fetch_connector(link_id)
734
- connector&.name
735
- end
736
-
737
- # @param link_id [String]
738
- # @param connector_type [String]
739
- # @return [Array<Hash, String>]
740
- # @note xpath %(//connector[@xmi:idref="#{link_id}"]/#{connector_type})
741
- def fetch_assoc_connector(link_id, connector_type) # rubocop:disable Metrics/AbcSize,Metrics/MethodLength,Metrics/CyclomaticComplexity,Metrics/PerceivedComplexity
742
- connector = fetch_connector(link_id)
743
- return [nil, nil] unless connector
744
-
745
- assoc_connector = connector.send(connector_type.to_sym)
746
-
747
- if assoc_connector
748
- assoc_connector_type = assoc_connector.type
749
- if assoc_connector_type&.multiplicity
750
- cardinality = assoc_connector_type.multiplicity.split("..")
751
- cardinality.unshift("1") if cardinality.length == 1
752
- min, max = cardinality
753
- end
754
-
755
- assoc_connector_role = assoc_connector.role
756
- attribute_name = assoc_connector.model.name if assoc_connector_role
757
- cardinality = cardinality_min_max_value(min, max)
758
- end
759
-
760
- [cardinality, attribute_name]
761
- end
762
-
763
- # @param owner_xmi_id [String]
764
- # @param link [Lutaml::Model::Serializable]
765
- # @return [Array<String, String, Hash, String, String>]
766
- # @note match return value of serialize_member_type
767
- def generalization_association(owner_xmi_id, link) # rubocop:disable Metrics/MethodLength
768
- member_end_type = "generalization"
769
- xmi_id = link.start
770
- source_or_target = :source
771
-
772
- if link.start == owner_xmi_id
773
- member_end_type = "inheritance"
774
- xmi_id = link.end
775
- source_or_target = :target
776
- end
777
-
778
- member_end = member_end_name(xmi_id, source_or_target, link)
779
-
780
- # member_end_cardinality, _member_end_attribute_name =
781
- # fetch_owned_attribute_node(xmi_id)
782
- # [member_end, member_end_type, member_end_cardinality, nil, xmi_id]
783
- [member_end, member_end_type, xmi_id]
784
- end
785
-
786
- # Multiple items if search type is idref. Should search association?
787
- # @param xmi_id [String]
788
- # @return [Array<Hash, String>]
789
- # @note xpath
790
- # %(//ownedAttribute[@association]/type[@xmi:idref="#{xmi_id}"])
791
- def fetch_owned_attribute_node(xmi_id)
792
- oa = xmi_index.find_owned_attrs_by_type(xmi_id)
793
- .find { |a| !!a.association }
794
-
795
- if oa
796
- cardinality = cardinality_min_max_value(
797
- oa.lower_value&.value, oa.upper_value&.value
798
- )
799
- oa_name = oa.name
800
- end
801
-
802
- [cardinality, oa_name]
803
- end
804
-
805
- # @param klass_id [String]
806
- # @return [Lutaml::Model::Serializable]
807
- # @note xpath %(//element[@xmi:idref="#{klass['xmi:id']}"])
808
- def fetch_element(klass_id)
809
- xmi_index.find_element(klass_id)
810
- end
811
-
812
- # @param klass [Lutaml::Model::Serializable]
813
- # @param with_assoc [Boolean]
814
- # @return [Array<Hash>]
815
- # @note xpath .//ownedAttribute[@xmi:type="uml:Property"]
816
- def serialize_class_attributes(klass, with_assoc: false) # rubocop:disable Metrics/AbcSize,Metrics/CyclomaticComplexity,Metrics/MethodLength
817
- owned_attributes = klass.owned_attribute.select do |attr|
818
- attr.type?("uml:Property")
819
- end
820
-
821
- owned_attributes.filter_map do |oa|
822
- if with_assoc || oa.association.nil?
823
- attrs = build_class_attributes(oa)
824
-
825
- if with_assoc && oa.association
826
- attrs[:association] = oa.association
827
- attrs[:definition] = loopup_assoc_def(oa.association)
828
- attrs[:type_ns] = get_ns_by_xmi_id(attrs[:xmi_id])
829
- end
830
-
831
- attrs
832
- end
833
- end
834
- end
835
-
836
- def loopup_assoc_def(association)
837
- connector = fetch_connector(association)
838
- connector&.documentation&.value
839
- end
840
-
841
- # @param type [String]
842
- # @return [String]
843
- def get_ns_by_type(type)
844
- return unless type
845
-
846
- p = find_klass_packaged_element_by_name(type)
847
- return unless p
848
-
849
- find_upper_level_packaged_element(p.id)&.name
850
- end
851
-
852
- # @param xmi_id [String]
853
- # @return [String]
854
- def get_ns_by_xmi_id(xmi_id)
855
- return unless xmi_id
856
-
857
- p = find_packaged_element_by_id(xmi_id)
858
- return unless p
859
-
860
- find_upper_level_packaged_element(p.id)&.name
861
- end
862
-
863
- # @param klass_id [String]
864
- # @return [Array<Hash>]
865
- def build_class_attributes(owned_attr) # rubocop:disable Metrics/MethodLength
866
- uml_type = owned_attr.uml_type
867
- uml_type_idref = uml_type.idref if uml_type
868
-
869
- {
870
- id: owned_attr.id,
871
- name: owned_attr.name,
872
- type: lookup_entity_name(uml_type_idref) || uml_type_idref,
873
- xmi_id: uml_type_idref,
874
- is_derived: owned_attr.is_derived,
875
- cardinality: cardinality_min_max_value(
876
- owned_attr.lower_value&.value,
877
- owned_attr.upper_value&.value,
878
- ),
879
- definition: lookup_attribute_documentation(owned_attr.id),
880
- }
881
- end
882
-
883
- # @param min [String]
884
- # @param max [String]
885
- # @return [Hash]
886
- def cardinality_min_max_value(min, max)
887
- {
888
- min: min,
889
- max: max,
890
- }
891
- end
892
-
893
207
  # @node [Lutaml::Model::Serializable]
894
208
  # @attr_name [String]
895
209
  # @return [String]
@@ -937,67 +251,6 @@ module Lutaml
937
251
  @id_name_mapping[xmi_id]
938
252
  end
939
253
 
940
- # @param xmi_id [String]
941
- # @param source_or_target [String]
942
- # @return [String]
943
- def connector_node_by_id(xmi_id, source_or_target)
944
- connector_lookup[[source_or_target.to_sym, xmi_id]]
945
- end
946
-
947
- # Lazy-built hash index for O(1) connector lookups
948
- # @return [Hash] Mapping of [direction, idref] => connector
949
- def connector_lookup
950
- @connector_lookup ||= begin
951
- lookup = {}
952
- connectors = @xmi_root_model.extension&.connectors&.connector || []
953
- connectors.each do |con|
954
- %i[source target].each do |dir|
955
- idref = con.send(dir)&.idref
956
- lookup[[dir, idref]] = con if idref
957
- end
958
- end
959
- lookup
960
- end
961
- end
962
-
963
- # @param xmi_id [String]
964
- # @param source_or_target [String]
965
- # @return [String]
966
- def connector_name_by_source_or_target(xmi_id, source_or_target) # rubocop:disable Metrics/AbcSize
967
- node = connector_node_by_id(xmi_id, source_or_target)
968
- return node.name if node&.name
969
-
970
- return if node.nil? ||
971
- node.send(source_or_target.to_sym).nil? ||
972
- node.send(source_or_target.to_sym).model.nil?
973
-
974
- node.send(source_or_target.to_sym).model.name
975
- end
976
-
977
- # @param xmi_id [String]
978
- # @param source_or_target [String]
979
- # @return [String]
980
- def connector_labels(xmi_id, source_or_target)
981
- node = connector_node_by_id(xmi_id, source_or_target)
982
- return if node.nil?
983
-
984
- node.labels&.rt || node.labels&.lt
985
- end
986
-
987
- # @param xmi_id [String]
988
- # @return [String]
989
- # @note xpath %(//source[@xmi:idref="#{xmi_id}"]/model)
990
- def connector_source_name(xmi_id)
991
- connector_name_by_source_or_target(xmi_id, :source)
992
- end
993
-
994
- # @param xmi_id [String]
995
- # @return [String]
996
- # @note xpath %(//target[@xmi:idref="#{xmi_id}"]/model)
997
- def connector_target_name(xmi_id)
998
- connector_name_by_source_or_target(xmi_id, :target)
999
- end
1000
-
1001
254
  # @note Removed: model_node_name_by_xmi_id - replaced by Xmi::Index
1002
255
 
1003
256
  # @return [Array<::Xmi::Uml::PackagedElement>]