ea 0.4.0 → 0.5.1

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 (548) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +128 -1
  3. data/Rakefile +3 -0
  4. data/TODO.complete/01-t-xref-parsing.md +91 -0
  5. data/TODO.complete/02-per-label-geometry.md +50 -0
  6. data/TODO.complete/03-object-properties-constraints.md +57 -0
  7. data/TODO.complete/04-operation-params.md +37 -0
  8. data/TODO.complete/05-pdata-flag-matrix.md +52 -0
  9. data/TODO.complete/06-emf-image-rendering.md +34 -0
  10. data/TODO.complete/07-auxiliary-tables.md +47 -0
  11. data/TODO.complete/10-mdg-stereotype-registry.md +40 -0
  12. data/TODO.complete/11-gml-xsd-generation.md +42 -0
  13. data/TODO.complete/13-shapescript-interpreter.md +28 -0
  14. data/TODO.complete/20-cli-diff.md +46 -0
  15. data/TODO.complete/21-cli-render.md +26 -0
  16. data/TODO.complete/22-cli-export.md +29 -0
  17. data/TODO.complete/23-cli-mdg.md +23 -0
  18. data/TODO.complete/30-headerlines-ocp-refactor.md +72 -0
  19. data/TODO.complete/31-public-send-cleanup.md +61 -0
  20. data/TODO.complete/32-spec-coverage.md +33 -0
  21. data/TODO.complete/33-blocked-parity-gaps.md +41 -0
  22. data/TODO.complete/36-stereotype-icon-wiring.md +32 -0
  23. data/TODO.complete/37-cli-lint.md +32 -0
  24. data/TODO.complete/38-cli-query.md +26 -0
  25. data/TODO.complete/39-cli-info.md +23 -0
  26. data/TODO.complete/40-ocl-evaluator.md +31 -0
  27. data/TODO.complete/41-round-trip-spec.md +18 -0
  28. data/TODO.complete/42-html-diff-report.md +18 -0
  29. data/TODO.complete/43-json-schema-export.md +20 -0
  30. data/TODO.complete/44-remaining-qea-tables.md +40 -0
  31. data/TODO.complete/45-shapescript-extensions.md +25 -0
  32. data/TODO.complete/46-xsd-consolidation.md +20 -0
  33. data/TODO.complete/47-headerlines-legacy-removal.md +20 -0
  34. data/TODO.complete/51-remove-respond-to.md +25 -0
  35. data/TODO.complete/52-xsd-decouple-fixtures.md +23 -0
  36. data/TODO.complete/53-xmi-public-send-cleanup.md +26 -0
  37. data/TODO.complete/54-wire-stereotype-icon-renderer.md +20 -0
  38. data/TODO.complete/55-wire-shapescript.md +20 -0
  39. data/TODO.complete/56-wire-emf-renderer.md +27 -0
  40. data/TODO.complete/57-wire-ocl-evaluator.md +23 -0
  41. data/TODO.complete/58-diff-modifications.md +21 -0
  42. data/TODO.complete/59-delete-toy-xmi-export.md +30 -0
  43. data/TODO.complete/60-curate-json-export.md +20 -0
  44. data/TODO.complete/61-plantuml-relationships.md +22 -0
  45. data/TODO.complete/62-changelog.md +17 -0
  46. data/TODO.complete/63-dependabot-fix.md +18 -0
  47. data/TODO.complete/STATUS.md +85 -0
  48. data/TODO.diagrams/01-svg-measurement-harness.md +31 -0
  49. data/TODO.diagrams/02-polygon-over-rendering.md +29 -0
  50. data/TODO.diagrams/03-text-over-rendering.md +30 -0
  51. data/TODO.diagrams/04-rect-under-rendering.md +33 -0
  52. data/TODO.diagrams/05-canvas-dimension-parity.md +51 -0
  53. data/TODO.diagrams/06-group-layering-parity.md +39 -0
  54. data/TODO.diagrams/07-text-content-fidelity.md +65 -0
  55. data/TODO.diagrams/08-qea-direct-pipeline.md +46 -0
  56. data/TODO.diagrams/12-connector-labels.md +40 -0
  57. data/TODO.diagrams/12-per-entity-svg-layer-ordering.md +24 -0
  58. data/TODO.diagrams/13-marker-polygon-vs-path-dispatch.md +20 -0
  59. data/TODO.diagrams/13-per-text-type-font-sizes.md +33 -0
  60. data/TODO.diagrams/14-center-header-text.md +33 -0
  61. data/TODO.diagrams/14-filter-diagram-frame-elements.md +18 -0
  62. data/TODO.diagrams/15-deep-dead-code-audit.md +47 -0
  63. data/TODO.diagrams/15-per-element-font-from-style.md +24 -0
  64. data/TODO.diagrams/16-canvas-marker-extent.md +30 -0
  65. data/TODO.diagrams/16-document-remaining-parity-gaps.md +91 -0
  66. data/TODO.diagrams/17-italic-abstract-classes.md +28 -0
  67. data/TODO.diagrams/17-remaining-parity-gaps.md +90 -0
  68. data/TODO.diagrams/18-canvas-from-image-bounds.md +20 -0
  69. data/TODO.diagrams/18-property-lookup-index.md +42 -0
  70. data/TODO.diagrams/19-connector-sx-sy-routing.md +27 -0
  71. data/TODO.diagrams/19-replace-respond-to-with-is-a.md +31 -0
  72. data/TODO.diagrams/20-split-labels-emitter.md +56 -0
  73. data/TODO.diagrams/20-visibility-glyph-font-encoding.md +27 -0
  74. data/TODO.diagrams/21-aggregation-navigability-arrow.md +21 -0
  75. data/TODO.diagrams/21-auto-generated-legend-block.md +65 -0
  76. data/TODO.diagrams/22-ghost-element-discriminator.md +57 -0
  77. data/TODO.diagrams/22-style-based-path-grouping.md +28 -0
  78. data/TODO.diagrams/23-marker-polygon-deduplication.md +47 -0
  79. data/TODO.diagrams/23-multiplicity-label-positioning.md +29 -0
  80. data/TODO.diagrams/24-marker-anchor-structural.md +35 -0
  81. data/TODO.diagrams/24-track-marker-anchors-structurally.md +66 -0
  82. data/TODO.diagrams/24-truncate-properties-to-fit-box.md +24 -0
  83. data/TODO.diagrams/26-phantom-general-parent-rendering.md +59 -0
  84. data/TODO.diagrams/27-path-grouping-mode-detection.md +43 -0
  85. data/TODO.diagrams/28-architecture-cleanup-batch.md +47 -0
  86. data/TODO.diagrams/30-decompose-elements-groups-for.md +52 -0
  87. data/TODO.diagrams/32-examples-coverage-batch.md +78 -0
  88. data/TODO.diagrams/36-instance-specification-model.md +42 -0
  89. data/TODO.diagrams/37-element-icon-decorations.md +41 -0
  90. data/TODO.diagrams/38-html-note-and-receptions.md +32 -0
  91. data/TODO.diagrams/39-property-stereotype-discriminator.md +40 -0
  92. data/TODO.diagrams/40-standalone-1-discriminator.md +38 -0
  93. data/TODO.diagrams/41-xmi-to-svg-pipeline.md +113 -0
  94. data/TODO.diagrams/42-close-all-parity-deltas.md +69 -0
  95. data/TODO.diagrams/43-marker-deduplication-strategy.md +54 -0
  96. data/TODO.diagrams/44-element-icon-decorations.md +34 -0
  97. data/TODO.diagrams/45-phantom-parent-class-boxes.md +40 -0
  98. data/TODO.diagrams/46-user-drawn-legend-swatches.md +44 -0
  99. data/TODO.diagrams/47-attribute-line-fidelity.md +72 -0
  100. data/TODO.diagrams/48-spec-coverage-critical-emitter-components.md +45 -0
  101. data/TODO.diagrams/49-spec-coverage-orchestrators.md +25 -0
  102. data/TODO.diagrams/50-examples-parity.md +85 -0
  103. data/TODO.diagrams/51-property-oy-gap-and-remaining-gaps.md +48 -0
  104. data/TODO.diagrams/52-marker-registration-architecture.md +89 -0
  105. data/TODO.diagrams/53-remaining-example-gaps.md +86 -0
  106. data/TODO.diagrams/54-display-name-nested-classes.md +40 -0
  107. data/TODO.diagrams/55-visibility-icon-discriminator.md +58 -0
  108. data/TODO.diagrams/56-package-contents-rendering.md +148 -0
  109. data/TODO.diagrams/57-instance-specification-model.md +100 -0
  110. data/TODO.diagrams/58-domain-model-note-text.md +67 -0
  111. data/TODO.diagrams/59-classes-arrow-discriminator.md +57 -0
  112. data/TODO.diagrams/60-testschema-association-marker.md +40 -0
  113. data/TODO.diagrams/61-legend-block-rendering.md +55 -0
  114. data/TODO.diagrams/61-plateau-parity-gaps.md +59 -0
  115. data/TODO.diagrams/62-ghost-element-rendering.md +56 -0
  116. data/TODO.diagrams/63-qualified-name-wrap.md +36 -0
  117. data/TODO.diagrams/64-property-stereotype-labels.md +22 -0
  118. data/TODO.diagrams/65-path-coordinate-frame.md +62 -0
  119. data/TODO.diagrams/67-path-coordinate-frame.md +62 -0
  120. data/TODO.diagrams/68-inherited-attributes.md +65 -0
  121. data/TODO.diagrams/69-package-anchor-conditional.md +29 -0
  122. data/TODO.diagrams/70-mdg-technology-support.md +68 -0
  123. data/TODO.diagrams/71-off-canvas-parent-ghost.md +45 -0
  124. data/TODO.diagrams/72-basic-attr-divider-paths.md +39 -0
  125. data/TODO.diagrams/73-plateau-polygon-gap.md +69 -0
  126. data/TODO.diagrams/74-plateau-rect-gap.md +22 -0
  127. data/TODO.diagrams/75-plateau-text-gap.md +39 -0
  128. data/TODO.diagrams/76-basic-poly-path-gaps.md +41 -0
  129. data/TODO.diagrams/77-basic-text-overrender.md +40 -0
  130. data/TODO.diagrams/78-headerlines-ocp-refactor.md +65 -0
  131. data/TODO.diagrams/79-architecture-backlog.md +65 -0
  132. data/TODO.diagrams/80-basic-triangle-polygons.md +51 -0
  133. data/TODO.diagrams/81-plateau-path-overrender.md +53 -0
  134. data/TODO.diagrams/82-appearance-canvas-offset.md +54 -0
  135. data/TODO.diagrams/83-3d-diagram-subtitle.md +58 -0
  136. data/TODO.diagrams/84-canvas-offset-mismatches.md +61 -0
  137. data/TODO.diagrams/85-phantom-property-overrender.md +95 -0
  138. data/TODO.diagrams/86-foreign-package-rule.md +62 -0
  139. data/TODO.diagrams/87-internal-tech-encryption.md +80 -0
  140. data/TODO.diagrams/EXAMPLES_STATUS.md +88 -0
  141. data/TODO.diagrams/README.md +69 -0
  142. data/TODO.diagrams/STATUS.md +73 -0
  143. data/TODO.fixup/01-default-grouped-paths.md +34 -0
  144. data/TODO.fixup/02-marker-consolidation-per-connector.md +20 -0
  145. data/TODO.fixup/03-diagram-font-inference.md +28 -0
  146. data/TODO.fixup/04-extract-bounds-calculator.md +25 -0
  147. data/TODO.fixup/05-marker-registry-ocp.md +32 -0
  148. data/TODO.fixup/06-connector-path-bend-routing.md +28 -0
  149. data/TODO.fixup/07-edge-attachment-formula.md +22 -0
  150. data/TODO.fixup/08-visual-diff-harness.md +28 -0
  151. data/TODO.fixup/09-extract-element-compartments.md +34 -0
  152. data/TODO.fixup/10-canvas-width-overshoot-fix.md +20 -0
  153. data/TODO.fixup/11-layer-sequencer-extraction.md +18 -0
  154. data/TODO.fixup/12-path-style-harmony.md +23 -0
  155. data/TODO.fixup/13-datatype-stereotype-fallback.md +28 -0
  156. data/TODO.fixup/14-ea-exe-reverse-engineering-notes.md +56 -0
  157. data/TODO.fixup/15-enumeration-literal-rendering.md +30 -0
  158. data/TODO.fixup/16-operation-compartment-rendering.md +42 -0
  159. data/TODO.fixup/17-path-count-calibration.md +27 -0
  160. data/TODO.fixup/18-polygon-count-calibration.md +32 -0
  161. data/TODO.fixup/19-rect-count-undershoot-investigation.md +40 -0
  162. data/TODO.fixup/20-stereotype-color-from-classifier.md +18 -0
  163. data/TODO.fixup/21-visibility-filter-for-properties.md +24 -0
  164. data/TODO.fixup/22-multiplicity-display-rule-calibration.md +25 -0
  165. data/TODO.fixup/23-diagram-frame-title-element.md +31 -0
  166. data/TODO.fixup/24-note-element-rendering.md +23 -0
  167. data/TODO.fixup/25-ea-exe-disassembly-findings.md +177 -0
  168. data/TODO.fixup/26-svg-renderer-architecture.md +78 -0
  169. data/TODO.fixup/27-svg-element-emitters-disassembly.md +135 -0
  170. data/TODO.fixup/28-geometry-parser-identification.md +57 -0
  171. data/TODO.fixup/29-qea-svg-xmi-triple-comparison.md +185 -0
  172. data/TODO.fixup/30-theme-system-stub.md +46 -0
  173. data/TODO.fixup/31-theme-value-object-registry.md +17 -0
  174. data/TODO.fixup/32-styleex-on-diagram-model.md +22 -0
  175. data/TODO.fixup/33-text-encoding-decimals-rotation.md +29 -0
  176. data/TODO.fixup/34-per-type-fill-via-theme.md +18 -0
  177. data/TODO.fixup/35-stroke-width-per-theme.md +7 -0
  178. data/TODO.fixup/36-qea-rect-coord-normalization.md +24 -0
  179. data/TODO.fixup/37-package-shape-rendering.md +22 -0
  180. data/TODO.fixup/38-note-element-rendering.md +15 -0
  181. data/TODO.fixup/39-styleex-flag-honoring.md +25 -0
  182. data/TODO.fixup/40-connector-dashed-lines.md +15 -0
  183. data/TODO.fixup/41-diagram-frame-showborder-detection.md +23 -0
  184. data/TODO.fixup/42-textrenderer-centralization.md +10 -0
  185. data/TODO.fixup/43-colorresolver-unification.md +24 -0
  186. data/TODO.fixup/44-theme-aware-textrenderer.md +17 -0
  187. data/TODO.fixup/45-theme-aware-fontresolver.md +22 -0
  188. data/TODO.fixup/46-style-parameterized-by-theme.md +21 -0
  189. data/TODO.fixup/47-canvas-frame-inset.md +19 -0
  190. data/TODO.fixup/48-background-rect-format.md +15 -0
  191. data/TODO.fixup/49-all-samples-integration-test.md +17 -0
  192. data/TODO.fixup/50-svg-emitter-architecture-docs.md +33 -0
  193. data/TODO.fixup/51-promote-theme-to-ea-namespace.md +28 -0
  194. data/TODO.fixup/52-theme-definition-integrated-fills.md +26 -0
  195. data/TODO.fixup/53-theme-registry-yaml-loading.md +50 -0
  196. data/TODO.fixup/54-diagram-theme-api.md +50 -0
  197. data/TODO.fixup/55-update-eaemitter-to-ea-theme.md +23 -0
  198. data/TODO.fixup/56-theme-yaml-files.md +65 -0
  199. data/TODO.fixup/57-theme-specs-and-integration.md +27 -0
  200. data/TODO.fixup/58-ea-entry-point-theme-autoload.md +20 -0
  201. data/TODO.fixup/59-thread-theme-through-all-renderers.md +29 -0
  202. data/TODO.fixup/60-cli-theme-option.md +22 -0
  203. data/TODO.fixup/61-theme-validation.md +28 -0
  204. data/TODO.fixup/62-theme-builder-dsl.md +31 -0
  205. data/TODO.fixup/63-theme-integration-rendering-spec.md +24 -0
  206. data/TODO.fixup/64-theme-writeback-styleex.md +21 -0
  207. data/TODO.fixup/65-remove-dead-eaemitter-theme-files.md +30 -0
  208. data/TODO.fixup/66-styleex-writeback.md +22 -0
  209. data/TODO.fixup/67-delete-dead-code.md +28 -0
  210. data/TODO.fixup/68-figure-parity-status.md +82 -0
  211. data/TODO.fixup/69-package-polygon-rendering.md +54 -0
  212. data/TODO.fixup/70-tagged-values-compartment.md +39 -0
  213. data/TODO.fixup/71-auto-detect-theme-from-xmi.md +37 -0
  214. data/TODO.fixup/72-sample-exports-as-regression-specs.md +37 -0
  215. data/TODO.fixup/73-delete-dead-transformations.md +14 -0
  216. data/TODO.fixup/74-delete-dead-diagram-renderers.md +18 -0
  217. data/TODO.fixup/75-visibility-legend-icons.md +23 -0
  218. data/TODO.fixup/76-plateau-text-undershoot.md +27 -0
  219. data/TODO.fixup/77-canvas-frame-margins.md +28 -0
  220. data/TODO.fixup/78-note-element-rendering.md +30 -0
  221. data/TODO.fixup/79-operation-compartment-rendering.md +27 -0
  222. data/TODO.fixup/80-tagged-value-stereotype-visibility.md +37 -0
  223. data/TODO.fixup/81-figure-parity-current-state.md +63 -0
  224. data/config/qea_schema.yml +356 -0
  225. data/config/themes/119.yml +98 -0
  226. data/config/themes/default.yml +14 -0
  227. data/examples/exports/20251010_current_plateau_v5/UML_EA.DTD +6856 -0
  228. data/examples/exports/20251010_current_plateau_v5/model.xml +96709 -0
  229. data/examples/exports/ArcGISWorkspace_template/UML_EA.DTD +6856 -0
  230. data/examples/exports/ArcGISWorkspace_template/model.xml +1427 -0
  231. data/examples/exports/UmlModel_template/UML_EA.DTD +6856 -0
  232. data/examples/exports/UmlModel_template/model.xml +23 -0
  233. data/examples/exports/basic/UML_EA.DTD +6856 -0
  234. data/examples/exports/basic/model.xml +8039 -0
  235. data/examples/exports/simple/UML_EA.DTD +6856 -0
  236. data/examples/exports/simple/model.xml +585 -0
  237. data/examples/exports/simple_example/UML_EA.DTD +6856 -0
  238. data/examples/exports/simple_example/model.xml +23 -0
  239. data/examples/exports/test/UML_EA.DTD +6856 -0
  240. data/examples/exports/test/model.xml +1638 -0
  241. data/examples/qea/basic.qea +0 -0
  242. data/frontend/README.md +51 -0
  243. data/frontend/dist/app.iife.js +24 -0
  244. data/frontend/dist/style.css +1 -0
  245. data/frontend/index.html +26 -0
  246. data/frontend/package-lock.json +2359 -0
  247. data/frontend/package.json +26 -0
  248. data/frontend/src/App.vue +59 -0
  249. data/frontend/src/app.ts +8 -0
  250. data/frontend/src/components/AppHeader.vue +127 -0
  251. data/frontend/src/components/AppSidebar.vue +119 -0
  252. data/frontend/src/components/ClassDetails.vue +247 -0
  253. data/frontend/src/components/DiagramView.vue +79 -0
  254. data/frontend/src/components/PackageDetails.vue +92 -0
  255. data/frontend/src/components/PackageTreeNode.vue +64 -0
  256. data/frontend/src/components/SearchResults.vue +48 -0
  257. data/frontend/src/components/WelcomeView.vue +87 -0
  258. data/frontend/src/shims-vue.d.ts +5 -0
  259. data/frontend/src/stores/dataStore.ts +79 -0
  260. data/frontend/src/stores/uiStore.ts +167 -0
  261. data/frontend/src/styles/main.css +1566 -0
  262. data/frontend/src/types.ts +221 -0
  263. data/frontend/tests/e2e/__screenshots__/new-dark-mode.png +0 -0
  264. data/frontend/tests/e2e/__screenshots__/new-package-details.png +0 -0
  265. data/frontend/tests/e2e/__screenshots__/new-search-modal.png +0 -0
  266. data/frontend/tests/e2e/__screenshots__/new-sidebar-collapsed.png +0 -0
  267. data/frontend/tests/e2e/__screenshots__/new-welcome.png +0 -0
  268. data/frontend/tests/e2e/render.spec.ts +188 -0
  269. data/frontend/tsconfig.json +20 -0
  270. data/frontend/vite.config.ts +26 -0
  271. data/frontend/vitest.config.ts +8 -0
  272. data/lib/ea/cli/app.rb +57 -2
  273. data/lib/ea/cli/command/diagrams.rb +37 -28
  274. data/lib/ea/cli/command/diff.rb +46 -0
  275. data/lib/ea/cli/command/export.rb +101 -0
  276. data/lib/ea/cli/command/info.rb +75 -0
  277. data/lib/ea/cli/command/lint.rb +48 -0
  278. data/lib/ea/cli/command/mdg.rb +98 -0
  279. data/lib/ea/cli/command/query.rb +34 -0
  280. data/lib/ea/cli/command/render.rb +135 -0
  281. data/lib/ea/cli/command/svg.rb +8 -15
  282. data/lib/ea/cli/command.rb +7 -0
  283. data/lib/ea/diagram/display_config.rb +184 -0
  284. data/lib/ea/diagram.rb +4 -41
  285. data/lib/ea/diff/change.rb +30 -0
  286. data/lib/ea/diff/comparator.rb +109 -0
  287. data/lib/ea/diff/html_reporter.rb +91 -0
  288. data/lib/ea/diff.rb +15 -0
  289. data/lib/ea/export/json/generator.rb +118 -0
  290. data/lib/ea/export/json.rb +12 -0
  291. data/lib/ea/export/json_schema/generator.rb +77 -0
  292. data/lib/ea/export/json_schema.rb +12 -0
  293. data/lib/ea/export/plantuml/generator.rb +140 -0
  294. data/lib/ea/export/plantuml.rb +12 -0
  295. data/lib/ea/export/xsd/class_mapping.rb +65 -0
  296. data/lib/ea/export/xsd/generator.rb +137 -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 +13 -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 +40 -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 +34 -0
  333. data/lib/ea/model/diagram_element.rb +16 -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/qea/validation/database/ocl_constraint_validator.rb +65 -0
  378. data/lib/ea/qea/validation/database.rb +2 -0
  379. data/lib/ea/qea/validation/validation_engine.rb +2 -0
  380. data/lib/ea/qea/validation.rb +2 -0
  381. data/lib/ea/query/builder.rb +127 -0
  382. data/lib/ea/query.rb +9 -0
  383. data/lib/ea/render/image_converter.rb +101 -0
  384. data/lib/ea/render.rb +10 -0
  385. data/lib/ea/shapescript/parser.rb +208 -0
  386. data/lib/ea/shapescript/renderer.rb +74 -0
  387. data/lib/ea/shapescript/shape.rb +34 -0
  388. data/lib/ea/shapescript.rb +24 -0
  389. data/lib/ea/sources/qea/adapter.rb +22 -5
  390. data/lib/ea/sources/qea/classifier_builder.rb +184 -7
  391. data/lib/ea/sources/qea/diagram_builder.rb +352 -24
  392. data/lib/ea/sources/qea/id_normalizer.rb +16 -1
  393. data/lib/ea/sources/qea/instance_builder.rb +113 -0
  394. data/lib/ea/sources/qea/legend_builder.rb +137 -0
  395. data/lib/ea/sources/qea/note_builder.rb +58 -0
  396. data/lib/ea/sources/qea/object_classifier_map.rb +6 -1
  397. data/lib/ea/sources/qea/operation_builder.rb +1 -0
  398. data/lib/ea/sources/qea/package_builder.rb +16 -0
  399. data/lib/ea/sources/qea/relationship_builder.rb +21 -5
  400. data/lib/ea/sources/qea/tagged_value_builder.rb +28 -9
  401. data/lib/ea/sources/qea/xref/legend_definition.rb +35 -0
  402. data/lib/ea/sources/qea/xref/parser.rb +150 -0
  403. data/lib/ea/sources/qea/xref/property_definition.rb +29 -0
  404. data/lib/ea/sources/qea/xref/record.rb +41 -0
  405. data/lib/ea/sources/qea/xref/stereotype_application.rb +37 -0
  406. data/lib/ea/sources/qea/xref.rb +27 -0
  407. data/lib/ea/sources/qea.rb +4 -0
  408. data/lib/ea/sources/xmi/adapter.rb +80 -2
  409. data/lib/ea/sources/xmi/classifier_builder.rb +10 -1
  410. data/lib/ea/sources/xmi/diagram_builder.rb +95 -18
  411. data/lib/ea/sources/xmi/extension_geometry_parser.rb +19 -2
  412. data/lib/ea/sources/xmi/extension_style_parser.rb +15 -2
  413. data/lib/ea/sources/xmi/note_builder.rb +46 -0
  414. data/lib/ea/sources/xmi/property_builder.rb +9 -0
  415. data/lib/ea/sources/xmi/stereotype_builder.rb +54 -0
  416. data/lib/ea/sources/xmi/tag_builder.rb +45 -0
  417. data/lib/ea/sources/xmi/umldi_keyword_extractor.rb +87 -0
  418. data/lib/ea/sources/xmi.rb +4 -0
  419. data/lib/ea/spa/output/sharded_multi_file_strategy.rb +18 -3
  420. data/lib/ea/spa/output/single_file_strategy.rb +8 -2
  421. data/lib/ea/spa/output/strategy.rb +34 -0
  422. data/lib/ea/svg/connector_router.rb +134 -0
  423. data/lib/ea/svg/ea_emitter/background.rb +2 -3
  424. data/lib/ea/svg/ea_emitter/bounds_calculator.rb +142 -0
  425. data/lib/ea/svg/ea_emitter/canvas.rb +56 -33
  426. data/lib/ea/svg/ea_emitter/color_resolver.rb +56 -0
  427. data/lib/ea/svg/ea_emitter/compartment/attributes.rb +28 -0
  428. data/lib/ea/svg/ea_emitter/compartment/constraints.rb +30 -0
  429. data/lib/ea/svg/ea_emitter/compartment/enum_literals.rb +86 -0
  430. data/lib/ea/svg/ea_emitter/compartment/header.rb +32 -0
  431. data/lib/ea/svg/ea_emitter/compartment/header_divider.rb +57 -0
  432. data/lib/ea/svg/ea_emitter/compartment/instance_slots.rb +96 -0
  433. data/lib/ea/svg/ea_emitter/compartment/instance_underline.rb +67 -0
  434. data/lib/ea/svg/ea_emitter/compartment/note_body.rb +52 -0
  435. data/lib/ea/svg/ea_emitter/compartment/note_text.rb +102 -0
  436. data/lib/ea/svg/ea_emitter/compartment/operations.rb +38 -0
  437. data/lib/ea/svg/ea_emitter/compartment/package_contents.rb +72 -0
  438. data/lib/ea/svg/ea_emitter/compartment/package_from_parent.rb +136 -0
  439. data/lib/ea/svg/ea_emitter/compartment/shape.rb +82 -0
  440. data/lib/ea/svg/ea_emitter/compartment/stereotype_icon.rb +32 -0
  441. data/lib/ea/svg/ea_emitter/compartment/tagged_values.rb +30 -0
  442. data/lib/ea/svg/ea_emitter/compartment.rb +60 -0
  443. data/lib/ea/svg/ea_emitter/connectors.rb +46 -12
  444. data/lib/ea/svg/ea_emitter/diagram_frame.rb +143 -0
  445. data/lib/ea/svg/ea_emitter/document.rb +49 -25
  446. data/lib/ea/svg/ea_emitter/element/attribute_line_builder.rb +117 -0
  447. data/lib/ea/svg/ea_emitter/element/attribute_renderer.rb +119 -0
  448. data/lib/ea/svg/ea_emitter/element/bcol_decoder.rb +29 -0
  449. data/lib/ea/svg/ea_emitter/element/compartment_geometry.rb +113 -0
  450. data/lib/ea/svg/ea_emitter/element/constraint_renderer.rb +53 -0
  451. data/lib/ea/svg/ea_emitter/element/divider_renderer.rb +17 -0
  452. data/lib/ea/svg/ea_emitter/element/enumeration_literal_renderer.rb +34 -0
  453. data/lib/ea/svg/ea_emitter/element/filter.rb +44 -0
  454. data/lib/ea/svg/ea_emitter/element/hand_draw_shape_renderer.rb +77 -0
  455. data/lib/ea/svg/ea_emitter/element/header_line_pipeline.rb +43 -0
  456. data/lib/ea/svg/ea_emitter/element/header_line_provider/instance_spec.rb +27 -0
  457. data/lib/ea/svg/ea_emitter/element/header_line_provider/name.rb +76 -0
  458. data/lib/ea/svg/ea_emitter/element/header_line_provider/parent_ghost.rb +25 -0
  459. data/lib/ea/svg/ea_emitter/element/header_line_provider/stereotype_label.rb +68 -0
  460. data/lib/ea/svg/ea_emitter/element/header_line_provider.rb +19 -0
  461. data/lib/ea/svg/ea_emitter/element/header_lines.rb +27 -0
  462. data/lib/ea/svg/ea_emitter/element/header_renderer.rb +48 -0
  463. data/lib/ea/svg/ea_emitter/element/icon_renderer.rb +109 -0
  464. data/lib/ea/svg/ea_emitter/element/legend_renderer.rb +177 -0
  465. data/lib/ea/svg/ea_emitter/element/note_shape_renderer.rb +112 -0
  466. data/lib/ea/svg/ea_emitter/element/operation_renderer.rb +100 -0
  467. data/lib/ea/svg/ea_emitter/element/package_shape_renderer.rb +181 -0
  468. data/lib/ea/svg/ea_emitter/element/row_icon_renderer.rb +156 -0
  469. data/lib/ea/svg/ea_emitter/element/shape_renderer.rb +17 -0
  470. data/lib/ea/svg/ea_emitter/element/stereotype_icon_renderer.rb +119 -0
  471. data/lib/ea/svg/ea_emitter/element/tagged_value_renderer.rb +50 -0
  472. data/lib/ea/svg/ea_emitter/element/text_escape.rb +20 -0
  473. data/lib/ea/svg/ea_emitter/element.rb +37 -0
  474. data/lib/ea/svg/ea_emitter/elements.rb +283 -95
  475. data/lib/ea/svg/ea_emitter/font_resolver.rb +111 -0
  476. data/lib/ea/svg/ea_emitter/ghost_labels.rb +66 -0
  477. data/lib/ea/svg/ea_emitter/label/end_label.rb +266 -0
  478. data/lib/ea/svg/ea_emitter/label/midpoint_label.rb +101 -0
  479. data/lib/ea/svg/ea_emitter/label/registry.rb +50 -0
  480. data/lib/ea/svg/ea_emitter/label.rb +23 -0
  481. data/lib/ea/svg/ea_emitter/labels.rb +93 -27
  482. data/lib/ea/svg/ea_emitter/layer.rb +20 -0
  483. data/lib/ea/svg/ea_emitter/layer_sequencer.rb +93 -0
  484. data/lib/ea/svg/ea_emitter/marker/arrow_path.rb +52 -0
  485. data/lib/ea/svg/ea_emitter/marker/diamond.rb +57 -0
  486. data/lib/ea/svg/ea_emitter/marker/kind.rb +35 -0
  487. data/lib/ea/svg/ea_emitter/marker/open_triangle.rb +27 -0
  488. data/lib/ea/svg/ea_emitter/marker/package_import.rb +39 -0
  489. data/lib/ea/svg/ea_emitter/marker/plus.rb +40 -0
  490. data/lib/ea/svg/ea_emitter/marker/registry.rb +42 -0
  491. data/lib/ea/svg/ea_emitter/marker.rb +37 -0
  492. data/lib/ea/svg/ea_emitter/markers.rb +351 -64
  493. data/lib/ea/svg/ea_emitter/render_context.rb +52 -0
  494. data/lib/ea/svg/ea_emitter/style.rb +15 -0
  495. data/lib/ea/svg/ea_emitter/text_renderer.rb +92 -0
  496. data/lib/ea/svg/ea_emitter.rb +33 -11
  497. data/lib/ea/svg/parity/checker.rb +105 -0
  498. data/lib/ea/svg/parity/source.rb +59 -0
  499. data/lib/ea/svg/parity/suite.rb +113 -0
  500. data/lib/ea/svg/parity.rb +14 -0
  501. data/lib/ea/svg.rb +2 -15
  502. data/lib/ea/theme/definition.rb +176 -0
  503. data/lib/ea/theme/loader.rb +125 -0
  504. data/lib/ea/theme/registry.rb +96 -0
  505. data/lib/ea/theme.rb +37 -0
  506. data/lib/ea/transformations.rb +5 -88
  507. data/lib/ea/validation/xmi_parity.rb +80 -0
  508. data/lib/ea/validation.rb +12 -0
  509. data/lib/ea/version.rb +4 -1
  510. data/lib/ea.rb +15 -4
  511. data/lib/tasks/svg_bench.rake +87 -0
  512. data/lutaml-uml-0.5.1.gem +0 -0
  513. data/reference-docs/enterprise-architect-appearance-dialogs/appearance-1-diagram-1-themes-list.png +0 -0
  514. data/reference-docs/enterprise-architect-appearance-dialogs/appearance-1-diagram-1-themes.png +0 -0
  515. data/reference-docs/enterprise-architect-appearance-dialogs/appearance-1-diagram-2-gradients.png +0 -0
  516. data/reference-docs/enterprise-architect-appearance-dialogs/appearance-1-diagram-3-colors.png +0 -0
  517. data/reference-docs/enterprise-architect-appearance-dialogs/appearance-1-diagram-4-appearance-fonts.png +0 -0
  518. data/reference-docs/enterprise-architect-appearance-dialogs/appearance-1-diagram-4-appearance.png +0 -0
  519. data/reference-docs/enterprise-architect-appearance-dialogs/appearance-1-diagram-5-behavior.png +0 -0
  520. data/reference-docs/enterprise-architect-appearance-dialogs/appearance-1-diagram-6-sequence.png +0 -0
  521. data/reference-docs/enterprise-architect-appearance-dialogs/appearance-1-diagram.png +0 -0
  522. data/reference-docs/enterprise-architect-appearance-dialogs/appearance-2-objects.png +0 -0
  523. data/reference-docs/enterprise-architect-appearance-dialogs/appearance-3-links.png +0 -0
  524. metadata +464 -26
  525. data/lib/ea/diagram/configuration.rb +0 -379
  526. data/lib/ea/diagram/element_renderers/base_renderer.rb +0 -77
  527. data/lib/ea/diagram/element_renderers/class_renderer.rb +0 -323
  528. data/lib/ea/diagram/element_renderers/connector_renderer.rb +0 -41
  529. data/lib/ea/diagram/element_renderers/package_renderer.rb +0 -61
  530. data/lib/ea/diagram/element_renderers.rb +0 -43
  531. data/lib/ea/diagram/extractor.rb +0 -566
  532. data/lib/ea/diagram/layout_engine.rb +0 -170
  533. data/lib/ea/diagram/path_builder.rb +0 -202
  534. data/lib/ea/diagram/style_parser.rb +0 -42
  535. data/lib/ea/diagram/style_resolver.rb +0 -291
  536. data/lib/ea/diagram/svg_renderer.rb +0 -274
  537. data/lib/ea/diagram/util.rb +0 -73
  538. data/lib/ea/svg/bounds_calculator.rb +0 -74
  539. data/lib/ea/svg/connector_path.rb +0 -138
  540. data/lib/ea/svg/element_box.rb +0 -256
  541. data/lib/ea/svg/renderer.rb +0 -77
  542. data/lib/ea/svg/style_resolver.rb +0 -72
  543. data/lib/ea/transformations/configuration.rb +0 -333
  544. data/lib/ea/transformations/format_registry.rb +0 -366
  545. data/lib/ea/transformations/parsers/base_parser.rb +0 -482
  546. data/lib/ea/transformations/parsers/qea_parser.rb +0 -401
  547. data/lib/ea/transformations/parsers/xmi_parser.rb +0 -243
  548. data/lib/ea/transformations/transformation_engine.rb +0 -390
