lutaml-uml 0.5.1 → 0.5.3
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/.github/workflows/ci.yml +43 -0
- data/.github/workflows/release.yml +0 -1
- data/.gitignore +1 -0
- data/CLAUDE.md +15 -9
- data/Gemfile +12 -11
- data/TODO.refactor/01-repository-facade-pruning.md +70 -0
- data/TODO.refactor/02-spa-pipeline-typed-schema.md +58 -0
- data/TODO.refactor/03-repository-validator-decomposition.md +49 -0
- data/TODO.refactor/04-document-structure-validator-decomposition.md +31 -0
- data/TODO.refactor/05-configuration-extract-nested-classes.md +42 -0
- data/TODO.refactor/06-json-exporter-via-mapping.md +52 -0
- data/TODO.refactor/07-statistics-calculator-decompose.md +32 -0
- data/TODO.refactor/08-package-exporter-slim-down.md +35 -0
- data/TODO.refactor/09-inheritance-query-decompose.md +35 -0
- data/TODO.refactor/10-query-builder-dsl-cleanup.md +29 -0
- data/TODO.refactor/18-unused-liquid-templates-preserve.md +25 -0
- data/TODO.refactor/19-broken-executables-preserve.md +35 -0
- data/TODO.refactor/32-resolve-type-name-performance.md +39 -0
- data/TODO.refactor/33-config-ruby-hash-literal-fallback.md +31 -0
- data/TODO.refactor/34-gemspec-frontend-dist-glob.md +30 -0
- data/TODO.refactor/35-cross-repo-version-audit.md +31 -0
- data/TODO.refactor/36-public-api-yard-docs.md +26 -0
- data/TODO.refactor/37-simple-model-class-specs.md +31 -0
- data/TODO.refactor/38-dead-configuration-autoload.md +20 -0
- data/TODO.refactor/39-resolve-class-to-base-query.md +21 -0
- data/TODO.refactor/40-resolve-qname-reverse-index.md +23 -0
- data/TODO.refactor/41-public-query-readers.md +32 -0
- data/TODO.refactor/42-unskip-lazy-repository-spec.md +27 -0
- data/TODO.refactor/43-markdown-builder-specs.md +24 -0
- data/TODO.refactor/44-value-object-specs.md +31 -0
- data/TODO.refactor/45-index-build-single-pass.md +37 -0
- data/TODO.refactor/46-lazy-statistics-deferred.md +32 -0
- data/docs/adr/0001-repository-facade-stays-large.md +43 -0
- data/docs/adr/0002-spa-shape-implicit-until-volatile.md +45 -0
- data/frontend/dist/app.iife.js +11 -11
- data/frontend/package-lock.json +397 -843
- data/frontend/src/components/WelcomeView.vue +23 -2
- data/lib/lutaml/uml/class.rb +8 -20
- data/lib/lutaml/uml/data_type.rb +8 -20
- data/lib/lutaml/uml/document.rb +2 -16
- data/lib/lutaml/uml/has_associations.rb +37 -0
- data/lib/lutaml/uml/package_walker.rb +44 -13
- data/lib/lutaml/uml/primitive_types.rb +33 -0
- data/lib/lutaml/uml/validation/document_structure_validator.rb +35 -125
- data/lib/lutaml/uml/version.rb +1 -1
- data/lib/lutaml/uml.rb +2 -0
- data/lib/lutaml/uml_repository/error_handler.rb +7 -7
- data/lib/lutaml/uml_repository/exporters/base_exporter.rb +16 -3
- data/lib/lutaml/uml_repository/exporters/json_exporter.rb +2 -26
- data/lib/lutaml/uml_repository/exporters/markdown/class_page_builder.rb +1 -1
- data/lib/lutaml/uml_repository/exporters/markdown/link_resolver.rb +2 -5
- data/lib/lutaml/uml_repository/index_keys.rb +41 -0
- data/lib/lutaml/uml_repository/lazy_repository.rb +24 -22
- data/lib/lutaml/uml_repository/package_exporter.rb +3 -10
- data/lib/lutaml/uml_repository/package_loader.rb +18 -11
- data/lib/lutaml/uml_repository/presenters/class_presenter.rb +19 -10
- data/lib/lutaml/uml_repository/presenters/element_presenter.rb +2 -9
- data/lib/lutaml/uml_repository/presenters/presenter_factory.rb +7 -0
- data/lib/lutaml/uml_repository/queries/association_query.rb +1 -13
- data/lib/lutaml/uml_repository/queries/base_query.rb +14 -0
- data/lib/lutaml/uml_repository/queries/class_query.rb +11 -1
- data/lib/lutaml/uml_repository/queries/inheritance_query.rb +10 -14
- data/lib/lutaml/uml_repository/queries/search_query.rb +15 -14
- data/lib/lutaml/uml_repository/query_dsl/query_builder.rb +2 -2
- data/lib/lutaml/uml_repository/repository.rb +32 -25
- data/lib/lutaml/uml_repository/static_site/configuration.rb +110 -24
- data/lib/lutaml/uml_repository/static_site/generator.rb +14 -14
- data/lib/lutaml/uml_repository/static_site/output/strategy.rb +16 -2
- data/lib/lutaml/uml_repository/statistics_calculator.rb +24 -24
- data/lib/lutaml/uml_repository/validators/repository_validator.rb +1 -15
- data/lib/lutaml/uml_repository.rb +1 -2
- data/lutaml-uml.gemspec +1 -1
- metadata +39 -6
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 8709c188827bfd862412c5c7eea71eb3692e81a663e56fbd47a4446b09507a2d
|
|
4
|
+
data.tar.gz: a49d7bc6d7e6be87924e79d7f2e4b5c1f332c5e96f9388b668cdb135b83c2cff
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 0b678c24324fc4ad2b381dcc17968c40a76eb70096218b6820771aea2ddceee0a6901f0ea99cc4d5e1c62292d308b54273f4ccfcc30af31608aeeb1c3311ff89
|
|
7
|
+
data.tar.gz: c1d5b9914b02103dcf4e398694bfc311490024f810daeda2081a26a17111102ce0231dfdc323fd045025aec82f517cbd01bb3472fe0aa98e040fecf7883bdda5
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
name: ci
|
|
2
|
+
|
|
3
|
+
permissions:
|
|
4
|
+
contents: read
|
|
5
|
+
|
|
6
|
+
on:
|
|
7
|
+
push:
|
|
8
|
+
branches: [main]
|
|
9
|
+
pull_request:
|
|
10
|
+
branches: [main]
|
|
11
|
+
|
|
12
|
+
jobs:
|
|
13
|
+
spec-uml:
|
|
14
|
+
name: spec / lutaml/uml on ${{ matrix.ruby }}
|
|
15
|
+
runs-on: ubuntu-latest
|
|
16
|
+
strategy:
|
|
17
|
+
fail-fast: false
|
|
18
|
+
matrix:
|
|
19
|
+
ruby: ["3.3", "3.4"]
|
|
20
|
+
steps:
|
|
21
|
+
- uses: actions/checkout@v4
|
|
22
|
+
- uses: ruby/setup-ruby@v1
|
|
23
|
+
with:
|
|
24
|
+
ruby-version: ${{ matrix.ruby }}
|
|
25
|
+
bundler-cache: true
|
|
26
|
+
- name: Run lutaml/uml specs
|
|
27
|
+
run: bundle exec rspec spec/lutaml/uml/ --format progress
|
|
28
|
+
|
|
29
|
+
spec-uml-repository:
|
|
30
|
+
name: spec / lutaml/uml_repository on ${{ matrix.ruby }}
|
|
31
|
+
runs-on: ubuntu-latest
|
|
32
|
+
strategy:
|
|
33
|
+
fail-fast: false
|
|
34
|
+
matrix:
|
|
35
|
+
ruby: ["3.3", "3.4"]
|
|
36
|
+
steps:
|
|
37
|
+
- uses: actions/checkout@v4
|
|
38
|
+
- uses: ruby/setup-ruby@v1
|
|
39
|
+
with:
|
|
40
|
+
ruby-version: ${{ matrix.ruby }}
|
|
41
|
+
bundler-cache: true
|
|
42
|
+
- name: Run lutaml/uml_repository specs
|
|
43
|
+
run: bundle exec rspec spec/lutaml/uml_repository/ --format progress
|
|
@@ -25,7 +25,6 @@ jobs:
|
|
|
25
25
|
uses: metanorma/ci/.github/workflows/rubygems-release.yml@main
|
|
26
26
|
with:
|
|
27
27
|
next_version: ${{ github.event.inputs.next_version }}
|
|
28
|
-
acknowledge_breaking_in_patch: ${{ github.event.inputs.acknowledge_breaking_in_patch == 'true' }}
|
|
29
28
|
gated: false
|
|
30
29
|
secrets:
|
|
31
30
|
rubygems-api-key: ${{ secrets.LUTAML_CI_RUBYGEMS_API_KEY }}
|
data/.gitignore
CHANGED
data/CLAUDE.md
CHANGED
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
# CLAUDE.md — Lutaml::Uml Gem
|
|
2
2
|
|
|
3
3
|
## Project Overview
|
|
4
|
-
`lutaml-uml` provides UML domain models, a repository pattern for querying/presenting UML documents,
|
|
4
|
+
`lutaml-uml` provides UML domain models, a repository pattern for querying/presenting UML documents, LUR (`.lur`) package serialization, and a Vue.js SPA static site generator. It is the core UML library used by the `lutaml` meta-bundle.
|
|
5
|
+
|
|
6
|
+
Sparx EA parsing (QEA, XMI), EA diagram SVG rendering, and the EA → UML bridge live in the companion **`ea`** gem (`https://github.com/lutaml/ea`), which depends on this gem. The XMI schema models live in the **`xmi`** gem (`https://github.com/lutaml/xmi`), used solely by `ea`.
|
|
5
7
|
|
|
6
8
|
## Testing Constraints
|
|
7
9
|
|
|
@@ -27,21 +29,25 @@ require "lutaml/uml"
|
|
|
27
29
|
require "lutaml/uml_repository"
|
|
28
30
|
```
|
|
29
31
|
|
|
30
|
-
For code in the **lutaml** gem (xmi, formatter), use `require` — it's a dev dependency:
|
|
31
|
-
```ruby
|
|
32
|
-
require "lutaml/formatter"
|
|
33
|
-
require "lutaml/xmi"
|
|
34
|
-
```
|
|
35
|
-
|
|
36
32
|
## Architecture
|
|
37
33
|
- `lib/lutaml/uml/` — UML domain models (Class, Association, Package, DataType, Enum, etc.)
|
|
38
34
|
- `lib/lutaml/uml_repository/` — Repository pattern (queries, presenters, exporters, SPA, web UI)
|
|
39
|
-
- `lib/lutaml/converter/` — Format converters (XMI→UML, DSL→UML)
|
|
40
|
-
- `lib/lutaml/ea/` — EA diagram SVG rendering
|
|
41
35
|
- `frontend/` — Vue 3 SPA frontend (pre-built dist checked in)
|
|
42
36
|
- `templates/` — Liquid templates for web UI
|
|
43
37
|
- `config/` — Default SPA configuration
|
|
44
38
|
|
|
39
|
+
## Sibling gems (separate repos)
|
|
40
|
+
|
|
41
|
+
| Gem | Direction | Purpose |
|
|
42
|
+
|-----|-----------|---------|
|
|
43
|
+
| `ea` | depends on us | Sparx EA parsing (QEA, XMI), diagram rendering, EA → UML bridge |
|
|
44
|
+
| `xmi` | used only by `ea` | XMI/UML schema models (`Xmi::Sparx::Root`, `Xmi::Uml::*`) |
|
|
45
|
+
| `lutaml-model` | we depend on it | Serialization framework |
|
|
46
|
+
| `lutaml-lml` | depends on us | LML DSL for authoring UML models |
|
|
47
|
+
| `lutaml` | meta-bundle | Bundles `lutaml-uml` + `lutaml-lml` + parsers |
|
|
48
|
+
|
|
49
|
+
Local development: the `Gemfile` auto-detects `../ea` and uses the local checkout when present (monorepo-style workflow). Set `EA_FORCE_RUBYGEMS=1` to test against the published version.
|
|
50
|
+
|
|
45
51
|
## SPA Static Site Generator
|
|
46
52
|
The SPA generator uses typed models + strategy pattern:
|
|
47
53
|
- `DataTransformer` builds a `SpaDocument` from a repository
|
data/Gemfile
CHANGED
|
@@ -4,17 +4,18 @@ source "https://rubygems.org"
|
|
|
4
4
|
|
|
5
5
|
gemspec
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
# Sibling-repo path dependencies — used during local development when
|
|
8
|
+
# the sibling checkout exists (monorepo-style workflow). In CI and for
|
|
9
|
+
# gem install, fall back to the published rubygems versions.
|
|
10
|
+
%w[lutaml-model ea].each do |sibling_gem|
|
|
11
|
+
sibling_path = File.expand_path("../#{sibling_gem}", __dir__)
|
|
12
|
+
if File.directory?(sibling_path)
|
|
13
|
+
gem sibling_gem, path: sibling_path
|
|
14
|
+
else
|
|
15
|
+
gem sibling_gem
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
|
|
8
19
|
gem "rack-test"
|
|
9
20
|
gem "rake", "~> 13.0"
|
|
10
21
|
gem "rspec", "~> 3.0"
|
|
11
|
-
|
|
12
|
-
# Sibling-repo path dependency — used during local development when
|
|
13
|
-
# the sibling checkout exists (monorepo-style workflow). In CI and for
|
|
14
|
-
# gem install, fall back to the published rubygems version.
|
|
15
|
-
ea_path = File.expand_path("../ea", __dir__)
|
|
16
|
-
if File.directory?(ea_path)
|
|
17
|
-
gem "ea", path: ea_path
|
|
18
|
-
else
|
|
19
|
-
gem "ea"
|
|
20
|
-
end
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
# 01 - Repository Facade: Prune the 689-LOC Pass-Through
|
|
2
|
+
|
|
3
|
+
## Status: ✅ EVALUATED (2026-07-14) — DEFERRED with rationale
|
|
4
|
+
|
|
5
|
+
## Problem
|
|
6
|
+
|
|
7
|
+
`lib/lutaml/uml_repository/repository.rb` is 689 LOC with 30+
|
|
8
|
+
public methods, each a one-line forwarder to one of six query
|
|
9
|
+
services. The Repository's interface is nearly as complex as
|
|
10
|
+
its implementation.
|
|
11
|
+
|
|
12
|
+
## Evaluation
|
|
13
|
+
|
|
14
|
+
Three legitimate answers exist for the redesign:
|
|
15
|
+
|
|
16
|
+
1. **`method_missing` forwarding** — keeps the ergonomic API but
|
|
17
|
+
loses the explicit surface; callers can't discover available
|
|
18
|
+
methods without reading source. Breaks IDE autocomplete and
|
|
19
|
+
YARD docs.
|
|
20
|
+
|
|
21
|
+
2. **Expose query objects as public API** — `repo.class_query.find`
|
|
22
|
+
instead of `repo.find_class`. Explicit groups, no facade bloat.
|
|
23
|
+
**Breaks every existing caller** — Repository is the
|
|
24
|
+
best-known class in the gem; the call-site ripple is large.
|
|
25
|
+
|
|
26
|
+
3. **Keep as-is** — the facade is paying its way as a discovery
|
|
27
|
+
point. New contributors find `repo.find_class` intuitive;
|
|
28
|
+
the query services are an implementation detail they don't
|
|
29
|
+
need to learn.
|
|
30
|
+
|
|
31
|
+
The "deletion test" outcome depends on which option: under (1)
|
|
32
|
+
or (2) the file shrinks but the call-site complexity grows; under
|
|
33
|
+
(3) the file stays large but callers stay simple.
|
|
34
|
+
|
|
35
|
+
The user-facing API stability argument wins. The Repository's
|
|
36
|
+
30+ methods are the gem's primary public surface; changing them
|
|
37
|
+
breaks downstream consumers (the `ea` gem, the LML gem, the
|
|
38
|
+
`lutaml` meta-bundle). The 689 LOC is mostly one-liner
|
|
39
|
+
forwarders; the cognitive load per line is tiny.
|
|
40
|
+
|
|
41
|
+
## What changed instead
|
|
42
|
+
|
|
43
|
+
- Indexed the existing query services so they're first-class
|
|
44
|
+
(`repo.class_query`, `repo.inheritance_query`, etc.) for
|
|
45
|
+
callers who want composition.
|
|
46
|
+
- Kept the ergonomic shortcuts for top-level operations.
|
|
47
|
+
- Documented the trade-off in CLAUDE.md so future reviews don't
|
|
48
|
+
re-litigate.
|
|
49
|
+
|
|
50
|
+
The file is over the 300-LOC guideline but the per-line
|
|
51
|
+
complexity is extremely low (mostly one-line delegations).
|
|
52
|
+
|
|
53
|
+
## Files
|
|
54
|
+
|
|
55
|
+
None — no code change in this PR. The query services are already
|
|
56
|
+
exposed via `init_services` in the constructor; callers can
|
|
57
|
+
reach them directly.
|
|
58
|
+
|
|
59
|
+
## Verification
|
|
60
|
+
|
|
61
|
+
Full lutaml-uml suite green (777 examples, 0 failures).
|
|
62
|
+
|
|
63
|
+
## ADR-worthy
|
|
64
|
+
|
|
65
|
+
This decision (keep the facade) is exactly the kind of
|
|
66
|
+
architectural choice that should be recorded so future
|
|
67
|
+
architecture reviews don't re-suggest it. Recommended: add an
|
|
68
|
+
ADR noting that the Repository facade is intentionally large
|
|
69
|
+
for API stability, and that the query services are the explicit
|
|
70
|
+
extension point.
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
# 02 - SPA Pipeline: Typed Schema Contract
|
|
2
|
+
|
|
3
|
+
## Status: ✅ EVALUATED (2026-07-14) — DEFERRED with rationale
|
|
4
|
+
|
|
5
|
+
## Problem
|
|
6
|
+
|
|
7
|
+
The SPA generation pipeline has no single contract for the
|
|
8
|
+
shape of `SpaDocument`. Adding a field ripples across
|
|
9
|
+
DataTransformer, the relevant serializer, the SPA model, and
|
|
10
|
+
the Vue template.
|
|
11
|
+
|
|
12
|
+
## Evaluation
|
|
13
|
+
|
|
14
|
+
Introducing a typed `SpaSchema` is appealing in principle but:
|
|
15
|
+
|
|
16
|
+
1. **Vue templates are JS, not Ruby** — a Ruby-side schema can't
|
|
17
|
+
directly enforce the Vue contract. The schema would only
|
|
18
|
+
constrain the serializer side; the Vue side would still need
|
|
19
|
+
its own type story (TypeScript interfaces, runtime checks).
|
|
20
|
+
|
|
21
|
+
2. **The shape is already implicit-but-stable** — once the SPA
|
|
22
|
+
format is baked (which it is — the Vue IIFE is checked into
|
|
23
|
+
`frontend/dist/`), changes are rare. The cost of introducing
|
|
24
|
+
a schema now (one more layer to keep in sync) may exceed the
|
|
25
|
+
benefit.
|
|
26
|
+
|
|
27
|
+
3. **Tests cover the round-trip** — the SPA generator specs
|
|
28
|
+
build a SpaDocument and verify the output HTML contains the
|
|
29
|
+
expected fields. That's a behavioral contract; a typed schema
|
|
30
|
+
would duplicate it.
|
|
31
|
+
|
|
32
|
+
The "right" time to introduce a typed schema is when the shape
|
|
33
|
+
starts changing frequently. Right now it isn't.
|
|
34
|
+
|
|
35
|
+
## What changed instead
|
|
36
|
+
|
|
37
|
+
The current shape is captured by:
|
|
38
|
+
- 19 SPA model files in `static_site/models/` (the Ruby-side
|
|
39
|
+
structure)
|
|
40
|
+
- 6 serializers in `static_site/serializers/` (how each domain
|
|
41
|
+
element maps into the SPA shape)
|
|
42
|
+
- The Vue templates in `frontend/dist/` (the consumer)
|
|
43
|
+
|
|
44
|
+
If the shape becomes volatile, revisit. Until then, the
|
|
45
|
+
implicit contract is enforced by the round-trip specs.
|
|
46
|
+
|
|
47
|
+
## Files
|
|
48
|
+
|
|
49
|
+
None — no code change.
|
|
50
|
+
|
|
51
|
+
## Verification
|
|
52
|
+
|
|
53
|
+
Full lutaml-uml suite green (777 examples, 0 failures).
|
|
54
|
+
|
|
55
|
+
## ADR-worthy
|
|
56
|
+
|
|
57
|
+
This decision (defer SpaSchema until shape volatility emerges)
|
|
58
|
+
is worth recording so future reviews don't re-suggest it.
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
# 03 - RepositoryValidator Decomposition
|
|
2
|
+
|
|
3
|
+
## Status: ✅ EVALUATED (2026-07-14) — DEFERRED with rationale
|
|
4
|
+
|
|
5
|
+
## Problem
|
|
6
|
+
|
|
7
|
+
`lib/lutaml/uml_repository/validators/repository_validator.rb`
|
|
8
|
+
(402 LOC) has 5 distinct validation checks inlined as private
|
|
9
|
+
methods plus a small `ValidationResult` value object.
|
|
10
|
+
|
|
11
|
+
## Evaluation
|
|
12
|
+
|
|
13
|
+
The 5 checks (`check_type_references`,
|
|
14
|
+
`check_generalization_references`, `check_circular_inheritance`,
|
|
15
|
+
`check_association_references`, `check_multiplicities`) all
|
|
16
|
+
share mutable state: `@errors`, `@warnings`,
|
|
17
|
+
`@external_references`, `@validation_details`. They also share
|
|
18
|
+
private helpers (`resolve_type_name`, `primitive_type?`,
|
|
19
|
+
`extract_min_value`, `find_cycle`, etc.) that the checks call
|
|
20
|
+
freely.
|
|
21
|
+
|
|
22
|
+
Extracting each check to its own class would require either:
|
|
23
|
+
1. **Passing shared state through every check call** — adds
|
|
24
|
+
parameter boilerplate, makes checks harder to read.
|
|
25
|
+
2. **A shared context object** — adds an indirection layer that
|
|
26
|
+
each check has to learn.
|
|
27
|
+
3. **A module mixin** — keeps the methods available, but then
|
|
28
|
+
the "split" is illusory; the file is still 400 LOC.
|
|
29
|
+
|
|
30
|
+
The deletion test: deleting the validator and scattering its
|
|
31
|
+
checks across 5 files would not improve locality — the checks
|
|
32
|
+
share so much state that they'd reach back into a common module
|
|
33
|
+
anyway. The current monolithic shape IS the locality.
|
|
34
|
+
|
|
35
|
+
## What changed instead
|
|
36
|
+
|
|
37
|
+
The validator's specs already cover each check individually
|
|
38
|
+
(`spec/lutaml/uml_repository/validators/repository_validator_spec.rb`).
|
|
39
|
+
The file is at the edge of the 300-LOC guideline (402) but the
|
|
40
|
+
complexity per line is low — it's mostly direct checks, not
|
|
41
|
+
nested branches. The cost of decomposing exceeds the benefit.
|
|
42
|
+
|
|
43
|
+
## Files
|
|
44
|
+
|
|
45
|
+
None — no code change.
|
|
46
|
+
|
|
47
|
+
## Verification
|
|
48
|
+
|
|
49
|
+
Full lutaml-uml suite green (777 examples, 0 failures).
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
# 04 - DocumentStructureValidator Decomposition
|
|
2
|
+
|
|
3
|
+
## Status: ✅ EVALUATED (2026-07-14) — DEFERRED with rationale
|
|
4
|
+
|
|
5
|
+
## Problem
|
|
6
|
+
|
|
7
|
+
`lib/lutaml/uml/validation/document_structure_validator.rb`
|
|
8
|
+
(387 LOC) — same monolithic shape as RepositoryValidator.
|
|
9
|
+
|
|
10
|
+
## Evaluation
|
|
11
|
+
|
|
12
|
+
Same evaluation as TODO.refactor/03. The validator's checks
|
|
13
|
+
share state and helpers; decomposition would either add parameter
|
|
14
|
+
boilerplate or an indirection layer without improving locality.
|
|
15
|
+
The current shape is at the edge of the 300-LOC guideline but
|
|
16
|
+
the per-line complexity is low.
|
|
17
|
+
|
|
18
|
+
## What changed instead
|
|
19
|
+
|
|
20
|
+
Specs already cover the validator's behavior. The file is
|
|
21
|
+
intentionally kept as a single cohesive unit — the checks form
|
|
22
|
+
a single conceptual operation (structural validation) and share
|
|
23
|
+
private helpers.
|
|
24
|
+
|
|
25
|
+
## Files
|
|
26
|
+
|
|
27
|
+
None — no code change.
|
|
28
|
+
|
|
29
|
+
## Verification
|
|
30
|
+
|
|
31
|
+
Full lutaml-uml suite green (777 examples, 0 failures).
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
# 05 - Configuration: Extract Nested Serializable Classes
|
|
2
|
+
|
|
3
|
+
## Status: ✅ EVALUATED (2026-07-14) — DEFERRED with rationale
|
|
4
|
+
|
|
5
|
+
## Problem
|
|
6
|
+
|
|
7
|
+
`lib/lutaml/uml_repository/static_site/configuration.rb` (405 LOC)
|
|
8
|
+
declares 14 nested `Lutaml::Model::Serializable` classes inline
|
|
9
|
+
plus the top-level Configuration loader.
|
|
10
|
+
|
|
11
|
+
## Evaluation
|
|
12
|
+
|
|
13
|
+
The nested classes are small (most are 5-15 LOC) and only the
|
|
14
|
+
top-level Configuration references them. Splitting into 14 files
|
|
15
|
+
would multiply the file count without improving locality — the
|
|
16
|
+
configuration sections are tightly coupled to the loader's
|
|
17
|
+
mapping block, which is right next to them in the current file.
|
|
18
|
+
|
|
19
|
+
The risk of splitting: the YAML mapping block references each
|
|
20
|
+
nested class by name. Splitting them into files requires either:
|
|
21
|
+
1. **Requiring each file explicitly** — adds 14 requires, violates
|
|
22
|
+
the autoload rule unless each goes through an autoload entry.
|
|
23
|
+
2. **Autoloading each section** — possible but adds 14 autoload
|
|
24
|
+
entries to maintain.
|
|
25
|
+
|
|
26
|
+
Neither path improves the readability of the configuration
|
|
27
|
+
loader itself. The current shape (one file, sections inline)
|
|
28
|
+
makes the configuration schema visible at a glance.
|
|
29
|
+
|
|
30
|
+
## What changed instead
|
|
31
|
+
|
|
32
|
+
The file is over the 300-LOC guideline but the LOC per concept is
|
|
33
|
+
low — it's mostly attribute declarations, not control flow. The
|
|
34
|
+
cost of splitting exceeds the benefit.
|
|
35
|
+
|
|
36
|
+
## Files
|
|
37
|
+
|
|
38
|
+
None — no code change.
|
|
39
|
+
|
|
40
|
+
## Verification
|
|
41
|
+
|
|
42
|
+
Full lutaml-uml suite green; all 23 configuration specs pass.
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
# 06 - JsonExporter: Replace Hand-Rolled `to_h` with lutaml-model
|
|
2
|
+
|
|
3
|
+
## Status: ✅ EVALUATED (2026-07-14) — DEFERRED with rationale
|
|
4
|
+
|
|
5
|
+
## Problem
|
|
6
|
+
|
|
7
|
+
JsonExporter had multiple `serialize_*` private methods that
|
|
8
|
+
hand-built Hashes from UML model instances.
|
|
9
|
+
|
|
10
|
+
## Evaluation
|
|
11
|
+
|
|
12
|
+
The exporter builds a wire-format hash with a specific shape
|
|
13
|
+
(`metadata`, `packages`, `classes`, `associations`) that does
|
|
14
|
+
NOT match the domain model shape 1:1. The hash includes computed
|
|
15
|
+
fields (`package_path` derived from qualified name, stereotype
|
|
16
|
+
normalization, qualified-name lookups via the index).
|
|
17
|
+
|
|
18
|
+
Replacing this with `lutaml-model` mappings would require:
|
|
19
|
+
1. Declaring a new Serializable for each output section with the
|
|
20
|
+
specific wire shape.
|
|
21
|
+
2. Mapping each output field to either a model attribute or a
|
|
22
|
+
computed value.
|
|
23
|
+
3. Maintaining the new Serializables separately from the
|
|
24
|
+
existing presenters (which already produce similar hashes via
|
|
25
|
+
`to_hash`).
|
|
26
|
+
|
|
27
|
+
The presenters already do most of this work — the exporter's
|
|
28
|
+
`serialize_*` methods are essentially calling presenter logic
|
|
29
|
+
plus a few computed fields. The right long-term shape is for the
|
|
30
|
+
exporter to delegate to presenters fully (already partially done
|
|
31
|
+
for some classes).
|
|
32
|
+
|
|
33
|
+
Per the same evaluation as TODO.refactor/13 (presenters are
|
|
34
|
+
presentation-layer code, not domain models), the hand-rolled
|
|
35
|
+
`to_hash` is appropriate at this layer.
|
|
36
|
+
|
|
37
|
+
## What changed instead
|
|
38
|
+
|
|
39
|
+
The TODO.refactor/16 work (replacing doubles in the
|
|
40
|
+
`json_exporter_spec`) revealed that the exporter's interface
|
|
41
|
+
works correctly when called against real model instances.
|
|
42
|
+
No correctness issue; the architectural concern is documented
|
|
43
|
+
but not blocking.
|
|
44
|
+
|
|
45
|
+
## Files
|
|
46
|
+
|
|
47
|
+
None — no code change.
|
|
48
|
+
|
|
49
|
+
## Verification
|
|
50
|
+
|
|
51
|
+
Full lutaml-uml suite green; all 4 json_exporter specs pass
|
|
52
|
+
against real model instances.
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
# 07 - StatisticsCalculator: Decompose
|
|
2
|
+
|
|
3
|
+
## Status: ✅ EVALUATED (2026-07-14) — DEFERRED with rationale
|
|
4
|
+
|
|
5
|
+
## Problem
|
|
6
|
+
|
|
7
|
+
`lib/lutaml/uml_repository/statistics_calculator.rb` (342 LOC)
|
|
8
|
+
with every statistic inlined in one class.
|
|
9
|
+
|
|
10
|
+
## Evaluation
|
|
11
|
+
|
|
12
|
+
Same evaluation as TODO.refactor/03. The statistics all read
|
|
13
|
+
from the same `@indexes` Hash and produce entries in one output
|
|
14
|
+
Hash. Decomposition would require passing the indexes to each
|
|
15
|
+
sub-calculator and merging their outputs — adding parameter
|
|
16
|
+
boilerplate without improving locality. The current class IS
|
|
17
|
+
the locality for "what statistics exist and how are they
|
|
18
|
+
computed."
|
|
19
|
+
|
|
20
|
+
## What changed instead
|
|
21
|
+
|
|
22
|
+
Specs cover each statistic individually. The file is at the
|
|
23
|
+
edge of the 300-LOC guideline but each method is small (3-10
|
|
24
|
+
LOC). The cost of decomposing exceeds the benefit.
|
|
25
|
+
|
|
26
|
+
## Files
|
|
27
|
+
|
|
28
|
+
None — no code change.
|
|
29
|
+
|
|
30
|
+
## Verification
|
|
31
|
+
|
|
32
|
+
Full lutaml-uml suite green.
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
# 08 - PackageExporter: Slim Down
|
|
2
|
+
|
|
3
|
+
## Status: ✅ EVALUATED (2026-07-14) — DEFERRED with rationale
|
|
4
|
+
|
|
5
|
+
## Problem
|
|
6
|
+
|
|
7
|
+
`lib/lutaml/uml_repository/package_exporter.rb` (334 LOC) with
|
|
8
|
+
inline helpers mixing serialization with statistics.
|
|
9
|
+
|
|
10
|
+
## Evaluation
|
|
11
|
+
|
|
12
|
+
The exporter composes two passes (manifest write + document
|
|
13
|
+
serialize) and includes helper methods that format data for the
|
|
14
|
+
manifest. Splitting would require either:
|
|
15
|
+
1. Extracting helpers to a separate file — but they're only
|
|
16
|
+
used here, so the locality gain is zero.
|
|
17
|
+
2. Delegating to JsonExporter for serialization — already done
|
|
18
|
+
for some pieces; the rest are LUR-package-specific
|
|
19
|
+
(manifest format, metadata file).
|
|
20
|
+
|
|
21
|
+
The current shape is cohesive: one class owns the LUR package
|
|
22
|
+
format end-to-end.
|
|
23
|
+
|
|
24
|
+
## What changed instead
|
|
25
|
+
|
|
26
|
+
File is at the edge of the 300-LOC guideline. Per-line
|
|
27
|
+
complexity is low. Defer.
|
|
28
|
+
|
|
29
|
+
## Files
|
|
30
|
+
|
|
31
|
+
None — no code change.
|
|
32
|
+
|
|
33
|
+
## Verification
|
|
34
|
+
|
|
35
|
+
Full lutaml-uml suite green.
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
# 09 - InheritanceQuery: Decompose
|
|
2
|
+
|
|
3
|
+
## Status: ✅ EVALUATED (2026-07-14) — DEFERRED with rationale
|
|
4
|
+
|
|
5
|
+
## Problem
|
|
6
|
+
|
|
7
|
+
`lib/lutaml/uml_repository/queries/inheritance_query.rb` (327
|
|
8
|
+
LOC) with multiple operations in one class.
|
|
9
|
+
|
|
10
|
+
## Evaluation
|
|
11
|
+
|
|
12
|
+
The operations (supertypes, subtypes, depth, ancestors,
|
|
13
|
+
descendants, siblings, is_a?, find_children, find_parent,
|
|
14
|
+
find_ancestors, inheritance_tree, has_circular_inheritance?) all
|
|
15
|
+
read from the same `@indexes[:inheritance_graph]` and share
|
|
16
|
+
private helpers (`resolve_qualified_name`, `walk_graph`).
|
|
17
|
+
Splitting into InheritanceGraph + InheritanceTraversal +
|
|
18
|
+
InheritanceQuery adds two more classes whose only consumer is
|
|
19
|
+
InheritanceQuery — premature abstraction.
|
|
20
|
+
|
|
21
|
+
Per CLAUDE.md: "Three similar lines is better than a premature
|
|
22
|
+
abstraction. Don't design for hypothetical future requirements."
|
|
23
|
+
|
|
24
|
+
## What changed instead
|
|
25
|
+
|
|
26
|
+
Specs cover each operation. File is at the edge of the 300-LOC
|
|
27
|
+
guideline; methods are small and cohesive.
|
|
28
|
+
|
|
29
|
+
## Files
|
|
30
|
+
|
|
31
|
+
None — no code change.
|
|
32
|
+
|
|
33
|
+
## Verification
|
|
34
|
+
|
|
35
|
+
Full lutaml-uml suite green.
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
# 10 - QueryBuilder DSL: Cleanup
|
|
2
|
+
|
|
3
|
+
## Status: ✅ EVALUATED (2026-07-14) — DEFERRED with rationale
|
|
4
|
+
|
|
5
|
+
## Problem
|
|
6
|
+
|
|
7
|
+
`lib/lutaml/uml_repository/query_dsl/query_builder.rb` (290 LOC)
|
|
8
|
+
mixes query construction, condition aggregation, and SQL-like
|
|
9
|
+
DSL semantics.
|
|
10
|
+
|
|
11
|
+
## Evaluation
|
|
12
|
+
|
|
13
|
+
At 290 LOC, this file is BELOW the 300-LOC guideline. The
|
|
14
|
+
methods are short chainable builders that delegate to a small
|
|
15
|
+
set of condition objects. Splitting into QueryBuilder +
|
|
16
|
+
QueryCondition + QueryCompiler would add two new classes whose
|
|
17
|
+
only consumer is QueryBuilder — premature abstraction.
|
|
18
|
+
|
|
19
|
+
## What changed instead
|
|
20
|
+
|
|
21
|
+
File is within the guideline. No action needed.
|
|
22
|
+
|
|
23
|
+
## Files
|
|
24
|
+
|
|
25
|
+
None — no code change.
|
|
26
|
+
|
|
27
|
+
## Verification
|
|
28
|
+
|
|
29
|
+
Full lutaml-uml suite green.
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
# 18 - Unused Liquid Templates (Policy: Preserve)
|
|
2
|
+
|
|
3
|
+
## Status: FLAGGED — preserved per CLAUDE.md "NEVER DELETE source files" rule
|
|
4
|
+
|
|
5
|
+
## What
|
|
6
|
+
|
|
7
|
+
`templates/static_site/` contains 248K of `.liquid` template files.
|
|
8
|
+
The Vue IIFE in `frontend/dist/` replaced them at runtime, but they
|
|
9
|
+
remain as source.
|
|
10
|
+
|
|
11
|
+
## Why not delete
|
|
12
|
+
|
|
13
|
+
CLAUDE.md absolute rule: "NEVER DELETE source files. ANY source
|
|
14
|
+
file — regardless of type." Templates are source. The Vue IIFE is
|
|
15
|
+
derived output.
|
|
16
|
+
|
|
17
|
+
## Recommendation
|
|
18
|
+
|
|
19
|
+
Move to `templates/static_site.legacy/` (preserved, clearly marked
|
|
20
|
+
as superseded) or add to `.gitignore` if the user prefers. Do not
|
|
21
|
+
delete without explicit user confirmation.
|
|
22
|
+
|
|
23
|
+
## Related
|
|
24
|
+
|
|
25
|
+
Supersedes TODO.next/07.
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
# 19 - Broken Executables (Policy: Preserve, Document)
|
|
2
|
+
|
|
3
|
+
## Status: FLAGGED — preserved per CLAUDE.md "NEVER DELETE source files" rule
|
|
4
|
+
|
|
5
|
+
## What
|
|
6
|
+
|
|
7
|
+
`exe/` contains four executables:
|
|
8
|
+
- `lutaml` — broken (was the EA-flavored CLI; removed during EA
|
|
9
|
+
extraction but the script remains)
|
|
10
|
+
- `lutaml-sysml` — broken (same)
|
|
11
|
+
- `lutaml-wsd2uml` — unrelated, works
|
|
12
|
+
- `lutaml-yaml2uml` — unrelated, works
|
|
13
|
+
|
|
14
|
+
The gemspec's `spec.executables = spec.files.grep(%r{^exe/})` ships
|
|
15
|
+
all four, including the broken ones.
|
|
16
|
+
|
|
17
|
+
## Why not delete
|
|
18
|
+
|
|
19
|
+
CLAUDE.md absolute rule: "NEVER DELETE any file you did not create."
|
|
20
|
+
The broken scripts predate my work on this repo.
|
|
21
|
+
|
|
22
|
+
## Recommendation
|
|
23
|
+
|
|
24
|
+
Two paths (need user decision):
|
|
25
|
+
1. **Restore**: re-implement `lutaml` and `lutaml-sysml` as thin
|
|
26
|
+
wrappers that delegate to the `ea` gem's CLI.
|
|
27
|
+
2. **Quarantine**: move to `exe/legacy/` and exclude from
|
|
28
|
+
`spec.executables` so they don't ship, but the files remain.
|
|
29
|
+
|
|
30
|
+
Option 2 is safer; option 1 is more useful if the user wants a
|
|
31
|
+
single CLI entry point again.
|
|
32
|
+
|
|
33
|
+
## Related
|
|
34
|
+
|
|
35
|
+
Supersedes TODO.next/08.
|