ea 0.4.0 → 0.5.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (548) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +128 -1
  3. data/Rakefile +3 -0
  4. data/TODO.complete/01-t-xref-parsing.md +91 -0
  5. data/TODO.complete/02-per-label-geometry.md +50 -0
  6. data/TODO.complete/03-object-properties-constraints.md +57 -0
  7. data/TODO.complete/04-operation-params.md +37 -0
  8. data/TODO.complete/05-pdata-flag-matrix.md +52 -0
  9. data/TODO.complete/06-emf-image-rendering.md +34 -0
  10. data/TODO.complete/07-auxiliary-tables.md +47 -0
  11. data/TODO.complete/10-mdg-stereotype-registry.md +40 -0
  12. data/TODO.complete/11-gml-xsd-generation.md +42 -0
  13. data/TODO.complete/13-shapescript-interpreter.md +28 -0
  14. data/TODO.complete/20-cli-diff.md +46 -0
  15. data/TODO.complete/21-cli-render.md +26 -0
  16. data/TODO.complete/22-cli-export.md +29 -0
  17. data/TODO.complete/23-cli-mdg.md +23 -0
  18. data/TODO.complete/30-headerlines-ocp-refactor.md +72 -0
  19. data/TODO.complete/31-public-send-cleanup.md +61 -0
  20. data/TODO.complete/32-spec-coverage.md +33 -0
  21. data/TODO.complete/33-blocked-parity-gaps.md +41 -0
  22. data/TODO.complete/36-stereotype-icon-wiring.md +32 -0
  23. data/TODO.complete/37-cli-lint.md +32 -0
  24. data/TODO.complete/38-cli-query.md +26 -0
  25. data/TODO.complete/39-cli-info.md +23 -0
  26. data/TODO.complete/40-ocl-evaluator.md +31 -0
  27. data/TODO.complete/41-round-trip-spec.md +18 -0
  28. data/TODO.complete/42-html-diff-report.md +18 -0
  29. data/TODO.complete/43-json-schema-export.md +20 -0
  30. data/TODO.complete/44-remaining-qea-tables.md +40 -0
  31. data/TODO.complete/45-shapescript-extensions.md +25 -0
  32. data/TODO.complete/46-xsd-consolidation.md +20 -0
  33. data/TODO.complete/47-headerlines-legacy-removal.md +20 -0
  34. data/TODO.complete/51-remove-respond-to.md +25 -0
  35. data/TODO.complete/52-xsd-decouple-fixtures.md +23 -0
  36. data/TODO.complete/53-xmi-public-send-cleanup.md +26 -0
  37. data/TODO.complete/54-wire-stereotype-icon-renderer.md +20 -0
  38. data/TODO.complete/55-wire-shapescript.md +20 -0
  39. data/TODO.complete/56-wire-emf-renderer.md +27 -0
  40. data/TODO.complete/57-wire-ocl-evaluator.md +23 -0
  41. data/TODO.complete/58-diff-modifications.md +21 -0
  42. data/TODO.complete/59-delete-toy-xmi-export.md +30 -0
  43. data/TODO.complete/60-curate-json-export.md +20 -0
  44. data/TODO.complete/61-plantuml-relationships.md +22 -0
  45. data/TODO.complete/62-changelog.md +17 -0
  46. data/TODO.complete/63-dependabot-fix.md +18 -0
  47. data/TODO.complete/STATUS.md +85 -0
  48. data/TODO.diagrams/01-svg-measurement-harness.md +31 -0
  49. data/TODO.diagrams/02-polygon-over-rendering.md +29 -0
  50. data/TODO.diagrams/03-text-over-rendering.md +30 -0
  51. data/TODO.diagrams/04-rect-under-rendering.md +33 -0
  52. data/TODO.diagrams/05-canvas-dimension-parity.md +51 -0
  53. data/TODO.diagrams/06-group-layering-parity.md +39 -0
  54. data/TODO.diagrams/07-text-content-fidelity.md +65 -0
  55. data/TODO.diagrams/08-qea-direct-pipeline.md +46 -0
  56. data/TODO.diagrams/12-connector-labels.md +40 -0
  57. data/TODO.diagrams/12-per-entity-svg-layer-ordering.md +24 -0
  58. data/TODO.diagrams/13-marker-polygon-vs-path-dispatch.md +20 -0
  59. data/TODO.diagrams/13-per-text-type-font-sizes.md +33 -0
  60. data/TODO.diagrams/14-center-header-text.md +33 -0
  61. data/TODO.diagrams/14-filter-diagram-frame-elements.md +18 -0
  62. data/TODO.diagrams/15-deep-dead-code-audit.md +47 -0
  63. data/TODO.diagrams/15-per-element-font-from-style.md +24 -0
  64. data/TODO.diagrams/16-canvas-marker-extent.md +30 -0
  65. data/TODO.diagrams/16-document-remaining-parity-gaps.md +91 -0
  66. data/TODO.diagrams/17-italic-abstract-classes.md +28 -0
  67. data/TODO.diagrams/17-remaining-parity-gaps.md +90 -0
  68. data/TODO.diagrams/18-canvas-from-image-bounds.md +20 -0
  69. data/TODO.diagrams/18-property-lookup-index.md +42 -0
  70. data/TODO.diagrams/19-connector-sx-sy-routing.md +27 -0
  71. data/TODO.diagrams/19-replace-respond-to-with-is-a.md +31 -0
  72. data/TODO.diagrams/20-split-labels-emitter.md +56 -0
  73. data/TODO.diagrams/20-visibility-glyph-font-encoding.md +27 -0
  74. data/TODO.diagrams/21-aggregation-navigability-arrow.md +21 -0
  75. data/TODO.diagrams/21-auto-generated-legend-block.md +65 -0
  76. data/TODO.diagrams/22-ghost-element-discriminator.md +57 -0
  77. data/TODO.diagrams/22-style-based-path-grouping.md +28 -0
  78. data/TODO.diagrams/23-marker-polygon-deduplication.md +47 -0
  79. data/TODO.diagrams/23-multiplicity-label-positioning.md +29 -0
  80. data/TODO.diagrams/24-marker-anchor-structural.md +35 -0
  81. data/TODO.diagrams/24-track-marker-anchors-structurally.md +66 -0
  82. data/TODO.diagrams/24-truncate-properties-to-fit-box.md +24 -0
  83. data/TODO.diagrams/26-phantom-general-parent-rendering.md +59 -0
  84. data/TODO.diagrams/27-path-grouping-mode-detection.md +43 -0
  85. data/TODO.diagrams/28-architecture-cleanup-batch.md +47 -0
  86. data/TODO.diagrams/30-decompose-elements-groups-for.md +52 -0
  87. data/TODO.diagrams/32-examples-coverage-batch.md +78 -0
  88. data/TODO.diagrams/36-instance-specification-model.md +42 -0
  89. data/TODO.diagrams/37-element-icon-decorations.md +41 -0
  90. data/TODO.diagrams/38-html-note-and-receptions.md +32 -0
  91. data/TODO.diagrams/39-property-stereotype-discriminator.md +40 -0
  92. data/TODO.diagrams/40-standalone-1-discriminator.md +38 -0
  93. data/TODO.diagrams/41-xmi-to-svg-pipeline.md +113 -0
  94. data/TODO.diagrams/42-close-all-parity-deltas.md +69 -0
  95. data/TODO.diagrams/43-marker-deduplication-strategy.md +54 -0
  96. data/TODO.diagrams/44-element-icon-decorations.md +34 -0
  97. data/TODO.diagrams/45-phantom-parent-class-boxes.md +40 -0
  98. data/TODO.diagrams/46-user-drawn-legend-swatches.md +44 -0
  99. data/TODO.diagrams/47-attribute-line-fidelity.md +72 -0
  100. data/TODO.diagrams/48-spec-coverage-critical-emitter-components.md +45 -0
  101. data/TODO.diagrams/49-spec-coverage-orchestrators.md +25 -0
  102. data/TODO.diagrams/50-examples-parity.md +85 -0
  103. data/TODO.diagrams/51-property-oy-gap-and-remaining-gaps.md +48 -0
  104. data/TODO.diagrams/52-marker-registration-architecture.md +89 -0
  105. data/TODO.diagrams/53-remaining-example-gaps.md +86 -0
  106. data/TODO.diagrams/54-display-name-nested-classes.md +40 -0
  107. data/TODO.diagrams/55-visibility-icon-discriminator.md +58 -0
  108. data/TODO.diagrams/56-package-contents-rendering.md +148 -0
  109. data/TODO.diagrams/57-instance-specification-model.md +100 -0
  110. data/TODO.diagrams/58-domain-model-note-text.md +67 -0
  111. data/TODO.diagrams/59-classes-arrow-discriminator.md +57 -0
  112. data/TODO.diagrams/60-testschema-association-marker.md +40 -0
  113. data/TODO.diagrams/61-legend-block-rendering.md +55 -0
  114. data/TODO.diagrams/61-plateau-parity-gaps.md +59 -0
  115. data/TODO.diagrams/62-ghost-element-rendering.md +56 -0
  116. data/TODO.diagrams/63-qualified-name-wrap.md +36 -0
  117. data/TODO.diagrams/64-property-stereotype-labels.md +22 -0
  118. data/TODO.diagrams/65-path-coordinate-frame.md +62 -0
  119. data/TODO.diagrams/67-path-coordinate-frame.md +62 -0
  120. data/TODO.diagrams/68-inherited-attributes.md +65 -0
  121. data/TODO.diagrams/69-package-anchor-conditional.md +29 -0
  122. data/TODO.diagrams/70-mdg-technology-support.md +68 -0
  123. data/TODO.diagrams/71-off-canvas-parent-ghost.md +45 -0
  124. data/TODO.diagrams/72-basic-attr-divider-paths.md +39 -0
  125. data/TODO.diagrams/73-plateau-polygon-gap.md +69 -0
  126. data/TODO.diagrams/74-plateau-rect-gap.md +22 -0
  127. data/TODO.diagrams/75-plateau-text-gap.md +39 -0
  128. data/TODO.diagrams/76-basic-poly-path-gaps.md +41 -0
  129. data/TODO.diagrams/77-basic-text-overrender.md +40 -0
  130. data/TODO.diagrams/78-headerlines-ocp-refactor.md +65 -0
  131. data/TODO.diagrams/79-architecture-backlog.md +65 -0
  132. data/TODO.diagrams/80-basic-triangle-polygons.md +51 -0
  133. data/TODO.diagrams/81-plateau-path-overrender.md +53 -0
  134. data/TODO.diagrams/82-appearance-canvas-offset.md +54 -0
  135. data/TODO.diagrams/83-3d-diagram-subtitle.md +58 -0
  136. data/TODO.diagrams/84-canvas-offset-mismatches.md +61 -0
  137. data/TODO.diagrams/85-phantom-property-overrender.md +95 -0
  138. data/TODO.diagrams/86-foreign-package-rule.md +62 -0
  139. data/TODO.diagrams/87-internal-tech-encryption.md +80 -0
  140. data/TODO.diagrams/EXAMPLES_STATUS.md +88 -0
  141. data/TODO.diagrams/README.md +69 -0
  142. data/TODO.diagrams/STATUS.md +73 -0
  143. data/TODO.fixup/01-default-grouped-paths.md +34 -0
  144. data/TODO.fixup/02-marker-consolidation-per-connector.md +20 -0
  145. data/TODO.fixup/03-diagram-font-inference.md +28 -0
  146. data/TODO.fixup/04-extract-bounds-calculator.md +25 -0
  147. data/TODO.fixup/05-marker-registry-ocp.md +32 -0
  148. data/TODO.fixup/06-connector-path-bend-routing.md +28 -0
  149. data/TODO.fixup/07-edge-attachment-formula.md +22 -0
  150. data/TODO.fixup/08-visual-diff-harness.md +28 -0
  151. data/TODO.fixup/09-extract-element-compartments.md +34 -0
  152. data/TODO.fixup/10-canvas-width-overshoot-fix.md +20 -0
  153. data/TODO.fixup/11-layer-sequencer-extraction.md +18 -0
  154. data/TODO.fixup/12-path-style-harmony.md +23 -0
  155. data/TODO.fixup/13-datatype-stereotype-fallback.md +28 -0
  156. data/TODO.fixup/14-ea-exe-reverse-engineering-notes.md +56 -0
  157. data/TODO.fixup/15-enumeration-literal-rendering.md +30 -0
  158. data/TODO.fixup/16-operation-compartment-rendering.md +42 -0
  159. data/TODO.fixup/17-path-count-calibration.md +27 -0
  160. data/TODO.fixup/18-polygon-count-calibration.md +32 -0
  161. data/TODO.fixup/19-rect-count-undershoot-investigation.md +40 -0
  162. data/TODO.fixup/20-stereotype-color-from-classifier.md +18 -0
  163. data/TODO.fixup/21-visibility-filter-for-properties.md +24 -0
  164. data/TODO.fixup/22-multiplicity-display-rule-calibration.md +25 -0
  165. data/TODO.fixup/23-diagram-frame-title-element.md +31 -0
  166. data/TODO.fixup/24-note-element-rendering.md +23 -0
  167. data/TODO.fixup/25-ea-exe-disassembly-findings.md +177 -0
  168. data/TODO.fixup/26-svg-renderer-architecture.md +78 -0
  169. data/TODO.fixup/27-svg-element-emitters-disassembly.md +135 -0
  170. data/TODO.fixup/28-geometry-parser-identification.md +57 -0
  171. data/TODO.fixup/29-qea-svg-xmi-triple-comparison.md +185 -0
  172. data/TODO.fixup/30-theme-system-stub.md +46 -0
  173. data/TODO.fixup/31-theme-value-object-registry.md +17 -0
  174. data/TODO.fixup/32-styleex-on-diagram-model.md +22 -0
  175. data/TODO.fixup/33-text-encoding-decimals-rotation.md +29 -0
  176. data/TODO.fixup/34-per-type-fill-via-theme.md +18 -0
  177. data/TODO.fixup/35-stroke-width-per-theme.md +7 -0
  178. data/TODO.fixup/36-qea-rect-coord-normalization.md +24 -0
  179. data/TODO.fixup/37-package-shape-rendering.md +22 -0
  180. data/TODO.fixup/38-note-element-rendering.md +15 -0
  181. data/TODO.fixup/39-styleex-flag-honoring.md +25 -0
  182. data/TODO.fixup/40-connector-dashed-lines.md +15 -0
  183. data/TODO.fixup/41-diagram-frame-showborder-detection.md +23 -0
  184. data/TODO.fixup/42-textrenderer-centralization.md +10 -0
  185. data/TODO.fixup/43-colorresolver-unification.md +24 -0
  186. data/TODO.fixup/44-theme-aware-textrenderer.md +17 -0
  187. data/TODO.fixup/45-theme-aware-fontresolver.md +22 -0
  188. data/TODO.fixup/46-style-parameterized-by-theme.md +21 -0
  189. data/TODO.fixup/47-canvas-frame-inset.md +19 -0
  190. data/TODO.fixup/48-background-rect-format.md +15 -0
  191. data/TODO.fixup/49-all-samples-integration-test.md +17 -0
  192. data/TODO.fixup/50-svg-emitter-architecture-docs.md +33 -0
  193. data/TODO.fixup/51-promote-theme-to-ea-namespace.md +28 -0
  194. data/TODO.fixup/52-theme-definition-integrated-fills.md +26 -0
  195. data/TODO.fixup/53-theme-registry-yaml-loading.md +50 -0
  196. data/TODO.fixup/54-diagram-theme-api.md +50 -0
  197. data/TODO.fixup/55-update-eaemitter-to-ea-theme.md +23 -0
  198. data/TODO.fixup/56-theme-yaml-files.md +65 -0
  199. data/TODO.fixup/57-theme-specs-and-integration.md +27 -0
  200. data/TODO.fixup/58-ea-entry-point-theme-autoload.md +20 -0
  201. data/TODO.fixup/59-thread-theme-through-all-renderers.md +29 -0
  202. data/TODO.fixup/60-cli-theme-option.md +22 -0
  203. data/TODO.fixup/61-theme-validation.md +28 -0
  204. data/TODO.fixup/62-theme-builder-dsl.md +31 -0
  205. data/TODO.fixup/63-theme-integration-rendering-spec.md +24 -0
  206. data/TODO.fixup/64-theme-writeback-styleex.md +21 -0
  207. data/TODO.fixup/65-remove-dead-eaemitter-theme-files.md +30 -0
  208. data/TODO.fixup/66-styleex-writeback.md +22 -0
  209. data/TODO.fixup/67-delete-dead-code.md +28 -0
  210. data/TODO.fixup/68-figure-parity-status.md +82 -0
  211. data/TODO.fixup/69-package-polygon-rendering.md +54 -0
  212. data/TODO.fixup/70-tagged-values-compartment.md +39 -0
  213. data/TODO.fixup/71-auto-detect-theme-from-xmi.md +37 -0
  214. data/TODO.fixup/72-sample-exports-as-regression-specs.md +37 -0
  215. data/TODO.fixup/73-delete-dead-transformations.md +14 -0
  216. data/TODO.fixup/74-delete-dead-diagram-renderers.md +18 -0
  217. data/TODO.fixup/75-visibility-legend-icons.md +23 -0
  218. data/TODO.fixup/76-plateau-text-undershoot.md +27 -0
  219. data/TODO.fixup/77-canvas-frame-margins.md +28 -0
  220. data/TODO.fixup/78-note-element-rendering.md +30 -0
  221. data/TODO.fixup/79-operation-compartment-rendering.md +27 -0
  222. data/TODO.fixup/80-tagged-value-stereotype-visibility.md +37 -0
  223. data/TODO.fixup/81-figure-parity-current-state.md +63 -0
  224. data/config/qea_schema.yml +356 -0
  225. data/config/themes/119.yml +98 -0
  226. data/config/themes/default.yml +14 -0
  227. data/examples/exports/20251010_current_plateau_v5/UML_EA.DTD +6856 -0
  228. data/examples/exports/20251010_current_plateau_v5/model.xml +96709 -0
  229. data/examples/exports/ArcGISWorkspace_template/UML_EA.DTD +6856 -0
  230. data/examples/exports/ArcGISWorkspace_template/model.xml +1427 -0
  231. data/examples/exports/UmlModel_template/UML_EA.DTD +6856 -0
  232. data/examples/exports/UmlModel_template/model.xml +23 -0
  233. data/examples/exports/basic/UML_EA.DTD +6856 -0
  234. data/examples/exports/basic/model.xml +8039 -0
  235. data/examples/exports/simple/UML_EA.DTD +6856 -0
  236. data/examples/exports/simple/model.xml +585 -0
  237. data/examples/exports/simple_example/UML_EA.DTD +6856 -0
  238. data/examples/exports/simple_example/model.xml +23 -0
  239. data/examples/exports/test/UML_EA.DTD +6856 -0
  240. data/examples/exports/test/model.xml +1638 -0
  241. data/examples/qea/basic.qea +0 -0
  242. data/frontend/README.md +51 -0
  243. data/frontend/dist/app.iife.js +24 -0
  244. data/frontend/dist/style.css +1 -0
  245. data/frontend/index.html +26 -0
  246. data/frontend/package-lock.json +2359 -0
  247. data/frontend/package.json +26 -0
  248. data/frontend/src/App.vue +59 -0
  249. data/frontend/src/app.ts +8 -0
  250. data/frontend/src/components/AppHeader.vue +127 -0
  251. data/frontend/src/components/AppSidebar.vue +119 -0
  252. data/frontend/src/components/ClassDetails.vue +247 -0
  253. data/frontend/src/components/DiagramView.vue +79 -0
  254. data/frontend/src/components/PackageDetails.vue +92 -0
  255. data/frontend/src/components/PackageTreeNode.vue +64 -0
  256. data/frontend/src/components/SearchResults.vue +48 -0
  257. data/frontend/src/components/WelcomeView.vue +87 -0
  258. data/frontend/src/shims-vue.d.ts +5 -0
  259. data/frontend/src/stores/dataStore.ts +79 -0
  260. data/frontend/src/stores/uiStore.ts +167 -0
  261. data/frontend/src/styles/main.css +1566 -0
  262. data/frontend/src/types.ts +221 -0
  263. data/frontend/tests/e2e/__screenshots__/new-dark-mode.png +0 -0
  264. data/frontend/tests/e2e/__screenshots__/new-package-details.png +0 -0
  265. data/frontend/tests/e2e/__screenshots__/new-search-modal.png +0 -0
  266. data/frontend/tests/e2e/__screenshots__/new-sidebar-collapsed.png +0 -0
  267. data/frontend/tests/e2e/__screenshots__/new-welcome.png +0 -0
  268. data/frontend/tests/e2e/render.spec.ts +188 -0
  269. data/frontend/tsconfig.json +20 -0
  270. data/frontend/vite.config.ts +26 -0
  271. data/frontend/vitest.config.ts +8 -0
  272. data/lib/ea/cli/app.rb +57 -2
  273. data/lib/ea/cli/command/diagrams.rb +37 -28
  274. data/lib/ea/cli/command/diff.rb +46 -0
  275. data/lib/ea/cli/command/export.rb +101 -0
  276. data/lib/ea/cli/command/info.rb +75 -0
  277. data/lib/ea/cli/command/lint.rb +48 -0
  278. data/lib/ea/cli/command/mdg.rb +98 -0
  279. data/lib/ea/cli/command/query.rb +34 -0
  280. data/lib/ea/cli/command/render.rb +135 -0
  281. data/lib/ea/cli/command/svg.rb +8 -15
  282. data/lib/ea/cli/command.rb +7 -0
  283. data/lib/ea/diagram/display_config.rb +184 -0
  284. data/lib/ea/diagram.rb +4 -41
  285. data/lib/ea/diff/change.rb +30 -0
  286. data/lib/ea/diff/comparator.rb +109 -0
  287. data/lib/ea/diff/html_reporter.rb +91 -0
  288. data/lib/ea/diff.rb +15 -0
  289. data/lib/ea/export/json/generator.rb +118 -0
  290. data/lib/ea/export/json.rb +12 -0
  291. data/lib/ea/export/json_schema/generator.rb +77 -0
  292. data/lib/ea/export/json_schema.rb +12 -0
  293. data/lib/ea/export/plantuml/generator.rb +140 -0
  294. data/lib/ea/export/plantuml.rb +12 -0
  295. data/lib/ea/export/xsd/class_mapping.rb +65 -0
  296. data/lib/ea/export/xsd/generator.rb +137 -0
  297. data/lib/ea/export/xsd/namespace_registry.rb +82 -0
  298. data/lib/ea/export/xsd.rb +19 -0
  299. data/lib/ea/export.rb +13 -0
  300. data/lib/ea/image/emf_renderer.rb +42 -0
  301. data/lib/ea/image.rb +12 -0
  302. data/lib/ea/lint/engine.rb +30 -0
  303. data/lib/ea/lint/lint_rule.rb +38 -0
  304. data/lib/ea/lint/offense.rb +18 -0
  305. data/lib/ea/lint/rules/cyclic_generalization.rb +62 -0
  306. data/lib/ea/lint/rules/duplicate_name.rb +28 -0
  307. data/lib/ea/lint/rules/missing_stereotype.rb +40 -0
  308. data/lib/ea/lint/rules/naming_convention.rb +44 -0
  309. data/lib/ea/lint/rules/orphan_element.rb +28 -0
  310. data/lib/ea/lint/rules.rb +14 -0
  311. data/lib/ea/lint.rb +13 -0
  312. data/lib/ea/mdg/document.rb +120 -0
  313. data/lib/ea/mdg/loader.rb +118 -0
  314. data/lib/ea/mdg/registry.rb +98 -0
  315. data/lib/ea/mdg/stereotype_alias_registry.rb +77 -0
  316. data/lib/ea/mdg/xml/applies_to.rb +18 -0
  317. data/lib/ea/mdg/xml/apply.rb +18 -0
  318. data/lib/ea/mdg/xml/content.rb +18 -0
  319. data/lib/ea/mdg/xml/documentation.rb +24 -0
  320. data/lib/ea/mdg/xml/stereotype.rb +28 -0
  321. data/lib/ea/mdg/xml/stereotypes.rb +18 -0
  322. data/lib/ea/mdg/xml/tag.rb +28 -0
  323. data/lib/ea/mdg/xml/tagged_values.rb +18 -0
  324. data/lib/ea/mdg/xml/technology.rb +28 -0
  325. data/lib/ea/mdg/xml/uml_profile.rb +22 -0
  326. data/lib/ea/mdg/xml/uml_profiles.rb +18 -0
  327. data/lib/ea/mdg/xml.rb +24 -0
  328. data/lib/ea/mdg.rb +25 -0
  329. data/lib/ea/model/classifier.rb +4 -0
  330. data/lib/ea/model/constraint.rb +24 -0
  331. data/lib/ea/model/diagram.rb +85 -0
  332. data/lib/ea/model/diagram_connector.rb +34 -0
  333. data/lib/ea/model/diagram_element.rb +16 -0
  334. data/lib/ea/model/document.rb +47 -2
  335. data/lib/ea/model/ghost_label.rb +32 -0
  336. data/lib/ea/model/instance_specification.rb +34 -0
  337. data/lib/ea/model/legend.rb +43 -0
  338. data/lib/ea/model/legend_item.rb +26 -0
  339. data/lib/ea/model/note.rb +28 -0
  340. data/lib/ea/model/operation.rb +2 -0
  341. data/lib/ea/model/property.rb +2 -0
  342. data/lib/ea/model/relationship.rb +2 -0
  343. data/lib/ea/model/signal.rb +14 -0
  344. data/lib/ea/model/slot.rb +19 -0
  345. data/lib/ea/model.rb +8 -0
  346. data/lib/ea/ocl/evaluator.rb +94 -0
  347. data/lib/ea/ocl/nodes.rb +30 -0
  348. data/lib/ea/ocl/parser.rb +133 -0
  349. data/lib/ea/ocl/unsupported_error.rb +7 -0
  350. data/lib/ea/ocl.rb +13 -0
  351. data/lib/ea/qea/factory/document_builder.rb +24 -10
  352. data/lib/ea/qea/factory/generalization_builder.rb +9 -11
  353. data/lib/ea/qea/infrastructure/table_reader.rb +9 -0
  354. data/lib/ea/qea/models/ea_author.rb +35 -0
  355. data/lib/ea/qea/models/ea_glossary.rb +34 -0
  356. data/lib/ea/qea/models/ea_image.rb +53 -0
  357. data/lib/ea/qea/models/ea_implement.rb +32 -0
  358. data/lib/ea/qea/models/ea_list.rb +42 -0
  359. data/lib/ea/qea/models/ea_object_effort.rb +34 -0
  360. data/lib/ea/qea/models/ea_object_problem.rb +37 -0
  361. data/lib/ea/qea/models/ea_object_require.rb +34 -0
  362. data/lib/ea/qea/models/ea_object_resource.rb +34 -0
  363. data/lib/ea/qea/models/ea_object_risk.rb +34 -0
  364. data/lib/ea/qea/models/ea_object_scenario.rb +34 -0
  365. data/lib/ea/qea/models/ea_object_test.rb +35 -0
  366. data/lib/ea/qea/models/ea_object_trx.rb +34 -0
  367. data/lib/ea/qea/models/ea_operation.rb +7 -0
  368. data/lib/ea/qea/models/ea_palette.rb +30 -0
  369. data/lib/ea/qea/models/ea_palette_item.rb +36 -0
  370. data/lib/ea/qea/models/ea_phase.rb +40 -0
  371. data/lib/ea/qea/models/ea_role_constraint.rb +32 -0
  372. data/lib/ea/qea/models/ea_secrypt.rb +34 -0
  373. data/lib/ea/qea/models/ea_version.rb +39 -0
  374. data/lib/ea/qea/models/ea_xref.rb +11 -1
  375. data/lib/ea/qea/models.rb +19 -0
  376. data/lib/ea/qea/services/database_loader.rb +22 -1
  377. data/lib/ea/qea/validation/database/ocl_constraint_validator.rb +65 -0
  378. data/lib/ea/qea/validation/database.rb +2 -0
  379. data/lib/ea/qea/validation/validation_engine.rb +2 -0
  380. data/lib/ea/qea/validation.rb +2 -0
  381. data/lib/ea/query/builder.rb +127 -0
  382. data/lib/ea/query.rb +9 -0
  383. data/lib/ea/render/image_converter.rb +101 -0
  384. data/lib/ea/render.rb +10 -0
  385. data/lib/ea/shapescript/parser.rb +208 -0
  386. data/lib/ea/shapescript/renderer.rb +74 -0
  387. data/lib/ea/shapescript/shape.rb +34 -0
  388. data/lib/ea/shapescript.rb +24 -0
  389. data/lib/ea/sources/qea/adapter.rb +22 -5
  390. data/lib/ea/sources/qea/classifier_builder.rb +184 -7
  391. data/lib/ea/sources/qea/diagram_builder.rb +352 -24
  392. data/lib/ea/sources/qea/id_normalizer.rb +16 -1
  393. data/lib/ea/sources/qea/instance_builder.rb +113 -0
  394. data/lib/ea/sources/qea/legend_builder.rb +137 -0
  395. data/lib/ea/sources/qea/note_builder.rb +58 -0
  396. data/lib/ea/sources/qea/object_classifier_map.rb +6 -1
  397. data/lib/ea/sources/qea/operation_builder.rb +1 -0
  398. data/lib/ea/sources/qea/package_builder.rb +16 -0
  399. data/lib/ea/sources/qea/relationship_builder.rb +21 -5
  400. data/lib/ea/sources/qea/tagged_value_builder.rb +28 -9
  401. data/lib/ea/sources/qea/xref/legend_definition.rb +35 -0
  402. data/lib/ea/sources/qea/xref/parser.rb +150 -0
  403. data/lib/ea/sources/qea/xref/property_definition.rb +29 -0
  404. data/lib/ea/sources/qea/xref/record.rb +41 -0
  405. data/lib/ea/sources/qea/xref/stereotype_application.rb +37 -0
  406. data/lib/ea/sources/qea/xref.rb +27 -0
  407. data/lib/ea/sources/qea.rb +4 -0
  408. data/lib/ea/sources/xmi/adapter.rb +80 -2
  409. data/lib/ea/sources/xmi/classifier_builder.rb +10 -1
  410. data/lib/ea/sources/xmi/diagram_builder.rb +95 -18
  411. data/lib/ea/sources/xmi/extension_geometry_parser.rb +19 -2
  412. data/lib/ea/sources/xmi/extension_style_parser.rb +15 -2
  413. data/lib/ea/sources/xmi/note_builder.rb +46 -0
  414. data/lib/ea/sources/xmi/property_builder.rb +9 -0
  415. data/lib/ea/sources/xmi/stereotype_builder.rb +54 -0
  416. data/lib/ea/sources/xmi/tag_builder.rb +45 -0
  417. data/lib/ea/sources/xmi/umldi_keyword_extractor.rb +87 -0
  418. data/lib/ea/sources/xmi.rb +4 -0
  419. data/lib/ea/spa/output/sharded_multi_file_strategy.rb +18 -3
  420. data/lib/ea/spa/output/single_file_strategy.rb +8 -2
  421. data/lib/ea/spa/output/strategy.rb +34 -0
  422. data/lib/ea/svg/connector_router.rb +134 -0
  423. data/lib/ea/svg/ea_emitter/background.rb +2 -3
  424. data/lib/ea/svg/ea_emitter/bounds_calculator.rb +142 -0
  425. data/lib/ea/svg/ea_emitter/canvas.rb +56 -33
  426. data/lib/ea/svg/ea_emitter/color_resolver.rb +56 -0
  427. data/lib/ea/svg/ea_emitter/compartment/attributes.rb +28 -0
  428. data/lib/ea/svg/ea_emitter/compartment/constraints.rb +30 -0
  429. data/lib/ea/svg/ea_emitter/compartment/enum_literals.rb +86 -0
  430. data/lib/ea/svg/ea_emitter/compartment/header.rb +32 -0
  431. data/lib/ea/svg/ea_emitter/compartment/header_divider.rb +57 -0
  432. data/lib/ea/svg/ea_emitter/compartment/instance_slots.rb +96 -0
  433. data/lib/ea/svg/ea_emitter/compartment/instance_underline.rb +67 -0
  434. data/lib/ea/svg/ea_emitter/compartment/note_body.rb +52 -0
  435. data/lib/ea/svg/ea_emitter/compartment/note_text.rb +102 -0
  436. data/lib/ea/svg/ea_emitter/compartment/operations.rb +38 -0
  437. data/lib/ea/svg/ea_emitter/compartment/package_contents.rb +72 -0
  438. data/lib/ea/svg/ea_emitter/compartment/package_from_parent.rb +136 -0
  439. data/lib/ea/svg/ea_emitter/compartment/shape.rb +82 -0
  440. data/lib/ea/svg/ea_emitter/compartment/stereotype_icon.rb +32 -0
  441. data/lib/ea/svg/ea_emitter/compartment/tagged_values.rb +30 -0
  442. data/lib/ea/svg/ea_emitter/compartment.rb +60 -0
  443. data/lib/ea/svg/ea_emitter/connectors.rb +46 -12
  444. data/lib/ea/svg/ea_emitter/diagram_frame.rb +143 -0
  445. data/lib/ea/svg/ea_emitter/document.rb +49 -25
  446. data/lib/ea/svg/ea_emitter/element/attribute_line_builder.rb +117 -0
  447. data/lib/ea/svg/ea_emitter/element/attribute_renderer.rb +119 -0
  448. data/lib/ea/svg/ea_emitter/element/bcol_decoder.rb +29 -0
  449. data/lib/ea/svg/ea_emitter/element/compartment_geometry.rb +113 -0
  450. data/lib/ea/svg/ea_emitter/element/constraint_renderer.rb +53 -0
  451. data/lib/ea/svg/ea_emitter/element/divider_renderer.rb +17 -0
  452. data/lib/ea/svg/ea_emitter/element/enumeration_literal_renderer.rb +34 -0
  453. data/lib/ea/svg/ea_emitter/element/filter.rb +44 -0
  454. data/lib/ea/svg/ea_emitter/element/hand_draw_shape_renderer.rb +77 -0
  455. data/lib/ea/svg/ea_emitter/element/header_line_pipeline.rb +43 -0
  456. data/lib/ea/svg/ea_emitter/element/header_line_provider/instance_spec.rb +27 -0
  457. data/lib/ea/svg/ea_emitter/element/header_line_provider/name.rb +76 -0
  458. data/lib/ea/svg/ea_emitter/element/header_line_provider/parent_ghost.rb +25 -0
  459. data/lib/ea/svg/ea_emitter/element/header_line_provider/stereotype_label.rb +68 -0
  460. data/lib/ea/svg/ea_emitter/element/header_line_provider.rb +19 -0
  461. data/lib/ea/svg/ea_emitter/element/header_lines.rb +27 -0
  462. data/lib/ea/svg/ea_emitter/element/header_renderer.rb +48 -0
  463. data/lib/ea/svg/ea_emitter/element/icon_renderer.rb +109 -0
  464. data/lib/ea/svg/ea_emitter/element/legend_renderer.rb +177 -0
  465. data/lib/ea/svg/ea_emitter/element/note_shape_renderer.rb +112 -0
  466. data/lib/ea/svg/ea_emitter/element/operation_renderer.rb +100 -0
  467. data/lib/ea/svg/ea_emitter/element/package_shape_renderer.rb +181 -0
  468. data/lib/ea/svg/ea_emitter/element/row_icon_renderer.rb +156 -0
  469. data/lib/ea/svg/ea_emitter/element/shape_renderer.rb +17 -0
  470. data/lib/ea/svg/ea_emitter/element/stereotype_icon_renderer.rb +119 -0
  471. data/lib/ea/svg/ea_emitter/element/tagged_value_renderer.rb +50 -0
  472. data/lib/ea/svg/ea_emitter/element/text_escape.rb +20 -0
  473. data/lib/ea/svg/ea_emitter/element.rb +37 -0
  474. data/lib/ea/svg/ea_emitter/elements.rb +283 -95
  475. data/lib/ea/svg/ea_emitter/font_resolver.rb +111 -0
  476. data/lib/ea/svg/ea_emitter/ghost_labels.rb +66 -0
  477. data/lib/ea/svg/ea_emitter/label/end_label.rb +266 -0
  478. data/lib/ea/svg/ea_emitter/label/midpoint_label.rb +101 -0
  479. data/lib/ea/svg/ea_emitter/label/registry.rb +50 -0
  480. data/lib/ea/svg/ea_emitter/label.rb +23 -0
  481. data/lib/ea/svg/ea_emitter/labels.rb +93 -27
  482. data/lib/ea/svg/ea_emitter/layer.rb +20 -0
  483. data/lib/ea/svg/ea_emitter/layer_sequencer.rb +93 -0
  484. data/lib/ea/svg/ea_emitter/marker/arrow_path.rb +52 -0
  485. data/lib/ea/svg/ea_emitter/marker/diamond.rb +57 -0
  486. data/lib/ea/svg/ea_emitter/marker/kind.rb +35 -0
  487. data/lib/ea/svg/ea_emitter/marker/open_triangle.rb +27 -0
  488. data/lib/ea/svg/ea_emitter/marker/package_import.rb +39 -0
  489. data/lib/ea/svg/ea_emitter/marker/plus.rb +40 -0
  490. data/lib/ea/svg/ea_emitter/marker/registry.rb +42 -0
  491. data/lib/ea/svg/ea_emitter/marker.rb +37 -0
  492. data/lib/ea/svg/ea_emitter/markers.rb +351 -64
  493. data/lib/ea/svg/ea_emitter/render_context.rb +52 -0
  494. data/lib/ea/svg/ea_emitter/style.rb +15 -0
  495. data/lib/ea/svg/ea_emitter/text_renderer.rb +92 -0
  496. data/lib/ea/svg/ea_emitter.rb +33 -11
  497. data/lib/ea/svg/parity/checker.rb +105 -0
  498. data/lib/ea/svg/parity/source.rb +59 -0
  499. data/lib/ea/svg/parity/suite.rb +113 -0
  500. data/lib/ea/svg/parity.rb +14 -0
  501. data/lib/ea/svg.rb +2 -15
  502. data/lib/ea/theme/definition.rb +176 -0
  503. data/lib/ea/theme/loader.rb +125 -0
  504. data/lib/ea/theme/registry.rb +96 -0
  505. data/lib/ea/theme.rb +37 -0
  506. data/lib/ea/transformations.rb +5 -88
  507. data/lib/ea/validation/xmi_parity.rb +80 -0
  508. data/lib/ea/validation.rb +12 -0
  509. data/lib/ea/version.rb +4 -1
  510. data/lib/ea.rb +15 -4
  511. data/lib/tasks/svg_bench.rake +87 -0
  512. data/lutaml-uml-0.5.1.gem +0 -0
  513. data/reference-docs/enterprise-architect-appearance-dialogs/appearance-1-diagram-1-themes-list.png +0 -0
  514. data/reference-docs/enterprise-architect-appearance-dialogs/appearance-1-diagram-1-themes.png +0 -0
  515. data/reference-docs/enterprise-architect-appearance-dialogs/appearance-1-diagram-2-gradients.png +0 -0
  516. data/reference-docs/enterprise-architect-appearance-dialogs/appearance-1-diagram-3-colors.png +0 -0
  517. data/reference-docs/enterprise-architect-appearance-dialogs/appearance-1-diagram-4-appearance-fonts.png +0 -0
  518. data/reference-docs/enterprise-architect-appearance-dialogs/appearance-1-diagram-4-appearance.png +0 -0
  519. data/reference-docs/enterprise-architect-appearance-dialogs/appearance-1-diagram-5-behavior.png +0 -0
  520. data/reference-docs/enterprise-architect-appearance-dialogs/appearance-1-diagram-6-sequence.png +0 -0
  521. data/reference-docs/enterprise-architect-appearance-dialogs/appearance-1-diagram.png +0 -0
  522. data/reference-docs/enterprise-architect-appearance-dialogs/appearance-2-objects.png +0 -0
  523. data/reference-docs/enterprise-architect-appearance-dialogs/appearance-3-links.png +0 -0
  524. metadata +464 -26
  525. data/lib/ea/diagram/configuration.rb +0 -379
  526. data/lib/ea/diagram/element_renderers/base_renderer.rb +0 -77
  527. data/lib/ea/diagram/element_renderers/class_renderer.rb +0 -323
  528. data/lib/ea/diagram/element_renderers/connector_renderer.rb +0 -41
  529. data/lib/ea/diagram/element_renderers/package_renderer.rb +0 -61
  530. data/lib/ea/diagram/element_renderers.rb +0 -43
  531. data/lib/ea/diagram/extractor.rb +0 -566
  532. data/lib/ea/diagram/layout_engine.rb +0 -170
  533. data/lib/ea/diagram/path_builder.rb +0 -202
  534. data/lib/ea/diagram/style_parser.rb +0 -42
  535. data/lib/ea/diagram/style_resolver.rb +0 -291
  536. data/lib/ea/diagram/svg_renderer.rb +0 -274
  537. data/lib/ea/diagram/util.rb +0 -73
  538. data/lib/ea/svg/bounds_calculator.rb +0 -74
  539. data/lib/ea/svg/connector_path.rb +0 -138
  540. data/lib/ea/svg/element_box.rb +0 -256
  541. data/lib/ea/svg/renderer.rb +0 -77
  542. data/lib/ea/svg/style_resolver.rb +0 -72
  543. data/lib/ea/transformations/configuration.rb +0 -333
  544. data/lib/ea/transformations/format_registry.rb +0 -366
  545. data/lib/ea/transformations/parsers/base_parser.rb +0 -482
  546. data/lib/ea/transformations/parsers/qea_parser.rb +0 -401
  547. data/lib/ea/transformations/parsers/xmi_parser.rb +0 -243
  548. data/lib/ea/transformations/transformation_engine.rb +0 -390
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: b401faad5f11e5b2504e50cabd3ee86dd4939bd8639c4c046b3fd9963408a116
4
- data.tar.gz: fe36564c5f8d52281a35e1fa49c7f1231a42f941b92e8e5895623e18d6f32ddf
3
+ metadata.gz: 8649c4d58ca59e1a753bf7b4c1400e14ac7026e1142e914a4025dfd09a2e5bb1
4
+ data.tar.gz: 170d39d2601ea16f0dd171c7ab51906b4bbe0baf5c973eaffdfc02df2e27ab59
5
5
  SHA512:
