ea 0.4.0 → 0.5.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (548) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +128 -1
  3. data/Rakefile +3 -0
  4. data/TODO.complete/01-t-xref-parsing.md +91 -0
  5. data/TODO.complete/02-per-label-geometry.md +50 -0
  6. data/TODO.complete/03-object-properties-constraints.md +57 -0
  7. data/TODO.complete/04-operation-params.md +37 -0
  8. data/TODO.complete/05-pdata-flag-matrix.md +52 -0
  9. data/TODO.complete/06-emf-image-rendering.md +34 -0
  10. data/TODO.complete/07-auxiliary-tables.md +47 -0
  11. data/TODO.complete/10-mdg-stereotype-registry.md +40 -0
  12. data/TODO.complete/11-gml-xsd-generation.md +42 -0
  13. data/TODO.complete/13-shapescript-interpreter.md +28 -0
  14. data/TODO.complete/20-cli-diff.md +46 -0
  15. data/TODO.complete/21-cli-render.md +26 -0
  16. data/TODO.complete/22-cli-export.md +29 -0
  17. data/TODO.complete/23-cli-mdg.md +23 -0
  18. data/TODO.complete/30-headerlines-ocp-refactor.md +72 -0
  19. data/TODO.complete/31-public-send-cleanup.md +61 -0
  20. data/TODO.complete/32-spec-coverage.md +33 -0
  21. data/TODO.complete/33-blocked-parity-gaps.md +41 -0
  22. data/TODO.complete/36-stereotype-icon-wiring.md +32 -0
  23. data/TODO.complete/37-cli-lint.md +32 -0
  24. data/TODO.complete/38-cli-query.md +26 -0
  25. data/TODO.complete/39-cli-info.md +23 -0
  26. data/TODO.complete/40-ocl-evaluator.md +31 -0
  27. data/TODO.complete/41-round-trip-spec.md +18 -0
  28. data/TODO.complete/42-html-diff-report.md +18 -0
  29. data/TODO.complete/43-json-schema-export.md +20 -0
  30. data/TODO.complete/44-remaining-qea-tables.md +40 -0
  31. data/TODO.complete/45-shapescript-extensions.md +25 -0
  32. data/TODO.complete/46-xsd-consolidation.md +20 -0
  33. data/TODO.complete/47-headerlines-legacy-removal.md +20 -0
  34. data/TODO.complete/51-remove-respond-to.md +25 -0
  35. data/TODO.complete/52-xsd-decouple-fixtures.md +23 -0
  36. data/TODO.complete/53-xmi-public-send-cleanup.md +26 -0
  37. data/TODO.complete/54-wire-stereotype-icon-renderer.md +20 -0
  38. data/TODO.complete/55-wire-shapescript.md +20 -0
  39. data/TODO.complete/56-wire-emf-renderer.md +27 -0
  40. data/TODO.complete/57-wire-ocl-evaluator.md +23 -0
  41. data/TODO.complete/58-diff-modifications.md +21 -0
  42. data/TODO.complete/59-delete-toy-xmi-export.md +30 -0
  43. data/TODO.complete/60-curate-json-export.md +20 -0
  44. data/TODO.complete/61-plantuml-relationships.md +22 -0
  45. data/TODO.complete/62-changelog.md +17 -0
  46. data/TODO.complete/63-dependabot-fix.md +18 -0
  47. data/TODO.complete/STATUS.md +85 -0
  48. data/TODO.diagrams/01-svg-measurement-harness.md +31 -0
  49. data/TODO.diagrams/02-polygon-over-rendering.md +29 -0
  50. data/TODO.diagrams/03-text-over-rendering.md +30 -0
  51. data/TODO.diagrams/04-rect-under-rendering.md +33 -0
  52. data/TODO.diagrams/05-canvas-dimension-parity.md +51 -0
  53. data/TODO.diagrams/06-group-layering-parity.md +39 -0
  54. data/TODO.diagrams/07-text-content-fidelity.md +65 -0
  55. data/TODO.diagrams/08-qea-direct-pipeline.md +46 -0
  56. data/TODO.diagrams/12-connector-labels.md +40 -0
  57. data/TODO.diagrams/12-per-entity-svg-layer-ordering.md +24 -0
  58. data/TODO.diagrams/13-marker-polygon-vs-path-dispatch.md +20 -0
  59. data/TODO.diagrams/13-per-text-type-font-sizes.md +33 -0
  60. data/TODO.diagrams/14-center-header-text.md +33 -0
  61. data/TODO.diagrams/14-filter-diagram-frame-elements.md +18 -0
  62. data/TODO.diagrams/15-deep-dead-code-audit.md +47 -0
  63. data/TODO.diagrams/15-per-element-font-from-style.md +24 -0
  64. data/TODO.diagrams/16-canvas-marker-extent.md +30 -0
  65. data/TODO.diagrams/16-document-remaining-parity-gaps.md +91 -0
  66. data/TODO.diagrams/17-italic-abstract-classes.md +28 -0
  67. data/TODO.diagrams/17-remaining-parity-gaps.md +90 -0
  68. data/TODO.diagrams/18-canvas-from-image-bounds.md +20 -0
  69. data/TODO.diagrams/18-property-lookup-index.md +42 -0
  70. data/TODO.diagrams/19-connector-sx-sy-routing.md +27 -0
  71. data/TODO.diagrams/19-replace-respond-to-with-is-a.md +31 -0
  72. data/TODO.diagrams/20-split-labels-emitter.md +56 -0
  73. data/TODO.diagrams/20-visibility-glyph-font-encoding.md +27 -0
  74. data/TODO.diagrams/21-aggregation-navigability-arrow.md +21 -0
  75. data/TODO.diagrams/21-auto-generated-legend-block.md +65 -0
  76. data/TODO.diagrams/22-ghost-element-discriminator.md +57 -0
  77. data/TODO.diagrams/22-style-based-path-grouping.md +28 -0
  78. data/TODO.diagrams/23-marker-polygon-deduplication.md +47 -0
  79. data/TODO.diagrams/23-multiplicity-label-positioning.md +29 -0
  80. data/TODO.diagrams/24-marker-anchor-structural.md +35 -0
  81. data/TODO.diagrams/24-track-marker-anchors-structurally.md +66 -0
  82. data/TODO.diagrams/24-truncate-properties-to-fit-box.md +24 -0
  83. data/TODO.diagrams/26-phantom-general-parent-rendering.md +59 -0
  84. data/TODO.diagrams/27-path-grouping-mode-detection.md +43 -0
  85. data/TODO.diagrams/28-architecture-cleanup-batch.md +47 -0
  86. data/TODO.diagrams/30-decompose-elements-groups-for.md +52 -0
  87. data/TODO.diagrams/32-examples-coverage-batch.md +78 -0
  88. data/TODO.diagrams/36-instance-specification-model.md +42 -0
  89. data/TODO.diagrams/37-element-icon-decorations.md +41 -0
  90. data/TODO.diagrams/38-html-note-and-receptions.md +32 -0
  91. data/TODO.diagrams/39-property-stereotype-discriminator.md +40 -0
  92. data/TODO.diagrams/40-standalone-1-discriminator.md +38 -0
  93. data/TODO.diagrams/41-xmi-to-svg-pipeline.md +113 -0
  94. data/TODO.diagrams/42-close-all-parity-deltas.md +69 -0
  95. data/TODO.diagrams/43-marker-deduplication-strategy.md +54 -0
  96. data/TODO.diagrams/44-element-icon-decorations.md +34 -0
  97. data/TODO.diagrams/45-phantom-parent-class-boxes.md +40 -0
  98. data/TODO.diagrams/46-user-drawn-legend-swatches.md +44 -0
  99. data/TODO.diagrams/47-attribute-line-fidelity.md +72 -0
  100. data/TODO.diagrams/48-spec-coverage-critical-emitter-components.md +45 -0
  101. data/TODO.diagrams/49-spec-coverage-orchestrators.md +25 -0
  102. data/TODO.diagrams/50-examples-parity.md +85 -0
  103. data/TODO.diagrams/51-property-oy-gap-and-remaining-gaps.md +48 -0
  104. data/TODO.diagrams/52-marker-registration-architecture.md +89 -0
  105. data/TODO.diagrams/53-remaining-example-gaps.md +86 -0
  106. data/TODO.diagrams/54-display-name-nested-classes.md +40 -0
  107. data/TODO.diagrams/55-visibility-icon-discriminator.md +58 -0
  108. data/TODO.diagrams/56-package-contents-rendering.md +148 -0
  109. data/TODO.diagrams/57-instance-specification-model.md +100 -0
  110. data/TODO.diagrams/58-domain-model-note-text.md +67 -0
  111. data/TODO.diagrams/59-classes-arrow-discriminator.md +57 -0
  112. data/TODO.diagrams/60-testschema-association-marker.md +40 -0
  113. data/TODO.diagrams/61-legend-block-rendering.md +55 -0
  114. data/TODO.diagrams/61-plateau-parity-gaps.md +59 -0
  115. data/TODO.diagrams/62-ghost-element-rendering.md +56 -0
  116. data/TODO.diagrams/63-qualified-name-wrap.md +36 -0
  117. data/TODO.diagrams/64-property-stereotype-labels.md +22 -0
  118. data/TODO.diagrams/65-path-coordinate-frame.md +62 -0
  119. data/TODO.diagrams/67-path-coordinate-frame.md +62 -0
  120. data/TODO.diagrams/68-inherited-attributes.md +65 -0
  121. data/TODO.diagrams/69-package-anchor-conditional.md +29 -0
  122. data/TODO.diagrams/70-mdg-technology-support.md +68 -0
  123. data/TODO.diagrams/71-off-canvas-parent-ghost.md +45 -0
  124. data/TODO.diagrams/72-basic-attr-divider-paths.md +39 -0
  125. data/TODO.diagrams/73-plateau-polygon-gap.md +69 -0
  126. data/TODO.diagrams/74-plateau-rect-gap.md +22 -0
  127. data/TODO.diagrams/75-plateau-text-gap.md +39 -0
  128. data/TODO.diagrams/76-basic-poly-path-gaps.md +41 -0
  129. data/TODO.diagrams/77-basic-text-overrender.md +40 -0
  130. data/TODO.diagrams/78-headerlines-ocp-refactor.md +65 -0
  131. data/TODO.diagrams/79-architecture-backlog.md +65 -0
  132. data/TODO.diagrams/80-basic-triangle-polygons.md +51 -0
  133. data/TODO.diagrams/81-plateau-path-overrender.md +53 -0
  134. data/TODO.diagrams/82-appearance-canvas-offset.md +54 -0
  135. data/TODO.diagrams/83-3d-diagram-subtitle.md +58 -0
  136. data/TODO.diagrams/84-canvas-offset-mismatches.md +61 -0
  137. data/TODO.diagrams/85-phantom-property-overrender.md +95 -0
  138. data/TODO.diagrams/86-foreign-package-rule.md +62 -0
  139. data/TODO.diagrams/87-internal-tech-encryption.md +80 -0
  140. data/TODO.diagrams/EXAMPLES_STATUS.md +88 -0
  141. data/TODO.diagrams/README.md +69 -0
  142. data/TODO.diagrams/STATUS.md +73 -0
  143. data/TODO.fixup/01-default-grouped-paths.md +34 -0
  144. data/TODO.fixup/02-marker-consolidation-per-connector.md +20 -0
  145. data/TODO.fixup/03-diagram-font-inference.md +28 -0
  146. data/TODO.fixup/04-extract-bounds-calculator.md +25 -0
  147. data/TODO.fixup/05-marker-registry-ocp.md +32 -0
  148. data/TODO.fixup/06-connector-path-bend-routing.md +28 -0
  149. data/TODO.fixup/07-edge-attachment-formula.md +22 -0
  150. data/TODO.fixup/08-visual-diff-harness.md +28 -0
  151. data/TODO.fixup/09-extract-element-compartments.md +34 -0
  152. data/TODO.fixup/10-canvas-width-overshoot-fix.md +20 -0
  153. data/TODO.fixup/11-layer-sequencer-extraction.md +18 -0
  154. data/TODO.fixup/12-path-style-harmony.md +23 -0
  155. data/TODO.fixup/13-datatype-stereotype-fallback.md +28 -0
  156. data/TODO.fixup/14-ea-exe-reverse-engineering-notes.md +56 -0
  157. data/TODO.fixup/15-enumeration-literal-rendering.md +30 -0
  158. data/TODO.fixup/16-operation-compartment-rendering.md +42 -0
  159. data/TODO.fixup/17-path-count-calibration.md +27 -0
  160. data/TODO.fixup/18-polygon-count-calibration.md +32 -0
  161. data/TODO.fixup/19-rect-count-undershoot-investigation.md +40 -0
  162. data/TODO.fixup/20-stereotype-color-from-classifier.md +18 -0
  163. data/TODO.fixup/21-visibility-filter-for-properties.md +24 -0
  164. data/TODO.fixup/22-multiplicity-display-rule-calibration.md +25 -0
  165. data/TODO.fixup/23-diagram-frame-title-element.md +31 -0
  166. data/TODO.fixup/24-note-element-rendering.md +23 -0
  167. data/TODO.fixup/25-ea-exe-disassembly-findings.md +177 -0
  168. data/TODO.fixup/26-svg-renderer-architecture.md +78 -0
  169. data/TODO.fixup/27-svg-element-emitters-disassembly.md +135 -0
  170. data/TODO.fixup/28-geometry-parser-identification.md +57 -0
  171. data/TODO.fixup/29-qea-svg-xmi-triple-comparison.md +185 -0
  172. data/TODO.fixup/30-theme-system-stub.md +46 -0
  173. data/TODO.fixup/31-theme-value-object-registry.md +17 -0
  174. data/TODO.fixup/32-styleex-on-diagram-model.md +22 -0
  175. data/TODO.fixup/33-text-encoding-decimals-rotation.md +29 -0
  176. data/TODO.fixup/34-per-type-fill-via-theme.md +18 -0
  177. data/TODO.fixup/35-stroke-width-per-theme.md +7 -0
  178. data/TODO.fixup/36-qea-rect-coord-normalization.md +24 -0
  179. data/TODO.fixup/37-package-shape-rendering.md +22 -0
  180. data/TODO.fixup/38-note-element-rendering.md +15 -0
  181. data/TODO.fixup/39-styleex-flag-honoring.md +25 -0
  182. data/TODO.fixup/40-connector-dashed-lines.md +15 -0
  183. data/TODO.fixup/41-diagram-frame-showborder-detection.md +23 -0
  184. data/TODO.fixup/42-textrenderer-centralization.md +10 -0
  185. data/TODO.fixup/43-colorresolver-unification.md +24 -0
  186. data/TODO.fixup/44-theme-aware-textrenderer.md +17 -0
  187. data/TODO.fixup/45-theme-aware-fontresolver.md +22 -0
  188. data/TODO.fixup/46-style-parameterized-by-theme.md +21 -0
  189. data/TODO.fixup/47-canvas-frame-inset.md +19 -0
  190. data/TODO.fixup/48-background-rect-format.md +15 -0
  191. data/TODO.fixup/49-all-samples-integration-test.md +17 -0
  192. data/TODO.fixup/50-svg-emitter-architecture-docs.md +33 -0
  193. data/TODO.fixup/51-promote-theme-to-ea-namespace.md +28 -0
  194. data/TODO.fixup/52-theme-definition-integrated-fills.md +26 -0
  195. data/TODO.fixup/53-theme-registry-yaml-loading.md +50 -0
  196. data/TODO.fixup/54-diagram-theme-api.md +50 -0
  197. data/TODO.fixup/55-update-eaemitter-to-ea-theme.md +23 -0
  198. data/TODO.fixup/56-theme-yaml-files.md +65 -0
  199. data/TODO.fixup/57-theme-specs-and-integration.md +27 -0
  200. data/TODO.fixup/58-ea-entry-point-theme-autoload.md +20 -0
  201. data/TODO.fixup/59-thread-theme-through-all-renderers.md +29 -0
  202. data/TODO.fixup/60-cli-theme-option.md +22 -0
  203. data/TODO.fixup/61-theme-validation.md +28 -0
  204. data/TODO.fixup/62-theme-builder-dsl.md +31 -0
  205. data/TODO.fixup/63-theme-integration-rendering-spec.md +24 -0
  206. data/TODO.fixup/64-theme-writeback-styleex.md +21 -0
  207. data/TODO.fixup/65-remove-dead-eaemitter-theme-files.md +30 -0
  208. data/TODO.fixup/66-styleex-writeback.md +22 -0
  209. data/TODO.fixup/67-delete-dead-code.md +28 -0
  210. data/TODO.fixup/68-figure-parity-status.md +82 -0
  211. data/TODO.fixup/69-package-polygon-rendering.md +54 -0
  212. data/TODO.fixup/70-tagged-values-compartment.md +39 -0
  213. data/TODO.fixup/71-auto-detect-theme-from-xmi.md +37 -0
  214. data/TODO.fixup/72-sample-exports-as-regression-specs.md +37 -0
  215. data/TODO.fixup/73-delete-dead-transformations.md +14 -0
  216. data/TODO.fixup/74-delete-dead-diagram-renderers.md +18 -0
  217. data/TODO.fixup/75-visibility-legend-icons.md +23 -0
  218. data/TODO.fixup/76-plateau-text-undershoot.md +27 -0
  219. data/TODO.fixup/77-canvas-frame-margins.md +28 -0
  220. data/TODO.fixup/78-note-element-rendering.md +30 -0
  221. data/TODO.fixup/79-operation-compartment-rendering.md +27 -0
  222. data/TODO.fixup/80-tagged-value-stereotype-visibility.md +37 -0
  223. data/TODO.fixup/81-figure-parity-current-state.md +63 -0
  224. data/config/qea_schema.yml +356 -0
  225. data/config/themes/119.yml +98 -0
  226. data/config/themes/default.yml +14 -0
  227. data/examples/exports/20251010_current_plateau_v5/UML_EA.DTD +6856 -0
  228. data/examples/exports/20251010_current_plateau_v5/model.xml +96709 -0
  229. data/examples/exports/ArcGISWorkspace_template/UML_EA.DTD +6856 -0
  230. data/examples/exports/ArcGISWorkspace_template/model.xml +1427 -0
  231. data/examples/exports/UmlModel_template/UML_EA.DTD +6856 -0
  232. data/examples/exports/UmlModel_template/model.xml +23 -0
  233. data/examples/exports/basic/UML_EA.DTD +6856 -0
  234. data/examples/exports/basic/model.xml +8039 -0
  235. data/examples/exports/simple/UML_EA.DTD +6856 -0
  236. data/examples/exports/simple/model.xml +585 -0
  237. data/examples/exports/simple_example/UML_EA.DTD +6856 -0
  238. data/examples/exports/simple_example/model.xml +23 -0
  239. data/examples/exports/test/UML_EA.DTD +6856 -0
  240. data/examples/exports/test/model.xml +1638 -0
  241. data/examples/qea/basic.qea +0 -0
  242. data/frontend/README.md +51 -0
  243. data/frontend/dist/app.iife.js +24 -0
  244. data/frontend/dist/style.css +1 -0
  245. data/frontend/index.html +26 -0
  246. data/frontend/package-lock.json +2359 -0
  247. data/frontend/package.json +26 -0
  248. data/frontend/src/App.vue +59 -0
  249. data/frontend/src/app.ts +8 -0
  250. data/frontend/src/components/AppHeader.vue +127 -0
  251. data/frontend/src/components/AppSidebar.vue +119 -0
  252. data/frontend/src/components/ClassDetails.vue +247 -0
  253. data/frontend/src/components/DiagramView.vue +79 -0
  254. data/frontend/src/components/PackageDetails.vue +92 -0
  255. data/frontend/src/components/PackageTreeNode.vue +64 -0
  256. data/frontend/src/components/SearchResults.vue +48 -0
  257. data/frontend/src/components/WelcomeView.vue +87 -0
  258. data/frontend/src/shims-vue.d.ts +5 -0
  259. data/frontend/src/stores/dataStore.ts +79 -0
  260. data/frontend/src/stores/uiStore.ts +167 -0
  261. data/frontend/src/styles/main.css +1566 -0
  262. data/frontend/src/types.ts +221 -0
  263. data/frontend/tests/e2e/__screenshots__/new-dark-mode.png +0 -0
  264. data/frontend/tests/e2e/__screenshots__/new-package-details.png +0 -0
  265. data/frontend/tests/e2e/__screenshots__/new-search-modal.png +0 -0
  266. data/frontend/tests/e2e/__screenshots__/new-sidebar-collapsed.png +0 -0
  267. data/frontend/tests/e2e/__screenshots__/new-welcome.png +0 -0
  268. data/frontend/tests/e2e/render.spec.ts +188 -0
  269. data/frontend/tsconfig.json +20 -0
  270. data/frontend/vite.config.ts +26 -0
  271. data/frontend/vitest.config.ts +8 -0
  272. data/lib/ea/cli/app.rb +57 -2
  273. data/lib/ea/cli/command/diagrams.rb +37 -28
  274. data/lib/ea/cli/command/diff.rb +46 -0
  275. data/lib/ea/cli/command/export.rb +101 -0
  276. data/lib/ea/cli/command/info.rb +75 -0
  277. data/lib/ea/cli/command/lint.rb +48 -0
  278. data/lib/ea/cli/command/mdg.rb +98 -0
  279. data/lib/ea/cli/command/query.rb +34 -0
  280. data/lib/ea/cli/command/render.rb +135 -0
  281. data/lib/ea/cli/command/svg.rb +8 -15
  282. data/lib/ea/cli/command.rb +7 -0
  283. data/lib/ea/diagram/display_config.rb +184 -0
  284. data/lib/ea/diagram.rb +4 -41
  285. data/lib/ea/diff/change.rb +30 -0
  286. data/lib/ea/diff/comparator.rb +109 -0
  287. data/lib/ea/diff/html_reporter.rb +91 -0
  288. data/lib/ea/diff.rb +15 -0
  289. data/lib/ea/export/json/generator.rb +118 -0
  290. data/lib/ea/export/json.rb +12 -0
  291. data/lib/ea/export/json_schema/generator.rb +77 -0
  292. data/lib/ea/export/json_schema.rb +12 -0
  293. data/lib/ea/export/plantuml/generator.rb +140 -0
  294. data/lib/ea/export/plantuml.rb +12 -0
  295. data/lib/ea/export/xsd/class_mapping.rb +65 -0
  296. data/lib/ea/export/xsd/generator.rb +137 -0
  297. data/lib/ea/export/xsd/namespace_registry.rb +82 -0
  298. data/lib/ea/export/xsd.rb +19 -0
  299. data/lib/ea/export.rb +13 -0
  300. data/lib/ea/image/emf_renderer.rb +42 -0
  301. data/lib/ea/image.rb +12 -0
  302. data/lib/ea/lint/engine.rb +30 -0
  303. data/lib/ea/lint/lint_rule.rb +38 -0
  304. data/lib/ea/lint/offense.rb +18 -0
  305. data/lib/ea/lint/rules/cyclic_generalization.rb +62 -0
  306. data/lib/ea/lint/rules/duplicate_name.rb +28 -0
  307. data/lib/ea/lint/rules/missing_stereotype.rb +40 -0
  308. data/lib/ea/lint/rules/naming_convention.rb +44 -0
  309. data/lib/ea/lint/rules/orphan_element.rb +28 -0
  310. data/lib/ea/lint/rules.rb +14 -0
  311. data/lib/ea/lint.rb +13 -0
  312. data/lib/ea/mdg/document.rb +120 -0
  313. data/lib/ea/mdg/loader.rb +118 -0
  314. data/lib/ea/mdg/registry.rb +98 -0
  315. data/lib/ea/mdg/stereotype_alias_registry.rb +77 -0
  316. data/lib/ea/mdg/xml/applies_to.rb +18 -0
  317. data/lib/ea/mdg/xml/apply.rb +18 -0
  318. data/lib/ea/mdg/xml/content.rb +18 -0
  319. data/lib/ea/mdg/xml/documentation.rb +24 -0
  320. data/lib/ea/mdg/xml/stereotype.rb +28 -0
  321. data/lib/ea/mdg/xml/stereotypes.rb +18 -0
  322. data/lib/ea/mdg/xml/tag.rb +28 -0
  323. data/lib/ea/mdg/xml/tagged_values.rb +18 -0
  324. data/lib/ea/mdg/xml/technology.rb +28 -0
  325. data/lib/ea/mdg/xml/uml_profile.rb +22 -0
  326. data/lib/ea/mdg/xml/uml_profiles.rb +18 -0
  327. data/lib/ea/mdg/xml.rb +24 -0
  328. data/lib/ea/mdg.rb +25 -0
  329. data/lib/ea/model/classifier.rb +4 -0
  330. data/lib/ea/model/constraint.rb +24 -0
  331. data/lib/ea/model/diagram.rb +85 -0
  332. data/lib/ea/model/diagram_connector.rb +34 -0
  333. data/lib/ea/model/diagram_element.rb +16 -0
  334. data/lib/ea/model/document.rb +47 -2
  335. data/lib/ea/model/ghost_label.rb +32 -0
  336. data/lib/ea/model/instance_specification.rb +34 -0
  337. data/lib/ea/model/legend.rb +43 -0
  338. data/lib/ea/model/legend_item.rb +26 -0
  339. data/lib/ea/model/note.rb +28 -0
  340. data/lib/ea/model/operation.rb +2 -0
  341. data/lib/ea/model/property.rb +2 -0
  342. data/lib/ea/model/relationship.rb +2 -0
  343. data/lib/ea/model/signal.rb +14 -0
  344. data/lib/ea/model/slot.rb +19 -0
  345. data/lib/ea/model.rb +8 -0
  346. data/lib/ea/ocl/evaluator.rb +94 -0
  347. data/lib/ea/ocl/nodes.rb +30 -0
  348. data/lib/ea/ocl/parser.rb +133 -0
  349. data/lib/ea/ocl/unsupported_error.rb +7 -0
  350. data/lib/ea/ocl.rb +13 -0
  351. data/lib/ea/qea/factory/document_builder.rb +24 -10
  352. data/lib/ea/qea/factory/generalization_builder.rb +9 -11
  353. data/lib/ea/qea/infrastructure/table_reader.rb +9 -0
  354. data/lib/ea/qea/models/ea_author.rb +35 -0
  355. data/lib/ea/qea/models/ea_glossary.rb +34 -0
  356. data/lib/ea/qea/models/ea_image.rb +53 -0
  357. data/lib/ea/qea/models/ea_implement.rb +32 -0
  358. data/lib/ea/qea/models/ea_list.rb +42 -0
  359. data/lib/ea/qea/models/ea_object_effort.rb +34 -0
  360. data/lib/ea/qea/models/ea_object_problem.rb +37 -0
  361. data/lib/ea/qea/models/ea_object_require.rb +34 -0
  362. data/lib/ea/qea/models/ea_object_resource.rb +34 -0
  363. data/lib/ea/qea/models/ea_object_risk.rb +34 -0
  364. data/lib/ea/qea/models/ea_object_scenario.rb +34 -0
  365. data/lib/ea/qea/models/ea_object_test.rb +35 -0
  366. data/lib/ea/qea/models/ea_object_trx.rb +34 -0
  367. data/lib/ea/qea/models/ea_operation.rb +7 -0
  368. data/lib/ea/qea/models/ea_palette.rb +30 -0
  369. data/lib/ea/qea/models/ea_palette_item.rb +36 -0
  370. data/lib/ea/qea/models/ea_phase.rb +40 -0
  371. data/lib/ea/qea/models/ea_role_constraint.rb +32 -0
  372. data/lib/ea/qea/models/ea_secrypt.rb +34 -0
  373. data/lib/ea/qea/models/ea_version.rb +39 -0
  374. data/lib/ea/qea/models/ea_xref.rb +11 -1
  375. data/lib/ea/qea/models.rb +19 -0
  376. data/lib/ea/qea/services/database_loader.rb +22 -1
  377. data/lib/ea/qea/validation/database/ocl_constraint_validator.rb +65 -0
  378. data/lib/ea/qea/validation/database.rb +2 -0
  379. data/lib/ea/qea/validation/validation_engine.rb +2 -0
  380. data/lib/ea/qea/validation.rb +2 -0
  381. data/lib/ea/query/builder.rb +127 -0
  382. data/lib/ea/query.rb +9 -0
  383. data/lib/ea/render/image_converter.rb +101 -0
  384. data/lib/ea/render.rb +10 -0
  385. data/lib/ea/shapescript/parser.rb +208 -0
  386. data/lib/ea/shapescript/renderer.rb +74 -0
  387. data/lib/ea/shapescript/shape.rb +34 -0
  388. data/lib/ea/shapescript.rb +24 -0
  389. data/lib/ea/sources/qea/adapter.rb +22 -5
  390. data/lib/ea/sources/qea/classifier_builder.rb +184 -7
  391. data/lib/ea/sources/qea/diagram_builder.rb +352 -24
  392. data/lib/ea/sources/qea/id_normalizer.rb +16 -1
  393. data/lib/ea/sources/qea/instance_builder.rb +113 -0
  394. data/lib/ea/sources/qea/legend_builder.rb +137 -0
  395. data/lib/ea/sources/qea/note_builder.rb +58 -0
  396. data/lib/ea/sources/qea/object_classifier_map.rb +6 -1
  397. data/lib/ea/sources/qea/operation_builder.rb +1 -0
  398. data/lib/ea/sources/qea/package_builder.rb +16 -0
  399. data/lib/ea/sources/qea/relationship_builder.rb +21 -5
  400. data/lib/ea/sources/qea/tagged_value_builder.rb +28 -9
  401. data/lib/ea/sources/qea/xref/legend_definition.rb +35 -0
  402. data/lib/ea/sources/qea/xref/parser.rb +150 -0
  403. data/lib/ea/sources/qea/xref/property_definition.rb +29 -0
  404. data/lib/ea/sources/qea/xref/record.rb +41 -0
  405. data/lib/ea/sources/qea/xref/stereotype_application.rb +37 -0
  406. data/lib/ea/sources/qea/xref.rb +27 -0
  407. data/lib/ea/sources/qea.rb +4 -0
  408. data/lib/ea/sources/xmi/adapter.rb +80 -2
  409. data/lib/ea/sources/xmi/classifier_builder.rb +10 -1
  410. data/lib/ea/sources/xmi/diagram_builder.rb +95 -18
  411. data/lib/ea/sources/xmi/extension_geometry_parser.rb +19 -2
  412. data/lib/ea/sources/xmi/extension_style_parser.rb +15 -2
  413. data/lib/ea/sources/xmi/note_builder.rb +46 -0
  414. data/lib/ea/sources/xmi/property_builder.rb +9 -0
  415. data/lib/ea/sources/xmi/stereotype_builder.rb +54 -0
  416. data/lib/ea/sources/xmi/tag_builder.rb +45 -0
  417. data/lib/ea/sources/xmi/umldi_keyword_extractor.rb +87 -0
  418. data/lib/ea/sources/xmi.rb +4 -0
  419. data/lib/ea/spa/output/sharded_multi_file_strategy.rb +18 -3
  420. data/lib/ea/spa/output/single_file_strategy.rb +8 -2
  421. data/lib/ea/spa/output/strategy.rb +34 -0
  422. data/lib/ea/svg/connector_router.rb +134 -0
  423. data/lib/ea/svg/ea_emitter/background.rb +2 -3
  424. data/lib/ea/svg/ea_emitter/bounds_calculator.rb +142 -0
  425. data/lib/ea/svg/ea_emitter/canvas.rb +56 -33
  426. data/lib/ea/svg/ea_emitter/color_resolver.rb +56 -0
  427. data/lib/ea/svg/ea_emitter/compartment/attributes.rb +28 -0
  428. data/lib/ea/svg/ea_emitter/compartment/constraints.rb +30 -0
  429. data/lib/ea/svg/ea_emitter/compartment/enum_literals.rb +86 -0
  430. data/lib/ea/svg/ea_emitter/compartment/header.rb +32 -0
  431. data/lib/ea/svg/ea_emitter/compartment/header_divider.rb +57 -0
  432. data/lib/ea/svg/ea_emitter/compartment/instance_slots.rb +96 -0
  433. data/lib/ea/svg/ea_emitter/compartment/instance_underline.rb +67 -0
  434. data/lib/ea/svg/ea_emitter/compartment/note_body.rb +52 -0
  435. data/lib/ea/svg/ea_emitter/compartment/note_text.rb +102 -0
  436. data/lib/ea/svg/ea_emitter/compartment/operations.rb +38 -0
  437. data/lib/ea/svg/ea_emitter/compartment/package_contents.rb +72 -0
  438. data/lib/ea/svg/ea_emitter/compartment/package_from_parent.rb +136 -0
  439. data/lib/ea/svg/ea_emitter/compartment/shape.rb +82 -0
  440. data/lib/ea/svg/ea_emitter/compartment/stereotype_icon.rb +32 -0
  441. data/lib/ea/svg/ea_emitter/compartment/tagged_values.rb +30 -0
  442. data/lib/ea/svg/ea_emitter/compartment.rb +60 -0
  443. data/lib/ea/svg/ea_emitter/connectors.rb +46 -12
  444. data/lib/ea/svg/ea_emitter/diagram_frame.rb +143 -0
  445. data/lib/ea/svg/ea_emitter/document.rb +49 -25
  446. data/lib/ea/svg/ea_emitter/element/attribute_line_builder.rb +117 -0
  447. data/lib/ea/svg/ea_emitter/element/attribute_renderer.rb +119 -0
  448. data/lib/ea/svg/ea_emitter/element/bcol_decoder.rb +29 -0
  449. data/lib/ea/svg/ea_emitter/element/compartment_geometry.rb +113 -0
  450. data/lib/ea/svg/ea_emitter/element/constraint_renderer.rb +53 -0
  451. data/lib/ea/svg/ea_emitter/element/divider_renderer.rb +17 -0
  452. data/lib/ea/svg/ea_emitter/element/enumeration_literal_renderer.rb +34 -0
  453. data/lib/ea/svg/ea_emitter/element/filter.rb +44 -0
  454. data/lib/ea/svg/ea_emitter/element/hand_draw_shape_renderer.rb +77 -0
  455. data/lib/ea/svg/ea_emitter/element/header_line_pipeline.rb +43 -0
  456. data/lib/ea/svg/ea_emitter/element/header_line_provider/instance_spec.rb +27 -0
  457. data/lib/ea/svg/ea_emitter/element/header_line_provider/name.rb +76 -0
  458. data/lib/ea/svg/ea_emitter/element/header_line_provider/parent_ghost.rb +25 -0
  459. data/lib/ea/svg/ea_emitter/element/header_line_provider/stereotype_label.rb +68 -0
  460. data/lib/ea/svg/ea_emitter/element/header_line_provider.rb +19 -0
  461. data/lib/ea/svg/ea_emitter/element/header_lines.rb +27 -0
  462. data/lib/ea/svg/ea_emitter/element/header_renderer.rb +48 -0
  463. data/lib/ea/svg/ea_emitter/element/icon_renderer.rb +109 -0
  464. data/lib/ea/svg/ea_emitter/element/legend_renderer.rb +177 -0
  465. data/lib/ea/svg/ea_emitter/element/note_shape_renderer.rb +112 -0
  466. data/lib/ea/svg/ea_emitter/element/operation_renderer.rb +100 -0
  467. data/lib/ea/svg/ea_emitter/element/package_shape_renderer.rb +181 -0
  468. data/lib/ea/svg/ea_emitter/element/row_icon_renderer.rb +156 -0
  469. data/lib/ea/svg/ea_emitter/element/shape_renderer.rb +17 -0
  470. data/lib/ea/svg/ea_emitter/element/stereotype_icon_renderer.rb +119 -0
  471. data/lib/ea/svg/ea_emitter/element/tagged_value_renderer.rb +50 -0
  472. data/lib/ea/svg/ea_emitter/element/text_escape.rb +20 -0
  473. data/lib/ea/svg/ea_emitter/element.rb +37 -0
  474. data/lib/ea/svg/ea_emitter/elements.rb +283 -95
  475. data/lib/ea/svg/ea_emitter/font_resolver.rb +111 -0
  476. data/lib/ea/svg/ea_emitter/ghost_labels.rb +66 -0
  477. data/lib/ea/svg/ea_emitter/label/end_label.rb +266 -0
  478. data/lib/ea/svg/ea_emitter/label/midpoint_label.rb +101 -0
  479. data/lib/ea/svg/ea_emitter/label/registry.rb +50 -0
  480. data/lib/ea/svg/ea_emitter/label.rb +23 -0
  481. data/lib/ea/svg/ea_emitter/labels.rb +93 -27
  482. data/lib/ea/svg/ea_emitter/layer.rb +20 -0
  483. data/lib/ea/svg/ea_emitter/layer_sequencer.rb +93 -0
  484. data/lib/ea/svg/ea_emitter/marker/arrow_path.rb +52 -0
  485. data/lib/ea/svg/ea_emitter/marker/diamond.rb +57 -0
  486. data/lib/ea/svg/ea_emitter/marker/kind.rb +35 -0
  487. data/lib/ea/svg/ea_emitter/marker/open_triangle.rb +27 -0
  488. data/lib/ea/svg/ea_emitter/marker/package_import.rb +39 -0
  489. data/lib/ea/svg/ea_emitter/marker/plus.rb +40 -0
  490. data/lib/ea/svg/ea_emitter/marker/registry.rb +42 -0
  491. data/lib/ea/svg/ea_emitter/marker.rb +37 -0
  492. data/lib/ea/svg/ea_emitter/markers.rb +351 -64
  493. data/lib/ea/svg/ea_emitter/render_context.rb +52 -0
  494. data/lib/ea/svg/ea_emitter/style.rb +15 -0
  495. data/lib/ea/svg/ea_emitter/text_renderer.rb +92 -0
  496. data/lib/ea/svg/ea_emitter.rb +33 -11
  497. data/lib/ea/svg/parity/checker.rb +105 -0
  498. data/lib/ea/svg/parity/source.rb +59 -0
  499. data/lib/ea/svg/parity/suite.rb +113 -0
  500. data/lib/ea/svg/parity.rb +14 -0
  501. data/lib/ea/svg.rb +2 -15
  502. data/lib/ea/theme/definition.rb +176 -0
  503. data/lib/ea/theme/loader.rb +125 -0
  504. data/lib/ea/theme/registry.rb +96 -0
  505. data/lib/ea/theme.rb +37 -0
  506. data/lib/ea/transformations.rb +5 -88
  507. data/lib/ea/validation/xmi_parity.rb +80 -0
  508. data/lib/ea/validation.rb +12 -0
  509. data/lib/ea/version.rb +4 -1
  510. data/lib/ea.rb +15 -4
  511. data/lib/tasks/svg_bench.rake +87 -0
  512. data/lutaml-uml-0.5.1.gem +0 -0
  513. data/reference-docs/enterprise-architect-appearance-dialogs/appearance-1-diagram-1-themes-list.png +0 -0
  514. data/reference-docs/enterprise-architect-appearance-dialogs/appearance-1-diagram-1-themes.png +0 -0
  515. data/reference-docs/enterprise-architect-appearance-dialogs/appearance-1-diagram-2-gradients.png +0 -0
  516. data/reference-docs/enterprise-architect-appearance-dialogs/appearance-1-diagram-3-colors.png +0 -0
  517. data/reference-docs/enterprise-architect-appearance-dialogs/appearance-1-diagram-4-appearance-fonts.png +0 -0
  518. data/reference-docs/enterprise-architect-appearance-dialogs/appearance-1-diagram-4-appearance.png +0 -0
  519. data/reference-docs/enterprise-architect-appearance-dialogs/appearance-1-diagram-5-behavior.png +0 -0
  520. data/reference-docs/enterprise-architect-appearance-dialogs/appearance-1-diagram-6-sequence.png +0 -0
  521. data/reference-docs/enterprise-architect-appearance-dialogs/appearance-1-diagram.png +0 -0
  522. data/reference-docs/enterprise-architect-appearance-dialogs/appearance-2-objects.png +0 -0
  523. data/reference-docs/enterprise-architect-appearance-dialogs/appearance-3-links.png +0 -0
  524. metadata +464 -26
  525. data/lib/ea/diagram/configuration.rb +0 -379
  526. data/lib/ea/diagram/element_renderers/base_renderer.rb +0 -77
  527. data/lib/ea/diagram/element_renderers/class_renderer.rb +0 -323
  528. data/lib/ea/diagram/element_renderers/connector_renderer.rb +0 -41
  529. data/lib/ea/diagram/element_renderers/package_renderer.rb +0 -61
  530. data/lib/ea/diagram/element_renderers.rb +0 -43
  531. data/lib/ea/diagram/extractor.rb +0 -566
  532. data/lib/ea/diagram/layout_engine.rb +0 -170
  533. data/lib/ea/diagram/path_builder.rb +0 -202
  534. data/lib/ea/diagram/style_parser.rb +0 -42
  535. data/lib/ea/diagram/style_resolver.rb +0 -291
  536. data/lib/ea/diagram/svg_renderer.rb +0 -274
  537. data/lib/ea/diagram/util.rb +0 -73
  538. data/lib/ea/svg/bounds_calculator.rb +0 -74
  539. data/lib/ea/svg/connector_path.rb +0 -138
  540. data/lib/ea/svg/element_box.rb +0 -256
  541. data/lib/ea/svg/renderer.rb +0 -77
  542. data/lib/ea/svg/style_resolver.rb +0 -72
  543. data/lib/ea/transformations/configuration.rb +0 -333
  544. data/lib/ea/transformations/format_registry.rb +0 -366
  545. data/lib/ea/transformations/parsers/base_parser.rb +0 -482
  546. data/lib/ea/transformations/parsers/qea_parser.rb +0 -401
  547. data/lib/ea/transformations/parsers/xmi_parser.rb +0 -243
  548. data/lib/ea/transformations/transformation_engine.rb +0 -390
