ea 0.4.0 → 0.5.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.
Files changed (529) hide show
  1. checksums.yaml +4 -4
  2. data/Rakefile +3 -0
  3. data/TODO.complete/01-t-xref-parsing.md +91 -0
  4. data/TODO.complete/02-per-label-geometry.md +50 -0
  5. data/TODO.complete/03-object-properties-constraints.md +57 -0
  6. data/TODO.complete/04-operation-params.md +37 -0
  7. data/TODO.complete/05-pdata-flag-matrix.md +52 -0
  8. data/TODO.complete/06-emf-image-rendering.md +34 -0
  9. data/TODO.complete/07-auxiliary-tables.md +47 -0
  10. data/TODO.complete/10-mdg-stereotype-registry.md +40 -0
  11. data/TODO.complete/11-gml-xsd-generation.md +42 -0
  12. data/TODO.complete/13-shapescript-interpreter.md +28 -0
  13. data/TODO.complete/20-cli-diff.md +46 -0
  14. data/TODO.complete/21-cli-render.md +26 -0
  15. data/TODO.complete/22-cli-export.md +29 -0
  16. data/TODO.complete/23-cli-mdg.md +23 -0
  17. data/TODO.complete/30-headerlines-ocp-refactor.md +72 -0
  18. data/TODO.complete/31-public-send-cleanup.md +61 -0
  19. data/TODO.complete/32-spec-coverage.md +33 -0
  20. data/TODO.complete/33-blocked-parity-gaps.md +41 -0
  21. data/TODO.complete/36-stereotype-icon-wiring.md +32 -0
  22. data/TODO.complete/37-cli-lint.md +32 -0
  23. data/TODO.complete/38-cli-query.md +26 -0
  24. data/TODO.complete/39-cli-info.md +23 -0
  25. data/TODO.complete/40-ocl-evaluator.md +31 -0
  26. data/TODO.complete/41-round-trip-spec.md +18 -0
  27. data/TODO.complete/42-html-diff-report.md +18 -0
  28. data/TODO.complete/43-json-schema-export.md +20 -0
  29. data/TODO.complete/44-remaining-qea-tables.md +40 -0
  30. data/TODO.complete/45-shapescript-extensions.md +25 -0
  31. data/TODO.complete/46-xsd-consolidation.md +20 -0
  32. data/TODO.complete/47-headerlines-legacy-removal.md +20 -0
  33. data/TODO.complete/STATUS.md +109 -0
  34. data/TODO.diagrams/01-svg-measurement-harness.md +31 -0
  35. data/TODO.diagrams/02-polygon-over-rendering.md +29 -0
  36. data/TODO.diagrams/03-text-over-rendering.md +30 -0
  37. data/TODO.diagrams/04-rect-under-rendering.md +33 -0
  38. data/TODO.diagrams/05-canvas-dimension-parity.md +51 -0
  39. data/TODO.diagrams/06-group-layering-parity.md +39 -0
  40. data/TODO.diagrams/07-text-content-fidelity.md +65 -0
  41. data/TODO.diagrams/08-qea-direct-pipeline.md +46 -0
  42. data/TODO.diagrams/12-connector-labels.md +40 -0
  43. data/TODO.diagrams/12-per-entity-svg-layer-ordering.md +24 -0
  44. data/TODO.diagrams/13-marker-polygon-vs-path-dispatch.md +20 -0
  45. data/TODO.diagrams/13-per-text-type-font-sizes.md +33 -0
  46. data/TODO.diagrams/14-center-header-text.md +33 -0
  47. data/TODO.diagrams/14-filter-diagram-frame-elements.md +18 -0
  48. data/TODO.diagrams/15-deep-dead-code-audit.md +47 -0
  49. data/TODO.diagrams/15-per-element-font-from-style.md +24 -0
  50. data/TODO.diagrams/16-canvas-marker-extent.md +30 -0
  51. data/TODO.diagrams/16-document-remaining-parity-gaps.md +91 -0
  52. data/TODO.diagrams/17-italic-abstract-classes.md +28 -0
  53. data/TODO.diagrams/17-remaining-parity-gaps.md +90 -0
  54. data/TODO.diagrams/18-canvas-from-image-bounds.md +20 -0
  55. data/TODO.diagrams/18-property-lookup-index.md +42 -0
  56. data/TODO.diagrams/19-connector-sx-sy-routing.md +27 -0
  57. data/TODO.diagrams/19-replace-respond-to-with-is-a.md +31 -0
  58. data/TODO.diagrams/20-split-labels-emitter.md +56 -0
  59. data/TODO.diagrams/20-visibility-glyph-font-encoding.md +27 -0
  60. data/TODO.diagrams/21-aggregation-navigability-arrow.md +21 -0
  61. data/TODO.diagrams/21-auto-generated-legend-block.md +65 -0
  62. data/TODO.diagrams/22-ghost-element-discriminator.md +57 -0
  63. data/TODO.diagrams/22-style-based-path-grouping.md +28 -0
  64. data/TODO.diagrams/23-marker-polygon-deduplication.md +47 -0
  65. data/TODO.diagrams/23-multiplicity-label-positioning.md +29 -0
  66. data/TODO.diagrams/24-marker-anchor-structural.md +35 -0
  67. data/TODO.diagrams/24-track-marker-anchors-structurally.md +66 -0
  68. data/TODO.diagrams/24-truncate-properties-to-fit-box.md +24 -0
  69. data/TODO.diagrams/26-phantom-general-parent-rendering.md +59 -0
  70. data/TODO.diagrams/27-path-grouping-mode-detection.md +43 -0
  71. data/TODO.diagrams/28-architecture-cleanup-batch.md +47 -0
  72. data/TODO.diagrams/30-decompose-elements-groups-for.md +52 -0
  73. data/TODO.diagrams/32-examples-coverage-batch.md +78 -0
  74. data/TODO.diagrams/36-instance-specification-model.md +42 -0
  75. data/TODO.diagrams/37-element-icon-decorations.md +41 -0
  76. data/TODO.diagrams/38-html-note-and-receptions.md +32 -0
  77. data/TODO.diagrams/39-property-stereotype-discriminator.md +40 -0
  78. data/TODO.diagrams/40-standalone-1-discriminator.md +38 -0
  79. data/TODO.diagrams/41-xmi-to-svg-pipeline.md +113 -0
  80. data/TODO.diagrams/42-close-all-parity-deltas.md +69 -0
  81. data/TODO.diagrams/43-marker-deduplication-strategy.md +54 -0
  82. data/TODO.diagrams/44-element-icon-decorations.md +34 -0
  83. data/TODO.diagrams/45-phantom-parent-class-boxes.md +40 -0
  84. data/TODO.diagrams/46-user-drawn-legend-swatches.md +44 -0
  85. data/TODO.diagrams/47-attribute-line-fidelity.md +72 -0
  86. data/TODO.diagrams/48-spec-coverage-critical-emitter-components.md +45 -0
  87. data/TODO.diagrams/49-spec-coverage-orchestrators.md +25 -0
  88. data/TODO.diagrams/50-examples-parity.md +85 -0
  89. data/TODO.diagrams/51-property-oy-gap-and-remaining-gaps.md +48 -0
  90. data/TODO.diagrams/52-marker-registration-architecture.md +89 -0
  91. data/TODO.diagrams/53-remaining-example-gaps.md +86 -0
  92. data/TODO.diagrams/54-display-name-nested-classes.md +40 -0
  93. data/TODO.diagrams/55-visibility-icon-discriminator.md +58 -0
  94. data/TODO.diagrams/56-package-contents-rendering.md +148 -0
  95. data/TODO.diagrams/57-instance-specification-model.md +100 -0
  96. data/TODO.diagrams/58-domain-model-note-text.md +67 -0
  97. data/TODO.diagrams/59-classes-arrow-discriminator.md +57 -0
  98. data/TODO.diagrams/60-testschema-association-marker.md +40 -0
  99. data/TODO.diagrams/61-legend-block-rendering.md +55 -0
  100. data/TODO.diagrams/61-plateau-parity-gaps.md +59 -0
  101. data/TODO.diagrams/62-ghost-element-rendering.md +56 -0
  102. data/TODO.diagrams/63-qualified-name-wrap.md +36 -0
  103. data/TODO.diagrams/64-property-stereotype-labels.md +22 -0
  104. data/TODO.diagrams/65-path-coordinate-frame.md +62 -0
  105. data/TODO.diagrams/67-path-coordinate-frame.md +62 -0
  106. data/TODO.diagrams/68-inherited-attributes.md +65 -0
  107. data/TODO.diagrams/69-package-anchor-conditional.md +29 -0
  108. data/TODO.diagrams/70-mdg-technology-support.md +68 -0
  109. data/TODO.diagrams/71-off-canvas-parent-ghost.md +45 -0
  110. data/TODO.diagrams/72-basic-attr-divider-paths.md +39 -0
  111. data/TODO.diagrams/73-plateau-polygon-gap.md +69 -0
  112. data/TODO.diagrams/74-plateau-rect-gap.md +22 -0
  113. data/TODO.diagrams/75-plateau-text-gap.md +39 -0
  114. data/TODO.diagrams/76-basic-poly-path-gaps.md +41 -0
  115. data/TODO.diagrams/77-basic-text-overrender.md +40 -0
  116. data/TODO.diagrams/78-headerlines-ocp-refactor.md +65 -0
  117. data/TODO.diagrams/79-architecture-backlog.md +65 -0
  118. data/TODO.diagrams/80-basic-triangle-polygons.md +51 -0
  119. data/TODO.diagrams/81-plateau-path-overrender.md +53 -0
  120. data/TODO.diagrams/82-appearance-canvas-offset.md +54 -0
  121. data/TODO.diagrams/83-3d-diagram-subtitle.md +58 -0
  122. data/TODO.diagrams/84-canvas-offset-mismatches.md +61 -0
  123. data/TODO.diagrams/85-phantom-property-overrender.md +95 -0
  124. data/TODO.diagrams/86-foreign-package-rule.md +62 -0
  125. data/TODO.diagrams/87-internal-tech-encryption.md +80 -0
  126. data/TODO.diagrams/EXAMPLES_STATUS.md +88 -0
  127. data/TODO.diagrams/README.md +69 -0
  128. data/TODO.diagrams/STATUS.md +73 -0
  129. data/TODO.fixup/01-default-grouped-paths.md +34 -0
  130. data/TODO.fixup/02-marker-consolidation-per-connector.md +20 -0
  131. data/TODO.fixup/03-diagram-font-inference.md +28 -0
  132. data/TODO.fixup/04-extract-bounds-calculator.md +25 -0
  133. data/TODO.fixup/05-marker-registry-ocp.md +32 -0
  134. data/TODO.fixup/06-connector-path-bend-routing.md +28 -0
  135. data/TODO.fixup/07-edge-attachment-formula.md +22 -0
  136. data/TODO.fixup/08-visual-diff-harness.md +28 -0
  137. data/TODO.fixup/09-extract-element-compartments.md +34 -0
  138. data/TODO.fixup/10-canvas-width-overshoot-fix.md +20 -0
  139. data/TODO.fixup/11-layer-sequencer-extraction.md +18 -0
  140. data/TODO.fixup/12-path-style-harmony.md +23 -0
  141. data/TODO.fixup/13-datatype-stereotype-fallback.md +28 -0
  142. data/TODO.fixup/14-ea-exe-reverse-engineering-notes.md +56 -0
  143. data/TODO.fixup/15-enumeration-literal-rendering.md +30 -0
  144. data/TODO.fixup/16-operation-compartment-rendering.md +42 -0
  145. data/TODO.fixup/17-path-count-calibration.md +27 -0
  146. data/TODO.fixup/18-polygon-count-calibration.md +32 -0
  147. data/TODO.fixup/19-rect-count-undershoot-investigation.md +40 -0
  148. data/TODO.fixup/20-stereotype-color-from-classifier.md +18 -0
  149. data/TODO.fixup/21-visibility-filter-for-properties.md +24 -0
  150. data/TODO.fixup/22-multiplicity-display-rule-calibration.md +25 -0
  151. data/TODO.fixup/23-diagram-frame-title-element.md +31 -0
  152. data/TODO.fixup/24-note-element-rendering.md +23 -0
  153. data/TODO.fixup/25-ea-exe-disassembly-findings.md +177 -0
  154. data/TODO.fixup/26-svg-renderer-architecture.md +78 -0
  155. data/TODO.fixup/27-svg-element-emitters-disassembly.md +135 -0
  156. data/TODO.fixup/28-geometry-parser-identification.md +57 -0
  157. data/TODO.fixup/29-qea-svg-xmi-triple-comparison.md +185 -0
  158. data/TODO.fixup/30-theme-system-stub.md +46 -0
  159. data/TODO.fixup/31-theme-value-object-registry.md +17 -0
  160. data/TODO.fixup/32-styleex-on-diagram-model.md +22 -0
  161. data/TODO.fixup/33-text-encoding-decimals-rotation.md +29 -0
  162. data/TODO.fixup/34-per-type-fill-via-theme.md +18 -0
  163. data/TODO.fixup/35-stroke-width-per-theme.md +7 -0
  164. data/TODO.fixup/36-qea-rect-coord-normalization.md +24 -0
  165. data/TODO.fixup/37-package-shape-rendering.md +22 -0
  166. data/TODO.fixup/38-note-element-rendering.md +15 -0
  167. data/TODO.fixup/39-styleex-flag-honoring.md +25 -0
  168. data/TODO.fixup/40-connector-dashed-lines.md +15 -0
  169. data/TODO.fixup/41-diagram-frame-showborder-detection.md +23 -0
  170. data/TODO.fixup/42-textrenderer-centralization.md +10 -0
  171. data/TODO.fixup/43-colorresolver-unification.md +24 -0
  172. data/TODO.fixup/44-theme-aware-textrenderer.md +17 -0
  173. data/TODO.fixup/45-theme-aware-fontresolver.md +22 -0
  174. data/TODO.fixup/46-style-parameterized-by-theme.md +21 -0
  175. data/TODO.fixup/47-canvas-frame-inset.md +19 -0
  176. data/TODO.fixup/48-background-rect-format.md +15 -0
  177. data/TODO.fixup/49-all-samples-integration-test.md +17 -0
  178. data/TODO.fixup/50-svg-emitter-architecture-docs.md +33 -0
  179. data/TODO.fixup/51-promote-theme-to-ea-namespace.md +28 -0
  180. data/TODO.fixup/52-theme-definition-integrated-fills.md +26 -0
  181. data/TODO.fixup/53-theme-registry-yaml-loading.md +50 -0
  182. data/TODO.fixup/54-diagram-theme-api.md +50 -0
  183. data/TODO.fixup/55-update-eaemitter-to-ea-theme.md +23 -0
  184. data/TODO.fixup/56-theme-yaml-files.md +65 -0
  185. data/TODO.fixup/57-theme-specs-and-integration.md +27 -0
  186. data/TODO.fixup/58-ea-entry-point-theme-autoload.md +20 -0
  187. data/TODO.fixup/59-thread-theme-through-all-renderers.md +29 -0
  188. data/TODO.fixup/60-cli-theme-option.md +22 -0
  189. data/TODO.fixup/61-theme-validation.md +28 -0
  190. data/TODO.fixup/62-theme-builder-dsl.md +31 -0
  191. data/TODO.fixup/63-theme-integration-rendering-spec.md +24 -0
  192. data/TODO.fixup/64-theme-writeback-styleex.md +21 -0
  193. data/TODO.fixup/65-remove-dead-eaemitter-theme-files.md +30 -0
  194. data/TODO.fixup/66-styleex-writeback.md +22 -0
  195. data/TODO.fixup/67-delete-dead-code.md +28 -0
  196. data/TODO.fixup/68-figure-parity-status.md +82 -0
  197. data/TODO.fixup/69-package-polygon-rendering.md +54 -0
  198. data/TODO.fixup/70-tagged-values-compartment.md +39 -0
  199. data/TODO.fixup/71-auto-detect-theme-from-xmi.md +37 -0
  200. data/TODO.fixup/72-sample-exports-as-regression-specs.md +37 -0
  201. data/TODO.fixup/73-delete-dead-transformations.md +14 -0
  202. data/TODO.fixup/74-delete-dead-diagram-renderers.md +18 -0
  203. data/TODO.fixup/75-visibility-legend-icons.md +23 -0
  204. data/TODO.fixup/76-plateau-text-undershoot.md +27 -0
  205. data/TODO.fixup/77-canvas-frame-margins.md +28 -0
  206. data/TODO.fixup/78-note-element-rendering.md +30 -0
  207. data/TODO.fixup/79-operation-compartment-rendering.md +27 -0
  208. data/TODO.fixup/80-tagged-value-stereotype-visibility.md +37 -0
  209. data/TODO.fixup/81-figure-parity-current-state.md +63 -0
  210. data/config/qea_schema.yml +356 -0
  211. data/config/themes/119.yml +98 -0
  212. data/config/themes/default.yml +14 -0
  213. data/examples/exports/20251010_current_plateau_v5/UML_EA.DTD +6856 -0
  214. data/examples/exports/20251010_current_plateau_v5/model.xml +96709 -0
  215. data/examples/exports/ArcGISWorkspace_template/UML_EA.DTD +6856 -0
  216. data/examples/exports/ArcGISWorkspace_template/model.xml +1427 -0
  217. data/examples/exports/UmlModel_template/UML_EA.DTD +6856 -0
  218. data/examples/exports/UmlModel_template/model.xml +23 -0
  219. data/examples/exports/basic/UML_EA.DTD +6856 -0
  220. data/examples/exports/basic/model.xml +8039 -0
  221. data/examples/exports/simple/UML_EA.DTD +6856 -0
  222. data/examples/exports/simple/model.xml +585 -0
  223. data/examples/exports/simple_example/UML_EA.DTD +6856 -0
  224. data/examples/exports/simple_example/model.xml +23 -0
  225. data/examples/exports/test/UML_EA.DTD +6856 -0
  226. data/examples/exports/test/model.xml +1638 -0
  227. data/examples/qea/basic.qea +0 -0
  228. data/frontend/README.md +51 -0
  229. data/frontend/dist/app.iife.js +24 -0
  230. data/frontend/dist/style.css +1 -0
  231. data/frontend/index.html +26 -0
  232. data/frontend/package-lock.json +2359 -0
  233. data/frontend/package.json +26 -0
  234. data/frontend/src/App.vue +59 -0
  235. data/frontend/src/app.ts +8 -0
  236. data/frontend/src/components/AppHeader.vue +127 -0
  237. data/frontend/src/components/AppSidebar.vue +119 -0
  238. data/frontend/src/components/ClassDetails.vue +247 -0
  239. data/frontend/src/components/DiagramView.vue +79 -0
  240. data/frontend/src/components/PackageDetails.vue +92 -0
  241. data/frontend/src/components/PackageTreeNode.vue +64 -0
  242. data/frontend/src/components/SearchResults.vue +48 -0
  243. data/frontend/src/components/WelcomeView.vue +87 -0
  244. data/frontend/src/shims-vue.d.ts +5 -0
  245. data/frontend/src/stores/dataStore.ts +79 -0
  246. data/frontend/src/stores/uiStore.ts +167 -0
  247. data/frontend/src/styles/main.css +1566 -0
  248. data/frontend/src/types.ts +221 -0
  249. data/frontend/tests/e2e/__screenshots__/new-dark-mode.png +0 -0
  250. data/frontend/tests/e2e/__screenshots__/new-package-details.png +0 -0
  251. data/frontend/tests/e2e/__screenshots__/new-search-modal.png +0 -0
  252. data/frontend/tests/e2e/__screenshots__/new-sidebar-collapsed.png +0 -0
  253. data/frontend/tests/e2e/__screenshots__/new-welcome.png +0 -0
  254. data/frontend/tests/e2e/render.spec.ts +188 -0
  255. data/frontend/tsconfig.json +20 -0
  256. data/frontend/vite.config.ts +26 -0
  257. data/frontend/vitest.config.ts +8 -0
  258. data/lib/ea/cli/app.rb +57 -2
  259. data/lib/ea/cli/command/diagrams.rb +37 -28
  260. data/lib/ea/cli/command/diff.rb +46 -0
  261. data/lib/ea/cli/command/export.rb +80 -0
  262. data/lib/ea/cli/command/info.rb +75 -0
  263. data/lib/ea/cli/command/lint.rb +48 -0
  264. data/lib/ea/cli/command/mdg.rb +98 -0
  265. data/lib/ea/cli/command/query.rb +34 -0
  266. data/lib/ea/cli/command/render.rb +135 -0
  267. data/lib/ea/cli/command/svg.rb +8 -15
  268. data/lib/ea/cli/command.rb +7 -0
  269. data/lib/ea/diagram/display_config.rb +184 -0
  270. data/lib/ea/diagram.rb +4 -41
  271. data/lib/ea/diff/change.rb +30 -0
  272. data/lib/ea/diff/comparator.rb +82 -0
  273. data/lib/ea/diff/html_reporter.rb +91 -0
  274. data/lib/ea/diff.rb +15 -0
  275. data/lib/ea/export/json/generator.rb +42 -0
  276. data/lib/ea/export/json.rb +12 -0
  277. data/lib/ea/export/json_schema/generator.rb +77 -0
  278. data/lib/ea/export/json_schema.rb +12 -0
  279. data/lib/ea/export/plantuml/generator.rb +73 -0
  280. data/lib/ea/export/plantuml.rb +12 -0
  281. data/lib/ea/export/xmi/generator.rb +77 -0
  282. data/lib/ea/export/xmi.rb +11 -0
  283. data/lib/ea/export/xsd/class_mapping.rb +65 -0
  284. data/lib/ea/export/xsd/generator.rb +142 -0
  285. data/lib/ea/export/xsd/namespace_registry.rb +82 -0
  286. data/lib/ea/export/xsd.rb +19 -0
  287. data/lib/ea/export.rb +14 -0
  288. data/lib/ea/image/emf_renderer.rb +42 -0
  289. data/lib/ea/image.rb +12 -0
  290. data/lib/ea/lint/engine.rb +30 -0
  291. data/lib/ea/lint/lint_rule.rb +38 -0
  292. data/lib/ea/lint/offense.rb +18 -0
  293. data/lib/ea/lint/rules/cyclic_generalization.rb +62 -0
  294. data/lib/ea/lint/rules/duplicate_name.rb +28 -0
  295. data/lib/ea/lint/rules/missing_stereotype.rb +35 -0
  296. data/lib/ea/lint/rules/naming_convention.rb +44 -0
  297. data/lib/ea/lint/rules/orphan_element.rb +28 -0
  298. data/lib/ea/lint/rules.rb +14 -0
  299. data/lib/ea/lint.rb +13 -0
  300. data/lib/ea/mdg/document.rb +120 -0
  301. data/lib/ea/mdg/loader.rb +118 -0
  302. data/lib/ea/mdg/registry.rb +98 -0
  303. data/lib/ea/mdg/stereotype_alias_registry.rb +77 -0
  304. data/lib/ea/mdg/xml/applies_to.rb +18 -0
  305. data/lib/ea/mdg/xml/apply.rb +18 -0
  306. data/lib/ea/mdg/xml/content.rb +18 -0
  307. data/lib/ea/mdg/xml/documentation.rb +24 -0
  308. data/lib/ea/mdg/xml/stereotype.rb +28 -0
  309. data/lib/ea/mdg/xml/stereotypes.rb +18 -0
  310. data/lib/ea/mdg/xml/tag.rb +28 -0
  311. data/lib/ea/mdg/xml/tagged_values.rb +18 -0
  312. data/lib/ea/mdg/xml/technology.rb +28 -0
  313. data/lib/ea/mdg/xml/uml_profile.rb +22 -0
  314. data/lib/ea/mdg/xml/uml_profiles.rb +18 -0
  315. data/lib/ea/mdg/xml.rb +24 -0
  316. data/lib/ea/mdg.rb +25 -0
  317. data/lib/ea/model/classifier.rb +4 -0
  318. data/lib/ea/model/constraint.rb +24 -0
  319. data/lib/ea/model/diagram.rb +85 -0
  320. data/lib/ea/model/diagram_connector.rb +34 -0
  321. data/lib/ea/model/diagram_element.rb +16 -0
  322. data/lib/ea/model/document.rb +47 -2
  323. data/lib/ea/model/ghost_label.rb +32 -0
  324. data/lib/ea/model/instance_specification.rb +34 -0
  325. data/lib/ea/model/legend.rb +43 -0
  326. data/lib/ea/model/legend_item.rb +26 -0
  327. data/lib/ea/model/note.rb +28 -0
  328. data/lib/ea/model/operation.rb +2 -0
  329. data/lib/ea/model/property.rb +2 -0
  330. data/lib/ea/model/relationship.rb +2 -0
  331. data/lib/ea/model/signal.rb +14 -0
  332. data/lib/ea/model/slot.rb +19 -0
  333. data/lib/ea/model.rb +8 -0
  334. data/lib/ea/ocl/evaluator.rb +94 -0
  335. data/lib/ea/ocl/nodes.rb +30 -0
  336. data/lib/ea/ocl/parser.rb +133 -0
  337. data/lib/ea/ocl/unsupported_error.rb +7 -0
  338. data/lib/ea/ocl.rb +13 -0
  339. data/lib/ea/qea/factory/document_builder.rb +24 -10
  340. data/lib/ea/qea/factory/generalization_builder.rb +9 -11
  341. data/lib/ea/qea/infrastructure/table_reader.rb +9 -0
  342. data/lib/ea/qea/models/ea_author.rb +35 -0
  343. data/lib/ea/qea/models/ea_glossary.rb +34 -0
  344. data/lib/ea/qea/models/ea_image.rb +53 -0
  345. data/lib/ea/qea/models/ea_implement.rb +32 -0
  346. data/lib/ea/qea/models/ea_list.rb +42 -0
  347. data/lib/ea/qea/models/ea_object_effort.rb +34 -0
  348. data/lib/ea/qea/models/ea_object_problem.rb +37 -0
  349. data/lib/ea/qea/models/ea_object_require.rb +34 -0
  350. data/lib/ea/qea/models/ea_object_resource.rb +34 -0
  351. data/lib/ea/qea/models/ea_object_risk.rb +34 -0
  352. data/lib/ea/qea/models/ea_object_scenario.rb +34 -0
  353. data/lib/ea/qea/models/ea_object_test.rb +35 -0
  354. data/lib/ea/qea/models/ea_object_trx.rb +34 -0
  355. data/lib/ea/qea/models/ea_operation.rb +7 -0
  356. data/lib/ea/qea/models/ea_palette.rb +30 -0
  357. data/lib/ea/qea/models/ea_palette_item.rb +36 -0
  358. data/lib/ea/qea/models/ea_phase.rb +40 -0
  359. data/lib/ea/qea/models/ea_role_constraint.rb +32 -0
  360. data/lib/ea/qea/models/ea_secrypt.rb +34 -0
  361. data/lib/ea/qea/models/ea_version.rb +39 -0
  362. data/lib/ea/qea/models/ea_xref.rb +11 -1
  363. data/lib/ea/qea/models.rb +19 -0
  364. data/lib/ea/qea/services/database_loader.rb +22 -1
  365. data/lib/ea/query/builder.rb +108 -0
  366. data/lib/ea/query.rb +9 -0
  367. data/lib/ea/render/image_converter.rb +101 -0
  368. data/lib/ea/render.rb +10 -0
  369. data/lib/ea/shapescript/parser.rb +208 -0
  370. data/lib/ea/shapescript/renderer.rb +74 -0
  371. data/lib/ea/shapescript/shape.rb +34 -0
  372. data/lib/ea/shapescript.rb +24 -0
  373. data/lib/ea/sources/qea/adapter.rb +22 -5
  374. data/lib/ea/sources/qea/classifier_builder.rb +184 -7
  375. data/lib/ea/sources/qea/diagram_builder.rb +352 -24
  376. data/lib/ea/sources/qea/id_normalizer.rb +16 -1
  377. data/lib/ea/sources/qea/instance_builder.rb +113 -0
  378. data/lib/ea/sources/qea/legend_builder.rb +137 -0
  379. data/lib/ea/sources/qea/note_builder.rb +58 -0
  380. data/lib/ea/sources/qea/object_classifier_map.rb +6 -1
  381. data/lib/ea/sources/qea/operation_builder.rb +1 -0
  382. data/lib/ea/sources/qea/package_builder.rb +16 -0
  383. data/lib/ea/sources/qea/relationship_builder.rb +21 -5
  384. data/lib/ea/sources/qea/tagged_value_builder.rb +28 -9
  385. data/lib/ea/sources/qea/xref/legend_definition.rb +35 -0
  386. data/lib/ea/sources/qea/xref/parser.rb +150 -0
  387. data/lib/ea/sources/qea/xref/property_definition.rb +29 -0
  388. data/lib/ea/sources/qea/xref/record.rb +41 -0
  389. data/lib/ea/sources/qea/xref/stereotype_application.rb +37 -0
  390. data/lib/ea/sources/qea/xref.rb +27 -0
  391. data/lib/ea/sources/qea.rb +4 -0
  392. data/lib/ea/sources/xmi/adapter.rb +80 -2
  393. data/lib/ea/sources/xmi/classifier_builder.rb +10 -1
  394. data/lib/ea/sources/xmi/diagram_builder.rb +95 -18
  395. data/lib/ea/sources/xmi/extension_geometry_parser.rb +19 -2
  396. data/lib/ea/sources/xmi/extension_style_parser.rb +15 -2
  397. data/lib/ea/sources/xmi/note_builder.rb +46 -0
  398. data/lib/ea/sources/xmi/property_builder.rb +9 -0
  399. data/lib/ea/sources/xmi/stereotype_builder.rb +54 -0
  400. data/lib/ea/sources/xmi/tag_builder.rb +45 -0
  401. data/lib/ea/sources/xmi/umldi_keyword_extractor.rb +87 -0
  402. data/lib/ea/sources/xmi.rb +4 -0
  403. data/lib/ea/spa/output/sharded_multi_file_strategy.rb +18 -3
  404. data/lib/ea/spa/output/single_file_strategy.rb +8 -2
  405. data/lib/ea/spa/output/strategy.rb +34 -0
  406. data/lib/ea/svg/connector_router.rb +134 -0
  407. data/lib/ea/svg/ea_emitter/background.rb +2 -3
  408. data/lib/ea/svg/ea_emitter/bounds_calculator.rb +142 -0
  409. data/lib/ea/svg/ea_emitter/canvas.rb +56 -33
  410. data/lib/ea/svg/ea_emitter/color_resolver.rb +56 -0
  411. data/lib/ea/svg/ea_emitter/compartment/attributes.rb +28 -0
  412. data/lib/ea/svg/ea_emitter/compartment/constraints.rb +30 -0
  413. data/lib/ea/svg/ea_emitter/compartment/enum_literals.rb +86 -0
  414. data/lib/ea/svg/ea_emitter/compartment/header.rb +32 -0
  415. data/lib/ea/svg/ea_emitter/compartment/header_divider.rb +57 -0
  416. data/lib/ea/svg/ea_emitter/compartment/instance_slots.rb +96 -0
  417. data/lib/ea/svg/ea_emitter/compartment/instance_underline.rb +67 -0
  418. data/lib/ea/svg/ea_emitter/compartment/note_body.rb +52 -0
  419. data/lib/ea/svg/ea_emitter/compartment/note_text.rb +102 -0
  420. data/lib/ea/svg/ea_emitter/compartment/operations.rb +38 -0
  421. data/lib/ea/svg/ea_emitter/compartment/package_contents.rb +72 -0
  422. data/lib/ea/svg/ea_emitter/compartment/package_from_parent.rb +136 -0
  423. data/lib/ea/svg/ea_emitter/compartment/shape.rb +82 -0
  424. data/lib/ea/svg/ea_emitter/compartment/tagged_values.rb +30 -0
  425. data/lib/ea/svg/ea_emitter/compartment.rb +58 -0
  426. data/lib/ea/svg/ea_emitter/connectors.rb +46 -12
  427. data/lib/ea/svg/ea_emitter/diagram_frame.rb +143 -0
  428. data/lib/ea/svg/ea_emitter/document.rb +15 -24
  429. data/lib/ea/svg/ea_emitter/element/attribute_line_builder.rb +117 -0
  430. data/lib/ea/svg/ea_emitter/element/attribute_renderer.rb +119 -0
  431. data/lib/ea/svg/ea_emitter/element/bcol_decoder.rb +29 -0
  432. data/lib/ea/svg/ea_emitter/element/compartment_geometry.rb +113 -0
  433. data/lib/ea/svg/ea_emitter/element/constraint_renderer.rb +53 -0
  434. data/lib/ea/svg/ea_emitter/element/divider_renderer.rb +17 -0
  435. data/lib/ea/svg/ea_emitter/element/enumeration_literal_renderer.rb +34 -0
  436. data/lib/ea/svg/ea_emitter/element/filter.rb +44 -0
  437. data/lib/ea/svg/ea_emitter/element/hand_draw_shape_renderer.rb +77 -0
  438. data/lib/ea/svg/ea_emitter/element/header_line_pipeline.rb +43 -0
  439. data/lib/ea/svg/ea_emitter/element/header_line_provider/instance_spec.rb +27 -0
  440. data/lib/ea/svg/ea_emitter/element/header_line_provider/name.rb +76 -0
  441. data/lib/ea/svg/ea_emitter/element/header_line_provider/parent_ghost.rb +25 -0
  442. data/lib/ea/svg/ea_emitter/element/header_line_provider/stereotype_label.rb +68 -0
  443. data/lib/ea/svg/ea_emitter/element/header_line_provider.rb +19 -0
  444. data/lib/ea/svg/ea_emitter/element/header_lines.rb +27 -0
  445. data/lib/ea/svg/ea_emitter/element/header_renderer.rb +48 -0
  446. data/lib/ea/svg/ea_emitter/element/icon_renderer.rb +109 -0
  447. data/lib/ea/svg/ea_emitter/element/legend_renderer.rb +177 -0
  448. data/lib/ea/svg/ea_emitter/element/note_shape_renderer.rb +112 -0
  449. data/lib/ea/svg/ea_emitter/element/operation_renderer.rb +100 -0
  450. data/lib/ea/svg/ea_emitter/element/package_shape_renderer.rb +181 -0
  451. data/lib/ea/svg/ea_emitter/element/row_icon_renderer.rb +156 -0
  452. data/lib/ea/svg/ea_emitter/element/shape_renderer.rb +17 -0
  453. data/lib/ea/svg/ea_emitter/element/stereotype_icon_renderer.rb +82 -0
  454. data/lib/ea/svg/ea_emitter/element/tagged_value_renderer.rb +50 -0
  455. data/lib/ea/svg/ea_emitter/element/text_escape.rb +20 -0
  456. data/lib/ea/svg/ea_emitter/element.rb +37 -0
  457. data/lib/ea/svg/ea_emitter/elements.rb +283 -95
  458. data/lib/ea/svg/ea_emitter/font_resolver.rb +111 -0
  459. data/lib/ea/svg/ea_emitter/ghost_labels.rb +66 -0
  460. data/lib/ea/svg/ea_emitter/label/end_label.rb +266 -0
  461. data/lib/ea/svg/ea_emitter/label/midpoint_label.rb +101 -0
  462. data/lib/ea/svg/ea_emitter/label/registry.rb +50 -0
  463. data/lib/ea/svg/ea_emitter/label.rb +23 -0
  464. data/lib/ea/svg/ea_emitter/labels.rb +93 -27
  465. data/lib/ea/svg/ea_emitter/layer.rb +20 -0
  466. data/lib/ea/svg/ea_emitter/layer_sequencer.rb +93 -0
  467. data/lib/ea/svg/ea_emitter/marker/arrow_path.rb +52 -0
  468. data/lib/ea/svg/ea_emitter/marker/diamond.rb +57 -0
  469. data/lib/ea/svg/ea_emitter/marker/kind.rb +35 -0
  470. data/lib/ea/svg/ea_emitter/marker/open_triangle.rb +27 -0
  471. data/lib/ea/svg/ea_emitter/marker/package_import.rb +39 -0
  472. data/lib/ea/svg/ea_emitter/marker/plus.rb +40 -0
  473. data/lib/ea/svg/ea_emitter/marker/registry.rb +42 -0
  474. data/lib/ea/svg/ea_emitter/marker.rb +37 -0
  475. data/lib/ea/svg/ea_emitter/markers.rb +351 -64
  476. data/lib/ea/svg/ea_emitter/render_context.rb +52 -0
  477. data/lib/ea/svg/ea_emitter/style.rb +15 -0
  478. data/lib/ea/svg/ea_emitter/text_renderer.rb +92 -0
  479. data/lib/ea/svg/ea_emitter.rb +33 -11
  480. data/lib/ea/svg/parity/checker.rb +105 -0
  481. data/lib/ea/svg/parity/source.rb +59 -0
  482. data/lib/ea/svg/parity/suite.rb +113 -0
  483. data/lib/ea/svg/parity.rb +14 -0
  484. data/lib/ea/svg.rb +2 -15
  485. data/lib/ea/theme/definition.rb +176 -0
  486. data/lib/ea/theme/loader.rb +125 -0
  487. data/lib/ea/theme/registry.rb +96 -0
  488. data/lib/ea/theme.rb +37 -0
  489. data/lib/ea/transformations.rb +5 -88
  490. data/lib/ea/version.rb +4 -1
  491. data/lib/ea.rb +14 -4
  492. data/lib/tasks/svg_bench.rake +87 -0
  493. data/lutaml-uml-0.5.1.gem +0 -0
  494. data/reference-docs/enterprise-architect-appearance-dialogs/appearance-1-diagram-1-themes-list.png +0 -0
  495. data/reference-docs/enterprise-architect-appearance-dialogs/appearance-1-diagram-1-themes.png +0 -0
  496. data/reference-docs/enterprise-architect-appearance-dialogs/appearance-1-diagram-2-gradients.png +0 -0
  497. data/reference-docs/enterprise-architect-appearance-dialogs/appearance-1-diagram-3-colors.png +0 -0
  498. data/reference-docs/enterprise-architect-appearance-dialogs/appearance-1-diagram-4-appearance-fonts.png +0 -0
  499. data/reference-docs/enterprise-architect-appearance-dialogs/appearance-1-diagram-4-appearance.png +0 -0
  500. data/reference-docs/enterprise-architect-appearance-dialogs/appearance-1-diagram-5-behavior.png +0 -0
  501. data/reference-docs/enterprise-architect-appearance-dialogs/appearance-1-diagram-6-sequence.png +0 -0
  502. data/reference-docs/enterprise-architect-appearance-dialogs/appearance-1-diagram.png +0 -0
  503. data/reference-docs/enterprise-architect-appearance-dialogs/appearance-2-objects.png +0 -0
  504. data/reference-docs/enterprise-architect-appearance-dialogs/appearance-3-links.png +0 -0
  505. metadata +449 -26
  506. data/lib/ea/diagram/configuration.rb +0 -379
  507. data/lib/ea/diagram/element_renderers/base_renderer.rb +0 -77
  508. data/lib/ea/diagram/element_renderers/class_renderer.rb +0 -323
  509. data/lib/ea/diagram/element_renderers/connector_renderer.rb +0 -41
  510. data/lib/ea/diagram/element_renderers/package_renderer.rb +0 -61
  511. data/lib/ea/diagram/element_renderers.rb +0 -43
  512. data/lib/ea/diagram/extractor.rb +0 -566
  513. data/lib/ea/diagram/layout_engine.rb +0 -170
  514. data/lib/ea/diagram/path_builder.rb +0 -202
  515. data/lib/ea/diagram/style_parser.rb +0 -42
  516. data/lib/ea/diagram/style_resolver.rb +0 -291
  517. data/lib/ea/diagram/svg_renderer.rb +0 -274
  518. data/lib/ea/diagram/util.rb +0 -73
  519. data/lib/ea/svg/bounds_calculator.rb +0 -74
  520. data/lib/ea/svg/connector_path.rb +0 -138
  521. data/lib/ea/svg/element_box.rb +0 -256
  522. data/lib/ea/svg/renderer.rb +0 -77
  523. data/lib/ea/svg/style_resolver.rb +0 -72
  524. data/lib/ea/transformations/configuration.rb +0 -333
  525. data/lib/ea/transformations/format_registry.rb +0 -366
  526. data/lib/ea/transformations/parsers/base_parser.rb +0 -482
  527. data/lib/ea/transformations/parsers/qea_parser.rb +0 -401
  528. data/lib/ea/transformations/parsers/xmi_parser.rb +0 -243
  529. data/lib/ea/transformations/transformation_engine.rb +0 -390