6
- metadata.gz: 7cd10052a2b16998cab3bde33d0874f605e6d8f767adefc710c7080ced3a39d76e3e0fb262b3931483d19cbfc35ff9715928f0d7d5f4dda22d95be693b0455a8
7
- data.tar.gz: 87d9150c1840ca118fe264b5b1cf2c01bf09ba5d7eb2c5f5cf5a3aedd3c27bc4a07ea86ac9e7d1636bd2ebf835b012c049bc535e76edbdf412b28152ae7e4b68
6
+ metadata.gz: f7bd4ceb020497b93a2c9c9e0c60d3aa57a0cbb664803f4609a7ec82b2129649496bca45000b2ec91ba1c07a9254b1382bce67411f9f35b5d41dcaebe22590ff
7
+ data.tar.gz: ed3b011237a1a76a85ac1af8315afcfd9250b97396fbbcefe15f0491adbe1a51a1944abd7ba9ec513b0011c2461c4ff3c7bb5be20dfa58156cc93e3698c39d44
data/CHANGELOG.md CHANGED
@@ -1,5 +1,132 @@
1
+ # Changelog
2
+
3
+ All notable changes to the `ea` gem are documented in this file.
4
+
5
+ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
6
+ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
+
1
8
  ## [Unreleased]
2
9
 
