ea 0.1.5 → 0.2.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: c45bd1d6024b9307f1d67422299289da426b353aa7ab7b9797d8d577b61529a9
4
- data.tar.gz: afaf525893ce02307e0fe4f6ab2242b8f0d27d9b3e618db56f1d026b8a0e17ac
3
+ metadata.gz: af7f7d010d0ca70a7230803dfd39e5037fda7f983e532ee6e4280ee7f472c16d
4
+ data.tar.gz: badde638cef78b714cc82aa872678b346a6f9ca230784984e5fa3771f040d610
5
5
  SHA512:
6
- metadata.gz: ae6d56dde262515befe5225a721fa2fca37f50e6162efd48eca52cce324508f18df1f0d916264ba531a57e3cc5a4c6a88818bd03fb33b0639129afce0e3a5aef
7
- data.tar.gz: 3ef8943ff38d4ed3c5494f27b29dffc525d1311a47d1452e49f6e34f5147571175d11a26c3931c0d37344b440764584eb184e5e1433b7bbe8d8b90abd40ac8e7
6
+ metadata.gz: 62d4940b0196c8e603905a05471c1770d904142b35a203a1303e479e4f2e7425afd8fac143641c20cb3d855ffa05c7393735d891897b3a3cae0be3bdcc1e950e
7
+ data.tar.gz: d0e112129ac798cc9b35f55666d40e594d9fc604bc6768f5de9cc5f9ac2a95a3dcb66b50cffa78145392b9d7c952ce576d9e0373df82e3645c689412f5f10ae3
data/CLAUDE.md CHANGED
@@ -16,14 +16,42 @@ usable standalone — `lutaml-uml` is an optional dependency for the UML bridge.
16
16
 
17
17
  **Dependency graph**:
18
18
  ```
19
- ea (standalone — sqlite3, rubyzip, nokogiri, xmi, liquid)
20
- └── [optional] lutaml-uml (for Ea::Qea.to_uml bridge → Lutaml::Uml::Document)
19
+ ea (standalone — lutaml-model, lutaml-path, sqlite3, rubyzip, xmi, nokogiri, liquid, thor)
20
+ └── [optional, dev] lutaml-uml (for Ea::Bridge::* → Lutaml::Uml::Document)
21
21
 
22
22
  lutaml-uml (UML metamodel + UmlRepository + SPA — no dependency on ea)
23
23
  └── lutaml-lml
24
24
  └── lutaml (meta-bundle)
25
25
  ```
26
26
 
27
+ **Architecture — pure parse vs bridge**:
28
+
29
+ The ea gem has TWO entry points:
30
+
31
+ ```ruby
32
+ # PURE — no lutaml-uml dependency. Returns internal EA model.
33
+ Ea.parse("model.qea") # → Ea::Qea::Database (SQLite tables as Ruby models)
34
+ Ea.parse("model.xmi") # → Xmi::Sparx::Root (xmi gem's typed Sparx model)
35
+
36
+ # BRIDGE — requires optional lutaml-uml. Returns tool-agnostic UML.
37
+ Ea.to_uml("model.qea") # → Lutaml::Uml::Document (for cross-vendor output)
38
+ Ea.to_uml("model.xmi") # → Lutaml::Uml::Document
39
+ ```
40
+
41
+ All lutaml-uml-dependent code lives under `Ea::Bridge::*`:
42
+ - `Ea::Bridge::QeaToUml` — transforms Ea::Qea::Database → Lutaml::Uml::Document
43
+ - `Ea::Bridge::XmiToUml` — transforms Xmi::Sparx::Root → Lutaml::Uml::Document
44
+
45
+ The bridge is lazy-loaded — `require "ea"` does NOT load lutaml-uml. Only calling
46
+ `Ea.to_uml(...)` (or CLI commands that use it: `ea spa`, `ea diagrams extract`)
47
+ triggers the bridge code path.
48
+
49
+ **Native QEA↔XMI round-trip** (no lutaml-uml):
50
+ ```
51
+ Ea::Transformers::QeaToXmi — Ea::Qea::Database → Sparx XMI string
52
+ Ea::Transformers::UmlToXmi — Lutaml::Uml::Document → Sparx XMI (bridge)
53
+ ```
54
+
27
55
  **XMI parsing**: `Ea::Xmi::Parser` is hard-wired to the Sparx schema
