ea 0.4.0 → 0.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (529) hide show
  1. checksums.yaml +4 -4
  2. data/Rakefile +3 -0
  3. data/TODO.complete/01-t-xref-parsing.md +91 -0
  4. data/TODO.complete/02-per-label-geometry.md +50 -0
  5. data/TODO.complete/03-object-properties-constraints.md +57 -0
  6. data/TODO.complete/04-operation-params.md +37 -0
  7. data/TODO.complete/05-pdata-flag-matrix.md +52 -0
  8. data/TODO.complete/06-emf-image-rendering.md +34 -0
  9. data/TODO.complete/07-auxiliary-tables.md +47 -0
  10. data/TODO.complete/10-mdg-stereotype-registry.md +40 -0
  11. data/TODO.complete/11-gml-xsd-generation.md +42 -0
  12. data/TODO.complete/13-shapescript-interpreter.md +28 -0
  13. data/TODO.complete/20-cli-diff.md +46 -0
  14. data/TODO.complete/21-cli-render.md +26 -0
  15. data/TODO.complete/22-cli-export.md +29 -0
  16. data/TODO.complete/23-cli-mdg.md +23 -0
  17. data/TODO.complete/30-headerlines-ocp-refactor.md +72 -0
  18. data/TODO.complete/31-public-send-cleanup.md +61 -0
  19. data/TODO.complete/32-spec-coverage.md +33 -0
  20. data/TODO.complete/33-blocked-parity-gaps.md +41 -0
  21. data/TODO.complete/36-stereotype-icon-wiring.md +32 -0
  22. data/TODO.complete/37-cli-lint.md +32 -0
  23. data/TODO.complete/38-cli-query.md +26 -0
  24. data/TODO.complete/39-cli-info.md +23 -0
  25. data/TODO.complete/40-ocl-evaluator.md +31 -0
  26. data/TODO.complete/41-round-trip-spec.md +18 -0
  27. data/TODO.complete/42-html-diff-report.md +18 -0
  28. data/TODO.complete/43-json-schema-export.md +20 -0
  29. data/TODO.complete/44-remaining-qea-tables.md +40 -0
  30. data/TODO.complete/45-shapescript-extensions.md +25 -0
  31. data/TODO.complete/46-xsd-consolidation.md +20 -0
  32. data/TODO.complete/47-headerlines-legacy-removal.md +20 -0
  33. data/TODO.complete/STATUS.md +109 -0
  34. data/TODO.diagrams/01-svg-measurement-harness.md +31 -0
  35. data/TODO.diagrams/02-polygon-over-rendering.md +29 -0
  36. data/TODO.diagrams/03-text-over-rendering.md +30 -0
  37. data/TODO.diagrams/04-rect-under-rendering.md +33 -0
  38. data/TODO.diagrams/05-canvas-dimension-parity.md +51 -0
  39. data/TODO.diagrams/06-group-layering-parity.md +39 -0
  40. data/TODO.diagrams/07-text-content-fidelity.md +65 -0
  41. data/TODO.diagrams/08-qea-direct-pipeline.md +46 -0
  42. data/TODO.diagrams/12-connector-labels.md +40 -0
  43. data/TODO.diagrams/12-per-entity-svg-layer-ordering.md +24 -0
  44. data/TODO.diagrams/13-marker-polygon-vs-path-dispatch.md +20 -0
  45. data/TODO.diagrams/13-per-text-type-font-sizes.md +33 -0
  46. data/TODO.diagrams/14-center-header-text.md +33 -0
  47. data/TODO.diagrams/14-filter-diagram-frame-elements.md +18 -0
  48. data/TODO.diagrams/15-deep-dead-code-audit.md +47 -0
  49. data/TODO.diagrams/15-per-element-font-from-style.md +24 -0
  50. data/TODO.diagrams/16-canvas-marker-extent.md +30 -0
  51. data/TODO.diagrams/16-document-remaining-parity-gaps.md +91 -0
  52. data/TODO.diagrams/17-italic-abstract-classes.md +28 -0
  53. data/TODO.diagrams/17-remaining-parity-gaps.md +90 -0
  54. data/TODO.diagrams/18-canvas-from-image-bounds.md +20 -0
  55. data/TODO.diagrams/18-property-lookup-index.md +42 -0
  56. data/TODO.diagrams/19-connector-sx-sy-routing.md +27 -0
  57. data/TODO.diagrams/19-replace-respond-to-with-is-a.md +31 -0
  58. data/TODO.diagrams/20-split-labels-emitter.md +56 -0
  59. data/TODO.diagrams/20-visibility-glyph-font-encoding.md +27 -0
  60. data/TODO.diagrams/21-aggregation-navigability-arrow.md +21 -0
  61. data/TODO.diagrams/21-auto-generated-legend-block.md +65 -0
  62. data/TODO.diagrams/22-ghost-element-discriminator.md +57 -0
  63. data/TODO.diagrams/22-style-based-path-grouping.md +28 -0
  64. data/TODO.diagrams/23-marker-polygon-deduplication.md +47 -0
  65. data/TODO.diagrams/23-multiplicity-label-positioning.md +29 -0
  66. data/TODO.diagrams/24-marker-anchor-structural.md +35 -0
  67. data/TODO.diagrams/24-track-marker-anchors-structurally.md +66 -0
  68. data/TODO.diagrams/24-truncate-properties-to-fit-box.md +24 -0
  69. data/TODO.diagrams/26-phantom-general-parent-rendering.md +59 -0
  70. data/TODO.diagrams/27-path-grouping-mode-detection.md +43 -0
  71. data/TODO.diagrams/28-architecture-cleanup-batch.md +47 -0
  72. data/TODO.diagrams/30-decompose-elements-groups-for.md +52 -0
  73. data/TODO.diagrams/32-examples-coverage-batch.md +78 -0
  74. data/TODO.diagrams/36-instance-specification-model.md +42 -0
  75. data/TODO.diagrams/37-element-icon-decorations.md +41 -0
  76. data/TODO.diagrams/38-html-note-and-receptions.md +32 -0
  77. data/TODO.diagrams/39-property-stereotype-discriminator.md +40 -0
  78. data/TODO.diagrams/40-standalone-1-discriminator.md +38 -0
  79. data/TODO.diagrams/41-xmi-to-svg-pipeline.md +113 -0
  80. data/TODO.diagrams/42-close-all-parity-deltas.md +69 -0
  81. data/TODO.diagrams/43-marker-deduplication-strategy.md +54 -0
  82. data/TODO.diagrams/44-element-icon-decorations.md +34 -0
  83. data/TODO.diagrams/45-phantom-parent-class-boxes.md +40 -0
  84. data/TODO.diagrams/46-user-drawn-legend-swatches.md +44 -0
  85. data/TODO.diagrams/47-attribute-line-fidelity.md +72 -0
  86. data/TODO.diagrams/48-spec-coverage-critical-emitter-components.md +45 -0
  87. data/TODO.diagrams/49-spec-coverage-orchestrators.md +25 -0
  88. data/TODO.diagrams/50-examples-parity.md +85 -0
  89. data/TODO.diagrams/51-property-oy-gap-and-remaining-gaps.md +48 -0
  90. data/TODO.diagrams/52-marker-registration-architecture.md +89 -0
  91. data/TODO.diagrams/53-remaining-example-gaps.md +86 -0
  92. data/TODO.diagrams/54-display-name-nested-classes.md +40 -0
  93. data/TODO.diagrams/55-visibility-icon-discriminator.md +58 -0
  94. data/TODO.diagrams/56-package-contents-rendering.md +148 -0
  95. data/TODO.diagrams/57-instance-specification-model.md +100 -0
  96. data/TODO.diagrams/58-domain-model-note-text.md +67 -0
  97. data/TODO.diagrams/59-classes-arrow-discriminator.md +57 -0
  98. data/TODO.diagrams/60-testschema-association-marker.md +40 -0
  99. data/TODO.diagrams/61-legend-block-rendering.md +55 -0
  100. data/TODO.diagrams/61-plateau-parity-gaps.md +59 -0
  101. data/TODO.diagrams/62-ghost-element-rendering.md +56 -0
  102. data/TODO.diagrams/63-qualified-name-wrap.md +36 -0
  103. data/TODO.diagrams/64-property-stereotype-labels.md +22 -0
  104. data/TODO.diagrams/65-path-coordinate-frame.md +62 -0
  105. data/TODO.diagrams/67-path-coordinate-frame.md +62 -0
  106. data/TODO.diagrams/68-inherited-attributes.md +65 -0
  107. data/TODO.diagrams/69-package-anchor-conditional.md +29 -0
  108. data/TODO.diagrams/70-mdg-technology-support.md +68 -0
  109. data/TODO.diagrams/71-off-canvas-parent-ghost.md +45 -0
  110. data/TODO.diagrams/72-basic-attr-divider-paths.md +39 -0
  111. data/TODO.diagrams/73-plateau-polygon-gap.md +69 -0
  112. data/TODO.diagrams/74-plateau-rect-gap.md +22 -0
  113. data/TODO.diagrams/75-plateau-text-gap.md +39 -0
  114. data/TODO.diagrams/76-basic-poly-path-gaps.md +41 -0
  115. data/TODO.diagrams/77-basic-text-overrender.md +40 -0
  116. data/TODO.diagrams/78-headerlines-ocp-refactor.md +65 -0
  117. data/TODO.diagrams/79-architecture-backlog.md +65 -0
  118. data/TODO.diagrams/80-basic-triangle-polygons.md +51 -0
  119. data/TODO.diagrams/81-plateau-path-overrender.md +53 -0
  120. data/TODO.diagrams/82-appearance-canvas-offset.md +54 -0
  121. data/TODO.diagrams/83-3d-diagram-subtitle.md +58 -0
  122. data/TODO.diagrams/84-canvas-offset-mismatches.md +61 -0
  123. data/TODO.diagrams/85-phantom-property-overrender.md +95 -0
  124. data/TODO.diagrams/86-foreign-package-rule.md +62 -0
  125. data/TODO.diagrams/87-internal-tech-encryption.md +80 -0
  126. data/TODO.diagrams/EXAMPLES_STATUS.md +88 -0
  127. data/TODO.diagrams/README.md +69 -0
  128. data/TODO.diagrams/STATUS.md +73 -0
  129. data/TODO.fixup/01-default-grouped-paths.md +34 -0
  130. data/TODO.fixup/02-marker-consolidation-per-connector.md +20 -0
  131. data/TODO.fixup/03-diagram-font-inference.md +28 -0
  132. data/TODO.fixup/04-extract-bounds-calculator.md +25 -0
  133. data/TODO.fixup/05-marker-registry-ocp.md +32 -0
  134. data/TODO.fixup/06-connector-path-bend-routing.md +28 -0
  135. data/TODO.fixup/07-edge-attachment-formula.md +22 -0
  136. data/TODO.fixup/08-visual-diff-harness.md +28 -0
  137. data/TODO.fixup/09-extract-element-compartments.md +34 -0
  138. data/TODO.fixup/10-canvas-width-overshoot-fix.md +20 -0
  139. data/TODO.fixup/11-layer-sequencer-extraction.md +18 -0
  140. data/TODO.fixup/12-path-style-harmony.md +23 -0
  141. data/TODO.fixup/13-datatype-stereotype-fallback.md +28 -0
  142. data/TODO.fixup/14-ea-exe-reverse-engineering-notes.md +56 -0
  143. data/TODO.fixup/15-enumeration-literal-rendering.md +30 -0
  144. data/TODO.fixup/16-operation-compartment-rendering.md +42 -0
  145. data/TODO.fixup/17-path-count-calibration.md +27 -0
  146. data/TODO.fixup/18-polygon-count-calibration.md +32 -0
  147. data/TODO.fixup/19-rect-count-undershoot-investigation.md +40 -0
  148. data/TODO.fixup/20-stereotype-color-from-classifier.md +18 -0
  149. data/TODO.fixup/21-visibility-filter-for-properties.md +24 -0
  150. data/TODO.fixup/22-multiplicity-display-rule-calibration.md +25 -0
  151. data/TODO.fixup/23-diagram-frame-title-element.md +31 -0
  152. data/TODO.fixup/24-note-element-rendering.md +23 -0
  153. data/TODO.fixup/25-ea-exe-disassembly-findings.md +177 -0
  154. data/TODO.fixup/26-svg-renderer-architecture.md +78 -0
  155. data/TODO.fixup/27-svg-element-emitters-disassembly.md +135 -0
  156. data/TODO.fixup/28-geometry-parser-identification.md +57 -0
  157. data/TODO.fixup/29-qea-svg-xmi-triple-comparison.md +185 -0
  158. data/TODO.fixup/30-theme-system-stub.md +46 -0
  159. data/TODO.fixup/31-theme-value-object-registry.md +17 -0
  160. data/TODO.fixup/32-styleex-on-diagram-model.md +22 -0
  161. data/TODO.fixup/33-text-encoding-decimals-rotation.md +29 -0
  162. data/TODO.fixup/34-per-type-fill-via-theme.md +18 -0
  163. data/TODO.fixup/35-stroke-width-per-theme.md +7 -0
  164. data/TODO.fixup/36-qea-rect-coord-normalization.md +24 -0
  165. data/TODO.fixup/37-package-shape-rendering.md +22 -0
  166. data/TODO.fixup/38-note-element-rendering.md +15 -0
  167. data/TODO.fixup/39-styleex-flag-honoring.md +25 -0
  168. data/TODO.fixup/40-connector-dashed-lines.md +15 -0
  169. data/TODO.fixup/41-diagram-frame-showborder-detection.md +23 -0
  170. data/TODO.fixup/42-textrenderer-centralization.md +10 -0
  171. data/TODO.fixup/43-colorresolver-unification.md +24 -0
  172. data/TODO.fixup/44-theme-aware-textrenderer.md +17 -0
  173. data/TODO.fixup/45-theme-aware-fontresolver.md +22 -0
  174. data/TODO.fixup/46-style-parameterized-by-theme.md +21 -0
  175. data/TODO.fixup/47-canvas-frame-inset.md +19 -0
  176. data/TODO.fixup/48-background-rect-format.md +15 -0
  177. data/TODO.fixup/49-all-samples-integration-test.md +17 -0
  178. data/TODO.fixup/50-svg-emitter-architecture-docs.md +33 -0
  179. data/TODO.fixup/51-promote-theme-to-ea-namespace.md +28 -0
  180. data/TODO.fixup/52-theme-definition-integrated-fills.md +26 -0
  181. data/TODO.fixup/53-theme-registry-yaml-loading.md +50 -0
  182. data/TODO.fixup/54-diagram-theme-api.md +50 -0
  183. data/TODO.fixup/55-update-eaemitter-to-ea-theme.md +23 -0
  184. data/TODO.fixup/56-theme-yaml-files.md +65 -0
  185. data/TODO.fixup/57-theme-specs-and-integration.md +27 -0
  186. data/TODO.fixup/58-ea-entry-point-theme-autoload.md +20 -0
  187. data/TODO.fixup/59-thread-theme-through-all-renderers.md +29 -0
  188. data/TODO.fixup/60-cli-theme-option.md +22 -0
  189. data/TODO.fixup/61-theme-validation.md +28 -0
  190. data/TODO.fixup/62-theme-builder-dsl.md +31 -0
  191. data/TODO.fixup/63-theme-integration-rendering-spec.md +24 -0
  192. data/TODO.fixup/64-theme-writeback-styleex.md +21 -0
  193. data/TODO.fixup/65-remove-dead-eaemitter-theme-files.md +30 -0
  194. data/TODO.fixup/66-styleex-writeback.md +22 -0
  195. data/TODO.fixup/67-delete-dead-code.md +28 -0
  196. data/TODO.fixup/68-figure-parity-status.md +82 -0
  197. data/TODO.fixup/69-package-polygon-rendering.md +54 -0
  198. data/TODO.fixup/70-tagged-values-compartment.md +39 -0
  199. data/TODO.fixup/71-auto-detect-theme-from-xmi.md +37 -0
  200. data/TODO.fixup/72-sample-exports-as-regression-specs.md +37 -0
  201. data/TODO.fixup/73-delete-dead-transformations.md +14 -0
  202. data/TODO.fixup/74-delete-dead-diagram-renderers.md +18 -0
  203. data/TODO.fixup/75-visibility-legend-icons.md +23 -0
  204. data/TODO.fixup/76-plateau-text-undershoot.md +27 -0
  205. data/TODO.fixup/77-canvas-frame-margins.md +28 -0
  206. data/TODO.fixup/78-note-element-rendering.md +30 -0
  207. data/TODO.fixup/79-operation-compartment-rendering.md +27 -0
  208. data/TODO.fixup/80-tagged-value-stereotype-visibility.md +37 -0
  209. data/TODO.fixup/81-figure-parity-current-state.md +63 -0
  210. data/config/qea_schema.yml +356 -0
  211. data/config/themes/119.yml +98 -0
  212. data/config/themes/default.yml +14 -0
  213. data/examples/exports/20251010_current_plateau_v5/UML_EA.DTD +6856 -0
  214. data/examples/exports/20251010_current_plateau_v5/model.xml +96709 -0
  215. data/examples/exports/ArcGISWorkspace_template/UML_EA.DTD +6856 -0
  216. data/examples/exports/ArcGISWorkspace_template/model.xml +1427 -0
  217. data/examples/exports/UmlModel_template/UML_EA.DTD +6856 -0
  218. data/examples/exports/UmlModel_template/model.xml +23 -0
  219. data/examples/exports/basic/UML_EA.DTD +6856 -0
  220. data/examples/exports/basic/model.xml +8039 -0
  221. data/examples/exports/simple/UML_EA.DTD +6856 -0
  222. data/examples/exports/simple/model.xml +585 -0
  223. data/examples/exports/simple_example/UML_EA.DTD +6856 -0
  224. data/examples/exports/simple_example/model.xml +23 -0
  225. data/examples/exports/test/UML_EA.DTD +6856 -0
  226. data/examples/exports/test/model.xml +1638 -0
  227. data/examples/qea/basic.qea +0 -0
  228. data/frontend/README.md +51 -0
  229. data/frontend/dist/app.iife.js +24 -0
  230. data/frontend/dist/style.css +1 -0
  231. data/frontend/index.html +26 -0
  232. data/frontend/package-lock.json +2359 -0
  233. data/frontend/package.json +26 -0
  234. data/frontend/src/App.vue +59 -0
  235. data/frontend/src/app.ts +8 -0
  236. data/frontend/src/components/AppHeader.vue +127 -0
  237. data/frontend/src/components/AppSidebar.vue +119 -0
  238. data/frontend/src/components/ClassDetails.vue +247 -0
  239. data/frontend/src/components/DiagramView.vue +79 -0
  240. data/frontend/src/components/PackageDetails.vue +92 -0
  241. data/frontend/src/components/PackageTreeNode.vue +64 -0
  242. data/frontend/src/components/SearchResults.vue +48 -0
  243. data/frontend/src/components/WelcomeView.vue +87 -0
  244. data/frontend/src/shims-vue.d.ts +5 -0
  245. data/frontend/src/stores/dataStore.ts +79 -0
  246. data/frontend/src/stores/uiStore.ts +167 -0
  247. data/frontend/src/styles/main.css +1566 -0
  248. data/frontend/src/types.ts +221 -0
  249. data/frontend/tests/e2e/__screenshots__/new-dark-mode.png +0 -0
  250. data/frontend/tests/e2e/__screenshots__/new-package-details.png +0 -0
  251. data/frontend/tests/e2e/__screenshots__/new-search-modal.png +0 -0
  252. data/frontend/tests/e2e/__screenshots__/new-sidebar-collapsed.png +0 -0
  253. data/frontend/tests/e2e/__screenshots__/new-welcome.png +0 -0
  254. data/frontend/tests/e2e/render.spec.ts +188 -0
  255. data/frontend/tsconfig.json +20 -0
  256. data/frontend/vite.config.ts +26 -0
  257. data/frontend/vitest.config.ts +8 -0
  258. data/lib/ea/cli/app.rb +57 -2
  259. data/lib/ea/cli/command/diagrams.rb +37 -28
  260. data/lib/ea/cli/command/diff.rb +46 -0
  261. data/lib/ea/cli/command/export.rb +80 -0
  262. data/lib/ea/cli/command/info.rb +75 -0
  263. data/lib/ea/cli/command/lint.rb +48 -0
  264. data/lib/ea/cli/command/mdg.rb +98 -0
  265. data/lib/ea/cli/command/query.rb +34 -0
  266. data/lib/ea/cli/command/render.rb +135 -0
  267. data/lib/ea/cli/command/svg.rb +8 -15
  268. data/lib/ea/cli/command.rb +7 -0
  269. data/lib/ea/diagram/display_config.rb +184 -0
  270. data/lib/ea/diagram.rb +4 -41
  271. data/lib/ea/diff/change.rb +30 -0
  272. data/lib/ea/diff/comparator.rb +82 -0
  273. data/lib/ea/diff/html_reporter.rb +91 -0
  274. data/lib/ea/diff.rb +15 -0
  275. data/lib/ea/export/json/generator.rb +42 -0
  276. data/lib/ea/export/json.rb +12 -0
  277. data/lib/ea/export/json_schema/generator.rb +77 -0
  278. data/lib/ea/export/json_schema.rb +12 -0
  279. data/lib/ea/export/plantuml/generator.rb +73 -0
  280. data/lib/ea/export/plantuml.rb +12 -0
  281. data/lib/ea/export/xmi/generator.rb +77 -0
  282. data/lib/ea/export/xmi.rb +11 -0
  283. data/lib/ea/export/xsd/class_mapping.rb +65 -0
  284. data/lib/ea/export/xsd/generator.rb +142 -0
  285. data/lib/ea/export/xsd/namespace_registry.rb +82 -0
  286. data/lib/ea/export/xsd.rb +19 -0
  287. data/lib/ea/export.rb +14 -0
  288. data/lib/ea/image/emf_renderer.rb +42 -0
  289. data/lib/ea/image.rb +12 -0
  290. data/lib/ea/lint/engine.rb +30 -0
  291. data/lib/ea/lint/lint_rule.rb +38 -0
  292. data/lib/ea/lint/offense.rb +18 -0
  293. data/lib/ea/lint/rules/cyclic_generalization.rb +62 -0
  294. data/lib/ea/lint/rules/duplicate_name.rb +28 -0
  295. data/lib/ea/lint/rules/missing_stereotype.rb +35 -0
  296. data/lib/ea/lint/rules/naming_convention.rb +44 -0
  297. data/lib/ea/lint/rules/orphan_element.rb +28 -0
  298. data/lib/ea/lint/rules.rb +14 -0
  299. data/lib/ea/lint.rb +13 -0
  300. data/lib/ea/mdg/document.rb +120 -0
  301. data/lib/ea/mdg/loader.rb +118 -0
  302. data/lib/ea/mdg/registry.rb +98 -0
  303. data/lib/ea/mdg/stereotype_alias_registry.rb +77 -0
  304. data/lib/ea/mdg/xml/applies_to.rb +18 -0
  305. data/lib/ea/mdg/xml/apply.rb +18 -0
  306. data/lib/ea/mdg/xml/content.rb +18 -0
  307. data/lib/ea/mdg/xml/documentation.rb +24 -0
  308. data/lib/ea/mdg/xml/stereotype.rb +28 -0
  309. data/lib/ea/mdg/xml/stereotypes.rb +18 -0
  310. data/lib/ea/mdg/xml/tag.rb +28 -0
  311. data/lib/ea/mdg/xml/tagged_values.rb +18 -0
  312. data/lib/ea/mdg/xml/technology.rb +28 -0
  313. data/lib/ea/mdg/xml/uml_profile.rb +22 -0
  314. data/lib/ea/mdg/xml/uml_profiles.rb +18 -0
  315. data/lib/ea/mdg/xml.rb +24 -0
  316. data/lib/ea/mdg.rb +25 -0
  317. data/lib/ea/model/classifier.rb +4 -0
  318. data/lib/ea/model/constraint.rb +24 -0
  319. data/lib/ea/model/diagram.rb +85 -0
  320. data/lib/ea/model/diagram_connector.rb +34 -0
  321. data/lib/ea/model/diagram_element.rb +16 -0
  322. data/lib/ea/model/document.rb +47 -2
  323. data/lib/ea/model/ghost_label.rb +32 -0
  324. data/lib/ea/model/instance_specification.rb +34 -0
  325. data/lib/ea/model/legend.rb +43 -0
  326. data/lib/ea/model/legend_item.rb +26 -0
  327. data/lib/ea/model/note.rb +28 -0
  328. data/lib/ea/model/operation.rb +2 -0
  329. data/lib/ea/model/property.rb +2 -0
  330. data/lib/ea/model/relationship.rb +2 -0
  331. data/lib/ea/model/signal.rb +14 -0
  332. data/lib/ea/model/slot.rb +19 -0
  333. data/lib/ea/model.rb +8 -0
  334. data/lib/ea/ocl/evaluator.rb +94 -0
  335. data/lib/ea/ocl/nodes.rb +30 -0
  336. data/lib/ea/ocl/parser.rb +133 -0
  337. data/lib/ea/ocl/unsupported_error.rb +7 -0
  338. data/lib/ea/ocl.rb +13 -0
  339. data/lib/ea/qea/factory/document_builder.rb +24 -10
  340. data/lib/ea/qea/factory/generalization_builder.rb +9 -11
  341. data/lib/ea/qea/infrastructure/table_reader.rb +9 -0
  342. data/lib/ea/qea/models/ea_author.rb +35 -0
  343. data/lib/ea/qea/models/ea_glossary.rb +34 -0
  344. data/lib/ea/qea/models/ea_image.rb +53 -0
  345. data/lib/ea/qea/models/ea_implement.rb +32 -0
  346. data/lib/ea/qea/models/ea_list.rb +42 -0
  347. data/lib/ea/qea/models/ea_object_effort.rb +34 -0
  348. data/lib/ea/qea/models/ea_object_problem.rb +37 -0
  349. data/lib/ea/qea/models/ea_object_require.rb +34 -0
  350. data/lib/ea/qea/models/ea_object_resource.rb +34 -0
  351. data/lib/ea/qea/models/ea_object_risk.rb +34 -0
  352. data/lib/ea/qea/models/ea_object_scenario.rb +34 -0
  353. data/lib/ea/qea/models/ea_object_test.rb +35 -0
  354. data/lib/ea/qea/models/ea_object_trx.rb +34 -0
  355. data/lib/ea/qea/models/ea_operation.rb +7 -0
  356. data/lib/ea/qea/models/ea_palette.rb +30 -0
  357. data/lib/ea/qea/models/ea_palette_item.rb +36 -0
  358. data/lib/ea/qea/models/ea_phase.rb +40 -0
  359. data/lib/ea/qea/models/ea_role_constraint.rb +32 -0
  360. data/lib/ea/qea/models/ea_secrypt.rb +34 -0
  361. data/lib/ea/qea/models/ea_version.rb +39 -0
  362. data/lib/ea/qea/models/ea_xref.rb +11 -1
  363. data/lib/ea/qea/models.rb +19 -0
  364. data/lib/ea/qea/services/database_loader.rb +22 -1
  365. data/lib/ea/query/builder.rb +108 -0
  366. data/lib/ea/query.rb +9 -0
  367. data/lib/ea/render/image_converter.rb +101 -0
  368. data/lib/ea/render.rb +10 -0
  369. data/lib/ea/shapescript/parser.rb +208 -0
  370. data/lib/ea/shapescript/renderer.rb +74 -0
  371. data/lib/ea/shapescript/shape.rb +34 -0
  372. data/lib/ea/shapescript.rb +24 -0
  373. data/lib/ea/sources/qea/adapter.rb +22 -5
  374. data/lib/ea/sources/qea/classifier_builder.rb +184 -7
  375. data/lib/ea/sources/qea/diagram_builder.rb +352 -24
  376. data/lib/ea/sources/qea/id_normalizer.rb +16 -1
  377. data/lib/ea/sources/qea/instance_builder.rb +113 -0
  378. data/lib/ea/sources/qea/legend_builder.rb +137 -0
  379. data/lib/ea/sources/qea/note_builder.rb +58 -0
  380. data/lib/ea/sources/qea/object_classifier_map.rb +6 -1
  381. data/lib/ea/sources/qea/operation_builder.rb +1 -0
  382. data/lib/ea/sources/qea/package_builder.rb +16 -0
  383. data/lib/ea/sources/qea/relationship_builder.rb +21 -5
  384. data/lib/ea/sources/qea/tagged_value_builder.rb +28 -9
  385. data/lib/ea/sources/qea/xref/legend_definition.rb +35 -0
  386. data/lib/ea/sources/qea/xref/parser.rb +150 -0
  387. data/lib/ea/sources/qea/xref/property_definition.rb +29 -0
  388. data/lib/ea/sources/qea/xref/record.rb +41 -0
  389. data/lib/ea/sources/qea/xref/stereotype_application.rb +37 -0
  390. data/lib/ea/sources/qea/xref.rb +27 -0
  391. data/lib/ea/sources/qea.rb +4 -0
  392. data/lib/ea/sources/xmi/adapter.rb +80 -2
  393. data/lib/ea/sources/xmi/classifier_builder.rb +10 -1
  394. data/lib/ea/sources/xmi/diagram_builder.rb +95 -18
  395. data/lib/ea/sources/xmi/extension_geometry_parser.rb +19 -2
  396. data/lib/ea/sources/xmi/extension_style_parser.rb +15 -2
  397. data/lib/ea/sources/xmi/note_builder.rb +46 -0
  398. data/lib/ea/sources/xmi/property_builder.rb +9 -0
  399. data/lib/ea/sources/xmi/stereotype_builder.rb +54 -0
  400. data/lib/ea/sources/xmi/tag_builder.rb +45 -0
  401. data/lib/ea/sources/xmi/umldi_keyword_extractor.rb +87 -0
  402. data/lib/ea/sources/xmi.rb +4 -0
  403. data/lib/ea/spa/output/sharded_multi_file_strategy.rb +18 -3
  404. data/lib/ea/spa/output/single_file_strategy.rb +8 -2
  405. data/lib/ea/spa/output/strategy.rb +34 -0
  406. data/lib/ea/svg/connector_router.rb +134 -0
  407. data/lib/ea/svg/ea_emitter/background.rb +2 -3
  408. data/lib/ea/svg/ea_emitter/bounds_calculator.rb +142 -0
  409. data/lib/ea/svg/ea_emitter/canvas.rb +56 -33
  410. data/lib/ea/svg/ea_emitter/color_resolver.rb +56 -0
  411. data/lib/ea/svg/ea_emitter/compartment/attributes.rb +28 -0
  412. data/lib/ea/svg/ea_emitter/compartment/constraints.rb +30 -0
  413. data/lib/ea/svg/ea_emitter/compartment/enum_literals.rb +86 -0
  414. data/lib/ea/svg/ea_emitter/compartment/header.rb +32 -0
  415. data/lib/ea/svg/ea_emitter/compartment/header_divider.rb +57 -0
  416. data/lib/ea/svg/ea_emitter/compartment/instance_slots.rb +96 -0
  417. data/lib/ea/svg/ea_emitter/compartment/instance_underline.rb +67 -0
  418. data/lib/ea/svg/ea_emitter/compartment/note_body.rb +52 -0
  419. data/lib/ea/svg/ea_emitter/compartment/note_text.rb +102 -0
  420. data/lib/ea/svg/ea_emitter/compartment/operations.rb +38 -0
  421. data/lib/ea/svg/ea_emitter/compartment/package_contents.rb +72 -0
  422. data/lib/ea/svg/ea_emitter/compartment/package_from_parent.rb +136 -0
  423. data/lib/ea/svg/ea_emitter/compartment/shape.rb +82 -0
  424. data/lib/ea/svg/ea_emitter/compartment/tagged_values.rb +30 -0
  425. data/lib/ea/svg/ea_emitter/compartment.rb +58 -0
  426. data/lib/ea/svg/ea_emitter/connectors.rb +46 -12
  427. data/lib/ea/svg/ea_emitter/diagram_frame.rb +143 -0
  428. data/lib/ea/svg/ea_emitter/document.rb +15 -24
  429. data/lib/ea/svg/ea_emitter/element/attribute_line_builder.rb +117 -0
  430. data/lib/ea/svg/ea_emitter/element/attribute_renderer.rb +119 -0
  431. data/lib/ea/svg/ea_emitter/element/bcol_decoder.rb +29 -0
  432. data/lib/ea/svg/ea_emitter/element/compartment_geometry.rb +113 -0
  433. data/lib/ea/svg/ea_emitter/element/constraint_renderer.rb +53 -0
  434. data/lib/ea/svg/ea_emitter/element/divider_renderer.rb +17 -0
  435. data/lib/ea/svg/ea_emitter/element/enumeration_literal_renderer.rb +34 -0
  436. data/lib/ea/svg/ea_emitter/element/filter.rb +44 -0
  437. data/lib/ea/svg/ea_emitter/element/hand_draw_shape_renderer.rb +77 -0
  438. data/lib/ea/svg/ea_emitter/element/header_line_pipeline.rb +43 -0
  439. data/lib/ea/svg/ea_emitter/element/header_line_provider/instance_spec.rb +27 -0
  440. data/lib/ea/svg/ea_emitter/element/header_line_provider/name.rb +76 -0
  441. data/lib/ea/svg/ea_emitter/element/header_line_provider/parent_ghost.rb +25 -0
  442. data/lib/ea/svg/ea_emitter/element/header_line_provider/stereotype_label.rb +68 -0
  443. data/lib/ea/svg/ea_emitter/element/header_line_provider.rb +19 -0
  444. data/lib/ea/svg/ea_emitter/element/header_lines.rb +27 -0
  445. data/lib/ea/svg/ea_emitter/element/header_renderer.rb +48 -0
  446. data/lib/ea/svg/ea_emitter/element/icon_renderer.rb +109 -0
  447. data/lib/ea/svg/ea_emitter/element/legend_renderer.rb +177 -0
  448. data/lib/ea/svg/ea_emitter/element/note_shape_renderer.rb +112 -0
  449. data/lib/ea/svg/ea_emitter/element/operation_renderer.rb +100 -0
  450. data/lib/ea/svg/ea_emitter/element/package_shape_renderer.rb +181 -0
  451. data/lib/ea/svg/ea_emitter/element/row_icon_renderer.rb +156 -0
  452. data/lib/ea/svg/ea_emitter/element/shape_renderer.rb +17 -0
  453. data/lib/ea/svg/ea_emitter/element/stereotype_icon_renderer.rb +82 -0
  454. data/lib/ea/svg/ea_emitter/element/tagged_value_renderer.rb +50 -0
  455. data/lib/ea/svg/ea_emitter/element/text_escape.rb +20 -0
  456. data/lib/ea/svg/ea_emitter/element.rb +37 -0
  457. data/lib/ea/svg/ea_emitter/elements.rb +283 -95
  458. data/lib/ea/svg/ea_emitter/font_resolver.rb +111 -0
  459. data/lib/ea/svg/ea_emitter/ghost_labels.rb +66 -0
  460. data/lib/ea/svg/ea_emitter/label/end_label.rb +266 -0
  461. data/lib/ea/svg/ea_emitter/label/midpoint_label.rb +101 -0
  462. data/lib/ea/svg/ea_emitter/label/registry.rb +50 -0
  463. data/lib/ea/svg/ea_emitter/label.rb +23 -0
  464. data/lib/ea/svg/ea_emitter/labels.rb +93 -27
  465. data/lib/ea/svg/ea_emitter/layer.rb +20 -0
  466. data/lib/ea/svg/ea_emitter/layer_sequencer.rb +93 -0
  467. data/lib/ea/svg/ea_emitter/marker/arrow_path.rb +52 -0
  468. data/lib/ea/svg/ea_emitter/marker/diamond.rb +57 -0
  469. data/lib/ea/svg/ea_emitter/marker/kind.rb +35 -0
  470. data/lib/ea/svg/ea_emitter/marker/open_triangle.rb +27 -0
  471. data/lib/ea/svg/ea_emitter/marker/package_import.rb +39 -0
  472. data/lib/ea/svg/ea_emitter/marker/plus.rb +40 -0
  473. data/lib/ea/svg/ea_emitter/marker/registry.rb +42 -0
  474. data/lib/ea/svg/ea_emitter/marker.rb +37 -0
  475. data/lib/ea/svg/ea_emitter/markers.rb +351 -64
  476. data/lib/ea/svg/ea_emitter/render_context.rb +52 -0
  477. data/lib/ea/svg/ea_emitter/style.rb +15 -0
  478. data/lib/ea/svg/ea_emitter/text_renderer.rb +92 -0
  479. data/lib/ea/svg/ea_emitter.rb +33 -11
  480. data/lib/ea/svg/parity/checker.rb +105 -0
  481. data/lib/ea/svg/parity/source.rb +59 -0
  482. data/lib/ea/svg/parity/suite.rb +113 -0
  483. data/lib/ea/svg/parity.rb +14 -0
  484. data/lib/ea/svg.rb +2 -15
  485. data/lib/ea/theme/definition.rb +176 -0
  486. data/lib/ea/theme/loader.rb +125 -0
  487. data/lib/ea/theme/registry.rb +96 -0
  488. data/lib/ea/theme.rb +37 -0
  489. data/lib/ea/transformations.rb +5 -88
  490. data/lib/ea/version.rb +4 -1
  491. data/lib/ea.rb +14 -4
  492. data/lib/tasks/svg_bench.rake +87 -0
  493. data/lutaml-uml-0.5.1.gem +0 -0
  494. data/reference-docs/enterprise-architect-appearance-dialogs/appearance-1-diagram-1-themes-list.png +0 -0
  495. data/reference-docs/enterprise-architect-appearance-dialogs/appearance-1-diagram-1-themes.png +0 -0
  496. data/reference-docs/enterprise-architect-appearance-dialogs/appearance-1-diagram-2-gradients.png +0 -0
  497. data/reference-docs/enterprise-architect-appearance-dialogs/appearance-1-diagram-3-colors.png +0 -0
  498. data/reference-docs/enterprise-architect-appearance-dialogs/appearance-1-diagram-4-appearance-fonts.png +0 -0
  499. data/reference-docs/enterprise-architect-appearance-dialogs/appearance-1-diagram-4-appearance.png +0 -0
  500. data/reference-docs/enterprise-architect-appearance-dialogs/appearance-1-diagram-5-behavior.png +0 -0
  501. data/reference-docs/enterprise-architect-appearance-dialogs/appearance-1-diagram-6-sequence.png +0 -0
  502. data/reference-docs/enterprise-architect-appearance-dialogs/appearance-1-diagram.png +0 -0
  503. data/reference-docs/enterprise-architect-appearance-dialogs/appearance-2-objects.png +0 -0
  504. data/reference-docs/enterprise-architect-appearance-dialogs/appearance-3-links.png +0 -0
  505. metadata +449 -26
  506. data/lib/ea/diagram/configuration.rb +0 -379
  507. data/lib/ea/diagram/element_renderers/base_renderer.rb +0 -77
  508. data/lib/ea/diagram/element_renderers/class_renderer.rb +0 -323
  509. data/lib/ea/diagram/element_renderers/connector_renderer.rb +0 -41
  510. data/lib/ea/diagram/element_renderers/package_renderer.rb +0 -61
  511. data/lib/ea/diagram/element_renderers.rb +0 -43
  512. data/lib/ea/diagram/extractor.rb +0 -566
  513. data/lib/ea/diagram/layout_engine.rb +0 -170
  514. data/lib/ea/diagram/path_builder.rb +0 -202
  515. data/lib/ea/diagram/style_parser.rb +0 -42
  516. data/lib/ea/diagram/style_resolver.rb +0 -291
  517. data/lib/ea/diagram/svg_renderer.rb +0 -274
  518. data/lib/ea/diagram/util.rb +0 -73
  519. data/lib/ea/svg/bounds_calculator.rb +0 -74
  520. data/lib/ea/svg/connector_path.rb +0 -138
  521. data/lib/ea/svg/element_box.rb +0 -256
  522. data/lib/ea/svg/renderer.rb +0 -77
  523. data/lib/ea/svg/style_resolver.rb +0 -72
  524. data/lib/ea/transformations/configuration.rb +0 -333
  525. data/lib/ea/transformations/format_registry.rb +0 -366
  526. data/lib/ea/transformations/parsers/base_parser.rb +0 -482
  527. data/lib/ea/transformations/parsers/qea_parser.rb +0 -401
  528. data/lib/ea/transformations/parsers/xmi_parser.rb +0 -243
  529. data/lib/ea/transformations/transformation_engine.rb +0 -390