3
- ## [0.1.0] - 2026-05-23
10
+ ## [0.5.1] 2026-08-03
11
+
12
+ ### Added
13
+ - Stereotype decorator icons now render inside element bodies via the
14
+ new `Compartment::StereotypeIcon` module. Falls back to hardcoded
15
+ polygons for FeatureType/Type; uses MDG-provided ShapeScript when
16
+ available.
17
+ - OCL constraint evaluation wired into `ea validate`. Invariants from
18
+ `t_objectconstraint` are parsed and evaluated against owning
19
+ objects' attribute values.
20
+ - Image rendering infrastructure: `Document#emit_images` walks the
21
+ `:images` collection and inlines `EmfRenderer` output. Gracefully
22
+ skips when `emfsvg` returns nil (current state — upstream parser
23
+ can't decode EA's EMF variant yet).
24
+ - Diff comparator detects `:modified` changes via `to_hash`
25
+ comparison (was: add/remove/rename only).
26
+ - PlantUML export now emits package nesting, generalizations
27
+ (`<\|--`), and composition arrows (`o--`, `*--`).
28
+ - JSON export uses a per-class projection schema (no more raw
29
+ `to_hash` dumping Lutaml::Model internals).
30
+ - CHANGELOG.md with full release history.
31
+
32
+ ### Changed
33
+ - `ea export xmi` now routes to the full `Ea::Transformers::QeaToXmi`
34
+ (142 KB Sparx XMI) instead of the toy hand-rolled generator. The
35
+ toy `Ea::Export::Xmi` namespace is deleted.
36
+
37
+ ### Fixed
38
+ - Removed all `respond_to?` calls from lib code (5 sites) — replaced
39
+ with `is_a?` type checks per the typing rule.
40
+ - Renamed `object_id` attribute to `ea_object_id` in 12 new QEA
41
+ models to avoid collision with Ruby's `Object#object_id`.
42
+ - XSD Generator no longer hardcodes `spec/fixtures/` paths; the CLI
43
+ layer loads fixtures and passes parsed data.
44
+ - Bumped `lycheeverse/lychee-action` v1 → v2 (dependabot alert).
45
+
46
+ ## [0.5.0] — 2026-08-03
47
+
48
+ ### Added — CLI commands (13 new)
49
+ - `ea diff OLD NEW` — structural comparison of two QEA files
50
+ (`--format=html` produces a color-coded HTML report).
51
+ - `ea render NAME FILE` — unified rendering (SVG/PNG/PDF via
52
+ rsvg-convert or ImageMagick).
53
+ - `ea export SUB FILE` — exports: `xmi`, `json`, `json-schema`,
54
+ `plantuml`, `xsd`.
55
+ - `ea mdg ACTION` — list registered MDG technologies, show
56
+ stereotype details, list all stereotypes.
57
+ - `ea lint FILE` — model quality checks (naming convention,
58
+ orphan elements, duplicate names, cyclic generalizations,
59
+ missing stereotypes).
60
+ - `ea query FILE` — filter elements via a chainable DSL
61
+ (by type, package, stereotype, name).
62
+ - `ea info NAME FILE` — show details of a single element.
63
+
64
+ ### Added — Subsystems
65
+ - `Ea::Sources::Qea::Xref` — parser for `t_xref.Description`
66
+ (stereotype applications, tagged-value specs, legend definitions).
67
+ - `Ea::Mdg::StereotypeAliasRegistry` — canonicalizes variant
68
+ stereotype spellings via GMLStereotypes.xml.
69
+ - `Ea::Export::Xsd::Generator` — GMLClassMapping-driven XSD
70
+ schema generation.
71
+ - `Ea::Export::JsonSchema::Generator` — JSON Schema (draft
72
+ 2020-12) export.
73
+ - `Ea::Export::Json::Generator`, `Ea::Export::PlantUml::Generator`
74
+ — JSON and PlantUML exports.
75
+ - `Ea::Image::EmfRenderer` — lazy emfsvg adapter for EMF→SVG.
76
+ - `Ea::Render::ImageConverter` — SVG → PNG / PDF via system tools.
77
+ - `Ea::Lint` — engine + 5 rules (OCP: new rule = new class).
78
+ - `Ea::Ocl` — OCL invariant parser + evaluator (subset: exists,
79
+ forAll, matches, and/or/not, attribute access).
80
+ - `Ea::Shapescript` — ShapeScript parser + renderer with
81
+ variables, arithmetic, conditionals, subshapes, labels.
82
+ - `Ea::Svg::EaEmitter::Element::HeaderLinePipeline` — OCP-friendly
83
+ provider chain replacing the monolithic HeaderLines module.
84
+ - `Ea::Svg::EaEmitter::Element::StereotypeIconRenderer` — emits
85
+ stereotype decorator icons inside element bodies.
86
+
87
+ ### Added — QEA table coverage (24 → 43 tables)
88
+ - `t_image`, `t_glossary`, `t_lists`, `t_versions`, `t_phase`,
89
+ `t_authors`, `t_secrypt`, `t_palette`, `t_paletteitem`,
90
+ `t_implement`, `t_roleconstraint`, `t_objectproblems`,
91
+ `t_objectrisks`, `t_objecttests`, `t_objecteffort`,
92
+ `t_objectresource`, `t_objectscenarios`, `t_objectrequires`,
93
+ `t_objecttrx`.
94
+
95
+ ### Changed
96
+ - `Ea::Svg::EaEmitter::Element::HeaderLines` is now a thin alias
97
+ to the new `HeaderLinePipeline` (OCP provider chain).
98
+ - Per-label styling fields (`BLD`, `ITA`, `UND`, `CLR`, `ALN`,
99
+ `DIR`, `ROT`) parsed from `t_diagramlinks.Geometry`.
100
+ - Six new PDATA flag accessors on `Ea::Diagram::DisplayConfig`:
101
+ `ShowEStereo`, `ShowSN`, `OpParams`, `UseAlias`, `SuppCN`,
102
+ `ShowCons`, `ScalePI`.
103
+ - `TableReader#table_exists?` — DatabaseLoader skips missing
104
+ tables gracefully instead of raising.
105
+ - `Ea::Export::Xmi` removed — `ea export xmi` now routes through
106
+ the established `Ea::Transformers::QeaToXmi` (full-fidelity
107
+ Sparx round-trip) instead of a toy generator.
108
+
109
+ ### Removed
110
+ - `Ea::Codegen` — speculative. We don't know what EA's actual
111
+ codegen does, so building our own was wrong.
112
+ - Plugin system TODO — not needed.
113
+ - Liquid template integration TODO — `lutaml-model` already
114
+ supports liquid drops natively.
115
+
116
+ ### Fixed
117
+ - Replaced all `respond_to?` calls in lib code with `is_a?`
118
+ type checks.
119
+ - Renamed `object_id` attribute to `ea_object_id` in 12 new
120
+ QEA models to avoid collision with Ruby's `Object#object_id`.
121
+
122
+ ### Spec coverage
123
+ - 1974 examples, 0 failures, 55 pending.
124
+
125
+ ## [0.4.0] — 2026-07-21
126
+
127
+ Initial public release of the standalone parser (QEA + Sparx XMI),
128
+ diagram SVG rendering, and UML bridge.
129
+
130
+ ## [0.1.0] — 2026-05-23
4
131
 
