ea 0.1.0 → 0.1.4
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.
- checksums.yaml +4 -4
- data/CLAUDE.md +125 -0
- data/Rakefile +12 -4
- data/TODO.next/00-publish-blocking-bugs.md +74 -0
- data/TODO.next/01-standalone-ea-gem-identity.md +76 -0
- data/TODO.next/02-optional-lutaml-uml-dependency.md +47 -0
- data/TODO.next/03-slim-lutaml-uml.md +79 -0
- data/TODO.next/04-loader-registry-for-uml-repository.md +49 -0
- data/TODO.next/05-extract-shared-transformer-methods.md +14 -0
- data/TODO.next/06-deduplicate-stereotype-loading.md +17 -0
- data/TODO.next/07-transformer-registry-in-factory.md +20 -0
- data/TODO.next/08-connector-type-registry.md +27 -0
- data/TODO.next/09-element-renderer-registry.md +29 -0
- data/TODO.next/10-connector-renderer-lsp.md +18 -0
- data/TODO.next/11-consolidate-style-knowledge.md +33 -0
- data/TODO.next/12-data-driven-from-db-row.md +24 -0
- data/TODO.next/13-extract-duplicated-methods.md +17 -0
- data/TODO.next/14-remove-dead-code.md +10 -0
- data/TODO.next/15-narrow-exception-handling.md +39 -0
- data/TODO.next/16-repository-indexes.md +28 -0
- data/TODO.next/17-fix-spec-quality-and-coverage.md +32 -0
- data/TODO.next/18-xmi-tool-specific-parser-architecture.md +172 -0
- data/TODO.next/19-fix-ea-gemspec-dependency-declarations.md +56 -0
- data/TODO.next/20-ci-requires-unreleased-lutaml-uml.md +63 -0
- data/TODO.next/21-qeatoxmi-via-xmi-gem.md +340 -0
- data/TODO.next/22-strip-respond-to-from-qeatoxmi-specs.md +32 -0
- data/TODO.next/23-cleanup-idallocator.md +41 -0
- data/TODO.next/24-tighten-parity-specs.md +42 -0
- data/TODO.next/25-sparx-eaid-format-for-synthesized-ids.md +62 -0
- data/TODO.next/26-fix-uppervalue-lowervalue-count-gap.md +51 -0
- data/TODO.next/27-extract-cardinality-module.md +68 -0
- data/TODO.next/28-extract-xml-sanitizer.md +51 -0
- data/TODO.next/29-ocp-registry-for-classifier-builders.md +58 -0
- data/TODO.next/30-struct-return-for-association-end.md +37 -0
- data/TODO.next/31-idallocator-specs.md +27 -0
- data/TODO.next/32-phase2-gap-sentinel-specs.md +53 -0
- data/TODO.next/33-normalize-lower-cleanup.md +30 -0
- data/TODO.next/34-document-member-end-order-rt-prefix.md +29 -0
- data/TODO.next/35-walk-runstate-for-instance-slots.md +76 -0
- data/TODO.next/36-wire-interface-realization.md +50 -0
- data/TODO.next/37-visibility-returns-real-booleans.md +36 -0
- data/config/diagram_styles.yml +200 -0
- data/config/model_transformations.yml +266 -0
- data/config/qea_schema.yml +1024 -0
- data/docs/ea_to_uml_type_mapping.md +89 -0
- data/docs/xmi_qea_conversion_capabilities.md +99 -0
- data/examples/lur/20251010_current_plateau_v5.1.lur +0 -0
- data/examples/lur/basic.lur +0 -0
- data/examples/lur/test-output.lur +0 -0
- data/examples/lur/test.lur +0 -0
- data/examples/lur_basic_usage.rb +221 -0
- data/examples/lur_cli_workflow.rb +263 -0
- data/examples/lur_statistics.rb +326 -0
- data/examples/qea/20251010_current_plateau_v5.1.qea +0 -0
- data/examples/qea/ArcGISWorkspace_template.qea +0 -0
- data/examples/qea/README_qea_parser.adoc +230 -0
- data/examples/qea/UmlModel_template.qea +0 -0
- data/examples/qea/basic.qea +0 -0
- data/examples/qea/simple.qea +0 -0
- data/examples/qea/simple_example.qea +0 -0
- data/examples/qea/test.qea +0 -0
- data/examples/qea_standalone_query.rb +73 -0
- data/examples/qea_to_repository.rb +51 -0
- data/examples/smoke_test_real_qea.rb +81 -0
- data/exe/ea +7 -0
- data/lib/ea/cli/app.rb +72 -0
- data/lib/ea/cli/command/base.rb +80 -0
- data/lib/ea/cli/command/convert.rb +62 -0
- data/lib/ea/cli/command/diagrams.rb +81 -0
- data/lib/ea/cli/command/list.rb +61 -0
- data/lib/ea/cli/command/parse.rb +29 -0
- data/lib/ea/cli/command/stats.rb +20 -0
- data/lib/ea/cli/command/validate.rb +41 -0
- data/lib/ea/cli/command.rb +15 -0
- data/lib/ea/cli/error.rb +34 -0
- data/lib/ea/cli/output/formatter.rb +34 -0
- data/lib/ea/cli/output/json_formatter.rb +20 -0
- data/lib/ea/cli/output/table_formatter.rb +42 -0
- data/lib/ea/cli/output/yaml_formatter.rb +20 -0
- data/lib/ea/cli/output.rb +56 -0
- data/lib/ea/cli.rb +17 -0
- data/lib/ea/diagram/configuration.rb +379 -0
- data/lib/ea/diagram/element_renderers/base_renderer.rb +77 -0
- data/lib/ea/diagram/element_renderers/class_renderer.rb +323 -0
- data/lib/ea/diagram/element_renderers/connector_renderer.rb +41 -0
- data/lib/ea/diagram/element_renderers/package_renderer.rb +61 -0
- data/lib/ea/diagram/element_renderers.rb +43 -0
- data/lib/ea/diagram/extractor.rb +560 -0
- data/lib/ea/diagram/layout_engine.rb +170 -0
- data/lib/ea/diagram/path_builder.rb +202 -0
- data/lib/ea/diagram/style_parser.rb +42 -0
- data/lib/ea/diagram/style_resolver.rb +276 -0
- data/lib/ea/diagram/svg_renderer.rb +274 -0
- data/lib/ea/diagram/util.rb +73 -0
- data/lib/ea/diagram.rb +47 -0
- data/lib/ea/qea/benchmark.rb +210 -0
- data/lib/ea/qea/database.rb +308 -0
- data/lib/ea/qea/factory/association_builder.rb +203 -0
- data/lib/ea/qea/factory/association_transformer.rb +91 -0
- data/lib/ea/qea/factory/attribute_tag_transformer.rb +57 -0
- data/lib/ea/qea/factory/attribute_transformer.rb +93 -0
- data/lib/ea/qea/factory/base_transformer.rb +177 -0
- data/lib/ea/qea/factory/class_transformer.rb +116 -0
- data/lib/ea/qea/factory/constraint_transformer.rb +75 -0
- data/lib/ea/qea/factory/data_type_transformer.rb +77 -0
- data/lib/ea/qea/factory/diagram_transformer.rb +157 -0
- data/lib/ea/qea/factory/document_builder.rb +283 -0
- data/lib/ea/qea/factory/ea_to_uml_factory.rb +229 -0
- data/lib/ea/qea/factory/enum_transformer.rb +74 -0
- data/lib/ea/qea/factory/generalization_builder.rb +227 -0
- data/lib/ea/qea/factory/generalization_transformer.rb +98 -0
- data/lib/ea/qea/factory/instance_transformer.rb +68 -0
- data/lib/ea/qea/factory/object_property_transformer.rb +58 -0
- data/lib/ea/qea/factory/operation_transformer.rb +66 -0
- data/lib/ea/qea/factory/package_transformer.rb +145 -0
- data/lib/ea/qea/factory/reference_resolver.rb +99 -0
- data/lib/ea/qea/factory/stereotype_loader.rb +39 -0
- data/lib/ea/qea/factory/tagged_value_transformer.rb +38 -0
- data/lib/ea/qea/factory/transformer_registry.rb +80 -0
- data/lib/ea/qea/factory.rb +37 -0
- data/lib/ea/qea/file_detector.rb +178 -0
- data/lib/ea/qea/infrastructure/database_connection.rb +100 -0
- data/lib/ea/qea/infrastructure/schema_reader.rb +136 -0
- data/lib/ea/qea/infrastructure/table_reader.rb +224 -0
- data/lib/ea/qea/infrastructure.rb +12 -0
- data/lib/ea/qea/models/base_model.rb +59 -0
- data/lib/ea/qea/models/ea_attribute.rb +109 -0
- data/lib/ea/qea/models/ea_attribute_tag.rb +100 -0
- data/lib/ea/qea/models/ea_complexity_type.rb +79 -0
- data/lib/ea/qea/models/ea_connector.rb +160 -0
- data/lib/ea/qea/models/ea_connector_type.rb +60 -0
- data/lib/ea/qea/models/ea_constraint_type.rb +63 -0
- data/lib/ea/qea/models/ea_datatype.rb +104 -0
- data/lib/ea/qea/models/ea_diagram.rb +115 -0
- data/lib/ea/qea/models/ea_diagram_link.rb +78 -0
- data/lib/ea/qea/models/ea_diagram_object.rb +73 -0
- data/lib/ea/qea/models/ea_diagram_type.rb +56 -0
- data/lib/ea/qea/models/ea_document.rb +63 -0
- data/lib/ea/qea/models/ea_object.rb +223 -0
- data/lib/ea/qea/models/ea_object_constraint.rb +53 -0
- data/lib/ea/qea/models/ea_object_property.rb +87 -0
- data/lib/ea/qea/models/ea_object_type.rb +73 -0
- data/lib/ea/qea/models/ea_operation.rb +127 -0
- data/lib/ea/qea/models/ea_operation_param.rb +76 -0
- data/lib/ea/qea/models/ea_package.rb +78 -0
- data/lib/ea/qea/models/ea_script.rb +62 -0
- data/lib/ea/qea/models/ea_status_type.rb +66 -0
- data/lib/ea/qea/models/ea_stereotype.rb +57 -0
- data/lib/ea/qea/models/ea_tagged_value.rb +99 -0
- data/lib/ea/qea/models/ea_xref.rb +165 -0
- data/lib/ea/qea/models.rb +35 -0
- data/lib/ea/qea/repositories/base_repository.rb +225 -0
- data/lib/ea/qea/repositories/object_repository.rb +219 -0
- data/lib/ea/qea/repositories.rb +10 -0
- data/lib/ea/qea/services/configuration.rb +211 -0
- data/lib/ea/qea/services/database_loader.rb +191 -0
- data/lib/ea/qea/services.rb +10 -0
- data/lib/ea/qea/validation/association_validator.rb +73 -0
- data/lib/ea/qea/validation/attribute_validator.rb +91 -0
- data/lib/ea/qea/validation/base_validator.rb +331 -0
- data/lib/ea/qea/validation/class_validator.rb +121 -0
- data/lib/ea/qea/validation/database/circular_reference_validator.rb +109 -0
- data/lib/ea/qea/validation/database/orphan_validator.rb +153 -0
- data/lib/ea/qea/validation/database/referential_integrity_validator.rb +128 -0
- data/lib/ea/qea/validation/database.rb +16 -0
- data/lib/ea/qea/validation/diagram_validator.rb +112 -0
- data/lib/ea/qea/validation/formatters/json_formatter.rb +137 -0
- data/lib/ea/qea/validation/formatters/text_formatter.rb +235 -0
- data/lib/ea/qea/validation/formatters.rb +12 -0
- data/lib/ea/qea/validation/operation_validator.rb +71 -0
- data/lib/ea/qea/validation/package_validator.rb +111 -0
- data/lib/ea/qea/validation/validation_engine.rb +387 -0
- data/lib/ea/qea/validation/validation_message.rb +144 -0
- data/lib/ea/qea/validation/validation_result.rb +210 -0
- data/lib/ea/qea/validation/validator_registry.rb +134 -0
- data/lib/ea/qea/validation.rb +28 -0
- data/lib/ea/qea/verification/comparison_result.rb +264 -0
- data/lib/ea/qea/verification/document_normalizer.rb +169 -0
- data/lib/ea/qea/verification/document_verifier.rb +322 -0
- data/lib/ea/qea/verification/element_comparator.rb +277 -0
- data/lib/ea/qea/verification/structure_matcher.rb +287 -0
- data/lib/ea/qea/verification.rb +14 -0
- data/lib/ea/qea.rb +185 -0
- data/lib/ea/transformations/configuration.rb +333 -0
- data/lib/ea/transformations/format_registry.rb +366 -0
- data/lib/ea/transformations/parsers/base_parser.rb +482 -0
- data/lib/ea/transformations/parsers/qea_parser.rb +401 -0
- data/lib/ea/transformations/parsers/xmi_parser.rb +243 -0
- data/lib/ea/transformations/transformation_engine.rb +390 -0
- data/lib/ea/transformations.rb +85 -0
- data/lib/ea/transformers/qea_to_xmi/association_end.rb +19 -0
- data/lib/ea/transformers/qea_to_xmi/cardinality.rb +96 -0
- data/lib/ea/transformers/qea_to_xmi/context.rb +106 -0
- data/lib/ea/transformers/qea_to_xmi/guid_format.rb +56 -0
- data/lib/ea/transformers/qea_to_xmi/id_allocator.rb +92 -0
- data/lib/ea/transformers/qea_to_xmi/run_state.rb +107 -0
- data/lib/ea/transformers/qea_to_xmi/transformer.rb +607 -0
- data/lib/ea/transformers/qea_to_xmi/visibility.rb +73 -0
- data/lib/ea/transformers/qea_to_xmi.rb +29 -0
- data/lib/ea/transformers/uml_to_xmi/id_generator.rb +54 -0
- data/lib/ea/transformers/uml_to_xmi/transformer.rb +152 -0
- data/lib/ea/transformers/uml_to_xmi/writer.rb +96 -0
- data/lib/ea/transformers/uml_to_xmi.rb +16 -0
- data/lib/ea/transformers.rb +34 -0
- data/lib/ea/version.rb +1 -1
- data/lib/ea/xmi/liquid_drops/association_drop.rb +56 -0
- data/lib/ea/xmi/liquid_drops/attribute_drop.rb +72 -0
- data/lib/ea/xmi/liquid_drops/cardinality_drop.rb +35 -0
- data/lib/ea/xmi/liquid_drops/connector_drop.rb +54 -0
- data/lib/ea/xmi/liquid_drops/constraint_drop.rb +29 -0
- data/lib/ea/xmi/liquid_drops/data_type_drop.rb +63 -0
- data/lib/ea/xmi/liquid_drops/dependency_drop.rb +36 -0
- data/lib/ea/xmi/liquid_drops/diagram_drop.rb +34 -0
- data/lib/ea/xmi/liquid_drops/enum_drop.rb +49 -0
- data/lib/ea/xmi/liquid_drops/enum_owned_literal_drop.rb +25 -0
- data/lib/ea/xmi/liquid_drops/generalization_attribute_drop.rb +87 -0
- data/lib/ea/xmi/liquid_drops/generalization_drop.rb +127 -0
- data/lib/ea/xmi/liquid_drops/klass_drop.rb +191 -0
- data/lib/ea/xmi/liquid_drops/operation_drop.rb +29 -0
- data/lib/ea/xmi/liquid_drops/package_drop.rb +108 -0
- data/lib/ea/xmi/liquid_drops/root_drop.rb +34 -0
- data/lib/ea/xmi/liquid_drops/source_target_drop.rb +43 -0
- data/lib/ea/xmi/lookup_service.rb +89 -0
- data/lib/ea/xmi/parser.rb +919 -0
- data/lib/ea/xmi.rb +35 -0
- data/lib/ea.rb +10 -1
- metadata +382 -9
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Ea
|
|
4
|
+
module Qea
|
|
5
|
+
module Factory
|
|
6
|
+
# Transforms EA attributes to UML attributes
|
|
7
|
+
class AttributeTransformer < BaseTransformer
|
|
8
|
+
# Transform EA attribute to UML attribute
|
|
9
|
+
# @param ea_attribute [EaAttribute] EA attribute model
|
|
10
|
+
# @return [Lutaml::Uml::TopElementAttribute] UML attribute
|
|
11
|
+
def transform(ea_attribute) # rubocop:disable Metrics/AbcSize,Metrics/CyclomaticComplexity,Metrics/MethodLength,Metrics/PerceivedComplexity
|
|
12
|
+
return nil if ea_attribute.nil?
|
|
13
|
+
|
|
14
|
+
Lutaml::Uml::TopElementAttribute.new.tap do |attr|
|
|
15
|
+
attr.name = ea_attribute.name
|
|
16
|
+
attr.type = ea_attribute.type
|
|
17
|
+
attr.visibility = map_visibility(ea_attribute.scope)
|
|
18
|
+
|
|
19
|
+
# XMI uses the TYPE's XMI ID, not the attribute's ID
|
|
20
|
+
type_xmi_id = lookup_type_xmi_id(ea_attribute.classifier)
|
|
21
|
+
attr.xmi_id = type_xmi_id || normalize_guid_to_xmi_format(
|
|
22
|
+
ea_attribute.ea_guid, "EAID"
|
|
23
|
+
)
|
|
24
|
+
|
|
25
|
+
attr.id = normalize_guid_to_xmi_format(ea_attribute.ea_guid, "EAID")
|
|
26
|
+
attr.static = ea_attribute.static? ? "true" : nil
|
|
27
|
+
attr.is_derived = ea_attribute.derived == "1"
|
|
28
|
+
|
|
29
|
+
# Map cardinality if bounds are present
|
|
30
|
+
if ea_attribute.lowerbound || ea_attribute.upperbound
|
|
31
|
+
attr.cardinality = build_cardinality(
|
|
32
|
+
ea_attribute.lowerbound,
|
|
33
|
+
ea_attribute.upperbound,
|
|
34
|
+
)
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
# Map definition/notes
|
|
38
|
+
attr.definition = normalize_line_endings(ea_attribute.notes) unless
|
|
39
|
+
ea_attribute.notes.nil? || ea_attribute.notes.empty?
|
|
40
|
+
|
|
41
|
+
# Load and transform attribute tags
|
|
42
|
+
attr.tagged_values = load_attribute_tags(ea_attribute.id)
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
private
|
|
47
|
+
|
|
48
|
+
# Look up the type object's XMI ID from classifier
|
|
49
|
+
# @param classifier_id [Integer] Classifier ID
|
|
50
|
+
# @return [String, nil] Type's XMI ID
|
|
51
|
+
def lookup_type_xmi_id(classifier_id) # rubocop:disable Metrics/AbcSize
|
|
52
|
+
return nil if classifier_id.nil? || classifier_id.to_i.zero?
|
|
53
|
+
|
|
54
|
+
obj = database.find_object(classifier_id.to_i)
|
|
55
|
+
return nil unless obj
|
|
56
|
+
|
|
57
|
+
normalize_guid_to_xmi_format(obj.ea_guid, "EAID")
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
# Build cardinality from lower and upper bounds
|
|
61
|
+
# @param lower [String] Lower bound
|
|
62
|
+
# @param upper [String] Upper bound
|
|
63
|
+
# @return [Lutaml::Uml::Cardinality] Cardinality object
|
|
64
|
+
def build_cardinality(lower, upper)
|
|
65
|
+
return nil if lower.nil? && upper.nil?
|
|
66
|
+
|
|
67
|
+
Lutaml::Uml::Cardinality.new.tap do |card|
|
|
68
|
+
card.min = lower || "0"
|
|
69
|
+
card.max = upper || "*"
|
|
70
|
+
end
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
# Load and transform attribute tags for an attribute
|
|
74
|
+
# @param attribute_id [Integer] Attribute ID
|
|
75
|
+
# @return [Array<Lutaml::Uml::TaggedValue>] UML tagged values
|
|
76
|
+
def load_attribute_tags(attribute_id)
|
|
77
|
+
return [] if attribute_id.nil?
|
|
78
|
+
return [] unless database.attribute_tags
|
|
79
|
+
|
|
80
|
+
# Filter attribute tags for this attribute from the in-memory
|
|
81
|
+
# collection
|
|
82
|
+
ea_tags = database.attribute_tags.select do |tag|
|
|
83
|
+
tag.element_id == attribute_id
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
# Transform to UML tagged values
|
|
87
|
+
tag_transformer = AttributeTagTransformer.new(database)
|
|
88
|
+
tag_transformer.transform_collection(ea_tags)
|
|
89
|
+
end
|
|
90
|
+
end
|
|
91
|
+
end
|
|
92
|
+
end
|
|
93
|
+
end
|
|
@@ -0,0 +1,177 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Ea
|
|
4
|
+
module Qea
|
|
5
|
+
module Factory
|
|
6
|
+
# Abstract base class for all EA to UML transformers
|
|
7
|
+
# Implements the Strategy pattern for model transformation
|
|
8
|
+
class BaseTransformer
|
|
9
|
+
attr_reader :database
|
|
10
|
+
|
|
11
|
+
# Initialize transformer with database reference
|
|
12
|
+
# @param database [Ea::Qea::Database] QEA database instance
|
|
13
|
+
def initialize(database)
|
|
14
|
+
@database = database
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
# Transform a single EA model to UML model
|
|
18
|
+
# @param ea_model [BaseModel] EA model instance
|
|
19
|
+
# @return [Object] UML model instance
|
|
20
|
+
# @raise [NotImplementedError] Must be implemented by subclasses
|
|
21
|
+
def transform(ea_model)
|
|
22
|
+
raise NotImplementedError,
|
|
23
|
+
"#{self.class} must implement #transform"
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
# Transform a collection of EA models to UML models
|
|
27
|
+
# @param collection [Array<BaseModel>] Collection of EA models
|
|
28
|
+
# @return [Array<Object>] Collection of UML models
|
|
29
|
+
def transform_collection(collection)
|
|
30
|
+
return [] if collection.nil? || collection.empty?
|
|
31
|
+
|
|
32
|
+
collection.filter_map { |item| transform(item) }
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
# Map EA visibility to UML visibility
|
|
36
|
+
# @param ea_visibility [String] EA visibility value
|
|
37
|
+
# @return [String] UML visibility value
|
|
38
|
+
def map_visibility(ea_visibility) # rubocop:disable Metrics/CyclomaticComplexity
|
|
39
|
+
return "public" if ea_visibility.nil? || ea_visibility.empty?
|
|
40
|
+
|
|
41
|
+
case ea_visibility.downcase
|
|
42
|
+
when "private" then "private"
|
|
43
|
+
when "protected" then "protected"
|
|
44
|
+
when "package" then "package"
|
|
45
|
+
else "public"
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
# Parse cardinality string to min/max values
|
|
50
|
+
# @param cardinality_str [String] Cardinality string (e.g., "0..1",
|
|
51
|
+
# "1..*")
|
|
52
|
+
# @return [Hash] Hash with :min and :max keys
|
|
53
|
+
def parse_cardinality(cardinality_str)
|
|
54
|
+
return { min: nil, max: nil } if cardinality_str.nil? ||
|
|
55
|
+
cardinality_str.empty?
|
|
56
|
+
|
|
57
|
+
parts = cardinality_str.split("..")
|
|
58
|
+
if parts.size == 2
|
|
59
|
+
{ min: parts[0], max: parts[1] }
|
|
60
|
+
elsif parts.size == 1
|
|
61
|
+
{ min: parts[0], max: parts[0] }
|
|
62
|
+
else
|
|
63
|
+
{ min: nil, max: nil }
|
|
64
|
+
end
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
# Convert boolean-like values to actual boolean
|
|
68
|
+
# @param value [Object] Value to convert
|
|
69
|
+
# @return [Boolean] Boolean value
|
|
70
|
+
def to_boolean(value)
|
|
71
|
+
return false if value.nil?
|
|
72
|
+
return value if [true, false].include?(value)
|
|
73
|
+
|
|
74
|
+
value.to_s == "1" || value.to_s.downcase == "true"
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
# Normalize EA GUID to XMI ID format
|
|
78
|
+
# Converts {GUID-WITH-HYPHENS} to PREFIX_GUID_WITH_UNDERSCORES
|
|
79
|
+
# @param ea_guid [String] EA GUID in format
|
|
80
|
+
# "{XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX}"
|
|
81
|
+
# @param prefix [String] Prefix to add (e.g., "EAID", "EAPK")
|
|
82
|
+
# @return [String, nil] XMI ID in format
|
|
83
|
+
# "PREFIX_XXXXXXXX_XXXX_XXXX_XXXX_XXXXXXXXXXXX"
|
|
84
|
+
def normalize_guid_to_xmi_format(ea_guid, prefix = "EAID")
|
|
85
|
+
return nil if ea_guid.nil? || ea_guid.empty?
|
|
86
|
+
|
|
87
|
+
# Remove braces and replace hyphens with underscores
|
|
88
|
+
clean = ea_guid.tr("{}", "").tr("-", "_")
|
|
89
|
+
"#{prefix}_#{clean}"
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
# Convert ea_guid to XMI SRC ID format
|
|
93
|
+
def normalize_guid_to_xmi_src_dst_format(
|
|
94
|
+
ea_guid, prefix = "EAID", is_src = true # rubocop:disable Style/OptionalBooleanParameter
|
|
95
|
+
)
|
|
96
|
+
xmi_id = normalize_guid_to_xmi_format(ea_guid, prefix)
|
|
97
|
+
|
|
98
|
+
# Trim prefix and add _src or _dst
|
|
99
|
+
src_dst = is_src ? "src" : "dst"
|
|
100
|
+
clean = xmi_id[(prefix.length + 3), xmi_id.length]
|
|
101
|
+
"#{prefix}_#{src_dst}#{clean}"
|
|
102
|
+
end
|
|
103
|
+
|
|
104
|
+
# Normalize line endings from Windows (\r\n) to Unix (\n)
|
|
105
|
+
# EA database stores text with Windows line endings, but XMI uses Unix
|
|
106
|
+
# @param text [String, nil] Text to normalize
|
|
107
|
+
# @return [String, nil] Text with normalized line endings
|
|
108
|
+
def normalize_line_endings(text)
|
|
109
|
+
return nil if text.nil?
|
|
110
|
+
|
|
111
|
+
text.gsub("\r\n", "\n")
|
|
112
|
+
end
|
|
113
|
+
|
|
114
|
+
# Find object by ID
|
|
115
|
+
# @param object_id [Integer] Object ID
|
|
116
|
+
# @return [Models::EaObject, nil] EA object or nil
|
|
117
|
+
def find_object_by_id(object_id)
|
|
118
|
+
return nil if object_id.nil?
|
|
119
|
+
|
|
120
|
+
database.find_object(object_id)
|
|
121
|
+
end
|
|
122
|
+
|
|
123
|
+
# Load and transform tagged values for an element
|
|
124
|
+
# @param ea_guid [String] Element GUID
|
|
125
|
+
# @return [Array<Lutaml::Uml::TaggedValue>] UML tagged values
|
|
126
|
+
def load_tagged_values(ea_guid)
|
|
127
|
+
return [] if ea_guid.nil?
|
|
128
|
+
|
|
129
|
+
ea_tags = database.tagged_values_for_element(ea_guid)
|
|
130
|
+
TaggedValueTransformer.new(database).transform_collection(ea_tags)
|
|
131
|
+
end
|
|
132
|
+
|
|
133
|
+
# Load and transform attributes for an object
|
|
134
|
+
# @param object_id [Integer] Object ID
|
|
135
|
+
# @return [Array<Lutaml::Uml::TopElementAttribute>] UML attributes
|
|
136
|
+
def load_attributes(object_id)
|
|
137
|
+
return [] if object_id.nil?
|
|
138
|
+
|
|
139
|
+
ea_attributes = database.attributes_for_object(object_id)
|
|
140
|
+
.sort_by { |a| a.pos || 0 }
|
|
141
|
+
AttributeTransformer.new(database).transform_collection(ea_attributes)
|
|
142
|
+
end
|
|
143
|
+
|
|
144
|
+
# Load and transform operations for an object
|
|
145
|
+
# @param object_id [Integer] Object ID
|
|
146
|
+
# @return [Array<Lutaml::Uml::Operation>] UML operations
|
|
147
|
+
def load_operations(object_id)
|
|
148
|
+
return [] if object_id.nil?
|
|
149
|
+
|
|
150
|
+
ea_operations = database.operations_for_object(object_id)
|
|
151
|
+
.sort_by { |op| op.pos || 0 }
|
|
152
|
+
OperationTransformer.new(database).transform_collection(ea_operations)
|
|
153
|
+
end
|
|
154
|
+
|
|
155
|
+
# Load and transform constraints for an object
|
|
156
|
+
# @param object_id [Integer] Object ID
|
|
157
|
+
# @return [Array<Lutaml::Uml::Constraint>] UML constraints
|
|
158
|
+
def load_constraints(object_id)
|
|
159
|
+
return [] if object_id.nil?
|
|
160
|
+
|
|
161
|
+
ea_constraints = database.constraints_for_object(object_id)
|
|
162
|
+
ConstraintTransformer.new(database).transform_collection(ea_constraints)
|
|
163
|
+
end
|
|
164
|
+
|
|
165
|
+
# Load and transform object properties for an object
|
|
166
|
+
# @param object_id [Integer] Object ID
|
|
167
|
+
# @return [Array<Lutaml::Uml::TaggedValue>] UML tagged values
|
|
168
|
+
def load_object_properties(object_id)
|
|
169
|
+
return [] if object_id.nil?
|
|
170
|
+
|
|
171
|
+
ea_props = database.properties_for_object(object_id)
|
|
172
|
+
ObjectPropertyTransformer.new(database).transform_collection(ea_props)
|
|
173
|
+
end
|
|
174
|
+
end
|
|
175
|
+
end
|
|
176
|
+
end
|
|
177
|
+
end
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Ea
|
|
4
|
+
module Qea
|
|
5
|
+
module Factory
|
|
6
|
+
class ClassTransformer < BaseTransformer
|
|
7
|
+
def transform(ea_object)
|
|
8
|
+
return nil if ea_object.nil?
|
|
9
|
+
return nil unless transformable?(ea_object)
|
|
10
|
+
|
|
11
|
+
Lutaml::Uml::UmlClass.new.tap do |klass|
|
|
12
|
+
assign_basic_properties(klass, ea_object)
|
|
13
|
+
assign_features(klass, ea_object)
|
|
14
|
+
assign_relationships(klass, ea_object)
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
private
|
|
19
|
+
|
|
20
|
+
def transformable?(ea_object)
|
|
21
|
+
ea_object.uml_class? || ea_object.interface?
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def assign_basic_properties(klass, ea_object)
|
|
25
|
+
klass.name = ea_object.name
|
|
26
|
+
klass.xmi_id = normalize_guid_to_xmi_format(ea_object.ea_guid, "EAID")
|
|
27
|
+
klass.is_abstract = ea_object.abstract?
|
|
28
|
+
klass.type = "Class"
|
|
29
|
+
klass.visibility = map_visibility(ea_object.visibility)
|
|
30
|
+
assign_stereotypes(klass, ea_object)
|
|
31
|
+
assign_definition(klass, ea_object)
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def assign_stereotypes(klass, ea_object)
|
|
35
|
+
stereotypes = build_stereotypes(ea_object)
|
|
36
|
+
klass.stereotype = stereotypes unless stereotypes.empty?
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
def assign_definition(klass, ea_object)
|
|
40
|
+
return if ea_object.note.nil? || ea_object.note.empty?
|
|
41
|
+
|
|
42
|
+
klass.definition = normalize_line_endings(ea_object.note)
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
def assign_features(klass, ea_object)
|
|
46
|
+
klass.attributes = load_all_attributes(ea_object)
|
|
47
|
+
assign_feature_collections(klass, ea_object)
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
def assign_feature_collections(klass, ea_object)
|
|
51
|
+
klass.operations = load_operations(ea_object.ea_object_id)
|
|
52
|
+
klass.constraints = load_constraints(ea_object.ea_object_id)
|
|
53
|
+
klass.tagged_values = load_tagged_values(ea_object.ea_guid)
|
|
54
|
+
klass.tagged_values.concat(
|
|
55
|
+
load_object_properties(ea_object.ea_object_id),
|
|
56
|
+
)
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
def assign_relationships(klass, ea_object)
|
|
60
|
+
gen_builder = GeneralizationBuilder.new(database)
|
|
61
|
+
assoc_builder = AssociationBuilder.new(database)
|
|
62
|
+
|
|
63
|
+
klass.generalization = gen_builder.load_generalization(
|
|
64
|
+
ea_object.ea_object_id,
|
|
65
|
+
)
|
|
66
|
+
klass.association_generalization = gen_builder
|
|
67
|
+
.load_association_generalizations(ea_object.ea_object_id)
|
|
68
|
+
|
|
69
|
+
klass.associations = assoc_builder.load_class_associations(
|
|
70
|
+
ea_object.ea_object_id, ea_object.ea_guid
|
|
71
|
+
)
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
def load_all_attributes(ea_object)
|
|
75
|
+
gen_builder = GeneralizationBuilder.new(database)
|
|
76
|
+
assoc_builder = AssociationBuilder.new(database)
|
|
77
|
+
|
|
78
|
+
attrs = load_attributes(ea_object.ea_object_id)
|
|
79
|
+
assoc_attrs = gen_builder.convert_to_top_element_attributes(
|
|
80
|
+
assoc_builder.load_association_attributes(ea_object.ea_object_id),
|
|
81
|
+
)
|
|
82
|
+
attrs + assoc_attrs
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
def build_stereotypes(ea_object)
|
|
86
|
+
stereotypes = []
|
|
87
|
+
add_direct_stereotype(stereotypes, ea_object)
|
|
88
|
+
add_xref_stereotype(stereotypes, ea_object)
|
|
89
|
+
add_interface_stereotype(stereotypes, ea_object)
|
|
90
|
+
|
|
91
|
+
stereotypes
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
def add_direct_stereotype(stereotypes, ea_object)
|
|
95
|
+
return unless ea_object.stereotype && !ea_object.stereotype.empty?
|
|
96
|
+
|
|
97
|
+
stereotypes << ea_object.stereotype
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
def add_xref_stereotype(stereotypes, ea_object)
|
|
101
|
+
xref_stereotype = StereotypeLoader.new(database)
|
|
102
|
+
.load_from_xref(ea_object.ea_guid)
|
|
103
|
+
return unless xref_stereotype && !stereotypes.include?(xref_stereotype)
|
|
104
|
+
|
|
105
|
+
stereotypes << xref_stereotype
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
def add_interface_stereotype(stereotypes, ea_object)
|
|
109
|
+
return unless ea_object.interface? && !stereotypes.include?("interface")
|
|
110
|
+
|
|
111
|
+
stereotypes << "interface"
|
|
112
|
+
end
|
|
113
|
+
end
|
|
114
|
+
end
|
|
115
|
+
end
|
|
116
|
+
end
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Ea
|
|
4
|
+
module Qea
|
|
5
|
+
module Factory
|
|
6
|
+
# Transforms EA ObjectConstraint to UML Constraint
|
|
7
|
+
#
|
|
8
|
+
# This transformer converts Enterprise Architect constraint definitions
|
|
9
|
+
# (typically OCL constraints) to standard UML Constraint objects.
|
|
10
|
+
#
|
|
11
|
+
# @example Transform a constraint
|
|
12
|
+
# ea_constraint = Models::EaObjectConstraint.new(
|
|
13
|
+
# constraint_id: 1,
|
|
14
|
+
# object_id: 4,
|
|
15
|
+
# constraint: "count(self.legalConstraints) >= 1",
|
|
16
|
+
# constraint_type: "Invariant",
|
|
17
|
+
# weight: 0.0,
|
|
18
|
+
# status: "Approved"
|
|
19
|
+
# )
|
|
20
|
+
# transformer = ConstraintTransformer.new(database)
|
|
21
|
+
# uml_constraint = transformer.transform(ea_constraint)
|
|
22
|
+
class ConstraintTransformer < BaseTransformer
|
|
23
|
+
# Transform EA constraint to UML Constraint
|
|
24
|
+
#
|
|
25
|
+
# @param ea_constraint [Models::EaObjectConstraint] EA constraint model
|
|
26
|
+
# @return [Lutaml::Uml::Constraint, nil] UML constraint or nil
|
|
27
|
+
def transform(ea_constraint) # rubocop:disable Metrics/AbcSize,Metrics/MethodLength
|
|
28
|
+
return nil unless ea_constraint
|
|
29
|
+
|
|
30
|
+
Lutaml::Uml::Constraint.new.tap do |constraint|
|
|
31
|
+
# Generate unique ID for the constraint
|
|
32
|
+
constraint.xmi_id = "constraint_#{ea_constraint.constraint_id}" if
|
|
33
|
+
ea_constraint.constraint_id
|
|
34
|
+
|
|
35
|
+
# Generate descriptive name from constraint body or use ID
|
|
36
|
+
constraint.name = constraint_name(ea_constraint)
|
|
37
|
+
|
|
38
|
+
# Map constraint properties
|
|
39
|
+
constraint.body = ea_constraint.constraint
|
|
40
|
+
constraint.type = ea_constraint.constraint_type
|
|
41
|
+
constraint.weight = ea_constraint.weight&.to_s
|
|
42
|
+
constraint.status = ea_constraint.status
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
private
|
|
47
|
+
|
|
48
|
+
# Generate descriptive name from constraint body
|
|
49
|
+
#
|
|
50
|
+
# Extracts the first meaningful part of the constraint body to use
|
|
51
|
+
# as a descriptive name. Falls back to a generic name if extraction
|
|
52
|
+
# fails.
|
|
53
|
+
#
|
|
54
|
+
# @param ea_constraint [Models::EaObjectConstraint] EA constraint
|
|
55
|
+
# @return [String] Constraint name
|
|
56
|
+
def constraint_name(ea_constraint) # rubocop:disable Metrics/MethodLength
|
|
57
|
+
return "constraint_#{ea_constraint.constraint_id}" unless
|
|
58
|
+
ea_constraint.constraint
|
|
59
|
+
|
|
60
|
+
body = ea_constraint.constraint.to_s.strip
|
|
61
|
+
|
|
62
|
+
# Try to extract a meaningful name from the constraint body
|
|
63
|
+
# Take first 50 chars or until special chars
|
|
64
|
+
name_part = body[0..50].split(/[()<>=\s]/).first&.strip
|
|
65
|
+
|
|
66
|
+
if name_part && !name_part.empty?
|
|
67
|
+
name_part
|
|
68
|
+
else
|
|
69
|
+
"constraint_#{ea_constraint.constraint_id}"
|
|
70
|
+
end
|
|
71
|
+
end
|
|
72
|
+
end
|
|
73
|
+
end
|
|
74
|
+
end
|
|
75
|
+
end
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Ea
|
|
4
|
+
module Qea
|
|
5
|
+
module Factory
|
|
6
|
+
# Transforms EA objects (DataType type) to UML data types
|
|
7
|
+
class DataTypeTransformer < BaseTransformer
|
|
8
|
+
# Transform EA object to UML data type
|
|
9
|
+
# @param ea_object [EaObject] EA object model
|
|
10
|
+
# @return [Lutaml::Uml::DataType] UML data type
|
|
11
|
+
def transform(ea_object) # rubocop:disable Metrics/AbcSize,Metrics/CyclomaticComplexity,Metrics/MethodLength
|
|
12
|
+
return nil if ea_object.nil?
|
|
13
|
+
return nil unless ea_object.data_type?
|
|
14
|
+
|
|
15
|
+
Lutaml::Uml::DataType.new.tap do |data_type| # rubocop:disable Metrics/BlockLength
|
|
16
|
+
# Map basic properties
|
|
17
|
+
data_type.name = ea_object.name
|
|
18
|
+
data_type.xmi_id = normalize_guid_to_xmi_format(ea_object.ea_guid,
|
|
19
|
+
"EAID")
|
|
20
|
+
data_type.is_abstract = ea_object.abstract?
|
|
21
|
+
data_type.type = "DataType"
|
|
22
|
+
data_type.visibility = map_visibility(ea_object.visibility)
|
|
23
|
+
|
|
24
|
+
# Map stereotype
|
|
25
|
+
if ea_object.stereotype && !ea_object.stereotype.empty?
|
|
26
|
+
data_type.stereotype = [ea_object.stereotype]
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
# Map definition/notes
|
|
30
|
+
data_type.definition = ea_object.note unless
|
|
31
|
+
ea_object.note.nil? || ea_object.note.empty?
|
|
32
|
+
|
|
33
|
+
# Load and transform attributes
|
|
34
|
+
data_type.attributes = load_attributes(ea_object.ea_object_id)
|
|
35
|
+
|
|
36
|
+
# Load and transform operations
|
|
37
|
+
data_type.operations = load_operations(ea_object.ea_object_id)
|
|
38
|
+
|
|
39
|
+
# Load and transform constraints
|
|
40
|
+
data_type.constraints = load_constraints(ea_object.ea_object_id)
|
|
41
|
+
|
|
42
|
+
# Load and transform tagged values
|
|
43
|
+
data_type.tagged_values = load_tagged_values(ea_object.ea_guid)
|
|
44
|
+
|
|
45
|
+
# Load associations for this data type
|
|
46
|
+
data_type.associations = load_associations(ea_object.ea_object_id,
|
|
47
|
+
ea_object.ea_guid)
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
private
|
|
52
|
+
|
|
53
|
+
# Load associations for a data type
|
|
54
|
+
# @param object_id [Integer] Object ID
|
|
55
|
+
# @param object_guid [String] Object GUID
|
|
56
|
+
# @return [Array<Lutaml::Uml::Association>] UML associations
|
|
57
|
+
def load_associations(object_id, object_guid) # rubocop:disable Metrics/MethodLength
|
|
58
|
+
return [] if object_id.nil?
|
|
59
|
+
|
|
60
|
+
assoc_connectors = database.connectors_for_object(object_id)
|
|
61
|
+
.select { |c| c.connector_type == "Association" }
|
|
62
|
+
|
|
63
|
+
assoc_transformer = AssociationTransformer.new(database)
|
|
64
|
+
normalized_xmi_id = normalize_guid_to_xmi_format(object_guid, "EAID")
|
|
65
|
+
|
|
66
|
+
assoc_connectors.filter_map do |ea_connector|
|
|
67
|
+
assoc = assoc_transformer.transform(ea_connector)
|
|
68
|
+
|
|
69
|
+
next unless assoc && assoc.owner_end_xmi_id == normalized_xmi_id
|
|
70
|
+
|
|
71
|
+
assoc
|
|
72
|
+
end
|
|
73
|
+
end
|
|
74
|
+
end
|
|
75
|
+
end
|
|
76
|
+
end
|
|
77
|
+
end
|
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Ea
|
|
4
|
+
module Qea
|
|
5
|
+
module Factory
|
|
6
|
+
# Transforms EA diagrams to UML diagrams
|
|
7
|
+
#
|
|
8
|
+
# This transformer loads diagram data along with diagram objects
|
|
9
|
+
# (visual placement) and diagram links (visual connector routing)
|
|
10
|
+
# to create a complete UML diagram representation.
|
|
11
|
+
class DiagramTransformer < BaseTransformer
|
|
12
|
+
# Transform EA diagram to UML diagram
|
|
13
|
+
# @param ea_diagram [EaDiagram] EA diagram model
|
|
14
|
+
# @return [Lutaml::Uml::Diagram] UML diagram
|
|
15
|
+
def transform(ea_diagram) # rubocop:disable Metrics/AbcSize,Metrics/CyclomaticComplexity,Metrics/PerceivedComplexity,Metrics/MethodLength
|
|
16
|
+
return nil if ea_diagram.nil?
|
|
17
|
+
|
|
18
|
+
Lutaml::Uml::Diagram.new.tap do |diagram| # rubocop:disable Metrics/BlockLength
|
|
19
|
+
# Map basic properties
|
|
20
|
+
diagram.name = ea_diagram.name
|
|
21
|
+
diagram.xmi_id = normalize_guid_to_xmi_format(ea_diagram.ea_guid,
|
|
22
|
+
"EAID")
|
|
23
|
+
|
|
24
|
+
# Map package relationship - use GUID not numeric ID
|
|
25
|
+
if ea_diagram.package_id
|
|
26
|
+
package = find_package(ea_diagram.package_id)
|
|
27
|
+
if package
|
|
28
|
+
diagram.package_id = normalize_guid_to_xmi_format(
|
|
29
|
+
package.ea_guid, "EAPK"
|
|
30
|
+
)
|
|
31
|
+
diagram.package_name = package.name
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
# Map definition/notes
|
|
36
|
+
diagram.definition = ea_diagram.notes unless
|
|
37
|
+
ea_diagram.notes.nil? || ea_diagram.notes.empty?
|
|
38
|
+
|
|
39
|
+
# Map stereotype
|
|
40
|
+
if ea_diagram.stereotype && !ea_diagram.stereotype.empty?
|
|
41
|
+
diagram.stereotype = [ea_diagram.stereotype]
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
# Load and transform diagram objects (visual placement)
|
|
45
|
+
diagram_objects = load_diagram_objects(ea_diagram.diagram_id)
|
|
46
|
+
if diagram_objects.any?
|
|
47
|
+
diagram.diagram_objects.concat(diagram_objects)
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
# Load and transform diagram links (visual routing)
|
|
51
|
+
diagram_links = load_diagram_links(ea_diagram.diagram_id)
|
|
52
|
+
diagram.diagram_links.concat(diagram_links) if diagram_links.any?
|
|
53
|
+
|
|
54
|
+
# Load diagram type
|
|
55
|
+
diagram.diagram_type = ea_diagram.diagram_type
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
private
|
|
60
|
+
|
|
61
|
+
# Find package by ID
|
|
62
|
+
# @param package_id [Integer] Package ID
|
|
63
|
+
# @return [EaPackage, nil] EA package or nil if not found
|
|
64
|
+
def find_package(package_id)
|
|
65
|
+
return nil if package_id.nil?
|
|
66
|
+
|
|
67
|
+
database.find_package(package_id)
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
# Load diagram objects for a diagram
|
|
71
|
+
# @param diagram_id [Integer] Diagram ID
|
|
72
|
+
# @return [Array<Lutaml::Uml::DiagramObject>] UML diagram objects
|
|
73
|
+
def load_diagram_objects(diagram_id)
|
|
74
|
+
return [] if diagram_id.nil?
|
|
75
|
+
|
|
76
|
+
ea_objects = database.diagram_objects_for(diagram_id)
|
|
77
|
+
ea_objects.filter_map do |ea_obj|
|
|
78
|
+
transform_diagram_object(ea_obj)
|
|
79
|
+
end
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
# Transform EA diagram object to UML diagram object
|
|
83
|
+
# @param ea_obj [Models::EaDiagramObject] EA diagram object
|
|
84
|
+
# @return [Lutaml::Uml::DiagramObject] UML diagram object
|
|
85
|
+
def transform_diagram_object(ea_obj) # rubocop:disable Metrics/AbcSize,Metrics/MethodLength
|
|
86
|
+
return nil if ea_obj.nil?
|
|
87
|
+
|
|
88
|
+
Lutaml::Uml::DiagramObject.new.tap do |obj|
|
|
89
|
+
obj.diagram_object_id = ea_obj.ea_object_id.to_s
|
|
90
|
+
obj.left = ea_obj.rectleft
|
|
91
|
+
obj.top = ea_obj.recttop
|
|
92
|
+
obj.right = ea_obj.rectright
|
|
93
|
+
obj.bottom = ea_obj.rectbottom
|
|
94
|
+
obj.sequence = ea_obj.sequence
|
|
95
|
+
obj.style = ea_obj.objectstyle
|
|
96
|
+
|
|
97
|
+
# Try to find and set xmi_id from the referenced object
|
|
98
|
+
if ea_obj.ea_object_id
|
|
99
|
+
uml_object = find_object_by_id(ea_obj.ea_object_id)
|
|
100
|
+
if uml_object
|
|
101
|
+
obj.object_xmi_id = normalize_guid_to_xmi_format(
|
|
102
|
+
uml_object.ea_guid, "EAID"
|
|
103
|
+
)
|
|
104
|
+
end
|
|
105
|
+
end
|
|
106
|
+
end
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
# Load diagram links for a diagram
|
|
110
|
+
# @param diagram_id [Integer] Diagram ID
|
|
111
|
+
# @return [Array<Lutaml::Uml::DiagramLink>] UML diagram links
|
|
112
|
+
def load_diagram_links(diagram_id)
|
|
113
|
+
return [] if diagram_id.nil?
|
|
114
|
+
|
|
115
|
+
ea_links = database.diagram_links_for(diagram_id)
|
|
116
|
+
ea_links.filter_map do |ea_link|
|
|
117
|
+
transform_diagram_link(ea_link)
|
|
118
|
+
end
|
|
119
|
+
end
|
|
120
|
+
|
|
121
|
+
# Transform EA diagram link to UML diagram link
|
|
122
|
+
# @param ea_link [Models::EaDiagramLink] EA diagram link
|
|
123
|
+
# @return [Lutaml::Uml::DiagramLink] UML diagram link
|
|
124
|
+
def transform_diagram_link(ea_link) # rubocop:disable Metrics/AbcSize,Metrics/MethodLength
|
|
125
|
+
return nil if ea_link.nil?
|
|
126
|
+
|
|
127
|
+
Lutaml::Uml::DiagramLink.new.tap do |link|
|
|
128
|
+
link.connector_id = ea_link.connectorid.to_s
|
|
129
|
+
link.geometry = ea_link.geometry
|
|
130
|
+
link.style = ea_link.style
|
|
131
|
+
link.hidden = ea_link.hidden?
|
|
132
|
+
link.path = ea_link.path
|
|
133
|
+
|
|
134
|
+
# Try to find and set xmi_id from the referenced connector
|
|
135
|
+
if ea_link.connectorid
|
|
136
|
+
connector = find_connector_by_id(ea_link.connectorid)
|
|
137
|
+
if connector
|
|
138
|
+
link.connector_xmi_id = normalize_guid_to_xmi_format(
|
|
139
|
+
connector.ea_guid, "EAID"
|
|
140
|
+
)
|
|
141
|
+
end
|
|
142
|
+
end
|
|
143
|
+
end
|
|
144
|
+
end
|
|
145
|
+
|
|
146
|
+
# Find connector by ID
|
|
147
|
+
# @param connector_id [Integer] Connector ID
|
|
148
|
+
# @return [Models::EaConnector, nil] EA connector or nil if not found
|
|
149
|
+
def find_connector_by_id(connector_id)
|
|
150
|
+
return nil if connector_id.nil?
|
|
151
|
+
|
|
152
|
+
database.find_connector(connector_id)
|
|
153
|
+
end
|
|
154
|
+
end
|
|
155
|
+
end
|
|
156
|
+
end
|
|
157
|
+
end
|