@@ -0,0 +1,101 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "json"
4
+
5
+ module Ea
6
+ module Cli
7
+ module Command
8
+ # `ea export SUB FILE` where SUB ∈ {xmi, json, plantuml, xsd}.
9
+ #
10
+ # Routes to the appropriate Exporter based on `sub`. Each
11
+ # exporter lives under Ea::Export::* and implements
12
+ # `call(model, **opts) → String`. Adding a new format = adding
13
+ # a new exporter (OCP), no changes to this command.
14
+ class Export < Base
15
+ COLUMNS = %i[format bytes_written path].freeze
16
+
17
+ def call
18
+ validate_file!(file_path)
19
+ output = exporter.call(model, **exporter_options)
20
+ path = write_output(output, default_name: default_name)
21
+ formatter.render([[sub, output.bytesize, path]], columns: COLUMNS)
22
+ end
23
+
24
+ private
25
+
26
+ def sub
27
+ options[:sub].to_sym
28
+ end
29
+
30
+ def exporter
31
+ @exporter ||= EXPORTERS.fetch(sub) do
32
+ raise Ea::Cli::Error,
33
+ "Unknown export format: #{sub}. " \
34
+ "Valid: #{EXPORTERS.keys.join(", ")}"
35
+ end
36
+ end
37
+
38
+ # Each value is a callable taking (model, **opts) and returning
39
+ # a string. New formats add a new entry here without touching
40
+ # this class body. Lambdas lazy-resolve autoloaded namespaces.
41
+ EXPORTERS = {
42
+ xmi: ->(model, **_o) { Ea::Transformers.qea_to_xmi(model) },
43
+ json: ->(model, **o) { Ea::Export::Json::Generator.call(model, **o) },
44
+ "json-schema": ->(model, **o) { Ea::Export::JsonSchema::Generator.call(model, **o) },
45
+ plantuml: ->(model, **o) { Ea::Export::PlantUml::Generator.call(model, **o) },
46
+ xsd: ->(model, **o) { Ea::Export::Xsd::Generator.call(model, **Ea::Cli::Command::Export.xsd_options(o)) }
47
+ }.freeze
48
+
49
+ # Load GMLClassMapping + GMLNamespaces fixtures when present
50
+ # (repo-local dev path) and pass to the XSD generator. Keeps
51
+ # fixture-path knowledge in the CLI layer; lib stays pure.
52
+ def self.xsd_options(opts)
53
+ mapping = load_if_present("spec/fixtures/mdg/ea_config/gml/GMLClassMapping.xml",
54
+ Ea::Export::Xsd::ClassMapping)
55
+ namespaces = load_if_present("spec/fixtures/mdg/ea_config/gml/GMLNamespaces.xml",
56
+ Ea::Export::Xsd::NamespaceRegistry)
57
+ opts[:class_mapping] = mapping if mapping
58
+ opts[:namespaces] = namespaces if namespaces
59
+ opts
60
+ end
61
+
62
+ def self.load_if_present(path, loader)
63
+ return nil unless File.exist?(path)
64
+
65
+ loader.from_path(path)
66
+ rescue StandardError
67
+ nil
68
+ end
69
+
70
+ def exporter_options
71
+ opts = {}
72
+ opts[:target_namespace] = options[:target_namespace] if options[:target_namespace]
73
+ opts[:prefix] = options[:prefix] if options[:prefix]
74
+ opts
75
+ end
76
+
77
+ def model
78
+ @model ||= load_database(file_path)
79
+ end
80
+
81
+ def default_name
82
+ base = File.basename(file_path, ".*")
83
+ dir = File.dirname(file_path)
84
+ ext = exporter_extension
85
+ File.join(dir, "#{base}.#{ext}")
86
+ end
87
+
88
+ def exporter_extension
89
+ case sub
90
+ when :xmi then "xmi"
91
+ when :json then "json"
92
+ when :"json-schema" then "schema.json"
93
+ when :plantuml then "puml"
94
+ when :xsd then "xsd"
95
+ else sub.to_s
96
+ end
97
+ end
98
+ end
99
+ end
100
+ end
101
+ end
@@ -0,0 +1,75 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Ea
4
+ module Cli
5
+ module Command
6
+ # `ea info NAME FILE` — show details of one element by name.
7
+ class Info < Base
8
+ COLUMNS = %i[field value].freeze
9
+
10
+ def call
11
+ element = find_element
12
+ unless element
13
+ warn "Element #{name.inspect} not found"
14
+ exit(1)
15
+ end
16
+
17
+ rows = build_info(element)
18
+ formatter.render(rows, columns: COLUMNS)
19
+ end
20
+
21
+ private
22
+
23
+ def name
24
+ options[:name]
25
+ end
26
+
27
+ def model
28
+ @model ||= load_database(file_path)
29
+ end
30
+
31
+ def find_element
32
+ (model.collections[:objects] || []).find { |o| o.name == name }
33
+ end
34
+
35
+ def build_info(element)
36
+ rows = [
37
+ ["id", element.object_id],
38
+ ["name", element.name],
39
+ ["type", element.object_type],
40
+ ["author", element.author],
41
+ ["version", element.version],
42
+ ["package", package_name_for(element)],
43
+ ["stereotypes", stereotypes_for(element).join(", ")],
44
+ ["notes", (element.note || "")[0, 100]]
45
+ ]
46
+
47
+ attrs = attributes_for(element)
48
+ rows.concat(attrs.each_with_index.map do |a, i|
49
+ ["attr[#{i}]", "#{a.name}: #{a.type || 'void'}"]
50
+ end)
51
+
52
+ rows
53
+ end
54
+
55
+ def attributes_for(element)
56
+ (model.collections[:attributes] || [])
57
+ .select { |a| a.object_id == element.object_id }
58
+ end
59
+
60
+ def package_name_for(element)
61
+ pkg = (model.collections[:packages] || []).find { |p| p.package_id == element.package_id }
62
+ pkg&.name || "-"
63
+ end
64
+
65
+ def stereotypes_for(element)
66
+ xrefs = model.collections[:xrefs] || []
67
+ stereo_xrefs = xrefs.select do |xr|
68
+ xr.client == element.ea_guid && xr.description&.include?("@STEREO")
69
+ end
70
+ stereo_xrefs.map { |xr| xr.description[/Name=([^;]+)/, 1] }.compact
71
+ end
72
+ end
73
+ end
74
+ end
75
+ end
@@ -0,0 +1,48 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Ea
4
+ module Cli
5
+ module Command
6
+ # `ea lint FILE [--rule=NAME] [--severity=error|warning]`
7
+ #
8
+ # Runs the Ea::Lint::Engine over a parsed model and reports
9
+ # offenses. Exit 1 when errors are found.
10
+ class Lint < Base
11
+ COLUMNS = %i[severity rule entity_name message].freeze
12
+
13
+ def call
14
+ offenses = engine.run(model)
15
+ offenses = filter_by_rule(offenses)
16
+ offenses = filter_by_severity(offenses)
17
+ rows = offenses.map { |o| [o.severity, o.rule, o.entity_name, o.message] }
18
+ formatter.render(rows, columns: COLUMNS)
19
+ exit(1) if offenses.any?(&:error?)
20
+ end
21
+
22
+ private
23
+
24
+ def engine
25
+ @engine ||= Ea::Lint::Engine.new
26
+ end
27
+
28
+ def model
29
+ @model ||= load_database(file_path)
30
+ end
31
+
32
+ def filter_by_rule(offenses)
33
+ return offenses unless options[:rule]
34
+
35
+ rule_filter = options[:rule].to_s
36
+ offenses.select { |o| o.rule.to_s.downcase.include?(rule_filter.downcase) }
37
+ end
38
+
39
+ def filter_by_severity(offenses)
40
+ return offenses unless options[:severity]
41
+
42
+ sev = options[:severity].to_sym
43
+ offenses.select { |o| o.severity == sev }
44
+ end
45
+ end
46
+ end
47
+ end
48
+ end
@@ -0,0 +1,98 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Ea
4
+ module Cli
5
+ module Command
6
+ # `ea mdg ACTION [ARG]`
7
+ #
8
+ # Actions:
9
+ # list — list registered technologies
10
+ # show NAME — show stereotype details
11
+ # stereotypes — list all stereotypes across technologies
12
+ class Mdg < Base
13
+ COLUMNS = %i[name version stereotypes].freeze
14
+
15
+ def call
16
+ case action
17
+ when "list" then list_technologies
18
+ when "show" then show_stereotype(arg)
19
+ when "stereotypes" then list_stereotypes
20
+ else
21
+ raise Ea::Cli::Error,
22
+ "Unknown mdg action: #{action}. " \
23
+ "Valid: list | show NAME | stereotypes"
24
+ end
25
+ end
26
+
27
+ private
28
+
29
+ def action
30
+ options[:action]
31
+ end
32
+
33
+ def arg
34
+ options[:arg]
35
+ end
36
+
37
+ def registry
38
+ @registry ||= build_registry
39
+ end
40
+
41
+ def build_registry
42
+ registry = Ea::Mdg::Registry.new
43
+ Dir.glob("spec/fixtures/mdg/**/*.xml").each do |path|
44
+ begin
45
+ doc = Ea::Mdg::Loader.from_path(path).document
46
+ registry.register(doc)
47
+ rescue StandardError => e
48
+ warn "Skipped #{path}: #{e.message}" if ENV["EA_DEBUG"]
49
+ end
50
+ end
51
+ registry
52
+ end
53
+
54
+ def list_technologies
55
+ rows = registry.documents.map do |doc|
56
+ [doc.technology_name, "-", (doc.stereotypes || []).size]
57
+ end
58
+ formatter.render(rows, columns: COLUMNS)
59
+ end
60
+
61
+ def list_stereotypes
62
+ rows = []
63
+ registry.documents.each do |doc|
64
+ (doc.stereotypes || []).each do |st|
65
+ rows << [doc.technology_name, st.name, st.applies_to.join(",")]
66
+ end
67
+ end
68
+ formatter.render(rows, columns: %i[technology name applies_to])
69
+ end
70
+
71
+ def show_stereotype(name)
72
+ return unless name
73
+
74
+ found = nil
75
+ registry.documents.each do |doc|
76
+ st = (doc.stereotypes || []).find { |s| s.name == name }
77
+ next unless st
78
+
79
+ found = { technology: doc.technology_name, stereo: st }
80
+ break
81
+ end
82
+
83
+ if found
84
+ formatter.render(
85
+ [[found[:technology], found[:stereo].name,
86
+ found[:stereo].applies_to.join(","),
87
+ (found[:stereo].tagged_values || []).size]],
88
+ columns: %i[technology name applies_to tagged_values]
89
+ )
90
+ else
91
+ warn "Stereotype #{name.inspect} not found"
92
+ exit(1)
93
+ end
94
+ end
95
+ end
96
+ end
97
+ end
98
+ end
@@ -0,0 +1,34 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Ea
4
+ module Cli
5
+ module Command
6
+ # `ea query FILE [--type=T] [--package=NAME] [--stereo=NAME]`
7
+ #
8
+ # Wraps Ea::Query::Builder for CLI consumption.
9
+ class Query < Base
10
+ COLUMNS = %i[id type name package].freeze
11
+
12
+ def call
13
+ builder = Ea::Query::Builder.new(model)
14
+ builder = builder.with_type(options[:type]) if options[:type]
15
+ builder = builder.in_package(options[:package]) if options[:package]
16
+ builder = builder.with_stereotype(options[:stereotype]) if options[:stereotype]
17
+ rows = builder.call.map { |o| [o.object_id, o.object_type, o.name, package_name_for(o)] }
18
+ formatter.render(rows, columns: COLUMNS)
19
+ end
20
+
21
+ private
22
+
23
+ def model
24
+ @model ||= load_database(file_path)
25
+ end
26
+
27
+ def package_name_for(obj)
28
+ pkg = (model.collections[:packages] || []).find { |p| p.package_id == obj.package_id }
29
+ pkg&.name || "-"
30
+ end
31
+ end
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,135 @@
1
+ # frozen_string: true
2
+
3
+ require "fileutils"
4
+
5
+ module Ea
6
+ module Cli
7
+ module Command
8
+ # `ea render NAME FILE [--format=svg|png|pdf]`
9
+ # `ea render --all FILE [--output-dir=PATH]`
10
+ #
11
+ # Unified rendering command. Currently supports SVG; PNG and PDF
12
+ # are routed through SVG intermediate (planned: rsvg-convert /
13
+ # headless chrome). The original `ea svg` command is preserved
14
+ # as a backward-compatible alias.
15
+ class Render < Base
16
+ def call
17
+ return render_all if options[:all]
18
+
19
+ render_one
20
+ end
21
+
22
+ private
23
+
24
+ def render_one
25
+ diagram = find_diagram
26
+ write_diagram(diagram, resolve_output_path(diagram))
27
+ end
28
+
29
+ def render_all
30
+ out_dir = options[:output_dir] || default_output_dir
31
+ FileUtils.mkdir_p(out_dir)
32
+ paths = document.diagrams.map do |diagram|
33
+ path = File.join(out_dir, "#{diagram.id}.#{format_ext}")
34
+ write_diagram(diagram, path)
35
+ path
36
+ end
37
+ formatter.render(paths.map { |p| [p] }, columns: [:written_to])
38
+ end
39
+
40
+ def write_diagram(diagram, output_path)
41
+ FileUtils.mkdir_p(File.dirname(output_path))
42
+ svg = render_svg(diagram)
43
+
44
+ case requested_format
45
+ when :svg
46
+ File.write(output_path, svg)
47
+ when :png
48
+ File.binwrite(output_path, svg_to_png(svg))
49
+ when :pdf
50
+ File.binwrite(output_path, svg_to_pdf(svg))
51
+ else
52
+ raise Ea::Cli::Error, "Unknown format: #{requested_format.inspect}"
53
+ end
54
+ end
55
+
56
+ def render_svg(diagram)
57
+ emitter_for_mode.new(diagram,
58
+ model_index: document.index_by_id,
59
+ document: document).render
60
+ end
61
+
62
+ def svg_to_png(svg)
63
+ Ea::Render::ImageConverter
64
+ .new(svg).to_png
65
+ end
66
+
67
+ def svg_to_pdf(svg)
68
+ Ea::Render::ImageConverter
69
+ .new(svg).to_pdf
70
+ end
71
+
72
+ def requested_format
73
+ (options[:format] || :svg).to_sym
74
+ end
75
+
76
+ def format_ext
77
+ case requested_format
78
+ when :svg then "svg"
79
+ when :png then "png"
80
+ when :pdf then "pdf"
81
+ else "svg"
82
+ end
83
+ end
84
+
85
+ def default_output_dir
86
+ base = File.basename(file_path, ".*")
87
+ dir = File.dirname(file_path)
88
+ File.join(dir, "#{base}.renders")
89
+ end
90
+
91
+ def emitter_for_mode
92
+ Ea::Svg::EaEmitter::Document
93
+ end
94
+
95
+ def document
96
+ @document ||= build_model_document
97
+ end
98
+
99
+ def build_model_document
100
+ case File.extname(file_path).downcase
101
+ when ".qea"
102
+ Ea::Sources::Qea::Adapter.from_path(file_path)
103
+ when ".xmi"
104
+ Ea::Sources::Xmi::Adapter.from_path(file_path)
105
+ else
106
+ raise Ea::Cli::UnsupportedFormat,
107
+ "Unknown file format: #{File.extname(file_path)}"
108
+ end
109
+ end
110
+
111
+ def diagram_name
112
+ options[:name] or raise Ea::Cli::Error, "missing required diagram name"
113
+ end
114
+
115
+ def find_diagram
116
+ match = document.diagrams.find { |d| d.name == diagram_name }
117
+ return match if match
118
+
119
+ raise Ea::Cli::Error,
120
+ "Diagram #{diagram_name.inspect} not found in #{file_path}. " \
121
+ "Use `ea diagrams list #{file_path}` to see names."
122
+ end
123
+
124
+ def resolve_output_path(diagram)
125
+ options[:output] || begin
126
+ base = File.basename(file_path, ".*")
127
+ dir = File.dirname(file_path)
128
+ safe_name = (diagram.name || "diagram").gsub(/[^\w.\-]+/, "_")
129
+ File.join(dir, "#{base}.#{safe_name}.#{format_ext}")
130
+ end
131
+ end
132
+ end
133
+ end
134
+ end
135
+ end
@@ -5,8 +5,8 @@ require "fileutils"
5
5
  module Ea