5
132
  - Initial release
data/Rakefile CHANGED
@@ -2,6 +2,9 @@
2
2
 
3
3
  require "bundler/gem_tasks"
4
4
  require "rspec/core/rake_task"
5
+ require "fileutils"
6
+
7
+ Dir[File.expand_path("lib/tasks/*.rake", __dir__)].sort.each { |f| load f }
5
8
 
6
9
  RSpec::Core::RakeTask.new(:spec)
7
10
 
@@ -0,0 +1,91 @@
1
+ # TODO.complete/01: Full t_xref parser
2
+
3
+ ## Status: open
4
+
5
+ EA's `t_xref` table stores semi-structured metadata in a custom mini-language.
6
+ We currently only consume the stereotype-application rows for classifier
7
+ stereo labels. The full format is the richest single metadata source in QEA.
8
+
9
+ ## Format observed
10
+
11
+ ### Stereotype application
12
+
13
+ ```
14
+ @STEREO;Name=FeatureType;FQName=GML::FeatureType;@ENDSTEREO;
15
+ ```
16
+
17
+ Fields: `Name` (short), `FQName` (`tech::Stereo`).
18
+
19
+ ### Per-label / element styling block
20
+
21
+ ```
22
+ @PROP=NAME@ENDPROP;CX=19:CY=18:OX=-42:OY=-2:HDN=0:BLD=0:ITA=0:UND=0:CLR=-1:ALN=1:DIR=0:ROT=0;
23
+ ```
24
+
25
+ Fields (colon-separated key=value pairs after `@PROP=NAME@ENDPROP;`):
26
+
27
+ | key | meaning |
28
+ |---|---|
29
+ | CX, CY | cell size for label box |
30
+ | OX, OY | label offset from anchor |
31
+ | HDN | hidden (0/1) |
32
+ | BLD | bold (0/1) |
33
+ | ITA | italic (0/1) |
34
+ | UND | underline (0/1) |
35
+ | CLR | font color (signed int; -1 = default) |
36
+ | ALN | alignment (0=left, 1=center, 2=right) |
37
+ | DIR | text direction |
38
+ | ROT | rotation in degrees |
39
+
40
+ ### CustomProperties
41
+
42
+ ```
43
+ @CUSTOM;Name=...;Value=...;Type=...;@ENDCUSTOM;
44
+ ```
45
+
46
+ (Repeated; semicolon-separated list.)
47
+
48
+ ### diagram properties
49
+
50
+ Type=`diagram properties`. Carries display options as a `;`-separated list.
51
+
52
+ ## Volume observed (plateau v5.1 QEA)
53
+
54
+ | Type | Count |
55
+ |---|---|
56
+ | element property | 599 |
57
+ | connectorSrcEnd property | 352 |
58
+ | diagram properties | 181 |
59
+ | attribute property | 68 |
60
+ | connector property | 34 |
61
+ | connectorDestEnd property | 12 |
62
+
63
+ Total: ~1246 rows in one real-world QEA.
64
+
65
+ ## Plan
66
+
67
+ 1. Add `Ea::Sources::Qea::XrefParser` — pure module, no state, parses one
68
+ `Description` string into a structured `XrefRecord` (value object).
69
+ 2. Define `XrefRecord` and `XrefStyleBlock` value objects in
70
+ `lib/ea/sources/qea/xref/` (autoload from `xref.rb`).
71
+ 3. Wire into `DiagramBuilder` and `ClassifierBuilder`:
72
+ - element property → per-element label style
73
+ - connectorSrcEnd / connectorDestEnd → per-end label style
74
+ - diagram properties → PDATA overrides
75
+ 4. Apply `BLD/ITA/UND/CLR/ALN/DIR/ROT` to connector labels in
76
+ `lib/ea/svg/ea_emitter/label/`.
77
+
78
+ ## OCP / MECE
79
+
80
+ - New namespace `Ea::Sources::Qea::Xref` with parser + value objects.
81
+ - `XrefParser.parse(description)` returns typed records — no mutation.
82
+ - Renderers consume records via `XrefStyleBlock` interface; no string
83
+ parsing in renderers.
84
+
85
+ ## Acceptance
86
+
87
+ - Spec: parse a real `@STEREO;Name=FeatureType;FQName=GML::FeatureType;@ENDSTEREO;`
88
+ → `{ stereotype: "FeatureType", fqname: "GML::FeatureType" }`.
89
+ - Spec: parse a `@PROP=...` block → all 12 fields populated correctly.
90
+ - Spec: `Ea.parse(plateau_v5_1_qea).xref_records.size` matches `SELECT COUNT(*) FROM t_xref`.
91
+ - Spec: applied BLD=1 on a connector label propagates to SVG output.
@@ -0,0 +1,50 @@
1
+ # TODO.complete/02: Per-label Geometry box parsing
2
+
3
+ ## Status: open
4
+
5
+ EA's `t_diagramlinks.Geometry` field encodes per-label styling boxes:
6
+
7
+ ```
8
+ SX=20;SY=-31;EX=44;EY=-31;EDGE=2;LLB=CX=24:CY=13:OX=-42:OY=-1:HDN=0:BLD=0:ITA=0:UND=0:CLR=-1:ALN=1:DIR=0:ROT=0;LLE=...
9
+ ```
10
+
11
+ Each label slot (`LLB`, `LLT`, `RLB`, `RLT`, `LLE`, `MLE`, `MTL`, `SLE`, `STE`)
12
+ carries its own font/style override. We currently parse position (SX/SY/EX/EY)
13
+ and label boxes for geometry but **drop the styling fields**.
14
+
15
+ ## Plan
16
+
17
+ 1. Extend `Ea::Sources::Qea::DiagramStyleParser` (or a new sibling
18
+ `GeometryParser`) to parse the inner `key=value:key=value:...` block of
19
+ each label slot into a `LabelStyle` value object.
20
+ 2. Thread `LabelStyle` onto `DiagramConnector` end-labels (left/right,
21
+ source/dest, role/mult).
22
+ 3. Renderers consume `LabelStyle` via accessors; no string parsing in
23
+ `lib/ea/svg/`.
24
+
25
+ ## Value object shape
26
+
27
+ ```ruby
28
+ LabelStyle = Struct.new(:hidden, :bold, :italic, :underline,
29
+ :color, :alignment, :direction, :rotation,
30
+ :offset_x, :offset_y, :cell_w, :cell_h, keyword_init: true)
31
+ ```
32
+
33
+ ## OCP / MECE
34
+
35
+ - Parsing lives in one place (Geometry parser).
36
+ - Value object carries typed fields.
37
+ - Renderers consume via attribute readers.
38
+
39
+ ## Acceptance
40
+
41
+ - Spec: parse `LLB=CX=24:CY=13:OX=-42:OY=-1:HDN=0:BLD=1:ITA=0:UND=0:CLR=-1:ALN=1:DIR=0:ROT=0;`
42
+ → `LabelStyle` with `bold=true, alignment=1, offset_x=-42`.
43
+ - Spec: a connector whose LLB has `BLD=1` renders bold left-label text.
44
+ - Spec: `LabelStyle#hidden?` suppresses label rendering entirely.
45
+
46
+ ## Dependencies
47
+
48
+ - Requires TODO.complete/01 if the styling block is shared with t_xref.
49
+ (They share the same `CX=..:OY=..:HDN=..:` shape — extract a shared
50
+ `CellStyleParser`.)
@@ -0,0 +1,57 @@
1
+ # TODO.complete/03: t_objectproperties + t_objectconstraint parsing
2
+
3
+ ## Status: open
4
+
5
+ Two EA tables we currently ignore. Both carry modeling metadata that maps
6
+ to UML2 concepts:
7
+
8
+ | Table | UML2 concept | Example |
9
+ |---|---|---|
10
+ | t_objectproperties | applied stereotype property values | `targetNamespace=http://...`, `xsdDocument=test.xsd` |
11
+ | t_objectconstraint | Constraint / invariant | OCL: `inv: self.string->exists(...)` |
12
+
13
+ ## Volume observed
14
+
15
+ | QEA | t_objectproperties | t_objectconstraint |
16
+ |---|---|---|
17
+ | basic | 0 | 0 |
18
+ | test | 44 | 1 |
19
+ | plateau v5.1 | 1537 | 4 |
20
+
21
+ ## Plan
22
+
23
+ 1. Add `Ea::Model::ObjectProperty` (or reuse `TaggedValue`) — EA's
24
+ t_objectproperties is functionally identical to applied-stereotype
25
+ properties. Decide: model as tagged values OR as distinct entity?
26
+ - **Decision**: model as `TaggedValue` (already exists) since EA
27
+ semantically treats these as stereotype property applications. The
28
+ distinction is storage, not semantics.
29
+ 2. Add `Ea::Model::Constraint` (already exists per `lib/ea/model/constraint.rb`).
30
+ 3. Add `Ea::Qea::Models::EaObjectProperty` and `EaObjectConstraint` raw-row models.
31
+ 4. Wire into `DatabaseLoader` + `Database` collections.
32
+ 5. `ClassifierBuilder` attaches both to the classifier.
33
+ 6. Constraint rendering: a new compartment below operations showing
34
+ `{constraint_name}: OCL expression`.
35
+
36
+ ## Schema (from plateau v5.1)
37
+
38
+ ```sql
39
+ -- t_objectproperties
40
+ Property TEXT, Value TEXT, Notes TEXT, ea_guid TEXT, Object_ID INTEGER, ...
41
+
42
+ -- t_objectconstraint
43
+ Constraint TEXT, ConstraintType TEXT, OCL, Notes, ea_guid, Object_ID
44
+ ```
45
+
46
+ ## OCP / MECE
47
+
48
+ - Raw-row model per table (MECE: each table = one model).
49
+ - Transformation to UML concept lives in the bridge (ClassifierBuilder).
50
+ - Constraint rendering is a new compartment module.
51
+
52
+ ## Acceptance
53
+
54
+ - Spec: `Ea.parse(test_qea).classifiers.find(...).constraints.first.name == "pattern"`.
55
+ - Spec: `Ea.parse(test_qea).classifiers.find(...).tagged_values` includes
56
+ `targetNamespace` property.
57
+ - Spec: plateau v5.1 parses 1537 properties without error.
@@ -0,0 +1,37 @@
1
+ # TODO.complete/04: t_operationparams parsing
2
+
3
+ ## Status: open
4
+
5
+ `t_operationparams` stores the parameters of an operation (method).
6
+ We parse `t_operation` but lose the parameter list.
7
+
8
+ ## Schema (basic.qea)
9
+
10
+ ```
11
+ OperationID INTEGER, Name TEXT, Type TEXT, Default TEXT, Notes TEXT,
12
+ Pos INTEGER, Const INTEGER, Style TEXT, Kind TEXT (in/out/inout/return),
13
+ ea_guid TEXT, ...
14
+ ```
15
+
16
+ ## Volume
17
+
18
+ - basic.qea: 12 rows
19
+ - plateau v5.1: 0 (no operations)
20
+
21
+ ## Plan
22
+
23
+ 1. Add `Ea::Qea::Models::EaOperationParam` raw-row model.
24
+ 2. Add `Ea::Model::Parameter` (already exists per `lib/ea/model/parameter.rb`).
25
+ 3. Wire into `DatabaseLoader` and `OperationBuilder`.
26
+ 4. Operation rendering: append `(name: Type, name2: Type2)` to operation line.
27
+
28
+ ## OCP / MECE
29
+
30
+ - One builder per table (OperationBuilder owns t_operation + t_operationparams).
31
+ - Parameter rendering is owned by the operation compartment renderer.
32
+
33
+ ## Acceptance
34
+
35
+ - Spec: parse basic.qea → operations on classes include parameter lists.
36
+ - Spec: parameter `kind` distinguishes `in/out/inout/return`.
37
+ - Spec: `Operation#parameters` returns ordered list (Pos-sorted).
@@ -0,0 +1,52 @@
1
+ # TODO.complete/05: Complete PDATA/StyleEx flag matrix
2
+
3
+ ## Status: open
4
+
5
+ EA's `t_diagram.PDATA` carries ~30 rendering flags as `Key=value;` pairs.
6
+ We currently parse only ~4 (`HideAtts`, `HideOps`, `HideParents`, `HideProps`).
7
+
8
+ ## Full flag matrix
9
+
10
+ | Flag | Meaning | Status |
11
+ |---|---|---|
12
+ | HideAtts | Hide attribute compartment | ✅ parsed |
13
+ | HideOps | Hide operation compartment | ✅ parsed |
14
+ | HideParents | Hide off-canvas parent ghosts | ✅ parsed |
15
+ | HideProps | Hide properties | ✅ parsed |
16
+ | HideStereo | Hide stereotype labels | parsed, partial |
17
+ | HideEStereo | Hide extended stereotypes | not parsed |
18
+ | ShowTags | Show tagged values on elements | not parsed |
19
+ | ShowSN | Show sequence numbers | not parsed |
20
+ | OpParams | Show operation parameter types | not parsed |
21
+ | UseAlias | Display Alias instead of Name | not parsed |
22
+ | SuppCN | Suppress connector names | not parsed |
23
+ | ShowIcons | Show stereotype icons | parsed, icons deferred |
24
+ | ScalePI | Scale page indicators | not parsed |
25
+ | ShowCons | Show constraints | not parsed |
26
+ | ShowParentWarn | Warn about hidden parents | not parsed |
27
+
28
+ ## Plan
29
+
30
+ 1. Create `Ea::Sources::Qea::PdataFlags` value object with all flags
31
+ as boolean accessors (default: EA defaults).
32
+ 2. `DiagramBuilder#build_one` parses PDATA once, threads the flags object
33
+ through `Diagram`.
34
+ 3. Renderers query `diagram.pdata_flags.show_tags?`, etc., via attribute
35
+ readers — no string parsing in renderer.
36
+ 4. Document EA defaults in the value object (ShowTags default = false,
37
+ UseAlias default = false, etc.).
38
+
39
+ ## OCP / MECE
40
+
41
+ - Parsing in one place (PDATA parser).
42
+ - Value object carries typed flags.
43
+ - Renderers consume via boolean methods.
44
+ - New flag = new accessor on the value object; no renderer changes for
45
+ existing flags.
46
+
47
+ ## Acceptance
48
+
49
+ - Spec: `PdataFlags.parse("HideAtts=1;ShowTags=1;").show_tags? == true`.
50
+ - Spec: `PdataFlags.parse("").use_alias? == false` (default).
51
+ - Spec: UseAlias=1 in source → element header shows `alias` not `name`.
52
+ - Spec: OpParams=0 → operation line shows `op()` not `op(name: Type)`.
@@ -0,0 +1,34 @@
1
+ # TODO.complete/06: EMF→SVG conversion for t_image
2
+
3
+ ## Status: open
4
+
5
+ EA's `t_image` table stores image blobs as Enhanced Metafile (EMF).
6
+ We currently skip them entirely.
7
+
8
+ The pure-Ruby `emfsvg` gem at `~/src/claricle/emfsvg/` consumes the
9
+ `emf` gem's domain model and converts EMF records to SVG — no FFI,
10
+ no libemf2svg. This is a perfect fit.
11
+
12
+ ## Plan
13
+
14
+ 1. Add `emfsvg` as an optional runtime dependency (`spec.add_dependency "emfsvg", "~> X"`).
15
+ 2. Add `Ea::Image::EmfRenderer` that wraps `emfsvg` to convert a t_image
16
+ BLOB to an SVG `<symbol>` definition.
17
+ 3. Render in `lib/ea/svg/ea_emitter/`: emit `<defs><symbol id="img-{id}">`
18
+ from EMF, then `<use href="#img-{id}"/>` at the placement rect.
19
+ 4. Cache converted images per render pass (one t_image → one symbol).
20
+ 5. Skip silently if `emfsvg` not available (graceful degradation).
21
+
22
+ ## OCP / MECE
23
+
24
+ - Image rendering is its own namespace (`Ea::Image::`).
25
+ - No dependency on lutaml-uml.
26
+ - Lazy-loaded: only required when t_image rows exist.
27
+
28
+ ## Acceptance
29
+
30
+ - Spec: `Ea.parse(plateau_v5_1_qea).images.size == 1`.
31
+ - Spec: SVG output for plateau includes an `<image>` reference or inline
32
+ converted vector group.
33
+ - Spec: when emfsvg is unavailable, render proceeds without the image
34
+ (no exception).
@@ -0,0 +1,47 @@
1
+ # TODO.complete/07: Auxiliary QEA tables
2
+
3
+ ## Status: open
4
+
5
+ EA has ~96 tables. We currently parse 24. Beyond the structural core
6
+ (objects, connectors, diagrams, packages, operations, attributes, xref),
7
+ several tables carry semantic value for the CLI replacement vision.
8
+
9
+ ## Tables worth adding
10
+
11
+ | Table | Purpose | CLI value |
12
+ |---|---|---|
13
+ | t_glossary | Term definitions | Documentation |
14
+ | t_version | Version control history | Audit |
15
+ | t_phase | Project phases | PM integration |
16
+ | t_lists | Enumeration lists | Validation |
17
+ | t_secuser / t_secgroup | Permissions (locked QEA) | Access control |
18
+ | t_secrypt | Encryption metadata | Security analysis |
19
+ | t_authors | Authors | Audit |
20
+ | t_clients | Client definitions | CRM-lite |
21
+ | t_resources | Resource allocation | PM |
22
+ | t_tasks | Tasks | PM |
23
+ | t_issues | Issue tracking | Bug tracker |
24
+ | t_risks | Risk register | PM |
25
+
26
+ ## Plan
27
+
28
+ Add these incrementally as demand appears. Each follows the same pattern:
29
+
30
+ 1. Raw-row model in `lib/ea/qea/models/ea_{table}.rb` (autoload from `models.rb`).
31
+ 2. Wire into `config/qea_schema.yml`.
32
+ 3. Wire into `DatabaseLoader`.
33
+ 4. Expose via `Database#collections[:{table}]`.
34
+ 5. CLI exposes via `ea stats` and lookup methods.
35
+
36
+ ## Priority order
37
+
38
+ 1. **t_glossary** — simple key/value, useful for documentation.
39
+ 2. **t_version** — version history, useful for audit.
40
+ 3. **t_authors** — already partly referenced by other tables.
41
+
42
+ The rest (PM/CRM/security) are low priority unless a user requests them.
43
+
44
+ ## Acceptance
45
+
46
+ - Spec: each table has a raw-row model with COLUMN_MAP.
47
+ - Spec: `ea stats FILE` includes the new table count.
@@ -0,0 +1,40 @@
1
+ # TODO.complete/10: MDG stereotype registry
2
+
3
+ ## Status: open
4
+
5
+ We have 49 EA-bundled MDG/GML definition files in `spec/fixtures/mdg/`:
6
+
7
+ - `ea_mdg/*.xml` (46 MDG technology XMLs: BPMN, ArchiMate, SysML, ...)
8
+ - `ea_config/gml/GMLStereotypes.xml` (7 GML stereotypes with aliases)
9
+ - `ea_config/gml/GMLClassMapping.xml` (UML→GML mapping rules)
10
+ - `ea_config/gml/GMLNamespaces.xml` (15+ GML namespace declarations)
11
+
12
+ The MDG loader is functional but doesn't expose these as a queryable
13
+ registry.
14
+
15
+ ## Plan
16
+
17
+ 1. Extend `Ea::Mdg::Registry` (existing) to load all 49 files at startup.
18
+ 2. Add lookup methods:
19
+ - `Registry#stereotype_by_name(name)` → returns Stereotype with alias,
20
+ tagged value definitions, default color, applicable element types.
21
+ - `Registry#stereotypes_for_technology(tech_name)` → list.
22
+ - `Registry#tagged_value_defs(stereo_name)` → list of tagged value
23
+ definitions.
24
+ 3. Use this in rendering:
25
+ - Apply default stereotype color from MDG definition (closes some
26
+ colorization gaps).
27
+ - Validate applied stereotypes against MDG definitions.
28
+ 4. Expose via CLI (`ea mdg list`, `ea mdg show`).
29
+
30
+ ## OCP / MECE
31
+
32
+ - Registry is the single source of truth.
33
+ - New technology = new file in fixtures/ + Registry auto-discovers.
34
+ - Renderers and validators query; they don't parse XML.
35
+
36
+ ## Acceptance
37
+
38
+ - Spec: `Registry.stereotype_by_name("FeatureType")` returns non-nil.
39
+ - Spec: registry covers ≥900 stereotypes after loading all 46 MDG files.
40
+ - Spec: `ea mdg list` CLI lists technologies.
@@ -0,0 +1,42 @@
1
+ # TODO.complete/11: GML XSD schema generation
2
+
3
+ ## Status: open
4
+
5
+ The `GMLClassMapping.xml` file defines how UML classes map to GML XML
6
+ Schema constructs:
7
+
8
+ ```xml
9
+ <Class name="FeatureType"
10
+ element="featureMember"
11
+ type="FeaturePropertyType"
12
+ propertyType="..."/>
13
+ ```
14
+
15
+ With this, we can generate GML XSD schemas from QEA models — a
16
+ high-value CLI feature that EA charges money for.
17
+
18
+ ## Plan
19
+
20
+ 1. Add `Ea::Export::Xsd::Generator` in `lib/ea/export/xsd/`.
21
+ 2. Use the `GMLClassMapping` to translate:
22
+ - Class with stereotype `FeatureType` → `<xs:element>` + `<xs:complexType>`.
23
+ - Property with type `FeatureType` → property type reference.
24
+ - Property of cardinality 0..n → `maxOccurs="unbounded"`.
25
+ 3. Use `GMLNamespaces.xml` to declare target namespaces.
26
+ 4. CLI: `ea export xsd model.qea --package core -o schema.xsd`.
27
+
28
+ ## OCP / MECE
29
+
30
+ - Generator is a single class with a `call` method.
31
+ - Mapping rules loaded once from XML.
32
+ - Output is a Nokogiri::XML::Document, serialized to string.
33
+
34
+ ## Acceptance
35
+
36
+ - Spec: generate XSD from test.qea TestSchema → matches expected root element.
37
+ - Spec: FeatureType class generates `<xs:element>` + complex type.
38
+ - Spec: property with targetNamespace picks up namespace from GMLNamespaces.
39
+
40
+ ## Dependencies
41
+
42
+ - TODO.complete/10 (registry) for stereotype lookup.
@@ -0,0 +1,28 @@
1
+ # TODO.complete/13: Basic ShapeScript interpreter
2
+
3
+ ## Status: deferred
4
+
5
+ EA's MDG technologies can define stereotype icons via ShapeScript — a
6
+ domain-specific language for vector shapes (lines, polygons, ellipses).
7
+
8
+ This is what closes the **polygon -4 parity gap** (TODO.diagrams/73): the
9
+ small stereotype decorator icons EA renders inside element bodies.
10
+
11
+ ## Why deferred
12
+
13
+ - Full ShapeScript interpreter is high effort (~1-2 weeks).
14
+ - The gap is small (4 polygons across 188 diagrams).
15
+ - EA's InternalTechnologies encryption blocks the easy path to reference
16
+ shape definitions (see TODO.diagrams/87).
17
+
18
+ ## When to revisit
19
+
20
+ - Encryption is broken and we have plaintext shape definitions.
21
+ - A user specifically requests stereotype decorator icon rendering.
22
+ - A larger gap emerges that ShapeScript would close.
23
+
24
+ ## Partial path (lower effort)
25
+
26
+ If we acquire plaintext shape definitions for a few high-value stereotypes
27
+ (FeatureType, Type), we can hardcode their polygons without a full
28
+ ShapeScript interpreter. This is a tactical compromise.