ea 0.2.5 → 0.3.1

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 (102) hide show
  1. checksums.yaml +4 -4
  2. data/TODO.refactor/01-ea-model-domain-layer.md +64 -0
  3. data/TODO.refactor/02-ea-model-qea-source-adapter.md +58 -0
  4. data/TODO.refactor/03-ea-model-xmi-source-adapter.md +33 -0
  5. data/TODO.refactor/04-ea-model-annotations-tagged-values.md +34 -0
  6. data/TODO.refactor/05-ea-model-diagrams-coordinates.md +37 -0
  7. data/TODO.refactor/06-spa-projection-layer.md +45 -0
  8. data/TODO.refactor/07-spa-sharded-output-strategy.md +28 -0
  9. data/TODO.refactor/08-spa-build-time-search-index.md +24 -0
  10. data/TODO.refactor/09-spa-frontend-data-contract.md +25 -0
  11. data/TODO.refactor/10-spa-cli-command-rework.md +34 -0
  12. data/TODO.refactor/11-spa-perf-benchmark.md +23 -0
  13. data/TODO.refactor/12-lutaml-uml-static-site-deprecation.md +28 -0
  14. data/lib/ea/cli/app.rb +13 -7
  15. data/lib/ea/cli/command/spa.rb +33 -48
  16. data/lib/ea/cli/command/svg.rb +68 -0
  17. data/lib/ea/cli/command.rb +1 -0
  18. data/lib/ea/model/annotation.rb +29 -0
  19. data/lib/ea/model/association.rb +40 -0
  20. data/lib/ea/model/base.rb +27 -0
  21. data/lib/ea/model/bounds.rb +22 -0
  22. data/lib/ea/model/classifier.rb +41 -0
  23. data/lib/ea/model/data_type.rb +9 -0
  24. data/lib/ea/model/dependency.rb +19 -0
  25. data/lib/ea/model/diagram.rb +28 -0
  26. data/lib/ea/model/diagram_connector.rb +30 -0
  27. data/lib/ea/model/diagram_element.rb +23 -0
  28. data/lib/ea/model/document.rb +107 -0
  29. data/lib/ea/model/enumeration.rb +15 -0
  30. data/lib/ea/model/enumeration_literal.rb +16 -0
  31. data/lib/ea/model/generalization.rb +19 -0
  32. data/lib/ea/model/interface.rb +9 -0
  33. data/lib/ea/model/klass.rb +16 -0
  34. data/lib/ea/model/metadata.rb +31 -0
  35. data/lib/ea/model/operation.rb +33 -0
  36. data/lib/ea/model/package.rb +36 -0
  37. data/lib/ea/model/parameter.rb +24 -0
  38. data/lib/ea/model/point.rb +16 -0
  39. data/lib/ea/model/polymorphic_maps.rb +30 -0
  40. data/lib/ea/model/primitive_type.rb +9 -0
  41. data/lib/ea/model/property.rb +49 -0
  42. data/lib/ea/model/realization.rb +19 -0
  43. data/lib/ea/model/relationship.rb +21 -0
  44. data/lib/ea/model/stereotype.rb +24 -0
  45. data/lib/ea/model/tagged_value.rb +20 -0
  46. data/lib/ea/model/waypoint.rb +19 -0
  47. data/lib/ea/model.rb +48 -0
  48. data/lib/ea/sources/qea/adapter.rb +63 -0
  49. data/lib/ea/sources/qea/annotation_builder.rb +36 -0
  50. data/lib/ea/sources/qea/classifier_builder.rb +119 -0
  51. data/lib/ea/sources/qea/connector_relationship_map.rb +42 -0
  52. data/lib/ea/sources/qea/diagram_builder.rb +214 -0
  53. data/lib/ea/sources/qea/diagram_style_parser.rb +43 -0
  54. data/lib/ea/sources/qea/id_normalizer.rb +24 -0
  55. data/lib/ea/sources/qea/metadata_builder.rb +42 -0
  56. data/lib/ea/sources/qea/object_classifier_map.rb +36 -0
  57. data/lib/ea/sources/qea/operation_builder.rb +79 -0
  58. data/lib/ea/sources/qea/package_builder.rb +44 -0
  59. data/lib/ea/sources/qea/property_builder.rb +86 -0
  60. data/lib/ea/sources/qea/relationship_builder.rb +113 -0
  61. data/lib/ea/sources/qea/stereotype_builder.rb +44 -0
  62. data/lib/ea/sources/qea/tagged_value_builder.rb +39 -0
  63. data/lib/ea/sources/qea.rb +31 -0
  64. data/lib/ea/sources/xmi/adapter.rb +62 -0
  65. data/lib/ea/sources/xmi/annotation_builder.rb +49 -0
  66. data/lib/ea/sources/xmi/classifier_builder.rb +89 -0
  67. data/lib/ea/sources/xmi/diagram_builder.rb +82 -0
  68. data/lib/ea/sources/xmi/id_normalizer.rb +27 -0
  69. data/lib/ea/sources/xmi/metadata_builder.rb +32 -0
  70. data/lib/ea/sources/xmi/operation_builder.rb +59 -0
  71. data/lib/ea/sources/xmi/package_builder.rb +73 -0
  72. data/lib/ea/sources/xmi/property_builder.rb +77 -0
  73. data/lib/ea/sources/xmi/relationship_builder.rb +142 -0
  74. data/lib/ea/sources/xmi/relationship_type_map.rb +34 -0
  75. data/lib/ea/sources/xmi/type_classifier_map.rb +33 -0
  76. data/lib/ea/sources/xmi.rb +29 -0
  77. data/lib/ea/sources.rb +15 -0
  78. data/lib/ea/spa/configuration.rb +110 -0
  79. data/lib/ea/spa/generator.rb +45 -0
  80. data/lib/ea/spa/lazy_ref.rb +18 -0
  81. data/lib/ea/spa/output/sharded_multi_file_strategy.rb +71 -0
  82. data/lib/ea/spa/output/single_file_strategy.rb +56 -0
  83. data/lib/ea/spa/output/strategy.rb +36 -0
  84. data/lib/ea/spa/output.rb +11 -0
  85. data/lib/ea/spa/package_tree.rb +15 -0
  86. data/lib/ea/spa/package_tree_node.rb +26 -0
  87. data/lib/ea/spa/projector.rb +199 -0
  88. data/lib/ea/spa/search_entry.rb +28 -0
  89. data/lib/ea/spa/search_index.rb +18 -0
  90. data/lib/ea/spa/shard.rb +19 -0
  91. data/lib/ea/spa/skeleton.rb +22 -0
  92. data/lib/ea/spa/skeleton_entry.rb +27 -0
  93. data/lib/ea/spa.rb +31 -0
  94. data/lib/ea/svg/bounds_calculator.rb +74 -0
  95. data/lib/ea/svg/connector_path.rb +138 -0
  96. data/lib/ea/svg/element_box.rb +256 -0
  97. data/lib/ea/svg/renderer.rb +77 -0
  98. data/lib/ea/svg/style_resolver.rb +72 -0
  99. data/lib/ea/svg.rb +21 -0
  100. data/lib/ea/version.rb +1 -1
  101. data/lib/ea.rb +4 -0
  102. metadata +97 -2