6
6
  module Cli
7
7
  module Command
8
- # `ea svg NAME FILE [--output=PATH] [--mode=ea|thin]`
9
- # `ea svg --all FILE [--output-dir=PATH] [--mode=ea|thin]`
8
+ # `ea svg NAME FILE [--output=PATH]`
9
+ # `ea svg --all FILE [--output-dir=PATH]`
10
10
  #
11
11
  # Renders one (NAME) or every (--all) diagram from a QEA or
12
12
  # XMI file into standalone SVG using the umldi content
@@ -14,8 +14,7 @@ module Ea
14
14
  # Ea::Model::Diagram.
15
15
  #
16
16
  # Default emitter is EaEmitter::Document which mirrors EA's SVG
17
- # structure (DOCTYPE, layered groups, EA-style markers). Pass
18
- # --mode=thin for the simpler Renderer output.
17
+ # structure (DOCTYPE, layered groups, EA-style markers).
19
18
  class Svg < Base
20
19
  def call
21
20
  return render_all if options[:all]
@@ -28,7 +27,8 @@ module Ea
28
27
  def render_one
29
28
  diagram = find_diagram
30
29
  svg = emitter_for_mode.new(diagram,
31
- model_index: document.index_by_id).render
30
+ model_index: document.index_by_id,
31
+ document: document).render
32
32
 
