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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +128 -1
- data/Rakefile +3 -0
- data/TODO.complete/01-t-xref-parsing.md +91 -0
- data/TODO.complete/02-per-label-geometry.md +50 -0
- data/TODO.complete/03-object-properties-constraints.md +57 -0
- data/TODO.complete/04-operation-params.md +37 -0
- data/TODO.complete/05-pdata-flag-matrix.md +52 -0
- data/TODO.complete/06-emf-image-rendering.md +34 -0
- data/TODO.complete/07-auxiliary-tables.md +47 -0
- data/TODO.complete/10-mdg-stereotype-registry.md +40 -0
- data/TODO.complete/11-gml-xsd-generation.md +42 -0
- data/TODO.complete/13-shapescript-interpreter.md +28 -0
- data/TODO.complete/20-cli-diff.md +46 -0
- data/TODO.complete/21-cli-render.md +26 -0
- data/TODO.complete/22-cli-export.md +29 -0
- data/TODO.complete/23-cli-mdg.md +23 -0
- data/TODO.complete/30-headerlines-ocp-refactor.md +72 -0
- data/TODO.complete/31-public-send-cleanup.md +61 -0
- data/TODO.complete/32-spec-coverage.md +33 -0
- data/TODO.complete/33-blocked-parity-gaps.md +41 -0
- data/TODO.complete/36-stereotype-icon-wiring.md +32 -0
- data/TODO.complete/37-cli-lint.md +32 -0
- data/TODO.complete/38-cli-query.md +26 -0
- data/TODO.complete/39-cli-info.md +23 -0
- data/TODO.complete/40-ocl-evaluator.md +31 -0
- data/TODO.complete/41-round-trip-spec.md +18 -0
- data/TODO.complete/42-html-diff-report.md +18 -0
- data/TODO.complete/43-json-schema-export.md +20 -0
- data/TODO.complete/44-remaining-qea-tables.md +40 -0
- data/TODO.complete/45-shapescript-extensions.md +25 -0
- data/TODO.complete/46-xsd-consolidation.md +20 -0
- data/TODO.complete/47-headerlines-legacy-removal.md +20 -0
- data/TODO.complete/51-remove-respond-to.md +25 -0
- data/TODO.complete/52-xsd-decouple-fixtures.md +23 -0
- data/TODO.complete/53-xmi-public-send-cleanup.md +26 -0
- data/TODO.complete/54-wire-stereotype-icon-renderer.md +20 -0
- data/TODO.complete/55-wire-shapescript.md +20 -0
- data/TODO.complete/56-wire-emf-renderer.md +27 -0
- data/TODO.complete/57-wire-ocl-evaluator.md +23 -0
- data/TODO.complete/58-diff-modifications.md +21 -0
- data/TODO.complete/59-delete-toy-xmi-export.md +30 -0
- data/TODO.complete/60-curate-json-export.md +20 -0
- data/TODO.complete/61-plantuml-relationships.md +22 -0
- data/TODO.complete/62-changelog.md +17 -0
- data/TODO.complete/63-dependabot-fix.md +18 -0
- data/TODO.complete/STATUS.md +85 -0
- data/TODO.diagrams/01-svg-measurement-harness.md +31 -0
- data/TODO.diagrams/02-polygon-over-rendering.md +29 -0
- data/TODO.diagrams/03-text-over-rendering.md +30 -0
- data/TODO.diagrams/04-rect-under-rendering.md +33 -0
- data/TODO.diagrams/05-canvas-dimension-parity.md +51 -0
- data/TODO.diagrams/06-group-layering-parity.md +39 -0
- data/TODO.diagrams/07-text-content-fidelity.md +65 -0
- data/TODO.diagrams/08-qea-direct-pipeline.md +46 -0
- data/TODO.diagrams/12-connector-labels.md +40 -0
- data/TODO.diagrams/12-per-entity-svg-layer-ordering.md +24 -0
- data/TODO.diagrams/13-marker-polygon-vs-path-dispatch.md +20 -0
- data/TODO.diagrams/13-per-text-type-font-sizes.md +33 -0
- data/TODO.diagrams/14-center-header-text.md +33 -0
- data/TODO.diagrams/14-filter-diagram-frame-elements.md +18 -0
- data/TODO.diagrams/15-deep-dead-code-audit.md +47 -0
- data/TODO.diagrams/15-per-element-font-from-style.md +24 -0
- data/TODO.diagrams/16-canvas-marker-extent.md +30 -0
- data/TODO.diagrams/16-document-remaining-parity-gaps.md +91 -0
- data/TODO.diagrams/17-italic-abstract-classes.md +28 -0
- data/TODO.diagrams/17-remaining-parity-gaps.md +90 -0
- data/TODO.diagrams/18-canvas-from-image-bounds.md +20 -0
- data/TODO.diagrams/18-property-lookup-index.md +42 -0
- data/TODO.diagrams/19-connector-sx-sy-routing.md +27 -0
- data/TODO.diagrams/19-replace-respond-to-with-is-a.md +31 -0
- data/TODO.diagrams/20-split-labels-emitter.md +56 -0
- data/TODO.diagrams/20-visibility-glyph-font-encoding.md +27 -0
- data/TODO.diagrams/21-aggregation-navigability-arrow.md +21 -0
- data/TODO.diagrams/21-auto-generated-legend-block.md +65 -0
- data/TODO.diagrams/22-ghost-element-discriminator.md +57 -0
- data/TODO.diagrams/22-style-based-path-grouping.md +28 -0
- data/TODO.diagrams/23-marker-polygon-deduplication.md +47 -0
- data/TODO.diagrams/23-multiplicity-label-positioning.md +29 -0
- data/TODO.diagrams/24-marker-anchor-structural.md +35 -0
- data/TODO.diagrams/24-track-marker-anchors-structurally.md +66 -0
- data/TODO.diagrams/24-truncate-properties-to-fit-box.md +24 -0
- data/TODO.diagrams/26-phantom-general-parent-rendering.md +59 -0
- data/TODO.diagrams/27-path-grouping-mode-detection.md +43 -0
- data/TODO.diagrams/28-architecture-cleanup-batch.md +47 -0
- data/TODO.diagrams/30-decompose-elements-groups-for.md +52 -0
- data/TODO.diagrams/32-examples-coverage-batch.md +78 -0
- data/TODO.diagrams/36-instance-specification-model.md +42 -0
- data/TODO.diagrams/37-element-icon-decorations.md +41 -0
- data/TODO.diagrams/38-html-note-and-receptions.md +32 -0
- data/TODO.diagrams/39-property-stereotype-discriminator.md +40 -0
- data/TODO.diagrams/40-standalone-1-discriminator.md +38 -0
- data/TODO.diagrams/41-xmi-to-svg-pipeline.md +113 -0
- data/TODO.diagrams/42-close-all-parity-deltas.md +69 -0
- data/TODO.diagrams/43-marker-deduplication-strategy.md +54 -0
- data/TODO.diagrams/44-element-icon-decorations.md +34 -0
- data/TODO.diagrams/45-phantom-parent-class-boxes.md +40 -0
- data/TODO.diagrams/46-user-drawn-legend-swatches.md +44 -0
- data/TODO.diagrams/47-attribute-line-fidelity.md +72 -0
- data/TODO.diagrams/48-spec-coverage-critical-emitter-components.md +45 -0
- data/TODO.diagrams/49-spec-coverage-orchestrators.md +25 -0
- data/TODO.diagrams/50-examples-parity.md +85 -0
- data/TODO.diagrams/51-property-oy-gap-and-remaining-gaps.md +48 -0
- data/TODO.diagrams/52-marker-registration-architecture.md +89 -0
- data/TODO.diagrams/53-remaining-example-gaps.md +86 -0
- data/TODO.diagrams/54-display-name-nested-classes.md +40 -0
- data/TODO.diagrams/55-visibility-icon-discriminator.md +58 -0
- data/TODO.diagrams/56-package-contents-rendering.md +148 -0
- data/TODO.diagrams/57-instance-specification-model.md +100 -0
- data/TODO.diagrams/58-domain-model-note-text.md +67 -0
- data/TODO.diagrams/59-classes-arrow-discriminator.md +57 -0
- data/TODO.diagrams/60-testschema-association-marker.md +40 -0
- data/TODO.diagrams/61-legend-block-rendering.md +55 -0
- data/TODO.diagrams/61-plateau-parity-gaps.md +59 -0
- data/TODO.diagrams/62-ghost-element-rendering.md +56 -0
- data/TODO.diagrams/63-qualified-name-wrap.md +36 -0
- data/TODO.diagrams/64-property-stereotype-labels.md +22 -0
- data/TODO.diagrams/65-path-coordinate-frame.md +62 -0
- data/TODO.diagrams/67-path-coordinate-frame.md +62 -0
- data/TODO.diagrams/68-inherited-attributes.md +65 -0
- data/TODO.diagrams/69-package-anchor-conditional.md +29 -0
- data/TODO.diagrams/70-mdg-technology-support.md +68 -0
- data/TODO.diagrams/71-off-canvas-parent-ghost.md +45 -0
- data/TODO.diagrams/72-basic-attr-divider-paths.md +39 -0
- data/TODO.diagrams/73-plateau-polygon-gap.md +69 -0
- data/TODO.diagrams/74-plateau-rect-gap.md +22 -0
- data/TODO.diagrams/75-plateau-text-gap.md +39 -0
- data/TODO.diagrams/76-basic-poly-path-gaps.md +41 -0
- data/TODO.diagrams/77-basic-text-overrender.md +40 -0
- data/TODO.diagrams/78-headerlines-ocp-refactor.md +65 -0
- data/TODO.diagrams/79-architecture-backlog.md +65 -0
- data/TODO.diagrams/80-basic-triangle-polygons.md +51 -0
- data/TODO.diagrams/81-plateau-path-overrender.md +53 -0
- data/TODO.diagrams/82-appearance-canvas-offset.md +54 -0
- data/TODO.diagrams/83-3d-diagram-subtitle.md +58 -0
- data/TODO.diagrams/84-canvas-offset-mismatches.md +61 -0
- data/TODO.diagrams/85-phantom-property-overrender.md +95 -0
- data/TODO.diagrams/86-foreign-package-rule.md +62 -0
- data/TODO.diagrams/87-internal-tech-encryption.md +80 -0
- data/TODO.diagrams/EXAMPLES_STATUS.md +88 -0
- data/TODO.diagrams/README.md +69 -0
- data/TODO.diagrams/STATUS.md +73 -0
- data/TODO.fixup/01-default-grouped-paths.md +34 -0
- data/TODO.fixup/02-marker-consolidation-per-connector.md +20 -0
- data/TODO.fixup/03-diagram-font-inference.md +28 -0
- data/TODO.fixup/04-extract-bounds-calculator.md +25 -0
- data/TODO.fixup/05-marker-registry-ocp.md +32 -0
- data/TODO.fixup/06-connector-path-bend-routing.md +28 -0
- data/TODO.fixup/07-edge-attachment-formula.md +22 -0
- data/TODO.fixup/08-visual-diff-harness.md +28 -0
- data/TODO.fixup/09-extract-element-compartments.md +34 -0
- data/TODO.fixup/10-canvas-width-overshoot-fix.md +20 -0
- data/TODO.fixup/11-layer-sequencer-extraction.md +18 -0
- data/TODO.fixup/12-path-style-harmony.md +23 -0
- data/TODO.fixup/13-datatype-stereotype-fallback.md +28 -0
- data/TODO.fixup/14-ea-exe-reverse-engineering-notes.md +56 -0
- data/TODO.fixup/15-enumeration-literal-rendering.md +30 -0
- data/TODO.fixup/16-operation-compartment-rendering.md +42 -0
- data/TODO.fixup/17-path-count-calibration.md +27 -0
- data/TODO.fixup/18-polygon-count-calibration.md +32 -0
- data/TODO.fixup/19-rect-count-undershoot-investigation.md +40 -0
- data/TODO.fixup/20-stereotype-color-from-classifier.md +18 -0
- data/TODO.fixup/21-visibility-filter-for-properties.md +24 -0
- data/TODO.fixup/22-multiplicity-display-rule-calibration.md +25 -0
- data/TODO.fixup/23-diagram-frame-title-element.md +31 -0
- data/TODO.fixup/24-note-element-rendering.md +23 -0
- data/TODO.fixup/25-ea-exe-disassembly-findings.md +177 -0
- data/TODO.fixup/26-svg-renderer-architecture.md +78 -0
- data/TODO.fixup/27-svg-element-emitters-disassembly.md +135 -0
- data/TODO.fixup/28-geometry-parser-identification.md +57 -0
- data/TODO.fixup/29-qea-svg-xmi-triple-comparison.md +185 -0
- data/TODO.fixup/30-theme-system-stub.md +46 -0
- data/TODO.fixup/31-theme-value-object-registry.md +17 -0
- data/TODO.fixup/32-styleex-on-diagram-model.md +22 -0
- data/TODO.fixup/33-text-encoding-decimals-rotation.md +29 -0
- data/TODO.fixup/34-per-type-fill-via-theme.md +18 -0
- data/TODO.fixup/35-stroke-width-per-theme.md +7 -0
- data/TODO.fixup/36-qea-rect-coord-normalization.md +24 -0
- data/TODO.fixup/37-package-shape-rendering.md +22 -0
- data/TODO.fixup/38-note-element-rendering.md +15 -0
- data/TODO.fixup/39-styleex-flag-honoring.md +25 -0
- data/TODO.fixup/40-connector-dashed-lines.md +15 -0
- data/TODO.fixup/41-diagram-frame-showborder-detection.md +23 -0
- data/TODO.fixup/42-textrenderer-centralization.md +10 -0
- data/TODO.fixup/43-colorresolver-unification.md +24 -0
- data/TODO.fixup/44-theme-aware-textrenderer.md +17 -0
- data/TODO.fixup/45-theme-aware-fontresolver.md +22 -0
- data/TODO.fixup/46-style-parameterized-by-theme.md +21 -0
- data/TODO.fixup/47-canvas-frame-inset.md +19 -0
- data/TODO.fixup/48-background-rect-format.md +15 -0
- data/TODO.fixup/49-all-samples-integration-test.md +17 -0
- data/TODO.fixup/50-svg-emitter-architecture-docs.md +33 -0
- data/TODO.fixup/51-promote-theme-to-ea-namespace.md +28 -0
- data/TODO.fixup/52-theme-definition-integrated-fills.md +26 -0
- data/TODO.fixup/53-theme-registry-yaml-loading.md +50 -0
- data/TODO.fixup/54-diagram-theme-api.md +50 -0
- data/TODO.fixup/55-update-eaemitter-to-ea-theme.md +23 -0
- data/TODO.fixup/56-theme-yaml-files.md +65 -0
- data/TODO.fixup/57-theme-specs-and-integration.md +27 -0
- data/TODO.fixup/58-ea-entry-point-theme-autoload.md +20 -0
- data/TODO.fixup/59-thread-theme-through-all-renderers.md +29 -0
- data/TODO.fixup/60-cli-theme-option.md +22 -0
- data/TODO.fixup/61-theme-validation.md +28 -0
- data/TODO.fixup/62-theme-builder-dsl.md +31 -0
- data/TODO.fixup/63-theme-integration-rendering-spec.md +24 -0
- data/TODO.fixup/64-theme-writeback-styleex.md +21 -0
- data/TODO.fixup/65-remove-dead-eaemitter-theme-files.md +30 -0
- data/TODO.fixup/66-styleex-writeback.md +22 -0
- data/TODO.fixup/67-delete-dead-code.md +28 -0
- data/TODO.fixup/68-figure-parity-status.md +82 -0
- data/TODO.fixup/69-package-polygon-rendering.md +54 -0
- data/TODO.fixup/70-tagged-values-compartment.md +39 -0
- data/TODO.fixup/71-auto-detect-theme-from-xmi.md +37 -0
- data/TODO.fixup/72-sample-exports-as-regression-specs.md +37 -0
- data/TODO.fixup/73-delete-dead-transformations.md +14 -0
- data/TODO.fixup/74-delete-dead-diagram-renderers.md +18 -0
- data/TODO.fixup/75-visibility-legend-icons.md +23 -0
- data/TODO.fixup/76-plateau-text-undershoot.md +27 -0
- data/TODO.fixup/77-canvas-frame-margins.md +28 -0
- data/TODO.fixup/78-note-element-rendering.md +30 -0
- data/TODO.fixup/79-operation-compartment-rendering.md +27 -0
- data/TODO.fixup/80-tagged-value-stereotype-visibility.md +37 -0
- data/TODO.fixup/81-figure-parity-current-state.md +63 -0
- data/config/qea_schema.yml +356 -0
- data/config/themes/119.yml +98 -0
- data/config/themes/default.yml +14 -0
- data/examples/exports/20251010_current_plateau_v5/UML_EA.DTD +6856 -0
- data/examples/exports/20251010_current_plateau_v5/model.xml +96709 -0
- data/examples/exports/ArcGISWorkspace_template/UML_EA.DTD +6856 -0
- data/examples/exports/ArcGISWorkspace_template/model.xml +1427 -0
- data/examples/exports/UmlModel_template/UML_EA.DTD +6856 -0
- data/examples/exports/UmlModel_template/model.xml +23 -0
- data/examples/exports/basic/UML_EA.DTD +6856 -0
- data/examples/exports/basic/model.xml +8039 -0
- data/examples/exports/simple/UML_EA.DTD +6856 -0
- data/examples/exports/simple/model.xml +585 -0
- data/examples/exports/simple_example/UML_EA.DTD +6856 -0
- data/examples/exports/simple_example/model.xml +23 -0
- data/examples/exports/test/UML_EA.DTD +6856 -0
- data/examples/exports/test/model.xml +1638 -0
- data/examples/qea/basic.qea +0 -0
- data/frontend/README.md +51 -0
- data/frontend/dist/app.iife.js +24 -0
- data/frontend/dist/style.css +1 -0
- data/frontend/index.html +26 -0
- data/frontend/package-lock.json +2359 -0
- data/frontend/package.json +26 -0
- data/frontend/src/App.vue +59 -0
- data/frontend/src/app.ts +8 -0
- data/frontend/src/components/AppHeader.vue +127 -0
- data/frontend/src/components/AppSidebar.vue +119 -0
- data/frontend/src/components/ClassDetails.vue +247 -0
- data/frontend/src/components/DiagramView.vue +79 -0
- data/frontend/src/components/PackageDetails.vue +92 -0
- data/frontend/src/components/PackageTreeNode.vue +64 -0
- data/frontend/src/components/SearchResults.vue +48 -0
- data/frontend/src/components/WelcomeView.vue +87 -0
- data/frontend/src/shims-vue.d.ts +5 -0
- data/frontend/src/stores/dataStore.ts +79 -0
- data/frontend/src/stores/uiStore.ts +167 -0
- data/frontend/src/styles/main.css +1566 -0
- data/frontend/src/types.ts +221 -0
- data/frontend/tests/e2e/__screenshots__/new-dark-mode.png +0 -0
- data/frontend/tests/e2e/__screenshots__/new-package-details.png +0 -0
- data/frontend/tests/e2e/__screenshots__/new-search-modal.png +0 -0
- data/frontend/tests/e2e/__screenshots__/new-sidebar-collapsed.png +0 -0
- data/frontend/tests/e2e/__screenshots__/new-welcome.png +0 -0
- data/frontend/tests/e2e/render.spec.ts +188 -0
- data/frontend/tsconfig.json +20 -0
- data/frontend/vite.config.ts +26 -0
- data/frontend/vitest.config.ts +8 -0
- data/lib/ea/cli/app.rb +57 -2
- data/lib/ea/cli/command/diagrams.rb +37 -28
- data/lib/ea/cli/command/diff.rb +46 -0
- data/lib/ea/cli/command/export.rb +101 -0
- data/lib/ea/cli/command/info.rb +75 -0
- data/lib/ea/cli/command/lint.rb +48 -0
- data/lib/ea/cli/command/mdg.rb +98 -0
- data/lib/ea/cli/command/query.rb +34 -0
- data/lib/ea/cli/command/render.rb +135 -0
- data/lib/ea/cli/command/svg.rb +8 -15
- data/lib/ea/cli/command.rb +7 -0
- data/lib/ea/diagram/display_config.rb +184 -0
- data/lib/ea/diagram.rb +4 -41
- data/lib/ea/diff/change.rb +30 -0
- data/lib/ea/diff/comparator.rb +109 -0
- data/lib/ea/diff/html_reporter.rb +91 -0
- data/lib/ea/diff.rb +15 -0
- data/lib/ea/export/json/generator.rb +118 -0
- data/lib/ea/export/json.rb +12 -0
- data/lib/ea/export/json_schema/generator.rb +77 -0
- data/lib/ea/export/json_schema.rb +12 -0
- data/lib/ea/export/plantuml/generator.rb +140 -0
- data/lib/ea/export/plantuml.rb +12 -0
- data/lib/ea/export/xsd/class_mapping.rb +65 -0
- data/lib/ea/export/xsd/generator.rb +137 -0
- data/lib/ea/export/xsd/namespace_registry.rb +82 -0
- data/lib/ea/export/xsd.rb +19 -0
- data/lib/ea/export.rb +13 -0
- data/lib/ea/image/emf_renderer.rb +42 -0
- data/lib/ea/image.rb +12 -0
- data/lib/ea/lint/engine.rb +30 -0
- data/lib/ea/lint/lint_rule.rb +38 -0
- data/lib/ea/lint/offense.rb +18 -0
- data/lib/ea/lint/rules/cyclic_generalization.rb +62 -0
- data/lib/ea/lint/rules/duplicate_name.rb +28 -0
- data/lib/ea/lint/rules/missing_stereotype.rb +40 -0
- data/lib/ea/lint/rules/naming_convention.rb +44 -0
- data/lib/ea/lint/rules/orphan_element.rb +28 -0
- data/lib/ea/lint/rules.rb +14 -0
- data/lib/ea/lint.rb +13 -0
- data/lib/ea/mdg/document.rb +120 -0
- data/lib/ea/mdg/loader.rb +118 -0
- data/lib/ea/mdg/registry.rb +98 -0
- data/lib/ea/mdg/stereotype_alias_registry.rb +77 -0
- data/lib/ea/mdg/xml/applies_to.rb +18 -0
- data/lib/ea/mdg/xml/apply.rb +18 -0
- data/lib/ea/mdg/xml/content.rb +18 -0
- data/lib/ea/mdg/xml/documentation.rb +24 -0
- data/lib/ea/mdg/xml/stereotype.rb +28 -0
- data/lib/ea/mdg/xml/stereotypes.rb +18 -0
- data/lib/ea/mdg/xml/tag.rb +28 -0
- data/lib/ea/mdg/xml/tagged_values.rb +18 -0
- data/lib/ea/mdg/xml/technology.rb +28 -0
- data/lib/ea/mdg/xml/uml_profile.rb +22 -0
- data/lib/ea/mdg/xml/uml_profiles.rb +18 -0
- data/lib/ea/mdg/xml.rb +24 -0
- data/lib/ea/mdg.rb +25 -0
- data/lib/ea/model/classifier.rb +4 -0
- data/lib/ea/model/constraint.rb +24 -0
- data/lib/ea/model/diagram.rb +85 -0
- data/lib/ea/model/diagram_connector.rb +34 -0
- data/lib/ea/model/diagram_element.rb +16 -0
- data/lib/ea/model/document.rb +47 -2
- data/lib/ea/model/ghost_label.rb +32 -0
- data/lib/ea/model/instance_specification.rb +34 -0
- data/lib/ea/model/legend.rb +43 -0
- data/lib/ea/model/legend_item.rb +26 -0
- data/lib/ea/model/note.rb +28 -0
- data/lib/ea/model/operation.rb +2 -0
- data/lib/ea/model/property.rb +2 -0
- data/lib/ea/model/relationship.rb +2 -0
- data/lib/ea/model/signal.rb +14 -0
- data/lib/ea/model/slot.rb +19 -0
- data/lib/ea/model.rb +8 -0
- data/lib/ea/ocl/evaluator.rb +94 -0
- data/lib/ea/ocl/nodes.rb +30 -0
- data/lib/ea/ocl/parser.rb +133 -0
- data/lib/ea/ocl/unsupported_error.rb +7 -0
- data/lib/ea/ocl.rb +13 -0
- data/lib/ea/qea/factory/document_builder.rb +24 -10
- data/lib/ea/qea/factory/generalization_builder.rb +9 -11
- data/lib/ea/qea/infrastructure/table_reader.rb +9 -0
- data/lib/ea/qea/models/ea_author.rb +35 -0
- data/lib/ea/qea/models/ea_glossary.rb +34 -0
- data/lib/ea/qea/models/ea_image.rb +53 -0
- data/lib/ea/qea/models/ea_implement.rb +32 -0
- data/lib/ea/qea/models/ea_list.rb +42 -0
- data/lib/ea/qea/models/ea_object_effort.rb +34 -0
- data/lib/ea/qea/models/ea_object_problem.rb +37 -0
- data/lib/ea/qea/models/ea_object_require.rb +34 -0
- data/lib/ea/qea/models/ea_object_resource.rb +34 -0
- data/lib/ea/qea/models/ea_object_risk.rb +34 -0
- data/lib/ea/qea/models/ea_object_scenario.rb +34 -0
- data/lib/ea/qea/models/ea_object_test.rb +35 -0
- data/lib/ea/qea/models/ea_object_trx.rb +34 -0
- data/lib/ea/qea/models/ea_operation.rb +7 -0
- data/lib/ea/qea/models/ea_palette.rb +30 -0
- data/lib/ea/qea/models/ea_palette_item.rb +36 -0
- data/lib/ea/qea/models/ea_phase.rb +40 -0
- data/lib/ea/qea/models/ea_role_constraint.rb +32 -0
- data/lib/ea/qea/models/ea_secrypt.rb +34 -0
- data/lib/ea/qea/models/ea_version.rb +39 -0
- data/lib/ea/qea/models/ea_xref.rb +11 -1
- data/lib/ea/qea/models.rb +19 -0
- data/lib/ea/qea/services/database_loader.rb +22 -1
- data/lib/ea/qea/validation/database/ocl_constraint_validator.rb +65 -0
- data/lib/ea/qea/validation/database.rb +2 -0
- data/lib/ea/qea/validation/validation_engine.rb +2 -0
- data/lib/ea/qea/validation.rb +2 -0
- data/lib/ea/query/builder.rb +127 -0
- data/lib/ea/query.rb +9 -0
- data/lib/ea/render/image_converter.rb +101 -0
- data/lib/ea/render.rb +10 -0
- data/lib/ea/shapescript/parser.rb +208 -0
- data/lib/ea/shapescript/renderer.rb +74 -0
- data/lib/ea/shapescript/shape.rb +34 -0
- data/lib/ea/shapescript.rb +24 -0
- data/lib/ea/sources/qea/adapter.rb +22 -5
- data/lib/ea/sources/qea/classifier_builder.rb +184 -7
- data/lib/ea/sources/qea/diagram_builder.rb +352 -24
- data/lib/ea/sources/qea/id_normalizer.rb +16 -1
- data/lib/ea/sources/qea/instance_builder.rb +113 -0
- data/lib/ea/sources/qea/legend_builder.rb +137 -0
- data/lib/ea/sources/qea/note_builder.rb +58 -0
- data/lib/ea/sources/qea/object_classifier_map.rb +6 -1
- data/lib/ea/sources/qea/operation_builder.rb +1 -0
- data/lib/ea/sources/qea/package_builder.rb +16 -0
- data/lib/ea/sources/qea/relationship_builder.rb +21 -5
- data/lib/ea/sources/qea/tagged_value_builder.rb +28 -9
- data/lib/ea/sources/qea/xref/legend_definition.rb +35 -0
- data/lib/ea/sources/qea/xref/parser.rb +150 -0
- data/lib/ea/sources/qea/xref/property_definition.rb +29 -0
- data/lib/ea/sources/qea/xref/record.rb +41 -0
- data/lib/ea/sources/qea/xref/stereotype_application.rb +37 -0
- data/lib/ea/sources/qea/xref.rb +27 -0
- data/lib/ea/sources/qea.rb +4 -0
- data/lib/ea/sources/xmi/adapter.rb +80 -2
- data/lib/ea/sources/xmi/classifier_builder.rb +10 -1
- data/lib/ea/sources/xmi/diagram_builder.rb +95 -18
- data/lib/ea/sources/xmi/extension_geometry_parser.rb +19 -2
- data/lib/ea/sources/xmi/extension_style_parser.rb +15 -2
- data/lib/ea/sources/xmi/note_builder.rb +46 -0
- data/lib/ea/sources/xmi/property_builder.rb +9 -0
- data/lib/ea/sources/xmi/stereotype_builder.rb +54 -0
- data/lib/ea/sources/xmi/tag_builder.rb +45 -0
- data/lib/ea/sources/xmi/umldi_keyword_extractor.rb +87 -0
- data/lib/ea/sources/xmi.rb +4 -0
- data/lib/ea/spa/output/sharded_multi_file_strategy.rb +18 -3
- data/lib/ea/spa/output/single_file_strategy.rb +8 -2
- data/lib/ea/spa/output/strategy.rb +34 -0
- data/lib/ea/svg/connector_router.rb +134 -0
- data/lib/ea/svg/ea_emitter/background.rb +2 -3
- data/lib/ea/svg/ea_emitter/bounds_calculator.rb +142 -0
- data/lib/ea/svg/ea_emitter/canvas.rb +56 -33
- data/lib/ea/svg/ea_emitter/color_resolver.rb +56 -0
- data/lib/ea/svg/ea_emitter/compartment/attributes.rb +28 -0
- data/lib/ea/svg/ea_emitter/compartment/constraints.rb +30 -0
- data/lib/ea/svg/ea_emitter/compartment/enum_literals.rb +86 -0
- data/lib/ea/svg/ea_emitter/compartment/header.rb +32 -0
- data/lib/ea/svg/ea_emitter/compartment/header_divider.rb +57 -0
- data/lib/ea/svg/ea_emitter/compartment/instance_slots.rb +96 -0
- data/lib/ea/svg/ea_emitter/compartment/instance_underline.rb +67 -0
- data/lib/ea/svg/ea_emitter/compartment/note_body.rb +52 -0
- data/lib/ea/svg/ea_emitter/compartment/note_text.rb +102 -0
- data/lib/ea/svg/ea_emitter/compartment/operations.rb +38 -0
- data/lib/ea/svg/ea_emitter/compartment/package_contents.rb +72 -0
- data/lib/ea/svg/ea_emitter/compartment/package_from_parent.rb +136 -0
- data/lib/ea/svg/ea_emitter/compartment/shape.rb +82 -0
- data/lib/ea/svg/ea_emitter/compartment/stereotype_icon.rb +32 -0
- data/lib/ea/svg/ea_emitter/compartment/tagged_values.rb +30 -0
- data/lib/ea/svg/ea_emitter/compartment.rb +60 -0
- data/lib/ea/svg/ea_emitter/connectors.rb +46 -12
- data/lib/ea/svg/ea_emitter/diagram_frame.rb +143 -0
- data/lib/ea/svg/ea_emitter/document.rb +49 -25
- data/lib/ea/svg/ea_emitter/element/attribute_line_builder.rb +117 -0
- data/lib/ea/svg/ea_emitter/element/attribute_renderer.rb +119 -0
- data/lib/ea/svg/ea_emitter/element/bcol_decoder.rb +29 -0
- data/lib/ea/svg/ea_emitter/element/compartment_geometry.rb +113 -0
- data/lib/ea/svg/ea_emitter/element/constraint_renderer.rb +53 -0
- data/lib/ea/svg/ea_emitter/element/divider_renderer.rb +17 -0
- data/lib/ea/svg/ea_emitter/element/enumeration_literal_renderer.rb +34 -0
- data/lib/ea/svg/ea_emitter/element/filter.rb +44 -0
- data/lib/ea/svg/ea_emitter/element/hand_draw_shape_renderer.rb +77 -0
- data/lib/ea/svg/ea_emitter/element/header_line_pipeline.rb +43 -0
- data/lib/ea/svg/ea_emitter/element/header_line_provider/instance_spec.rb +27 -0
- data/lib/ea/svg/ea_emitter/element/header_line_provider/name.rb +76 -0
- data/lib/ea/svg/ea_emitter/element/header_line_provider/parent_ghost.rb +25 -0
- data/lib/ea/svg/ea_emitter/element/header_line_provider/stereotype_label.rb +68 -0
- data/lib/ea/svg/ea_emitter/element/header_line_provider.rb +19 -0
- data/lib/ea/svg/ea_emitter/element/header_lines.rb +27 -0
- data/lib/ea/svg/ea_emitter/element/header_renderer.rb +48 -0
- data/lib/ea/svg/ea_emitter/element/icon_renderer.rb +109 -0
- data/lib/ea/svg/ea_emitter/element/legend_renderer.rb +177 -0
- data/lib/ea/svg/ea_emitter/element/note_shape_renderer.rb +112 -0
- data/lib/ea/svg/ea_emitter/element/operation_renderer.rb +100 -0
- data/lib/ea/svg/ea_emitter/element/package_shape_renderer.rb +181 -0
- data/lib/ea/svg/ea_emitter/element/row_icon_renderer.rb +156 -0
- data/lib/ea/svg/ea_emitter/element/shape_renderer.rb +17 -0
- data/lib/ea/svg/ea_emitter/element/stereotype_icon_renderer.rb +119 -0
- data/lib/ea/svg/ea_emitter/element/tagged_value_renderer.rb +50 -0
- data/lib/ea/svg/ea_emitter/element/text_escape.rb +20 -0
- data/lib/ea/svg/ea_emitter/element.rb +37 -0
- data/lib/ea/svg/ea_emitter/elements.rb +283 -95
- data/lib/ea/svg/ea_emitter/font_resolver.rb +111 -0
- data/lib/ea/svg/ea_emitter/ghost_labels.rb +66 -0
- data/lib/ea/svg/ea_emitter/label/end_label.rb +266 -0
- data/lib/ea/svg/ea_emitter/label/midpoint_label.rb +101 -0
- data/lib/ea/svg/ea_emitter/label/registry.rb +50 -0
- data/lib/ea/svg/ea_emitter/label.rb +23 -0
- data/lib/ea/svg/ea_emitter/labels.rb +93 -27
- data/lib/ea/svg/ea_emitter/layer.rb +20 -0
- data/lib/ea/svg/ea_emitter/layer_sequencer.rb +93 -0
- data/lib/ea/svg/ea_emitter/marker/arrow_path.rb +52 -0
- data/lib/ea/svg/ea_emitter/marker/diamond.rb +57 -0
- data/lib/ea/svg/ea_emitter/marker/kind.rb +35 -0
- data/lib/ea/svg/ea_emitter/marker/open_triangle.rb +27 -0
- data/lib/ea/svg/ea_emitter/marker/package_import.rb +39 -0
- data/lib/ea/svg/ea_emitter/marker/plus.rb +40 -0
- data/lib/ea/svg/ea_emitter/marker/registry.rb +42 -0
- data/lib/ea/svg/ea_emitter/marker.rb +37 -0
- data/lib/ea/svg/ea_emitter/markers.rb +351 -64
- data/lib/ea/svg/ea_emitter/render_context.rb +52 -0
- data/lib/ea/svg/ea_emitter/style.rb +15 -0
- data/lib/ea/svg/ea_emitter/text_renderer.rb +92 -0
- data/lib/ea/svg/ea_emitter.rb +33 -11
- data/lib/ea/svg/parity/checker.rb +105 -0
- data/lib/ea/svg/parity/source.rb +59 -0
- data/lib/ea/svg/parity/suite.rb +113 -0
- data/lib/ea/svg/parity.rb +14 -0
- data/lib/ea/svg.rb +2 -15
- data/lib/ea/theme/definition.rb +176 -0
- data/lib/ea/theme/loader.rb +125 -0
- data/lib/ea/theme/registry.rb +96 -0
- data/lib/ea/theme.rb +37 -0
- data/lib/ea/transformations.rb +5 -88
- data/lib/ea/validation/xmi_parity.rb +80 -0
- data/lib/ea/validation.rb +12 -0
- data/lib/ea/version.rb +4 -1
- data/lib/ea.rb +15 -4
- data/lib/tasks/svg_bench.rake +87 -0
- data/lutaml-uml-0.5.1.gem +0 -0
- data/reference-docs/enterprise-architect-appearance-dialogs/appearance-1-diagram-1-themes-list.png +0 -0
- data/reference-docs/enterprise-architect-appearance-dialogs/appearance-1-diagram-1-themes.png +0 -0
- data/reference-docs/enterprise-architect-appearance-dialogs/appearance-1-diagram-2-gradients.png +0 -0
- data/reference-docs/enterprise-architect-appearance-dialogs/appearance-1-diagram-3-colors.png +0 -0
- data/reference-docs/enterprise-architect-appearance-dialogs/appearance-1-diagram-4-appearance-fonts.png +0 -0
- data/reference-docs/enterprise-architect-appearance-dialogs/appearance-1-diagram-4-appearance.png +0 -0
- data/reference-docs/enterprise-architect-appearance-dialogs/appearance-1-diagram-5-behavior.png +0 -0
- data/reference-docs/enterprise-architect-appearance-dialogs/appearance-1-diagram-6-sequence.png +0 -0
- data/reference-docs/enterprise-architect-appearance-dialogs/appearance-1-diagram.png +0 -0
- data/reference-docs/enterprise-architect-appearance-dialogs/appearance-2-objects.png +0 -0
- data/reference-docs/enterprise-architect-appearance-dialogs/appearance-3-links.png +0 -0
- metadata +464 -26
- data/lib/ea/diagram/configuration.rb +0 -379
- data/lib/ea/diagram/element_renderers/base_renderer.rb +0 -77
- data/lib/ea/diagram/element_renderers/class_renderer.rb +0 -323
- data/lib/ea/diagram/element_renderers/connector_renderer.rb +0 -41
- data/lib/ea/diagram/element_renderers/package_renderer.rb +0 -61
- data/lib/ea/diagram/element_renderers.rb +0 -43
- data/lib/ea/diagram/extractor.rb +0 -566
- data/lib/ea/diagram/layout_engine.rb +0 -170
- data/lib/ea/diagram/path_builder.rb +0 -202
- data/lib/ea/diagram/style_parser.rb +0 -42
- data/lib/ea/diagram/style_resolver.rb +0 -291
- data/lib/ea/diagram/svg_renderer.rb +0 -274
- data/lib/ea/diagram/util.rb +0 -73
- data/lib/ea/svg/bounds_calculator.rb +0 -74
- data/lib/ea/svg/connector_path.rb +0 -138
- data/lib/ea/svg/element_box.rb +0 -256
- data/lib/ea/svg/renderer.rb +0 -77
- data/lib/ea/svg/style_resolver.rb +0 -72
- data/lib/ea/transformations/configuration.rb +0 -333
- data/lib/ea/transformations/format_registry.rb +0 -366
- data/lib/ea/transformations/parsers/base_parser.rb +0 -482
- data/lib/ea/transformations/parsers/qea_parser.rb +0 -401
- data/lib/ea/transformations/parsers/xmi_parser.rb +0 -243
- data/lib/ea/transformations/transformation_engine.rb +0 -390
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
# 19 - Connector Source/Target Edge Routing from SX/SY/EX/EY
|
|
2
|
+
|
|
3
|
+
## Status: DONE (2026-07-23)
|
|
4
|
+
|
|
5
|
+
## Outcome
|
|
6
|
+
|
|
7
|
+
`ConnectorRouter` now accepts `source_delta` and `target_delta`
|
|
8
|
+
(defaulting to [0,0]). `DiagramBuilder#compute_waypoints` passes
|
|
9
|
+
SX/SY/EX/EY from the parsed geometry to the router, which applies
|
|
10
|
+
them as deltas to the edge-attachment point.
|
|
11
|
+
|
|
12
|
+
`ExtensionGeometryParser.Placement` already exposed `sx`, `sy`,
|
|
13
|
+
`ex`, `ey` — just plumbs them through.
|
|
14
|
+
|
|
15
|
+
## Remaining diff
|
|
16
|
+
|
|
17
|
+
Waterway connectors still show ~20 px y-offset vs EA reference
|
|
18
|
+
(643 vs 663). The SX/SY deltas are small (-21 to 150) and don't
|
|
19
|
+
account for this gap. EA likely uses a different attachment
|
|
20
|
+
formula (not strict edge center) — possibly offset by half
|
|
21
|
+
font-height or other rendering consideration. Deferred to deeper
|
|
22
|
+
reverse-engineering.
|
|
23
|
+
|
|
24
|
+
## Files changed
|
|
25
|
+
|
|
26
|
+
- `lib/ea/svg/connector_router.rb` — source_delta / target_delta support
|
|
27
|
+
- `lib/ea/sources/xmi/diagram_builder.rb` — passes deltas to router
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
# TODO-D 19: Replace respond_to? with is_a? (encapsulation)
|
|
2
|
+
|
|
3
|
+
## Problem
|
|
4
|
+
|
|
5
|
+
`Ea::Svg::EaEmitter::Labels#connector_stereotype` uses
|
|
6
|
+
`respond_to?(:stereotype)`:
|
|
7
|
+
|
|
8
|
+
```ruby
|
|
9
|
+
def connector_stereotype(connector)
|
|
10
|
+
rel = model_index ? model_index[connector.relationship_ref] : nil
|
|
11
|
+
stereotype = rel&.respond_to?(:stereotype) ? rel.stereotype : nil
|
|
12
|
+
return nil if stereotype.nil? || stereotype.to_s.empty?
|
|
13
|
+
"«#{stereotype}»"
|
|
14
|
+
end
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
`respond_to?` is duck-typing that hides type errors until runtime.
|
|
18
|
+
Per the project rules: use `is_a?` for type checks, or design the
|
|
19
|
+
type hierarchy so the check isn't needed.
|
|
20
|
+
|
|
21
|
+
## Fix
|
|
22
|
+
|
|
23
|
+
`Ea::Model::Relationship` (base class) now declares `stereotype` as
|
|
24
|
+
an attribute. All concrete relationship subclasses inherit it. So
|
|
25
|
+
the check should be `rel.is_a?(Ea::Model::Relationship)`.
|
|
26
|
+
|
|
27
|
+
## Acceptance
|
|
28
|
+
|
|
29
|
+
- No `respond_to?` calls in `lib/`.
|
|
30
|
+
- Connector stereotype labels still render correctly.
|
|
31
|
+
- Specs pass.
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
# TODO-D 20: Split Labels emitter into MECE collaborators
|
|
2
|
+
|
|
3
|
+
## Problem
|
|
4
|
+
|
|
5
|
+
`Ea::Svg::EaEmitter::Labels` currently handles three distinct
|
|
6
|
+
responsibilities:
|
|
7
|
+
|
|
8
|
+
1. Connector midpoint stereotype labels (e.g. «import»).
|
|
9
|
+
2. End-label role + «property» + multiplicity rendering.
|
|
10
|
+
3. Geometry box parsing and position resolution.
|
|
11
|
+
|
|
12
|
+
These change for different reasons:
|
|
13
|
+
|
|
14
|
+
- Midpoint rendering changes when EA's connector stereotype
|
|
15
|
+
conventions change.
|
|
16
|
+
- End-label rendering changes when role-name / multiplicity
|
|
17
|
+
rules change.
|
|
18
|
+
- Box parsing changes when the QEA geometry format changes.
|
|
19
|
+
|
|
20
|
+
MECE violation: the three concerns overlap inside one class. OCP
|
|
21
|
+
violation: adding a new label kind (e.g. connector name above the
|
|
22
|
+
midpoint) requires editing Labels rather than registering a new
|
|
23
|
+
collaborator.
|
|
24
|
+
|
|
25
|
+
## Fix
|
|
26
|
+
|
|
27
|
+
Introduce a small LabelRenderer registry:
|
|
28
|
+
|
|
29
|
+
```
|
|
30
|
+
Ea::Svg::EaEmitter::Label
|
|
31
|
+
├─ EndLabel (role + «property» + mult at LLT/LRT boxes)
|
|
32
|
+
├─ MidpointLabel (stereotype at path midpoint)
|
|
33
|
+
└─ Registry (dispatch by relationship kind / connector flag)
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
`Labels#texts_for` becomes:
|
|
37
|
+
|
|
38
|
+
```ruby
|
|
39
|
+
def texts_for(connector)
|
|
40
|
+
points = waypoint_pairs(connector)
|
|
41
|
+
return [] if points.size < 2
|
|
42
|
+
|
|
43
|
+
Label::Registry.for(connector, model_index: model_index)
|
|
44
|
+
.flat_map { |r| r.texts(connector, points) }
|
|
45
|
+
end
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
Each renderer is independently testable. New label kinds are added
|
|
49
|
+
by registering, not by editing Labels (OCP).
|
|
50
|
+
|
|
51
|
+
## Acceptance
|
|
52
|
+
|
|
53
|
+
- Three discrete classes; each has its own spec.
|
|
54
|
+
- No behavior change (parity text overlap ≥ 87%).
|
|
55
|
+
- Existing labels spec still passes.
|
|
56
|
+
- New midpoint label spec covers the «import» path.
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
# 20 - Visibility Glyph Font (Plus Sign in Monospace)
|
|
2
|
+
|
|
3
|
+
## Status: DONE (2026-07-23)
|
|
4
|
+
|
|
5
|
+
## Outcome
|
|
6
|
+
|
|
7
|
+
Three text-encoding fixes:
|
|
8
|
+
1. Visibility marker now emits as `+ ` (with trailing space) —
|
|
9
|
+
matches EA's text content exactly.
|
|
10
|
+
2. Namespace separator in type names converted to `::` (UML
|
|
11
|
+
standard) — `gml:CodeType` → `gml::CodeType`.
|
|
12
|
+
3. Abstract class names no longer get double underscore when the
|
|
13
|
+
source name already starts with `_` (e.g. `_Feature` stays
|
|
14
|
+
`_Feature`, not `__Feature`).
|
|
15
|
+
|
|
16
|
+
## Remaining gap
|
|
17
|
+
|
|
18
|
+
Text counts overshoot ref on diagrams where the source classifier
|
|
19
|
+
has more `ownedAttribute` entries than EA displays. EA truncates the
|
|
20
|
+
visible attribute list (likely a per-diagram display filter or box-
|
|
21
|
+
size fit), while we render every property. This is a content-
|
|
22
|
+
filtering concern, not an encoding concern — deferred.
|
|
23
|
+
|
|
24
|
+
## Files changed
|
|
25
|
+
|
|
26
|
+
- `lib/ea/svg/ea_emitter/elements.rb` — `abstract_name`,
|
|
27
|
+
`namespace_double_colon`, `split_visibility` updates
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
# 21 - Aggregation Navigability Arrow at Part End
|
|
2
|
+
|
|
3
|
+
## Status: DONE (2026-07-23)
|
|
4
|
+
|
|
5
|
+
## Outcome
|
|
6
|
+
|
|
7
|
+
`Markers#marker_specs` for Aggregation/Composition now returns TWO
|
|
8
|
+
Specs:
|
|
9
|
+
- Diamond polygon at whole end
|
|
10
|
+
- Arrow path at part end
|
|
11
|
+
|
|
12
|
+
Document interleaves line + diamond + arrow per aggregation
|
|
13
|
+
connector (via `count_for` API + `pair_per_connector`).
|
|
14
|
+
|
|
15
|
+
Waterway path count: 15 → 21 (ref=20, within ±1).
|
|
16
|
+
Bridge polygon+path counts now within ±2 of ref.
|
|
17
|
+
|
|
18
|
+
## Files changed
|
|
19
|
+
|
|
20
|
+
- `lib/ea/svg/ea_emitter/markers.rb` — `marker_specs` returns Array, `count_for` API
|
|
21
|
+
- `lib/ea/svg/ea_emitter/document.rb` — `pair_per_connector` interleave
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
# TODO-D 21: Auto-generated legend block
|
|
2
|
+
|
|
3
|
+
## Problem
|
|
4
|
+
|
|
5
|
+
EA renders a "凡例" (Legend) block in many diagrams that contain
|
|
6
|
+
color-coded stereotype elements. The block contains:
|
|
7
|
+
|
|
8
|
+
- A rounded-corner container rect (`rx=3`)
|
|
9
|
+
- 3 color swatch rects (`17×17`)
|
|
10
|
+
- A bold 12pt #003060 title "凡例"
|
|
11
|
+
- Three 9pt #003060 lines naming the source packages
|
|
12
|
+
|
|
13
|
+
Reference SVG example (EAID_0016F797):
|
|
14
|
+
|
|
15
|
+
```xml
|
|
16
|
+
<rect x="485" y="368" width="194" height="120" rx="3.00"/>
|
|
17
|
+
<rect x="495" y="398" width="17" height="17"/> <!-- swatch 1 -->
|
|
18
|
+
<rect x="495" y="417" width="17" height="17"/> <!-- swatch 2 -->
|
|
19
|
+
<rect x="495" y="436" width="17" height="17"/> <!-- swatch 3 -->
|
|
20
|
+
<text x="546.00" y="387.00" font-weight:700 font-size:12pt>凡例</text>
|
|
21
|
+
<text x="517.00" y="410.00">GMLに定義されたクラス</text>
|
|
22
|
+
<text x="517.00" y="429.00">CityGMLに定義されたクラス</text>
|
|
23
|
+
<text x="517.00" y="448.00">i-URに定義されたクラス</text>
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
The block is NOT modeled in the QEA schema. There is no "Legend"
|
|
27
|
+
Object_Type, no t_lists row, no StyleEx flag tied to it.
|
|
28
|
+
|
|
29
|
+
## Investigation Notes
|
|
30
|
+
|
|
31
|
+
- 27 Note objects in the QEA, none contains "凡例".
|
|
32
|
+
- 5 Text objects in the QEA, all empty Note field.
|
|
33
|
+
- The legend titles and swatch colors vary per diagram but follow
|
|
34
|
+
a fixed vocabulary: GML, CityGML, i-UR.
|
|
35
|
+
- The color swatches are the stereotype fill colors of elements
|
|
36
|
+
visible in the diagram (e.g. FFCFFF for CityGML, CCFFCC for GML).
|
|
37
|
+
|
|
38
|
+
## Hypothesis
|
|
39
|
+
|
|
40
|
+
EA's "Diagram Legend" feature is a built-in diagram decoration
|
|
41
|
+
that auto-generates when:
|
|
42
|
+
|
|
43
|
+
1. The diagram contains elements whose stereotype maps to a
|
|
44
|
+
known "package source" (GML, CityGML, i-UR).
|
|
45
|
+
2. The user has placed a Legend UI element (which EA serializes
|
|
46
|
+
somewhere we haven't found yet — possibly t_image or a binary
|
|
47
|
+
blob).
|
|
48
|
+
|
|
49
|
+
Without reverse-engineering EA.exe's legend code path or finding
|
|
50
|
+
the serialization, replicating this verbatim is high-risk.
|
|
51
|
+
|
|
52
|
+
## Status
|
|
53
|
+
|
|
54
|
+
Deferred. Pinned in the parity report (TODO.diagrams/
|
|
55
|
+
17-remaining-parity-gaps.md) as a known ~448-text gap.
|
|
56
|
+
|
|
57
|
+
## Acceptance (when picked up)
|
|
58
|
+
|
|
59
|
+
- Locate the legend serialization in the QEA (table + column).
|
|
60
|
+
- Model `Ea::Model::Legend` with `position`, `title`, `entries`
|
|
61
|
+
(each entry: color + label).
|
|
62
|
+
- Build `Ea::Svg::EaEmitter::Legend` renderer producing the
|
|
63
|
+
container rect + swatch rects + texts.
|
|
64
|
+
- Specs cover: empty legend, single-entry, three-entry.
|
|
65
|
+
- Parity text overlap climbs above 90%.
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
# TODO-D 22: Ghost element discriminator
|
|
2
|
+
|
|
3
|
+
## Problem
|
|
4
|
+
|
|
5
|
+
EA renders some elements as "ghosts": smaller font (7pt), gray
|
|
6
|
+
text (#595959), no attribute/operation/tag compartments. The
|
|
7
|
+
discriminator is unclear.
|
|
8
|
+
|
|
9
|
+
## Empirical Observations
|
|
10
|
+
|
|
11
|
+
| Diagram | Element | ObjectStyle | Rendered as |
|
|
12
|
+
|--------------------|----------------------------|------------------------------------------------------|-------------|
|
|
13
|
+
| 位置図C0301 | _UrbanFunction | NSL=0;LCol=-1;...font=Yu Gothic UI;... | Full |
|
|
14
|
+
| 位置図C0301 | MultiSurface | NSL=0;BFol=-1;...fontsz=0;bold=0;... (no font=) | Ghost |
|
|
15
|
+
| CityGMLCore | _Feature | NSL=0;BCol=-1;BFol=-1;LCol=-1;LWth=-1;fontsz=0;... | Ghost |
|
|
16
|
+
| urf_4 | _UrbanFunction | NSL=0;BFol=-1;LCol=-1;fontsz=0;bold=0;... (no font=) | **Full** |
|
|
17
|
+
| 都市計画決定情報 | _UrbanFunction | NSL=0;LCol=-1;bold=0;... (no font=) | Ghost |
|
|
18
|
+
|
|
19
|
+
The presence or absence of `font=` is **not** the discriminator
|
|
20
|
+
(urf_4 elements lack `font=` but render full attributes).
|
|
21
|
+
|
|
22
|
+
`BCol` value is **not** the discriminator (urf_4 has explicit
|
|
23
|
+
BCol=16777215; MultiSurface in 位置図C0301 has BCol=13434828).
|
|
24
|
+
|
|
25
|
+
Classifier `package_id` vs diagram `package_id` is **not** the
|
|
26
|
+
discriminator (urf_4 cross-package elements get full attrs;
|
|
27
|
+
CityGMLCore cross-package elements get ghost).
|
|
28
|
+
|
|
29
|
+
## Hypothesis To Test
|
|
30
|
+
|
|
31
|
+
1. **Diagram-level "is reference" flag**: maybe EA marks diagrams
|
|
32
|
+
that only show snapshots of an external model. The discriminator
|
|
33
|
+
could be `t_diagram.SPT=1` (already 1 in all observed diagrams)
|
|
34
|
+
combined with another flag.
|
|
35
|
+
|
|
36
|
+
2. **Element-level "Link" semantics**: maybe elements placed as
|
|
37
|
+
"links" rather than embedded get ghost styling. The QEA may
|
|
38
|
+
encode this in t_diagramlinks.Path or t_object.Documentation
|
|
39
|
+
style flags we haven't parsed.
|
|
40
|
+
|
|
41
|
+
3. **t_objectstatistics or t_objectproperties**: an explicit "ghost
|
|
42
|
+
mode" tagged value.
|
|
43
|
+
|
|
44
|
+
## Status
|
|
45
|
+
|
|
46
|
+
Deferred. Without EA.exe disassembly or empirical testing inside
|
|
47
|
+
the EA GUI, the rule cannot be confidently derived.
|
|
48
|
+
|
|
49
|
+
## Acceptance (when picked up)
|
|
50
|
+
|
|
51
|
+
- Open the QEA in EA GUI, toggle the "Link" vs "Embed" property
|
|
52
|
+
on an element, observe the rendered SVG, and identify the QEA
|
|
53
|
+
field that changes.
|
|
54
|
+
- Implement a `ghost?` predicate on `Ea::Model::DiagramElement`
|
|
55
|
+
using the discovered field.
|
|
56
|
+
- Wire through `Elements` emitter to apply ghost styling.
|
|
57
|
+
- Specs cover both ghost and full paths.
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
# 22 - Style-Based Path Grouping
|
|
2
|
+
|
|
3
|
+
## Status: DONE (2026-07-23)
|
|
4
|
+
|
|
5
|
+
## Outcome
|
|
6
|
+
|
|
7
|
+
`Connectors` emitter now supports `group_by_style:` constructor
|
|
8
|
+
option. When true, consecutive connectors with the same line style
|
|
9
|
+
are merged into a single `<g>` element with multiple `<path>` kids
|
|
10
|
+
(matching EA's encoding for diagrams with many similarly-styled
|
|
11
|
+
connectors).
|
|
12
|
+
|
|
13
|
+
Default behavior remains per-entity grouping (one `<g>` per
|
|
14
|
+
connector) to preserve z-order interleaving with markers.
|
|
15
|
+
|
|
16
|
+
## Usage
|
|
17
|
+
|
|
18
|
+
```ruby
|
|
19
|
+
# Default: per-entity groups (current behavior)
|
|
20
|
+
Connectors.new(diagram, canvas: canvas)
|
|
21
|
+
|
|
22
|
+
# EA-style grouped:
|
|
23
|
+
Connectors.new(diagram, canvas: canvas, group_by_style: true)
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
## Files changed
|
|
27
|
+
|
|
28
|
+
- `lib/ea/svg/ea_emitter/connectors.rb` — `group_by_style` option + `grouped_groups`
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
# TODO-D 23: Marker polygon deduplication rules
|
|
2
|
+
|
|
3
|
+
## Problem
|
|
4
|
+
|
|
5
|
+
EA's rules for emitting polygon markers when multiple connectors
|
|
6
|
+
share an endpoint are non-obvious.
|
|
7
|
+
|
|
8
|
+
## Empirical Observations
|
|
9
|
+
|
|
10
|
+
Aggregate across 188 reference SVGs:
|
|
11
|
+
- Total polygons: 1485
|
|
12
|
+
- Exact-duplicate polygons (same points string): **536** (36%)
|
|
13
|
+
|
|
14
|
+
EA duplicates polygon markers in many cases but not always. The
|
|
15
|
+
discriminator is unclear.
|
|
16
|
+
|
|
17
|
+
## Experiments Tried
|
|
18
|
+
|
|
19
|
+
| Strategy | Polygon delta | Within-tol |
|
|
20
|
+
|-----------------------------|---------------|------------|
|
|
21
|
+
| Anchor-based dedup (current)| -166 (-11.2%) | 123/188 (65.4%) |
|
|
22
|
+
| No dedup | +257 (+17.3%) | 139/188 (73.9%) |
|
|
23
|
+
| Exact-body dedup | +247 (+16.6%) | 141/188 (75.0%) |
|
|
24
|
+
|
|
25
|
+
Both "no dedup" and "exact-body dedup" improve within-tolerance
|
|
26
|
+
diagram count (+13%) but introduce polygon overshoot. Anchor-based
|
|
27
|
+
dedup has best polygon delta but lower diagram-tol rate.
|
|
28
|
+
|
|
29
|
+
## Hypothesis To Test
|
|
30
|
+
|
|
31
|
+
EA likely has per-marker-per-connector emission for `Path=`-routed
|
|
32
|
+
connectors (each visible link emits its own markers) but deduplicates
|
|
33
|
+
markers that share an anchor AND belong to connectors sharing a
|
|
34
|
+
common segment.
|
|
35
|
+
|
|
36
|
+
The QEA stores a `Path=` field on t_diagramlinks; connectors that
|
|
37
|
+
share the same visual path are co-rendered. We currently treat
|
|
38
|
+
each t_diagramlinks row independently.
|
|
39
|
+
|
|
40
|
+
## Acceptance (when picked up)
|
|
41
|
+
|
|
42
|
+
- Correlate polygon duplicates with shared `Path=` values.
|
|
43
|
+
- Implement per-diagram `grouped:` mode selection in Markers.
|
|
44
|
+
- Specs cover: distinct anchors (no dedup), shared anchor + shared
|
|
45
|
+
path (dedup), shared anchor + distinct path (no dedup).
|
|
46
|
+
- Polygon delta within ±20 (currently -166).
|
|
47
|
+
- Within-tolerance diagrams ≥ 75% (currently 65.4%).
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
# 23 - Diagram-Level Multiplicity Label Positioning
|
|
2
|
+
|
|
3
|
+
## Status: DONE (2026-07-23)
|
|
4
|
+
|
|
5
|
+
## Outcome
|
|
6
|
+
|
|
7
|
+
Refactored `Ea::Svg::EaEmitter::Labels` to emit per-end role name +
|
|
8
|
+
multiplicity using LLB (left label box) / LLT (left label text) and
|
|
9
|
+
RLB / RLT offsets from the connector geometry.
|
|
10
|
+
|
|
11
|
+
Uses UML convention: the role visible at one end of the connector is
|
|
12
|
+
the property owned by the OPPOSITE classifier. So LLT (near source)
|
|
13
|
+
shows the target-end property; RLT (near target) shows the source-
|
|
14
|
+
end property.
|
|
15
|
+
|
|
16
|
+
Each label emits as TWO `<text>` elements matching EA's encoding:
|
|
17
|
+
one for the role name (`+roleName`) and one for the multiplicity
|
|
18
|
+
(`0..1`).
|
|
19
|
+
|
|
20
|
+
## Files changed
|
|
21
|
+
|
|
22
|
+
- `lib/ea/svg/ea_emitter/labels.rb` — full rewrite with model_index,
|
|
23
|
+
association_ends, label_position, role_text, multiplicity_text
|
|
24
|
+
- `lib/ea/svg/ea_emitter/document.rb` — passes `model_index` to Labels
|
|
25
|
+
|
|
26
|
+
## Outcome metrics
|
|
27
|
+
|
|
28
|
+
Text count mean abs diff dropped from 20 → 14 across 185 diagrams.
|
|
29
|
+
Waterway: 92 → 103 (ref=113). CityFurniture: 24 → 30 (ref=34).
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
# TODO-D 24: Track marker anchors structurally
|
|
2
|
+
|
|
3
|
+
## Problem
|
|
4
|
+
|
|
5
|
+
`Ea::Svg::EaEmitter::Markers#anchor_key` parses the SVG string the
|
|
6
|
+
class itself just emitted in order to deduplicate entries by their
|
|
7
|
+
anchor point:
|
|
8
|
+
|
|
9
|
+
```ruby
|
|
10
|
+
def anchor_key(body)
|
|
11
|
+
match = body.match(/polygon points="(-?[\d.]+)\s+(-?[\d.]+)|path d="M (-?[\d.]+)\s+(-?[\d.]+)/)
|
|
12
|
+
return body unless match
|
|
13
|
+
...
|
|
14
|
+
end
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
This is fragile:
|
|
18
|
+
|
|
19
|
+
- Round-trip through string parsing for data we already had
|
|
20
|
+
structurally.
|
|
21
|
+
- Regex assumes EA's exact SVG attribute ordering and whitespace.
|
|
22
|
+
- Hard to test in isolation (must build the body string first).
|
|
23
|
+
|
|
24
|
+
## Fix
|
|
25
|
+
|
|
26
|
+
Add `anchor` to the `Entry` struct. Capture it when the entry is
|
|
27
|
+
built (we already have `tip` at that point). Dedup on
|
|
28
|
+
`Entry#anchor` rather than re-parsing the body.
|
|
29
|
+
|
|
30
|
+
## Acceptance
|
|
31
|
+
|
|
32
|
+
- `Entry` struct carries `[x, y]` anchor.
|
|
33
|
+
- `anchor_key` method removed; dedup uses `Entry#anchor` directly.
|
|
34
|
+
- Markers specs continue to pass.
|
|
35
|
+
- Parity polygon delta unchanged.
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
# TODO-D 24: Track marker anchors structurally (DONE)
|
|
2
|
+
|
|
3
|
+
## Before
|
|
4
|
+
|
|
5
|
+
`Markers#anchor_key` parsed the rendered SVG string with regex to
|
|
6
|
+
extract the marker's anchor coordinates:
|
|
7
|
+
|
|
8
|
+
```ruby
|
|
9
|
+
def anchor_key(body)
|
|
10
|
+
match = body.match(/polygon points="(-?[\d.]+)\s+(-?[\d.]+)|path d="M (-?[\d.]+)\s+(-?[\d.]+)/)
|
|
11
|
+
return body unless match
|
|
12
|
+
x = (match[1] || match[3]).to_f.round
|
|
13
|
+
y = (match[2] || match[4]).to_f.round
|
|
14
|
+
[x, y]
|
|
15
|
+
end
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
That mixes "data" (the anchor) with "presentation" (the rendered
|
|
19
|
+
string), and it parses the same SVG twice. Re-introducing the
|
|
20
|
+
anchor as a Ruby value fixes both.
|
|
21
|
+
|
|
22
|
+
## After
|
|
23
|
+
|
|
24
|
+
`Markers::Entry` is now a Struct that carries the anchor alongside
|
|
25
|
+
the body, with hash/eql? defined so `Array#uniq` collapses by
|
|
26
|
+
anchor without touching the SVG:
|
|
27
|
+
|
|
28
|
+
```ruby
|
|
29
|
+
Entry = Struct.new(:style_key, :body, :anchor, keyword_init: true) do
|
|
30
|
+
def hash
|
|
31
|
+
anchor.hash
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def eql?(other)
|
|
35
|
+
other.is_a?(Entry) && anchor == other.anchor
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
`entries_for` computes the anchor once when building the Entry:
|
|
41
|
+
|
|
42
|
+
```ruby
|
|
43
|
+
def anchor_for(spec)
|
|
44
|
+
tx, ty = translate_point(spec.anchor)
|
|
45
|
+
[tx.round, ty.round]
|
|
46
|
+
end
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
## Benefits
|
|
50
|
+
|
|
51
|
+
- **Performance**: one anchor computation per marker instead of
|
|
52
|
+
a regex match per dedup pass.
|
|
53
|
+
- **Type safety**: anchor is a `[Integer, Integer]` pair, not a
|
|
54
|
+
parsed fragment of a String.
|
|
55
|
+
- **Encapsulation**: rendered SVG never re-parsed.
|
|
56
|
+
- **Testability**: `Entry#eql?` is unit-testable in isolation.
|
|
57
|
+
|
|
58
|
+
## Tests
|
|
59
|
+
|
|
60
|
+
- `spec/ea/svg/ea_emitter/markers_entry_spec.rb` covers anchor
|
|
61
|
+
equality, deduplication, and false-positive guards.
|
|
62
|
+
|
|
63
|
+
## Bench
|
|
64
|
+
|
|
65
|
+
Unchanged: rect -221, path -280, polygon -6, text -601,
|
|
66
|
+
overlap 64.5%. The refactor is behavior-preserving.
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
# 24 - Truncate Properties to Fit Box (Match EA Display)
|
|
2
|
+
|
|
3
|
+
## Status: DONE (2026-07-23)
|
|
4
|
+
|
|
5
|
+
## Outcome
|
|
6
|
+
|
|
7
|
+
Discovered the actual rule: EA hides properties that are navigable
|
|
8
|
+
ends of an association (those are rendered as connector lines, not
|
|
9
|
+
as attribute text). This is NOT box-fit truncation — it's a content
|
|
10
|
+
filter based on property semantics.
|
|
11
|
+
|
|
12
|
+
## Implementation
|
|
13
|
+
|
|
14
|
+
1. Added `association_id` field to `Ea::Model::Property` (non-nil
|
|
15
|
+
when the property is a navigable end of an Association).
|
|
16
|
+
2. `Ea::Sources::Xmi::PropertyBuilder` captures `attr.association`.
|
|
17
|
+
3. `Ea::Svg::EaEmitter::Elements#displayable_properties` rejects
|
|
18
|
+
properties with `association_id` set.
|
|
19
|
+
|
|
20
|
+
## Files changed
|
|
21
|
+
|
|
22
|
+
- `lib/ea/model/property.rb` — `association_id` attribute + JSON mapping
|
|
23
|
+
- `lib/ea/sources/xmi/property_builder.rb` — populate `association_id`
|
|
24
|
+
- `lib/ea/svg/ea_emitter/elements.rb` — `displayable_properties` filter
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
# TODO-D 26: Phantom general-parent rendering
|
|
2
|
+
|
|
3
|
+
## Problem
|
|
4
|
+
|
|
5
|
+
The reference SVGs contain class headers (`_AbstractGeometricAggregate`,
|
|
6
|
+
`_CityObject`, `_FeatureCollection`, etc.) that do NOT appear in
|
|
7
|
+
`t_diagramobjects` for the diagram. ~150 missing text instances
|
|
8
|
+
across the plateau dataset.
|
|
9
|
+
|
|
10
|
+
## Empirical Rule (partial)
|
|
11
|
+
|
|
12
|
+
When a class is placed in a diagram, EA also displays its
|
|
13
|
+
generalization parent if the parent isn't already in the diagram.
|
|
14
|
+
|
|
15
|
+
Validation across 188 diagrams:
|
|
16
|
+
|
|
17
|
+
- Total parent-checks: 241
|
|
18
|
+
- Parent rendered in SVG: 129 (53.5%)
|
|
19
|
+
|
|
20
|
+
53.5% match suggests the rule is "right idea, wrong details." Other
|
|
21
|
+
factors:
|
|
22
|
+
|
|
23
|
+
- Per-element font/style override may suppress phantom rendering
|
|
24
|
+
when the parent's style isn't explicit
|
|
25
|
+
- The discriminator may be tied to AttPkg / SuppressFOC flags
|
|
26
|
+
- EA may only render one level up the generalization chain
|
|
27
|
+
|
|
28
|
+
## Implementation Sketch
|
|
29
|
+
|
|
30
|
+
Add `phantom_generalizations_for(diagram, model_index)` returning
|
|
31
|
+
phantom DiagramElements with synthetic bounds (placed near their
|
|
32
|
+
child). Render them through the existing `groups_for` path so they
|
|
33
|
+
participate in the same compartment math, color resolution, etc.
|
|
34
|
+
|
|
35
|
+
```ruby
|
|
36
|
+
def ordered_elements
|
|
37
|
+
placed = (diagram.elements || []).sort_by { |e| e.z_order || 0 }
|
|
38
|
+
placed + phantom_elements(placed)
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
def phantom_elements(placed)
|
|
42
|
+
placed_ids = placed.map(&:model_element_ref)
|
|
43
|
+
parents = placed_ids.flat_map { |id| generalizations_of(id) }.uniq - placed_ids
|
|
44
|
+
parents.map { |pid| phantom_diagram_element(pid) }
|
|
45
|
+
end
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
The hard part is positioning: EA computes phantoms at coordinates
|
|
49
|
+
we cannot derive without GUI testing or sample-data correlation.
|
|
50
|
+
|
|
51
|
+
## Acceptance
|
|
52
|
+
|
|
53
|
+
- Render general-parent phantoms for at least the cases where the
|
|
54
|
+
rule applies cleanly.
|
|
55
|
+
- Phantom bounding box is plausible (within canvas extents).
|
|
56
|
+
- Parity text overlap climbs to ~90%+.
|
|
57
|
+
- Specs cover: parent not in diagram (phantom added), parent
|
|
58
|
+
already in diagram (no duplicate), phantom appears in correct
|
|
59
|
+
sub-layer.
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
# TODO-D 27: Per-diagram path grouping mode detection
|
|
2
|
+
|
|
3
|
+
## Problem
|
|
4
|
+
|
|
5
|
+
EA emits connector paths in two styles:
|
|
6
|
+
|
|
7
|
+
1. **Grouped** — All same-style paths joined into one `<g>` block
|
|
8
|
+
(matches what we currently do in `LayerSequencer#merge_layers_by_style`).
|
|
9
|
+
2. **Per-connector** — Each connector path in its own `<g>` block.
|
|
10
|
+
|
|
11
|
+
Some diagrams use one mode, others use the other. We always use
|
|
12
|
+
grouped, contributing to the -181 path delta.
|
|
13
|
+
|
|
14
|
+
## Investigation
|
|
15
|
+
|
|
16
|
+
Tested in StyleEx flags — no obvious "grouped" toggle. EA's
|
|
17
|
+
emit-mode decision appears to be runtime/export-time, not stored in
|
|
18
|
+
the QEA.
|
|
19
|
+
|
|
20
|
+
## Empirical Observations
|
|
21
|
+
|
|
22
|
+
- Grouped-style diagrams: 0 to 5 path-delta diagrams (most match)
|
|
23
|
+
- Per-connector-style diagrams: 10-30 path-delta (we're missing 10-30
|
|
24
|
+
`<g>` wrappers)
|
|
25
|
+
|
|
26
|
+
The discriminator might be:
|
|
27
|
+
|
|
28
|
+
- Diagram export-time option set in EA GUI at export
|
|
29
|
+
- Per-diagram count threshold (more connectors → per-connector)
|
|
30
|
+
- User preference cached in some EA-specific location we can't access
|
|
31
|
+
|
|
32
|
+
## Status
|
|
33
|
+
|
|
34
|
+
Deferred. Without empirical access to EA's export preferences or a
|
|
35
|
+
binary blob in the QEA, the mode detection is speculative.
|
|
36
|
+
|
|
37
|
+
## Acceptance (when picked up)
|
|
38
|
+
|
|
39
|
+
- Identify the QEA field or runtime condition that controls grouping.
|
|
40
|
+
- Implement a per-diagram detector.
|
|
41
|
+
- Wire into LayerSequencer: `grouped: detect_grouped_mode(diagram)`.
|
|
42
|
+
- Specs cover: small diagrams → grouped, large diagrams → per-connector.
|
|
43
|
+
- Path delta within ±20 of zero.
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
# TODO-D 28-31: Architectural cleanup batch
|
|
2
|
+
|
|
3
|
+
## Completed (this session)
|
|
4
|
+
|
|
5
|
+
### 28. Canvas promoted to proper class
|
|
6
|
+
|
|
7
|
+
`lib/ea/svg/ea_emitter/canvas.rb` was a `Struct.new + do ... end`
|
|
8
|
+
block. Promoted to an explicit class with `attr_reader` for the
|
|
9
|
+
four bound fields. Public API is now named rather than implicit;
|
|
10
|
+
the type stays immutable.
|
|
11
|
+
|
|
12
|
+
8 new specs cover `translate_x`, `translate_y`, `.coord`,
|
|
13
|
+
immutability, and the existing `.from` factory.
|
|
14
|
+
|
|
15
|
+
### 29. OpenStruct removed
|
|
16
|
+
|
|
17
|
+
`elements.rb#translate_bounds` returned an `OpenStruct.new`. This
|
|
18
|
+
required `require "ostruct"` at the top of the file and obscured
|
|
19
|
+
the return type.
|
|
20
|
+
|
|
21
|
+
Now returns `Ea::Model::Bounds.new` directly — the existing model
|
|
22
|
+
value object — and the `require "ostruct"` line is removed. Type
|
|
23
|
+
flows cleanly through the pipeline (model → renderer).
|
|
24
|
+
|
|
25
|
+
### 31. Specs for under-tested components
|
|
26
|
+
|
|
27
|
+
- `spec/ea/svg/ea_emitter/canvas_spec.rb` — added `translate_x`,
|
|
28
|
+
`translate_y`, `.coord`, and immutability specs.
|
|
29
|
+
- `spec/ea/svg/ea_emitter/layer_spec.rb` — new file (10 specs).
|
|
30
|
+
- `spec/ea/svg/ea_emitter/background_spec.rb` — new file (3 specs).
|
|
31
|
+
|
|
32
|
+
## Deferred
|
|
33
|
+
|
|
34
|
+
### 30. Decompose Elements groups_for
|
|
35
|
+
|
|
36
|
+
`Elements#groups_for` is ~100 lines of linear rendering steps.
|
|
37
|
+
Two previous attempts to extract a helper method broke 5+ specs
|
|
38
|
+
due to complex parameter threading (model_element vs classifier
|
|
39
|
+
distinction, Optional bounds, theme plumbing).
|
|
40
|
+
|
|
41
|
+
The method reads as a recipe: each step adds one output string.
|
|
42
|
+
Linear recipes are easier to read as one method than as a chain
|
|
43
|
+
of helper calls with overlapping parameter lists.
|
|
44
|
+
|
|
45
|
+
Deferred until a structural refactor (e.g. a Compartments
|
|
46
|
+
collaborator that holds rendering state) is justified by a new
|
|
47
|
+
requirement.
|