@@ -0,0 +1,68 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "fileutils"
4
+
5
+ module Ea
6
+ module Cli
7
+ module Command
8
+ # `ea svg NAME FILE [--output=PATH]`
9
+ #
10
+ # Renders a single diagram from a QEA or XMI file into a
11
+ # standalone SVG using the umldi content (placed element
12
+ # bounds + connector waypoints) captured in Ea::Model::Diagram.
13
+ class Svg < Base
14
+ def call
15
+ diagram = find_diagram
16
+ svg = Ea::Svg::Renderer.new(diagram,
17
+ model_index: document.index_by_id).render
18
+
19
+ output_path = resolve_output_path(diagram)
20
+ FileUtils.mkdir_p(File.dirname(output_path))
21
+ File.write(output_path, svg)
22
+
23
+ formatter.render([[output_path]], columns: [:written_to])
24
+ end
25
+
26
+ private
27
+
28
+ def document
29
+ @document ||= build_model_document
30
+ end
31
+
32
+ def build_model_document
33
+ case File.extname(file_path).downcase
34
+ when ".qea"
35
+ Ea::Sources::Qea::Adapter.from_path(file_path)
36
+ when ".xmi"
37
+ Ea::Sources::Xmi::Adapter.from_path(file_path)
38
+ else
39
+ raise Ea::Cli::UnsupportedFormat,
40
+ "Unknown file format: #{File.extname(file_path)}"
41
+ end
42
+ end
43
+
44
+ def diagram_name
45
+ options[:name] or raise Ea::Cli::Error, "missing required diagram name"
46
+ end
47
+
48
+ def find_diagram
49
+ match = document.diagrams.find { |d| d.name == diagram_name }
50
+ return match if match
51
+
52
+ raise Ea::Cli::Error,
53
+ "Diagram #{diagram_name.inspect} not found in #{file_path}. " \
54
+ "Use `ea diagrams list #{file_path}` to see names."
55
+ end
56
+
57
+ def resolve_output_path(diagram)
58
+ options[:output] || begin
59
+ base = File.basename(file_path, ".*")
60
+ dir = File.dirname(file_path)
61
+ safe_name = (diagram.name || "diagram").gsub(/[^\w.\-]+/, "_")
62
+ File.join(dir, "#{base}.#{safe_name}.svg")
63
+ end
64
+ end
65
+ end
66
+ end
67
+ end
68
+ end
@@ -11,6 +11,7 @@ module Ea
11
11
  autoload :Parse, "ea/cli/command/parse"
