ea 0.4.0 → 0.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (529) hide show
  1. checksums.yaml +4 -4
  2. data/Rakefile +3 -0
  3. data/TODO.complete/01-t-xref-parsing.md +91 -0
  4. data/TODO.complete/02-per-label-geometry.md +50 -0
  5. data/TODO.complete/03-object-properties-constraints.md +57 -0
  6. data/TODO.complete/04-operation-params.md +37 -0
  7. data/TODO.complete/05-pdata-flag-matrix.md +52 -0
  8. data/TODO.complete/06-emf-image-rendering.md +34 -0
  9. data/TODO.complete/07-auxiliary-tables.md +47 -0
  10. data/TODO.complete/10-mdg-stereotype-registry.md +40 -0
  11. data/TODO.complete/11-gml-xsd-generation.md +42 -0
  12. data/TODO.complete/13-shapescript-interpreter.md +28 -0
  13. data/TODO.complete/20-cli-diff.md +46 -0
  14. data/TODO.complete/21-cli-render.md +26 -0
  15. data/TODO.complete/22-cli-export.md +29 -0
  16. data/TODO.complete/23-cli-mdg.md +23 -0
  17. data/TODO.complete/30-headerlines-ocp-refactor.md +72 -0
  18. data/TODO.complete/31-public-send-cleanup.md +61 -0
  19. data/TODO.complete/32-spec-coverage.md +33 -0
  20. data/TODO.complete/33-blocked-parity-gaps.md +41 -0
  21. data/TODO.complete/36-stereotype-icon-wiring.md +32 -0
  22. data/TODO.complete/37-cli-lint.md +32 -0
  23. data/TODO.complete/38-cli-query.md +26 -0
  24. data/TODO.complete/39-cli-info.md +23 -0
  25. data/TODO.complete/40-ocl-evaluator.md +31 -0
  26. data/TODO.complete/41-round-trip-spec.md +18 -0
  27. data/TODO.complete/42-html-diff-report.md +18 -0
  28. data/TODO.complete/43-json-schema-export.md +20 -0
  29. data/TODO.complete/44-remaining-qea-tables.md +40 -0
  30. data/TODO.complete/45-shapescript-extensions.md +25 -0
  31. data/TODO.complete/46-xsd-consolidation.md +20 -0
  32. data/TODO.complete/47-headerlines-legacy-removal.md +20 -0
  33. data/TODO.complete/STATUS.md +109 -0
  34. data/TODO.diagrams/01-svg-measurement-harness.md +31 -0
  35. data/TODO.diagrams/02-polygon-over-rendering.md +29 -0
  36. data/TODO.diagrams/03-text-over-rendering.md +30 -0
  37. data/TODO.diagrams/04-rect-under-rendering.md +33 -0
  38. data/TODO.diagrams/05-canvas-dimension-parity.md +51 -0
  39. data/TODO.diagrams/06-group-layering-parity.md +39 -0
  40. data/TODO.diagrams/07-text-content-fidelity.md +65 -0
  41. data/TODO.diagrams/08-qea-direct-pipeline.md +46 -0
  42. data/TODO.diagrams/12-connector-labels.md +40 -0
  43. data/TODO.diagrams/12-per-entity-svg-layer-ordering.md +24 -0
  44. data/TODO.diagrams/13-marker-polygon-vs-path-dispatch.md +20 -0
  45. data/TODO.diagrams/13-per-text-type-font-sizes.md +33 -0
  46. data/TODO.diagrams/14-center-header-text.md +33 -0
  47. data/TODO.diagrams/14-filter-diagram-frame-elements.md +18 -0
  48. data/TODO.diagrams/15-deep-dead-code-audit.md +47 -0
  49. data/TODO.diagrams/15-per-element-font-from-style.md +24 -0
  50. data/TODO.diagrams/16-canvas-marker-extent.md +30 -0
  51. data/TODO.diagrams/16-document-remaining-parity-gaps.md +91 -0
  52. data/TODO.diagrams/17-italic-abstract-classes.md +28 -0
  53. data/TODO.diagrams/17-remaining-parity-gaps.md +90 -0
  54. data/TODO.diagrams/18-canvas-from-image-bounds.md +20 -0
  55. data/TODO.diagrams/18-property-lookup-index.md +42 -0
  56. data/TODO.diagrams/19-connector-sx-sy-routing.md +27 -0
  57. data/TODO.diagrams/19-replace-respond-to-with-is-a.md +31 -0
  58. data/TODO.diagrams/20-split-labels-emitter.md +56 -0
  59. data/TODO.diagrams/20-visibility-glyph-font-encoding.md +27 -0
  60. data/TODO.diagrams/21-aggregation-navigability-arrow.md +21 -0
  61. data/TODO.diagrams/21-auto-generated-legend-block.md +65 -0
  62. data/TODO.diagrams/22-ghost-element-discriminator.md +57 -0
  63. data/TODO.diagrams/22-style-based-path-grouping.md +28 -0
  64. data/TODO.diagrams/23-marker-polygon-deduplication.md +47 -0
  65. data/TODO.diagrams/23-multiplicity-label-positioning.md +29 -0
  66. data/TODO.diagrams/24-marker-anchor-structural.md +35 -0
  67. data/TODO.diagrams/24-track-marker-anchors-structurally.md +66 -0
  68. data/TODO.diagrams/24-truncate-properties-to-fit-box.md +24 -0
  69. data/TODO.diagrams/26-phantom-general-parent-rendering.md +59 -0
  70. data/TODO.diagrams/27-path-grouping-mode-detection.md +43 -0
  71. data/TODO.diagrams/28-architecture-cleanup-batch.md +47 -0
  72. data/TODO.diagrams/30-decompose-elements-groups-for.md +52 -0
  73. data/TODO.diagrams/32-examples-coverage-batch.md +78 -0
  74. data/TODO.diagrams/36-instance-specification-model.md +42 -0
  75. data/TODO.diagrams/37-element-icon-decorations.md +41 -0
  76. data/TODO.diagrams/38-html-note-and-receptions.md +32 -0
  77. data/TODO.diagrams/39-property-stereotype-discriminator.md +40 -0
  78. data/TODO.diagrams/40-standalone-1-discriminator.md +38 -0
  79. data/TODO.diagrams/41-xmi-to-svg-pipeline.md +113 -0
  80. data/TODO.diagrams/42-close-all-parity-deltas.md +69 -0
  81. data/TODO.diagrams/43-marker-deduplication-strategy.md +54 -0
  82. data/TODO.diagrams/44-element-icon-decorations.md +34 -0
  83. data/TODO.diagrams/45-phantom-parent-class-boxes.md +40 -0
  84. data/TODO.diagrams/46-user-drawn-legend-swatches.md +44 -0
  85. data/TODO.diagrams/47-attribute-line-fidelity.md +72 -0
  86. data/TODO.diagrams/48-spec-coverage-critical-emitter-components.md +45 -0
  87. data/TODO.diagrams/49-spec-coverage-orchestrators.md +25 -0
  88. data/TODO.diagrams/50-examples-parity.md +85 -0
  89. data/TODO.diagrams/51-property-oy-gap-and-remaining-gaps.md +48 -0
  90. data/TODO.diagrams/52-marker-registration-architecture.md +89 -0
  91. data/TODO.diagrams/53-remaining-example-gaps.md +86 -0
  92. data/TODO.diagrams/54-display-name-nested-classes.md +40 -0
  93. data/TODO.diagrams/55-visibility-icon-discriminator.md +58 -0
  94. data/TODO.diagrams/56-package-contents-rendering.md +148 -0
  95. data/TODO.diagrams/57-instance-specification-model.md +100 -0
  96. data/TODO.diagrams/58-domain-model-note-text.md +67 -0
  97. data/TODO.diagrams/59-classes-arrow-discriminator.md +57 -0
  98. data/TODO.diagrams/60-testschema-association-marker.md +40 -0
  99. data/TODO.diagrams/61-legend-block-rendering.md +55 -0
  100. data/TODO.diagrams/61-plateau-parity-gaps.md +59 -0
  101. data/TODO.diagrams/62-ghost-element-rendering.md +56 -0
  102. data/TODO.diagrams/63-qualified-name-wrap.md +36 -0
  103. data/TODO.diagrams/64-property-stereotype-labels.md +22 -0
  104. data/TODO.diagrams/65-path-coordinate-frame.md +62 -0
  105. data/TODO.diagrams/67-path-coordinate-frame.md +62 -0
  106. data/TODO.diagrams/68-inherited-attributes.md +65 -0
  107. data/TODO.diagrams/69-package-anchor-conditional.md +29 -0
  108. data/TODO.diagrams/70-mdg-technology-support.md +68 -0
  109. data/TODO.diagrams/71-off-canvas-parent-ghost.md +45 -0
  110. data/TODO.diagrams/72-basic-attr-divider-paths.md +39 -0
  111. data/TODO.diagrams/73-plateau-polygon-gap.md +69 -0
  112. data/TODO.diagrams/74-plateau-rect-gap.md +22 -0
  113. data/TODO.diagrams/75-plateau-text-gap.md +39 -0
  114. data/TODO.diagrams/76-basic-poly-path-gaps.md +41 -0
  115. data/TODO.diagrams/77-basic-text-overrender.md +40 -0
  116. data/TODO.diagrams/78-headerlines-ocp-refactor.md +65 -0
  117. data/TODO.diagrams/79-architecture-backlog.md +65 -0
  118. data/TODO.diagrams/80-basic-triangle-polygons.md +51 -0
  119. data/TODO.diagrams/81-plateau-path-overrender.md +53 -0
  120. data/TODO.diagrams/82-appearance-canvas-offset.md +54 -0
  121. data/TODO.diagrams/83-3d-diagram-subtitle.md +58 -0
  122. data/TODO.diagrams/84-canvas-offset-mismatches.md +61 -0
  123. data/TODO.diagrams/85-phantom-property-overrender.md +95 -0
  124. data/TODO.diagrams/86-foreign-package-rule.md +62 -0
  125. data/TODO.diagrams/87-internal-tech-encryption.md +80 -0
  126. data/TODO.diagrams/EXAMPLES_STATUS.md +88 -0
  127. data/TODO.diagrams/README.md +69 -0
  128. data/TODO.diagrams/STATUS.md +73 -0
  129. data/TODO.fixup/01-default-grouped-paths.md +34 -0
  130. data/TODO.fixup/02-marker-consolidation-per-connector.md +20 -0
  131. data/TODO.fixup/03-diagram-font-inference.md +28 -0
  132. data/TODO.fixup/04-extract-bounds-calculator.md +25 -0
  133. data/TODO.fixup/05-marker-registry-ocp.md +32 -0
  134. data/TODO.fixup/06-connector-path-bend-routing.md +28 -0
  135. data/TODO.fixup/07-edge-attachment-formula.md +22 -0
  136. data/TODO.fixup/08-visual-diff-harness.md +28 -0
  137. data/TODO.fixup/09-extract-element-compartments.md +34 -0
  138. data/TODO.fixup/10-canvas-width-overshoot-fix.md +20 -0
  139. data/TODO.fixup/11-layer-sequencer-extraction.md +18 -0
  140. data/TODO.fixup/12-path-style-harmony.md +23 -0
  141. data/TODO.fixup/13-datatype-stereotype-fallback.md +28 -0
  142. data/TODO.fixup/14-ea-exe-reverse-engineering-notes.md +56 -0
  143. data/TODO.fixup/15-enumeration-literal-rendering.md +30 -0
  144. data/TODO.fixup/16-operation-compartment-rendering.md +42 -0
  145. data/TODO.fixup/17-path-count-calibration.md +27 -0
  146. data/TODO.fixup/18-polygon-count-calibration.md +32 -0
  147. data/TODO.fixup/19-rect-count-undershoot-investigation.md +40 -0
  148. data/TODO.fixup/20-stereotype-color-from-classifier.md +18 -0
  149. data/TODO.fixup/21-visibility-filter-for-properties.md +24 -0
  150. data/TODO.fixup/22-multiplicity-display-rule-calibration.md +25 -0
  151. data/TODO.fixup/23-diagram-frame-title-element.md +31 -0
  152. data/TODO.fixup/24-note-element-rendering.md +23 -0
  153. data/TODO.fixup/25-ea-exe-disassembly-findings.md +177 -0
  154. data/TODO.fixup/26-svg-renderer-architecture.md +78 -0
  155. data/TODO.fixup/27-svg-element-emitters-disassembly.md +135 -0
  156. data/TODO.fixup/28-geometry-parser-identification.md +57 -0
  157. data/TODO.fixup/29-qea-svg-xmi-triple-comparison.md +185 -0
  158. data/TODO.fixup/30-theme-system-stub.md +46 -0
  159. data/TODO.fixup/31-theme-value-object-registry.md +17 -0
  160. data/TODO.fixup/32-styleex-on-diagram-model.md +22 -0
  161. data/TODO.fixup/33-text-encoding-decimals-rotation.md +29 -0
  162. data/TODO.fixup/34-per-type-fill-via-theme.md +18 -0
  163. data/TODO.fixup/35-stroke-width-per-theme.md +7 -0
  164. data/TODO.fixup/36-qea-rect-coord-normalization.md +24 -0
  165. data/TODO.fixup/37-package-shape-rendering.md +22 -0
  166. data/TODO.fixup/38-note-element-rendering.md +15 -0
  167. data/TODO.fixup/39-styleex-flag-honoring.md +25 -0
  168. data/TODO.fixup/40-connector-dashed-lines.md +15 -0
  169. data/TODO.fixup/41-diagram-frame-showborder-detection.md +23 -0
  170. data/TODO.fixup/42-textrenderer-centralization.md +10 -0
  171. data/TODO.fixup/43-colorresolver-unification.md +24 -0
  172. data/TODO.fixup/44-theme-aware-textrenderer.md +17 -0
  173. data/TODO.fixup/45-theme-aware-fontresolver.md +22 -0
  174. data/TODO.fixup/46-style-parameterized-by-theme.md +21 -0
  175. data/TODO.fixup/47-canvas-frame-inset.md +19 -0
  176. data/TODO.fixup/48-background-rect-format.md +15 -0
  177. data/TODO.fixup/49-all-samples-integration-test.md +17 -0
  178. data/TODO.fixup/50-svg-emitter-architecture-docs.md +33 -0
  179. data/TODO.fixup/51-promote-theme-to-ea-namespace.md +28 -0
  180. data/TODO.fixup/52-theme-definition-integrated-fills.md +26 -0
  181. data/TODO.fixup/53-theme-registry-yaml-loading.md +50 -0
  182. data/TODO.fixup/54-diagram-theme-api.md +50 -0
  183. data/TODO.fixup/55-update-eaemitter-to-ea-theme.md +23 -0
  184. data/TODO.fixup/56-theme-yaml-files.md +65 -0
  185. data/TODO.fixup/57-theme-specs-and-integration.md +27 -0
  186. data/TODO.fixup/58-ea-entry-point-theme-autoload.md +20 -0
  187. data/TODO.fixup/59-thread-theme-through-all-renderers.md +29 -0
  188. data/TODO.fixup/60-cli-theme-option.md +22 -0
  189. data/TODO.fixup/61-theme-validation.md +28 -0
  190. data/TODO.fixup/62-theme-builder-dsl.md +31 -0
  191. data/TODO.fixup/63-theme-integration-rendering-spec.md +24 -0
  192. data/TODO.fixup/64-theme-writeback-styleex.md +21 -0
  193. data/TODO.fixup/65-remove-dead-eaemitter-theme-files.md +30 -0
  194. data/TODO.fixup/66-styleex-writeback.md +22 -0
  195. data/TODO.fixup/67-delete-dead-code.md +28 -0
  196. data/TODO.fixup/68-figure-parity-status.md +82 -0
  197. data/TODO.fixup/69-package-polygon-rendering.md +54 -0
  198. data/TODO.fixup/70-tagged-values-compartment.md +39 -0
  199. data/TODO.fixup/71-auto-detect-theme-from-xmi.md +37 -0
  200. data/TODO.fixup/72-sample-exports-as-regression-specs.md +37 -0
  201. data/TODO.fixup/73-delete-dead-transformations.md +14 -0
  202. data/TODO.fixup/74-delete-dead-diagram-renderers.md +18 -0
  203. data/TODO.fixup/75-visibility-legend-icons.md +23 -0
  204. data/TODO.fixup/76-plateau-text-undershoot.md +27 -0
  205. data/TODO.fixup/77-canvas-frame-margins.md +28 -0
  206. data/TODO.fixup/78-note-element-rendering.md +30 -0
  207. data/TODO.fixup/79-operation-compartment-rendering.md +27 -0
  208. data/TODO.fixup/80-tagged-value-stereotype-visibility.md +37 -0
  209. data/TODO.fixup/81-figure-parity-current-state.md +63 -0
  210. data/config/qea_schema.yml +356 -0
  211. data/config/themes/119.yml +98 -0
  212. data/config/themes/default.yml +14 -0
  213. data/examples/exports/20251010_current_plateau_v5/UML_EA.DTD +6856 -0
  214. data/examples/exports/20251010_current_plateau_v5/model.xml +96709 -0
  215. data/examples/exports/ArcGISWorkspace_template/UML_EA.DTD +6856 -0
  216. data/examples/exports/ArcGISWorkspace_template/model.xml +1427 -0
  217. data/examples/exports/UmlModel_template/UML_EA.DTD +6856 -0
  218. data/examples/exports/UmlModel_template/model.xml +23 -0
  219. data/examples/exports/basic/UML_EA.DTD +6856 -0
  220. data/examples/exports/basic/model.xml +8039 -0
  221. data/examples/exports/simple/UML_EA.DTD +6856 -0
  222. data/examples/exports/simple/model.xml +585 -0
  223. data/examples/exports/simple_example/UML_EA.DTD +6856 -0
  224. data/examples/exports/simple_example/model.xml +23 -0
  225. data/examples/exports/test/UML_EA.DTD +6856 -0
  226. data/examples/exports/test/model.xml +1638 -0
  227. data/examples/qea/basic.qea +0 -0
  228. data/frontend/README.md +51 -0
  229. data/frontend/dist/app.iife.js +24 -0
  230. data/frontend/dist/style.css +1 -0
  231. data/frontend/index.html +26 -0
  232. data/frontend/package-lock.json +2359 -0
  233. data/frontend/package.json +26 -0
  234. data/frontend/src/App.vue +59 -0
  235. data/frontend/src/app.ts +8 -0
  236. data/frontend/src/components/AppHeader.vue +127 -0
  237. data/frontend/src/components/AppSidebar.vue +119 -0
  238. data/frontend/src/components/ClassDetails.vue +247 -0
  239. data/frontend/src/components/DiagramView.vue +79 -0
  240. data/frontend/src/components/PackageDetails.vue +92 -0
  241. data/frontend/src/components/PackageTreeNode.vue +64 -0
  242. data/frontend/src/components/SearchResults.vue +48 -0
  243. data/frontend/src/components/WelcomeView.vue +87 -0
  244. data/frontend/src/shims-vue.d.ts +5 -0
  245. data/frontend/src/stores/dataStore.ts +79 -0
  246. data/frontend/src/stores/uiStore.ts +167 -0
  247. data/frontend/src/styles/main.css +1566 -0
  248. data/frontend/src/types.ts +221 -0
  249. data/frontend/tests/e2e/__screenshots__/new-dark-mode.png +0 -0
  250. data/frontend/tests/e2e/__screenshots__/new-package-details.png +0 -0
  251. data/frontend/tests/e2e/__screenshots__/new-search-modal.png +0 -0
  252. data/frontend/tests/e2e/__screenshots__/new-sidebar-collapsed.png +0 -0
  253. data/frontend/tests/e2e/__screenshots__/new-welcome.png +0 -0
  254. data/frontend/tests/e2e/render.spec.ts +188 -0
  255. data/frontend/tsconfig.json +20 -0
  256. data/frontend/vite.config.ts +26 -0
  257. data/frontend/vitest.config.ts +8 -0
  258. data/lib/ea/cli/app.rb +57 -2
  259. data/lib/ea/cli/command/diagrams.rb +37 -28
  260. data/lib/ea/cli/command/diff.rb +46 -0
  261. data/lib/ea/cli/command/export.rb +80 -0
  262. data/lib/ea/cli/command/info.rb +75 -0
  263. data/lib/ea/cli/command/lint.rb +48 -0
  264. data/lib/ea/cli/command/mdg.rb +98 -0
  265. data/lib/ea/cli/command/query.rb +34 -0
  266. data/lib/ea/cli/command/render.rb +135 -0
  267. data/lib/ea/cli/command/svg.rb +8 -15
  268. data/lib/ea/cli/command.rb +7 -0
  269. data/lib/ea/diagram/display_config.rb +184 -0
  270. data/lib/ea/diagram.rb +4 -41
  271. data/lib/ea/diff/change.rb +30 -0
  272. data/lib/ea/diff/comparator.rb +82 -0
  273. data/lib/ea/diff/html_reporter.rb +91 -0
  274. data/lib/ea/diff.rb +15 -0
  275. data/lib/ea/export/json/generator.rb +42 -0
  276. data/lib/ea/export/json.rb +12 -0
  277. data/lib/ea/export/json_schema/generator.rb +77 -0
  278. data/lib/ea/export/json_schema.rb +12 -0
  279. data/lib/ea/export/plantuml/generator.rb +73 -0
  280. data/lib/ea/export/plantuml.rb +12 -0
  281. data/lib/ea/export/xmi/generator.rb +77 -0
  282. data/lib/ea/export/xmi.rb +11 -0
  283. data/lib/ea/export/xsd/class_mapping.rb +65 -0
  284. data/lib/ea/export/xsd/generator.rb +142 -0
  285. data/lib/ea/export/xsd/namespace_registry.rb +82 -0
  286. data/lib/ea/export/xsd.rb +19 -0
  287. data/lib/ea/export.rb +14 -0
  288. data/lib/ea/image/emf_renderer.rb +42 -0
  289. data/lib/ea/image.rb +12 -0
  290. data/lib/ea/lint/engine.rb +30 -0
  291. data/lib/ea/lint/lint_rule.rb +38 -0
  292. data/lib/ea/lint/offense.rb +18 -0
  293. data/lib/ea/lint/rules/cyclic_generalization.rb +62 -0
  294. data/lib/ea/lint/rules/duplicate_name.rb +28 -0
  295. data/lib/ea/lint/rules/missing_stereotype.rb +35 -0
  296. data/lib/ea/lint/rules/naming_convention.rb +44 -0
  297. data/lib/ea/lint/rules/orphan_element.rb +28 -0
  298. data/lib/ea/lint/rules.rb +14 -0
  299. data/lib/ea/lint.rb +13 -0
  300. data/lib/ea/mdg/document.rb +120 -0
  301. data/lib/ea/mdg/loader.rb +118 -0
  302. data/lib/ea/mdg/registry.rb +98 -0
  303. data/lib/ea/mdg/stereotype_alias_registry.rb +77 -0
  304. data/lib/ea/mdg/xml/applies_to.rb +18 -0
  305. data/lib/ea/mdg/xml/apply.rb +18 -0
  306. data/lib/ea/mdg/xml/content.rb +18 -0
  307. data/lib/ea/mdg/xml/documentation.rb +24 -0
  308. data/lib/ea/mdg/xml/stereotype.rb +28 -0
  309. data/lib/ea/mdg/xml/stereotypes.rb +18 -0
  310. data/lib/ea/mdg/xml/tag.rb +28 -0
  311. data/lib/ea/mdg/xml/tagged_values.rb +18 -0
  312. data/lib/ea/mdg/xml/technology.rb +28 -0
  313. data/lib/ea/mdg/xml/uml_profile.rb +22 -0
  314. data/lib/ea/mdg/xml/uml_profiles.rb +18 -0
  315. data/lib/ea/mdg/xml.rb +24 -0
  316. data/lib/ea/mdg.rb +25 -0
  317. data/lib/ea/model/classifier.rb +4 -0
  318. data/lib/ea/model/constraint.rb +24 -0
  319. data/lib/ea/model/diagram.rb +85 -0
  320. data/lib/ea/model/diagram_connector.rb +34 -0
  321. data/lib/ea/model/diagram_element.rb +16 -0
  322. data/lib/ea/model/document.rb +47 -2
  323. data/lib/ea/model/ghost_label.rb +32 -0
  324. data/lib/ea/model/instance_specification.rb +34 -0
  325. data/lib/ea/model/legend.rb +43 -0
  326. data/lib/ea/model/legend_item.rb +26 -0
  327. data/lib/ea/model/note.rb +28 -0
  328. data/lib/ea/model/operation.rb +2 -0
  329. data/lib/ea/model/property.rb +2 -0
  330. data/lib/ea/model/relationship.rb +2 -0
  331. data/lib/ea/model/signal.rb +14 -0
  332. data/lib/ea/model/slot.rb +19 -0
  333. data/lib/ea/model.rb +8 -0
  334. data/lib/ea/ocl/evaluator.rb +94 -0
  335. data/lib/ea/ocl/nodes.rb +30 -0
  336. data/lib/ea/ocl/parser.rb +133 -0
  337. data/lib/ea/ocl/unsupported_error.rb +7 -0
  338. data/lib/ea/ocl.rb +13 -0
  339. data/lib/ea/qea/factory/document_builder.rb +24 -10
  340. data/lib/ea/qea/factory/generalization_builder.rb +9 -11
  341. data/lib/ea/qea/infrastructure/table_reader.rb +9 -0
  342. data/lib/ea/qea/models/ea_author.rb +35 -0
  343. data/lib/ea/qea/models/ea_glossary.rb +34 -0
  344. data/lib/ea/qea/models/ea_image.rb +53 -0
  345. data/lib/ea/qea/models/ea_implement.rb +32 -0
  346. data/lib/ea/qea/models/ea_list.rb +42 -0
  347. data/lib/ea/qea/models/ea_object_effort.rb +34 -0
  348. data/lib/ea/qea/models/ea_object_problem.rb +37 -0
  349. data/lib/ea/qea/models/ea_object_require.rb +34 -0
  350. data/lib/ea/qea/models/ea_object_resource.rb +34 -0
  351. data/lib/ea/qea/models/ea_object_risk.rb +34 -0
  352. data/lib/ea/qea/models/ea_object_scenario.rb +34 -0
  353. data/lib/ea/qea/models/ea_object_test.rb +35 -0
  354. data/lib/ea/qea/models/ea_object_trx.rb +34 -0
  355. data/lib/ea/qea/models/ea_operation.rb +7 -0
  356. data/lib/ea/qea/models/ea_palette.rb +30 -0
  357. data/lib/ea/qea/models/ea_palette_item.rb +36 -0
  358. data/lib/ea/qea/models/ea_phase.rb +40 -0
  359. data/lib/ea/qea/models/ea_role_constraint.rb +32 -0
  360. data/lib/ea/qea/models/ea_secrypt.rb +34 -0
  361. data/lib/ea/qea/models/ea_version.rb +39 -0
  362. data/lib/ea/qea/models/ea_xref.rb +11 -1
  363. data/lib/ea/qea/models.rb +19 -0
  364. data/lib/ea/qea/services/database_loader.rb +22 -1
  365. data/lib/ea/query/builder.rb +108 -0
  366. data/lib/ea/query.rb +9 -0
  367. data/lib/ea/render/image_converter.rb +101 -0
  368. data/lib/ea/render.rb +10 -0
  369. data/lib/ea/shapescript/parser.rb +208 -0
  370. data/lib/ea/shapescript/renderer.rb +74 -0
  371. data/lib/ea/shapescript/shape.rb +34 -0
  372. data/lib/ea/shapescript.rb +24 -0
  373. data/lib/ea/sources/qea/adapter.rb +22 -5
  374. data/lib/ea/sources/qea/classifier_builder.rb +184 -7
  375. data/lib/ea/sources/qea/diagram_builder.rb +352 -24
  376. data/lib/ea/sources/qea/id_normalizer.rb +16 -1
  377. data/lib/ea/sources/qea/instance_builder.rb +113 -0
  378. data/lib/ea/sources/qea/legend_builder.rb +137 -0
  379. data/lib/ea/sources/qea/note_builder.rb +58 -0
  380. data/lib/ea/sources/qea/object_classifier_map.rb +6 -1
  381. data/lib/ea/sources/qea/operation_builder.rb +1 -0
  382. data/lib/ea/sources/qea/package_builder.rb +16 -0
  383. data/lib/ea/sources/qea/relationship_builder.rb +21 -5
  384. data/lib/ea/sources/qea/tagged_value_builder.rb +28 -9
  385. data/lib/ea/sources/qea/xref/legend_definition.rb +35 -0
  386. data/lib/ea/sources/qea/xref/parser.rb +150 -0
  387. data/lib/ea/sources/qea/xref/property_definition.rb +29 -0
  388. data/lib/ea/sources/qea/xref/record.rb +41 -0
  389. data/lib/ea/sources/qea/xref/stereotype_application.rb +37 -0
  390. data/lib/ea/sources/qea/xref.rb +27 -0
  391. data/lib/ea/sources/qea.rb +4 -0
  392. data/lib/ea/sources/xmi/adapter.rb +80 -2
  393. data/lib/ea/sources/xmi/classifier_builder.rb +10 -1
  394. data/lib/ea/sources/xmi/diagram_builder.rb +95 -18
  395. data/lib/ea/sources/xmi/extension_geometry_parser.rb +19 -2
  396. data/lib/ea/sources/xmi/extension_style_parser.rb +15 -2
  397. data/lib/ea/sources/xmi/note_builder.rb +46 -0
  398. data/lib/ea/sources/xmi/property_builder.rb +9 -0
  399. data/lib/ea/sources/xmi/stereotype_builder.rb +54 -0
  400. data/lib/ea/sources/xmi/tag_builder.rb +45 -0
  401. data/lib/ea/sources/xmi/umldi_keyword_extractor.rb +87 -0
  402. data/lib/ea/sources/xmi.rb +4 -0
  403. data/lib/ea/spa/output/sharded_multi_file_strategy.rb +18 -3
  404. data/lib/ea/spa/output/single_file_strategy.rb +8 -2
  405. data/lib/ea/spa/output/strategy.rb +34 -0
  406. data/lib/ea/svg/connector_router.rb +134 -0
  407. data/lib/ea/svg/ea_emitter/background.rb +2 -3
  408. data/lib/ea/svg/ea_emitter/bounds_calculator.rb +142 -0
  409. data/lib/ea/svg/ea_emitter/canvas.rb +56 -33
  410. data/lib/ea/svg/ea_emitter/color_resolver.rb +56 -0
  411. data/lib/ea/svg/ea_emitter/compartment/attributes.rb +28 -0
  412. data/lib/ea/svg/ea_emitter/compartment/constraints.rb +30 -0
  413. data/lib/ea/svg/ea_emitter/compartment/enum_literals.rb +86 -0
  414. data/lib/ea/svg/ea_emitter/compartment/header.rb +32 -0
  415. data/lib/ea/svg/ea_emitter/compartment/header_divider.rb +57 -0
  416. data/lib/ea/svg/ea_emitter/compartment/instance_slots.rb +96 -0
  417. data/lib/ea/svg/ea_emitter/compartment/instance_underline.rb +67 -0
  418. data/lib/ea/svg/ea_emitter/compartment/note_body.rb +52 -0
  419. data/lib/ea/svg/ea_emitter/compartment/note_text.rb +102 -0
  420. data/lib/ea/svg/ea_emitter/compartment/operations.rb +38 -0
  421. data/lib/ea/svg/ea_emitter/compartment/package_contents.rb +72 -0
  422. data/lib/ea/svg/ea_emitter/compartment/package_from_parent.rb +136 -0
  423. data/lib/ea/svg/ea_emitter/compartment/shape.rb +82 -0
  424. data/lib/ea/svg/ea_emitter/compartment/tagged_values.rb +30 -0
  425. data/lib/ea/svg/ea_emitter/compartment.rb +58 -0
  426. data/lib/ea/svg/ea_emitter/connectors.rb +46 -12
  427. data/lib/ea/svg/ea_emitter/diagram_frame.rb +143 -0
  428. data/lib/ea/svg/ea_emitter/document.rb +15 -24
  429. data/lib/ea/svg/ea_emitter/element/attribute_line_builder.rb +117 -0
  430. data/lib/ea/svg/ea_emitter/element/attribute_renderer.rb +119 -0
  431. data/lib/ea/svg/ea_emitter/element/bcol_decoder.rb +29 -0
  432. data/lib/ea/svg/ea_emitter/element/compartment_geometry.rb +113 -0
  433. data/lib/ea/svg/ea_emitter/element/constraint_renderer.rb +53 -0
  434. data/lib/ea/svg/ea_emitter/element/divider_renderer.rb +17 -0
  435. data/lib/ea/svg/ea_emitter/element/enumeration_literal_renderer.rb +34 -0
  436. data/lib/ea/svg/ea_emitter/element/filter.rb +44 -0
  437. data/lib/ea/svg/ea_emitter/element/hand_draw_shape_renderer.rb +77 -0
  438. data/lib/ea/svg/ea_emitter/element/header_line_pipeline.rb +43 -0
  439. data/lib/ea/svg/ea_emitter/element/header_line_provider/instance_spec.rb +27 -0
  440. data/lib/ea/svg/ea_emitter/element/header_line_provider/name.rb +76 -0
  441. data/lib/ea/svg/ea_emitter/element/header_line_provider/parent_ghost.rb +25 -0
  442. data/lib/ea/svg/ea_emitter/element/header_line_provider/stereotype_label.rb +68 -0
  443. data/lib/ea/svg/ea_emitter/element/header_line_provider.rb +19 -0
  444. data/lib/ea/svg/ea_emitter/element/header_lines.rb +27 -0
  445. data/lib/ea/svg/ea_emitter/element/header_renderer.rb +48 -0
  446. data/lib/ea/svg/ea_emitter/element/icon_renderer.rb +109 -0
  447. data/lib/ea/svg/ea_emitter/element/legend_renderer.rb +177 -0
  448. data/lib/ea/svg/ea_emitter/element/note_shape_renderer.rb +112 -0
  449. data/lib/ea/svg/ea_emitter/element/operation_renderer.rb +100 -0
  450. data/lib/ea/svg/ea_emitter/element/package_shape_renderer.rb +181 -0
  451. data/lib/ea/svg/ea_emitter/element/row_icon_renderer.rb +156 -0
  452. data/lib/ea/svg/ea_emitter/element/shape_renderer.rb +17 -0
  453. data/lib/ea/svg/ea_emitter/element/stereotype_icon_renderer.rb +82 -0
  454. data/lib/ea/svg/ea_emitter/element/tagged_value_renderer.rb +50 -0
  455. data/lib/ea/svg/ea_emitter/element/text_escape.rb +20 -0
  456. data/lib/ea/svg/ea_emitter/element.rb +37 -0
  457. data/lib/ea/svg/ea_emitter/elements.rb +283 -95
  458. data/lib/ea/svg/ea_emitter/font_resolver.rb +111 -0
  459. data/lib/ea/svg/ea_emitter/ghost_labels.rb +66 -0
  460. data/lib/ea/svg/ea_emitter/label/end_label.rb +266 -0
  461. data/lib/ea/svg/ea_emitter/label/midpoint_label.rb +101 -0
  462. data/lib/ea/svg/ea_emitter/label/registry.rb +50 -0
  463. data/lib/ea/svg/ea_emitter/label.rb +23 -0
  464. data/lib/ea/svg/ea_emitter/labels.rb +93 -27
  465. data/lib/ea/svg/ea_emitter/layer.rb +20 -0
  466. data/lib/ea/svg/ea_emitter/layer_sequencer.rb +93 -0
  467. data/lib/ea/svg/ea_emitter/marker/arrow_path.rb +52 -0
  468. data/lib/ea/svg/ea_emitter/marker/diamond.rb +57 -0
  469. data/lib/ea/svg/ea_emitter/marker/kind.rb +35 -0
  470. data/lib/ea/svg/ea_emitter/marker/open_triangle.rb +27 -0
  471. data/lib/ea/svg/ea_emitter/marker/package_import.rb +39 -0
  472. data/lib/ea/svg/ea_emitter/marker/plus.rb +40 -0
  473. data/lib/ea/svg/ea_emitter/marker/registry.rb +42 -0
  474. data/lib/ea/svg/ea_emitter/marker.rb +37 -0
  475. data/lib/ea/svg/ea_emitter/markers.rb +351 -64
  476. data/lib/ea/svg/ea_emitter/render_context.rb +52 -0
  477. data/lib/ea/svg/ea_emitter/style.rb +15 -0
  478. data/lib/ea/svg/ea_emitter/text_renderer.rb +92 -0
  479. data/lib/ea/svg/ea_emitter.rb +33 -11
  480. data/lib/ea/svg/parity/checker.rb +105 -0
  481. data/lib/ea/svg/parity/source.rb +59 -0
  482. data/lib/ea/svg/parity/suite.rb +113 -0
  483. data/lib/ea/svg/parity.rb +14 -0
  484. data/lib/ea/svg.rb +2 -15
  485. data/lib/ea/theme/definition.rb +176 -0
  486. data/lib/ea/theme/loader.rb +125 -0
  487. data/lib/ea/theme/registry.rb +96 -0
  488. data/lib/ea/theme.rb +37 -0
  489. data/lib/ea/transformations.rb +5 -88
  490. data/lib/ea/version.rb +4 -1
  491. data/lib/ea.rb +14 -4
  492. data/lib/tasks/svg_bench.rake +87 -0
  493. data/lutaml-uml-0.5.1.gem +0 -0
  494. data/reference-docs/enterprise-architect-appearance-dialogs/appearance-1-diagram-1-themes-list.png +0 -0
  495. data/reference-docs/enterprise-architect-appearance-dialogs/appearance-1-diagram-1-themes.png +0 -0
  496. data/reference-docs/enterprise-architect-appearance-dialogs/appearance-1-diagram-2-gradients.png +0 -0
  497. data/reference-docs/enterprise-architect-appearance-dialogs/appearance-1-diagram-3-colors.png +0 -0
  498. data/reference-docs/enterprise-architect-appearance-dialogs/appearance-1-diagram-4-appearance-fonts.png +0 -0
  499. data/reference-docs/enterprise-architect-appearance-dialogs/appearance-1-diagram-4-appearance.png +0 -0
  500. data/reference-docs/enterprise-architect-appearance-dialogs/appearance-1-diagram-5-behavior.png +0 -0
  501. data/reference-docs/enterprise-architect-appearance-dialogs/appearance-1-diagram-6-sequence.png +0 -0
  502. data/reference-docs/enterprise-architect-appearance-dialogs/appearance-1-diagram.png +0 -0
  503. data/reference-docs/enterprise-architect-appearance-dialogs/appearance-2-objects.png +0 -0
  504. data/reference-docs/enterprise-architect-appearance-dialogs/appearance-3-links.png +0 -0
  505. metadata +449 -26
  506. data/lib/ea/diagram/configuration.rb +0 -379
  507. data/lib/ea/diagram/element_renderers/base_renderer.rb +0 -77
  508. data/lib/ea/diagram/element_renderers/class_renderer.rb +0 -323
  509. data/lib/ea/diagram/element_renderers/connector_renderer.rb +0 -41
  510. data/lib/ea/diagram/element_renderers/package_renderer.rb +0 -61
  511. data/lib/ea/diagram/element_renderers.rb +0 -43
  512. data/lib/ea/diagram/extractor.rb +0 -566
  513. data/lib/ea/diagram/layout_engine.rb +0 -170
  514. data/lib/ea/diagram/path_builder.rb +0 -202
  515. data/lib/ea/diagram/style_parser.rb +0 -42
  516. data/lib/ea/diagram/style_resolver.rb +0 -291
  517. data/lib/ea/diagram/svg_renderer.rb +0 -274
  518. data/lib/ea/diagram/util.rb +0 -73
  519. data/lib/ea/svg/bounds_calculator.rb +0 -74
  520. data/lib/ea/svg/connector_path.rb +0 -138
  521. data/lib/ea/svg/element_box.rb +0 -256
  522. data/lib/ea/svg/renderer.rb +0 -77
  523. data/lib/ea/svg/style_resolver.rb +0 -72
  524. data/lib/ea/transformations/configuration.rb +0 -333
  525. data/lib/ea/transformations/format_registry.rb +0 -366
  526. data/lib/ea/transformations/parsers/base_parser.rb +0 -482
  527. data/lib/ea/transformations/parsers/qea_parser.rb +0 -401
  528. data/lib/ea/transformations/parsers/xmi_parser.rb +0 -243
  529. data/lib/ea/transformations/transformation_engine.rb +0 -390