28
56
  (`::Xmi::Sparx::Root.parse_xml`). It cannot parse MagicDraw or Papyrus XMI.
29
57
  When registering with `UmlRepository`, `ea` registers `.xmi` with content
@@ -0,0 +1,30 @@
1
+ # 01 — Release lutaml-uml 0.3.0
2
+
3
+ **Status: PENDING**
4
+
5
+ ## Problem
6
+ The local lutaml-uml has 10 unpushed commits (559 files, +354k LOC)
7
+ containing the UmlRepository + StaticSite + Vue frontend infrastructure.
8
+ None of this is on rubygems. The published versions (0.2.12, 1.0.0)
9
+ don't include any of it.
10
+
11
+ This blocks ea CI — `lutaml/uml_repository` is not installable from
12
+ rubygems.
13
+
14
+ ## Steps
15
+ 1. Commit all local changes on `chore/consolidate-todos` branch.
16
+ 2. Bump version: `0.2.0` → `0.3.0`.
17
+ 3. Verify `bundle exec rspec` passes.
18
+ 4. Push branch + open PR.
19
+ 5. Merge-rebase.
20
+ 6. Trigger GHA release.
21
+
22
+ ## Version rationale
23
+ 0.3.0 not 0.2.13 because the UmlRepository + StaticSite is a major
24
+ feature surface. 0.3.0 continues the 0.x API line (Lutaml::Uml::UmlClass
25
+ etc.) that ea targets. Published 1.0.0 has a different API (renamed
26
+ classes) and should be ignored / yanked.
27
+
28
+ ## Verification
29
+ - `gem list -r --exact lutaml-uml` shows 0.3.0.
30
+ - `gem content lutaml-uml --version 0.3.0 | grep uml_repository` succeeds.
@@ -0,0 +1,33 @@
1
+ # 02 — Fix lutaml meta-gem broken requires
2
+
3
+ **Status: PENDING**
4
+
5
+ ## Problem
6
+ `lib/lutaml.rb` requires 6 files that don't exist:
7
+
8
+ ```ruby
9
+ require "lutaml/converter" # MISSING
10
+ require "lutaml/ea" # MISSING (ea uses Ea:: namespace)
11
+ require "lutaml/xmi" # MISSING (xmi uses Xmi:: namespace)
12
+ require "lutaml/qea" # MISSING
13
+ require "lutaml/model_transformations" # MISSING
14
+ require "lutaml/cli" # MISSING
15
+ ```
16
+
17
+ `require "lutaml"` crashes immediately. The meta-gem is unusable.
18
+
19
+ ## Fix
20
+ Remove the 6 broken requires. Keep only the ones that resolve to
21
+ real files in the gem's own `lib/` tree:
22
+
23
+ ```ruby
24
+ require_relative "lutaml/version"
25
+ require "lutaml/lml"
26
+ require "lutaml/uml"
27
+ require "lutaml/uml_repository"
28
+ ```
29
+
30
+ ## Note
31
+ The meta-gem should NOT try to remap other gems' namespaces. The ea
32
+ gem uses `Ea::*`, the xmi gem uses `Xmi::*`. Users who want both should
33
+ `require "ea"` and `require "xmi"` explicitly.
@@ -0,0 +1,20 @@
1
+ # 03 — Release lutaml 0.11.0
2
+
3
+ **Status: PENDING (depends on 02)**
4
+
5
+ ## Problem
6
+ Published 0.10.19 has phantom runtime deps (htmlentities, liquid,
7
+ listen, nokogiri, paint, lutaml-path) that shouldn't be in the
8
+ meta-gem gemspec. Plus the 6 broken requires from TODO 02.
9
+
10
+ ## Steps
11
+ 1. After TODO 02 fix is merged.
12
+ 2. Bump version: `0.10.19` → `0.11.0`.
13
+ 3. Verify `require "lutaml"` works without LoadError.
14
+ 4. Push + merge.
15
+ 5. Trigger GHA release.
16
+
17
+ ## Verification
18
+ - `require "lutaml"` succeeds.
19
+ - No LoadError from missing requires.
20
+ - Published gemspec deps are clean.
@@ -0,0 +1,23 @@
1
+ # 04 — Update ea gemspec pin to ~> 0.3
2
+
3
+ **Status: PENDING (depends on 01)**
4
+
5
+ ## Problem
6
+ ea.gemspec pins `spec.add_development_dependency "lutaml-uml", "~> 0.2.0"`.
7
+ This resolves to 0.2.12 on rubygems, which doesn't have UmlRepository.
8
+ CI fails on every PR.
9
+
10
+ ## Fix
11
+ ```ruby
12
+ # BEFORE:
13
+ spec.add_development_dependency "lutaml-uml", "~> 0.2.0"
14
+
15
+ # AFTER:
16
+ spec.add_development_dependency "lutaml-uml", "~> 0.3"
17
+ ```
18
+
19
+ `~> 0.3` means `>= 0.3.0, < 1.0.0`, which resolves to 0.3.0 (with
20
+ UmlRepository) and excludes the incompatible 1.0.0.
21
+
22
+ ## Verification
23
+ - `bundle exec rspec` passes in CI (rubygems mode) without admin override.
@@ -0,0 +1,48 @@
1
+ # 05 — Remove ea conditional require workarounds
2
+
3
+ **Status: PENDING (depends on 01)**
4
+
5
+ ## Problem
6
+ Multiple spec files use `begin/rescue LoadError` around
7
+ `require "lutaml/uml_repository"` because the published gem didn't
8
+ ship the file. After lutaml-uml 0.3.0 is released, these workarounds
9
+ are unnecessary noise.
10
+
11
+ ## Files to simplify
12
+
13
+ ### spec/spec_helper.rb
14
+ ```ruby
15
+ # BEFORE:
16
+ begin
17
+ require "lutaml/uml"
18
+ rescue LoadError
19
+ end
20
+ begin
21
+ require "lutaml/uml_repository"
22
+ rescue LoadError
23
+ end
24
+
25
+ # AFTER:
26
+ require "lutaml/uml"
27
+ require "lutaml/uml_repository"
28
+ ```
29
+
30
+ ### spec/ea/diagram/extractor_spec.rb
31
+ ```ruby
32
+ # BEFORE:
33
+ begin
34
+ require "lutaml/uml_repository/repository"
35
+ rescue LoadError
36
+ end
37
+ RSpec.configure do ... skip ... end
38
+
39
+ # AFTER:
40
+ require "lutaml/uml_repository/repository"
41
+ ```
42
+
43
+ ### spec/ea/qea/verification/comprehensive_equivalence_spec.rb
44
+ Same pattern — remove begin/rescue + skip guard.
45
+
46
+ ## Verification
47
+ - Full suite passes without any conditional requires.
48
+ - No `skip "lutaml/uml_repository not available"` messages.
@@ -0,0 +1,20 @@
1
+ # 06 — Release ea 0.2.0
2
+
3
+ **Status: PENDING (depends on 04, 05)**
4
+
5
+ ## Problem
6
+ ea is at 0.1.6. The gemspec pin change (`~> 0.2.0` → `~> 0.3`) is a
7
+ breaking change for anyone using ea's dev dependency — they need to
8
+ install lutaml-uml 0.3.0. This warrants a minor version bump.
9
+
10
+ ## Steps
11
+ 1. After TODO 04 and 05 are merged.
12
+ 2. Bump version: `0.1.6` → `0.2.0`.
13
+ 3. Verify `bundle exec rspec` passes in rubygems mode (CI mode).
14
+ 4. Push + merge.
15
+ 5. Trigger GHA release.
16
+
17
+ ## Verification
18
+ - ea 0.2.0 on rubygems.
19
+ - `gem install ea && ea spa model.qea` works with published lutaml-uml 0.3.0.
20
+ - CI passes WITHOUT admin override (first time ever).
@@ -0,0 +1,35 @@
1
+ # 07 — Migrate plateau-model to ea gem
2
+
3
+ **Status: PENDING (depends on 06)**
4
+
5
+ ## Problem
6
+ The plateau-model project (`/Users/mulgogi/src/mn/plateau-model`)
7
+ currently depends on the broken `lutaml` meta-gem via a local path:
8
+
9
+ ```ruby
10
+ # Gemfile
11
+ gem "lutaml", path: "/Users/mulgogi/src/lutaml/lutaml"
12
+ ```
13
+
14
+ And generates SPA via:
15
+ ```bash
16
+ bundle exec lutaml uml build-spa model.qea -o index.html
17
+ ```
18
+
19
+ ## Fix
20
+ Switch to the standalone `ea` gem:
21
+
22
+ ```ruby
23
+ # Gemfile
24
+ source "https://rubygems.org"
25
+ gem "ea", "~> 0.2"
26
+ ```
27
+
28
+ ```bash
29
+ bundle exec ea spa model.qea -o index.html
30
+ ```
31
+
32
+ ## Verification
33
+ - Generated index.html is structurally equivalent to the existing one
34
+ (same packages=58, diagrams=188, classes≈600).
35
+ - No dependency on the lutaml meta-gem.
@@ -0,0 +1,15 @@
1
+ # TODO.release — Streamlined dependency tree
2
+
3
+ Execute each item in order. Each step depends on the previous.
4
+
5
+ ## Index
6
+
7
+ | # | Title | Gem | Priority |
8
+ |---|---|---|---|
9
+ | 01 | [Release lutaml-uml 0.3.0](01-release-lutaml-uml-030.md) | lutaml-uml | BLOCKING — critical path |
10
+ | 02 | [Fix lutaml meta-gem broken requires](02-fix-lutaml-meta-gem-requires.md) | lutaml | high — independent of 01 |
11
+ | 03 | [Release lutaml 0.11.0](03-release-lutaml-0110.md) | lutaml | high — depends on 02 |
12
+ | 04 | [Update ea gemspec pin to ~> 0.3](04-update-ea-gemspec-pin.md) | ea | high — depends on 01 |
13
+ | 05 | [Remove ea conditional require workarounds](05-remove-ea-conditional-requires.md) | ea | high — depends on 01 |
14
+ | 06 | [Release ea 0.2.0](06-release-ea-020.md) | ea | high — depends on 04, 05 |
15
+ | 07 | [Migrate plateau-model to ea gem](07-migrate-plateau-model.md) | plateau-model | medium — depends on 06 |
@@ -0,0 +1,39 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Ea
4
+ module Bridge
5
+ # Transforms an `Ea::Qea::Database` into a `Lutaml::Uml::Document`.
6
+ #
7
+ # This is the bridge between ea's internal EA-native representation
8
+ # (the SQLite-derived row models) and the tool-agnostic UML
9
+ # metamodel from `lutaml-uml`.
10
+ #
11
+ # The heavy lifting is done by the existing factory classes under
12
+ # `Ea::Qea::Factory::*`. This module is the clean public entry
13
+ # point — consumers should call `Ea::Bridge::QeaToUml.transform(db)`
14
+ # rather than reaching into the factory internals.
15
+ module QeaToUml
16
+ module_function
17
+
18
+ # @param database [Ea::Qea::Database] loaded QEA database
19
+ # @param options [Hash] transformation options
20
+ # @return [Lutaml::Uml::Document]
21
+ def transform(database, options = {})
22
+ require_lutaml_uml!
23
+ factory(database, options).create_document
24
+ end
25
+
26
+ def require_lutaml_uml!
27
+ require "lutaml/uml"
28
+ rescue LoadError => e
29
+ raise Ea::Error,
30
+ "Ea::Bridge requires the `lutaml-uml` gem. " \
31
+ "Install it via `gem install lutaml-uml`. (#{e.message})"
32
+ end
33
+
34
+ def factory(database, options)
35
+ Ea::Qea::Factory::EaToUmlFactory.new(database, options)
36
+ end
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,35 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Ea
4
+ module Bridge
5
+ # Transforms an `Xmi::Sparx::Root` (the xmi gem's typed Sparx XMI
6
+ # model) into a `Lutaml::Uml::Document`.
7
+ #
8
+ # This is the bridge between ea's internal XMI representation
9
+ # (the xmi gem's model tree) and the tool-agnostic UML metamodel
10
+ # from `lutaml-uml`.
11
+ #
12
+ # The heavy lifting is done by the existing parser code in
13
+ # `Ea::Xmi::Parser`. This module is the clean public entry point
14
+ # — consumers should call `Ea::Bridge::XmiToUml.transform(root)`
15
+ # rather than reaching into the parser internals.
16
+ module XmiToUml
17
+ module_function
18
+
19
+ # @param xmi_root [Xmi::Sparx::Root] parsed xmi gem model
20
+ # @return [Lutaml::Uml::Document]
21
+ def transform(xmi_root)
22
+ require_lutaml_uml!
23
+ Ea::Xmi::Parser.new.parse(xmi_root)
24
+ end
25
+
26
+ def require_lutaml_uml!
27
+ require "lutaml/uml"
28
+ rescue LoadError => e
29
+ raise Ea::Error,
30
+ "Ea::Bridge requires the `lutaml-uml` gem. " \
31
+ "Install it via `gem install lutaml-uml`. (#{e.message})"
32
+ end
33
+ end
34
+ end
35
+ end
data/lib/ea/bridge.rb ADDED
@@ -0,0 +1,28 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Ea
4
+ # The bridge namespace contains ALL code that depends on the
5
+ # optional `lutaml-uml` gem. The rest of the ea gem is pure
6
+ # Sparx EA parsing (QEA SQLite, Sparx XMI) and does NOT require
7
+ # lutaml-uml.
8
+ #
9
+ # The bridge transforms ea's internal model representations:
10
+ #
11
+ # Ea::Qea::Database ──→ Lutaml::Uml::Document
12
+ # Xmi::Sparx::Root ──→ Lutaml::Uml::Document
13
+ #
14
+ # This is the "transformation" layer for cross-vendor UML output.
15
+ # It is NOT needed for:
16
+ # - Parsing QEA/XMI files
17
+ # - Converting QEA ↔ XMI (native Sparx round-trip)
18
+ # - Listing diagrams, elements, stats
19
+ #
20
+ # It IS needed for:
21
+ # - Generating a SPA (via lutaml-uml's StaticSite::Generator)
22
+ # - Rendering diagrams to SVG (via lutaml-uml's Repository)
23
+ # - Producing tool-agnostic UML output for non-Sparx consumers
24
+ module Bridge
25
+ autoload :QeaToUml, "ea/bridge/qea_to_uml"
26
+ autoload :XmiToUml, "ea/bridge/xmi_to_uml"
27
+ end
28
+ end
@@ -29,7 +29,7 @@ module Ea
29
29
  return Lutaml::UmlRepository::Repository.from_file(path)
