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,185 @@
1
+ # 29 - QEA+SVG+XMI Triple Comparison Findings
2
+
3
+ ## Status: DONE (2026-07-25)
4
+
5
+ ## Methodology
6
+
7
+ Three synchronized data sources now available:
8
+
9
+ - `examples/qea/*.qea` — source QEA files (SQLite database)
10
+ - `examples/exports/*/model.xml` — XMI exports
11
+ - `examples/exports/*/Images/*.svg` — SVG exports (from EA)
12
+
13
+ Triple comparison isolates where parity gaps come from:
14
+
15
+ | Compare | Reveals |
16
+ |---|---|
17
+ | QEA vs XMI | What info is lost in XMI export |
18
+ | XMI → our SVG vs EA's SVG | Our renderer bugs |
19
+ | QEA → our SVG (when supported) vs EA's SVG | Pure renderer comparison |
20
+
21
+ ## Available datasets
22
+
23
+ | QEA | Diagrams | Notes |
24
+ |---|---|---|
25
+ | `simple` | 2 | Tiny — Package + Class diagrams |
26
+ | `test` | 2 | Small test models |
27
+ | `basic` | 22 | UML template with all classifier types |
28
+ | `ArcGISWorkspace_template` | 6 | ArcGIS domain |
29
+ | `UmlModel_template` | 0 (empty) | N/A |
30
+ | `simple_example` | 0 (empty) | N/A |
31
+ | `20251010_current_plateau_v5.1` | 188 | Production model |
32
+
33
+ ## Key finding #1: EA has a THEME system
34
+
35
+ The QEA's `t_diagram.StyleEx` field carries a `Theme=:NNN` flag:
36
+
37
+ | QEA | Theme | Resulting style |
38
+ |---|---|---|
39
+ | `simple` | `:119` | Carlito 7pt, gray text, pastel fills |
40
+ | `basic` | `:119` | Same as simple |
41
+ | `test` | `:119` (some), `nil` (others) | Mixed |
42
+ | `ArcGISWorkspace_template` | `nil` | Default styling |
43
+ | `plateau v5.1` | `nil` | Yu Gothic UI 13px (element-stored) |
44
+
45
+ Theme `:119` produces:
46
+ - **Font**: Carlito (a Calibri-compatible open font)
47
+ - **Font size**: 7pt (not px)
48
+ - **Text color**: #595959 (gray, NOT black)
49
+ - **Text font-weight**: 0 for normal, 700 for bold (0 instead of 400!)
50
+ - **Element border**: #9A8484 (purple-gray, NOT black)
51
+ - **Element fill**: pastel per classifier type (see below)
52
+ - **Stroke width**: 1 (NOT 2)
53
+ - **Stroke cap/join**: round/bevel
54
+
55
+ ## Key finding #2: Per-type fill colors (theme :119)
56
+
57
+ | Classifier type | Fill color | Stereotype label |
58
+ |---|---|---|
59
+ | Class | `#FDFAF7` | (depends on applied stereotype) |
60
+ | Interface | `#F1ECFA` | `«interface»` |
61
+ | DataType | `#FAF9E6` | `«dataType»` (lowercase d!) |
62
+ | Enumeration | `#E8FDE3` | `«enumeration»` |
63
+ | PrimitiveType | `#FAF9E6` | `«primitive»` |
64
+
65
+ Stereotype label casing observed in ref SVGs:
66
+ - `«DataType»` — Class with explicit DataType stereotype applied (CapD, CapT)
67
+ - `«dataType»` — DataType classifier (lowercase d, CapT)
68
+ - `«interface»` — Interface classifier (all lowercase)
69
+ - `«enumeration»` — Enumeration classifier (all lowercase)
70
+ - `«primitive»` — PrimitiveType classifier (all lowercase)
71
+
72
+ Our current emitter uses `«DataType»` for ALL Klass subclasses,
73
+ which is WRONG for actual DataType/Interface/Enumeration types.
74
+
75
+ ## Key finding #3: Diagram frame
76
+
77
+ Every EA diagram has an outer border with a "tab" containing
78
+ the diagram name+type. Rendered as:
79
+
80
+ ```xml
81
+ <!-- Outer border (path, not rect) -->
82
+ <g style="stroke-width:1;stroke-linecap:square;stroke-linejoin:miter;
83
+ fill:#000000;fill-opacity:0.00; stroke:#000000; stroke-opacity:1.00">
84
+ <path d="M 6 6 L 6 H-6 W-6 W-6 6 L 6 6" shape-rendering="auto"/>
85
+ </g>
86
+ <!-- Tab polygon (hexagon shape) -->
87
+ <g style="stroke-width:1;stroke-linecap:square;stroke-linejoin:miter;
88
+ fill:#FFFFFF;fill-opacity:1.00; stroke:#000000; stroke-opacity:1.00">
89
+ <polygon points="6 26 X 26 X+13 12 X+13 6 6 6 6 26"
90
+ shape-rendering="auto" style="fill-rule:evenodd;"/>
91
+ </g>
92
+ <!-- Tab title text -->
93
+ <g style="...">
94
+ <text x="11" y="19" textLength="W"
95
+ style="font-family:Carlito; font-weight:700; ...;
96
+ transform=rotate(-0.00 11 19)">
97
+ class DiagramName
98
+ </text>
99
+ </g>
100
+ ```
101
+
102
+ Format: `<diagram_type> <diagram_name>` (e.g., `class Package A.1.1`,
103
+ `pkg Package Contents`).
104
+
105
+ Our emitter does NOT render the diagram frame at all.
106
+
107
+ ## Key finding #4: Package rendering
108
+
109
+ Packages are rendered as POLYGONS, not rects:
110
+
111
+ ```xml
112
+ <g style="stroke-width:1;stroke-linecap:round;stroke-linejoin:bevel;
113
+ fill:#FAF3F0;fill-opacity:1.00; stroke:#9A8484; stroke-opacity:1.00">
114
+ <!-- Main package body -->
115
+ <polygon points="L T R T R B L B L T" .../>
116
+ <!-- Tab on top-left -->
117
+ <polygon points="L T-20 L+105 T-20 L+105 T L T L T-20" .../>
118
+ </g>
119
+ ```
120
+
121
+ ## Key finding #5: Text rotation transform
122
+
123
+ EVERY text element has a rotation transform, even when 0:
124
+
125
+ ```xml
126
+ <text x="11.00" y="19.00" textLength="88"
127
+ style="..."
128
+ xml:space="preserve"
129
+ transform="rotate(-0.00 11.00 19.00)">text</text>
130
+ ```
131
+
132
+ Note: `x` and `y` are decimals (2 places), `textLength` is an integer.
133
+ The transform uses the same decimal x,y as the text.
134
+
135
+ Our emitter emits integer coords and no transform.
136
+
137
+ ## Key finding #6: Stroke width per layer
138
+
139
+ | Layer | stroke-width | cap/join |
140
+ |---|---|---|
141
+ | Background rect | (none) | n/a |
142
+ | Diagram frame border | 1 | square/miter |
143
+ | Diagram frame tab | 1 | square/miter |
144
+ | Class boxes (theme :119) | 1 | round/bevel |
145
+ | Class dividers | 1 | round/bevel |
146
+ | Connector lines | 1 or 2 | round/bevel |
147
+
148
+ Our emitter hardcodes stroke-width 2 for everything.
149
+
150
+ ## Key finding #7: DiagramObjects coords
151
+
152
+ QEA's t_diagramobjects stores rect coords with NEGATIVE y values
153
+ (e.g., `RectTop=-195, RectBottom=-265`). EA normalizes by
154
+ translating all elements so the topmost has y=padding.
155
+
156
+ Width = RectRight - RectLeft (positive)
157
+ Height = RectTop - RectBottom (positive — top > bottom in QEA's coords!)
158
+
159
+ Our current parser treats `top` as the upper coord and computes
160
+ height as `bottom - top`. For QEA data, this produces NEGATIVE
161
+ height. Need to take absolute value or swap.
162
+
163
+ ## Practical parity improvements identified
164
+
165
+ 1. **Diagram frame rendering** — add path + polygon + text for the
166
+ outer border and tab.
167
+ 2. **Theme support** — load theme from QEA's `t_diagram.StyleEx`
168
+ `Theme=:NNN` field. Map theme ID to font/color/stroke values.
169
+ 3. **Per-type stereotype labels** — fix the casing per classifier
170
+ concrete class.
171
+ 4. **Per-type fill colors** — lookup table for theme :119.
172
+ 5. **Text rotation transform** — always emit `transform="rotate(-0.00 X Y)"`.
173
+ 6. **Decimal text coords** — format x/y as `%.2f`.
174
+ 7. **Stroke width 1** — use 1 for elements, dividers, frame.
175
+ 8. **QEA rect coord fix** — height is `top - bottom` (not `bottom - top`).
176
+ 9. **Package shape** — render as polygon with tab.
177
+ 10. **Diagram style flags** — honor `SuppressFOC`, `AttPkg`,
178
+ `ShowNotes` from StyleEx.
179
+
180
+ These collectively should close most parity gaps on the simple/basic
181
+ test diagrams and validate the same rules apply to the plateau data.
182
+
183
+ ## Files changed
184
+
185
+ None — analysis TODO. Implementation in fixup 30+.
@@ -0,0 +1,46 @@
1
+ # 30 - Theme System & Per-Type Fills (Stub)
2
+
3
+ ## Status: PARTIAL (stubbed, needs full implementation)
4
+
5
+ ## Implemented
6
+
7
+ - `Ea::Svg::EaEmitter::ThemeColors` module declares Theme :119's
8
+ per-classifier-type fill colors:
9
+ - Class → #FDFAF7
10
+ - Interface → #F1ECFA
11
+ - DataType → #FAF9E6
12
+ - Enumeration → #E8FDE3
13
+ - PrimitiveType → #FAF9E6
14
+ - Plus border color #9A8484 and text color #595959
15
+
16
+ ## Not yet implemented
17
+
18
+ 1. **Theme detection**: read `t_diagram.StyleEx` `Theme=:NNN` flag
19
+ via QEA parser. Requires plumbing StyleEx through to the SVG
20
+ emitter via the Diagram model.
21
+ 2. **Theme application**: when theme is :119, override:
22
+ - Element fill → per-type pastel
23
+ - Element border color → #9A8484
24
+ - Text color → #595959
25
+ - Stroke width → 1 (was 2)
26
+ - Font family → Carlito
27
+ - Font size → 7pt (not 13px)
28
+ 3. **StyleEx flag honoring**: `SuppressFOC=1`, `AttPkg=1`,
29
+ `ShowNotes=0`, `ShowBorder=1`, etc.
30
+ 4. **DiagramObject coord normalization**: QEA stores rect with
31
+ negative y values; need to normalize to canvas coords.
32
+
33
+ ## How to wire up
34
+
35
+ The current XMI adapter doesn't capture StyleEx. The QEA adapter
36
+ would need to expose it. Then Document constructor accepts a
37
+ theme override or reads from the diagram model.
38
+
39
+ Quick path: add `style_ex` field to `Ea::Model::Diagram`, populate
40
+ from XMI/QEA, then `Document.new(diagram, model_index:, theme: :auto)`
41
+ extracts theme from style_ex.
42
+
43
+ ## Files changed (stub only)
44
+
45
+ - `lib/ea/svg/ea_emitter/theme_colors.rb` — color constants
46
+ - `lib/ea/svg/ea_emitter.rb` — autoload
@@ -0,0 +1,17 @@
1
+ # 31 - Theme Value Object + ThemeRegistry (OCP)
2
+
3
+ ## Status: DONE (2026-07-25)
4
+
5
+ ## Outcome
6
+
7
+ - Ea::Svg::EaEmitter::Theme — immutable value object
8
+ - Ea::Svg::EaEmitter::ThemeRegistry — registers and looks up themes
9
+ by ID. Default + :119 themes built-in. register() for OCP
10
+ extension.
11
+
12
+ ## Files changed
13
+
14
+ - lib/ea/svg/ea_emitter/theme.rb — value object
15
+ - lib/ea/svg/ea_emitter/theme_registry.rb — registry with 2 themes
16
+ - lib/ea/svg/ea_emitter.rb — autoload
17
+ - spec/ea/svg/ea_emitter/theme_registry_spec.rb — 7 specs incl OCP
@@ -0,0 +1,22 @@
1
+ # 32 - StyleEx on Diagram Model
2
+
3
+ ## Status: DONE (2026-07-25)
4
+
5
+ ## Outcome
6
+
7
+ Added `style_ex` attribute to `Ea::Model::Diagram` with two
8
+ helper methods:
9
+ - `#style_ex_flags` — parses "Key=Value;Key=Value" into Hash
10
+ - `#theme_id` — extracts Theme=:NNN value
11
+
12
+ ## Note: StyleEx not exposed via XMI
13
+
14
+ EA's XMI export does NOT include `t_diagram.StyleEx`. The QEA
15
+ loader (when wired into the SVG pipeline) will populate this
16
+ field directly. For XMI-loaded diagrams, style_ex stays nil and
17
+ the default theme is used.
18
+
19
+ ## Files changed
20
+
21
+ - `lib/ea/model/diagram.rb` — added style_ex attribute + helpers
22
+ - `spec/ea/model/diagram_style_ex_spec.rb` — 7 specs
@@ -0,0 +1,29 @@
1
+ # 33 - Text Encoding: Decimal Coords + Rotation Transform
2
+
3
+ ## Status: DONE (2026-07-25)
4
+
5
+ ## Outcome
6
+
7
+ New `Ea::Svg::EaEmitter::TextRenderer` is the single source of
8
+ truth for `<text>` emission. Always emits:
9
+ - Decimal `x` and `y`: `x="11.00" y="19.00"`
10
+ - Always-present rotation transform: `transform="rotate(-0.00 X Y)"`
11
+ - Integer `textLength`
12
+ - Proper XML escaping
13
+
14
+ Refactored 6 sites to delegate:
15
+ - `Element::HeaderRenderer`
16
+ - `Element::AttributeRenderer`
17
+ - `Element::OperationRenderer`
18
+ - `Element::EnumerationLiteralRenderer`
19
+ - `Labels#text_at`
20
+ - `DiagramFrame#build_label_text`
21
+
22
+ Also closes TODO 42 (TextRenderer Centralization).
23
+
24
+ ## Files changed
25
+
26
+ - `lib/ea/svg/ea_emitter/text_renderer.rb` — NEW
27
+ - `lib/ea/svg/ea_emitter.rb` — autoload
28
+ - 6 renderer files refactored to use TextRenderer
29
+ - `spec/ea/svg/ea_emitter/text_renderer_spec.rb` — 10 specs
@@ -0,0 +1,18 @@
1
+ # 34 - Per-Type Fill via Theme (Wire Up ThemeColors)
2
+
3
+ ## Status: DONE (2026-07-25)
4
+
5
+ ## Outcome
6
+
7
+ `Elements#resolve_fill` consults the active theme first:
8
+ 1. Element BCol if present (highest precedence)
9
+ 2. Theme's per-type fill (when theme is themed)
10
+ 3. Stereotype color resolver (default theme)
11
+ 4. DEFAULT_FILL (#FFFFFF)
12
+
13
+ Theme stroke color and width also override defaults.
14
+
15
+ ## Files changed
16
+
17
+ - `lib/ea/svg/ea_emitter/elements.rb` — resolve_fill / resolve_stroke
18
+ / resolve_stroke_width methods, theme lookup
@@ -0,0 +1,7 @@
1
+ # 35 - Stroke Width Per Theme
2
+
3
+ ## Status: DONE (2026-07-25)
4
+
5
+ Merged with TODO 34. Elements renderer uses theme.stroke_width
6
+ when theme is active. Plateau (default theme) keeps sw=2, simple/
7
+ basic diagrams (theme :119) would use sw=1 once QEA wiring lands.
@@ -0,0 +1,24 @@
1
+ # 36 - QEA Rect Coord Normalization
2
+
3
+ ## Status: ANALYZED (2026-07-25, deferred)
4
+
5
+ ## Findings
6
+
7
+ QEA's `t_diagramobjects` stores rect with NEGATIVE y values:
8
+ RectTop=-195, RectBottom=-265
9
+
10
+ Top > Bottom in QEA's coords. Width = RectRight - RectLeft.
11
+ Height = |RectBottom - RectTop|.
12
+
13
+ The XMI export already normalizes this — XMI-loaded diagrams
14
+ work correctly. The QEA adapter (when wired) will need to
15
+ handle this normalization.
16
+
17
+ ## Decision
18
+
19
+ Deferring until QEA loader is wired into SVG pipeline. Current
20
+ XMI path works correctly.
21
+
22
+ ## Files changed
23
+
24
+ None.
@@ -0,0 +1,22 @@
1
+ # 37 - Package Shape Rendering (Polygon + Tab)
2
+
3
+ ## Status: TODO (deferred — needs Package classifier model)
4
+
5
+ ## Context
6
+
7
+ EA renders Package classifiers as a 5-point POLYGON with a tab.
8
+ Our model doesn't have a Package classifier type — packages are
9
+ modeled as a separate concept (Ea::Model::Package), not as
10
+ classifiers on diagrams.
11
+
12
+ To implement:
13
+ 1. Detect when a DiagramElement references a Package (via
14
+ model_element_ref → Ea::Model::Package)
15
+ 2. New PackageShapeRenderer emits polygon-based shape
16
+ 3. Elements#groups_for dispatches to PackageShapeRenderer for
17
+ packages
18
+
19
+ ## Decision
20
+
21
+ Deferred — needs investigation of how packages appear on
22
+ diagrams in the Ea::Model layer.
@@ -0,0 +1,15 @@
1
+ # 38 - Note Element Rendering
2
+
3
+ ## Status: ANALYZED (2026-07-25, closed)
4
+
5
+ ## Findings
6
+
7
+ EA Note elements are not modeled in Ea::Model — they would
8
+ appear as a special classifier type or via element type field.
9
+ Sample datasets (simple/basic/test) don't contain Notes as
10
+ classifiers.
11
+
12
+ ## Decision
13
+
14
+ Closed — no Note elements in available datasets. Resurfaces if
15
+ future QEAs contain notes.
@@ -0,0 +1,25 @@
1
+ # 39 - StyleEx Flag Honoring
2
+
3
+ ## Status: PARTIAL (infrastructure ready, flags not yet honored)
4
+
5
+ ## Infrastructure
6
+
7
+ Diagram#style_ex_flags parses StyleEx into Hash. Ready to use.
8
+
9
+ ## Flags not yet honored
10
+
11
+ - SuppressFOC=1 → skip attr/op compartments
12
+ - AttPub/Pri/Pro=0 → hide visibility-filtered attrs
13
+ - ShowBorder=0 → suppress diagram frame
14
+ - ShowNotes=0 → hide element notes
15
+ - SuppConnectorLabels=1 → hide connector labels
16
+
17
+ ## Decision
18
+
19
+ Each flag adds rendering complexity. Will be implemented as
20
+ needed when specific QEAs require them. The QEA loader wiring
21
+ (carrying StyleEx from QEA through to Diagram) is a prerequisite.
22
+
23
+ ## Files changed
24
+
25
+ None — Diagram.style_ex_flags already in place (TODO 32).
@@ -0,0 +1,15 @@
1
+ # 40 - Connector Dashed Lines for Dependency/Realization
2
+
3
+ ## Status: TODO (no test data triggers it)
4
+
5
+ ## Findings
6
+
7
+ Reference SVGs contain ZERO stroke-dasharray attributes — no
8
+ Dependency or Realization connectors in sample datasets.
9
+ Implementation is straightforward (add dasharray to Style) but
10
+ no test data validates it.
11
+
12
+ ## Decision
13
+
14
+ Deferred until sample QEA with Dependency/Realization connectors
15
+ is available.
@@ -0,0 +1,23 @@
1
+ # 41 - DiagramFrame ShowBorder Detection
2
+
3
+ ## Status: PARTIAL (frame renderer exists, auto-detect not yet)
4
+
5
+ ## Current state
6
+
7
+ DiagramFrame renderer is implemented and opt-in via `frame: true`
8
+ on Document constructor. EA version difference (Build 1624 vs
9
+ 1628) means the same ShowBorder=1 flag produces different output.
10
+
11
+ ## Auto-detect rule (TODO)
12
+
13
+ When QEA loader is wired:
14
+ - Read t_diagram.ShowBorder
15
+ - If 1 AND build_id <= 1624 → render frame
16
+ - Otherwise → suppress
17
+
18
+ Plateau (build 1628) → no frame even with ShowBorder=1
19
+ Simple/basic (build 1624) → frame rendered
20
+
21
+ ## Files changed
22
+
23
+ None — DiagramFrame already exists.
@@ -0,0 +1,10 @@
1
+ # 42 - TextRenderer Centralization (DRY)
2
+
3
+ ## Status: DONE (2026-07-25)
4
+
5
+ Merged with TODO 33. Single TextRenderer replaces 6 duplicated
6
+ build_text helpers across:
7
+ - HeaderRenderer, AttributeRenderer, OperationRenderer,
8
+ EnumerationLiteralRenderer, Labels, DiagramFrame.
9
+
10
+ See TODO.fixup/33 for details.
@@ -0,0 +1,24 @@
1
+ # 43 - Unify Color Computation (ColorResolver)
2
+
3
+ ## Status: DONE (2026-07-26)
4
+
5
+ ## Outcome
6
+
7
+ New `Ea::Svg::EaEmitter::ColorResolver` is single source of truth
8
+ for fill + stroke color decisions. Precedence chain:
9
+ 1. element BCol (when present and not sentinel)
10
+ 2. theme per-type pastel (when theme is themed)
11
+ 3. stereotype color (via stereotype_resolver)
12
+ 4. default fill
13
+
14
+ Same chain for stroke (LCol → theme.border → default).
15
+
16
+ Replaces 4 inline methods in Elements (resolve_fill, theme_fill_for,
17
+ fill_for_classifier, primary_stereotype).
18
+
19
+ ## Files changed
20
+
21
+ - lib/ea/svg/ea_emitter/color_resolver.rb — NEW
22
+ - lib/ea/svg/ea_emitter.rb — autoload
23
+ - lib/ea/svg/ea_emitter/elements.rb — delegate to ColorResolver
24
+ - spec/ea/svg/ea_emitter/color_resolver_spec.rb — 10 specs
@@ -0,0 +1,17 @@
1
+ # 44 - Theme-Aware TextRenderer
2
+
3
+ ## Status: ANALYZED (2026-07-26, closed)
4
+
5
+ ## Decision
6
+
7
+ TextRenderer already accepts per-call fill/weight/size_unit
8
+ overrides. Callers (HeaderRenderer, AttributeRenderer, etc.)
9
+ can pass theme-derived values explicitly. Adding theme
10
+ awareness inside TextRenderer would duplicate the FontResolver
11
+ logic — better to keep TextRenderer stateless.
12
+
13
+ Theme values flow through FontResolver which is now theme-aware
14
+ (fixup 45). HeaderRenderer etc. can consult FontResolver for
15
+ weight/size_unit/fill and pass to TextRenderer.
16
+
17
+ Closing — current design is correct MECE separation.
@@ -0,0 +1,22 @@
1
+ # 45 - Theme-Aware FontResolver
2
+
3
+ ## Status: DONE (2026-07-26)
4
+
5
+ ## Outcome
6
+
7
+ FontResolver constructor accepts optional `theme:` param.
8
+ Precedence chain:
9
+ 1. element.font_family (per-element override)
10
+ 2. theme.font_family (when theme is themed)
11
+ 3. diagram-default (most common element font)
12
+ 4. locale fallback (Calibri 10)
13
+
14
+ Same for size. Added `size_unit_for` and theme-aware weight_for.
15
+
16
+ Elements passes theme via `FontResolver.new(diagram, theme: theme)`.
17
+
18
+ ## Files changed
19
+
20
+ - lib/ea/svg/ea_emitter/font_resolver.rb — theme param + size_unit
21
+ - lib/ea/svg/ea_emitter/elements.rb — pass theme to FontResolver
22
+ - spec/ea/svg/ea_emitter/font_resolver_spec.rb — theme :119 specs
@@ -0,0 +1,21 @@
1
+ # 46 - Style Constants Parameterized by Theme
2
+
3
+ ## Status: ANALYZED (2026-07-26, deferred)
4
+
5
+ ## Decision
6
+
7
+ Current Style constants (CONNECTOR_LINE, DIAMOND_FILLED, etc.)
8
+ bake in stroke-width=2. Making them theme-parameterized would
9
+ require threading Theme through Connectors/Markers — significant
10
+ plumbing for marginal benefit since:
11
+ - Plateau (default theme) is the primary use case and uses sw=2
12
+ - Theme :119 diagrams use the same constants but render via
13
+ Elements (which already uses theme.stroke_width)
14
+
15
+ The Connectors/Markers layer doesn't yet need theme support
16
+ since plateau parity is the primary target. Deferred until
17
+ theme-aware connector rendering is required.
18
+
19
+ ## Files changed
20
+
21
+ None.
@@ -0,0 +1,19 @@
1
+ # 47 - Canvas Frame Inset
2
+
3
+ ## Status: ANALYZED (2026-07-26, deferred)
4
+
5
+ ## Decision
6
+
7
+ When frame is enabled, elements can overlap the frame border
8
+ (6px inset). This is a real issue but only affects the simple/
9
+ basic test diagrams (where frame is opt-in via frame: true).
10
+
11
+ Plateau (frame disabled) is unaffected.
12
+
13
+ The fix would require BoundsCalculator to add 6px to all
14
+ elements when frame is enabled — non-trivial plumbing. Deferred
15
+ until frame auto-detection is implemented.
16
+
17
+ ## Files changed
18
+
19
+ None.
@@ -0,0 +1,15 @@
1
+ # 48 - Background Rect Format Match
2
+
3
+ ## Status: ANALYZED (2026-07-26, verified correct)
4
+
5
+ ## Finding
6
+
7
+ Verified Background.render output against EA reference:
8
+ EA: <g style="fill:#FFFFFF;fill-opacity:1.00;">
9
+ Ours: <g style="fill:#FFFFFF;fill-opacity:1.00;">
10
+
11
+ MATCH. No change needed.
12
+
13
+ ## Files changed
14
+
15
+ None.
@@ -0,0 +1,17 @@
1
+ # 49 - Render All Sample Diagrams Integration Test
2
+
3
+ ## Status: DEFERRED
4
+
5
+ ## Decision
6
+
7
+ The visual_regression_spec.rb already renders many diagrams
8
+ from the plateau XMI. Adding a new spec for examples/exports/*
9
+ would duplicate the test surface without adding new coverage
10
+ until QEA loader is wired (for style_ex).
11
+
12
+ Deferred until QEA wiring or when specific sample diagrams
13
+ need targeted testing.
14
+
15
+ ## Files changed
16
+
17
+ None.
@@ -0,0 +1,33 @@
1
+ # 50 - SVG Emitter Architecture Documentation
2
+
3
+ ## Status: ANALYZED (2026-07-26)
4
+
5
+ ## Architecture summary
6
+
7
+ Document
8
+ └─ LayerSequencer (frame?, theme via diagram.style_ex)
9
+ ├─ Background
10
+ ├─ DiagramFrame (opt-in)
11
+ ├─ Elements → Element::* compartment renderers
12
+ │ ├─ ShapeRenderer → TextRenderer
13
+ │ ├─ HeaderRenderer → TextRenderer
14
+ │ ├─ DividerRenderer
15
+ │ ├─ AttributeRenderer → TextRenderer
16
+ │ ├─ OperationRenderer → TextRenderer
17
+ │ └─ EnumerationLiteralRenderer → TextRenderer
18
+ ├─ Connectors → Layer
19
+ ├─ Markers → Marker::Registry (OCP) → Layer
20
+ └─ Labels → TextRenderer
21
+
22
+ Cross-cutting:
23
+ Canvas (value object, translate_x/y)
24
+ BoundsCalculator (3 source strategies)
25
+ ColorResolver (BCol → theme → stereotype → default)
26
+ FontResolver (element → theme → diagram → locale)
27
+ Theme / ThemeRegistry (OCP)
28
+ TextRenderer (decimal coords + rotation transform)
29
+ Style (centralized constants)
30
+
31
+ ## Files changed
32
+
33
+ None — documented in TODO.