@@ -0,0 +1,148 @@
1
+ # TODO-D 56: Package contents rendering (DONE)
2
+
3
+ ## Before
4
+
5
+ When a diagram's `t_diagram.ShowPackageContents` flag was non-zero,
6
+ EA renders each Package element with:
7
+ - A 2-line tab when the package has a stereotype («applicationSchema»)
8
+ - A body compartment listing child classifiers and sub-packages as
9
+ "+ Name" rows
10
+ - A per-row icon whose shape encodes the child's type
11
+
12
+ Our renderer produced only the bare folder silhouette. All test.qea
13
+ "Test Model" diagrams and basic.qea "Package Imports" diagrams
14
+ under-rendered by ~70 elements each.
15
+
16
+ ## After
17
+
18
+ ### Source side
19
+
20
+ - `Ea::Sources::Qea::PackageBuilder#stereotype_refs_for`: now reads
21
+ the t_object.Stereotype column for the package's mirror row
22
+ (matched by ea_guid). EA stores the stereotype on t_object, not
23
+ t_package.
24
+ - `Ea::Sources::Qea::DiagramBuilder#package_contents_enabled?`:
25
+ threads `show_package_contents` (non-zero t_diagram column) into
26
+ `Ea::Model::Diagram`.
27
+ - `Ea::Model::Diagram#show_package_contents`: boolean attribute
28
+ controlling whether the package-contents compartment is rendered.
29
+
30
+ ### Render side
31
+
32
+ - `Ea::Svg::EaEmitter::Element::PackageShapeRenderer`: now accepts
33
+ an optional `stereotype:` argument. When present, the tab grows
34
+ to 36px tall (vs 20px) and renders two left-aligned text lines
35
+ («stereotype» + name). Tab width is fixed at 105px (EA convention).
36
+ - `Ea::Svg::EaEmitter::Compartment::PackageContents`: new
37
+ compartment module that renders the body's child rows. Each row
38
+ is one `<text>` element ("+ Name") plus a small per-type icon.
39
+ - `Ea::Svg::EaEmitter::Element::RowIconRenderer`: new renderer for
40
+ the per-row icons. Three kinds:
41
+ - `:enumeration` (12×13 green rect + 7 paths) — used for
42
+ Enumeration classifiers or Klass with stereotype "enumeration".
43
+ - `:package` (13×9 folder rect, no paths) — used for sub-Packages.
44
+ - `:default` (11×14 + 11×4 rects + 7 paths) — used for other
45
+ Classifiers (Klass, DataType, etc.).
46
+ - `Ea::Svg::EaEmitter::Compartment::Shape`: threads the package's
47
+ stereotype to PackageShapeRenderer.
48
+ - `Ea::Svg::EaEmitter::Elements`: computes `package_content_lines`
49
+ for Package model elements when `diagram.show_package_contents`
50
+ is truthy. Children include both Classifier and sub-Package
51
+ instances; the icon kind is chosen by classifier type or
52
+ "enumeration" stereotype.
53
+
54
+ ### Specs
55
+
56
+ - Updated `spec/ea/svg/ea_emitter/compartment_spec.rb` to include
57
+ PackageContents in the expected ALL list.
58
+
59
+ ## Verification
60
+
61
+ - simple.qea: 2/2 (100% strict-perfect) — unchanged.
62
+ - basic.qea: 21/22 matched within tolerance (up from 20/22).
63
+ 14/22 strict-perfect (up from 7/22).
64
+ - test.qea: 2/2 matched within tolerance. Test Model is strict
65
+ perfect (was shape_delta=71). TestSchema still has a small
66
+ pre-existing -4 text gap unrelated to package contents.
67
+ - Plateau: rect/path/polygon deltas unchanged (text improved
68
+ slightly, -626 → -615, from stereotype rendering).
69
+ - 1767 specs pass, 0 failures.
70
+
71
+ ## Remaining gaps
72
+
73
+ - test.qea TestSchema: -3 text. Ref includes «voidable» constraint
74
+ stereotype, "constraints" header, and "{pattern}" annotation that
75
+ we don't render yet. Pre-existing.
76
+ - basic.qea Domain Model: rect=+3 (Concept boxes drawn as rects
77
+ but ref uses bezier paths). Pre-existing.
78
+ - basic.qea Class-diagram-with-X diagrams: path deltas from
79
+ association marker encoding differences (QEA polygon vs XMI
80
+ arrow path). Pre-existing.
81
+ - basic.qea Object diagrams: missing instance-name underline paths
82
+ and instance label format ("Object 01 / roleOne: Class A"). Needs
83
+ an InstanceSpecification model. Pre-existing.
84
+
85
+ ## Follow-up commits
86
+
87
+ `feat: promote enumeration-stereotyped Class to Enumeration model` —
88
+ ClassifierBuilder now treats a Class with stereotype "enumeration"
89
+ as an Enumeration. Closes 1 additional text delta on TestSchema
90
+ (-4 → -3).
91
+
92
+ `feat: constraints compartment (italic header + {name} expression)` —
93
+ Adds Ea::Model::Constraint, reads t_objectconstraint in the QEA
94
+ classifier builder, and renders via Compartment::Constraints +
95
+ Element::ConstraintRenderer. Closes 2 text deltas on TestSchema
96
+ (-3 → -1).
97
+
98
+ `feat: render attribute stereotypes as separate text lines` —
99
+ AttributeRenderer.lines_for inserts «stereotype» entries before
100
+ stereotyped properties. Closes the final TestSchema text gap
101
+ (-1 → 0).
102
+
103
+ `feat: instance-name underline for object diagrams` — Object
104
+ diagrams draw a horizontal underline below each instance name.
105
+ New Compartment::InstanceUnderline module fires for diagrams
106
+ where diagram_type=="Object". RenderContext gains a :diagram
107
+ field. Improves path delta on all 4 basic.qea object diagrams.
108
+
109
+ `feat: «import» markers for Package connectors` — New
110
+ Marker::PackageImport kind emits both a closed trapezoid at the
111
+ source end and an open V-arrow at the target end of Package
112
+ («import») connectors. Closes the basic.qea Package Imports
113
+ path delta (-4 → 0).
114
+
115
+ `feat: Object diagram — divider + suppress arrows` — Object
116
+ diagrams render associations as instance-level links without
117
+ navigability arrows. Markers suppresses :arrow specs for
118
+ Association connectors when diagram_type=="Object". HeaderDivider
119
+ gains a diagram-type-aware discriminator: on Object diagrams the
120
+ divider is shown when bounds.height > 50 (matches EA's "has slot
121
+ compartment" heuristic). Closes path deltas on all 4 basic.qea
122
+ Object diagrams. Starter Object Diagram is now strict-perfect.
123
+
124
+ ## Final state
125
+
126
+ - simple.qea: 2/2 strict-perfect (100%).
127
+ - basic.qea: **16/22 strict-perfect**, 22/22 within tolerance.
128
+ - test.qea: 1/2 strict-perfect (Test Model perfect; TestSchema at
129
+ text=0, path=-1).
130
+ - Plateau: rect -221, path -280, polygon -6, text -615.
131
+ - 1800 specs pass, 0 failures.
132
+
133
+ ## Remaining gaps (all pre-existing, out of scope)
134
+
135
+ - test.qea TestSchema: -1 path (association marker encoding).
136
+ - basic.qea Domain Model: +3 rect (Concept boxes drawn as rects
137
+ but ref uses bezier paths in a "domain class" style with
138
+ Comic Sans MS italic font).
139
+ - basic.qea Classes (×2): +1 path each (extra arrow marker on
140
+ tree-routed Association connectors — source discriminator not
141
+ yet identified; same connectors on Multiplicities render WITH
142
+ arrows in ref, so the rule is more subtle than waypoint count).
143
+ - basic.qea Object diagrams (×3 with text deltas): instance label
144
+ format ("Object 01 / roleOne: Class A"), slot value renderings
145
+ ("attr = value"), and "(from package)" subtitle. Needs
146
+ InstanceSpecification model.
147
+ - Association marker encoding: QEA polygon vs XMI arrow path
148
+ discriminator not yet identified.
@@ -0,0 +1,100 @@
1
+ # TODO-D 57: InstanceSpecification model + slot rendering
2
+
3
+ ## Status: open (blocks 3 basic.qea diagrams + plateau)
4
+
5
+ EA stores UML InstanceSpecifications in `t_object` rows with
6
+ `Object_Type="Object"`. Currently we parse these as `Klass`
7
+ instances (the closest classifier shape). Ref renders them as
8
+ instances with three features we don't emit:
9
+
10
+ 1. **Instance label format** in the header: `instance_name` plus,
11
+ when the instance is a role in an association, the role +
12
+ classifier name (e.g. `"Object 01 / roleOne: Class A"`).
13
+ 2. **Slot compartment** below the header: each `RunState` variable
14
+ is rendered as `"variable = value"` (e.g.
15
+ `"attributeOne = valueOne"`).
16
+ 3. **From-package subtitle** below the slots:
17
+ `"(from Objects)"` — the containing package name in italics.
18
+
19
+ ## Affected diagrams
20
+
21
+ | Diagram | text_delta | Notes |
22
+ |---------|-----------|-------|
23
+ | Basic Object Diagram with Value Specification | -2 | 1 slot per instance |
24
+ | Objects as Instances of Classes | -9 | 1 instance label + slot + from-package per box |
25
+ | Object with Value Specifications | -19 | 1 instance label + multiple slots + from-package per box |
26
+
27
+ Plus widespread contribution to the plateau text delta (-615).
28
+
29
+ ## Source data
30
+
31
+ `t_object` columns for Object instances:
32
+ - `Object_Type="Object"`
33
+ - `Name="Object 01"` (the instance name)
34
+ - `Classifier=<id>` (the class this is an instance of; 0 = none)
35
+ - `RunState="@VAR;Variable=X;Value=Y;Op==;@ENDVAR;..."` (slots)
36
+
37
+ The role name (`"roleOne"`) comes from the connector's source role
38
+ field on the association linking this instance to another.
39
+
40
+ ## Implementation plan
41
+
42
+ ### 1. Model
43
+
44
+ - `Ea::Model::InstanceSpecification < Base` — new model class
45
+ - `name :string`
46
+ - `classifier_id :string` (id of the class this is an instance of)
47
+ - `slots :Slot, collection: true`
48
+ - `role_name :string` (filled in later by relationship resolver)
49
+ - `package_id :string`
50
+ - `qualified_name :string`
51
+ - `Ea::Model::Slot < Base` — a slot value
52
+ - `name :string` (the variable)
53
+ - `value :string`
54
+ - `op :string` (default `"="`)
55
+
56
+ ### 2. Source side
57
+
58
+ - `Ea::Sources::Qea::InstanceBuilder` — new builder that reads
59
+ `t_object` rows where `Object_Type="Object"` and parses `RunState`
60
+ into Slot instances. Replaces the `Object → Klass` mapping in
61
+ `ObjectClassifierMap`.
62
+ - Update `Ea::Sources::Qea::Adapter` to call both `ClassifierBuilder`
63
+ and `InstanceBuilder`.
64
+ - Update `Document#index_by_id` to include instance specifications.
65
+
66
+ ### 3. Render side
67
+
68
+ - `Compartment::InstanceHeader` (new) — renders the instance label
69
+ format `name / role: ClassName` in the header.
70
+ - `Compartment::InstanceSlots` (new) — renders the slot compartment
71
+ (`variable = value` lines).
72
+ - `Compartment::InstanceFromPackage` (new) — renders the
73
+ `"(from packageName)"` subtitle in italics.
74
+ - The existing `InstanceUnderline` module is reused for the
75
+ instance-name underline.
76
+ - `Shape` compartment: dispatch instance specs to a new
77
+ `InstanceShapeRenderer` (or reuse `ShapeRenderer` since the box
78
+ shape is the same).
79
+
80
+ ### 4. Specs
81
+
82
+ - Instance model spec (round-trip JSON)
83
+ - InstanceBuilder spec (parses RunState correctly)
84
+ - InstanceSlots spec (renders "var = value")
85
+ - InstanceFromPackage spec (renders italic "(from X)")
86
+
87
+ ## Discriminator
88
+
89
+ When `diagram.diagram_type == "Object"` AND `model_element.is_a?(InstanceSpecification)`:
90
+ - Header: instance label format
91
+ - Body: slot compartment + from-package subtitle
92
+
93
+ Otherwise: standard classifier rendering.
94
+
95
+ ## Why deferred initially
96
+
97
+ Requires a new top-level model class, source-builder wiring, and 3
98
+ new compartments. ~300 lines of code + ~150 lines of specs. Affects
99
+ the parity metric broadly (basic.qea +3 diagrams strict-perfect,
100
+ plateau text delta improves).
@@ -0,0 +1,67 @@
1
+ # TODO-D 58: Domain Model note text + missing multiplicity
2
+
3
+ ## Status: open (blocks 1 basic.qea diagram)
4
+
5
+ Domain Model is at shape_delta_total=0 (sum-zero parity) but has
6
+ text_delta=-7. Two missing items:
7
+
8
+ ### A. Wrapped note text (-6)
9
+
10
+ EA wraps long note text across multiple `<text>` lines. For the
11
+ Domain Model Concepts, the note `"Detailed notes that describe the
12
+ concept."` is wrapped onto two lines per element:
13
+
14
+ <text x="45" y="95">[Detailed notes that describe the </text>
15
+ <text x="45" y="109">concept.]</text>
16
+
17
+ The leading `[` and trailing `]` are EA's convention for marking
18
+ the note body (not part of the actual note content). Line-wrap
19
+ width is determined by the element bounds width minus padding
20
+ (~125px usable for a 167px-wide box at font size 7pt).
21
+
22
+ Currently we don't render note text in element bodies at all. The
23
+ note text comes from `t_object.Note`.
24
+
25
+ ### B. Missing target multiplicity (-1)
26
+
27
+ One Aggregation connector (`Relationship Two`) has source mult
28
+ `0..*` (rendered at top) and target mult `1..1` (should render
29
+ near Concept A's top edge but doesn't). The target endpoint lands
30
+ inside the element box and our EndLabel skips the label.
31
+
32
+ ## Implementation plan
33
+
34
+ ### For (A) — wrapped note text
35
+
36
+ - `Ea::Model::Classifier` already has `annotations` — re-use for
37
+ the documentation note OR add `note :string` as a separate field
38
+ (EA's `t_object.Note` is distinct from `t_objectproperties` tagged
39
+ values).
40
+ - `Ea::Sources::Qea::ClassifierBuilder#note_for` reads `object.note`.
41
+ - New `Compartment::NoteText` (different from `Compartment::NoteBody`
42
+ which handles Note elements):
43
+ - Splits the note text into lines based on a width estimate
44
+ - Wraps with `[` ... `]`
45
+ - Renders one `<text>` per line below the header divider
46
+ - Discriminator: render when `classifier.note` is non-empty AND
47
+ the element has no attribute compartment (the note replaces
48
+ attributes in this style).
49
+
50
+ ### For (B) — multiplicity inside element
51
+
52
+ - `Ea::Svg::EaEmitter::Label::EndLabel`: relax the
53
+ "skip when inside element" rule for multiplicity labels — they
54
+ should render even when the anchor is inside an element box
55
+ (just offset outward).
56
+
57
+ ## Verification
58
+
59
+ - basic.qea "Domain Model": text_delta -7 → 0.
60
+ - basic.qea: 16/22 → 17/22 strict-perfect.
61
+
62
+ ## Why deferred
63
+
64
+ Note wrapping needs a width-estimation helper (font size × char
65
+ count × width factor) and a `Compartment::NoteText` module. The
66
+ multiplicity fix requires relaxing EndLabel's collision rule which
67
+ could regress other diagrams.
@@ -0,0 +1,57 @@
1
+ # TODO-D 59: Classes diagram association arrow discriminator
2
+
3
+ ## Status: open (blocks 2 basic.qea diagrams)
4
+
5
+ Two basic.qea "Classes" diagrams have shape_delta=1 each. We render
6
+ one extra `<path>` per diagram — the navigability arrow at the
7
+ target end of an Association connector that EA's reference SVG
8
+ omits.
9
+
10
+ ## Investigation summary
11
+
12
+ Compared fields across the rendering-pipeline:
13
+
14
+ | Diagram | Direction | SourceStyle | DestStyle | LineStyle | RouteStyle | SourceCard | DestCard | SourceIsAggregate | DestIsAggregate | SX/SY/EX/EY | Object types |
15
+ |---------|-----------|-------------|-----------|-----------|------------|------------|----------|-------------------|-----------------|-------------|--------------|
16
+ | Multiplicities (HAS arrow) | Unspecified | Navigable=U | Navigable=U | 0 | 3 | 0..* | 0..* | 0 | 0 | -6/-2/-57/-2 | Class ↔ Class |
17
+ | Classes (NO arrow) | Unspecified | Navigable=U | Navigable=U | 0 | 3 | 0..2 | 1 | 0 | 0 | -1/4/3/4 | Class ↔ Class |
18
+
19
+ All fields identical except cardinality and SX/SY/EX/EY values.
20
+ The visual difference: Multiplicities renders as a single straight
21
+ path + arrow polygon; Classes renders as 3 separate horizontal
22
+ segments + no arrow. EA appears to apply an internal "are bends
23
+ real?" heuristic.
24
+
25
+ ## Hypothesis
26
+
27
+ EA computes the maximum perpendicular deviation of bend waypoints
28
+ from the straight source-target line. Below a threshold (likely
29
+ ~2-3px), bends are treated as noise and the connector renders as
30
+ straight WITH navigability arrow. Above the threshold, the
31
+ connector renders as orthogonal segments with NO arrow.
32
+
33
+ For Multiplicities: deviations 1-2px → straight + arrow.
34
+ For Classes: deviations 4-5px → segmented + no arrow.
35
+
36
+ ## Implementation plan
37
+
38
+ - In `Ea::Svg::EaEmitter::Connectors#path_for`, compute the
39
+ perpendicular deviation of each interior waypoint from the
40
+ source-target line. If max deviation ≤ THRESHOLD (try 3), emit
41
+ a straight 2-point path. Otherwise keep current multi-segment
42
+ path.
43
+ - In `Ea::Svg::EaEmitter::Markers#suppress_arrow?`, suppress
44
+ Association arrow when the connector is multi-segment (max
45
+ deviation > THRESHOLD).
46
+ - THRESHOLD constant lives on `Connectors` (or a shared
47
+ `ConnectorRouting` module) so both renderers use the same value.
48
+
49
+ ## Verification
50
+
51
+ - basic.qea "Classes" (×2): shape_delta 1 → 0.
52
+ - basic.qea: 16/22 → 18/22 strict-perfect.
53
+
54
+ ## Risk
55
+
56
+ The threshold value is reverse-engineered from a single sample.
57
+ Verifying against plateau connectors would confirm.
@@ -0,0 +1,40 @@
1
+ # TODO-D 60: TestSchema association marker encoding (-1 path)
2
+
3
+ ## Status: open (blocks 1 test.qea diagram)
4
+
5
+ test.qea TestSchema is at text_delta=0 but path_delta=-1.
6
+
7
+ ## Symptom
8
+
9
+ Ref renders a particular Association connector with an open
10
+ `<path>` V-shape arrow at the target end. We render the connector
11
+ line but no arrow — the marker is suppressed somewhere in our
12
+ dispatch.
13
+
14
+ ## Likely cause
15
+
16
+ The connector is on a Logical (not Object) diagram so our
17
+ "Object diagrams suppress Association arrows" rule doesn't apply.
18
+ Yet we still don't emit the marker. The Markers#specs_for path
19
+ returns no specs because... needs investigation.
20
+
21
+ ## Plan
22
+
23
+ 1. Render TestSchema and identify which connector is missing its
24
+ arrow.
25
+ 2. Trace through Marker::Registry.specs_for and confirm ArrowPath
26
+ is registered and returns a spec.
27
+ 3. Trace through Markers#entries_for and check whether the spec is
28
+ being filtered out (suppress_arrow? or render_shape returns nil).
29
+ 4. Most likely culprit: `unit_vector` returns nil because tip and
30
+ base are coincident (connector shorter than 1 unit vector step).
31
+
32
+ ## Verification
33
+
34
+ - test.qea TestSchema: path_delta -1 → 0.
35
+ - test.qea: 1/2 → 2/2 strict-perfect (100%).
36
+
37
+ ## Why deferred
38
+
39
+ Small delta (-1 path) and the fix likely requires non-trivial
40
+ debugging of the unit-vector geometry for very short connectors.
@@ -0,0 +1,55 @@
1
+ # TODO-D 61: Legend block rendering
2
+
3
+ ## Status: completed
4
+
5
+ The plateau QEA's `t_object` rows with `Object_Type='Text'` and
6
+ `StyleEx` carrying `LegendOpts=` are auto-generated legend blocks.
7
+ EA renders each as a 4-rect + 4-text cluster (container + 3 colored
8
+ icons + title + 3 labels), with the legend configuration parsed
9
+ from a sibling `t_xref` row keyed off the same GUID.
10
+
11
+ ## Implementation
12
+
13
+ - `Ea::Model::Legend` and `Ea::Model::LegendItem` — new models
14
+ carrying the legend title, colors (BGR-packed), and per-item
15
+ background colors. Default colors pulled from plateau SVG refs.
16
+ - `Ea::Model::Note` gains an optional `legend` attribute. Text
17
+ elements with `LegendOpts=` in StyleEx parse the legend payload
18
+ at load time; other Notes stay unencumbered.
19
+ - `Ea::Sources::Qea::LegendBuilder` parses the `@PROP=...@ENDPROP;`
20
+ blobs in `t_xref.Description` for a given Text element GUID.
21
+ - `Ea::Svg::EaEmitter::Element::LegendRenderer` emits the container
22
+ rect, icon rects, title text, and item labels. BGR colors decode
23
+ via the existing `Element::BColDecoder`.
24
+ - `Compartment::Shape` dispatches to `LegendRenderer` when the
25
+ element carries a legend payload; `Compartment::NoteBody` skips
26
+ rendering (legend replaces note body).
27
+
28
+ ## Related fix: marker dedup removed
29
+
30
+ Reference inspection showed EA does NOT dedup polygon markers even
31
+ when N connectors share the same anchor — the Bridge diagram emits
32
+ 9 distinct triangle polygons at one parent anchor. Removed the
33
+ `Markers::Entry#generalization_tree_routed?` dedup logic; EA emits
34
+ one marker per connector, period.
35
+
36
+ ## Related fix: spec pollution
37
+
38
+ `spec/ea/svg/qea_regression_spec.rb` and
39
+ `spec/ea/svg/visual_regression_spec.rb` both defined top-level
40
+ constants named `REF_DIR` inside `RSpec.describe` blocks. Ruby
41
+ resolves these to top-level constants — the spec loaded second
42
+ won, silently pointing the other spec at the wrong reference SVG
43
+ directory. Renamed to `QEA_REF_DIR` and `VISUAL_REF_DIR`.
44
+
45
+ ## Results (plateau QEA)
46
+
47
+ | Metric | Before | After | Change |
48
+ |---------|--------|--------|--------|
49
+ | Matched | 130/188| 137/188| +7 |
50
+ | rect | -460 | +4 | +464 |
51
+ | path | -92 | -92 | — |
52
+ | polygon | +27 | +25 | -2 |
53
+ | text | -519 | -55 | +464 |
54
+
55
+ basic.qea and test.qea remain at 22/22 and 2/2 respectively.
@@ -0,0 +1,59 @@
1
+ # TODO-D 61: Plateau parity gaps
2
+
3
+ ## Status: open (broad cross-cutting gaps on plateau QEA)
4
+
5
+ The plateau is the `20251010_current_plateau_v5.1.qea` file at
6
+ `examples/qea/`. Its 188 reference SVGs live at
7
+ `examples/exports/20251010_current_plateau_v5/Images/`.
8
+
9
+ A separate plateau XMI is at
10
+ `~/src/mn/mn-samples-plateau/sources/xmi/plateau_all_packages_export.xmi`
11
+ with its own reference SVGs at
12
+ `~/src/mn/mn-samples-plateau/sources/001-mds/xmi-images/`.
13
+
14
+ ## Current state — Plateau QEA (examples/)
15
+
16
+ | Metric | Before | After improvements | Change |
17
+ |--------|--------|-------------------|--------|
18
+ | Matched | 126/188 | **130/188** | +4 |
19
+ | rect | -460 | **-460** | — |
20
+ | path | -455 | **-92** | +363 recovered |
21
+ | polygon | +27 | **+27** | — |
22
+ | text | -519 | **-519** | — |
23
+
24
+ Key improvements this session:
25
+ - Horizontal-tree-routed arrow suppression (narrower check)
26
+ - Marker dedup changed to polygon-only (never dedup arrows)
27
+ → recovered ~200 association arrow paths on plateau
28
+
29
+ ## Current state — Plateau XMI (~/src/mn/)
30
+
31
+ | Metric | Value |
32
+ |--------|-------|
33
+ | Diagrams matched (tolerance ≤5) | 127/185 |
34
+ | rect delta | -221 (-11.0%) |
35
+ | path delta | -338 (-10.2%) |
36
+ | polygon delta | -6 (-0.6%) |
37
+ | text delta | +97 (+0.6%) |
38
+
39
+ ## Where the deltas come from
40
+
41
+ ### rect -460 (QEA) / -221 (XMI)
42
+ - Missing visibility icons (2 rects per attribute × many elements)
43
+ - Package-content child rows missing on some diagrams
44
+ - Element shape encoding (rect vs polygon)
45
+
46
+ ### path -455 (QEA) / -338 (XMI)
47
+ - Connector arrow markers (tree-routed suppression removes some)
48
+ - Visibility icon paths (7 per attr × many elements)
49
+ - Connector routing encoding differences
50
+
51
+ ### text -519 (QEA) / +97 (XMI)
52
+ - QEA has richer data (RunState, more tagged values) but some
53
+ texts are not rendered (instance labels, slot values)
54
+ - XMI over-renders some texts (from InstanceSpecification parsing)
55
+
56
+ ## Plan
57
+
58
+ Each delta spans dozens of diagrams. Improvements require broad
59
+ pipeline changes rather than single-diagram fixes.
@@ -0,0 +1,56 @@
1
+ # TODO-D 62: Ghost element rendering (off-canvas connector endpoints)
2
+
3
+ ## Status: open
4
+
5
+ EA phantom-renders classifier names near connector endpoints that
6
+ reference elements NOT placed on the current diagram. These "ghost
7
+ elements" appear as italic class names (e.g. `_CityObject`,
8
+ `_Site`, `_Geometry`) at the connector's off-canvas end. They are
9
+ NOT in `t_diagramobjects` for the diagram but ARE referenced by
10
+ `t_connector.Start_Object_ID` / `End_Object_ID` of connectors
11
+ that ARE on the diagram.
12
+
13
+ ## Evidence (plateau QEA, "indoor" diagram)
14
+
15
+ - `_CityObject` does not appear in `t_diagramobjects` for the
16
+ indoor diagram.
17
+ - It IS referenced by connectors on the indoor diagram (e.g.
18
+ generalizations from `Room` to `_CityObject`).
19
+ - EA renders the name as 5+ separate italic `<text>` elements at
20
+ different positions, one per connector endpoint.
21
+
22
+ ## Approach
23
+
24
+ 1. **Source side**: in `DiagramBuilder`, walk every renderable
25
+ connector and look up its source/target object via
26
+ `database.find_connector` → `start_object_id`/`end_object_id` →
27
+ `database.find_object`. When the object is NOT placed on this
28
+ diagram (no entry in `t_diagramobjects`), synthesise a
29
+ "ghost element" annotation on the connector: the off-canvas
30
+ end's classifier name + a virtual anchor position (probably
31
+ the on-canvas endpoint).
32
+
33
+ 2. **Model side**: add `ghost_labels` to `DiagramConnector` —
34
+ a collection of `(name, end_kind, anchor_offset)` tuples.
35
+
36
+ 3. **Renderer side**: emit each ghost label as an italic `<text>`
37
+ at the connector's endpoint, offset to one side. Match EA's
38
+ offset rules (need to reverse-engineer from reference SVGs).
39
+
40
+ ## Impact
41
+
42
+ Closing the text gap from -292 to near 0 on plateau QEA. Most of
43
+ the missing text delta comes from ghost labels:
44
+ - indoor: -17 (mostly `_CityObject`)
45
+ - frn_1: -7
46
+ - cons_1: -6
47
+ - tran_2: -5
48
+ - bldg_1: -6 (BuildingAttribute)
49
+ - and 10+ more diagrams with -1 to -5 each.
50
+
51
+ Combined: ~80-100 missing ghost labels across the plateau.
52
+
53
+ ## Related
54
+
55
+ - TODO-D 26 (Investigate phantom class headers from connector
56
+ endpoints) is the older writeup of the same issue.
@@ -0,0 +1,36 @@
1
+ # TODO-D 63: Qualified-name line wrap for long class names
2
+
3
+ ## Status: completed
4
+
5
+ EA wraps long qualified class names (e.g. `brid::OuterFloorSurface`)
6
+ across TWO `<text>` elements when the rendered width exceeds the
7
+ element's header width.
8
+
9
+ ## Implementation
10
+
11
+ `Ea::Svg::EaEmitter::Element::HeaderLines.for` now accepts
12
+ `bounds_width:` and `font_size:` keyword args. When the qualified
13
+ name's estimated rendered width (using `TextRenderer.estimate_width`
14
+ with `width_factor=0.55` and `QUALIFIED_WRAP_PADDING=8`) exceeds
15
+ the element's bounds, the name splits into two header lines:
16
+
17
+ 1. `"qualifier::"` (with trailing `::`)
18
+ 2. `"ClassName"` (the base name after `::`)
19
+
20
+ The `Elements` orchestrator threads `raw_bounds.width` and the
21
+ resolved `font_size` through to `HeaderLines.for`.
22
+
23
+ ## Results
24
+
25
+ - Plateau text delta: -3 → +5 (slight over-rendering on a few
26
+ borderline cases — both name+wrap and not-quite-fit names).
27
+ - 154/188 matched diagrams (unchanged).
28
+ - basic.qea, test.qea, simple.qea: unchanged.
29
+
30
+ ## Tuning
31
+
32
+ Width factor 0.55 matches Carlito 9pt bold's average glyph advance
33
+ for the CJK + Latin mix on the plateau. The 8px padding accounts
34
+ for the element's internal left+right padding that EA reserves
35
+ around header text. Both constants are at the top of HeaderLines
36
+ for easy future adjustment if EA's font metrics shift.
@@ -0,0 +1,22 @@
1
+ # TODO-D 64: Missing «property» stereotype labels on association roles
2
+
3
+ ## Status: completed
4
+
5
+ The `PROPERTY_OY_GAP_THRESHOLD = 15` constant in
6
+ `Ea::Svg::EaEmitter::Label::EndLabel` was incorrectly gating
7
+ `«property»` rendering. Reference SVGs show EA always emits the
8
+ stereotype when both a role name and multiplicity are present,
9
+ regardless of the OY gap between the LLT and LLB geometry boxes.
10
+
11
+ ## Fix
12
+
13
+ Removed the threshold; `property_label?` now returns true whenever
14
+ called. The basic.qea associations that skip `«property»` do so
15
+ because they have no role name, not because of any gap.
16
+
17
+ ## Results
18
+
19
+ Plateau QEA text delta: -292 → -3 (closed 289 missing text labels).
20
+ test.qea text delta: 0 → +2 (regression of 2 —
21
+ the threshold was masking a different issue there).
22
+ Matched count unchanged (154/188).