12
12
  autoload :Convert, "ea/cli/command/convert"
13
13
  autoload :Spa, "ea/cli/command/spa"
14
+ autoload :Svg, "ea/cli/command/svg"
14
15
  autoload :RepositoryBuilder, "ea/cli/command/repository_builder"
15
16
  end
16
17
  end
@@ -0,0 +1,29 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Ea
4
+ module Model
5
+ # First-class annotation: comments, documentation, change notes,
6
+ # requirements, file references — the textual meta-content EA
7
+ # authors attach to model elements.
8
+ #
9
+ # Modeled as a typed concept rather than a packed string, so the
10
+ # SPA can show different annotation kinds with appropriate
11
+ # presentation (e.g. documentation gets rendered as markdown,
12
+ # change history goes in a sidebar).
13
+ class Annotation < Base
14
+ attribute :kind, :string # comment|documentation|change|file|requirement
15
+ attribute :body, :string
16
+ attribute :author, :string
17
+ attribute :modified_date, :string
18
+ attribute :language, :string
19
+
20
+ json do
21
+ map "kind", to: :kind
22
+ map "body", to: :body
23
+ map "author", to: :author
24
+ map "modifiedDate", to: :modified_date
25
+ map "language", to: :language
26
+ end
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,40 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Ea
4
+ module Model
5
+ # An Association between two classifiers. Each end carries its
6
+ # own role name, multiplicity, aggregation kind, and
7
+ # navigability. Source and target are referenced by id.
8
+ class Association < Relationship
9
+ attribute :source_id, :string
10
+ attribute :target_id, :string
11
+ attribute :source_role_name, :string
12
+ attribute :target_role_name, :string
13
+ attribute :source_multiplicity_lower, :integer
14
+ attribute :source_multiplicity_upper, :integer
15
+ attribute :target_multiplicity_lower, :integer
16
+ attribute :target_multiplicity_upper, :integer
17
+ attribute :source_aggregation, :string, default: -> { "none" }
18
+ attribute :target_aggregation, :string, default: -> { "none" }
19
+ attribute :source_navigable, :boolean, default: true
20
+ attribute :target_navigable, :boolean, default: true
21
+
22
+ attribute :relationship_kind, :string, default: -> { "association" }
23
+
24
+ json do
25
+ map "sourceId", to: :source_id
26
+ map "targetId", to: :target_id
27
+ map "sourceRoleName", to: :source_role_name
28
+ map "targetRoleName", to: :target_role_name
29
+ map "sourceMultiplicityLower", to: :source_multiplicity_lower
30
+ map "sourceMultiplicityUpper", to: :source_multiplicity_upper
31
+ map "targetMultiplicityLower", to: :target_multiplicity_lower
32
+ map "targetMultiplicityUpper", to: :target_multiplicity_upper
33
+ map "sourceAggregation", to: :source_aggregation, render_default: true
34
+ map "targetAggregation", to: :target_aggregation, render_default: true
35
+ map "sourceNavigable", to: :source_navigable, render_default: true
36
+ map "targetNavigable", to: :target_navigable, render_default: true
37
+ end
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,27 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Ea
4
+ module Model
5
+ # Common base for every Ea::Model type.
6
+ #
7
+ # Every model element has a stable identity (`id`) used to
8
+ # reference it from other elements (e.g. a Property refers to its
9
+ # type by id, a Relationship refers to its ends by id). Source
10
+ # adapters normalize the source-specific identifier (xmi:id,
11
+ # ea_guid, etc.) into this `id` field.
12
+ class Base < Lutaml::Model::Serializable
13
+ attribute :id, :string
14
+ attribute :name, :string
15
+
16
+ json do
17
+ map "id", to: :id
18
+ map "name", to: :name
19
+ end
20
+
21
+ yaml do
22
+ map "id", to: :id
23
+ map "name", to: :name
24
+ end
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,22 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Ea
4
+ module Model
5
+ # Rectangular bounds in diagram pixel coordinates. Used by
6
+ # DiagramElement to record where a classifier is placed on a
7
+ # diagram.
8
+ class Bounds < Base
9
+ attribute :x, :integer
10
+ attribute :y, :integer
11
+ attribute :width, :integer
12
+ attribute :height, :integer
13
+
14
+ json do
15
+ map "x", to: :x
16
+ map "y", to: :y
17
+ map "width", to: :width
18
+ map "height", to: :height
19
+ end
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,41 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Ea
4
+ module Model
5
+ # Abstract base for Class, DataType, Enumeration, Interface,
6
+ # PrimitiveType — anything that can be a type of a Property, an
7
+ # end of an Association, etc.
8
+ #
9
+ # Concrete subclasses live in their own files and add their own
10
+ # specific attributes (e.g. Enumeration#literals). Source
11
+ # adapters dispatch on the source's type discriminator
12
+ # (t_object.Object_Type, xmi:type) to pick the right subclass.
13
+ class Classifier < Base
14
+ attribute :qualified_name, :string
15
+ attribute :package_id, :string # containing package
16
+ attribute :is_abstract, :boolean, default: false
17
+ attribute :visibility, :string
18
+ attribute :model_kind, :string, default: -> { "classifier" }
19
+ attribute :properties, Property, collection: true, initialize_empty: true
20
+ attribute :operations, Operation, collection: true, initialize_empty: true
21
+ attribute :stereotype_refs, :string, collection: true, initialize_empty: true
22
+ attribute :tagged_values, TaggedValue, collection: true, initialize_empty: true
23
+ attribute :annotations, Annotation, collection: true, initialize_empty: true
24
+
25
+ json do
26
+ map "id", to: :id
27
+ map "name", to: :name
28
+ map "qualifiedName", to: :qualified_name
29
+ map "packageId", to: :package_id
30
+ map "isAbstract", to: :is_abstract, render_default: true
31
+ map "visibility", to: :visibility
32
+ map "modelKind", to: :model_kind, render_default: true
33
+ map "properties", to: :properties, render_empty: true
34
+ map "operations", to: :operations, render_empty: true
35
+ map "stereotypeRefs", to: :stereotype_refs, render_empty: true
36
+ map "taggedValues", to: :tagged_values, render_empty: true
37
+ map "annotations", to: :annotations, render_empty: true
38
+ end
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,9 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Ea
4
+ module Model
5
+ class DataType < Classifier
6
+ attribute :model_kind, :string, default: -> { "data_type" }
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,19 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Ea
4
+ module Model
5
+ # Dependency: client depends on supplier. No semantic
6
+ # implication beyond "client references supplier".
7
+ class Dependency < Relationship
8
+ attribute :client_id, :string
9
+ attribute :supplier_id, :string
10
+
11
+ attribute :relationship_kind, :string, default: -> { "dependency" }
12
+
13
+ json do
14
+ map "clientId", to: :client_id
15
+ map "supplierId", to: :supplier_id
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,28 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Ea
4
+ module Model
5
+ # A diagram: an ordered set of placed elements and connectors.
6
+ # The diagram references the package it belongs to (by id) and
7
+ # owns its elements/connectors compositionally.
8
+ class Diagram < Base
9
+ attribute :package_id, :string
10
+ attribute :diagram_type, :string # logical|class|sequence|use_case|...
11
+ attribute :bounds, Bounds # canvas size
12
+ attribute :elements, DiagramElement, collection: true, initialize_empty: true
13
+ attribute :connectors, DiagramConnector, collection: true, initialize_empty: true
14
+ attribute :annotations, Annotation, collection: true, initialize_empty: true
15
+
16
+ json do
17
+ map "id", to: :id
18
+ map "name", to: :name
19
+ map "packageId", to: :package_id
20
+ map "diagramType", to: :diagram_type
21
+ map "bounds", to: :bounds
22
+ map "elements", to: :elements, render_empty: true
23
+ map "connectors", to: :connectors, render_empty: true
24
+ map "annotations", to: :annotations, render_empty: true
25
+ end
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,30 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Ea
4
+ module Model
5
+ # A connector drawn on a diagram between two DiagramElements.
6
+ # References the underlying Relationship (by id) and the source
7
+ # and target DiagramElements (by id). Carries ordered waypoints
8
+ # for routing.
9
+ class DiagramConnector < Base
10
+ attribute :diagram_id, :string
11
+ attribute :relationship_ref, :string
12
+ attribute :source_element_ref, :string
13
+ attribute :target_element_ref, :string
14
+ attribute :waypoints, Waypoint, collection: true, initialize_empty: true
15
+ attribute :label, :string
16
+ attribute :style, :hash, default: -> { {} }
17
+
18
+ json do
19
+ map "id", to: :id
20
+ map "diagramId", to: :diagram_id
21
+ map "relationshipRef", to: :relationship_ref
22
+ map "sourceElementRef", to: :source_element_ref
23
+ map "targetElementRef", to: :target_element_ref
24
+ map "waypoints", to: :waypoints, render_empty: true
25
+ map "label", to: :label
26
+ map "style", to: :style
27
+ end
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,23 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Ea
4
+ module Model
5
+ # A single placed element on a diagram. References the model
6
+ # element it visualizes (by id), carries pixel bounds and a
7
+ # parsed style map (fill color, line color, font, etc.).
8
+ class DiagramElement < Base
9
+ attribute :diagram_id, :string
10
+ attribute :model_element_ref, :string # id of Classifier/Package/etc.
11
+ attribute :bounds, Bounds
12
+ attribute :style, :hash, default: -> { {} } # parsed style fields
13
+
14
+ json do
15
+ map "id", to: :id
16
+ map "diagramId", to: :diagram_id
17
+ map "modelElementRef", to: :model_element_ref
18
+ map "bounds", to: :bounds
19
+ map "style", to: :style
20
+ end
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,107 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Ea
4
+ module Model
5
+ # Discriminator → subclass maps for polymorphic Classifier and
6
+ # Relationship collections. Defined here (rather than autoloaded)
7
+ # because lutaml-model needs them at class-evaluation time, and
8
+ # autoload only triggers on first constant reference.
9
+ CLASSIFIER_POLYMORPHIC_MAP = {
10
+ attribute: "modelKind",
11
+ class_map: {
12
+ "class" => "Ea::Model::Klass",
13
+ "data_type" => "Ea::Model::DataType",
14
+ "primitive_type" => "Ea::Model::PrimitiveType",
15
+ "enumeration" => "Ea::Model::Enumeration",
16
+ "interface" => "Ea::Model::Interface"
17
+ }
18
+ }.freeze
19
+
20
+ RELATIONSHIP_POLYMORPHIC_MAP = {
21
+ attribute: "relationshipKind",
22
+ class_map: {
23
+ "association" => "Ea::Model::Association",
24
+ "generalization" => "Ea::Model::Generalization",
25
+ "realization" => "Ea::Model::Realization",
26
+ "dependency" => "Ea::Model::Dependency"
27
+ }
28
+ }.freeze
29
+
30
+ # Root container for a harmonized model. Source adapters build
31
+ # one of these; consumer adapters read from it.
32
+ #
33
+ # Element identity is global within the document: every package,
34
+ # classifier, relationship, diagram, and diagram element has a
35
+ # unique `id`. References between elements are by id, so the
36
+ # document can be sharded cheaply (no need to walk a tree to
37
+ # resolve a reference).
38
+ class Document < Base
39
+ attribute :metadata, Metadata
40
+ attribute :packages, Package, collection: true, initialize_empty: true
41
+ attribute :classifiers, Classifier, collection: true, initialize_empty: true,
42
+ polymorphic: CLASSIFIER_POLYMORPHIC_MAP
43
+ attribute :relationships, Relationship, collection: true, initialize_empty: true,
44
+ polymorphic: RELATIONSHIP_POLYMORPHIC_MAP
45
+ attribute :stereotypes, Stereotype, collection: true, initialize_empty: true
46
+ attribute :diagrams, Diagram, collection: true, initialize_empty: true
47
+
48
+ # Flat lookup indexes, built lazily by consumers. Not
49
+ # serialized — they're derived from the element collections.
50
+ def index_by_id
51
+ @index_by_id ||= begin
52
+ idx = {}
53
+ packages.each { |p| idx[p.id] = p }
54
+ classifiers.each { |c| idx[c.id] = c }
55
+ relationships.each { |r| idx[r.id] = r }
56
+ stereotypes.each { |s| idx[s.id] = s }
57
+ diagrams.each { |d| idx[d.id] = d }
58
+ diagrams.each do |d|
59
+ d.elements.each { |e| idx[e.id] = e }
60
+ d.connectors.each { |c| idx[c.id] = c }
61
+ end
62
+ idx
63
+ end
64
+ end
65
+
66
+ def root_packages
67
+ packages.select { |p| p.parent_id.nil? }
68
+ end
69
+
70
+ def classifiers_in_package(package_id)
71
+ classifiers.select { |c| c.package_id == package_id }
72
+ end
73
+
74
+ def relationships_for(classifier_id)
75
+ relationships.select do |r|
76
+ case r
77
+ when Association
78
+ r.source_id == classifier_id || r.target_id == classifier_id
79
+ when Generalization
80
+ r.specific_id == classifier_id || r.general_id == classifier_id
81
+ when Realization
82
+ r.realizing_id == classifier_id || r.contract_id == classifier_id
83
+ when Dependency
84
+ r.client_id == classifier_id || r.supplier_id == classifier_id
85
+ else
86
+ false
87
+ end
88
+ end
89
+ end
90
+
91
+ def reset_indexes
92
+ @index_by_id = nil
93
+ end
94
+
95
+ json do
96
+ map "metadata", to: :metadata
97
+ map "packages", to: :packages, render_empty: true
98
+ map "classifiers", to: :classifiers, render_empty: true,
99
+ polymorphic: CLASSIFIER_POLYMORPHIC_MAP
100
+ map "relationships", to: :relationships, render_empty: true,
101
+ polymorphic: RELATIONSHIP_POLYMORPHIC_MAP
102
+ map "stereotypes", to: :stereotypes, render_empty: true
103
+ map "diagrams", to: :diagrams, render_empty: true
104
+ end
105
+ end
106
+ end
107
+ end
@@ -0,0 +1,15 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Ea
4
+ module Model
5
+ class Enumeration < Classifier
6
+ attribute :model_kind, :string, default: -> { "enumeration" }
7
+ attribute :literals, EnumerationLiteral, collection: true,
8
+ initialize_empty: true
9
+
10
+ json do
11
+ map "literals", to: :literals, render_empty: true
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,16 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Ea
4
+ module Model
5
+ # A single literal of an Enumeration.
6
+ class EnumerationLiteral < Base
7
+ attribute :value, :string
8
+ attribute :ordinal, :integer
9
+
10
+ json do
11
+ map "value", to: :value
12
+ map "ordinal", to: :ordinal
13
+ end
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,19 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Ea
4
+ module Model
5
+ # Generalization (inheritance): specific (child) extends
6
+ # general (parent).
7
+ class Generalization < Relationship
8
+ attribute :specific_id, :string # child
9
+ attribute :general_id, :string # parent
10
+
11
+ attribute :relationship_kind, :string, default: -> { "generalization" }
12
+
13
+ json do
14
+ map "specificId", to: :specific_id
15
+ map "generalId", to: :general_id
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,9 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Ea
4
+ module Model
5
+ class Interface < Classifier
6
+ attribute :model_kind, :string, default: -> { "interface" }
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,16 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Ea
4
+ module Model
5
+ # Named `Klass` (not `Class`) to avoid collision with Ruby's
6
+ # built-in Class. Represents a UML Class.
7
+ class Klass < Classifier
8
+ attribute :model_kind, :string, default: -> { "class" }
9
+ attribute :is_active, :boolean, default: false
10
+
11
+ json do
12
+ map "isActive", to: :is_active, render_default: true
13
+ end
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,31 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Ea
4
+ module Model
5
+ # Document-level metadata. Captured during source adaptation;
6
+ # surfaced by the SPA as project info.
7
+ class Metadata < Base
8
+ attribute :title, :string
9
+ attribute :version, :string
10
+ attribute :author, :string
11
+ attribute :company, :string
12
+ attribute :created_date, :string
13
+ attribute :modified_date, :string
14
+ attribute :source_format, :string # "qea" | "xmi"
15
+ attribute :source_tool, :string # e.g. "Sparx EA 16.0"
16
+ attribute :source_path, :string
17
+
18
+ json do
19
+ map "title", to: :title
20
+ map "version", to: :version
21
+ map "author", to: :author
22
+ map "company", to: :company
23
+ map "createdDate", to: :created_date
24
+ map "modifiedDate", to: :modified_date
25
+ map "sourceFormat", to: :source_format
26
+ map "sourceTool", to: :source_tool
27
+ map "sourcePath", to: :source_path
28
+ end
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,33 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Ea
4
+ module Model
5
+ # An Operation on a Classifier (method). Parameters are owned
6
+ # composition-style.
7
+ class Operation < Base
8
+ attribute :owner_id, :string
9
+ attribute :qualified_name, :string
10
+ attribute :return_type_name, :string
11
+ attribute :is_static, :boolean, default: false
12
+ attribute :is_abstract, :boolean, default: false
13
+ attribute :visibility, :string
14
+ attribute :parameters, Parameter, collection: true, initialize_empty: true
15
+ attribute :stereotype_refs, :string, collection: true, initialize_empty: true
16
+ attribute :annotations, Annotation, collection: true, initialize_empty: true
17
+
18
+ json do
19
+ map "id", to: :id
20
+ map "name", to: :name
21
+ map "ownerId", to: :owner_id
22
+ map "qualifiedName", to: :qualified_name
23
+ map "returnTypeName", to: :return_type_name
24
+ map "isStatic", to: :is_static, render_default: true
25
+ map "isAbstract", to: :is_abstract, render_default: true
26
+ map "visibility", to: :visibility
27
+ map "parameters", to: :parameters, render_empty: true
28
+ map "stereotypeRefs", to: :stereotype_refs, render_empty: true
29
+ map "annotations", to: :annotations, render_empty: true
30
+ end
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,36 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Ea
4
+ module Model
5
+ # A Package: hierarchical container for sub-packages and
6
+ # classifiers. References children by id (flat index in the
7
+ # Document) rather than nesting, so the same model is cheap to
8
+ # serialize, shard, and walk from any entry point.
9
+ class Package < Base
10
+ attribute :parent_id, :string # nil for root
11
+ attribute :qualified_name, :string
12
+ attribute :sub_package_ids, :string, collection: true,
13
+ initialize_empty: true
14
+ attribute :classifier_ids, :string, collection: true,
15
+ initialize_empty: true
16
+ attribute :diagram_ids, :string, collection: true,
17
+ initialize_empty: true
18
+ attribute :stereotype_refs, :string, collection: true, initialize_empty: true
19
+ attribute :tagged_values, TaggedValue, collection: true, initialize_empty: true
20
+ attribute :annotations, Annotation, collection: true, initialize_empty: true
21
+
22
+ json do
23
+ map "id", to: :id
24
+ map "name", to: :name
25
+ map "parentId", to: :parent_id
26
+ map "qualifiedName", to: :qualified_name
27
+ map "subPackageIds", to: :sub_package_ids, render_empty: true
28
+ map "classifierIds", to: :classifier_ids, render_empty: true
29
+ map "diagramIds", to: :diagram_ids, render_empty: true
30
+ map "stereotypeRefs", to: :stereotype_refs, render_empty: true
31
+ map "taggedValues", to: :tagged_values, render_empty: true
32
+ map "annotations", to: :annotations, render_empty: true
33
+ end
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,24 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Ea
4
+ module Model
5
+ # A single parameter of an Operation.
6
+ class Parameter < Base
7
+ attribute :ordinal, :integer
8
+ attribute :direction, :string, default: -> { "in" } # in|out|inout|return
9
+ attribute :type_name, :string
10
+ attribute :multiplicity_lower, :integer
11
+ attribute :multiplicity_upper, :integer
12
+ attribute :default_value, :string
13
+
14
+ json do
15
+ map "ordinal", to: :ordinal
16
+ map "direction", to: :direction
17
+ map "typeName", to: :type_name
18
+ map "multiplicityLower", to: :multiplicity_lower
19
+ map "multiplicityUpper", to: :multiplicity_upper
20
+ map "defaultValue", to: :default_value
21
+ end
22
+ end
23
+ end
24
+ end