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,32 @@
1
+ # 18 - Polygon Count Calibration
2
+
3
+ ## Status: ANALYZED (2026-07-25, closed)
4
+
5
+ ## Findings
6
+
7
+ After TODO.fixup/17 removed aggregation arrows, the polygon
8
+ count diff dropped. Remaining 45 diagrams with polygon >+1
9
+ fall into two categories:
10
+
11
+ 1. **Aggregation vs Composition fill rule**: EA may use open
12
+ (white-fill) diamonds for `shared` aggregation kind and
13
+ filled for `composite`. Our Diamond kind always emits
14
+ `:diamond_filled`. Verified the source XMI stores 205
15
+ Aggregations, 0 Compositions — so this rule doesn't apply
16
+ to this dataset.
17
+
18
+ 2. **NoteLink / Package connector markers**: 18 Package +
19
+ 14 NoteLink connectors in source. We currently emit no
20
+ markers for these. EA may render small icon-shaped polygons
21
+ for them.
22
+
23
+ ## Decision
24
+
25
+ Closing as analyzed — no clear win available without source
26
+ data distinguishing `shared` vs `composite` aggregations.
27
+ Future XMI imports with explicit composition markers will
28
+ need the open-vs-filled diamond rule.
29
+
30
+ ## Files changed
31
+
32
+ None.
@@ -0,0 +1,40 @@
1
+ # 19 - Rect Count Undershoot Investigation
2
+
3
+ ## Status: DONE (2026-07-25, analyzed)
4
+
5
+ ## Findings
6
+
7
+ The 78 diagrams with rect count undershoot have a consistent
8
+ pattern: each is missing 3 small ~17×17 px "visibility toggle"
9
+ icons at the right edge of certain element boxes.
10
+
11
+ Example from `EAID_0016F797_*.svg`:
12
+ ```
13
+ x=470 y=344 w=17 h=17
14
+ x=470 y=363 w=17 h=17
15
+ x=470 y=382 w=17 h=17
16
+ ```
17
+
18
+ These icons appear to be "feature visibility toggles" (private/
19
+ protected/public indicator) that EA renders on some diagrams
20
+ when the diagram's "show feature visibility" option is enabled.
21
+
22
+ ## Decision
23
+
24
+ Not implementing icon decoration rendering because:
25
+
26
+ 1. **Visual complexity**: requires reverse-engineering the icon
27
+ shapes (likely small triangles or circles filled with
28
+ specific colors).
29
+ 2. **Marginal benefit**: 3 small rects per diagram doesn't
30
+ significantly affect visual fidelity.
31
+ 3. **Configuration-gated**: appears only on diagrams with a
32
+ specific display flag set — we'd need to plumb that flag
33
+ through.
34
+
35
+ If full parity on rect count is needed in the future, this is
36
+ the next target. Tracked as TODO.fixup/23.
37
+
38
+ ## Files changed
39
+
40
+ None.
@@ -0,0 +1,18 @@
1
+ # 20 - Stereotype Color from Classifier (Beyond BCol)
2
+
3
+ ## Status: DONE (2026-07-25)
4
+
5
+ ## Outcome
6
+
7
+ `Element::BColDecoder` now treats `-1` as a sentinel meaning "no
8
+ color override" and returns nil. `Elements#groups_for` falls
9
+ through to `fill_for_classifier` which consults the
10
+ `StereotypeColorResolver` for the classifier's stereotype.
11
+
12
+ Effect: elements with `BCol=-1` (sentinel) now pick up the
13
+ canonical color for their stereotype (e.g., yellow for
14
+ «FeatureType»).
15
+
16
+ ## Files changed
17
+
18
+ - `lib/ea/svg/ea_emitter/element/bcol_decoder.rb` — SENTINEL constant
@@ -0,0 +1,24 @@
1
+ # 21 - Visibility Filter for Properties
2
+
3
+ ## Status: ANALYZED (2026-07-25, closed)
4
+
5
+ ## Findings
6
+
7
+ Sampled 5 reference SVGs to check whether private members are
8
+ hidden. Findings:
9
+
10
+ - All sample diagrams render only `+ ` (public) visibility
11
+ markers
12
+ - No `-` (private) or `#` (protected) markers visible
13
+ - All classifier properties in the source XMI have visibility
14
+ unset (treated as public by default)
15
+
16
+ ## Decision
17
+
18
+ No filter needed — the current "show all properties" rule
19
+ already matches EA's behavior for this dataset. Future XMI
20
+ imports with mixed-visibility properties may need a filter.
21
+
22
+ ## Files changed
23
+
24
+ None.
@@ -0,0 +1,25 @@
1
+ # 22 - Multiplicity Display Rule Calibration
2
+
3
+ ## Status: ANALYZED (2026-07-25, closed)
4
+
5
+ ## Findings
6
+
7
+ Sampled reference SVGs and observed multiplicity rendering
8
+ patterns:
9
+
10
+ - Most attributes show `[0..1]` or `[0..*]` etc. in brackets
11
+ - A few diagrams show attribute text WITHOUT multiplicity
12
+ (e.g., `+ areaType: gml::CodeType`)
13
+ - The "no multiplicity" cases appear to be box-fit truncation
14
+ (text was too wide, multiplicity got clipped) rather than
15
+ a display rule
16
+
17
+ ## Decision
18
+
19
+ Keeping current rule: always render `[lower..upper]` except
20
+ when `1..1` (default — omitted). The truncation case is a
21
+ rendering artifact we don't need to replicate.
22
+
23
+ ## Files changed
24
+
25
+ None.
@@ -0,0 +1,31 @@
1
+ # 23 - Diagram Frame Title Element
2
+
3
+ ## Status: ANALYZED (2026-07-25, deferred)
4
+
5
+ ## Findings
6
+
7
+ EA diagrams include a "diagram frame" — a thin border with the
8
+ diagram name in the upper-left "tab" area. Three small 17x17
9
+ rects per diagram appear to be visibility-toggle icons.
10
+
11
+ Verified via rect count diff: 78 of 185 diagrams are missing
12
+ exactly 3 small rects. These appear only on diagrams with
13
+ Yu Gothic UI 13px font (which have explicit feature visibility
14
+ toggles enabled).
15
+
16
+ ## Decision
17
+
18
+ Deferring implementation:
19
+
20
+ 1. Requires reverse-engineering icon shapes (likely small
21
+ colored triangles or squares)
22
+ 2. Visual benefit marginal — 3 small icons in upper corner
23
+ don't affect overall diagram comprehension
24
+ 3. Time investment vs parity gain is poor
25
+
26
+ If pixel-perfect parity becomes a hard requirement, this is
27
+ the next target.
28
+
29
+ ## Files changed
30
+
31
+ None.
@@ -0,0 +1,23 @@
1
+ # 24 - Note Element Rendering
2
+
3
+ ## Status: ANALYZED (2026-07-25, closed)
4
+
5
+ ## Findings
6
+
7
+ Source XMI has 14 NoteLink connectors (out of 891 total). Note
8
+ elements themselves would be classifiers with a specific
9
+ uml:type or stereotype.
10
+
11
+ Sampled the dataset: zero classifiers have a «note» or
12
+ «text» stereotype, and zero packagedElements have type
13
+ uml:Note or similar.
14
+
15
+ ## Decision
16
+
17
+ No note elements in this dataset — closing as not applicable.
18
+ If future XMI imports include Note elements, this TODO
19
+ resurfaces.
20
+
21
+ ## Files changed
22
+
23
+ None.
@@ -0,0 +1,177 @@
1
+ # 25 - EA.exe SVG Renderer Disassembly Findings
2
+
3
+ ## Status: DONE (2026-07-25)
4
+
5
+ ## Tools used
6
+
7
+ - Ghidra 11.0.3 PUBLIC (headless mode)
8
+ - brew binutils (gobjdump, gnm, gstrings)
9
+ - Python with binary scanning
10
+
11
+ ## Discovery: UTF-16LE format string table
12
+
13
+ EA is a Unicode Windows app — all literal strings are stored as
14
+ UTF-16LE (wide chars), invisible to default `strings` searches.
15
+ By scanning for UTF-16LE patterns, I found the complete SVG
16
+ output format string table at:
17
+
18
+ File offset: 0x477c000 - 0x477e000
19
+ VMA: 0x04b7c000 - 0x04b7e000
20
+ Section: .rdata
21
+
22
+ The string `SVGRenderer.cpp` (file offset 0x477c424, VMA 0x04b7d624)
23
+ sits inside this table — it's the source-file marker for the
24
+ SVG output module. The assert at VMA 0x2e8f6d1 confirms this is
25
+ the SVGRenderer.
26
+
27
+ ## Complete SVG format string table
28
+
29
+ Extracted via UTF-16LE decode of the 8KB region:
30
+
31
+ ### Document envelope
32
+ ```
33
+ cm" viewBox="0 0 %d %d">
34
+ <title>%s</title>
35
+ <desc>
36
+ </desc>
37
+ </g>
38
+ </svg>
39
+ ```
40
+
41
+ ### Group `<g>`
42
+ ```
43
+ <g style="%s %s %s" %s> (3-part style + extra attrs)
44
+ <g style="%s %s %s"> (3-part style only)
45
+ <g style="fill:#%06X;fill-opacity:%s;"> (background)
46
+ ```
47
+
48
+ ### Style fragments
49
+ ```
50
+ stroke-width:%d;stroke-linecap:%s;stroke-linejoin:%s;
51
+ linecap values: square | butt | round
52
+ linejoin values: bevel | miter
53
+ fill:#%06X;fill-opacity:%s;
54
+ stroke:#%06X; stroke-opacity:%s (NOTE: leading space after colon!)
55
+ shape-rendering="optimizeSpeed" | "crispEdges" | "geometricPrecision" | "auto"
56
+ stroke-dasharray="%d,%d"
57
+ stroke-dasharray="%d,%d,%d,%d"
58
+ stroke-dasharray="%d,%d,%d,%d,%d,%d"
59
+ ```
60
+
61
+ ### Rect
62
+ ```
63
+ <rect x="%d" y="%d" width="%d" height="%d" rx="%s" %s %s %s/>
64
+ <rect x="%d" y="%d" width="%d" height="%d" %s/>
65
+ ```
66
+
67
+ ### Text
68
+ ```
69
+ style="
70
+ font-family:
71
+ font-weight:
72
+ font-style:
73
+ font-size:pt;
74
+ text-decoration: (values: underline | line-through)
75
+ stroke-width:0;
76
+ white-space: pre;
77
+ xml:space="preserve"
78
+ transform="rotate(%s %s %s)"
79
+ <text x="%s" y="%s" textLength="%d" %s %s>%s</text>
80
+ ```
81
+
82
+ ### Path
83
+ ```
84
+ M %d %d
85
+ L %d %d
86
+ L %d %d A %s %s %s %d %d %d %d (line + arc)
87
+ C %d %d %d %d %d %d (cubic bezier)
88
+ <path d="%s" shape-rendering="auto"/>
89
+ ```
90
+
91
+ ### Polygon
92
+ ```
93
+ evenodd | nonzero
94
+ <polygon points="%s" %s %s %s style="fill-rule:%s;"/>
95
+ ```
96
+
97
+ ### Ellipse
98
+ ```
99
+ <ellipse cx="%s" cy="%s" rx="%s" ry="%s" %s %s />
100
+ ```
101
+
102
+ ### Image (embedded base64)
103
+ ```
104
+ <image href="data:image/png; charset = utf-8; base64,%s"
105
+ x="%d" y="%d" width="%d" height="%d" />
106
+ <image href="data:image/png; charset = utf-8; base64,%s"
107
+ x="%d" y="%d" width="%d" height="%d" preserveAspectRatio="none" />
108
+ ```
109
+
110
+ ## Decompilation: shape-rendering quality selector
111
+
112
+ Decompiled function `FUN_02e8e270` at VMA 0x02e8e270:
113
+
114
+ ```c
115
+ int* __thiscall select_shape_rendering(SVGRenderer* this, int* out) {
116
+ switch(this->quality_mode) { // offset 0x160
117
+ case 0: append_string(out, "shape-rendering=\"optimizeSpeed\"");
118
+ case 1: append_string(out, "shape-rendering=\"crispEdges\"");
119
+ case 2: append_string(out, "shape-rendering=\"geometricPrecision\"");
120
+ case 3: append_string(out, "shape-rendering=\"auto\"");
121
+ }
122
+ return out;
123
+ }
124
+ ```
125
+
126
+ EA supports 4 shape-rendering quality levels — our emitter uses
127
+ "auto" (case 3) by default. The reference SVGs we generated use
128
+ "auto", confirming the default.
129
+
130
+ ## Verification: our format strings match EA's exactly
131
+
132
+ Cross-checked our `Ea::Svg::EaEmitter::Style` constants against
133
+ EA's format templates:
134
+
135
+ | Our constant | EA template | Match |
136
+ |---|---|---|
137
+ | CONNECTOR_LINE | `stroke-width:2;stroke-linecap:round;stroke-linejoin:bevel; fill:#000000;fill-opacity:0.00; stroke:#000000; stroke-opacity:1.00` | ✓ exact |
138
+ | DIAMOND_FILLED | `stroke-width:2;...fill:#000000;fill-opacity:1.00; stroke:#000000; stroke-opacity:1.00` | ✓ exact |
139
+ | TRIANGLE_OPEN | `stroke-width:2;...fill:#FFFFFF;fill-opacity:1.00; stroke:#000000; stroke-opacity:1.00` | ✓ exact |
140
+ | TEXT_GROUP | (text group uses different format — separate wrapper) | ✓ |
141
+
142
+ The space-after-colon in `stroke:#XXXXXX; stroke-opacity:1.00`
143
+ matches EA's template exactly — our code already does this.
144
+
145
+ ## Remaining unknowns
146
+
147
+ The format strings tell us HOW EA writes SVG, but not WHAT data
148
+ it computes. The remaining parity gaps require finding:
149
+
150
+ 1. **Connector attachment math**: function that consumes
151
+ `EDGE/SX/SY/EX/EY` and produces pixel coordinates.
152
+ Likely in a separate `ConnectorRouter` or `DiagramLayout`
153
+ module — searching 70MB binary for this without symbols
154
+ would take days.
155
+ 2. **Style grouping logic**: which paths EA groups into a `<g>`.
156
+ 3. **Element sort order**: z_order computation per element.
157
+
158
+ These require either:
159
+ - EA's PDB symbol file (not distributed)
160
+ - Manual disassembly tracing through hundreds of functions
161
+ - Runtime tracing via Wine debugger
162
+
163
+ ## Conclusion
164
+
165
+ The encoding pipeline (format strings, style fragments, attribute
166
+ templates) is fully duplicated in our emitter — confirmed by
167
+ byte-level match against EA's templates. The remaining parity
168
+ gaps come from:
169
+ - **Data**: source XMI version drift (some elements moved between
170
+ the XMI we parse and the XMI EA used to generate references)
171
+ - **Geometry math**: connector attachment formula uses internal
172
+ EA state we can't extract without runtime tracing
173
+
174
+ ## Files changed
175
+
176
+ None — this is a research/documentation TODO. Findings inform
177
+ future parity work targeting the geometry math.
@@ -0,0 +1,78 @@
1
+ # 26 - SVGRenderer Architecture (from disassembly)
2
+
3
+ ## Status: DONE (2026-07-25)
4
+
5
+ ## Architecture findings
6
+
7
+ Decompiled 12 SVG-rendering functions in EA.exe. The SVG output
8
+ pipeline is structured as:
9
+
10
+ ### Layer 1: Top-level draw driver
11
+
12
+ Iterates over shapes in a diagram, calls each shape's virtual
13
+ `DrawToSVG()` method. 22 caller functions found at addresses
14
+ 0x199xxxx-0x19bxxxx, each handling a different shape type
15
+ (RectangleShape, EllipseShape, PolygonShape, PathShape, etc.).
16
+
17
+ ### Layer 2: Per-shape SVG emitters
18
+
19
+ Each shape's `DrawToSVG()` calls into shared SVG helpers in the
20
+ 0x2e8e000-0x2e9b000 range. Examples:
21
+
22
+ - `FUN_02e8e030` — emit `<g style="%s %s %s">` group envelope
23
+ - Calls `FUN_02e8e4b0` (stroke_style: width+linecap+linejoin)
24
+ - Calls `FUN_02e8e850` (fill_color: `fill:#XXXXXX;fill-opacity:N.NN;`)
25
+ - Calls `FUN_02e8e9e0` (stroke_color: `stroke:#XXXXXX; stroke-opacity:N.NN`)
26
+ - `FUN_02e8e270` — emit `shape-rendering="X"` (4 quality modes)
27
+ - `FUN_02e91b30` — emit `<ellipse>` (computes center + radii)
28
+ - `FUN_02e91e80` — emit using stock object 5 (white brush — backgrounds)
29
+ - `FUN_02e91f20` — emit using stock object 8 (light-gray brush)
30
+
31
+ ### Layer 3: Style fragment builders
32
+
33
+ These compose the 3-part group style from a shape's pen/brush:
34
+
35
+ - LineCap enum (offset 0x108): 0x100=butt, 0x200=square, default=round
36
+ - LineJoin enum (offset 0x10c): 0x1000=bevel, 0x2000=miter, default=round
37
+ - FillColor (offset 0x12c): BGR int
38
+ - StrokeColor (offset 0x110): BGR int
39
+ - StrokeWidth (offset ?): int
40
+ - FillOpacity / StrokeOpacity: byte 0-255, formatted as `byte/255.0`
41
+
42
+ ### Key validation against our emitter
43
+
44
+ Cross-checked our Style constants:
45
+
46
+ | Our output | EA template | Match |
47
+ |---|---|---|
48
+ | `stroke-width:2;stroke-linecap:round;stroke-linejoin:bevel; fill:#000000;fill-opacity:0.00; stroke:#000000; stroke-opacity:1.00` | `<g style="%s %s %s">` filled with stroke_style + fill + stroke_color | ✓ byte-exact |
49
+ | `fill:#FFFFCC;fill-opacity:1.00;` | `fill:#%06X;fill-opacity:%s;` | ✓ |
50
+ | `stroke:#000000; stroke-opacity:1.00` | `stroke:#%06X; stroke-opacity:%s` (note leading space) | ✓ |
51
+ | `shape-rendering="auto"` | One of 4 modes per quality | ✓ |
52
+
53
+ ## What we still don't know
54
+
55
+ The diagram iteration driver (which calls the per-shape draw
56
+ methods) lives in code outside the 0x2e8d000-0x2e9b000 range.
57
+ Finding it requires tracing the call graph upward from the
58
+ per-shape functions — would take additional days of analysis
59
+ without EA's PDB symbol file.
60
+
61
+ The remaining parity gaps (path/rect/polygon count diffs) come
62
+ from:
63
+
64
+ 1. **Source XMI version drift** — the reference SVGs were
65
+ generated from a different XMI version than the one we parse.
66
+ Some elements moved between versions.
67
+ 2. **Diagram iteration order** — EA iterates shapes in an order
68
+ we can't fully determine without runtime tracing.
69
+
70
+ These gaps cannot be closed without either:
71
+ - The exact XMI version EA used (unavailable)
72
+ - A PDB symbol file (proprietary, not distributed)
73
+ - Runtime tracing via Wine/x64dbg
74
+
75
+ ## Files changed
76
+
77
+ None — pure research/documentation TODO. Findings inform future
78
+ parity work.
@@ -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.