30
30
  end
31
31
 
32
- document = Ea::Transformations.parse(path)
32
+ document = Ea::Transformations.to_uml(path)
33
33
  require_lutaml_uml_repository!
34
34
  Lutaml::UmlRepository::Repository.from_document(document)
35
35
  end
@@ -10,7 +10,7 @@ module Ea
10
10
  # details, diagram list, and member navigation in a browser.
11
11
  #
12
12
  # Pipeline:
13
- # 1. Ea::Transformations.parse(file) → Lutaml::Uml::Document
13
+ # 1. Ea::Transformations.to_uml(file) → Lutaml::Uml::Document
14
14
  # 2. Lutaml::UmlRepository::Repository.from_document(document)
15
15
  # 3. Lutaml::UmlRepository::StaticSite::Generator.new(repo, ...).generate
16
16
  #
@@ -497,24 +497,30 @@ module Ea
497
497
  }
498
498
  end
499
499
 
500
- # Determine element type from UML element
500
+ # Determine element type from UML element. Lazy-resolves
501
+ # Lutaml::Uml::* classes so the file loads cleanly without
502
+ # lutaml-uml installed.
501
503
  def element_type(uml_element)
504
+ return "unknown" unless defined?(::Lutaml::Uml)
505
+
502
506
  case uml_element
