ea 0.5.2 → 0.6.0
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/TODO.complete/01-t-xref-parsing.md +1 -1
- data/TODO.complete/02-per-label-geometry.md +1 -1
- data/TODO.complete/03-object-properties-constraints.md +1 -1
- data/TODO.complete/04-operation-params.md +1 -1
- data/TODO.complete/05-pdata-flag-matrix.md +1 -1
- data/TODO.complete/06-emf-image-rendering.md +1 -1
- data/TODO.complete/07-auxiliary-tables.md +1 -1
- data/TODO.complete/10-mdg-stereotype-registry.md +1 -1
- data/TODO.complete/11-gml-xsd-generation.md +1 -1
- data/TODO.complete/13-shapescript-interpreter.md +12 -23
- data/TODO.complete/20-cli-diff.md +1 -1
- data/TODO.complete/21-cli-render.md +1 -1
- data/TODO.complete/22-cli-export.md +1 -1
- data/TODO.complete/23-cli-mdg.md +1 -1
- data/TODO.complete/30-headerlines-ocp-refactor.md +1 -1
- data/TODO.complete/32-spec-coverage.md +1 -1
- data/TODO.complete/33-blocked-parity-gaps.md +1 -1
- data/TODO.complete/36-stereotype-icon-wiring.md +1 -1
- data/TODO.complete/37-cli-lint.md +1 -1
- data/TODO.complete/38-cli-query.md +1 -1
- data/TODO.complete/39-cli-info.md +1 -1
- data/TODO.complete/40-ocl-evaluator.md +1 -1
- data/TODO.complete/41-round-trip-spec.md +1 -1
- data/TODO.complete/42-html-diff-report.md +1 -1
- data/TODO.complete/43-json-schema-export.md +1 -1
- data/TODO.complete/44-remaining-qea-tables.md +1 -1
- data/TODO.complete/45-shapescript-extensions.md +1 -1
- data/TODO.complete/46-xsd-consolidation.md +1 -1
- data/TODO.complete/47-headerlines-legacy-removal.md +1 -1
- data/TODO.complete/51-remove-respond-to.md +42 -15
- data/TODO.complete/52-xsd-decouple-fixtures.md +1 -1
- data/TODO.complete/54-wire-stereotype-icon-renderer.md +1 -1
- data/TODO.complete/55-wire-shapescript.md +1 -1
- data/TODO.complete/56-wire-emf-renderer.md +1 -1
- data/TODO.complete/57-wire-ocl-evaluator.md +1 -1
- data/TODO.complete/58-diff-modifications.md +1 -1
- data/TODO.complete/59-delete-toy-xmi-export.md +1 -1
- data/TODO.complete/60-curate-json-export.md +1 -1
- data/TODO.complete/61-plantuml-relationships.md +1 -1
- data/TODO.complete/62-changelog.md +1 -1
- data/TODO.complete/63-dependabot-fix.md +1 -1
- data/TODO.complete/64-qeatoxmi-connectors.md +9 -24
- data/TODO.complete/65-qeatoxmi-diagrams.md +9 -23
- data/TODO.complete/66-qeatoxmi-style-tags-docs.md +25 -18
- data/TODO.complete/67-ocl-collection-ops.md +12 -12
- data/TODO.complete/68-ocl-comparison-ops.md +16 -11
- data/TODO.complete/69-spec-new-models.md +13 -18
- data/TODO.complete/70-specs-for-all-models.md +21 -0
- data/TODO.complete/71-autoload-audit.md +26 -0
- data/TODO.complete/72-extension-serializer-ocp-naming.md +26 -0
- data/TODO.complete/73-ocl-validator-latent-bugs.md +50 -0
- data/TODO.complete/74-visibility-symbol-dry.md +39 -0
- data/TODO.complete/75-database-table-collection-registry.md +32 -0
- data/TODO.complete/76-stale-todo-cleanup.md +52 -0
- data/TODO.complete/77-eliminate-banned-patterns-from-specs.md +55 -0
- data/TODO.complete/78-mdg-stereotype-emission.md +66 -0
- data/TODO.complete/79-equivalence-fixes.md +57 -0
- data/TODO.complete/80-performance-extension-serializer-indexes.md +43 -0
- data/TODO.complete/81-dry-scope-guid-extraction.md +33 -0
- data/TODO.complete/82-public-send-audit-conclusion.md +25 -0
- data/TODO.complete/83-dry-shared-xml-escape-guid-format.md +52 -0
- data/TODO.complete/84-ocp-markers-shape-registry.md +54 -0
- data/TODO.complete/85-frozen-literal-rubocop-normalize-type-spec.md +38 -0
- data/TODO.complete/86-frozen-sweep-lint-query-specs.md +55 -0
- data/TODO.complete/STATUS.md +26 -5
- data/lib/ea/cli/app.rb +1 -0
- data/lib/ea/cli/command/export.rb +10 -1
- data/lib/ea/cli/command/mdg.rb +1 -10
- data/lib/ea/cli/command/render.rb +2 -1
- data/lib/ea/diff/html_reporter.rb +1 -5
- data/lib/ea/export/json/generator.rb +5 -6
- data/lib/ea/export/plantuml/generator.rb +5 -3
- data/lib/ea/guid_format.rb +91 -0
- data/lib/ea/mdg/document.rb +2 -1
- data/lib/ea/mdg/loader.rb +2 -1
- data/lib/ea/mdg/registry.rb +57 -2
- data/lib/ea/mdg/xml/applies_to.rb +1 -1
- data/lib/ea/mdg/xml/apply.rb +1 -1
- data/lib/ea/mdg/xml/content.rb +1 -1
- data/lib/ea/mdg/xml/documentation.rb +1 -1
- data/lib/ea/mdg/xml/stereotype.rb +1 -1
- data/lib/ea/mdg/xml/stereotypes.rb +1 -1
- data/lib/ea/mdg/xml/tag.rb +1 -1
- data/lib/ea/mdg/xml/tagged_values.rb +1 -1
- data/lib/ea/mdg/xml/technology.rb +1 -1
- data/lib/ea/mdg/xml/uml_profile.rb +1 -1
- data/lib/ea/mdg/xml/uml_profiles.rb +1 -1
- data/lib/ea/mdg/xml.rb +2 -1
- data/lib/ea/mdg.rb +2 -1
- data/lib/ea/model/ghost_label.rb +2 -1
- data/lib/ea/ocl/evaluator.rb +4 -2
- data/lib/ea/qea/database.rb +57 -2
- data/lib/ea/qea/factory/reference_resolver.rb +1 -1
- data/lib/ea/qea/models/ea_attribute.rb +1 -17
- data/lib/ea/qea/models/ea_connector.rb +3 -2
- data/lib/ea/qea/models/ea_object.rb +14 -9
- data/lib/ea/qea/models/ea_operation.rb +1 -17
- data/lib/ea/qea/models/ea_xref.rb +3 -0
- data/lib/ea/qea/models/scope_predicate.rb +29 -0
- data/lib/ea/qea/models.rb +1 -0
- data/lib/ea/qea/repositories/base_repository.rb +4 -1
- data/lib/ea/qea/validation/base_validator.rb +3 -48
- data/lib/ea/qea/validation/database/ocl_constraint_validator.rb +23 -13
- data/lib/ea/shapescript/renderer.rb +1 -3
- data/lib/ea/sources/qea/diagram_builder.rb +1 -0
- data/lib/ea/sources/qea/id_normalizer.rb +2 -2
- data/lib/ea/svg/ea_emitter/background.rb +2 -1
- data/lib/ea/svg/ea_emitter/element/attribute_line_builder.rb +1 -6
- data/lib/ea/svg/ea_emitter/element/operation_renderer.rb +2 -7
- data/lib/ea/svg/ea_emitter/elements.rb +1 -3
- data/lib/ea/svg/ea_emitter/ghost_labels.rb +2 -1
- data/lib/ea/svg/ea_emitter/label/end_label.rb +1 -6
- data/lib/ea/svg/ea_emitter/marker/package_import.rb +1 -1
- data/lib/ea/svg/ea_emitter/markers.rb +52 -23
- data/lib/ea/svg/ea_emitter/text_renderer.rb +1 -4
- data/lib/ea/svg/ea_emitter/visibility_symbol.rb +37 -0
- data/lib/ea/svg/ea_emitter.rb +1 -0
- data/lib/ea/svg/parity/source.rb +0 -2
- data/lib/ea/svg/parity/suite.rb +0 -1
- data/lib/ea/transformers/qea_to_xmi/cardinality.rb +40 -28
- data/lib/ea/transformers/qea_to_xmi/context.rb +35 -1
- data/lib/ea/transformers/qea_to_xmi/extension_serializer.rb +686 -0
- data/lib/ea/transformers/qea_to_xmi/guid_format.rb +5 -48
- data/lib/ea/transformers/qea_to_xmi/id_allocator.rb +55 -54
- data/lib/ea/transformers/qea_to_xmi/primitive_types.rb +105 -0
- data/lib/ea/transformers/qea_to_xmi/profile_serializer.rb +163 -0
- data/lib/ea/transformers/qea_to_xmi/run_state.rb +7 -6
- data/lib/ea/transformers/qea_to_xmi/transformer.rb +396 -185
- data/lib/ea/transformers/qea_to_xmi/visibility.rb +30 -19
- data/lib/ea/transformers/qea_to_xmi.rb +5 -2
- data/lib/ea/transformers.rb +7 -2
- data/lib/ea/validation.rb +1 -1
- data/lib/ea/version.rb +1 -1
- data/lib/ea/xmi/liquid_drops/attribute_drop.rb +12 -4
- data/lib/ea/xmi/liquid_drops/klass_drop.rb +1 -2
- data/lib/ea/xmi/lookup_service.rb +4 -0
- data/lib/ea/xmi/parser.rb +30 -1
- data/lib/ea/xml_escape.rb +21 -0
- data/lib/ea.rb +2 -0
- metadata +28 -11
- data/lutaml-uml-0.5.1.gem +0 -0
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Ea
|
|
4
|
+
module Svg
|
|
5
|
+
module EaEmitter
|
|
6
|
+
# Maps UML visibility strings to EA's single-character symbols.
|
|
7
|
+
#
|
|
8
|
+
# Centralised so that adding a new visibility level (e.g.
|
|
9
|
+
# "implementation" in Java) changes one hash entry, not three
|
|
10
|
+
# case/when branches across separate renderer files.
|
|
11
|
+
#
|
|
12
|
+
# EA's convention:
|
|
13
|
+
# + public
|
|
14
|
+
# - private
|
|
15
|
+
# # protected
|
|
16
|
+
# ~ package
|
|
17
|
+
module VisibilitySymbol
|
|
18
|
+
SYMBOLS = {
|
|
19
|
+
"public" => "+",
|
|
20
|
+
"private" => "-",
|
|
21
|
+
"protected" => "#",
|
|
22
|
+
"package" => "~"
|
|
23
|
+
}.freeze
|
|
24
|
+
|
|
25
|
+
# @param visibility [String, nil] EA scope string ("Public",
|
|
26
|
+
# "Private", etc.). Case-insensitive; nil defaults to public.
|
|
27
|
+
# @param with_space [Boolean] append a trailing space (used
|
|
28
|
+
# by operation renderers: "+ method", not "+method").
|
|
29
|
+
# @return [String] the UML visibility symbol
|
|
30
|
+
def self.for(visibility, with_space: false)
|
|
31
|
+
symbol = SYMBOLS[(visibility || "public").downcase] || "+"
|
|
32
|
+
with_space ? "#{symbol} " : symbol
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
end
|
data/lib/ea/svg/ea_emitter.rb
CHANGED
|
@@ -46,6 +46,7 @@ module Ea
|
|
|
46
46
|
autoload :Label, "ea/svg/ea_emitter/label"
|
|
47
47
|
autoload :Compartment, "ea/svg/ea_emitter/compartment"
|
|
48
48
|
autoload :RenderContext, "ea/svg/ea_emitter/render_context"
|
|
49
|
+
autoload :VisibilitySymbol, "ea/svg/ea_emitter/visibility_symbol"
|
|
49
50
|
end
|
|
50
51
|
end
|
|
51
52
|
end
|
data/lib/ea/svg/parity/source.rb
CHANGED
data/lib/ea/svg/parity/suite.rb
CHANGED
|
@@ -13,21 +13,42 @@ module Ea
|
|
|
13
13
|
# `<upperValue value="M"/>`) — never a range string. This module
|
|
14
14
|
# translates the EA form to a `{ lower:, upper: }` pair.
|
|
15
15
|
#
|
|
16
|
-
# Default-when-empty:
|
|
17
|
-
#
|
|
18
|
-
#
|
|
19
|
-
#
|
|
20
|
-
# real Sparx XMI (see TODO 26).
|
|
16
|
+
# Default-when-empty: blank input maps to UML's unspecified
|
|
17
|
+
# multiplicity, `{ lower: "0", upper: "*" }`. Whether those
|
|
18
|
+
# bounds reach the document is the caller's call — EA leaves an
|
|
19
|
+
# association end bare when its card field is blank.
|
|
21
20
|
module Cardinality
|
|
22
21
|
# Tokens EA uses for "unbounded". Matched case-insensitively.
|
|
23
|
-
UNLIMITED_TOKENS = %w[* *-1 unbounded].freeze
|
|
22
|
+
UNLIMITED_TOKENS = %w[* *-1 -1 unbounded].freeze
|
|
24
23
|
|
|
25
|
-
# UML defaults when EA carries no explicit bound.
|
|
24
|
+
# UML defaults when EA carries no explicit bound. EA's wire
|
|
25
|
+
# form for unlimited is "*" (never "-1" — the reference
|
|
26
|
+
# exports contain no value="-1" at all).
|
|
26
27
|
DEFAULT_LOWER = "0"
|
|
27
|
-
DEFAULT_UPPER = "
|
|
28
|
+
DEFAULT_UPPER = "*"
|
|
29
|
+
|
|
30
|
+
# EA writes an explicit 1..1 for a Property whose t_attribute
|
|
31
|
+
# bound columns are BOTH blank, rather than falling back to the
|
|
32
|
+
# UML unspecified multiplicity.
|
|
33
|
+
DEFAULT_ATTRIBUTE_BOUNDS = { lower: "1", upper: "1" }.freeze
|
|
28
34
|
|
|
29
35
|
module_function
|
|
30
36
|
|
|
37
|
+
# The bound pair for a t_attribute row. The 1..1 default is a
|
|
38
|
+
# property of the PAIR — with one column set, the missing side
|
|
39
|
+
# keeps the normal UML fallback, so `2` and a blank upper is
|
|
40
|
+
# 2..* rather than the invalid 2..1.
|
|
41
|
+
#
|
|
42
|
+
# @param lower [String, Integer, nil] t_attribute.lowerbound
|
|
43
|
+
# @param upper [String, Integer, nil] t_attribute.upperbound
|
|
44
|
+
# @return [Hash{Symbol=>String}] `{ lower:, upper: }`
|
|
45
|
+
def attribute_bounds(lower, upper)
|
|
46
|
+
both_blank = lower.to_s.strip.empty? && upper.to_s.strip.empty?
|
|
47
|
+
return DEFAULT_ATTRIBUTE_BOUNDS if both_blank
|
|
48
|
+
|
|
49
|
+
{ lower: normalize_lower(lower), upper: normalize_upper(upper) }.freeze
|
|
50
|
+
end
|
|
51
|
+
|
|
31
52
|
# @param raw [String, nil] e.g. "1..*", "0..1", "1", "*", nil
|
|
32
53
|
# @return [Hash{Symbol=>String}] `{ lower:, upper: }` always
|
|
33
54
|
# populated; never nil. Empty/nil input returns the UML default.
|
|
@@ -38,17 +59,14 @@ module Ea
|
|
|
38
59
|
return parse_range(stripped) if stripped.include?("..")
|
|
39
60
|
|
|
40
61
|
# Bare unlimited token (e.g. "*") means "many" — lower bound
|
|
41
|
-
# is unspecified, which
|
|
42
|
-
# `{ lower: "-1", upper: "-1" }` here would be invalid:
|
|
43
|
-
# LiteralInteger cannot hold -1.
|
|
62
|
+
# is unspecified, which renders as 0..*.
|
|
44
63
|
return defaults if UNLIMITED_TOKENS.include?(stripped.downcase)
|
|
45
64
|
|
|
46
|
-
|
|
47
|
-
{ lower: single, upper: single }
|
|
65
|
+
{ lower: stripped, upper: stripped }
|
|
48
66
|
end
|
|
49
67
|
|
|
50
|
-
# Normalise an upper-bound token: `*` / `unbounded` →
|
|
51
|
-
# (
|
|
68
|
+
# Normalise an upper-bound token: `*` / `unbounded` → `*`
|
|
69
|
+
# (the LiteralUnlimitedNatural wire form EA also uses).
|
|
52
70
|
# @param raw [String, Integer, nil]
|
|
53
71
|
# @return [String]
|
|
54
72
|
def normalize_upper(raw)
|
|
@@ -57,17 +75,21 @@ module Ea
|
|
|
57
75
|
stripped = raw.to_s.strip
|
|
58
76
|
return DEFAULT_UPPER if stripped.empty?
|
|
59
77
|
|
|
60
|
-
UNLIMITED_TOKENS.include?(stripped.downcase) ? "
|
|
78
|
+
UNLIMITED_TOKENS.include?(stripped.downcase) ? "*" : stripped
|
|
61
79
|
end
|
|
62
80
|
|
|
63
81
|
# Normalise a lower-bound token: empty/nil → "0" (UML default).
|
|
82
|
+
# Unlimited tokens also → "0" — a lower bound serializes as
|
|
83
|
+
# uml:LiteralInteger, which cannot hold `*` or `-1`.
|
|
64
84
|
# @param raw [String, Integer, nil]
|
|
65
85
|
# @return [String]
|
|
66
86
|
def normalize_lower(raw)
|
|
67
87
|
return DEFAULT_LOWER if raw.nil?
|
|
68
88
|
|
|
69
89
|
stripped = raw.to_s.strip
|
|
70
|
-
|
|
90
|
+
return DEFAULT_LOWER if stripped.empty?
|
|
91
|
+
|
|
92
|
+
UNLIMITED_TOKENS.include?(stripped.downcase) ? DEFAULT_LOWER : stripped
|
|
71
93
|
end
|
|
72
94
|
|
|
73
95
|
# ---- Internal helpers ----
|
|
@@ -78,17 +100,7 @@ module Ea
|
|
|
78
100
|
|
|
79
101
|
def parse_range(stripped)
|
|
80
102
|
lower, upper = stripped.split("..", 2)
|
|
81
|
-
{ lower:
|
|
82
|
-
end
|
|
83
|
-
|
|
84
|
-
# A single bound token (one side of `..` or a bare scalar).
|
|
85
|
-
# Empty / `*` → UML unlimited (`-1`).
|
|
86
|
-
def normalize_bound(token)
|
|
87
|
-
return "-1" if token.nil?
|
|
88
|
-
return "-1" if token.strip.empty?
|
|
89
|
-
|
|
90
|
-
stripped = token.strip
|
|
91
|
-
UNLIMITED_TOKENS.include?(stripped.downcase) ? "-1" : stripped
|
|
103
|
+
{ lower: normalize_lower(lower), upper: normalize_upper(upper) }
|
|
92
104
|
end
|
|
93
105
|
end
|
|
94
106
|
end
|
|
@@ -9,6 +9,11 @@ module Ea
|
|
|
9
9
|
# - ID-derivation helpers (`xmi_id_for`, `end_xmi_id_for`) backed by
|
|
10
10
|
# {GuidFormat}
|
|
11
11
|
# - delegated database lookups (objects, packages, attributes, etc.)
|
|
12
|
+
# - the walk's position ordering (`sorted_by_position`), applied at
|
|
13
|
+
# the lookup for operation parameters so the UML tree and the
|
|
14
|
+
# extension block cannot disagree about their order. Attributes
|
|
15
|
+
# and operations are deliberately left for their callers to
|
|
16
|
+
# order — see `attributes_for`.
|
|
12
17
|
#
|
|
13
18
|
# The {Ea::Qea::Database} already maintains its own lookup indexes
|
|
14
19
|
# (object-by-id, connectors-by-object, attributes-by-object, etc.).
|
|
@@ -33,6 +38,17 @@ module Ea
|
|
|
33
38
|
GuidFormat.ea_guid_to_xmi_id(record.ea_guid, prefix: prefix)
|
|
34
39
|
end
|
|
35
40
|
|
|
41
|
+
# Whether a record can anchor a synthesized id. EA derives a
|
|
42
|
+
# synthesized id's tail from its owner's GUID, so an owner
|
|
43
|
+
# without one yields a tailless id. Both the UML tree and the
|
|
44
|
+
# extension block ask this, so they cannot disagree about
|
|
45
|
+
# whether to emit the thing that id would have named.
|
|
46
|
+
# @param record [#ea_guid]
|
|
47
|
+
# @return [Boolean]
|
|
48
|
+
def identifiable?(record)
|
|
49
|
+
!record&.ea_guid.to_s.strip.empty?
|
|
50
|
+
end
|
|
51
|
+
|
|
36
52
|
# @param connector_xmi_id [String]
|
|
37
53
|
# @param side [Symbol] :source or :destination
|
|
38
54
|
# @return [String]
|
|
@@ -66,6 +82,11 @@ module Ea
|
|
|
66
82
|
database.objects_in_package(package_id)
|
|
67
83
|
end
|
|
68
84
|
|
|
85
|
+
# Deliberately NOT ordered here, unlike params_for_operation:
|
|
86
|
+
# the extension block emits attributes in database order while
|
|
87
|
+
# the LI-bound preallocation sorts them by name, so each caller
|
|
88
|
+
# orders for itself. Sorting at this lookup would move export
|
|
89
|
+
# bytes.
|
|
69
90
|
# @param object_id [Integer]
|
|
70
91
|
# @return [Array<Ea::Qea::Models::EaAttribute>]
|
|
71
92
|
def attributes_for(object_id)
|
|
@@ -78,10 +99,23 @@ module Ea
|
|
|
78
99
|
database.operations_for_object(object_id)
|
|
79
100
|
end
|
|
80
101
|
|
|
102
|
+
# t_operationparams is loaded with an unordered SELECT, and both
|
|
103
|
+
# the UML tree and the extension block emit parameters in Pos
|
|
104
|
+
# order. Ordering here means no caller can obtain them unordered.
|
|
81
105
|
# @param operation_id [Integer]
|
|
82
106
|
# @return [Array<Ea::Qea::Models::EaOperationParam>]
|
|
83
107
|
def params_for_operation(operation_id)
|
|
84
|
-
database.operation_params_for(operation_id)
|
|
108
|
+
sorted_by_position(database.operation_params_for(operation_id))
|
|
109
|
+
end
|
|
110
|
+
|
|
111
|
+
# ---- Ordering -----------------------------------------------------
|
|
112
|
+
|
|
113
|
+
# EA emits a record's children in tree-position order (TPos / Pos),
|
|
114
|
+
# ties broken by name.
|
|
115
|
+
# @param records [Array<Ea::Qea::Models::BaseModel>]
|
|
116
|
+
# @return [Array<Ea::Qea::Models::BaseModel>]
|
|
117
|
+
def sorted_by_position(records)
|
|
118
|
+
records.sort_by { |record| [record.sort_position, record.name.to_s] }
|
|
85
119
|
end
|
|
86
120
|
|
|
87
121
|
# Connectors where the object is on either side.
|