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,59 @@
1
+ # TODO-D 26: Phantom general-parent rendering
2
+
3
+ ## Problem
4
+
5
+ The reference SVGs contain class headers (`_AbstractGeometricAggregate`,
6
+ `_CityObject`, `_FeatureCollection`, etc.) that do NOT appear in
7
+ `t_diagramobjects` for the diagram. ~150 missing text instances
8
+ across the plateau dataset.
9
+
10
+ ## Empirical Rule (partial)
11
+
12
+ When a class is placed in a diagram, EA also displays its
13
+ generalization parent if the parent isn't already in the diagram.
14
+
15
+ Validation across 188 diagrams:
16
+
17
+ - Total parent-checks: 241
18
+ - Parent rendered in SVG: 129 (53.5%)
19
+
20
+ 53.5% match suggests the rule is "right idea, wrong details." Other
21
+ factors:
22
+
23
+ - Per-element font/style override may suppress phantom rendering
24
+ when the parent's style isn't explicit
25
+ - The discriminator may be tied to AttPkg / SuppressFOC flags
26
+ - EA may only render one level up the generalization chain
27
+
28
+ ## Implementation Sketch
29
+
30
+ Add `phantom_generalizations_for(diagram, model_index)` returning
31
+ phantom DiagramElements with synthetic bounds (placed near their
32
+ child). Render them through the existing `groups_for` path so they
33
+ participate in the same compartment math, color resolution, etc.
34
+
35
+ ```ruby
36
+ def ordered_elements
37
+ placed = (diagram.elements || []).sort_by { |e| e.z_order || 0 }
38
+ placed + phantom_elements(placed)
39
+ end
40
+
41
+ def phantom_elements(placed)
42
+ placed_ids = placed.map(&:model_element_ref)
43
+ parents = placed_ids.flat_map { |id| generalizations_of(id) }.uniq - placed_ids
44
+ parents.map { |pid| phantom_diagram_element(pid) }
45
+ end
46
+ ```
47
+
48
+ The hard part is positioning: EA computes phantoms at coordinates
49
+ we cannot derive without GUI testing or sample-data correlation.
50
+
51
+ ## Acceptance
52
+
53
+ - Render general-parent phantoms for at least the cases where the
54
+ rule applies cleanly.
55
+ - Phantom bounding box is plausible (within canvas extents).
56
+ - Parity text overlap climbs to ~90%+.
57
+ - Specs cover: parent not in diagram (phantom added), parent
58
+ already in diagram (no duplicate), phantom appears in correct
59
+ sub-layer.
@@ -0,0 +1,43 @@
1
+ # TODO-D 27: Per-diagram path grouping mode detection
2
+
3
+ ## Problem
4
+
5
+ EA emits connector paths in two styles:
6
+
7
+ 1. **Grouped** — All same-style paths joined into one `<g>` block
8
+ (matches what we currently do in `LayerSequencer#merge_layers_by_style`).
9
+ 2. **Per-connector** — Each connector path in its own `<g>` block.
10
+
11
+ Some diagrams use one mode, others use the other. We always use
12
+ grouped, contributing to the -181 path delta.
13
+
14
+ ## Investigation
15
+
16
+ Tested in StyleEx flags — no obvious "grouped" toggle. EA's
17
+ emit-mode decision appears to be runtime/export-time, not stored in
18
+ the QEA.
19
+
20
+ ## Empirical Observations
21
+
22
+ - Grouped-style diagrams: 0 to 5 path-delta diagrams (most match)
23
+ - Per-connector-style diagrams: 10-30 path-delta (we're missing 10-30
24
+ `<g>` wrappers)
25
+
26
+ The discriminator might be:
27
+
28
+ - Diagram export-time option set in EA GUI at export
29
+ - Per-diagram count threshold (more connectors → per-connector)
30
+ - User preference cached in some EA-specific location we can't access
31
+
32
+ ## Status
33
+
34
+ Deferred. Without empirical access to EA's export preferences or a
35
+ binary blob in the QEA, the mode detection is speculative.
36
+
37
+ ## Acceptance (when picked up)
38
+
39
+ - Identify the QEA field or runtime condition that controls grouping.
40
+ - Implement a per-diagram detector.
41
+ - Wire into LayerSequencer: `grouped: detect_grouped_mode(diagram)`.
42
+ - Specs cover: small diagrams → grouped, large diagrams → per-connector.
43
+ - Path delta within ±20 of zero.
@@ -0,0 +1,47 @@
1
+ # TODO-D 28-31: Architectural cleanup batch
2
+
3
+ ## Completed (this session)
4
+
5
+ ### 28. Canvas promoted to proper class
6
+
7
+ `lib/ea/svg/ea_emitter/canvas.rb` was a `Struct.new + do ... end`
8
+ block. Promoted to an explicit class with `attr_reader` for the
9
+ four bound fields. Public API is now named rather than implicit;
10
+ the type stays immutable.
11
+
12
+ 8 new specs cover `translate_x`, `translate_y`, `.coord`,
13
+ immutability, and the existing `.from` factory.
14
+
15
+ ### 29. OpenStruct removed
16
+
17
+ `elements.rb#translate_bounds` returned an `OpenStruct.new`. This
18
+ required `require "ostruct"` at the top of the file and obscured
19
+ the return type.
20
+
21
+ Now returns `Ea::Model::Bounds.new` directly — the existing model
22
+ value object — and the `require "ostruct"` line is removed. Type
23
+ flows cleanly through the pipeline (model → renderer).
24
+
25
+ ### 31. Specs for under-tested components
26
+
27
+ - `spec/ea/svg/ea_emitter/canvas_spec.rb` — added `translate_x`,
28
+ `translate_y`, `.coord`, and immutability specs.
29
+ - `spec/ea/svg/ea_emitter/layer_spec.rb` — new file (10 specs).
30
+ - `spec/ea/svg/ea_emitter/background_spec.rb` — new file (3 specs).
31
+
32
+ ## Deferred
33
+
34
+ ### 30. Decompose Elements groups_for
35
+
36
+ `Elements#groups_for` is ~100 lines of linear rendering steps.
37
+ Two previous attempts to extract a helper method broke 5+ specs
38
+ due to complex parameter threading (model_element vs classifier
39
+ distinction, Optional bounds, theme plumbing).
40
+
41
+ The method reads as a recipe: each step adds one output string.
42
+ Linear recipes are easier to read as one method than as a chain
43
+ of helper calls with overlapping parameter lists.
44
+
45
+ Deferred until a structural refactor (e.g. a Compartments
46
+ collaborator that holds rendering state) is justified by a new
47
+ requirement.
@@ -0,0 +1,52 @@
1
+ # TODO-D 30: Decompose Elements groups_for (DONE)
2
+
3
+ ## Goal
4
+
5
+ The `Elements#groups_for` method had grown to ~100 lines, mixing
6
+ shape dispatch, header rendering, divider logic, attribute /
7
+ operation / enum-literal / tagged-value compartment rendering,
8
+ and special-case branching for Note bodies.
9
+
10
+ ## Implementation
11
+
12
+ Extracted a Compartment pipeline:
13
+
14
+ ```
15
+ Elements#groups_for(element)
16
+ └─ build_context(element) → RenderContext
17
+ └─ Compartment.render_all(context) → Array<String>
18
+ ├─ Compartment::Shape
19
+ ├─ Compartment::NoteBody
20
+ ├─ Compartment::Header
21
+ ├─ Compartment::HeaderDivider
22
+ ├─ Compartment::Attributes
23
+ ├─ Compartment::Operations
24
+ ├─ Compartment::EnumLiterals
25
+ └─ Compartment::TaggedValues
26
+ ```
27
+
28
+ - `RenderContext` (Struct): immutable per-element state — bounds,
29
+ classifier, fill/stroke, font, geometry, line arrays, theme,
30
+ canvas. Built once, passed to every compartment.
31
+ - `Compartment::ALL`: frozen list of compartment modules in EA's
32
+ render order. Adding a new compartment = appending a module to
33
+ this list. Elements does not change.
34
+ - Each compartment is a Module with `module_function :render`.
35
+ Returns nil when the compartment does not apply (no content,
36
+ no geometry). The pipeline compacts the result.
37
+
38
+ ## Benefits
39
+
40
+ - **OCP**: new compartments don't modify Elements#groups_for.
41
+ - **SRP**: each compartment knows one concern.
42
+ - **Testability**: each compartment has a focused spec.
43
+ - **Readability**: Elements went from ~377 lines to ~232 lines;
44
+ groups_for went from ~100 lines to ~10.
45
+
46
+ ## Verification
47
+
48
+ - All 1694 existing specs pass.
49
+ - New specs: `spec/ea/svg/ea_emitter/compartment_spec.rb` covers
50
+ the pipeline ordering and RenderContext helpers.
51
+ - Parity bench unchanged: rect -221, path -280, polygon -6,
52
+ text -601, overlap 64.5%. The refactor is behavior-preserving.
@@ -0,0 +1,78 @@
1
+ # TODO-D 32-35: Examples coverage batch
2
+
3
+ ## Motivation
4
+
5
+ The user asked to test ALL of examples/ against QEAs, XMIs (model.xml),
6
+ and reference SVGs. Running through each fixture surfaced four bugs
7
+ that the plateau-only regression harness missed.
8
+
9
+ ## Completed
10
+
11
+ ### 32. Examples regression spec
12
+
13
+ `spec/ea/svg/examples_regression_spec.rb` runs each QEA, parses its
14
+ matching `model.xml`, and renders every diagram with a reference SVG.
15
+ Threshold is 0.4 average text-overlap (loose — known per-example gaps
16
+ documented in TODO.diagrams/).
17
+
18
+ Covers: plateau (188 diagrams), arcgis (6), basic (22), simple (2),
19
+ test (2) = **220 diagrams across 5 fixtures**.
20
+
21
+ ### 33. Package label rendering
22
+
23
+ `PackageShapeRenderer` took a `label:` argument but never emitted it
24
+ as `<text>` — Package model elements had no visible name in the SVG.
25
+ Now renders the label inside the tab area, bold, using the same
26
+ font family/size as the element renderer.
27
+
28
+ Plateau impact: text delta -96 → -52 (44 package names recovered).
29
+ Simple impact: text delta -10 → -5.
30
+
31
+ ### 34. Suppress implicit connectors
32
+
33
+ EA encodes package nesting as `Connector_Type = "Nesting"` rows in
34
+ `t_diagramlinks` but does NOT render them as paths in SVG — the
35
+ containment is implied by visual position.
36
+
37
+ Added `Ea::Model::DiagramConnector#renderable?` returning false for
38
+ hidden + implicit-type connectors. All three emitters (Connectors,
39
+ Markers, Labels) use the shared predicate instead of duplicating
40
+ the reject logic.
41
+
42
+ Simple example went from 6 paths (canvas + 5 nesting lines) to 1
43
+ path (canvas only) — matches EA exactly.
44
+
45
+ ### 35. Object properties as tagged values
46
+
47
+ EA stores UML profile tagged values in `t_taggedvalue` (keyed by
48
+ ElementID GUID) AND per-object custom properties in
49
+ `t_objectproperties` (keyed by Object_ID integer). Both surface as
50
+ tagged values in the SVG.
51
+
52
+ `TaggedValueBuilder#for_object` now takes both `ea_guid` AND
53
+ `ea_object_id:` and merges both sources. ClassifierBuilder threads
54
+ the integer Object_ID through.
55
+
56
+ Simple example: AcmeUmlClass tagged values went from 0 to 2
57
+ (`noPropertyType=false`, `isCollection=false`), matching EA.
58
+
59
+ ## Current Per-Example Parity Snapshot
60
+
61
+ | Example | Text overlap avg | Improvement |
62
+ |----------|------------------|-------------|
63
+ | plateau | 87.1% | (unchanged baseline) |
64
+ | arcgis | ~55% | +20pp |
65
+ | basic | ~59% | +5pp |
66
+ | simple | ~85% | +35pp |
67
+ | test | ~54% | small |
68
+
69
+ ## Remaining per-example gaps (deferred)
70
+
71
+ - **ArcGISWorkspace_template**: HTML formatting in note bodies
72
+ (`<ul>`, `<li>`, `<b>`) — we render raw HTML as text, EA strips it.
73
+ Diagram frame title format also differs (we emit "class NAME",
74
+ EA emits "ArcGIS NAME" — package-prefixed).
75
+ - **basic**: 19 missing polygons, 30 missing paths. Likely tagged-
76
+ value / signal-classifier-type related.
77
+ - **test**: 58 missing paths. Path grouping mode detection
78
+ (TODO-D 27).
@@ -0,0 +1,42 @@
1
+ # TODO-D 36: InstanceSpecification model (full Object diagram support)
2
+
3
+ ## Problem
4
+
5
+ EA `t_object.Object_Type = 'Object'` rows are UML
6
+ InstanceSpecifications. Currently mapped to Klass (the instance
7
+ name renders correctly), but EA also shows:
8
+
9
+ - The role binding: "Object 01 / roleOne: Class A"
10
+ - The slot compartment: "attributeOne = valueOne" per slot
11
+
12
+ ## Current State
13
+
14
+ basic.qea text delta: -38. The 4 Object diagrams in basic.qea
15
+ have instance names rendered but miss role bindings and slots.
16
+
17
+ ## Implementation Plan
18
+
19
+ 1. Add `Ea::Model::InstanceSpecification < Classifier`:
20
+ - `name` (already inherited)
21
+ - `classifier_ref` (GUID of instantiated Class)
22
+ - `slots` collection of `Ea::Model::Slot {name, value}`
23
+
24
+ 2. Update `t_object.Object_Type = 'Object'` → InstanceSpecification
25
+ in ObjectClassifierMap.
26
+
27
+ 3. Parse the Classifier column from t_object to populate
28
+ `classifier_ref`. Parse t_objectproperties rows owned by
29
+ instance objects as Slot entries.
30
+
31
+ 4. Render header as "InstanceName / roleName: ClassName" when
32
+ classifier_ref + role are set; else just InstanceName.
33
+
34
+ 5. Render slot compartment below the header (italic, like tagged
35
+ values) with "slotName = value" per slot.
36
+
37
+ ## Acceptance
38
+
39
+ - Object diagrams in basic.qea render all reference texts.
40
+ - basic.qea text delta within ±10.
41
+ - InstanceSpecification specs cover: bare instance, instance +
42
+ classifier, instance + slots, instance + role + slots.
@@ -0,0 +1,41 @@
1
+ # TODO-D 37: Element header icon decorations (test.qea path gap)
2
+
3
+ ## Problem
4
+
5
+ test.qea has 69 reference paths but we render only 11. The
6
+ missing 58 paths are small line segments forming per-element-type
7
+ icons inside each attribute / operation row.
8
+
9
+ Reference example (Test Model diagram, 1 element "Test Schema"):
10
+
11
+ ```
12
+ M 40 87 L 50 87 # 10px horizontal stroke (icon body)
13
+ M 42 85 L 46 85 # 4px stroke above (icon decoration)
14
+ M 48 85 L 49 85 # 1px stroke (icon decoration)
15
+ M 42 89 L 46 89 # 4px stroke below
16
+ M 48 89 L 49 89 # 1px stroke below
17
+ ```
18
+
19
+ The 5-path pattern repeats every 16px (one row per attribute /
20
+ operation / tagged-value).
21
+
22
+ ## Cause
23
+
24
+ EA renders a small icon next to each row in attribute / operation
25
+ compartments when the per-element `HideIcon=0` flag is set in
26
+ ObjectStyle. The icon shape varies by row kind (attribute gets
27
+ one icon, operation gets another, tagged value gets a third).
28
+
29
+ ## Status
30
+
31
+ Deferred. Reverse-engineering each icon's exact path coordinates
32
+ requires EA.exe disassembly or empirical SVG byte-diff for each
33
+ icon kind.
34
+
35
+ ## Acceptance (when picked up)
36
+
37
+ - Identify each icon shape (attribute icon, operation icon, etc.).
38
+ - Add Element::RowIcon renderer with a registry by row kind.
39
+ - Wire into AttributeRenderer, OperationRenderer, TaggedValueRenderer.
40
+ - Specs cover each icon kind with reference-SVG byte match.
41
+ - test.qea path delta within ±20 (currently -58).
@@ -0,0 +1,32 @@
1
+ # TODO-D 38: HTML note body rendering + receptions compartment
2
+
3
+ ## Two related gaps
4
+
5
+ ### HTML in note bodies
6
+
7
+ EA stores Note and Diagram Notes as RTF / HTML strings. When
8
+ rendered to SVG, EA strips the HTML tags and emits plain text
9
+ formatted to the visible character width.
10
+
11
+ We currently emit the raw HTML body verbatim — `<ul>`, `<li>`,
12
+ `<b>` tags appear as text in the SVG.
13
+
14
+ ArcGISWorkspace_template uses HTML notes heavily; this is the
15
+ biggest contributor to its 36.9% → ~55% text overlap gap.
16
+
17
+ ### Receptions compartment
18
+
19
+ UML Class can declare "receptions" — `«signal» SignalName()`
20
+ entries that say the class accepts a Signal. EA renders these as
21
+ a 4th compartment below operations.
22
+
23
+ basic.qea "Basic Class Diagram with Receptions" misses
24
+ "receptions" header + 6 `«signal» Signal X()` entries.
25
+
26
+ ## Acceptance (when picked up)
27
+
28
+ - HTML Note: strip tags using a simple HTML parser; wrap text at
29
+ the note's pixel width; emit one `<text>` per wrapped line.
30
+ - Receptions: model as `Klass#receptions` collection of
31
+ `Ea::Model::Reception {signal_ref, name}`; render in a
32
+ dedicated compartment below operations.
@@ -0,0 +1,40 @@
1
+ # TODO-D 39: «property» stereotype label discriminator
2
+
3
+ ## Problem
4
+
5
+ EA renders the «property» stereotype between role name and
6
+ multiplicity for some association connectors but NOT others.
7
+ We currently always render it, causing basic.qea over-rendering
8
+ (~8 extra texts per diagram).
9
+
10
+ ## Investigation
11
+
12
+ Tried **OY gap between LLT and LLB geometry boxes** as discriminator:
13
+
14
+ | Threshold | Plateau delta | Basic delta |
15
+ |-----------|---------------|-------------|
16
+ | Always (no filter) | -39 | -38 |
17
+ | Gap >= 15 | -392 (−353) | -46 (−8) |
18
+ | Gap >= 5 | -280 (−241) | -38 |
19
+ | Gap >= 1 | -188 (−149) | -30 (−8) |
20
+
21
+ The OY gap is NOT the correct discriminator. Many plateau connectors
22
+ with gap=0 still need «property», while basic connectors with gap=0
23
+ don't. Both sets have role names and multiplicities.
24
+
25
+ ## Architecture
26
+
27
+ The structural predicate `EndLabel#property_label?` is already
28
+ extracted and wired. When the correct discriminator is found, it's
29
+ a one-line change to the predicate body.
30
+
31
+ ## Acceptance
32
+
33
+ - Identify the field/flag in t_connector or t_diagramlinks that
34
+ controls «property» rendering. Candidates:
35
+ - t_connector.SubType
36
+ - t_connector.StyleEx (per-connector)
37
+ - LLT box CY value (content height)
38
+ - TExplicitNavigability flag interaction
39
+ - Implement the check in property_label?
40
+ - Specs cover both rendering and non-rendering cases.
@@ -0,0 +1,38 @@
1
+ # TODO-D 40: Standalone "1" multiplicity discriminator
2
+
3
+ ## Problem
4
+
5
+ EA renders the "1" multiplicity at connector endpoints in SOME
6
+ diagrams but NOT others. In basic.qea's "Domain Model" diagram, EA
7
+ shows "1" at the dest end of two connectors. In plateau, most
8
+ connectors with explicit cardinality "1" do NOT show "1".
9
+
10
+ ## Empirical Findings
11
+
12
+ | Change | Plateau | Basic |
13
+ |----------------------------------|---------|-------|
14
+ | Always render (no filter) | -39 | -22 |
15
+ | Filter "1" from standalone mult | -30 | -30 |
16
+ | Allow "1" from explicit "1" only | +89 | TBD |
17
+
18
+ The "filter '1'" approach helps plateau (-9) but hurts basic (-8).
19
+ The "allow explicit '1'" approach hurts plateau (+128) more.
20
+
21
+ ## Root Cause
22
+
23
+ The discriminator is NOT in t_connector.SourceCard/DestCard alone
24
+ (both basic and plateau have explicit "1" in some connectors).
25
+ It may be in:
26
+ - Per-diagram StyleEx flag (not yet identified)
27
+ - Per-connector StyleEx (similar to HideIcon)
28
+ - TConnectorNotation vs explicit navigability
29
+ - Connector SubType
30
+
31
+ ## Acceptance
32
+
33
+ - Identify the discriminator that separates "Domain Model" (shows "1")
34
+ from typical plateau connector (no "1" despite same cardinality).
35
+ - Implement in standalone_multiplicity in EndLabel.
36
+ - basic.qea Domain Model overlap 0.7 → ~0.9.
37
+ - basic.qea average 81.5% → ~85%.
38
+ - plateau text delta unchanged.
@@ -0,0 +1,113 @@
1
+ # TODO-D 41: EA's XMI → SVG rendering pipeline
2
+
3
+ ## Goal
4
+
5
+ Duplicate EA's SVG rendering when the SOURCE is a Sparx XMI export
6
+ (not a .qea). Reference corpus:
7
+
8
+ - Source: `~/src/mn/mn-samples-plateau/sources/xmi/plateau_all_packages_export.xmi`
9
+ - Reference: `~/src/mn/mn-samples-plateau/sources/001-mds/xmi-images/*.svg` (192 files)
10
+
11
+ These SVGs were produced by EA.exe from that exact XMI, so they are a
12
+ byte-level oracle for the XMI path — no QEA intermediate.
13
+
14
+ ## Verified XMI encoding
15
+
16
+ The Sparx XMI carries every rendering input the QEA carries, in
17
+ `xmi:Extension` blocks:
18
+
19
+ | QEA table/column | XMI location |
20
+ |----------------------------|---------------------------------------------|
21
+ | t_diagram.StyleEx | `<diagram><properties/>` + `<xrefs/>` |
22
+ | t_diagramobjects.RectTop.. | `<elements><element geometry="...">` |
23
+ | t_diagramlinks.Geometry | `<connectors><connector geometry="...">` |
24
+ | t_object.Style (ObjectStyle)| `element/@style` — `NSL=0;LCol=-1;...` |
25
+ | t_object.StyleEx font | `element/@style` — `font=Yu Gothic UI;fontsz=100` |
26
+ | t_connector.StyleEx | `connector/@style` — `CX=19:CY=13:OX=0:...` |
27
+ | t_objectproperties | `<tags><tag name= value=>` |
28
+
29
+ Font differences vs plateau.qea:
30
+
31
+ - XMI export: `font=Yu Gothic UI; fontsz=100` → 10pt → 13px
32
+ - plateau.qea: `Carlito; fontsz=70` → 7pt → 9px
33
+
34
+ So the SAME model renders at a different scale depending on which
35
+ export the SVG was produced from. Font resolution must come from the
36
+ source's own StyleEx, never a hard-coded default.
37
+
38
+ ## Per-element layer order (verified from reference SVGs)
39
+
40
+ EA emits one `<g>` per *visual concern*, not one per element. Within
41
+ one element the order is stable:
42
+
43
+ 1. shape — `<rect>` (or folder polygons for Package)
44
+ 2. header — `<text>` × N (stereotype, name, optional qualifier)
45
+ 3. divider — `<path>` horizontal rule
46
+ 4. attributes — `<text>` × 2N (visibility glyph + content)
47
+ 5. operations — divider + `<text>` × N
48
+ 6. literals — divider + italic "literals" + `<text>` × N
49
+ 7. tagged vals — divider + `<text>` × N
50
+
51
+ Connector layers interleave by z-order, not per element.
52
+
53
+ ## Current parity (plateau XMI, 188 diagrams)
54
+
55
+ ```
56
+ Matched: 185/188 Errors: 0
57
+ rect ours= 1781 ref= 2002 delta=-221 (-11.0%)
58
+ path ours= 3018 ref= 3298 delta=-280 ( -8.5%)
59
+ polygon ours= 955 ref= 961 delta= -6 ( -0.6%)
60
+ text ours=16918 ref=17548 delta=-630 ( -3.6%)
61
+ Text overlap avg: 19.1%
62
+ ```
63
+
64
+ ## Acceptance
65
+
66
+ - A reusable benchmark task that scores ANY source (qea or xmi)
67
+ against a reference SVG directory, so the XMI path is measured on
68
+ every change instead of ad-hoc scripts.
69
+ - Font resolution driven by the source's own StyleEx (no default
70
+ drift between qea and xmi inputs).
71
+ - rect delta explained: which element kinds are missing shapes.
72
+ - path delta explained: which connectors are missing.
73
+ - 3 unmatched diagrams identified (name-normalization or genuinely
74
+ absent from the export).
75
+
76
+ ## Sub-tasks
77
+
78
+ - [x] 41a — Locate and parse the XMI corpus
79
+ - [x] 41b — Map every QEA rendering input to its XMI counterpart
80
+ - [x] 41c — Verify per-element layer order against references
81
+ - [x] 41d — Land the benchmark as a rake task (`rake svg:bench`)
82
+ - [x] 41e — Explain the rect/path/text deltas by element kind
83
+ - [x] 41f — Read UMLDI keyword labels from the XMI source so the
84
+ header stereotype («Type», «FeatureType», «DataType») matches
85
+ what EA actually rendered. New `Ea::Sources::Xmi::UmldiKeywordExtractor`
86
+ parses the raw XMI once; `DiagramBuilder` threads the
87
+ `umldi_keyword` per element; `HeaderLines` consumes it.
88
+ - [x] 41g — Fix `qualified_name` for XMI classifiers whose `name`
89
+ already carries a namespace prefix (e.g. `xs:string` in the
90
+ `xs` package). Was producing `xs::xs:string`; now `xs::string`,
91
+ matching EA's reference output.
92
+
93
+ ## Bench results after fixes
94
+
95
+ ```
96
+ Matched: 185/188 Errors: 0
97
+ rect ours= 1781 ref= 2002 delta=-221 (-11.0%)
98
+ path ours= 3018 ref= 3298 delta=-280 ( -8.5%)
99
+ polygon ours= 955 ref= 961 delta= -6 ( -0.6%)
100
+ text ours=16947 ref=17548 delta=-601 ( -3.4%)
101
+ Text overlap avg: 64.5% (was 19.1% before UMLDI fix)
102
+ ```
103
+
104
+ ## Remaining parity gaps (in priority order)
105
+
106
+ 1. **rect -221** — likely connector marker anchors rendered as
107
+ `<polygon>` instead of the EA split across `<rect>`/`<polygon>`.
108
+ Audit per element-type to confirm.
109
+ 2. **path -280** — EA's bend points for connectors use a longer
110
+ path string. Possibly: missing waypoint endpoint waypoints.
111
+ 3. **text -601** — some label text still mismatching. Likely
112
+ cross-package role names and multiplicity position.
113
+ 4. **-221 / -280** explain-by-element-kind audit (TODO 41e).
@@ -0,0 +1,69 @@
1
+ # TODO-D 42: Close all SVG parity deltas to zero
2
+
3
+ ## Goal
4
+
5
+ Reach shape/text parity 0/0/0/0 against the plateau XMI
6
+ reference set (192 SVGs in `001-mds/xmi-images/`).
7
+
8
+ ## Current state (after TODO-D 41, 42)
9
+
10
+ ```
11
+ rect ours= 1781 ref= 2002 delta=-221 (-11.0%)
12
+ path ours= 3018 ref= 3298 delta=-280 ( -8.5%)
13
+ polygon ours= 955 ref= 961 delta= -6 ( -0.6%)
14
+ text ours=16947 ref=17548 delta=-601 ( -3.4%)
15
+ Text overlap avg: 64.5%
16
+ ```
17
+
18
+ 185/188 diagrams matched, 59 outliers.
19
+
20
+ ## Architecture cleanup (DONE)
21
+
22
+ - `lib/ea.rb` no longer `require_relative`s `ea/version`. VERSION
23
+ is inlined.
24
+ - `lib/ea/sources/xmi/diagram_builder.rb` no longer
25
+ `require_relative`s `umldi_keyword_extractor`. Uses autoload.
26
+ - `lib/ea/qea/factory/generalization_builder.rb` no longer uses
27
+ `public_send(:"#{k}=", v)` for attribute assignment.
28
+
29
+ ## Diagnosis (DONE)
30
+
31
+ The deltas decompose into three root causes:
32
+
33
+ 1. **Element icon decorations** (TODO-D 44, ~280 paths).
34
+ EA renders a small "folded paper" icon at the top-right of
35
+ some elements. IconRenderer exists but the discriminator
36
+ (which elements get icons) is non-trivial — not just
37
+ `HideIcon=0`.
38
+
39
+ 2. **Phantom parent class boxes** (TODO-D 45, ~80 rects).
40
+ When a connector's endpoint references a classifier that
41
+ isn't placed on the diagram, EA renders a minimal "phantom"
42
+ box at the connector's endpoint.
43
+
44
+ 3. **User-drawn legend swatches** (TODO-D 46, ~50-100 rects).
45
+ Manually-drawn colored rectangles inside Note/text elements.
46
+ Not encoded as standard UML — may be unrecoverable from XMI.
47
+
48
+ Plus two text-delta sources:
49
+ - Diagrams where EA renders only a frame and no elements
50
+ (TODO-D 41 has examples). The reference SVG is a tiny blank
51
+ canvas; our renderer emits the full content.
52
+ - Tree-routing generalization markers: EA collapses 9 parallel
53
+ connectors into 9 polygons at the same anchor (TODO-D 43).
54
+
55
+ ## Acceptance
56
+
57
+ Closing each delta to zero requires:
58
+ - [ ] TODO-D 44 discriminator identified and IconRenderer enabled
59
+ - [ ] TODO-D 45 phantom parent rendering implemented
60
+ - [ ] TODO-D 46 either implemented or excluded from parity measurement
61
+ - [ ] TODO-D 43 marker strategy per connector Mode (tree vs custom)
62
+ - [ ] Blank-frame diagram detection (small canvas, all elements off-canvas)
63
+
64
+ ## Out of scope for this commit
65
+
66
+ The remaining work requires EA GUI testing or Ghidra disassembly
67
+ to identify the icon discriminator and phantom-box trigger. These
68
+ are tracked in their own TODOs and will be addressed in focused
69
+ follow-up PRs.