503
- when Lutaml::Uml::UmlClass then "class"
504
- when Lutaml::Uml::Package then "package"
505
- when Lutaml::Uml::DataType then "datatype"
506
- when Lutaml::Uml::Enum then "enumeration"
507
- when Lutaml::Uml::Instance then "instance"
507
+ when ::Lutaml::Uml::UmlClass then "class"
508
+ when ::Lutaml::Uml::Package then "package"
509
+ when ::Lutaml::Uml::DataType then "datatype"
510
+ when ::Lutaml::Uml::Enum then "enumeration"
511
+ when ::Lutaml::Uml::Instance then "instance"
508
512
  else "unknown"
509
513
  end
510
514
  end
511
515
 
512
516
  # Determine connector type
513
517
  def connector_type(connector)
518
+ return "connector" unless defined?(::Lutaml::Uml)
519
+
514
520
  case connector
515
- when Lutaml::Uml::Association then "association"
516
- when Lutaml::Uml::Generalization then "generalization"
517
- when Lutaml::Uml::Dependency then "dependency"
521
+ when ::Lutaml::Uml::Association then "association"
522
+ when ::Lutaml::Uml::Generalization then "generalization"
523
+ when ::Lutaml::Uml::Dependency then "dependency"
518
524
  else "connector"
519
525
  end