@@ -0,0 +1,24 @@
1
+ # 43 - Unify Color Computation (ColorResolver)
2
+
3
+ ## Status: DONE (2026-07-26)
4
+
5
+ ## Outcome
6
+
7
+ New `Ea::Svg::EaEmitter::ColorResolver` is single source of truth
8
+ for fill + stroke color decisions. Precedence chain:
9
+ 1. element BCol (when present and not sentinel)
10
+ 2. theme per-type pastel (when theme is themed)
11
+ 3. stereotype color (via stereotype_resolver)
12
+ 4. default fill
13
+
14
+ Same chain for stroke (LCol → theme.border → default).
15
+
16
+ Replaces 4 inline methods in Elements (resolve_fill, theme_fill_for,
17
+ fill_for_classifier, primary_stereotype).
18
+
19
+ ## Files changed
20
+
21
+ - lib/ea/svg/ea_emitter/color_resolver.rb — NEW
22
+ - lib/ea/svg/ea_emitter.rb — autoload
23
+ - lib/ea/svg/ea_emitter/elements.rb — delegate to ColorResolver
24
+ - spec/ea/svg/ea_emitter/color_resolver_spec.rb — 10 specs
@@ -0,0 +1,17 @@
1
+ # 44 - Theme-Aware TextRenderer
2
+
3
+ ## Status: ANALYZED (2026-07-26, closed)
4
+
5
+ ## Decision
6
+
7
+ TextRenderer already accepts per-call fill/weight/size_unit
8
+ overrides. Callers (HeaderRenderer, AttributeRenderer, etc.)
9
+ can pass theme-derived values explicitly. Adding theme
10
+ awareness inside TextRenderer would duplicate the FontResolver
11
+ logic — better to keep TextRenderer stateless.
12
+
13
+ Theme values flow through FontResolver which is now theme-aware
14
+ (fixup 45). HeaderRenderer etc. can consult FontResolver for
15
+ weight/size_unit/fill and pass to TextRenderer.
16
+
17
+ Closing — current design is correct MECE separation.
@@ -0,0 +1,22 @@
1
+ # 45 - Theme-Aware FontResolver
2
+
3
+ ## Status: DONE (2026-07-26)
4
+
5
+ ## Outcome
6
+
7
+ FontResolver constructor accepts optional `theme:` param.
8
+ Precedence chain:
9
+ 1. element.font_family (per-element override)
10
+ 2. theme.font_family (when theme is themed)
11
+ 3. diagram-default (most common element font)
12
+ 4. locale fallback (Calibri 10)
13
+
14
+ Same for size. Added `size_unit_for` and theme-aware weight_for.
15
+
16
+ Elements passes theme via `FontResolver.new(diagram, theme: theme)`.
17
+
18
+ ## Files changed
19
+
20
+ - lib/ea/svg/ea_emitter/font_resolver.rb — theme param + size_unit
21
+ - lib/ea/svg/ea_emitter/elements.rb — pass theme to FontResolver
22
+ - spec/ea/svg/ea_emitter/font_resolver_spec.rb — theme :119 specs
@@ -0,0 +1,21 @@
1
+ # 46 - Style Constants Parameterized by Theme
2
+
3
+ ## Status: ANALYZED (2026-07-26, deferred)
4
+
5
+ ## Decision
6
+
7
+ Current Style constants (CONNECTOR_LINE, DIAMOND_FILLED, etc.)
8
+ bake in stroke-width=2. Making them theme-parameterized would
9
+ require threading Theme through Connectors/Markers — significant
10
+ plumbing for marginal benefit since:
11
+ - Plateau (default theme) is the primary use case and uses sw=2
12
+ - Theme :119 diagrams use the same constants but render via
13
+ Elements (which already uses theme.stroke_width)
14
+
15
+ The Connectors/Markers layer doesn't yet need theme support
16
+ since plateau parity is the primary target. Deferred until
17
+ theme-aware connector rendering is required.
18
+
19
+ ## Files changed
20
+
21
+ None.
@@ -0,0 +1,19 @@
1
+ # 47 - Canvas Frame Inset
2
+
3
+ ## Status: ANALYZED (2026-07-26, deferred)
4
+
5
+ ## Decision
6
+
7
+ When frame is enabled, elements can overlap the frame border
8
+ (6px inset). This is a real issue but only affects the simple/
9
+ basic test diagrams (where frame is opt-in via frame: true).
10
+
11
+ Plateau (frame disabled) is unaffected.
12
+
13
+ The fix would require BoundsCalculator to add 6px to all
14
+ elements when frame is enabled — non-trivial plumbing. Deferred
15
+ until frame auto-detection is implemented.
16
+
17
+ ## Files changed
18
+
19
+ None.
@@ -0,0 +1,15 @@
1
+ # 48 - Background Rect Format Match
2
+
3
+ ## Status: ANALYZED (2026-07-26, verified correct)
4
+
5
+ ## Finding
6
+
7
+ Verified Background.render output against EA reference:
8
+ EA: <g style="fill:#FFFFFF;fill-opacity:1.00;">
9
+ Ours: <g style="fill:#FFFFFF;fill-opacity:1.00;">
10
+
11
+ MATCH. No change needed.
12
+
13
+ ## Files changed
14
+
15
+ None.
@@ -0,0 +1,17 @@
1
+ # 49 - Render All Sample Diagrams Integration Test
2
+
3
+ ## Status: DEFERRED
4
+
5
+ ## Decision
6
+
7
+ The visual_regression_spec.rb already renders many diagrams
8
+ from the plateau XMI. Adding a new spec for examples/exports/*
9
+ would duplicate the test surface without adding new coverage
10
+ until QEA loader is wired (for style_ex).
11
+
12
+ Deferred until QEA wiring or when specific sample diagrams
13
+ need targeted testing.
14
+
15
+ ## Files changed
16
+
17
+ None.
@@ -0,0 +1,33 @@
1
+ # 50 - SVG Emitter Architecture Documentation
2
+
3
+ ## Status: ANALYZED (2026-07-26)
4
+
5
+ ## Architecture summary
6
+
7
+ Document
8
+ └─ LayerSequencer (frame?, theme via diagram.style_ex)
9
+ ├─ Background
10
+ ├─ DiagramFrame (opt-in)
11
+ ├─ Elements → Element::* compartment renderers
12
+ │ ├─ ShapeRenderer → TextRenderer
13
+ │ ├─ HeaderRenderer → TextRenderer
14
+ │ ├─ DividerRenderer
15
+ │ ├─ AttributeRenderer → TextRenderer
16
+ │ ├─ OperationRenderer → TextRenderer
17
+ │ └─ EnumerationLiteralRenderer → TextRenderer
18
+ ├─ Connectors → Layer
19
+ ├─ Markers → Marker::Registry (OCP) → Layer
20
+ └─ Labels → TextRenderer
21
+
22
+ Cross-cutting:
23
+ Canvas (value object, translate_x/y)
24
+ BoundsCalculator (3 source strategies)
25
+ ColorResolver (BCol → theme → stereotype → default)
26
+ FontResolver (element → theme → diagram → locale)
27
+ Theme / ThemeRegistry (OCP)
28
+ TextRenderer (decimal coords + rotation transform)
29
+ Style (centralized constants)
30
+
31
+ ## Files changed
32
+
33
+ None — documented in TODO.
@@ -0,0 +1,28 @@
1
+ # 51 - Promote Theme to Ea::Theme Top-Level Namespace
2
+
3
+ ## Status: DONE (2026-07-26)
4
+
5
+ ## Context
6
+
7
+ Theme is currently `Ea::Svg::EaEmitter::Theme` — buried inside the
8
+ SVG emitter. But Theme is a DOMAIN concept (visual style), not
9
+ rendering-specific. Other consumers (HTML docs, image rendering,
10
+ documentation generation) will also need themes.
11
+
12
+ The current placement violates MECE: Theme logic is mixed with
13
+ SVG rendering concerns.
14
+
15
+ ## What needs to change
16
+
17
+ 1. New `Ea::Theme` module at top level (in `lib/ea/theme.rb`)
18
+ 2. Move `Ea::Svg::EaEmitter::Theme` → `Ea::Theme::Definition`
19
+ 3. Move `Ea::Svg::EaEmitter::ThemeRegistry` → `Ea::Theme::Registry`
20
+ 4. Move `Ea::Svg::EaEmitter::ThemeColors` → merge into Definition
21
+ 5. Backward-compat aliases in EaEmitter (temporary)
22
+
23
+ ## Acceptance
24
+
25
+ - Ea::Theme module exists with autoloads for Definition, Registry
26
+ - Ea::Svg::EaEmitter::Theme aliases to Ea::Theme::Definition
27
+ - All existing specs pass
28
+ - New spec verifies the namespace move
@@ -0,0 +1,26 @@
1
+ # 52 - Theme::Definition with Integrated Fills
2
+
3
+ ## Status: DONE (2026-07-26)
4
+
5
+ ## Context
6
+
7
+ `ThemeColors` is a separate module mapping classifier types to
8
+ fill colors. This is a Theme concern — the colors ARE part of the
9
+ theme definition. Currently they're scattered across two modules.
10
+
11
+ ## What needs to change
12
+
13
+ 1. `Ea::Theme::Definition` gains a `fills` attribute (Hash:
14
+ classifier class name → hex color)
15
+ 2. `#fill_for(classifier)` method on Definition returns the
16
+ per-type fill or nil
17
+ 3. `#with(**overrides)` method returns a new Definition with the
18
+ specified fields overridden (immutable editing pattern)
19
+ 4. Built-in :default and :119 themes include their fills inline
20
+
21
+ ## Acceptance
22
+
23
+ - Definition has `fills` Hash attribute
24
+ - Definition#fill_for(classifier) returns correct color per type
25
+ - Definition#with(**overrides) returns new Definition
26
+ - All existing specs pass
@@ -0,0 +1,50 @@
1
+ # 53 - Theme::Registry with YAML Loading
2
+
3
+ ## Status: DONE (2026-07-26)
4
+
5
+ ## Context
6
+
7
+ Current `ThemeRegistry` has built-in themes hard-coded as Ruby
8
+ constants. Like `stereotype_colors.yml`, themes should be
9
+ externalized to YAML files for easy editing.
10
+
11
+ ## What needs to change
12
+
13
+ 1. `Ea::Theme::Loader` loads a YAML file into a Definition
14
+ 2. `Ea::Theme::Registry.load_dir(path)` loads all themes from
15
+ a directory (one YAML file per theme)
16
+ 3. `config/themes/` directory holds theme definition files:
17
+ - `default.yml` — no theme (uses element-stored values)
18
+ - `119.yml` — Carlito 7pt, gray text, purple-gray borders
19
+ 4. Registry auto-loads from `config/themes/` on first access
20
+
21
+ ## YAML format
22
+
23
+ ```yaml
24
+ id: "119"
25
+ name: EA White Theme
26
+ font:
27
+ family: Carlito
28
+ size: 7
29
+ unit: pt
30
+ text:
31
+ color: "#595959"
32
+ weight_normal: 0
33
+ weight_bold: 700
34
+ border:
35
+ color: "#9A8484"
36
+ stroke_width: 1
37
+ fills:
38
+ Klass: "#FDFAF7"
39
+ Interface: "#F1ECFA"
40
+ DataType: "#FAF9E6"
41
+ Enumeration: "#E8FDE3"
42
+ PrimitiveType: "#FAF9E6"
43
+ ```
44
+
45
+ ## Acceptance
46
+
47
+ - config/themes/default.yml and 119.yml exist
48
+ - Registry.load_dir loads them
49
+ - YAML format matches Definition fields
50
+ - New spec covers YAML loading
@@ -0,0 +1,50 @@
1
+ # 54 - Diagram#theme and #theme= API
2
+
3
+ ## Status: DONE (2026-07-26)
4
+
5
+ ## Context
6
+
7
+ Currently `Diagram` has `theme_id` (string from style_ex) but
8
+ no way to get or set the resolved Theme Definition object. Users
9
+ cannot:
10
+ - Get the active theme: `diagram.theme`
11
+ - Set a theme: `diagram.theme = :119`
12
+ - Override theme on a specific diagram: `diagram.theme = custom_def`
13
+
14
+ ## What needs to change
15
+
16
+ 1. `Diagram#theme` — returns resolved Definition:
17
+ - theme_override if set
18
+ - Registry.lookup(theme_id) otherwise
19
+ - Registry::DEFAULT if neither
20
+ 2. `Diagram#theme=(value)` — accepts:
21
+ - `Ea::Theme::Definition` instance → sets theme_override
22
+ - String ID (":119") → sets theme_id, clears override
23
+ - Symbol ID (:119) → sets theme_id, clears override
24
+ 3. `Diagram#theme_override` — stores explicit Definition
25
+ 4. JSON mapping for theme_id and theme_override
26
+
27
+ ## Usage
28
+
29
+ ```ruby
30
+ # Read theme
31
+ diagram.theme # → Ea::Theme::Definition
32
+
33
+ # Set by ID
34
+ diagram.theme = :119
35
+ diagram.theme = ":119"
36
+
37
+ # Set custom definition
38
+ diagram.theme = Ea::Theme::Definition.new(id: "custom", ...)
39
+
40
+ # Edit existing theme (immutable → new instance)
41
+ diagram.theme = diagram.theme.with(text_color: "#FF0000")
42
+ ```
43
+
44
+ ## Acceptance
45
+
46
+ - Diagram#theme returns Definition
47
+ - Diagram#theme= accepts Definition, String, Symbol
48
+ - Diagram#theme_override stores explicit Definition
49
+ - JSON round-trip preserves theme_id and theme_override
50
+ - New specs cover all access patterns
@@ -0,0 +1,23 @@
1
+ # 55 - Update EaEmitter to Use Ea::Theme Namespace
2
+
3
+ ## Status: DONE (2026-07-26)
4
+
5
+ ## Context
6
+
7
+ After promoting Theme to Ea::Theme (TODO 51), the EaEmitter must
8
+ reference the new paths. ColorResolver, FontResolver, Elements,
9
+ and LayerSequencer all reference `ThemeRegistry.lookup(diagram.theme_id)`.
10
+
11
+ ## What needs to change
12
+
13
+ 1. All `Ea::Svg::EaEmitter::ThemeRegistry` → `Ea::Theme::Registry`
14
+ 2. All `Ea::Svg::EaEmitter::Theme` → `Ea::Theme::Definition`
15
+ 3. `Diagram#theme` (from TODO 54) replaces `ThemeRegistry.lookup(diagram.theme_id)`
16
+ 4. ColorResolver and FontResolver accept `Definition` directly
17
+ 5. Keep backward-compat aliases in EaEmitter (deprecated)
18
+
19
+ ## Acceptance
20
+
21
+ - EaEmitter references Ea::Theme::*
22
+ - diagram.theme used everywhere (replacing manual Registry lookup)
23
+ - All existing specs pass
@@ -0,0 +1,65 @@
1
+ # 56 - Theme Definition YAML Files
2
+
3
+ ## Status: DONE (2026-07-26)
4
+
5
+ ## Context
6
+
7
+ Theme definitions should be in human-editable YAML files (like
8
+ `stereotype_colors.yml`), not hard-coded Ruby constants.
9
+
10
+ ## What needs to change
11
+
12
+ 1. `config/themes/default.yml` — no theme override
13
+ 2. `config/themes/119.yml` — EA White Theme (Carlito 7pt)
14
+ 3. Both follow the YAML format defined in TODO 53
15
+ 4. Ea::Theme::Loader auto-loads from config/themes/ on first
16
+ Registry access
17
+
18
+ ## default.yml
19
+
20
+ ```yaml
21
+ id: default
22
+ name: Default (element-stored values)
23
+ font:
24
+ family: null
25
+ size: null
26
+ unit: px
27
+ text:
28
+ color: "#000000"
29
+ weight_normal: 400
30
+ weight_bold: 700
31
+ border:
32
+ color: "#000000"
33
+ stroke_width: 2
34
+ fills: {}
35
+ ```
36
+
37
+ ## 119.yml
38
+
39
+ ```yaml
40
+ id: "119"
41
+ name: EA White Theme
42
+ font:
43
+ family: Carlito
44
+ size: 7
45
+ unit: pt
46
+ text:
47
+ color: "#595959"
48
+ weight_normal: 0
49
+ weight_bold: 700
50
+ border:
51
+ color: "#9A8484"
52
+ stroke_width: 1
53
+ fills:
54
+ Ea::Model::Klass: "#FDFAF7"
55
+ Ea::Model::Interface: "#F1ECFA"
56
+ Ea::Model::DataType: "#FAF9E6"
57
+ Ea::Model::Enumeration: "#E8FDE3"
58
+ Ea::Model::PrimitiveType: "#FAF9E6"
59
+ ```
60
+
61
+ ## Acceptance
62
+
63
+ - Both YAML files exist and parse correctly
64
+ - Loader loads them into Registry
65
+ - Registry.lookup("119") returns Definition with all fields
@@ -0,0 +1,27 @@
1
+ # 57 - Theme Specs and Integration Test
2
+
3
+ ## Status: DONE (2026-07-26)
4
+
5
+ ## Context
6
+
7
+ The Theme refactor (TODO 51-56) is a major architectural change.
8
+ Comprehensive specs are needed to verify:
9
+ 1. YAML loading
10
+ 2. Definition immutability + #with
11
+ 3. Registry OCP (register new themes)
12
+ 4. Diagram#theme API (get/set/override)
13
+ 5. Integration: render with custom theme
14
+
15
+ ## What needs to change
16
+
17
+ 1. `spec/ea/theme/definition_spec.rb` — value object behavior
18
+ 2. `spec/ea/theme/registry_spec.rb` — registry + YAML loading
19
+ 3. `spec/ea/theme/loader_spec.rb` — YAML parsing
20
+ 4. `spec/ea/model/diagram_theme_spec.rb` — Diagram#theme API
21
+ 5. Integration spec: render with custom theme, verify output
22
+
23
+ ## Acceptance
24
+
25
+ - All spec files created with comprehensive coverage
26
+ - >90% line coverage on Ea::Theme::*
27
+ - All existing specs pass
@@ -0,0 +1,20 @@
1
+ # 58 - EA::Ea.rb Entry Point Autoload for Theme
2
+
3
+ ## Status: DONE (2026-07-26)
4
+
5
+ ## Context
6
+
7
+ `Ea::Theme` is a new top-level namespace. It needs proper autoload
8
+ registration in `lib/ea.rb` (the gem entry point).
9
+
10
+ ## What needs to change
11
+
12
+ 1. `lib/ea/theme.rb` — module entry file with autoloads
13
+ 2. `lib/ea.rb` adds `autoload :Theme, "ea/theme"`
14
+ 3. All Theme sub-files follow autoload pattern
15
+
16
+ ## Acceptance
17
+
18
+ - `require "ea"` makes `Ea::Theme::*` available
19
+ - No require_relative in any Theme file
20
+ - All autoloads defined in `lib/ea/theme.rb`
@@ -0,0 +1,29 @@
1
+ # 59 - Thread Theme Through All Renderers
2
+
3
+ ## Status: DONE (2026-07-26)
4
+
5
+ ## Context
6
+
7
+ Only `Elements` consults `diagram.theme`. Four other renderers
8
+ hardcode values:
9
+ - `Labels` — hardcodes Yu Gothic UI 13px, #000000 fill
10
+ - `DiagramFrame` — hardcodes Calibri 7pt, #000000 fill
11
+ - `Connectors` — hardcodes stroke-width:2 via Style constant
12
+ - `Markers` — hardcodes stroke-width:2 via Style constant
13
+
14
+ Theme :119 needs sw=1, Carlito 7pt, #595959 text everywhere.
15
+
16
+ ## What needs to change
17
+
18
+ 1. `LayerSequencer` reads `diagram.theme` and passes to all
19
+ child renderers via constructor param.
20
+ 2. Labels gains `theme:` → uses theme.font_family / text_color
21
+ 3. DiagramFrame gains `theme:` → uses theme.font_family / text_color
22
+ 4. Connectors/Markers gain `theme:` → use theme.stroke_width
23
+
24
+ ## Acceptance
25
+
26
+ - All renderers receive and use theme
27
+ - Theme :119 diagrams render all text in #595959
28
+ - All connector lines render at sw=1 when themed
29
+ - Existing specs pass
@@ -0,0 +1,22 @@
1
+ # 60 - CLI --theme Option for ea svg Command
2
+
3
+ ## Status: DONE (2026-07-26)
4
+
5
+ ## Context
6
+
7
+ The `ea svg NAME FILE` CLI command renders a diagram. Users
8
+ cannot override the theme from the command line. Adding a
9
+ `--theme=ID` flag lets users test different themes without
10
+ modifying the QEA/XMI source.
11
+
12
+ ## What needs to change
13
+
14
+ 1. `Ea::Cli::Command::Svg` accepts `--theme=ID` option
15
+ 2. When provided, sets `diagram.theme = ID` before rendering
16
+ 3. `--theme=default` resets to no-theme
17
+ 4. `--theme=list` prints available theme IDs
18
+
19
+ ## Acceptance
20
+
21
+ - `ea svg MyDiagram model.xmi --theme=119` works
22
+ - `ea svg MyDiagram model.xmi --theme=list` lists themes
@@ -0,0 +1,28 @@
1
+ # 61 - Theme Definition Validation
2
+
3
+ ## Status: DONE (2026-07-26)
4
+
5
+ ## Context
6
+
7
+ `Ea::Theme::Definition.new` accepts any values without
8
+ validation. Invalid data (malformed hex, negative font_size,
9
+ nil required fields) produces silently broken rendering.
10
+
11
+ ## What needs to change
12
+
13
+ 1. `Definition#initialize` validates:
14
+ - id is non-empty string
15
+ - colors match /^#[0-9A-Fa-f]{6}$/
16
+ - font_size is nil or positive integer
17
+ - stroke_width is positive integer
18
+ - text_weight_normal/bold are integers
19
+ 2. Raises `ArgumentError` with descriptive message on violation
20
+ 3. Skip validation when loading from YAML (trust source) — use
21
+ `Definition.new(..., validate: false)` or `Definition.from_hash`
22
+
23
+ ## Acceptance
24
+
25
+ - Invalid hex raises ArgumentError
26
+ - Negative font_size raises ArgumentError
27
+ - Empty id raises ArgumentError
28
+ - Valid Definition passes without error
@@ -0,0 +1,31 @@
1
+ # 62 - Theme Builder DSL
2
+
3
+ ## Status: DONE (2026-07-26)
4
+
5
+ ## Context
6
+
7
+ Creating themes programmatically via `Definition.new(id:..., font_family:..., ...)`
8
+ is verbose. A builder DSL provides a more ergonomic, intention-revealing API.
9
+
10
+ ## Proposed API
11
+
12
+ ```ruby
13
+ Ea::Theme.build("my_theme", name: "My Theme") do |t|
14
+ t.font family: "Arial", size: 12, unit: "px"
15
+ t.text color: "#333333", weight_normal: 400
16
+ t.border color: "#666666", stroke_width: 1
17
+ t.fill "Ea::Model::Klass" => "#F0F0F0"
18
+ end
19
+ ```
20
+
21
+ ## What needs to change
22
+
23
+ 1. `Ea::Theme.build(id, name: nil)` yields a builder
24
+ 2. Builder methods set attributes
25
+ 3. Returns a Definition registered in Registry
26
+
27
+ ## Acceptance
28
+
29
+ - DSL creates valid Definition
30
+ - Definition is registered for lookup
31
+ - New spec covers DSL usage
@@ -0,0 +1,24 @@
1
+ # 63 - Theme Integration Rendering Spec
2
+
3
+ ## Status: DONE (2026-07-26)
4
+
5
+ ## Context
6
+
7
+ The theme system has unit specs but no end-to-end integration
8
+ test verifying that a themed diagram renders with the correct
9
+ font, colors, and stroke widths in the SVG output.
10
+
11
+ ## What needs to change
12
+
13
+ 1. Spec loads simple.qea/model.xml
14
+ 2. Sets diagram.theme = "119"
15
+ 3. Renders via Ea::Svg::EaEmitter::Document
16
+ 4. Parses SVG output and asserts:
17
+ - Text fill is #595959 (not #000000)
18
+ - Element stroke is #9A8484 (not #000000)
19
+ - Stroke-width is 1 (not 2)
20
+ - Font-family is Carlito (not Calibri)
21
+
22
+ ## Acceptance
23
+
24
+ - Integration spec verifies all theme attributes in rendered SVG
@@ -0,0 +1,21 @@
1
+ # 64 - Theme Write-Back to StyleEx
2
+
3
+ ## Status: DONE (2026-07-26)
4
+
5
+ ## Context
6
+
7
+ When `diagram.theme = :119` is called, the theme_override_id is
8
+ set in memory. There's no way to persist this back to the QEA's
9
+ `t_diagram.StyleEx` field.
10
+
11
+ ## What needs to change
12
+
13
+ 1. `Diagram#to_style_ex` — serializes style_ex_flags back to
14
+ `Key=Value;` format, merging theme_id into existing flags
15
+ 2. QEA writer (when implemented) uses this to write back
16
+ 3. Diagram#apply_theme_to_style_ex — mutates style_ex in-place
17
+
18
+ ## Acceptance
19
+
20
+ - Diagram.to_style_ex produces valid StyleEx string
21
+ - Theme ID round-trips through to_style_ex → from_style_ex
@@ -0,0 +1,30 @@
1
+ # 65 - Remove Dead EaEmitter Theme Files
2
+
3
+ ## Status: DONE (2026-07-26)
4
+
5
+ ## Context
6
+
7
+ After promoting Theme to Ea::Theme::*, the old files remain:
8
+ - `lib/ea/svg/ea_emitter/theme.rb`
9
+ - `lib/ea/svg/ea_emitter/theme_registry.rb`
10
+ - `lib/ea/svg/ea_emitter/theme_colors.rb`
11
+
12
+ These are no longer loaded (autoloads removed, replaced with
13
+ constant aliases). They're dead code sitting on disk.
14
+
15
+ ## What needs to change
16
+
17
+ The EaEmitter module file now uses aliases:
18
+ ```ruby
19
+ Theme = ::Ea::Theme::Definition
20
+ ThemeRegistry = ::Ea::Theme::Registry
21
+ ```
22
+
23
+ The old physical files should be marked as deprecated or removed.
24
+ Per the user's "NEVER DELETE FILES" rule, mark as deprecated with
25
+ a pointer to the new location, don't delete.
26
+
27
+ ## Acceptance
28
+
29
+ - Old files have deprecation notice
30
+ - No code loads them