ea 0.3.1 → 0.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- 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/STATUS.md +109 -0
- data/TODO.diagrams/01-svg-measurement-harness.md +31 -0
- data/TODO.diagrams/01-xmi-extension-elements-parsing.md +67 -0
- data/TODO.diagrams/02-diagram-element-rich-model.md +61 -0
- data/TODO.diagrams/02-polygon-over-rendering.md +29 -0
- data/TODO.diagrams/03-ea-style-svg-emitter.md +70 -0
- data/TODO.diagrams/03-text-over-rendering.md +30 -0
- data/TODO.diagrams/04-connector-routing-from-soid-eoid.md +55 -0
- data/TODO.diagrams/04-rect-under-rendering.md +33 -0
- data/TODO.diagrams/05-canvas-dimension-parity.md +51 -0
- data/TODO.diagrams/05-marker-rendering-per-relationship-type.md +49 -0
- data/TODO.diagrams/06-connector-labels.md +49 -0
- data/TODO.diagrams/06-group-layering-parity.md +39 -0
- data/TODO.diagrams/07-canvas-size-and-viewbox.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/08-visual-regression-harness.md +34 -0
- data/TODO.diagrams/09-cli-render-all-diagrams.md +25 -0
- data/TODO.diagrams/10-stereotype-color-config.md +29 -0
- data/TODO.diagrams/11-elkrb-auto-layout-integration.md +53 -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/stereotype_colors.yml +15 -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 +62 -1
- 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 +80 -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 +43 -6
- 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 +82 -0
- data/lib/ea/diff/html_reporter.rb +91 -0
- data/lib/ea/diff.rb +15 -0
- data/lib/ea/export/json/generator.rb +42 -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 +73 -0
- data/lib/ea/export/plantuml.rb +12 -0
- data/lib/ea/export/xmi/generator.rb +77 -0
- data/lib/ea/export/xmi.rb +11 -0
- data/lib/ea/export/xsd/class_mapping.rb +65 -0
- data/lib/ea/export/xsd/generator.rb +142 -0
- data/lib/ea/export/xsd/namespace_registry.rb +82 -0
- data/lib/ea/export/xsd.rb +19 -0
- data/lib/ea/export.rb +14 -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 +35 -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 +53 -1
- data/lib/ea/model/diagram_element.rb +44 -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/query/builder.rb +108 -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/annotation_builder.rb +1 -1
- data/lib/ea/sources/xmi/classifier_builder.rb +10 -1
- data/lib/ea/sources/xmi/diagram_builder.rb +242 -45
- data/lib/ea/sources/xmi/extension_elements.rb +74 -0
- data/lib/ea/sources/xmi/extension_geometry_parser.rb +124 -0
- data/lib/ea/sources/xmi/extension_style_parser.rb +91 -0
- 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 +7 -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 +15 -0
- data/lib/ea/svg/ea_emitter/bounds_calculator.rb +142 -0
- data/lib/ea/svg/ea_emitter/canvas.rb +88 -0
- 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/tagged_values.rb +30 -0
- data/lib/ea/svg/ea_emitter/compartment.rb +58 -0
- data/lib/ea/svg/ea_emitter/connectors.rb +84 -0
- data/lib/ea/svg/ea_emitter/diagram_frame.rb +143 -0
- data/lib/ea/svg/ea_emitter/document.rb +35 -0
- 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 +82 -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 +357 -0
- 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 +130 -0
- 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 +404 -0
- 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 +51 -0
- 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/stereotype_color_resolver.rb +50 -0
- data/lib/ea/svg.rb +4 -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/version.rb +4 -1
- data/lib/ea.rb +14 -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 +473 -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,88 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Ea
|
|
4
|
+
module Svg
|
|
5
|
+
module EaEmitter
|
|
6
|
+
# Canvas carries the diagram's computed pixel bounds plus the
|
|
7
|
+
# coordinate-translation helpers that align element (0,0) with
|
|
8
|
+
# EA's content origin (35, 40). Bound computation itself is
|
|
9
|
+
# delegated to BoundsCalculator (SRP).
|
|
10
|
+
#
|
|
11
|
+
# Promoted from a Struct.new + `do ... end` block to a proper
|
|
12
|
+
# class so the public API is explicit (attr_reader vs implicit
|
|
13
|
+
# struct fields) and behavior is named rather than implicit.
|
|
14
|
+
# Struct definitions with instance methods conflate "data" and
|
|
15
|
+
# "behavior" — a class keeps them separable while the values
|
|
16
|
+
# stay immutable.
|
|
17
|
+
class Canvas
|
|
18
|
+
# EA's diagram canvas places element (0,0) at SVG (35, 40) —
|
|
19
|
+
# the diagram's content origin inset from the canvas top-left
|
|
20
|
+
# corner. Reverse-engineered from reference SVG byte-diff
|
|
21
|
+
# against the maintenance diagram.
|
|
22
|
+
PX_PER_CM = 37.795275591
|
|
23
|
+
FRAME_INSET_LEFT = 35
|
|
24
|
+
FRAME_INSET_TOP = 40
|
|
25
|
+
|
|
26
|
+
attr_reader :min_x, :min_y, :width, :height
|
|
27
|
+
|
|
28
|
+
def initialize(min_x:, min_y:, width:, height:)
|
|
29
|
+
@min_x = min_x
|
|
30
|
+
@min_y = min_y
|
|
31
|
+
@width = width
|
|
32
|
+
@height = height
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
# Build a Canvas for a diagram by running the bound
|
|
36
|
+
# calculator. Defaults model_index to nil (no canvas-aware
|
|
37
|
+
# element bounds needed) for callers that only need a
|
|
38
|
+
# frame-size estimate.
|
|
39
|
+
def self.from(diagram, model_index: nil)
|
|
40
|
+
min_x, min_y, width, height =
|
|
41
|
+
BoundsCalculator.new(diagram, model_index: model_index).compute
|
|
42
|
+
new(min_x: min_x, min_y: min_y, width: width, height: height)
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
def view_box
|
|
46
|
+
"0 0 #{width} #{height}"
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
def width_cm
|
|
50
|
+
format_cm(width)
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
def height_cm
|
|
54
|
+
format_cm(height)
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
# Translate a content-space point into SVG-space. EA insets
|
|
58
|
+
# the content area from the canvas top-left by
|
|
59
|
+
# FRAME_INSET_LEFT/TOP.
|
|
60
|
+
def translate_x(x)
|
|
61
|
+
x - min_x + FRAME_INSET_LEFT
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
def translate_y(y)
|
|
65
|
+
y - min_y + FRAME_INSET_TOP
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
# Compact coordinate formatter. Integers lose the decimal
|
|
69
|
+
# point; floats keep up to two digits with trailing zeros
|
|
70
|
+
# stripped (matches EA's emitted numeric format).
|
|
71
|
+
def self.coord(value)
|
|
72
|
+
return value.to_i.to_s if value == value.to_i
|
|
73
|
+
|
|
74
|
+
format("%.2f", value).sub(/\.?0+$/, "")
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
private
|
|
78
|
+
|
|
79
|
+
def format_cm(px)
|
|
80
|
+
return "0cm" if px.nil? || px.zero?
|
|
81
|
+
|
|
82
|
+
cm = (px / PX_PER_CM.to_f)
|
|
83
|
+
format("%.2fcm", cm)
|
|
84
|
+
end
|
|
85
|
+
end
|
|
86
|
+
end
|
|
87
|
+
end
|
|
88
|
+
end
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Ea
|
|
4
|
+
module Svg
|
|
5
|
+
module EaEmitter
|
|
6
|
+
# Single source of truth for fill + stroke color decisions.
|
|
7
|
+
#
|
|
8
|
+
# Theme :119 applies:
|
|
9
|
+
# - Border color (#9A8484) for element strokes
|
|
10
|
+
# - Attribute color (#66413F) for attribute text
|
|
11
|
+
# - Method color for operation text
|
|
12
|
+
# Theme :119 does NOT apply:
|
|
13
|
+
# - Per-type fill colors (elements use default #FFFFFF)
|
|
14
|
+
# - Text color (#000000 black for non-attribute text)
|
|
15
|
+
#
|
|
16
|
+
# Precedence chain for fill:
|
|
17
|
+
# 1. Element's BCol int (when present and not sentinel)
|
|
18
|
+
# 2. Default fill (#FFFFFF)
|
|
19
|
+
#
|
|
20
|
+
# Precedence chain for stroke:
|
|
21
|
+
# 1. Element's LCol int (when present and not sentinel)
|
|
22
|
+
# 2. Theme border color (when theme is themed)
|
|
23
|
+
# 3. Default stroke (#000000)
|
|
24
|
+
class ColorResolver
|
|
25
|
+
DEFAULT_FILL = "#FFFFFF"
|
|
26
|
+
DEFAULT_STROKE = "#000000"
|
|
27
|
+
|
|
28
|
+
attr_reader :theme, :stereotype_resolver
|
|
29
|
+
|
|
30
|
+
def initialize(theme: nil, stereotype_resolver: Ea::Svg::StereotypeColorResolver.new)
|
|
31
|
+
@theme = theme || Ea::Theme::Registry.default
|
|
32
|
+
@stereotype_resolver = stereotype_resolver
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def fill_for(element, classifier)
|
|
36
|
+
bcol = Element::BColDecoder.to_hex(element&.background_color)
|
|
37
|
+
return bcol if bcol
|
|
38
|
+
|
|
39
|
+
DEFAULT_FILL
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
def stroke_for(element)
|
|
43
|
+
lcol = Element::BColDecoder.to_hex(element&.line_color)
|
|
44
|
+
return lcol if lcol
|
|
45
|
+
return theme.border_color if theme.themed?
|
|
46
|
+
|
|
47
|
+
DEFAULT_STROKE
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
def attribute_text_color
|
|
51
|
+
theme.themed? ? (theme.attribute_color || DEFAULT_STROKE) : DEFAULT_STROKE
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
end
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Ea
|
|
4
|
+
module Svg
|
|
5
|
+
module EaEmitter
|
|
6
|
+
module Compartment
|
|
7
|
+
# Attribute compartment. Skipped when no attribute lines.
|
|
8
|
+
module Attributes
|
|
9
|
+
module_function
|
|
10
|
+
|
|
11
|
+
def render(context)
|
|
12
|
+
return nil if context.attr_lines.empty?
|
|
13
|
+
|
|
14
|
+
Element::AttributeRenderer.render(
|
|
15
|
+
context.attr_lines,
|
|
16
|
+
bounds: context.bounds,
|
|
17
|
+
first_y: context.geometry.attr_first_y,
|
|
18
|
+
family: context.family, size: context.size, size_unit: context.size_unit,
|
|
19
|
+
fill: context.theme.attribute_text_color,
|
|
20
|
+
visibility_x_offset: context.theme.attribute_spec.visibility_x_offset,
|
|
21
|
+
content_x_offset: context.theme.attribute_spec.content_x_offset
|
|
22
|
+
)
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
end
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Ea
|
|
4
|
+
module Svg
|
|
5
|
+
module EaEmitter
|
|
6
|
+
module Compartment
|
|
7
|
+
# Constraints compartment. Skipped when the classifier has no
|
|
8
|
+
# constraints. Renders an italic "constraints" header and one
|
|
9
|
+
# "{name}" line per constraint.
|
|
10
|
+
module Constraints
|
|
11
|
+
DEFAULT_TEXT_COLOR = "#000000"
|
|
12
|
+
|
|
13
|
+
module_function
|
|
14
|
+
|
|
15
|
+
def render(context)
|
|
16
|
+
return nil unless context.constraints&.any?
|
|
17
|
+
|
|
18
|
+
Element::ConstraintRenderer.render(
|
|
19
|
+
context.constraints,
|
|
20
|
+
bounds: context.bounds,
|
|
21
|
+
first_y: context.geometry.tagged_value_first_y,
|
|
22
|
+
family: context.family, size: context.size,
|
|
23
|
+
fill: DEFAULT_TEXT_COLOR
|
|
24
|
+
)
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
end
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Ea
|
|
4
|
+
module Svg
|
|
5
|
+
module EaEmitter
|
|
6
|
+
module Compartment
|
|
7
|
+
# Enumeration literal compartment: divider line + "literals"
|
|
8
|
+
# italic header + each literal name. Skipped when the
|
|
9
|
+
# classifier has no literals or the geometry cannot fit them.
|
|
10
|
+
module EnumLiterals
|
|
11
|
+
module_function
|
|
12
|
+
|
|
13
|
+
def render(context)
|
|
14
|
+
return nil unless context.enum_literals.any?
|
|
15
|
+
return nil unless context.geometry.enum_literal_first_y
|
|
16
|
+
|
|
17
|
+
[
|
|
18
|
+
Element::DividerRenderer.render(
|
|
19
|
+
context.bounds,
|
|
20
|
+
y: context.geometry.enum_divider_y,
|
|
21
|
+
stroke: context.stroke,
|
|
22
|
+
stroke_width: context.stroke_width
|
|
23
|
+
),
|
|
24
|
+
render_literals_block(context)
|
|
25
|
+
].join("\n")
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def render_literals_block(context)
|
|
29
|
+
line_h = context.size + (context.theme.compartments.attr_line_offset || 4)
|
|
30
|
+
text_blocks = [literal_header_text(context)]
|
|
31
|
+
context.enum_literals.each_with_index do |literal, idx|
|
|
32
|
+
y = context.geometry.enum_literal_first_y + ((idx + 1) * line_h)
|
|
33
|
+
text_blocks << visibility_placeholder(context, y)
|
|
34
|
+
text_blocks << literal_name_text(context, literal, y)
|
|
35
|
+
end
|
|
36
|
+
wrap_group(text_blocks, context.theme.text_color)
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
def literal_header_text(context)
|
|
40
|
+
TextRenderer.new(
|
|
41
|
+
content: "literals",
|
|
42
|
+
x: context.bounds.x + (context.bounds.width / 2.0) -
|
|
43
|
+
(8 * context.size * context.theme.text_width_factor) / 2,
|
|
44
|
+
y: context.geometry.enum_literal_first_y,
|
|
45
|
+
family: context.family, size: context.size, size_unit: context.size_unit,
|
|
46
|
+
style: "italic", fill: context.theme.text_color,
|
|
47
|
+
stroke_in_text: context.theme.stroke_in_text_color,
|
|
48
|
+
width_factor: context.theme.text_width_factor
|
|
49
|
+
).to_svg
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
def visibility_placeholder(context, y)
|
|
53
|
+
TextRenderer.new(
|
|
54
|
+
content: " ",
|
|
55
|
+
x: context.bounds.x + (context.theme.attribute_spec.visibility_x_offset || 5),
|
|
56
|
+
y: y,
|
|
57
|
+
family: context.family, size: context.size, size_unit: context.size_unit,
|
|
58
|
+
fill: context.theme.text_color,
|
|
59
|
+
stroke_in_text: context.theme.stroke_in_text_color,
|
|
60
|
+
width_factor: context.theme.text_width_factor
|
|
61
|
+
).to_svg
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
def literal_name_text(context, literal, y)
|
|
65
|
+
TextRenderer.new(
|
|
66
|
+
content: literal.name.to_s,
|
|
67
|
+
x: context.bounds.x + (context.theme.attribute_spec.content_x_offset || 26),
|
|
68
|
+
y: y,
|
|
69
|
+
family: context.family, size: context.size, size_unit: context.size_unit,
|
|
70
|
+
fill: context.theme.text_color,
|
|
71
|
+
stroke_in_text: context.theme.stroke_in_text_color,
|
|
72
|
+
width_factor: context.theme.text_width_factor
|
|
73
|
+
).to_svg
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
def wrap_group(text_blocks, text_color)
|
|
77
|
+
style = "stroke-width:1;stroke-linecap:round;stroke-linejoin:bevel; " \
|
|
78
|
+
"fill:#{text_color};fill-opacity:1.00; " \
|
|
79
|
+
"stroke:#000000; stroke-opacity:0.00"
|
|
80
|
+
%(<g style="#{style}">\n#{text_blocks.join("\n")}\n</g>)
|
|
81
|
+
end
|
|
82
|
+
end
|
|
83
|
+
end
|
|
84
|
+
end
|
|
85
|
+
end
|
|
86
|
+
end
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Ea
|
|
4
|
+
module Svg
|
|
5
|
+
module EaEmitter
|
|
6
|
+
module Compartment
|
|
7
|
+
# Header compartment: stereotype label + class name. Skips
|
|
8
|
+
# rendering when the classifier produces no header lines.
|
|
9
|
+
module Header
|
|
10
|
+
module_function
|
|
11
|
+
|
|
12
|
+
def render(context)
|
|
13
|
+
return nil if context.header_lines.empty?
|
|
14
|
+
|
|
15
|
+
Element::HeaderRenderer.render(
|
|
16
|
+
context.header_lines,
|
|
17
|
+
bounds: context.bounds,
|
|
18
|
+
first_y: context.geometry.header_first_y,
|
|
19
|
+
family: context.family, size: context.size, size_unit: context.size_unit,
|
|
20
|
+
fill: context.theme.text_color,
|
|
21
|
+
weight_normal: context.theme.text_weight_normal,
|
|
22
|
+
weight_bold: context.theme.text_weight_bold,
|
|
23
|
+
stroke_in_text: context.theme.stroke_in_text_color,
|
|
24
|
+
width_factor: context.theme.text_width_factor,
|
|
25
|
+
line_offset: context.theme.compartments.header_line_offset
|
|
26
|
+
)
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
end
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Ea
|
|
4
|
+
module Svg
|
|
5
|
+
module EaEmitter
|
|
6
|
+
module Compartment
|
|
7
|
+
# Horizontal divider between header and the first content
|
|
8
|
+
# compartment (attributes / operations / literals / tagged
|
|
9
|
+
# values). Skipped when there is no content below.
|
|
10
|
+
module HeaderDivider
|
|
11
|
+
module_function
|
|
12
|
+
|
|
13
|
+
def render(context)
|
|
14
|
+
return nil unless context.geometry
|
|
15
|
+
return nil unless context.geometry.divider_y
|
|
16
|
+
return nil unless divider_required?(context)
|
|
17
|
+
|
|
18
|
+
Element::DividerRenderer.render(
|
|
19
|
+
context.bounds,
|
|
20
|
+
y: context.geometry.divider_y,
|
|
21
|
+
stroke: context.stroke,
|
|
22
|
+
stroke_width: context.stroke_width
|
|
23
|
+
)
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
# EA shows a header divider on Object diagrams when the
|
|
27
|
+
# element is large enough to hold a slot compartment (height
|
|
28
|
+
# > 50). The starter Object diagram uses 90×50 boxes with
|
|
29
|
+
# no slots and no divider; richer Object diagrams use
|
|
30
|
+
# 133×53+ boxes with the divider always present. On
|
|
31
|
+
# HandDraw diagrams (Domain Model), every element shows a
|
|
32
|
+
# divider regardless of content. For other diagrams the
|
|
33
|
+
# divider is shown only when there is content below the
|
|
34
|
+
# header.
|
|
35
|
+
def divider_required?(context)
|
|
36
|
+
return true if hand_draw?(context)
|
|
37
|
+
return object_element_with_slots?(context) if object_diagram?(context)
|
|
38
|
+
|
|
39
|
+
context.content_below_header?
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
def object_diagram?(context)
|
|
43
|
+
context.diagram && context.diagram.diagram_type == "Object"
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
def hand_draw?(context)
|
|
47
|
+
context.diagram && context.diagram.hand_draw
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
def object_element_with_slots?(context)
|
|
51
|
+
context.bounds && context.bounds.height.to_i > 50
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
end
|
|
57
|
+
end
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Ea
|
|
4
|
+
module Svg
|
|
5
|
+
module EaEmitter
|
|
6
|
+
module Compartment
|
|
7
|
+
# Instance slot compartment. Renders each slot on an
|
|
8
|
+
# InstanceSpecification as "name op value", then appends
|
|
9
|
+
# "(from PackageName)" in italics below the slots when the
|
|
10
|
+
# instance has a classifier. Skipped entirely when the model
|
|
11
|
+
# element is not an InstanceSpecification or has neither
|
|
12
|
+
# slots nor a classifier.
|
|
13
|
+
module InstanceSlots
|
|
14
|
+
ROW_OFFSET = 13
|
|
15
|
+
SUBTITLE_EXTRA_OFFSET = 10
|
|
16
|
+
|
|
17
|
+
module_function
|
|
18
|
+
|
|
19
|
+
def render(context)
|
|
20
|
+
return nil unless instance?(context)
|
|
21
|
+
|
|
22
|
+
instance = context.model_element
|
|
23
|
+
slots = instance.slots || []
|
|
24
|
+
subtitle = from_package_subtitle(instance)
|
|
25
|
+
return nil if slots.empty? && subtitle.nil?
|
|
26
|
+
|
|
27
|
+
first_y = context.geometry.attr_first_y
|
|
28
|
+
bounds = context.bounds
|
|
29
|
+
fill = context.theme.attribute_text_color
|
|
30
|
+
blocks = []
|
|
31
|
+
slots.each_with_index do |slot, idx|
|
|
32
|
+
y = first_y + (idx * ROW_OFFSET)
|
|
33
|
+
blocks << line_text(slot, bounds, y, context, fill)
|
|
34
|
+
end
|
|
35
|
+
if subtitle
|
|
36
|
+
y = first_y + (slots.size * ROW_OFFSET) + SUBTITLE_EXTRA_OFFSET
|
|
37
|
+
blocks << subtitle_text(subtitle, bounds, y, context, fill)
|
|
38
|
+
end
|
|
39
|
+
wrap(blocks.join("\n"), fill)
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
def instance?(context)
|
|
43
|
+
context.model_element.is_a?(Ea::Model::InstanceSpecification)
|
|
44
|
+
end
|
|
45
|
+
module_function :instance?
|
|
46
|
+
|
|
47
|
+
def from_package_subtitle(instance)
|
|
48
|
+
pkg = instance.package_name
|
|
49
|
+
return nil if pkg.nil? || pkg.empty?
|
|
50
|
+
|
|
51
|
+
classifier = instance.classifier_name
|
|
52
|
+
return nil if classifier.nil? || classifier.empty?
|
|
53
|
+
|
|
54
|
+
"(from #{pkg})"
|
|
55
|
+
end
|
|
56
|
+
module_function :from_package_subtitle
|
|
57
|
+
|
|
58
|
+
def line_text(slot, bounds, y_pos, context, fill)
|
|
59
|
+
content = "#{slot.name} #{slot.op} #{slot.value}"
|
|
60
|
+
TextRenderer.new(
|
|
61
|
+
content: content,
|
|
62
|
+
x: bounds.x + (context.theme.attribute_spec.content_x_offset || 26),
|
|
63
|
+
y: y_pos,
|
|
64
|
+
family: context.family, size: context.size,
|
|
65
|
+
size_unit: context.size_unit, fill: fill
|
|
66
|
+
).to_svg
|
|
67
|
+
end
|
|
68
|
+
module_function :line_text
|
|
69
|
+
|
|
70
|
+
def subtitle_text(text, bounds, y_pos, context, fill)
|
|
71
|
+
estimated_width = text.length * context.size * 0.5
|
|
72
|
+
x_pos = bounds.x + (bounds.width - estimated_width) / 2.0
|
|
73
|
+
TextRenderer.new(
|
|
74
|
+
content: text,
|
|
75
|
+
x: x_pos,
|
|
76
|
+
y: y_pos,
|
|
77
|
+
family: context.family, size: context.size,
|
|
78
|
+
size_unit: context.size_unit, fill: fill,
|
|
79
|
+
style: "italic"
|
|
80
|
+
).to_svg
|
|
81
|
+
end
|
|
82
|
+
module_function :subtitle_text
|
|
83
|
+
|
|
84
|
+
def wrap(body, fill)
|
|
85
|
+
group_style = "stroke-width:1;stroke-linecap:round;" \
|
|
86
|
+
"stroke-linejoin:bevel; fill:#{fill};" \
|
|
87
|
+
"fill-opacity:1.00; stroke:#000000;" \
|
|
88
|
+
" stroke-opacity:0.00"
|
|
89
|
+
%(<g style="#{group_style}">\n#{body}\n</g>)
|
|
90
|
+
end
|
|
91
|
+
module_function :wrap
|
|
92
|
+
end
|
|
93
|
+
end
|
|
94
|
+
end
|
|
95
|
+
end
|
|
96
|
+
end
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Ea
|
|
4
|
+
module Svg
|
|
5
|
+
module EaEmitter
|
|
6
|
+
module Compartment
|
|
7
|
+
# Instance-name underline for object diagrams. EA draws a
|
|
8
|
+
# short horizontal line just below each instance name to
|
|
9
|
+
# denote that it is an instance (UML convention). Rendered
|
|
10
|
+
# only when the diagram's `diagram_type` is "Object".
|
|
11
|
+
module InstanceUnderline
|
|
12
|
+
Y_OFFSET = 2
|
|
13
|
+
WIDTH_FACTOR = 0.65
|
|
14
|
+
|
|
15
|
+
module_function
|
|
16
|
+
|
|
17
|
+
def render(context)
|
|
18
|
+
return nil unless context.diagram
|
|
19
|
+
return nil unless object_diagram?(context)
|
|
20
|
+
return nil if context.header_lines.empty?
|
|
21
|
+
|
|
22
|
+
name_line = context.header_lines.last
|
|
23
|
+
text = name_line.first.to_s
|
|
24
|
+
return nil if text.empty?
|
|
25
|
+
|
|
26
|
+
underline_path(context, text)
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def object_diagram?(context)
|
|
30
|
+
context.diagram && context.diagram.diagram_type == "Object"
|
|
31
|
+
end
|
|
32
|
+
module_function :object_diagram?
|
|
33
|
+
|
|
34
|
+
def underline_path(context, text)
|
|
35
|
+
bounds = context.bounds
|
|
36
|
+
text_width = TextRenderer.estimate_width(text, context.size,
|
|
37
|
+
WIDTH_FACTOR)
|
|
38
|
+
x_start = bounds.x + (bounds.width - text_width) / 2.0
|
|
39
|
+
y_pos = context.geometry.header_first_y + Y_OFFSET
|
|
40
|
+
build_path_tag(x_start, y_pos, text_width)
|
|
41
|
+
end
|
|
42
|
+
module_function :underline_path
|
|
43
|
+
|
|
44
|
+
def build_path_tag(x_start, y_pos, text_width)
|
|
45
|
+
x_end = x_start + text_width
|
|
46
|
+
coords = format_coords(x_start, y_pos, x_end)
|
|
47
|
+
d = "M #{coords[:x1]} #{coords[:y1]} L #{coords[:x2]} #{coords[:y1]}"
|
|
48
|
+
style = "stroke-width:1;stroke-linecap:square;" \
|
|
49
|
+
"stroke-linejoin:miter; fill:none; stroke:#000000;" \
|
|
50
|
+
" stroke-opacity:1.00"
|
|
51
|
+
%(<g style="#{style}">\n <path d="#{d}" shape-rendering="auto"/>\n</g>)
|
|
52
|
+
end
|
|
53
|
+
module_function :build_path_tag
|
|
54
|
+
|
|
55
|
+
def format_coords(x_start, y_pos, x_end)
|
|
56
|
+
{
|
|
57
|
+
x1: Ea::Svg::EaEmitter::Canvas.coord(x_start),
|
|
58
|
+
x2: Ea::Svg::EaEmitter::Canvas.coord(x_end),
|
|
59
|
+
y1: Ea::Svg::EaEmitter::Canvas.coord(y_pos)
|
|
60
|
+
}
|
|
61
|
+
end
|
|
62
|
+
module_function :format_coords
|
|
63
|
+
end
|
|
64
|
+
end
|
|
65
|
+
end
|
|
66
|
+
end
|
|
67
|
+
end
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Ea
|
|
4
|
+
module Svg
|
|
5
|
+
module EaEmitter
|
|
6
|
+
module Compartment
|
|
7
|
+
# Note body text wrapped inside a Note element's bounds.
|
|
8
|
+
# Renders only when the host element is a Note with a
|
|
9
|
+
# non-empty body.
|
|
10
|
+
module NoteBody
|
|
11
|
+
module_function
|
|
12
|
+
|
|
13
|
+
def render(context)
|
|
14
|
+
return nil if context.model_element.is_a?(Ea::Model::Note) &&
|
|
15
|
+
context.model_element.legend
|
|
16
|
+
|
|
17
|
+
body = context.note_body
|
|
18
|
+
return nil unless body
|
|
19
|
+
|
|
20
|
+
text_blocks = wrapped_lines(context, body)
|
|
21
|
+
%(<g style="#{group_style(context)}">\n#{text_blocks.join("\n")}\n</g>)
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def wrapped_lines(context, body)
|
|
25
|
+
max_chars = [(context.bounds.width / (context.size * 0.6)).floor, 10].max
|
|
26
|
+
body.to_s.split(/\n/).flat_map do |para|
|
|
27
|
+
para.gsub(/(.{1,#{max_chars}})(\s+|$)/, "\\1\n").strip.split(/\n/)
|
|
28
|
+
end.each_with_index.map do |line, idx|
|
|
29
|
+
y = context.bounds.y + context.theme.note.text_y_offset +
|
|
30
|
+
(idx * context.theme.note.line_height)
|
|
31
|
+
TextRenderer.new(
|
|
32
|
+
content: line,
|
|
33
|
+
x: context.bounds.x + context.theme.note.text_x_offset,
|
|
34
|
+
y: y,
|
|
35
|
+
family: context.family, size: context.size, size_unit: context.size_unit,
|
|
36
|
+
fill: context.theme.text_color,
|
|
37
|
+
stroke_in_text: context.theme.stroke_in_text_color,
|
|
38
|
+
width_factor: context.theme.text_width_factor
|
|
39
|
+
).to_svg
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
def group_style(context)
|
|
44
|
+
"stroke-width:1;stroke-linecap:round;stroke-linejoin:bevel; " \
|
|
45
|
+
"fill:#{context.theme.text_color};fill-opacity:1.00; " \
|
|
46
|
+
"stroke:#000000; stroke-opacity:0.00"
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
end
|