@@ -0,0 +1,86 @@
1
+ # TODO-D 53: Remaining example parity gaps (deferred)
2
+
3
+ ## Summary
4
+
5
+ This round achieved 15/27 → 17/27 example diagrams at 100% parity
6
+ (plus 2/2 simple + 1/2 test, 20/22 basic, 5/6 ArcGIS).
7
+
8
+ ```
9
+ simple 2/2 matched 100% ✓
10
+ ArcGISWorkspace 5/6 matched
11
+ basic 20/22 matched
12
+ test 1/2 matched
13
+ ```
14
+
15
+ ## Remaining basic.qea gaps (7 diagrams, all minor)
16
+
17
+ | Diagram | rect | path | polygon | text | Root cause |
18
+ |---------|------|------|---------|------|------------|
19
+ | Package Imports | -6 | -18 | 0 | -4 | visibility icons missing |
20
+ | Object with Value Specifications | 0 | -6 | 0 | -19 | object instance format |
21
+ | Objects as Instances of Classes | 0 | -4 | 0 | -9 | object instance format |
22
+ | Domain Model | +3 | -7 | +1 | -8 | tree-routed bezier paths |
23
+ | Basic Object Diagram | 0 | -3 | 0 | -2 | (object value slots) |
24
+ | Basic Class with Receptions | 0 | +5 | -2 | -3 | extra compartment dividers |
25
+ | Composition with Substitution | 0 | 0 | 0 | -1 | nested class display_name |
26
+
27
+ ## test.qea gap
28
+
29
+ `Test Model` diagram: r=-15, p=-58, po=0, t=-11. Needs visibility
30
+ icons + Package element attribute rendering.
31
+
32
+ ## Implementation paths (in priority order)
33
+
34
+ ### TODO-D 54: Visibility icons (TODO-D 51 expansion)
35
+
36
+ EA renders 5-6 element decorations per attribute row when
37
+ `ShowIcons=1`:
38
+ - 1 outer rect (11x14, pale yellow + blue stroke)
39
+ - 1 inner rect (11x4, white)
40
+ - 1 horizontal divider path (midline)
41
+ - 3-4 short "text line" paths inside
42
+
43
+ This closes `Test Model` (r=-15, p=-58) and `Package Imports`
44
+ (r=-6, p=-18). 73+ missing elements across examples.
45
+
46
+ Implementation: `Compartment::VisibilityIcon` + discriminator in
47
+ `RenderContext` (default hidden, opt-in via DiagramElement#icon_visible
48
+ or DisplayConfig#show_icons).
49
+
50
+ ### TODO-D 55: Object instance format
51
+
52
+ EA renders object instances as:
53
+ - Header: `Object 01 / roleOne: Class A` (instance name + role + classifier)
54
+ - Slot rows: `attribute = value` for each slot
55
+ - Package qualifier: `(from Objects)`
56
+
57
+ Current code renders them as plain classes with the qualified class
58
+ name. Requires new `Ea::Model::InstanceSpecification` model + QEA
59
+ parser support + ObjectInstanceRenderer compartment.
60
+
61
+ ### TODO-D 56: Tree-routed bezier paths
62
+
63
+ EA renders tree-routed connectors with cubic bezier curves
64
+ (C commands) for smooth paths. We render straight L segments.
65
+ The visual is similar but path count differs. Detection: when a
66
+ connector has 3+ waypoints with `tree:` style, emit bezier.
67
+
68
+ ## Architectural decisions documented this round
69
+
70
+ 1. **«property» label OY-gap rule**: real geometry check (15px
71
+ threshold) instead of always-true.
72
+ 2. **Implicit connector visibility**: render Nesting when
73
+ `tree:` style is set, filter otherwise.
74
+ 3. **Plus marker**: new `Marker::Plus` kind for Nesting connector
75
+ "+" decoration (lazy registration architecture).
76
+ 4. **Marker registration**: per-file `Registry.register(...)` +
77
+ `Marker.ensure_builtins_registered!` — OCP-friendly, no
78
+ autoload cycle.
79
+
80
+ ## Final state
81
+
82
+ - 1764 specs pass
83
+ - Zero code-quality violations
84
+ - basic.qea: 8 → 9 perfect diagrams (out of 22)
85
+ - test.qea: 0 → 1 perfect diagram (out of 2)
86
+ - simple.qea: 2/2 perfect
@@ -0,0 +1,40 @@
1
+ # TODO-D 54: display_name for nested classes (DONE)
2
+
3
+ ## Before
4
+
5
+ `HeaderLines#display_name` used both `visually_nested` AND
6
+ `nested_class_qualifier?` to decide whether to render the
7
+ qualified name:
8
+
9
+ ```ruby
10
+ return name if visually_nested &&
11
+ classifier.is_a?(Ea::Model::Classifier) &&
12
+ nested_class_qualifier?(classifier, name)
13
+ ```
14
+
15
+ The `visually_nested` check is a position-based heuristic (child
16
+ bounds inside parent bounds). For basic.qea's "Composition with
17
+ Substitution" diagram, Class B.1, B.2, B.3 are placed at y=-330
18
+ (off-canvas) while Class B is at y=-172. The position check returns
19
+ false, but the reference renders "Class B::Class B.1" (qualified).
20
+
21
+ ## After
22
+
23
+ The `visually_nested` check is dropped. The `nested_class_qualifier?`
24
+ check alone determines the display:
25
+
26
+ ```ruby
27
+ return name if classifier.is_a?(Ea::Model::Classifier) &&
28
+ nested_class_qualifier?(classifier, name)
29
+ ```
30
+
31
+ The qualifier is a parent class name (not a package name) when it
32
+ differs from the classifier's package name. EA always shows the
33
+ parent-class qualifier regardless of visual position.
34
+
35
+ ## Verification
36
+
37
+ - basic.qea "Composition with Substitution": text delta -1 → 0 ✓
38
+ - 1764 specs pass
39
+ - Plateau unchanged (text overlap 64.5%)
40
+ - simple.qea unchanged (100%)
@@ -0,0 +1,58 @@
1
+ # TODO-D 55: Visibility icon discriminator (deferred)
2
+
3
+ ## Status: deferred (out of scope for current session)
4
+
5
+ EA renders a "folded page" visibility icon for each attribute row
6
+ in some diagrams. The discriminator is `ShowIcons=1` in the
7
+ diagram's Style1 string.
8
+
9
+ ## Icon design (per attribute row)
10
+
11
+ ```
12
+ y_top (rect.y)
13
+ y_top..y_top+4: inner rect 11x4 (white fill, blue stroke)
14
+ y_top..y_top+14: outer rect 11x14 (pale yellow, blue stroke)
15
+ y_top+7: horizontal path (midline)
16
+ y_top+5, y_top+9, y_top+11: 3 short "text line" paths (4 wide)
17
+ ```
18
+
19
+ Total: 2 rects + 4 paths = 6 elements per attribute row.
20
+
21
+ ## Where it appears
22
+
23
+ | Diagram | rect | path | text | Why |
24
+ |---------|------|------|------|-----|
25
+ | basic.qea Package Imports | -6 | -18 | -4 | 2 attrs × 6 elements = 12 missing |
26
+ | test.qea Test Model | -15 | -58 | -11 | 8 attrs × 6 elements = 48 missing |
27
+ | basic.qea Operations+Object | similar | similar | similar | some object diagrams |
28
+
29
+ ## Implementation
30
+
31
+ 1. Parse `ShowIcons=N` from `t_diagram.Style1` (or per-element
32
+ `HideIcon=N` from `t_diagramobjects.Style`).
33
+ 2. When ShowIcons=1 (or default-icon), pass an `icon_visibility`
34
+ flag through `RenderContext`.
35
+ 3. Add a new `Compartment::VisibilityIcon` module that renders
36
+ the 2 rects + 4 paths per attribute row.
37
+ 4. Wire it into the Attribute compartment (or render alongside
38
+ it).
39
+
40
+ ## Why deferred
41
+
42
+ - Requires parsing the QEA Style1 string (already done in
43
+ DisplayConfig for other flags).
44
+ - Discriminator must be verified across more diagrams (e.g.
45
+ plateau's Building diagram has 1 icon — the same logic should
46
+ apply).
47
+ - Each attribute row needs the icon rendered at a precise offset
48
+ (currently at content_x_offset, attr_y - 9).
49
+
50
+ Closes ~80 rects + ~50 paths in basic.qea + ~70 rects + ~250
51
+ paths in test.qea (Test Model with 8 attrs).
52
+
53
+ ## Code-quality alignment
54
+
55
+ The new `Compartment::VisibilityIcon` would follow the OCP
56
+ pattern established by the Compartment pipeline — adding a new
57
+ compartment = appending to `Compartment::ALL`, no modification
58
+ of `Elements#groups_for` needed.
@@ -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.