ea 0.3.1 → 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 (544) 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/01-xmi-extension-elements-parsing.md +67 -0
  36. data/TODO.diagrams/02-diagram-element-rich-model.md +61 -0
  37. data/TODO.diagrams/02-polygon-over-rendering.md +29 -0
  38. data/TODO.diagrams/03-ea-style-svg-emitter.md +70 -0
  39. data/TODO.diagrams/03-text-over-rendering.md +30 -0
  40. data/TODO.diagrams/04-connector-routing-from-soid-eoid.md +55 -0
  41. data/TODO.diagrams/04-rect-under-rendering.md +33 -0
  42. data/TODO.diagrams/05-canvas-dimension-parity.md +51 -0
  43. data/TODO.diagrams/05-marker-rendering-per-relationship-type.md +49 -0
  44. data/TODO.diagrams/06-connector-labels.md +49 -0
  45. data/TODO.diagrams/06-group-layering-parity.md +39 -0
  46. data/TODO.diagrams/07-canvas-size-and-viewbox.md +39 -0
  47. data/TODO.diagrams/07-text-content-fidelity.md +65 -0
  48. data/TODO.diagrams/08-qea-direct-pipeline.md +46 -0
  49. data/TODO.diagrams/08-visual-regression-harness.md +34 -0
  50. data/TODO.diagrams/09-cli-render-all-diagrams.md +25 -0
  51. data/TODO.diagrams/10-stereotype-color-config.md +29 -0
  52. data/TODO.diagrams/11-elkrb-auto-layout-integration.md +53 -0
  53. data/TODO.diagrams/12-connector-labels.md +40 -0
  54. data/TODO.diagrams/12-per-entity-svg-layer-ordering.md +24 -0
  55. data/TODO.diagrams/13-marker-polygon-vs-path-dispatch.md +20 -0
  56. data/TODO.diagrams/13-per-text-type-font-sizes.md +33 -0
  57. data/TODO.diagrams/14-center-header-text.md +33 -0
  58. data/TODO.diagrams/14-filter-diagram-frame-elements.md +18 -0
  59. data/TODO.diagrams/15-deep-dead-code-audit.md +47 -0
  60. data/TODO.diagrams/15-per-element-font-from-style.md +24 -0
  61. data/TODO.diagrams/16-canvas-marker-extent.md +30 -0
  62. data/TODO.diagrams/16-document-remaining-parity-gaps.md +91 -0
  63. data/TODO.diagrams/17-italic-abstract-classes.md +28 -0
  64. data/TODO.diagrams/17-remaining-parity-gaps.md +90 -0
  65. data/TODO.diagrams/18-canvas-from-image-bounds.md +20 -0
  66. data/TODO.diagrams/18-property-lookup-index.md +42 -0
  67. data/TODO.diagrams/19-connector-sx-sy-routing.md +27 -0
  68. data/TODO.diagrams/19-replace-respond-to-with-is-a.md +31 -0
  69. data/TODO.diagrams/20-split-labels-emitter.md +56 -0
  70. data/TODO.diagrams/20-visibility-glyph-font-encoding.md +27 -0
  71. data/TODO.diagrams/21-aggregation-navigability-arrow.md +21 -0
  72. data/TODO.diagrams/21-auto-generated-legend-block.md +65 -0
  73. data/TODO.diagrams/22-ghost-element-discriminator.md +57 -0
  74. data/TODO.diagrams/22-style-based-path-grouping.md +28 -0
  75. data/TODO.diagrams/23-marker-polygon-deduplication.md +47 -0
  76. data/TODO.diagrams/23-multiplicity-label-positioning.md +29 -0
  77. data/TODO.diagrams/24-marker-anchor-structural.md +35 -0
  78. data/TODO.diagrams/24-track-marker-anchors-structurally.md +66 -0
  79. data/TODO.diagrams/24-truncate-properties-to-fit-box.md +24 -0
  80. data/TODO.diagrams/26-phantom-general-parent-rendering.md +59 -0
  81. data/TODO.diagrams/27-path-grouping-mode-detection.md +43 -0
  82. data/TODO.diagrams/28-architecture-cleanup-batch.md +47 -0
  83. data/TODO.diagrams/30-decompose-elements-groups-for.md +52 -0
  84. data/TODO.diagrams/32-examples-coverage-batch.md +78 -0
  85. data/TODO.diagrams/36-instance-specification-model.md +42 -0
  86. data/TODO.diagrams/37-element-icon-decorations.md +41 -0
  87. data/TODO.diagrams/38-html-note-and-receptions.md +32 -0
  88. data/TODO.diagrams/39-property-stereotype-discriminator.md +40 -0
  89. data/TODO.diagrams/40-standalone-1-discriminator.md +38 -0
  90. data/TODO.diagrams/41-xmi-to-svg-pipeline.md +113 -0
  91. data/TODO.diagrams/42-close-all-parity-deltas.md +69 -0
  92. data/TODO.diagrams/43-marker-deduplication-strategy.md +54 -0
  93. data/TODO.diagrams/44-element-icon-decorations.md +34 -0
  94. data/TODO.diagrams/45-phantom-parent-class-boxes.md +40 -0
  95. data/TODO.diagrams/46-user-drawn-legend-swatches.md +44 -0
  96. data/TODO.diagrams/47-attribute-line-fidelity.md +72 -0
  97. data/TODO.diagrams/48-spec-coverage-critical-emitter-components.md +45 -0
  98. data/TODO.diagrams/49-spec-coverage-orchestrators.md +25 -0
  99. data/TODO.diagrams/50-examples-parity.md +85 -0
  100. data/TODO.diagrams/51-property-oy-gap-and-remaining-gaps.md +48 -0
  101. data/TODO.diagrams/52-marker-registration-architecture.md +89 -0
  102. data/TODO.diagrams/53-remaining-example-gaps.md +86 -0
  103. data/TODO.diagrams/54-display-name-nested-classes.md +40 -0
  104. data/TODO.diagrams/55-visibility-icon-discriminator.md +58 -0
  105. data/TODO.diagrams/56-package-contents-rendering.md +148 -0
  106. data/TODO.diagrams/57-instance-specification-model.md +100 -0
  107. data/TODO.diagrams/58-domain-model-note-text.md +67 -0
  108. data/TODO.diagrams/59-classes-arrow-discriminator.md +57 -0
  109. data/TODO.diagrams/60-testschema-association-marker.md +40 -0
  110. data/TODO.diagrams/61-legend-block-rendering.md +55 -0
  111. data/TODO.diagrams/61-plateau-parity-gaps.md +59 -0
  112. data/TODO.diagrams/62-ghost-element-rendering.md +56 -0
  113. data/TODO.diagrams/63-qualified-name-wrap.md +36 -0
  114. data/TODO.diagrams/64-property-stereotype-labels.md +22 -0
  115. data/TODO.diagrams/65-path-coordinate-frame.md +62 -0
  116. data/TODO.diagrams/67-path-coordinate-frame.md +62 -0
  117. data/TODO.diagrams/68-inherited-attributes.md +65 -0
  118. data/TODO.diagrams/69-package-anchor-conditional.md +29 -0
  119. data/TODO.diagrams/70-mdg-technology-support.md +68 -0
  120. data/TODO.diagrams/71-off-canvas-parent-ghost.md +45 -0
  121. data/TODO.diagrams/72-basic-attr-divider-paths.md +39 -0
  122. data/TODO.diagrams/73-plateau-polygon-gap.md +69 -0
  123. data/TODO.diagrams/74-plateau-rect-gap.md +22 -0
  124. data/TODO.diagrams/75-plateau-text-gap.md +39 -0
  125. data/TODO.diagrams/76-basic-poly-path-gaps.md +41 -0
  126. data/TODO.diagrams/77-basic-text-overrender.md +40 -0
  127. data/TODO.diagrams/78-headerlines-ocp-refactor.md +65 -0
  128. data/TODO.diagrams/79-architecture-backlog.md +65 -0
  129. data/TODO.diagrams/80-basic-triangle-polygons.md +51 -0
  130. data/TODO.diagrams/81-plateau-path-overrender.md +53 -0
  131. data/TODO.diagrams/82-appearance-canvas-offset.md +54 -0
  132. data/TODO.diagrams/83-3d-diagram-subtitle.md +58 -0
  133. data/TODO.diagrams/84-canvas-offset-mismatches.md +61 -0
  134. data/TODO.diagrams/85-phantom-property-overrender.md +95 -0
  135. data/TODO.diagrams/86-foreign-package-rule.md +62 -0
  136. data/TODO.diagrams/87-internal-tech-encryption.md +80 -0
  137. data/TODO.diagrams/EXAMPLES_STATUS.md +88 -0
  138. data/TODO.diagrams/README.md +69 -0
  139. data/TODO.diagrams/STATUS.md +73 -0
  140. data/TODO.fixup/01-default-grouped-paths.md +34 -0
  141. data/TODO.fixup/02-marker-consolidation-per-connector.md +20 -0
  142. data/TODO.fixup/03-diagram-font-inference.md +28 -0
  143. data/TODO.fixup/04-extract-bounds-calculator.md +25 -0
  144. data/TODO.fixup/05-marker-registry-ocp.md +32 -0
  145. data/TODO.fixup/06-connector-path-bend-routing.md +28 -0
  146. data/TODO.fixup/07-edge-attachment-formula.md +22 -0
  147. data/TODO.fixup/08-visual-diff-harness.md +28 -0
  148. data/TODO.fixup/09-extract-element-compartments.md +34 -0
  149. data/TODO.fixup/10-canvas-width-overshoot-fix.md +20 -0
  150. data/TODO.fixup/11-layer-sequencer-extraction.md +18 -0
  151. data/TODO.fixup/12-path-style-harmony.md +23 -0
  152. data/TODO.fixup/13-datatype-stereotype-fallback.md +28 -0
  153. data/TODO.fixup/14-ea-exe-reverse-engineering-notes.md +56 -0
  154. data/TODO.fixup/15-enumeration-literal-rendering.md +30 -0
  155. data/TODO.fixup/16-operation-compartment-rendering.md +42 -0
  156. data/TODO.fixup/17-path-count-calibration.md +27 -0
  157. data/TODO.fixup/18-polygon-count-calibration.md +32 -0
  158. data/TODO.fixup/19-rect-count-undershoot-investigation.md +40 -0
  159. data/TODO.fixup/20-stereotype-color-from-classifier.md +18 -0
  160. data/TODO.fixup/21-visibility-filter-for-properties.md +24 -0
  161. data/TODO.fixup/22-multiplicity-display-rule-calibration.md +25 -0
  162. data/TODO.fixup/23-diagram-frame-title-element.md +31 -0
  163. data/TODO.fixup/24-note-element-rendering.md +23 -0
  164. data/TODO.fixup/25-ea-exe-disassembly-findings.md +177 -0
  165. data/TODO.fixup/26-svg-renderer-architecture.md +78 -0
  166. data/TODO.fixup/27-svg-element-emitters-disassembly.md +135 -0
  167. data/TODO.fixup/28-geometry-parser-identification.md +57 -0
  168. data/TODO.fixup/29-qea-svg-xmi-triple-comparison.md +185 -0
  169. data/TODO.fixup/30-theme-system-stub.md +46 -0
  170. data/TODO.fixup/31-theme-value-object-registry.md +17 -0
  171. data/TODO.fixup/32-styleex-on-diagram-model.md +22 -0
  172. data/TODO.fixup/33-text-encoding-decimals-rotation.md +29 -0
  173. data/TODO.fixup/34-per-type-fill-via-theme.md +18 -0
  174. data/TODO.fixup/35-stroke-width-per-theme.md +7 -0
  175. data/TODO.fixup/36-qea-rect-coord-normalization.md +24 -0
  176. data/TODO.fixup/37-package-shape-rendering.md +22 -0
  177. data/TODO.fixup/38-note-element-rendering.md +15 -0
  178. data/TODO.fixup/39-styleex-flag-honoring.md +25 -0
  179. data/TODO.fixup/40-connector-dashed-lines.md +15 -0
  180. data/TODO.fixup/41-diagram-frame-showborder-detection.md +23 -0
  181. data/TODO.fixup/42-textrenderer-centralization.md +10 -0
  182. data/TODO.fixup/43-colorresolver-unification.md +24 -0
  183. data/TODO.fixup/44-theme-aware-textrenderer.md +17 -0
  184. data/TODO.fixup/45-theme-aware-fontresolver.md +22 -0
  185. data/TODO.fixup/46-style-parameterized-by-theme.md +21 -0
  186. data/TODO.fixup/47-canvas-frame-inset.md +19 -0
  187. data/TODO.fixup/48-background-rect-format.md +15 -0
  188. data/TODO.fixup/49-all-samples-integration-test.md +17 -0
  189. data/TODO.fixup/50-svg-emitter-architecture-docs.md +33 -0
  190. data/TODO.fixup/51-promote-theme-to-ea-namespace.md +28 -0
  191. data/TODO.fixup/52-theme-definition-integrated-fills.md +26 -0
  192. data/TODO.fixup/53-theme-registry-yaml-loading.md +50 -0
  193. data/TODO.fixup/54-diagram-theme-api.md +50 -0
  194. data/TODO.fixup/55-update-eaemitter-to-ea-theme.md +23 -0
  195. data/TODO.fixup/56-theme-yaml-files.md +65 -0
  196. data/TODO.fixup/57-theme-specs-and-integration.md +27 -0
  197. data/TODO.fixup/58-ea-entry-point-theme-autoload.md +20 -0
  198. data/TODO.fixup/59-thread-theme-through-all-renderers.md +29 -0
  199. data/TODO.fixup/60-cli-theme-option.md +22 -0
  200. data/TODO.fixup/61-theme-validation.md +28 -0
  201. data/TODO.fixup/62-theme-builder-dsl.md +31 -0
  202. data/TODO.fixup/63-theme-integration-rendering-spec.md +24 -0
  203. data/TODO.fixup/64-theme-writeback-styleex.md +21 -0
  204. data/TODO.fixup/65-remove-dead-eaemitter-theme-files.md +30 -0
  205. data/TODO.fixup/66-styleex-writeback.md +22 -0
  206. data/TODO.fixup/67-delete-dead-code.md +28 -0
  207. data/TODO.fixup/68-figure-parity-status.md +82 -0
  208. data/TODO.fixup/69-package-polygon-rendering.md +54 -0
  209. data/TODO.fixup/70-tagged-values-compartment.md +39 -0
  210. data/TODO.fixup/71-auto-detect-theme-from-xmi.md +37 -0
  211. data/TODO.fixup/72-sample-exports-as-regression-specs.md +37 -0
  212. data/TODO.fixup/73-delete-dead-transformations.md +14 -0
  213. data/TODO.fixup/74-delete-dead-diagram-renderers.md +18 -0
  214. data/TODO.fixup/75-visibility-legend-icons.md +23 -0
  215. data/TODO.fixup/76-plateau-text-undershoot.md +27 -0
  216. data/TODO.fixup/77-canvas-frame-margins.md +28 -0
  217. data/TODO.fixup/78-note-element-rendering.md +30 -0
  218. data/TODO.fixup/79-operation-compartment-rendering.md +27 -0
  219. data/TODO.fixup/80-tagged-value-stereotype-visibility.md +37 -0
  220. data/TODO.fixup/81-figure-parity-current-state.md +63 -0
  221. data/config/qea_schema.yml +356 -0
  222. data/config/stereotype_colors.yml +15 -0
  223. data/config/themes/119.yml +98 -0
  224. data/config/themes/default.yml +14 -0
  225. data/examples/exports/20251010_current_plateau_v5/UML_EA.DTD +6856 -0
  226. data/examples/exports/20251010_current_plateau_v5/model.xml +96709 -0
  227. data/examples/exports/ArcGISWorkspace_template/UML_EA.DTD +6856 -0
  228. data/examples/exports/ArcGISWorkspace_template/model.xml +1427 -0
  229. data/examples/exports/UmlModel_template/UML_EA.DTD +6856 -0
  230. data/examples/exports/UmlModel_template/model.xml +23 -0
  231. data/examples/exports/basic/UML_EA.DTD +6856 -0
  232. data/examples/exports/basic/model.xml +8039 -0
  233. data/examples/exports/simple/UML_EA.DTD +6856 -0
  234. data/examples/exports/simple/model.xml +585 -0
  235. data/examples/exports/simple_example/UML_EA.DTD +6856 -0
  236. data/examples/exports/simple_example/model.xml +23 -0
  237. data/examples/exports/test/UML_EA.DTD +6856 -0
  238. data/examples/exports/test/model.xml +1638 -0
  239. data/examples/qea/basic.qea +0 -0
  240. data/frontend/README.md +51 -0
  241. data/frontend/dist/app.iife.js +24 -0
  242. data/frontend/dist/style.css +1 -0
  243. data/frontend/index.html +26 -0
  244. data/frontend/package-lock.json +2359 -0
  245. data/frontend/package.json +26 -0
  246. data/frontend/src/App.vue +59 -0
  247. data/frontend/src/app.ts +8 -0
  248. data/frontend/src/components/AppHeader.vue +127 -0
  249. data/frontend/src/components/AppSidebar.vue +119 -0
  250. data/frontend/src/components/ClassDetails.vue +247 -0
  251. data/frontend/src/components/DiagramView.vue +79 -0
  252. data/frontend/src/components/PackageDetails.vue +92 -0
  253. data/frontend/src/components/PackageTreeNode.vue +64 -0
  254. data/frontend/src/components/SearchResults.vue +48 -0
  255. data/frontend/src/components/WelcomeView.vue +87 -0
  256. data/frontend/src/shims-vue.d.ts +5 -0
  257. data/frontend/src/stores/dataStore.ts +79 -0
  258. data/frontend/src/stores/uiStore.ts +167 -0
  259. data/frontend/src/styles/main.css +1566 -0
  260. data/frontend/src/types.ts +221 -0
  261. data/frontend/tests/e2e/__screenshots__/new-dark-mode.png +0 -0
  262. data/frontend/tests/e2e/__screenshots__/new-package-details.png +0 -0
  263. data/frontend/tests/e2e/__screenshots__/new-search-modal.png +0 -0
  264. data/frontend/tests/e2e/__screenshots__/new-sidebar-collapsed.png +0 -0
  265. data/frontend/tests/e2e/__screenshots__/new-welcome.png +0 -0
  266. data/frontend/tests/e2e/render.spec.ts +188 -0
  267. data/frontend/tsconfig.json +20 -0
  268. data/frontend/vite.config.ts +26 -0
  269. data/frontend/vitest.config.ts +8 -0
  270. data/lib/ea/cli/app.rb +62 -1
  271. data/lib/ea/cli/command/diagrams.rb +37 -28
  272. data/lib/ea/cli/command/diff.rb +46 -0
  273. data/lib/ea/cli/command/export.rb +80 -0
  274. data/lib/ea/cli/command/info.rb +75 -0
  275. data/lib/ea/cli/command/lint.rb +48 -0
  276. data/lib/ea/cli/command/mdg.rb +98 -0
  277. data/lib/ea/cli/command/query.rb +34 -0
  278. data/lib/ea/cli/command/render.rb +135 -0
  279. data/lib/ea/cli/command/svg.rb +43 -6
  280. data/lib/ea/cli/command.rb +7 -0
  281. data/lib/ea/diagram/display_config.rb +184 -0
  282. data/lib/ea/diagram.rb +4 -41
  283. data/lib/ea/diff/change.rb +30 -0
  284. data/lib/ea/diff/comparator.rb +82 -0
  285. data/lib/ea/diff/html_reporter.rb +91 -0
  286. data/lib/ea/diff.rb +15 -0
  287. data/lib/ea/export/json/generator.rb +42 -0
  288. data/lib/ea/export/json.rb +12 -0
  289. data/lib/ea/export/json_schema/generator.rb +77 -0
  290. data/lib/ea/export/json_schema.rb +12 -0
  291. data/lib/ea/export/plantuml/generator.rb +73 -0
  292. data/lib/ea/export/plantuml.rb +12 -0
  293. data/lib/ea/export/xmi/generator.rb +77 -0
  294. data/lib/ea/export/xmi.rb +11 -0
  295. data/lib/ea/export/xsd/class_mapping.rb +65 -0
  296. data/lib/ea/export/xsd/generator.rb +142 -0
  297. data/lib/ea/export/xsd/namespace_registry.rb +82 -0
  298. data/lib/ea/export/xsd.rb +19 -0
  299. data/lib/ea/export.rb +14 -0
  300. data/lib/ea/image/emf_renderer.rb +42 -0
  301. data/lib/ea/image.rb +12 -0
  302. data/lib/ea/lint/engine.rb +30 -0
  303. data/lib/ea/lint/lint_rule.rb +38 -0
  304. data/lib/ea/lint/offense.rb +18 -0
  305. data/lib/ea/lint/rules/cyclic_generalization.rb +62 -0
  306. data/lib/ea/lint/rules/duplicate_name.rb +28 -0
  307. data/lib/ea/lint/rules/missing_stereotype.rb +35 -0
  308. data/lib/ea/lint/rules/naming_convention.rb +44 -0
  309. data/lib/ea/lint/rules/orphan_element.rb +28 -0
  310. data/lib/ea/lint/rules.rb +14 -0
  311. data/lib/ea/lint.rb +13 -0
  312. data/lib/ea/mdg/document.rb +120 -0
  313. data/lib/ea/mdg/loader.rb +118 -0
  314. data/lib/ea/mdg/registry.rb +98 -0
  315. data/lib/ea/mdg/stereotype_alias_registry.rb +77 -0
  316. data/lib/ea/mdg/xml/applies_to.rb +18 -0
  317. data/lib/ea/mdg/xml/apply.rb +18 -0
  318. data/lib/ea/mdg/xml/content.rb +18 -0
  319. data/lib/ea/mdg/xml/documentation.rb +24 -0
  320. data/lib/ea/mdg/xml/stereotype.rb +28 -0
  321. data/lib/ea/mdg/xml/stereotypes.rb +18 -0
  322. data/lib/ea/mdg/xml/tag.rb +28 -0
  323. data/lib/ea/mdg/xml/tagged_values.rb +18 -0
  324. data/lib/ea/mdg/xml/technology.rb +28 -0
  325. data/lib/ea/mdg/xml/uml_profile.rb +22 -0
  326. data/lib/ea/mdg/xml/uml_profiles.rb +18 -0
  327. data/lib/ea/mdg/xml.rb +24 -0
  328. data/lib/ea/mdg.rb +25 -0
  329. data/lib/ea/model/classifier.rb +4 -0
  330. data/lib/ea/model/constraint.rb +24 -0
  331. data/lib/ea/model/diagram.rb +85 -0
  332. data/lib/ea/model/diagram_connector.rb +53 -1
  333. data/lib/ea/model/diagram_element.rb +44 -0
  334. data/lib/ea/model/document.rb +47 -2
  335. data/lib/ea/model/ghost_label.rb +32 -0
  336. data/lib/ea/model/instance_specification.rb +34 -0
  337. data/lib/ea/model/legend.rb +43 -0
  338. data/lib/ea/model/legend_item.rb +26 -0
  339. data/lib/ea/model/note.rb +28 -0
  340. data/lib/ea/model/operation.rb +2 -0
  341. data/lib/ea/model/property.rb +2 -0
  342. data/lib/ea/model/relationship.rb +2 -0
  343. data/lib/ea/model/signal.rb +14 -0
  344. data/lib/ea/model/slot.rb +19 -0
  345. data/lib/ea/model.rb +8 -0
  346. data/lib/ea/ocl/evaluator.rb +94 -0
  347. data/lib/ea/ocl/nodes.rb +30 -0
  348. data/lib/ea/ocl/parser.rb +133 -0
  349. data/lib/ea/ocl/unsupported_error.rb +7 -0
  350. data/lib/ea/ocl.rb +13 -0
  351. data/lib/ea/qea/factory/document_builder.rb +24 -10
  352. data/lib/ea/qea/factory/generalization_builder.rb +9 -11
  353. data/lib/ea/qea/infrastructure/table_reader.rb +9 -0
  354. data/lib/ea/qea/models/ea_author.rb +35 -0
  355. data/lib/ea/qea/models/ea_glossary.rb +34 -0
  356. data/lib/ea/qea/models/ea_image.rb +53 -0
  357. data/lib/ea/qea/models/ea_implement.rb +32 -0
  358. data/lib/ea/qea/models/ea_list.rb +42 -0
  359. data/lib/ea/qea/models/ea_object_effort.rb +34 -0
  360. data/lib/ea/qea/models/ea_object_problem.rb +37 -0
  361. data/lib/ea/qea/models/ea_object_require.rb +34 -0
  362. data/lib/ea/qea/models/ea_object_resource.rb +34 -0
  363. data/lib/ea/qea/models/ea_object_risk.rb +34 -0
  364. data/lib/ea/qea/models/ea_object_scenario.rb +34 -0
  365. data/lib/ea/qea/models/ea_object_test.rb +35 -0
  366. data/lib/ea/qea/models/ea_object_trx.rb +34 -0
  367. data/lib/ea/qea/models/ea_operation.rb +7 -0
  368. data/lib/ea/qea/models/ea_palette.rb +30 -0
  369. data/lib/ea/qea/models/ea_palette_item.rb +36 -0
  370. data/lib/ea/qea/models/ea_phase.rb +40 -0
  371. data/lib/ea/qea/models/ea_role_constraint.rb +32 -0
  372. data/lib/ea/qea/models/ea_secrypt.rb +34 -0
  373. data/lib/ea/qea/models/ea_version.rb +39 -0
  374. data/lib/ea/qea/models/ea_xref.rb +11 -1
  375. data/lib/ea/qea/models.rb +19 -0
  376. data/lib/ea/qea/services/database_loader.rb +22 -1
  377. data/lib/ea/query/builder.rb +108 -0
  378. data/lib/ea/query.rb +9 -0
  379. data/lib/ea/render/image_converter.rb +101 -0
  380. data/lib/ea/render.rb +10 -0
  381. data/lib/ea/shapescript/parser.rb +208 -0
  382. data/lib/ea/shapescript/renderer.rb +74 -0
  383. data/lib/ea/shapescript/shape.rb +34 -0
  384. data/lib/ea/shapescript.rb +24 -0
  385. data/lib/ea/sources/qea/adapter.rb +22 -5
  386. data/lib/ea/sources/qea/classifier_builder.rb +184 -7
  387. data/lib/ea/sources/qea/diagram_builder.rb +352 -24
  388. data/lib/ea/sources/qea/id_normalizer.rb +16 -1
  389. data/lib/ea/sources/qea/instance_builder.rb +113 -0
  390. data/lib/ea/sources/qea/legend_builder.rb +137 -0
  391. data/lib/ea/sources/qea/note_builder.rb +58 -0
  392. data/lib/ea/sources/qea/object_classifier_map.rb +6 -1
  393. data/lib/ea/sources/qea/operation_builder.rb +1 -0
  394. data/lib/ea/sources/qea/package_builder.rb +16 -0
  395. data/lib/ea/sources/qea/relationship_builder.rb +21 -5
  396. data/lib/ea/sources/qea/tagged_value_builder.rb +28 -9
  397. data/lib/ea/sources/qea/xref/legend_definition.rb +35 -0
  398. data/lib/ea/sources/qea/xref/parser.rb +150 -0
  399. data/lib/ea/sources/qea/xref/property_definition.rb +29 -0
  400. data/lib/ea/sources/qea/xref/record.rb +41 -0
  401. data/lib/ea/sources/qea/xref/stereotype_application.rb +37 -0
  402. data/lib/ea/sources/qea/xref.rb +27 -0
  403. data/lib/ea/sources/qea.rb +4 -0
  404. data/lib/ea/sources/xmi/adapter.rb +80 -2
  405. data/lib/ea/sources/xmi/annotation_builder.rb +1 -1
  406. data/lib/ea/sources/xmi/classifier_builder.rb +10 -1
  407. data/lib/ea/sources/xmi/diagram_builder.rb +242 -45
  408. data/lib/ea/sources/xmi/extension_elements.rb +74 -0
  409. data/lib/ea/sources/xmi/extension_geometry_parser.rb +124 -0
  410. data/lib/ea/sources/xmi/extension_style_parser.rb +91 -0
  411. data/lib/ea/sources/xmi/note_builder.rb +46 -0
  412. data/lib/ea/sources/xmi/property_builder.rb +9 -0
  413. data/lib/ea/sources/xmi/stereotype_builder.rb +54 -0
  414. data/lib/ea/sources/xmi/tag_builder.rb +45 -0
  415. data/lib/ea/sources/xmi/umldi_keyword_extractor.rb +87 -0
  416. data/lib/ea/sources/xmi.rb +7 -0
  417. data/lib/ea/spa/output/sharded_multi_file_strategy.rb +18 -3
  418. data/lib/ea/spa/output/single_file_strategy.rb +8 -2
  419. data/lib/ea/spa/output/strategy.rb +34 -0
  420. data/lib/ea/svg/connector_router.rb +134 -0
  421. data/lib/ea/svg/ea_emitter/background.rb +15 -0
  422. data/lib/ea/svg/ea_emitter/bounds_calculator.rb +142 -0
  423. data/lib/ea/svg/ea_emitter/canvas.rb +88 -0
  424. data/lib/ea/svg/ea_emitter/color_resolver.rb +56 -0
  425. data/lib/ea/svg/ea_emitter/compartment/attributes.rb +28 -0
  426. data/lib/ea/svg/ea_emitter/compartment/constraints.rb +30 -0
  427. data/lib/ea/svg/ea_emitter/compartment/enum_literals.rb +86 -0
  428. data/lib/ea/svg/ea_emitter/compartment/header.rb +32 -0
  429. data/lib/ea/svg/ea_emitter/compartment/header_divider.rb +57 -0
  430. data/lib/ea/svg/ea_emitter/compartment/instance_slots.rb +96 -0
  431. data/lib/ea/svg/ea_emitter/compartment/instance_underline.rb +67 -0
  432. data/lib/ea/svg/ea_emitter/compartment/note_body.rb +52 -0
  433. data/lib/ea/svg/ea_emitter/compartment/note_text.rb +102 -0
  434. data/lib/ea/svg/ea_emitter/compartment/operations.rb +38 -0
  435. data/lib/ea/svg/ea_emitter/compartment/package_contents.rb +72 -0
  436. data/lib/ea/svg/ea_emitter/compartment/package_from_parent.rb +136 -0
  437. data/lib/ea/svg/ea_emitter/compartment/shape.rb +82 -0
  438. data/lib/ea/svg/ea_emitter/compartment/tagged_values.rb +30 -0
  439. data/lib/ea/svg/ea_emitter/compartment.rb +58 -0
  440. data/lib/ea/svg/ea_emitter/connectors.rb +84 -0
  441. data/lib/ea/svg/ea_emitter/diagram_frame.rb +143 -0
  442. data/lib/ea/svg/ea_emitter/document.rb +35 -0
  443. data/lib/ea/svg/ea_emitter/element/attribute_line_builder.rb +117 -0
  444. data/lib/ea/svg/ea_emitter/element/attribute_renderer.rb +119 -0
  445. data/lib/ea/svg/ea_emitter/element/bcol_decoder.rb +29 -0
  446. data/lib/ea/svg/ea_emitter/element/compartment_geometry.rb +113 -0
  447. data/lib/ea/svg/ea_emitter/element/constraint_renderer.rb +53 -0
  448. data/lib/ea/svg/ea_emitter/element/divider_renderer.rb +17 -0
  449. data/lib/ea/svg/ea_emitter/element/enumeration_literal_renderer.rb +34 -0
  450. data/lib/ea/svg/ea_emitter/element/filter.rb +44 -0
  451. data/lib/ea/svg/ea_emitter/element/hand_draw_shape_renderer.rb +77 -0
  452. data/lib/ea/svg/ea_emitter/element/header_line_pipeline.rb +43 -0
  453. data/lib/ea/svg/ea_emitter/element/header_line_provider/instance_spec.rb +27 -0
  454. data/lib/ea/svg/ea_emitter/element/header_line_provider/name.rb +76 -0
  455. data/lib/ea/svg/ea_emitter/element/header_line_provider/parent_ghost.rb +25 -0
  456. data/lib/ea/svg/ea_emitter/element/header_line_provider/stereotype_label.rb +68 -0
  457. data/lib/ea/svg/ea_emitter/element/header_line_provider.rb +19 -0
  458. data/lib/ea/svg/ea_emitter/element/header_lines.rb +27 -0
  459. data/lib/ea/svg/ea_emitter/element/header_renderer.rb +48 -0
  460. data/lib/ea/svg/ea_emitter/element/icon_renderer.rb +109 -0
  461. data/lib/ea/svg/ea_emitter/element/legend_renderer.rb +177 -0
  462. data/lib/ea/svg/ea_emitter/element/note_shape_renderer.rb +112 -0
  463. data/lib/ea/svg/ea_emitter/element/operation_renderer.rb +100 -0
  464. data/lib/ea/svg/ea_emitter/element/package_shape_renderer.rb +181 -0
  465. data/lib/ea/svg/ea_emitter/element/row_icon_renderer.rb +156 -0
  466. data/lib/ea/svg/ea_emitter/element/shape_renderer.rb +17 -0
  467. data/lib/ea/svg/ea_emitter/element/stereotype_icon_renderer.rb +82 -0
  468. data/lib/ea/svg/ea_emitter/element/tagged_value_renderer.rb +50 -0
  469. data/lib/ea/svg/ea_emitter/element/text_escape.rb +20 -0
  470. data/lib/ea/svg/ea_emitter/element.rb +37 -0
  471. data/lib/ea/svg/ea_emitter/elements.rb +357 -0
  472. data/lib/ea/svg/ea_emitter/font_resolver.rb +111 -0
  473. data/lib/ea/svg/ea_emitter/ghost_labels.rb +66 -0
  474. data/lib/ea/svg/ea_emitter/label/end_label.rb +266 -0
  475. data/lib/ea/svg/ea_emitter/label/midpoint_label.rb +101 -0
  476. data/lib/ea/svg/ea_emitter/label/registry.rb +50 -0
  477. data/lib/ea/svg/ea_emitter/label.rb +23 -0
  478. data/lib/ea/svg/ea_emitter/labels.rb +130 -0
  479. data/lib/ea/svg/ea_emitter/layer.rb +20 -0
  480. data/lib/ea/svg/ea_emitter/layer_sequencer.rb +93 -0
  481. data/lib/ea/svg/ea_emitter/marker/arrow_path.rb +52 -0
  482. data/lib/ea/svg/ea_emitter/marker/diamond.rb +57 -0
  483. data/lib/ea/svg/ea_emitter/marker/kind.rb +35 -0
  484. data/lib/ea/svg/ea_emitter/marker/open_triangle.rb +27 -0
  485. data/lib/ea/svg/ea_emitter/marker/package_import.rb +39 -0
  486. data/lib/ea/svg/ea_emitter/marker/plus.rb +40 -0
  487. data/lib/ea/svg/ea_emitter/marker/registry.rb +42 -0
  488. data/lib/ea/svg/ea_emitter/marker.rb +37 -0
  489. data/lib/ea/svg/ea_emitter/markers.rb +404 -0
  490. data/lib/ea/svg/ea_emitter/render_context.rb +52 -0
  491. data/lib/ea/svg/ea_emitter/style.rb +15 -0
  492. data/lib/ea/svg/ea_emitter/text_renderer.rb +92 -0
  493. data/lib/ea/svg/ea_emitter.rb +51 -0
  494. data/lib/ea/svg/parity/checker.rb +105 -0
  495. data/lib/ea/svg/parity/source.rb +59 -0
  496. data/lib/ea/svg/parity/suite.rb +113 -0
  497. data/lib/ea/svg/parity.rb +14 -0
  498. data/lib/ea/svg/stereotype_color_resolver.rb +50 -0
  499. data/lib/ea/svg.rb +4 -15
  500. data/lib/ea/theme/definition.rb +176 -0
  501. data/lib/ea/theme/loader.rb +125 -0
  502. data/lib/ea/theme/registry.rb +96 -0
  503. data/lib/ea/theme.rb +37 -0
  504. data/lib/ea/transformations.rb +5 -88
  505. data/lib/ea/version.rb +4 -1
  506. data/lib/ea.rb +14 -4
  507. data/lib/tasks/svg_bench.rake +87 -0
  508. data/lutaml-uml-0.5.1.gem +0 -0
  509. data/reference-docs/enterprise-architect-appearance-dialogs/appearance-1-diagram-1-themes-list.png +0 -0
  510. data/reference-docs/enterprise-architect-appearance-dialogs/appearance-1-diagram-1-themes.png +0 -0
  511. data/reference-docs/enterprise-architect-appearance-dialogs/appearance-1-diagram-2-gradients.png +0 -0
  512. data/reference-docs/enterprise-architect-appearance-dialogs/appearance-1-diagram-3-colors.png +0 -0
  513. data/reference-docs/enterprise-architect-appearance-dialogs/appearance-1-diagram-4-appearance-fonts.png +0 -0
  514. data/reference-docs/enterprise-architect-appearance-dialogs/appearance-1-diagram-4-appearance.png +0 -0
  515. data/reference-docs/enterprise-architect-appearance-dialogs/appearance-1-diagram-5-behavior.png +0 -0
  516. data/reference-docs/enterprise-architect-appearance-dialogs/appearance-1-diagram-6-sequence.png +0 -0
  517. data/reference-docs/enterprise-architect-appearance-dialogs/appearance-1-diagram.png +0 -0
  518. data/reference-docs/enterprise-architect-appearance-dialogs/appearance-2-objects.png +0 -0
  519. data/reference-docs/enterprise-architect-appearance-dialogs/appearance-3-links.png +0 -0
  520. metadata +473 -26
  521. data/lib/ea/diagram/configuration.rb +0 -379
  522. data/lib/ea/diagram/element_renderers/base_renderer.rb +0 -77
  523. data/lib/ea/diagram/element_renderers/class_renderer.rb +0 -323
  524. data/lib/ea/diagram/element_renderers/connector_renderer.rb +0 -41
  525. data/lib/ea/diagram/element_renderers/package_renderer.rb +0 -61
  526. data/lib/ea/diagram/element_renderers.rb +0 -43
  527. data/lib/ea/diagram/extractor.rb +0 -566
  528. data/lib/ea/diagram/layout_engine.rb +0 -170
  529. data/lib/ea/diagram/path_builder.rb +0 -202
  530. data/lib/ea/diagram/style_parser.rb +0 -42
  531. data/lib/ea/diagram/style_resolver.rb +0 -291
  532. data/lib/ea/diagram/svg_renderer.rb +0 -274
  533. data/lib/ea/diagram/util.rb +0 -73
  534. data/lib/ea/svg/bounds_calculator.rb +0 -74
  535. data/lib/ea/svg/connector_path.rb +0 -138
  536. data/lib/ea/svg/element_box.rb +0 -256
  537. data/lib/ea/svg/renderer.rb +0 -77
  538. data/lib/ea/svg/style_resolver.rb +0 -72
  539. data/lib/ea/transformations/configuration.rb +0 -333
  540. data/lib/ea/transformations/format_registry.rb +0 -366
  541. data/lib/ea/transformations/parsers/base_parser.rb +0 -482
  542. data/lib/ea/transformations/parsers/qea_parser.rb +0 -401
  543. data/lib/ea/transformations/parsers/xmi_parser.rb +0 -243
  544. data/lib/ea/transformations/transformation_engine.rb +0 -390