33
33
  output_path = resolve_output_path(diagram)
34
34
  FileUtils.mkdir_p(File.dirname(output_path))
@@ -42,7 +42,8 @@ module Ea
42
42
  FileUtils.mkdir_p(out_dir)
43
43
  paths = document.diagrams.map do |diagram|
44
44
  svg = emitter_for_mode.new(diagram,
45
- model_index: document.index_by_id).render
45
+ model_index: document.index_by_id,
46
+ document: document).render
46
47
  path = File.join(out_dir, "#{diagram.id}.svg")
47
48
  File.write(path, svg)
48
49
  path
@@ -58,15 +59,7 @@ module Ea
58
59
  end
59
60
 
60
61
  def emitter_for_mode
61
- case (options[:mode] || :ea).to_sym
62
- when :ea
63
- Ea::Svg::EaEmitter::Document
64
- when :thin
65
- Ea::Svg::Renderer
66
- else
67
- raise Ea::Cli::UnsupportedFormat,
68
- "Unknown svg mode: #{options[:mode]}"
69
- end
62
+ Ea::Svg::EaEmitter::Document
70
63
  end
71
64
 
72
65
  def document
@@ -12,7 +12,14 @@ module Ea
12
12
  autoload :Convert, "ea/cli/command/convert"
13
13
  autoload :Spa, "ea/cli/command/spa"
14
14
  autoload :Svg, "ea/cli/command/svg"
15
+ autoload :Render, "ea/cli/command/render"
16
+ autoload :Export, "ea/cli/command/export"
17
+ autoload :Mdg, "ea/cli/command/mdg"
15
18
  autoload :RepositoryBuilder, "ea/cli/command/repository_builder"
19
+ autoload :Diff, "ea/cli/command/diff"
20
+ autoload :Lint, "ea/cli/command/lint"
21
+ autoload :Query, "ea/cli/command/query"
22
+ autoload :Info, "ea/cli/command/info"
16
23
  end
17
24
  end
18
25
  end