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,93 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Ea
4
+ module Svg
5
+ module EaEmitter
6
+ # Sequences SVG layer output in EA's canonical order:
7
+ #
8
+ # 1. Background <g>
9
+ # 2. (optional) Diagram frame: border + tab + label
10
+ # 3. Per-element groups (shape, header, divider, attrs)
11
+ # 4. Connector + marker groups (merged by style)
12
+ # 5. Labels <g>
13
+ #
14
+ # Reads diagram.theme once and passes to all child renderers
15
+ # so theme settings (font, colors, stroke width) apply
16
+ # uniformly across the entire SVG output.
17
+ #
18
+ # Document delegates the layer assembly here so the Document
19
+ # class shrinks to SVG envelope construction.
20
+ class LayerSequencer
21
+ DEFAULT_STROKE_WIDTH = 2
22
+
23
+ attr_reader :diagram, :model_index, :canvas, :frame_enabled, :theme,
24
+ :document
25
+
26
+ def initialize(diagram, model_index:, canvas:, frame: false, document: nil)
27
+ @diagram = diagram
28
+ @model_index = model_index
29
+ @canvas = canvas
30
+ @frame_enabled = frame
31
+ @theme = diagram.theme
32
+ @document = document
33
+ end
34
+
35
+ def layers
36
+ layers = [Background.render(canvas)]
37
+ layers += frame_layers if frame_enabled
38
+ layers += element_layers
39
+ layers += connector_layers
40
+ layers << labels_layer
41
+ layers << ghost_labels_layer
42
+ layers
43
+ end
44
+
45
+ private
46
+
47
+ def frame_layers
48
+ DiagramFrame.new(canvas: canvas, theme: theme).layers(diagram).map(&:to_svg)
49
+ end
50
+
51
+ def element_layers
52
+ Elements.new(diagram, model_index: model_index, canvas: canvas,
53
+ document: document).groups
54
+ end
55
+
56
+ def connector_layers
57
+ connector_layers_raw = Connectors.new(diagram, canvas: canvas,
58
+ grouped: true,
59
+ stroke_width: DEFAULT_STROKE_WIDTH).layers
60
+ marker_layers_raw = Markers.new(diagram, model_index: model_index,
61
+ canvas: canvas, grouped: true,
62
+ stroke_width: DEFAULT_STROKE_WIDTH).layers
63
+ merge_layers_by_style(connector_layers_raw + marker_layers_raw).map(&:to_svg)
64
+ end
65
+
66
+ def labels_layer
67
+ Labels.new(diagram, canvas: canvas, model_index: model_index,
68
+ theme: theme, document: document).render
69
+ end
70
+
71
+ def ghost_labels_layer
72
+ GhostLabels.new(diagram, canvas: canvas).render
73
+ end
74
+
75
+ def merge_layers_by_style(layers)
76
+ merged = {}
77
+ layers.each do |layer|
78
+ if merged[layer.style_key]
79
+ merged[layer.style_key] = Layer.new(
80
+ style_key: layer.style_key,
81
+ style: layer.style,
82
+ body: "#{merged[layer.style_key].body}\n #{layer.body}"
83
+ )
84
+ else
85
+ merged[layer.style_key] = layer
86
+ end
87
+ end
88
+ merged.values
89
+ end
90
+ end
91
+ end
92
+ end
93
+ end
@@ -0,0 +1,52 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Ea
4
+ module Svg
5
+ module EaEmitter
6
+ module Marker
7
+ # Navigability arrow at the target end of an association.
8
+ # Rendered as a `<path>` (not polygon) sharing style with the
9
+ # connector line. When both ends are navigable
10
+ # (bidirectional association), EA renders a separate arrow at
11
+ # each end.
12
+ class ArrowPath < Kind
13
+ def self.handles?(effective_type)
14
+ effective_type == "Association"
15
+ end
16
+
17
+ def self.specs_for(connector, source, target, before_target,
18
+ after_source, relationship: nil)
19
+ return bidirectional_specs(source, target, before_target,
20
+ after_source) if bidirectional?(connector)
21
+
22
+ whole_end_at_source = whole_end_at_source?(connector)
23
+ anchor = whole_end_at_source ? target : source
24
+ base = whole_end_at_source ? before_target : after_source
25
+ [Registry::Spec.new(shape: :arrow, anchor: anchor, base: base)]
26
+ end
27
+
28
+ # EA marks truly bidirectional associations with
29
+ # direction="Bi-Directional" on t_connector. These get a
30
+ # separate arrow at each end. All other directions render
31
+ # a single arrow at the navigable end.
32
+ def self.bidirectional?(connector)
33
+ connector.direction == "Bi-Directional"
34
+ end
35
+ private_class_method :bidirectional?
36
+
37
+ def self.bidirectional_specs(source, target, before_target, after_source)
38
+ [
39
+ Registry::Spec.new(shape: :arrow, anchor: source,
40
+ base: after_source),
41
+ Registry::Spec.new(shape: :arrow, anchor: target,
42
+ base: before_target)
43
+ ]
44
+ end
45
+ private_class_method :bidirectional_specs
46
+ end
47
+ end
48
+ end
49
+ end
50
+ end
51
+
52
+ Ea::Svg::EaEmitter::Marker::Registry.register(Ea::Svg::EaEmitter::Marker::ArrowPath)
@@ -0,0 +1,57 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Ea
4
+ module Svg
5
+ module EaEmitter
6
+ module Marker
7
+ # Diamond marker at the whole end of an aggregation or
8
+ # composition, PLUS a navigability arrow at the part end
9
+ # when the connector's direction is "Destination -> Source".
10
+ # Reference SVGs confirm EA emits BOTH markers for
11
+ # reverse-direction aggregations on the plateau: the diamond
12
+ # distinguishes aggregation from association, the arrow shows
13
+ # navigability direction. Forward-direction ("Source ->
14
+ # Destination") aggregations get the diamond only — verified
15
+ # against basic.qea's "Two Level Class Composition Hierarchy"
16
+ # diagram, where the reference SVG has 17 diamonds and 0
17
+ # arrows.
18
+ class Diamond < Kind
19
+ def self.handles?(effective_type)
20
+ effective_type == "Aggregation" || effective_type == "Composition"
21
+ end
22
+
23
+ def self.specs_for(connector, source, target, before_target, after_source, relationship: nil)
24
+ whole_end_at_source = whole_end_at_source?(connector)
25
+ whole_anchor = whole_end_at_source ? source : target
26
+ whole_base = whole_end_at_source ? after_source : before_target
27
+ specs = [Registry::Spec.new(shape: :diamond,
28
+ anchor: whole_anchor,
29
+ base: whole_base)]
30
+ return specs unless navigable_part_end?(connector)
31
+
32
+ part_anchor = whole_end_at_source ? target : source
33
+ part_base = whole_end_at_source ? before_target : after_source
34
+ specs << Registry::Spec.new(shape: :arrow,
35
+ anchor: part_anchor,
36
+ base: part_base)
37
+ specs
38
+ end
39
+
40
+ # EA renders the navigability arrow at the part end of an
41
+ # aggregation only when the connector's direction is
42
+ # "Destination -> Source" — the conventional EA encoding
43
+ # for "part -> whole" with navigability back to the whole.
44
+ # Forward-direction aggregations ("Source -> Destination")
45
+ # omit the arrow: the diamond already communicates the
46
+ # aggregation semantic and the destination is not
47
+ # explicitly navigable.
48
+ def self.navigable_part_end?(connector)
49
+ connector.direction == "Destination -> Source"
50
+ end
51
+ end
52
+ end
53
+ end
54
+ end
55
+ end
56
+
57
+ Ea::Svg::EaEmitter::Marker::Registry.register(Ea::Svg::EaEmitter::Marker::Diamond)
@@ -0,0 +1,35 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Ea
4
+ module Svg
5
+ module EaEmitter
6
+ module Marker
7
+ # Base class for marker kinds. Subclasses declare which
8
+ # connector types they handle and produce Spec instances
9
+ # describing the marker geometry.
10
+ class Kind
11
+ # Returns true if this kind handles the given effective
12
+ # connector type (e.g. "Aggregation", "Generalization").
13
+ def self.handles?(_effective_type)
14
+ false
15
+ end
16
+
17
+ # Returns an Array of Spec instances describing the
18
+ # markers to emit. Each Spec has :shape, :anchor, :base.
19
+ # `relationship` is the resolved relationship model (e.g.
20
+ # Association) when available, nil otherwise.
21
+ def self.specs_for(_connector, _source, _target,
22
+ _before_target, _after_source, relationship: nil)
23
+ []
24
+ end
25
+
26
+ # Common helper: "destination → source" direction means
27
+ # the whole end of an aggregation is at the target end.
28
+ def self.whole_end_at_source?(connector)
29
+ connector.direction != "Destination -> Source"
30
+ end
31
+ end
32
+ end
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,27 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Ea
4
+ module Svg
5
+ module EaEmitter
6
+ module Marker
7
+ # Open triangle marker for UML generalization, realization,
8
+ # and dependency. White-filled 3-point polygon at the
9
+ # general / supplier end.
10
+ class OpenTriangle < Kind
11
+ def self.handles?(effective_type)
12
+ %w[Generalization Realization Dependency].include?(effective_type)
13
+ end
14
+
15
+ def self.specs_for(connector, source, target, before_target, after_source, relationship: nil)
16
+ whole_end_at_source = whole_end_at_source?(connector)
17
+ anchor = whole_end_at_source ? target : source
18
+ base = whole_end_at_source ? before_target : after_source
19
+ [Registry::Spec.new(shape: :triangle, anchor: anchor, base: base)]
20
+ end
21
+ end
22
+ end
23
+ end
24
+ end
25
+ end
26
+
27
+ Ea::Svg::EaEmitter::Marker::Registry.register(Ea::Svg::EaEmitter::Marker::OpenTriangle)
@@ -0,0 +1,39 @@
1
+ # frozen_string: true
2
+
3
+ module Ea
4
+ module Svg
5
+ module EaEmitter
6
+ module Marker
7
+ # PackageImport marker for «import» connectors between
8
+ # packages. EA draws a closed trapezoid silhouette at the
9
+ # source end (the importing package) and an open V-arrow at
10
+ # the target end (the imported package) — but ONLY when the
11
+ # connector's geometry string carries explicit SX/SY offset
12
+ # fields. Auto-routed connectors (no SX/SY) render as a
13
+ # plain solid line with no package_anchor marker.
14
+ #
15
+ # Verified against both QEAs (output by the same EA run):
16
+ # - basic.qea Package Imports: SX=0;SY=0 present → marker
17
+ # - plateau Urban Planning ADE2: SX/SY absent → no marker
18
+ class PackageImport < Kind
19
+ def self.handles?(effective_type)
20
+ effective_type == "Package"
21
+ end
22
+
23
+ def self.specs_for(connector, source, target, before_target, after_source, relationship: nil)
24
+ return [] unless connector.has_geometry_offsets
25
+
26
+ [
27
+ Registry::Spec.new(shape: :package_anchor,
28
+ anchor: source, base: after_source),
29
+ Registry::Spec.new(shape: :arrow, anchor: target,
30
+ base: before_target)
31
+ ]
32
+ end
33
+ end
34
+ end
35
+ end
36
+ end
37
+ end
38
+
39
+ Ea::Svg::EaEmitter::Marker::Registry.register(Ea::Svg::EaEmitter::Marker::PackageImport)
@@ -0,0 +1,40 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Ea
4
+ module Svg
5
+ module EaEmitter
6
+ module Marker
7
+ # Plus-symbol marker at the contained end of a Nesting
8
+ # connector. EA renders a "+" (16x16, two crossed lines)
9
+ # at the end pointing INTO the container.
10
+ #
11
+ # Path encoding (two sub-paths in one <path>):
12
+ #
13
+ # M cx cy-8 L cx cy+8 (vertical arm, 16 tall)
14
+ # M cx+8 cy L cx-8 cy (horizontal arm, 16 wide)
15
+ #
16
+ # cx, cy = plus center, anchored at the source-end waypoint.
17
+ class Plus < Kind
18
+ ARM_LENGTH = 8
19
+
20
+ def self.handles?(effective_type)
21
+ effective_type == "Nesting"
22
+ end
23
+
24
+ def self.specs_for(connector, source, target, before_target, after_source, relationship: nil)
25
+ # Plus is at the contained (child) end. EA's convention:
26
+ # source end is the child, target end is the parent.
27
+ # Default to source unless the connector direction
28
+ # reverses the ends.
29
+ whole_end_at_source = whole_end_at_source?(connector)
30
+ anchor = whole_end_at_source ? source : target
31
+ base = whole_end_at_source ? after_source : before_target
32
+ [Registry::Spec.new(shape: :plus, anchor: anchor, base: base)]
33
+ end
34
+ end
35
+ end
36
+ end
37
+ end
38
+ end
39
+
40
+ Ea::Svg::EaEmitter::Marker::Registry.register(Ea::Svg::EaEmitter::Marker::Plus)
@@ -0,0 +1,42 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Ea
4
+ module Svg
5
+ module EaEmitter
6
+ module Marker
7
+ # Dispatches a connector to the first registered Kind that
8
+ # handles its effective type. New kinds are added by calling
9
+ # `Registry.register(MyKind)` — no modification of existing
10
+ # code required (OCP).
11
+ class Registry
12
+ @kinds = []
13
+
14
+ class << self
15
+ attr_reader :kinds
16
+
17
+ def register(kind)
18
+ @kinds << kind
19
+ end
20
+
21
+ def specs_for(connector, effective_type, source, target,
22
+ before_target, after_source, relationship: nil)
23
+ # Lazy: ensure built-in markers are registered on first
24
+ # query. The Marker module's autoload declaration means
25
+ # the marker files only load when referenced.
26
+ Marker.ensure_builtins_registered! if defined?(Marker)
27
+ kind = @kinds.find { |k| k.handles?(effective_type) }
28
+ return [] unless kind
29
+
30
+ kind.specs_for(connector, source, target, before_target,
31
+ after_source, relationship: relationship)
32
+ end
33
+ end
34
+
35
+ # Spec carries the geometry recipe for a single marker
36
+ # emission. Renderers consume it.
37
+ Spec = Struct.new(:shape, :anchor, :base, keyword_init: true)
38
+ end
39
+ end
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,37 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Ea
4
+ module Svg
5
+ module EaEmitter
6
+ # Marker dispatch registry. Each `Kind` subclass handles one
7
+ # connector type (or family) and produces the marker specs.
8
+ # Adding a new marker kind = creating a class + registering
9
+ # it (OCP).
10
+ module Marker
11
+ autoload :Kind, "ea/svg/ea_emitter/marker/kind"
12
+ autoload :Registry, "ea/svg/ea_emitter/marker/registry"
13
+ autoload :Diamond, "ea/svg/ea_emitter/marker/diamond"
14
+ autoload :OpenTriangle, "ea/svg/ea_emitter/marker/open_triangle"
15
+ autoload :ArrowPath, "ea/svg/ea_emitter/marker/arrow_path"
16
+ autoload :Plus, "ea/svg/ea_emitter/marker/plus"
17
+ autoload :PackageImport, "ea/svg/ea_emitter/marker/package_import"
18
+
19
+ # Built-in marker kinds register themselves at the bottom of
20
+ # their respective files. Referencing each constant here
21
+ # forces autoload, which runs the per-file registration lines.
22
+ # Diamond first so "Aggregation" wins over generic fallback.
23
+ def self.ensure_builtins_registered!
24
+ # Touch the constants to trigger autoload + registration.
25
+ # Each constant is autoloaded, so merely referencing it
26
+ # causes the file to load. Registration lines at the
27
+ # bottom of each file then add the kind to the Registry.
28
+ Diamond
29
+ OpenTriangle
30
+ Plus
31
+ ArrowPath
32
+ PackageImport
33
+ end
34
+ end
35
+ end
36
+ end
37
+ end