@@ -0,0 +1,67 @@
1
+ # 01 - Parse XMI Extension Elements Block
2
+
3
+ ## Status: DONE (2026-07-21)
4
+
5
+ ## Problem
6
+
7
+ EA's XMI stores diagram placement data inside an `<xmi:Extension>`
8
+ block, under `<elements>/<element>` rows. Each row carries:
9
+
10
+ - `geometry="Left=X;Top=Y;Right=X2;Bottom=Y2;imgL=..;imgT=..;imgR=..;imgB=..;"`
11
+ (pixel bounds + image bounds with 25 px padding)
12
+ - `subject="EAID_..."` (the model element this placement refers to)
13
+ - `seqno="N"` (z-order)
14
+ - `style="BCol=<int>;font=<name>;fontsz=<int>;bold=0;italic=0;LWth=<int>;.."`
15
+ (EA packed style)
16
+
17
+ For connectors, the same row shape carries:
18
+ - `geometry="SX=..;SY=..;EX=..;EY=..;EDGE=N;$LLB=..;$LLT=..;LRT=..;LRB=..;Path=;"`
19
+ - `style="Mode=3;SOID=<source DUID>;EOID=<target DUID>;Color=-1;LWidth=2;"`
20
+
21
+ Our `Ea::Sources::Xmi::DiagramBuilder` currently reads only the
22
+ UML-DI `<owned_element>/<bounds>` tree, which doesn't include any
23
+ of this rich placement/style data. Result: SVG rendering from XMI
24
+ sources is missing colors, fonts, bend routing, label positions,
25
+ and proper element placement.
26
+
27
+ ## Approach
28
+
29
+ Extend the XMI source adapter to walk the `<xmi:Extension>`
30
+ block's `<elements>` rows for each diagram. Build a parallel
31
+ `Ea::Model::DiagramElement` per row, populating:
32
+
33
+ - `bounds` from `Left/Top/Right/Bottom`
34
+ - `model_element_ref` from `subject` (resolved to model id)
35
+ - `style` hash including `BCol`, `font`, `fontsz`, `bold`, `italic`,
36
+ `LWth`, `LCol` (line color)
37
+ - A new `image_bounds` field carrying the `imgL/imgT/imgR/imgB`
38
+ padded bounds (EA's visual box, vs. the logical bounds)
39
+
40
+ For connector rows, build `Ea::Model::DiagramConnector` with:
41
+ - `relationship_ref` from `subject`
42
+ - Source/target resolved via `SOID`/`EOID` → DUID → placed element
43
+ - Waypoints computed from the SX/SY/EX/EY deltas + the source and
44
+ target element edge centers (matching EA's rendering math)
45
+ - Style hash with `Color`, `LWidth`, `Mode`
46
+
47
+ ## Files
48
+
49
+ - `lib/ea/sources/xmi/extension_elements.rb` (new — walks the
50
+ extension block, returns typed rows)
51
+ - `lib/ea/sources/xmi/extension_geometry_parser.rb` (new — parses
52
+ `geometry="..."` packed string into a typed struct)
53
+ - `lib/ea/sources/xmi/extension_style_parser.rb` (new — parses
54
+ `style="..."` packed string into a typed struct)
55
+ - `lib/ea/sources/xmi/diagram_builder.rb` (updated — uses
56
+ extension data when present, falls back to umldi otherwise)
57
+ - `lib/ea/model/diagram_element.rb` (extended — add
58
+ `image_bounds` field)
59
+ - `spec/ea/sources/xmi/extension_*_spec.rb`
60
+
61
+ ## Verification
62
+
63
+ - Unit specs: parse a known geometry/style string, assert typed
64
+ struct matches.
65
+ - Integration: load `plateau_all_packages_export.xmi`, find diagram
66
+ `EAID_0016F797_...`, assert every placed element has bounds +
67
+ style populated.
@@ -0,0 +1,61 @@
1
+ # 02 - Rich DiagramElement / DiagramConnector Model
2
+
3
+ ## Status: DONE (2026-07-21, folded into TODO 03)
4
+
5
+ ## Problem
6
+
7
+ The current `Ea::Model::DiagramElement` carries only `bounds` and
8
+ an untyped `style` hash. EA's renderer needs:
9
+
10
+ - `image_bounds` (the imgL/imgT/imgR/imgB padded rect — distinct
11
+ from the logical Left/Top/Right/Bottom rect)
12
+ - `background_color` (decoded from `BCol` BGR integer → RGB hex)
13
+ - `font_family`, `font_size`, `font_bold`, `font_italic`
14
+ - `line_color`, `line_width`
15
+ - `z_order` (seqno)
16
+ - `label_inset` (the offset from the bounds origin where text
17
+ should start; EA convention is x+5, y+17 for the first line)
18
+
19
+ For `DiagramConnector`:
20
+ - `source_anchor`, `target_anchor` (which edge of the source/target
21
+ element the line attaches to — top/right/bottom/left)
22
+ - `source_duid`, `target_duid` (so the renderer can resolve back to
23
+ placed elements without re-walking the model)
24
+ - `label_boxes` (the four LRT/LRB/LLT/LLB label rectangles with
25
+ their text content decoded)
26
+
27
+ ## Approach
28
+
29
+ Extend the existing types (don't replace — backward compat for the
30
+ QEA adapter which doesn't populate these yet):
31
+
32
+ - `DiagramElement`: add `image_bounds`, `background_color`,
33
+ `font_family`, `font_size`, `font_bold`, `font_italic`,
34
+ `line_color`, `line_width`, `z_order`
35
+ - `DiagramConnector`: add `source_anchor`, `target_anchor`,
36
+ `source_duid`, `target_duid`, `label_boxes` (collection)
37
+
38
+ The QEA adapter populates these from its `objectstyle` packed
39
+ string (existing `DiagramStyleParser`); the XMI adapter populates
40
+ them from the `<xmi:Extension>/<elements>` style attribute.
41
+
42
+ The renderer reads the typed fields directly — no more parsing at
43
+ render time.
44
+
45
+ ## Files
46
+
47
+ - `lib/ea/model/diagram_element.rb`
48
+ - `lib/ea/model/diagram_connector.rb`
49
+ - `lib/ea/model/label_box.rb` (new)
50
+ - `lib/ea/sources/qea/diagram_builder.rb` (populate the new fields)
51
+ - `lib/ea/sources/qea/diagram_style_parser.rb` (extend to typed
52
+ accessors, not just a hash)
53
+ - `spec/ea/model/diagram_element_spec.rb`
54
+ - `spec/ea/model/diagram_connector_spec.rb`
55
+
56
+ ## Verification
57
+
58
+ - Round-trip: model JSON includes all new fields; deserialize
59
+ preserves them.
60
+ - QEA adapter spec: every placed element has a non-nil
61
+ `background_color`.
@@ -0,0 +1,29 @@
1
+ # TODO-D 02 - Polygon over-rendering
2
+
3
+ ## Status: COMPLETE (2026-07-26)
4
+
5
+ ## Root cause
6
+
7
+ Two bugs caused polygon over-rendering:
8
+
9
+ 1. **Markers emitted one polygon per connector, even when multiple
10
+ connectors ended at the same anchor** (e.g., 9 inheritance arrows
11
+ converging on a single base class produced 9 identical triangle
12
+ polygons).
13
+
14
+ 2. **Floating-point waypoint precision caused "identical" markers
15
+ to differ in their point strings** (e.g., `683.37 2041.37` vs
16
+ `683.39 2043.35`), defeating naive `body.uniq` deduplication.
17
+
18
+ ## Fix
19
+
20
+ `Markers#layers` now deduplicates by **rounded anchor point** —
21
+ the first coordinate pair of each polygon/path, rounded to integer.
22
+ Two markers anchored at the same integer pixel are treated as
23
+ duplicates regardless of their other point values.
24
+
25
+ ## Impact (full plateau measurement)
26
+
27
+ | Metric | Before | After |
28
+ |---|---|---|
29
+ | Polygon delta vs ref | +442 (46% over) | -10 (parity) |
@@ -0,0 +1,70 @@
1
+ # 03 - EA-Style SVG Emitter
2
+
3
+ ## Status: DONE (2026-07-21) (depends on 02)
4
+
5
+ ## Problem
6
+
7
+ The current `Ea::Svg::Renderer` emits minimal SVG: header,
8
+ background rect, then per-element `<g class="element">` groups
9
+ with the box + label inside. EA's SVG output is structurally
10
+ different:
11
+
12
+ 1. DOCTYPE declaration (SVG 1.0)
13
+ 2. Root `<svg>` with `width="Xcm" height="Ycm"` and
14
+ `viewBox="0 0 W H"`
15
+ 3. `<title></title>` (empty)
16
+ 4. `<desc>Created with Enterprise Architect (Build: 1628) 2</desc>`
17
+ 5. Background `<g style="fill:#FFFFFF;..."><rect .../></g>`
18
+ 6. For each element, TWO `<g>` blocks:
19
+ a. Shape `<g>` with `style="...fill:COLOR;..."` containing the
20
+ `<rect>`
21
+ b. Text `<g>` with `style="fill:#000000;..."` containing all
22
+ `<text>` labels for that element
23
+ 7. Divider line as `<g><path d="M x y L x2 y2"/></g>`
24
+ 8. Connector paths as separate `<g>` blocks per path segment
25
+ 9. Arrow markers as `<g><polygon .../></g>`
26
+ 10. Connector labels as a final `<g>` block of `<text>`
27
+
28
+ The output is layered by visual category, not by element. Our
29
+ current emitter layers by element, mixing shapes and text in one
30
+ `<g>`.
31
+
32
+ ## Approach
33
+
34
+ Rewrite the emitter to follow EA's layering. Each render phase
35
+ emits one or more `<g>` blocks in the canonical order:
36
+
37
+ 1. `Ea::Svg::EaEmitter::Background`
38
+ 2. `Ea::Svg::EaEmitter::Elements` (one shape `<g>` + one text `<g>`
39
+ per element, in z-order)
40
+ 3. `Ea::Svg::EaEmitter::Dividers` (one `<g>` per divider line)
41
+ 4. `Ea::Svg::EaEmitter::Connectors` (one `<g>` per path)
42
+ 5. `Ea::Svg::EaEmitter::Markers` (filled / open polygons)
43
+ 6. `Ea::Svg::EaEmitter::Labels` (all text labels last)
44
+
45
+ Each emitter is a single-responsibility class. The orchestrator
46
+ calls them in order.
47
+
48
+ The existing `Ea::Svg::Renderer` stays as a thinner alternative
49
+ (useful for diagrams without full style data, e.g. from QEA
50
+ sources with sparse style). The new `EaEmitter` is the default
51
+ when full EA-style data is available.
52
+
53
+ ## Files
54
+
55
+ - `lib/ea/svg/ea_emitter.rb` (orchestrator)
56
+ - `lib/ea/svg/ea_emitter/background.rb`
57
+ - `lib/ea/svg/ea_emitter/elements.rb`
58
+ - `lib/ea/svg/ea_emitter/dividers.rb`
59
+ - `lib/ea/svg/ea_emitter/connectors.rb`
60
+ - `lib/ea/svg/ea_emitter/markers.rb`
61
+ - `lib/ea/svg/ea_emitter/labels.rb`
62
+ - `lib/ea/svg/ea_emitter/canvas.rb` (computes cm dimensions + viewBox)
63
+ - `spec/ea/svg/ea_emitter/*_spec.rb`
64
+
65
+ ## Verification
66
+
67
+ - Byte-level structural diff against EA's reference SVG for one
68
+ diagram. We don't require pixel-perfect match (font rendering
69
+ differences), but the element layering, group structure, and
70
+ attribute presence should match.
@@ -0,0 +1,30 @@
1
+ # TODO-D 03 - Text over-rendering
2
+
3
+ ## Status: COMPLETE (2026-07-26)
4
+
5
+ ## Root cause
6
+
7
+ The tagged values compartment was rendered unconditionally for
8
+ every classifier that had tagged values, regardless of the
9
+ diagram's actual display configuration. The reference SVGs only
10
+ show tagged values when the per-element style has `Tag=1`.
11
+
12
+ The previous fix (TODO 70) added the TaggedValueRenderer but did
13
+ not gate it on the element-level Tag flag.
14
+
15
+ ## Fix
16
+
17
+ `Elements#groups_for` now reads `element.show_tagged_values`
18
+ (parsed from the per-element style `Tag=0/1` field) and only
19
+ renders the tagged value compartment when the flag is set.
20
+
21
+ The `DiagramElement` model gained `show_tagged_values` boolean.
22
+ `ExtensionStyleParser` populates it from the `Tag=` style key.
23
+ `DiagramBuilder` passes it through to the model.
24
+
25
+ ## Impact (full plateau measurement)
26
+
27
+ | Metric | Before | After |
28
+ |---|---|---|
29
+ | Text delta vs ref | +5134 (29% over) | -252 (parity) |
30
+ | Text overlap avg | 57% | 62% |
@@ -0,0 +1,55 @@
1
+ # 04 - Connector Routing via SOID/EOID Resolution
2
+
3
+ ## Status: DONE (2026-07-21, folded into TODO 03)
4
+
5
+ ## Problem
6
+
7
+ EA connector geometry stores only bend deltas (SX/SY/EX/EY) and
8
+ the EDGE code (which side of the element the line attaches to).
9
+ The actual line endpoints are computed by EA's renderer at draw
10
+ time, by looking up the source and target element placements via
11
+ their DUIDs (style `SOID` and `EOID`).
12
+
13
+ Our current QEA adapter computes waypoints from the connector's
14
+ Start_Object_ID/End_Object_ID via the model. That works but
15
+ ignores the EDGE hint, producing lines that always start at the
16
+ element center instead of the correct edge.
17
+
18
+ ## Approach
19
+
20
+ In both the QEA and XMI source adapters, when building a
21
+ DiagramConnector:
22
+
23
+ 1. Resolve source and target placements via SOID/EOID (XMI) or
24
+ Start_Object_ID/End_Object_ID (QEA).
25
+ 2. Read the `EDGE` field (1=top, 2=right, 3=bottom, 4=left,
26
+ 5..8 = diagonal variants).
27
+ 3. Compute the source connection point as the center of the
28
+ chosen edge on the source element.
29
+ 4. Apply the SX/SY delta to get the first bend.
30
+ 5. Apply the EX/EY delta from the target edge center to get the
31
+ second bend.
32
+ 6. Compute the target connection point as the center of the
33
+ chosen edge on the target element.
34
+
35
+ Emit exactly 2-4 waypoints: source edge → first bend → second
36
+ bend → target edge. This matches EA's typical "L" or "Z" routing.
37
+
38
+ For connectors without EDGE or SOID/EOID, fall back to straight
39
+ line between element centers.
40
+
41
+ ## Files
42
+
43
+ - `lib/ea/sources/qea/diagram_builder.rb`
44
+ - `lib/ea/sources/xmi/diagram_builder.rb`
45
+ - `lib/ea/svg/edge_anchor.rb` (computes edge center given bounds +
46
+ EDGE code)
47
+ - `spec/ea/svg/edge_anchor_spec.rb`
48
+
49
+ ## Verification
50
+
51
+ - Spec: source element with EDGE=1 produces a source point at the
52
+ top edge center.
53
+ - Spec: connector with both bends produces 4 waypoints.
54
+ - Visual: connector lines visually attach to element edges, not
55
+ centers.
@@ -0,0 +1,33 @@
1
+ # TODO-D 04 - Rect under-rendering
2
+
3
+ ## Status: WONTFIX (data drift) (2026-07-26)
4
+
5
+ ## Investigation
6
+
7
+ Across 185 plateau diagrams, we under-render 221 rects (11%). The
8
+ worst case (bldg_1) shows 18 rects in reference vs 11 in ours —
9
+ 7 missing rects.
10
+
11
+ Examining bldg_1's reference SVG reveals classifiers placed on the
12
+ diagram (e.g., `uro::ReservoirFloodingRiskAttribute`) that are NOT
13
+ in the XMI's `<diagram>/<elements>` block. The classifier exists
14
+ in the uml:Model hierarchy, but no `<element subject="..."/>` ref
15
+ places it on this diagram.
16
+
17
+ ## Conclusion
18
+
19
+ The reference SVGs were generated from a MORE COMPLETE XMI than
20
+ the one we have. The XMI/SVG pair has drift — the SVG has
21
+ placements the XMI doesn't carry.
22
+
23
+ This is a fixture data issue, not an emitter bug. We cannot render
24
+ elements the XMI doesn't place. Closing this gap requires either:
25
+
26
+ 1. Regenerating the plateau XMI from the same QEA source that
27
+ produced the reference SVGs.
28
+ 2. Implementing a "implicit placement" mode that auto-places
29
+ classifiers referenced by connectors but not in `<elements>`.
30
+ This would be guesswork — we don't know where EA placed them.
31
+
32
+ Option 1 is the right path. Marking this wontfix pending fixture
33
+ regeneration.
@@ -0,0 +1,51 @@
1
+ # TODO-D 05 - Canvas dimension parity
2
+
3
+ ## Status: PARTIAL (2026-07-26)
4
+
5
+ ## Current state
6
+
7
+ | | Avg delta | Range |
8
+ |---|---|---|
9
+ | Width | +87px | -403 to +1482 |
10
+ | Height | +576px | -109 to +4833 |
11
+
12
+ For diagrams where XMI matches reference content (small delta),
13
+ the canvas is consistently ~20-25 px wider and ~7-15 px taller
14
+ than reference. That delta is the frame margin.
15
+
16
+ ## Frame margin rule
17
+
18
+ Reference SVGs use non-uniform frame margins around element
19
+ bounds:
20
+
21
+ - Left: 35 px (body left to canvas left)
22
+ - Right: 50 px (body right to canvas right)
23
+ - Top: 60 px (body top to canvas top)
24
+ - Bottom: 36 px (body bottom to canvas bottom)
25
+
26
+ These come from EA's frame outer border (6 px from canvas edge)
27
+ plus an additional 29/44/54/30 px inset for the body. The asymmetry
28
+ exists because:
29
+
30
+ - Top: extra space for the frame tab label (extends from y=6 to
31
+ y=26 plus padding to body_top=60).
32
+ - Right/bottom: extra space for shadow / image padding.
33
+
34
+ ## Fix attempted
35
+
36
+ `BoundsCalculator#compute` already reserves 20 px above each
37
+ Package element for the tab polygon. Adding frame-aware padding
38
+ to all four sides would close the per-diagram gap on small
39
+ diagrams.
40
+
41
+ ## Why deferred
42
+
43
+ The 576 px average height delta dwarfs the frame margin issue.
44
+ Most of the height over-rendering is from XMI/SVG drift (we render
45
+ elements the reference SVG doesn't show). Until that's resolved
46
+ (fixture regeneration — see TODO-D 04), fixing the frame margin
47
+ won't move the aggregate metric meaningfully.
48
+
49
+ The small-diagram match (those closest to reference) shows the
50
+ frame margin fix would close ~5-10 px of the remaining 20-25 px
51
+ delta. Not enough to justify the added complexity right now.
@@ -0,0 +1,49 @@
1
+ # 05 - Marker Rendering Per Relationship Type
2
+
3
+ ## Status: DONE (2026-07-21, folded into TODO 03)
4
+
5
+ ## Problem
6
+
7
+ EA renders different arrow markers based on the connector's
8
+ semantic type:
9
+
10
+ - **Association** (navigable): filled triangle at target
11
+ - **Generalization**: open triangle at target (white fill, black
12
+ stroke)
13
+ - **Realization**: open triangle at target + dashed line
14
+ - **Dependency**: open arrow at target + dashed line
15
+ - **Aggregation** (source): open diamond at source
16
+ - **Composition** (source): filled diamond at source
17
+
18
+ Our current renderer emits a filled triangle at target regardless
19
+ of relationship type, plus a diamond for aggregations. The
20
+ distinction between open and filled markers matters visually.
21
+
22
+ ## Approach
23
+
24
+ Add a `MarkerResolver` that maps a relationship type + end
25
+ (source/target) to a marker shape:
26
+
27
+ - `:filled_triangle`, `:open_triangle`, `:filled_diamond`,
28
+ `:open_diamond`, `:open_arrow`, `:none`
29
+
30
+ Each shape is rendered as a 4-point `<polygon>` with the
31
+ appropriate fill color.
32
+
33
+ The marker anchor is the END of the polyline (target) or the
34
+ START (source). The marker is rotated to align with the line's
35
+ direction at that end.
36
+
37
+ ## Files
38
+
39
+ - `lib/ea/svg/marker_resolver.rb`
40
+ - `lib/ea/svg/marker_shapes.rb` (one class per shape)
41
+ - Update `lib/ea/svg/ea_emitter/markers.rb`
42
+ - `spec/ea/svg/marker_resolver_spec.rb`
43
+
44
+ ## Verification
45
+
46
+ - Spec: Association → filled triangle at target.
47
+ - Spec: Generalization → open triangle at target.
48
+ - Spec: Composition → filled diamond at source + filled triangle
49
+ at target.
@@ -0,0 +1,49 @@
1
+ # 06 - Connector Labels (Role Names + Multiplicities)
2
+
3
+ ## Status: DONE (2026-07-21, folded into TODO 03)
4
+
5
+ ## Problem
6
+
7
+ EA renders labels on connectors at four canonical positions:
8
+
9
+ - `LLB` (lower-left, near source) — source role name
10
+ - `LLT` (upper-left, near source) — source multiplicity
11
+ - `LRB` (lower-right, near target) — target role name
12
+ - `LRT` (upper-right, near target) — target multiplicity
13
+
14
+ Each label has CX/CY (size), OX/OY (offset from the connector
15
+ endpoint), plus font/style flags.
16
+
17
+ Our current renderer emits no connector labels at all. The
18
+ information is in the XMI geometry string but never extracted.
19
+
20
+ ## Approach
21
+
22
+ Extend the XMI adapter's geometry parser to also extract the four
23
+ label boxes, each as an `Ea::Model::LabelBox` with:
24
+
25
+ - `role` (:source_name, :source_multiplicity, :target_name,
26
+ :target_multiplicity)
27
+ - `text` (decoded from the model's relationship ends)
28
+ - `offset_x`, `offset_y` (from OX/OY)
29
+ - `width`, `height` (from CX/CY)
30
+
31
+ The emitter renders each label as `<text>` at the appropriate
32
+ offset from the connector endpoint.
33
+
34
+ For QEA sources, the same data is in the connector's `SourceRole`
35
+ and `DestRole` notes + cardinality fields.
36
+
37
+ ## Files
38
+
39
+ - `lib/ea/model/label_box.rb`
40
+ - `lib/ea/sources/xmi/extension_geometry_parser.rb` (extend)
41
+ - `lib/ea/svg/ea_emitter/labels.rb` (extend)
42
+ - `spec/ea/sources/xmi/extension_geometry_parser_spec.rb`
43
+ - `spec/ea/svg/ea_emitter/labels_spec.rb`
44
+
45
+ ## Verification
46
+
47
+ - Spec: known geometry string yields 4 label boxes with correct
48
+ offsets.
49
+ - Visual: connector labels appear at the same positions as EA.
@@ -0,0 +1,39 @@
1
+ # TODO-D 06 - Group layering parity
2
+
3
+ ## Status: PARTIAL (2026-07-26)
4
+
5
+ ## Current state
6
+
7
+ EA emits each `<rect>`, `<polygon>`, `<path>`, `<text>` inside its
8
+ own `<g>` block with a specific `style` attribute. Style strings
9
+ differ by:
10
+
11
+ - stroke_width (1 vs 2)
12
+ - stroke_linecap (round vs square)
13
+ - stroke_linejoin (bevel vs miter)
14
+ - fill color
15
+ - stroke color
16
+ - opacity
17
+
18
+ Our emitter groups output by `style_key` (a Symbol like
19
+ `:diamond_filled` or `:triangle_open`), with the style string
20
+ looked up from a small dispatch table. This matches EA's grouping
21
+ semantics for most cases.
22
+
23
+ ## Note element body
24
+
25
+ The Note element body was previously emitted as a `<polygon>`. EA
26
+ emits it as a closed `<path d="M...L...Z"/>` with
27
+ `stroke-linejoin=bevel` and `stroke-linecap=square`. Fixed in
28
+ commit f4fa55f.
29
+
30
+ ## Remaining gap
31
+
32
+ EA sometimes uses different `stroke-linecap` for the same shape
33
+ type depending on whether it's a "decorative" element (square cap)
34
+ or a "connector" element (round cap). Our style dispatch table
35
+ doesn't distinguish these. Visible in:
36
+
37
+ - Note bodies (square) vs classifier rects (round) — fixed
38
+ - Connector lines (round) vs divider lines (round) — both round
39
+ - Visibility icon rects inside attribute compartments — TBD
@@ -0,0 +1,39 @@
1
+ # 07 - Canvas Size + viewBox Computation
2
+
3
+ ## Status: DONE (2026-07-21, folded into TODO 03)
4
+
5
+ ## Problem
6
+
7
+ EA's root `<svg>` element declares `width="Xcm" height="Ycm"` and
8
+ `viewBox="0 0 W H"`. The cm dimensions are computed from the
9
+ union of all element `image_bounds` (the padded bounds), with
10
+ ~25 px padding around the canvas. The viewBox is in pixel units.
11
+
12
+ Our current renderer computes a viewBox from the union of element
13
+ bounds + connectors, but doesn't emit cm dimensions.
14
+
15
+ ## Approach
16
+
17
+ `Ea::Svg::EaEmitter::Canvas` computes:
18
+
19
+ 1. Union of all element `image_bounds` (NOT logical bounds — EA's
20
+ canvas size is based on the visual padding).
21
+ 2. Adds 10 px outer margin.
22
+ 3. Emits viewBox = "min_x min_y width height".
23
+ 4. Emits width/height in cm as `width / 28.346` (72 DPI conversion).
24
+
25
+ The canvas module is also responsible for translating the
26
+ coordinate space if min_x/min_y are non-zero (EA's convention is
27
+ to keep the viewBox starting at 0,0 by translating all elements).
28
+
29
+ ## Files
30
+
31
+ - `lib/ea/svg/ea_emitter/canvas.rb`
32
+ - `spec/ea/svg/ea_emitter/canvas_spec.rb`
33
+
34
+ ## Verification
35
+
36
+ - Spec: known element set produces expected viewBox and cm
37
+ dimensions.
38
+ - Visual: SVG opens in a viewer at the same physical size as EA's
39
+ output.
@@ -0,0 +1,65 @@
1
+ # TODO-D 07 - Full text content fidelity
2
+
3
+ ## Status: PARTIAL (62% overlap) (2026-07-26)
4
+
5
+ ## Current state
6
+
7
+ Text overlap (Jaccard index of text content sets between our SVG
8
+ and reference SVG):
9
+
10
+ - Average across 185 plateau diagrams: **62%**
11
+ - Best diagrams: ~95%
12
+ - Worst diagrams: ~20%
13
+
14
+ ## What's working
15
+
16
+ - Classifier names and stereotypes render correctly when the
17
+ element is placed on the diagram.
18
+ - Attribute text matches when the element has Tag=0 (no tagged
19
+ values compartment).
20
+ - Visibility prefixes ("+ ", "- ") match.
21
+ - Multiplicity brackets match.
22
+
23
+ ## What's still off
24
+
25
+ ### 1. Tagged value visibility (mostly fixed, edge cases remain)
26
+ Reference SVGs don't render the "tags" header compartment except
27
+ on 2 diagrams. Our Tag-flag gating brought text overlap from 41%
28
+ to 62%. Remaining misses are likely from elements where the
29
+ `Tag=1` flag is set but the reference still doesn't render tags
30
+ — possibly tied to stereotype source (profile-applied vs
31
+ user-defined tagged values).
32
+
33
+ ### 2. Qualified name vs simple name
34
+ Reference uses qualified names like
35
+ `uro::TrafficVolumeAttribute`. Our output sometimes uses the
36
+ short name only. The qualified_name attribute is set on the
37
+ Classifier model, but the renderer doesn't always pick it up
38
+ correctly when the element is placed on a sub-package diagram.
39
+
40
+ ### 3. Attribute ordering
41
+ Within a classifier's attribute compartment, EA sorts attributes
42
+ by some criteria (possibly visibility then alphabetical). Our
43
+ ordering follows the XMI's `ownedAttribute` order, which may
44
+ differ.
45
+
46
+ ### 4. Attribute visibility color
47
+ Reference uses different fill colors for public/protected/private
48
+ attributes (`#66413F` for some, `#595959` for others). Our
49
+ renderer uses a single text color from the theme.
50
+
51
+ ## Path to 100% text overlap
52
+
53
+ 1. Characterize the tagged value visibility rule by examining
54
+ which elements with `Tag=1` still don't render tags in
55
+ reference (estimated 5-10 diagrams).
56
+
57
+ 2. Always use `classifier.qualified_name` for the header label
58
+ (currently mixed).
59
+
60
+ 3. Sort attributes by visibility prefix, then alphabetical.
61
+
62
+ 4. Apply theme.color_for_attribute_visibility for attribute text.
63
+
64
+ Each of these is a separate fix. None require architectural
65
+ changes.