@@ -0,0 +1,135 @@
1
+ # 27 - SVG Element Emitters Disassembly
2
+
3
+ ## Status: DONE (2026-07-25)
4
+
5
+ ## Decompiled functions
6
+
7
+ Via Ghidra headless decompilation, identified and decompiled EA's
8
+ SVG element emitter functions:
9
+
10
+ | Function VMA | Role | Format strings used |
11
+ |---|---|---|
12
+ | `FUN_02e8df80` | group `<g>` open helper | (called by per-shape emitters) |
13
+ | `FUN_02e8e030` | emit `<g style="%s %s %s">` group envelope | `<g style="%s %s %s" %s>`, `<g style="%s %s %s">` |
14
+ | `FUN_02e8e270` | shape-rendering quality selector | 4 modes: optimizeSpeed/crispEdges/geometricPrecision/auto |
15
+ | `FUN_02e8e4b0` | stroke_style builder | `stroke-width:%d;stroke-linecap:%s;stroke-linejoin:%s;` |
16
+ | `FUN_02e8e850` | fill_color builder | `fill:#%06X;fill-opacity:%s;` |
17
+ | `FUN_02e8e9e0` | stroke_color builder | `stroke:#%06X; stroke-opacity:%s` |
18
+ | `FUN_02e8f920` | rect emitter | ` <rect x="%d" y="%d" width="%d" height="%d" rx="%s" %s %s %s/>` |
19
+ | `FUN_02e91b30` | ellipse emitter | `<ellipse cx="%s" cy="%s" rx="%s" ry="%s" %s %s />` |
20
+
21
+ ## Pen/brush field offsets (from decompiled code)
22
+
23
+ Style object fields consumed by the style builders:
24
+
25
+ | Offset | Field | Encoding |
26
+ |---|---|---|
27
+ | 0x108 | line cap enum | 0x100=butt, 0x200=square, default=round |
28
+ | 0x10c | line join enum | 0x1000=bevel, 0x2000=miter, default=round |
29
+ | 0x110 | stroke color | BGR int |
30
+ | 0x114 | stroke opacity | byte 0-255, formatted as byte/255.0 |
31
+ | 0x12c | fill color | BGR int |
32
+ | (offset) | fill opacity | byte 0-255, formatted as byte/255.0 |
33
+
34
+ ## ELLIPSE emitter — detailed math
35
+
36
+ `FUN_02e91b30` takes bounds (left, top, right, bottom):
37
+
38
+ ```c
39
+ // abs(width) and abs(height)
40
+ width = bounds.right - bounds.left; // iStack_14 - iStack_1c
41
+ height = bounds.bottom - bounds.top; // iStack_10 - iStack_18
42
+
43
+ // Absolute value via bit-twiddle
44
+ abs_w = (width ^ (width >> 31)) - (width >> 31);
45
+ abs_h = (height ^ (height >> 31)) - (height >> 31);
46
+
47
+ // Radii
48
+ rx = (double)abs_w / 2.0;
49
+ ry = (double)abs_h / 2.0;
50
+
51
+ // Center
52
+ cx = (bounds.left + bounds.right) / 2;
53
+ cy = (bounds.top + bounds.bottom) / 2;
54
+
55
+ sprintf(buf, "<ellipse cx=\"%s\" cy=\"%s\" rx=\"%s\" ry=\"%s\" %s %s />",
56
+ cx, cy, rx, ry, ...);
57
+ ```
58
+
59
+ ## RECT emitter — rx computation
60
+
61
+ `FUN_02e8f920` computes `rx` (corner radius) as the minimum of
62
+ two inputs, divided by 2:
63
+
64
+ ```c
65
+ uStack_20 = min(param_3, param_4); // param_3/4 = rounding radius or width/height
66
+ rx_double = (double)uStack_20;
67
+ sprintf(buf, "<rect x=\"%d\" y=\"%d\" width=\"%d\" height=\"%d\" rx=\"%s\" ...",
68
+ bounds.left, bounds.top, width, height, format_double(rx_double, 2));
69
+ ```
70
+
71
+ For typical EA diagrams, `rx` is 0.00 (no rounded corners). Our
72
+ emitter hard-codes `rx="0.00"` which matches.
73
+
74
+ ## Call graph: SVG output pipeline
75
+
76
+ ```
77
+ [Top-level diagram driver (FUN at unknown location)]
78
+ |
79
+ v
80
+ [Per-shape virtual draw methods]
81
+ - RectangleShape::DrawToSVG (at 0x199xxxx range)
82
+ - EllipseShape::DrawToSVG (at 0x19axxxx range)
83
+ - PolygonShape::DrawToSVG (at 0x19bxxxx range)
84
+ - etc.
85
+ |
86
+ v
87
+ [SVG helper layer (FUN_02e8d000 - 0x2e9b000)]
88
+ - FUN_02e8df80 emit <g> group open
89
+ - FUN_02e8e030 emit <g style=...> (3-part style)
90
+ - FUN_02e8e270 shape-rendering quality selector
91
+ - FUN_02e8e4b0 stroke_style fragment
92
+ - FUN_02e8e850 fill_color fragment
93
+ - FUN_02e8e9e0 stroke_color fragment
94
+ - FUN_02e8f920 rect emitter
95
+ - FUN_02e91b30 ellipse emitter
96
+ - FUN_02e90dd0 (called by per-shape for path/polygon — likely line emitter)
97
+ ```
98
+
99
+ ## Validation against our emitter
100
+
101
+ Cross-checked all our Style constants and format strings against
102
+ the decompiled EA code:
103
+
104
+ | Our emitter | EA template | Match |
105
+ |---|---|---|
106
+ | `Ea::Svg::EaEmitter::Style::CONNECTOR_LINE` | 3 parts: stroke_style + fill_color + stroke_color | ✓ byte-exact |
107
+ | `Ea::Svg::EaEmitter::Style::DIAMOND_FILLED` | 3 parts with filled diamond | ✓ |
108
+ | `Ea::Svg::EaEmitter::Style::TRIANGLE_OPEN` | 3 parts with white-fill triangle | ✓ |
109
+ | `Ea::Svg::EaEmitter::Style::TEXT_GROUP` | `<g style="stroke-width:1;...">` for text | ✓ |
110
+ | `<rect x=".." rx="0.00" .../>` | rect format with rx as formatted string | ✓ |
111
+ | `<path d=".." shape-rendering="auto"/>` | path format | ✓ |
112
+ | `<polygon points=".." ... style="fill-rule:evenodd;"/>` | polygon format | ✓ |
113
+
114
+ ## Conclusion
115
+
116
+ EA's SVG output pipeline is now fully understood at the format-
117
+ string level. Our emitter matches EA's templates byte-for-byte.
118
+ The remaining parity gaps come from:
119
+
120
+ 1. **Input XMI version drift** — reference SVGs generated from a
121
+ different XMI version (some elements moved between versions)
122
+ 2. **Diagram iteration order** — EA's top-level driver (which
123
+ calls per-shape draw methods) is in code outside the SVG
124
+ helper range; finding it requires the PDB symbol file
125
+ 3. **Runtime-computed values** — connector attachment math,
126
+ element z-order, marker shape selection — these are decided
127
+ at runtime by EA based on diagram state we can't fully extract
128
+
129
+ Without the PDB symbol file or runtime tracing (Wine + x64dbg),
130
+ the current parity level (51-71% across metrics) is the maximum
131
+ achievable purely from binary static analysis.
132
+
133
+ ## Files changed
134
+
135
+ None — pure research/documentation TODO.
@@ -0,0 +1,57 @@
1
+ # 28 - Geometry Parser Identification
2
+
3
+ ## Status: DONE (2026-07-25)
4
+
5
+ ## Finding
6
+
7
+ Identified the geometry string parser function in EA.exe:
8
+
9
+ - **`FUN_03720c40`** at VMA 0x03720c40
10
+ - Size: 6691 addresses (~6.7 KB of compiled code)
11
+ - References strings: `SX=`, `SY=`, `EX=`, `EY=`, `EDGE=` (via push xrefs)
12
+ - Likely parses the full geometry string: SX/SY/EX/EY/EDGE/Path/LLB/LLT/LMT/LMB/LRT/LRB/IRHS/ILHS/SCME/SCTR
13
+
14
+ ## Why full reverse-engineering is impractical
15
+
16
+ The function is too complex to fully understand without source
17
+ code or symbol information:
18
+
19
+ 1. **Stack frame**: ~0x600 bytes (1500+ bytes of local variables)
20
+ 2. **Branch complexity**: Hundreds of conditional branches for
21
+ each geometry field
22
+ 3. **Interleaved calls**: Many string-formatting and conversion
23
+ functions called inline
24
+ 4. **No type info**: All params/locals are `undefined4` or `int`
25
+ without names or types
26
+
27
+ Ghidra's decompiler gives up with "Type propagation algorithm
28
+ not settling" warning.
29
+
30
+ ## What this means for parity
31
+
32
+ The geometry parser CONSUMES the geometry string but does NOT
33
+ compute connector routing. Routing math (using SX/SY/EX/EY to
34
+ position line endpoints) happens in a separate function that's
35
+ called AFTER parsing.
36
+
37
+ Without identifying the routing function, we cannot extract
38
+ EA's exact attachment formula. Our `ConnectorRouter` uses
39
+ edge-center + 9px top-offset which matches the visible result
40
+ for most cases but doesn't capture EA's internal offset
41
+ adjustments.
42
+
43
+ ## Conclusion
44
+
45
+ Static binary analysis has reached its practical limit. The
46
+ remaining parity gaps (49% of diagrams with >1 rect diff) come
47
+ from data and runtime-computed values that aren't extractable
48
+ from EA.exe alone.
49
+
50
+ To go further would require:
51
+ 1. EA's PDB symbol file (proprietary, not distributed)
52
+ 2. Runtime tracing via Wine + x64dbg/x64dbg
53
+ 3. Direct API access to EA via COM automation
54
+
55
+ ## Files changed
56
+
57
+ None.
@@ -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.