520
526
  end
@@ -231,13 +231,7 @@ module Ea
231
231
  end
232
232
 
233
233
  # Maps UML connector classes to their style type names.
234
- # New connector types are added here no method changes needed.
235
- CONNECTOR_TYPE_MAP = {
236
- Lutaml::Uml::Generalization => "generalization",
237
- Lutaml::Uml::Association => "association",
238
- Lutaml::Uml::Dependency => "dependency",
239
- Lutaml::Uml::Realization => "realization",
240
- }.freeze
234
+ # Built lazilysee {#connector_type_map}.
241
235
 
242
236
  # Association sub-type precedence for style resolution
243
237
  ASSOCIATION_SUBTYPE_MAP = {
@@ -251,18 +245,39 @@ module Ea
251
245
  def determine_connector_type(connector)
252
246
  return "association" unless connector
253
247
 
254
- type_name = CONNECTOR_TYPE_MAP[connector.class]
248
+ type_name = connector_type_map[connector.class]
255
249
  return type_name if type_name && type_name != "association"
256
250
  return determine_association_type(connector) if type_name == "association"
257
251
 
258
252
  "association"
259
253
  end
260
254
 
255
+ # Maps UML connector classes to their style type names.
256
+ # Built lazily on first call so the resolver can be loaded
257
+ # without `lutaml/uml` installed (the ea gem is standalone;
258
+ # lutaml-uml is an optional bridge dependency). Adding a new
259
+ # connector type = adding one entry here.
260
+ def connector_type_map
261
+ @connector_type_map ||= build_connector_type_map
262
+ end
263
+
264
+ def build_connector_type_map
265
+ map = {}
266
+ return map unless defined?(::Lutaml::Uml)
267
+
268
+ map[::Lutaml::Uml::Generalization] = "generalization"
269
+ map[::Lutaml::Uml::Association] = "association"
270
+ map[::Lutaml::Uml::Dependency] = "dependency"
271
+ map[::Lutaml::Uml::Realization] = "realization"
272
+ map
273
+ end
274
+
261
275
  # Determine specific association type
262
276
  # @param connector [Object] Association connector
263
277
  # @return [String] Specific association type
264
278
  def determine_association_type(connector)
265
- return "association" unless connector.is_a?(Lutaml::Uml::Association)
279
+ return "association" unless defined?(::Lutaml::Uml::Association)
280
+ return "association" unless connector.is_a?(::Lutaml::Uml::Association)
266
281
 
267
282
  [connector.owner_end_type, connector.member_end_type].each do |type|
268
283
  resolved = ASSOCIATION_SUBTYPE_MAP[type&.downcase]
@@ -33,8 +33,57 @@ module Ea
33
33
  @engine = engine
34
34
  end
35
35
 
36
+ # Parse an EA file into its native representation.
37
+ #
38
+ # Pure entry point — does NOT require `lutaml-uml`. Returns:
39
+ # .qea → Ea::Qea::Database
40
+ # .xmi → Xmi::Sparx::Root
41
+ #
42
+ # To get a Lutaml::Uml::Document instead, use {to_uml}.
43
+ #
44
+ # @param file_path [String] path to a .qea or .xmi file
45
+ # @param options [Hash] parser options (e.g. config: for QEA)
46
+ # @return [Ea::Qea::Database, Xmi::Sparx::Root]
36
47
  def parse(file_path, options = {})
37
- engine.parse(file_path, options)
48
+ ext = File.extname(file_path).downcase
49
+ case ext
50
+ when ".qea"
51
+ Ea::Qea.load(file_path, options[:config])
52
+ when ".xmi", ".xml"
53
+ Ea::Xmi.load(file_path)
54
+ else
55
+ raise Ea::Error,
56
+ "Unsupported file extension #{ext.inspect}. " \
57
+ "Supported: .qea, .xmi"
58
+ end
59
+ end
60
+
61
+ # Transform an EA file (or pre-parsed model) into a
62
+ # `Lutaml::Uml::Document`.
63
+ #
64
+ # Bridge entry point — requires the optional `lutaml-uml` gem.
65
+ # Lazy-loads the bridge code on first call.
66
+ #
67
+ # @param path_or_model [String, Ea::Qea::Database, Xmi::Sparx::Root]
68
+ # @param options [Hash] transformation options
69
+ # @return [Lutaml::Uml::Document]
70
+ def to_uml(path_or_model, options = {})
71
+ model = if path_or_model.is_a?(String)
72
+ parse(path_or_model, options)
73
+ else
74
+ path_or_model
75
+ end
76
+
77
+ case model
78
+ when Ea::Qea::Database
79
+ Ea::Bridge::QeaToUml.transform(model, options)
80
+ when ::Xmi::Sparx::Root
81
+ Ea::Bridge::XmiToUml.transform(model)
82
+ else
83
+ raise Ea::Error,
84
+ "Cannot transform #{model.class} to Lutaml::Uml::Document. " \
85
+ "Expected Ea::Qea::Database or Xmi::Sparx::Root."
86
+ end
38
87
  end
39
88
 
40
89
  def detect_parser(file_path)
data/lib/ea/version.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Ea
4
- VERSION = "0.1.5"
4
+ VERSION = "0.2.0"
5
5
  end
data/lib/ea/xmi.rb CHANGED
@@ -31,5 +31,22 @@ module Ea
31
31
  autoload :ConnectorDrop, "ea/xmi/liquid_drops/connector_drop"
32
32
  autoload :SourceTargetDrop, "ea/xmi/liquid_drops/source_target_drop"
33
33
  end
34
+
35
+ module_function
36
+
37
+ # Parse an XMI file into the xmi gem's typed Sparx model.
38
+ #
39
+ # Pure entry point — does NOT require `lutaml-uml`. Returns the
40
+ # `Xmi::Sparx::Root` model tree from the `xmi` gem. This is the
41
+ # internal EA-native representation for XMI files.
42
+ #
43
+ # To get a `Lutaml::Uml::Document` instead (requires the optional
44
+ # `lutaml-uml` gem), use `Ea::Bridge::XmiToUml.transform(root)`.
45
+ #
46
+ # @param path [String] path to a .xmi file
47
+ # @return [Xmi::Sparx::Root]
48
+ def load(path)
49
+ ::Xmi::Sparx::Root.parse_xml(File.read(path))
50
+ end
34
51
  end
35
52
  end
data/lib/ea.rb CHANGED
@@ -13,5 +13,36 @@ module Ea
13
13
  autoload :Transformations, "ea/transformations"
14
14
  autoload :Xmi, "ea/xmi"
15
15
  autoload :Transformers, "ea/transformers"
16
+ autoload :Bridge, "ea/bridge"
16
17
  autoload :Cli, "ea/cli"
18
+
19
+ class << self
20
+ # Parse an EA file into its native representation.
21
+ #
22
+ # Pure entry point — does NOT require the optional `lutaml-uml`
23
+ # gem. The return type depends on the input format:
24
+ #
25
+ # .qea → Ea::Qea::Database (Sparx SQLite tables as Ruby models)
26
+ # .xmi → Xmi::Sparx::Root (typed Sparx XMI model from the xmi gem)
27
+ #
28
+ # @param path [String] path to a .qea or .xmi file
29
+ # @return [Ea::Qea::Database, Xmi::Sparx::Root]
30
+ def parse(path)
31
+ Transformations.parse(path)
32
+ end
33
+
34
+ # Transform an EA file (or pre-parsed model) into a
35
+ # `Lutaml::Uml::Document`.
36
+ #
37
+ # Bridge entry point — requires the optional `lutaml-uml` gem.
38
+ # Used for cross-vendor UML output (e.g. EA → PlantUML via the
39
+ # tool-agnostic UML metamodel). The lutaml-uml dependency is
40
+ # lazy-required on first call.
41
+ #
42
+ # @param path_or_model [String, Ea::Qea::Database, Xmi::Sparx::Root]
43
+ # @return [Lutaml::Uml::Document]
44
+ def to_uml(path_or_model)
45
+ Transformations.to_uml(path_or_model)
46
+ end
47
+ end
17
48
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ea
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.5
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ribose Inc.
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2026-07-07 00:00:00.000000000 Z
11
+ date: 2026-07-08 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: lutaml-model
@@ -134,14 +134,14 @@ dependencies:
134
134
  requirements:
135
135
  - - "~>"
136
136
  - !ruby/object:Gem::Version
137
- version: 0.2.0
137
+ version: '0.5'
138
138
  type: :development
139
139
  prerelease: false
140
140
  version_requirements: !ruby/object:Gem::Requirement
141
141
  requirements:
142
142
  - - "~>"
143
143
  - !ruby/object:Gem::Version
144
- version: 0.2.0
144
+ version: '0.5'
145
145
  - !ruby/object:Gem::Dependency
146
146
  name: rubocop
147
147
  requirement: !ruby/object:Gem::Requirement
@@ -213,6 +213,14 @@ files:
213
213
  - TODO.next/38-xmi-parser-feature-parity.md
214
214
  - TODO.next/39-ea-spa-cli-command.md
215
215
  - TODO.next/40-drop-lur-only-check-in-diagrams-extract.md
216
+ - TODO.release/01-release-lutaml-uml-030.md
217
+ - TODO.release/02-fix-lutaml-meta-gem-requires.md
218
+ - TODO.release/03-release-lutaml-0110.md
219
+ - TODO.release/04-update-ea-gemspec-pin.md
220
+ - TODO.release/05-remove-ea-conditional-requires.md
221
+ - TODO.release/06-release-ea-020.md
222
+ - TODO.release/07-migrate-plateau-model.md
223
+ - TODO.release/README.md
216
224
  - config/diagram_styles.yml
217
225
  - config/model_transformations.yml
218
226
  - config/qea_schema.yml
@@ -238,6 +246,9 @@ files:
238
246
  - examples/smoke_test_real_qea.rb
239
247
  - exe/ea
240
248
  - lib/ea.rb
249
+ - lib/ea/bridge.rb
250
+ - lib/ea/bridge/qea_to_uml.rb
251
+ - lib/ea/bridge/xmi_to_uml.rb
241
252
  - lib/ea/cli.rb
242
253
  - lib/ea/cli/app.rb
243
254
  - lib/ea/cli/command.rb