ea 0.4.0 → 0.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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/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 +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 +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 +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 +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/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/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/tagged_values.rb +30 -0
- data/lib/ea/svg/ea_emitter/compartment.rb +58 -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 +15 -24
- 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 +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/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 +449 -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,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
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Ea
|
|
4
|
+
module Svg
|
|
5
|
+
module EaEmitter
|
|
6
|
+
module Compartment
|
|
7
|
+
# Note text compartment. When diagram.show_notes is true,
|
|
8
|
+
# renders the classifier's documentation note (from
|
|
9
|
+
# t_object.Note) as wrapped text lines in the element body.
|
|
10
|
+
# Lines are estimated by character width and split at word
|
|
11
|
+
# boundaries to fit the element bounds.
|
|
12
|
+
module NoteText
|
|
13
|
+
X_PADDING = 5
|
|
14
|
+
Y_FIRST_OFFSET = 15
|
|
15
|
+
LINE_OFFSET = 13
|
|
16
|
+
CHAR_WIDTH_FACTOR = 0.55
|
|
17
|
+
|
|
18
|
+
module_function
|
|
19
|
+
|
|
20
|
+
def render(context)
|
|
21
|
+
return nil unless show_notes?(context)
|
|
22
|
+
return nil unless context.classifier&.is_a?(Ea::Model::Classifier)
|
|
23
|
+
|
|
24
|
+
notes = note_bodies(context.classifier)
|
|
25
|
+
return nil if notes.empty?
|
|
26
|
+
|
|
27
|
+
first_y = context.geometry.attr_first_y + Y_FIRST_OFFSET
|
|
28
|
+
bounds = context.bounds
|
|
29
|
+
fill = context.theme.attribute_text_color
|
|
30
|
+
usable_width = bounds.width - (X_PADDING * 2)
|
|
31
|
+
max_chars = (usable_width / (context.size * CHAR_WIDTH_FACTOR)).floor
|
|
32
|
+
|
|
33
|
+
texts = []
|
|
34
|
+
y = first_y
|
|
35
|
+
notes.each do |body|
|
|
36
|
+
wrapped_lines(body, max_chars).each do |line|
|
|
37
|
+
texts << build_text(line, bounds.x + X_PADDING, y, context, fill)
|
|
38
|
+
y += LINE_OFFSET
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
wrap_group(texts.join("\n"), fill)
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
def show_notes?(context)
|
|
45
|
+
context.diagram && context.diagram.show_notes
|
|
46
|
+
end
|
|
47
|
+
module_function :show_notes?
|
|
48
|
+
|
|
49
|
+
def note_bodies(classifier)
|
|
50
|
+
(classifier.annotations || []).filter_map do |a|
|
|
51
|
+
body = a.body.to_s.strip
|
|
52
|
+
body.empty? ? nil : body
|
|
53
|
+
end
|
|
54
|
+
end
|
|
55
|
+
module_function :note_bodies
|
|
56
|
+
|
|
57
|
+
# Word-wrap text at max_chars, preserving word boundaries.
|
|
58
|
+
def wrapped_lines(text, max_chars)
|
|
59
|
+
return [text] if text.length <= max_chars
|
|
60
|
+
|
|
61
|
+
words = text.split(" ")
|
|
62
|
+
lines = []
|
|
63
|
+
current = ""
|
|
64
|
+
words.each do |word|
|
|
65
|
+
if current.empty?
|
|
66
|
+
current = word
|
|
67
|
+
elsif (current + " " + word).length <= max_chars
|
|
68
|
+
current = "#{current} #{word}"
|
|
69
|
+
else
|
|
70
|
+
lines << current
|
|
71
|
+
current = word
|
|
72
|
+
end
|
|
73
|
+
end
|
|
74
|
+
lines << current unless current.empty?
|
|
75
|
+
lines
|
|
76
|
+
end
|
|
77
|
+
module_function :wrapped_lines
|
|
78
|
+
|
|
79
|
+
def build_text(content, x_pos, y_pos, context, fill)
|
|
80
|
+
TextRenderer.new(
|
|
81
|
+
content: content,
|
|
82
|
+
x: x_pos, y: y_pos,
|
|
83
|
+
family: context.family, size: context.size,
|
|
84
|
+
size_unit: context.size_unit, fill: fill,
|
|
85
|
+
style: "italic"
|
|
86
|
+
).to_svg
|
|
87
|
+
end
|
|
88
|
+
module_function :build_text
|
|
89
|
+
|
|
90
|
+
def wrap_group(body, fill)
|
|
91
|
+
style = "stroke-width:1;stroke-linecap:round;" \
|
|
92
|
+
"stroke-linejoin:bevel; fill:#{fill};" \
|
|
93
|
+
"fill-opacity:1.00; stroke:#000000;" \
|
|
94
|
+
" stroke-opacity:0.00"
|
|
95
|
+
%(<g style="#{style}">\n#{body}\n</g>)
|
|
96
|
+
end
|
|
97
|
+
module_function :wrap_group
|
|
98
|
+
end
|
|
99
|
+
end
|
|
100
|
+
end
|
|
101
|
+
end
|
|
102
|
+
end
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Ea
|
|
4
|
+
module Svg
|
|
5
|
+
module EaEmitter
|
|
6
|
+
module Compartment
|
|
7
|
+
# Operation compartment: divider line + operation signatures.
|
|
8
|
+
# Skipped when no operations or when geometry cannot fit them.
|
|
9
|
+
module Operations
|
|
10
|
+
module_function
|
|
11
|
+
|
|
12
|
+
def render(context)
|
|
13
|
+
return nil unless context.op_lines.any?
|
|
14
|
+
return nil unless context.geometry.op_first_y
|
|
15
|
+
return nil unless context.classifier
|
|
16
|
+
|
|
17
|
+
parts = []
|
|
18
|
+
if context.attr_lines.any?
|
|
19
|
+
parts << Element::DividerRenderer.render(
|
|
20
|
+
context.bounds,
|
|
21
|
+
y: context.geometry.op_divider_y,
|
|
22
|
+
stroke: context.stroke,
|
|
23
|
+
stroke_width: context.stroke_width
|
|
24
|
+
)
|
|
25
|
+
end
|
|
26
|
+
parts << Element::OperationRenderer.render(
|
|
27
|
+
context.classifier.operations,
|
|
28
|
+
bounds: context.bounds,
|
|
29
|
+
first_y: context.geometry.op_first_y,
|
|
30
|
+
family: context.family, size: context.size
|
|
31
|
+
)
|
|
32
|
+
parts.join("\n")
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
end
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Ea
|
|
4
|
+
module Svg
|
|
5
|
+
module EaEmitter
|
|
6
|
+
module Compartment
|
|
7
|
+
# Package-contents compartment. Renders the package's child
|
|
8
|
+
# classifiers and sub-packages as a list of "+ Name" rows in
|
|
9
|
+
# the body, matching EA's package-on-diagram rendering. Each
|
|
10
|
+
# row also draws a small per-type icon to the left of the
|
|
11
|
+
# text (Enumeration gets a list-style icon; other classifiers
|
|
12
|
+
# get the "folded paper" silhouette).
|
|
13
|
+
module PackageContents
|
|
14
|
+
ROW_HEIGHT = 16
|
|
15
|
+
ICON_X_OFFSET = 5
|
|
16
|
+
TEXT_X_OFFSET = 23
|
|
17
|
+
|
|
18
|
+
module_function
|
|
19
|
+
|
|
20
|
+
def render(context)
|
|
21
|
+
rows = context.package_content_lines
|
|
22
|
+
return nil if rows.nil? || rows.empty?
|
|
23
|
+
|
|
24
|
+
bounds = context.bounds
|
|
25
|
+
first_y = context.geometry.attr_first_y
|
|
26
|
+
blocks = rows.each_with_index.flat_map do |row, idx|
|
|
27
|
+
y_top = first_y - 11 + (idx * ROW_HEIGHT)
|
|
28
|
+
y_text = first_y + (idx * ROW_HEIGHT)
|
|
29
|
+
[
|
|
30
|
+
icon_block(bounds, y_top, row.kind),
|
|
31
|
+
text_block(bounds, y_text, row.name, context)
|
|
32
|
+
]
|
|
33
|
+
end
|
|
34
|
+
wrap_group(blocks.join("\n"))
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
def wrap_group(body)
|
|
38
|
+
%(<g style="#{group_style}">\n#{body}\n</g>)
|
|
39
|
+
end
|
|
40
|
+
module_function :wrap_group
|
|
41
|
+
|
|
42
|
+
def group_style
|
|
43
|
+
"stroke-width:1;stroke-linecap:square;stroke-linejoin:bevel; " \
|
|
44
|
+
"fill-opacity:1.00; stroke-opacity:1.00"
|
|
45
|
+
end
|
|
46
|
+
module_function :group_style
|
|
47
|
+
|
|
48
|
+
def icon_block(bounds, y_top, kind)
|
|
49
|
+
Element::RowIconRenderer.render(
|
|
50
|
+
x_pos: bounds.x + ICON_X_OFFSET,
|
|
51
|
+
y_pos: y_top,
|
|
52
|
+
kind: kind || :default
|
|
53
|
+
)
|
|
54
|
+
end
|
|
55
|
+
module_function :icon_block
|
|
56
|
+
|
|
57
|
+
def text_block(bounds, y, name, context)
|
|
58
|
+
TextRenderer.new(
|
|
59
|
+
content: "+ #{name}",
|
|
60
|
+
x: bounds.x + TEXT_X_OFFSET,
|
|
61
|
+
y: y,
|
|
62
|
+
family: context.family, size: context.size,
|
|
63
|
+
size_unit: context.size_unit,
|
|
64
|
+
fill: context.theme.attribute_text_color
|
|
65
|
+
).to_svg
|
|
66
|
+
end
|
|
67
|
+
module_function :text_block
|
|
68
|
+
end
|
|
69
|
+
end
|
|
70
|
+
end
|
|
71
|
+
end
|
|
72
|
+
end
|
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Ea
|
|
4
|
+
module Svg
|
|
5
|
+
module EaEmitter
|
|
6
|
+
module Compartment
|
|
7
|
+
# Renders the "(from ParentPackage)" italic subtitle inside
|
|
8
|
+
# a Package element's body. EA emits this when a package is
|
|
9
|
+
# placed on a diagram whose own package is NOT the package's
|
|
10
|
+
# parent — the subtitle shows the package's actual parent
|
|
11
|
+
# context so the reader can locate it in the model tree.
|
|
12
|
+
#
|
|
13
|
+
# Format: italic, small font, centered horizontally in the
|
|
14
|
+
# element body, positioned near the bottom of the body.
|
|
15
|
+
module PackageFromParent
|
|
16
|
+
Y_OFFSET_FROM_BOTTOM = 5
|
|
17
|
+
|
|
18
|
+
module_function
|
|
19
|
+
|
|
20
|
+
def render(context)
|
|
21
|
+
pkg = context.model_element
|
|
22
|
+
return nil unless pkg.is_a?(Ea::Model::Package)
|
|
23
|
+
|
|
24
|
+
parent_name = parent_name_for(pkg, context)
|
|
25
|
+
return nil if parent_name.nil? || parent_name.empty?
|
|
26
|
+
|
|
27
|
+
subtitle = "(from #{parent_name})"
|
|
28
|
+
bounds = context.bounds
|
|
29
|
+
fill = context.theme.attribute_text_color
|
|
30
|
+
y = bounds.y + bounds.height - Y_OFFSET_FROM_BOTTOM
|
|
31
|
+
estimated_width = subtitle.length * context.size * 0.5
|
|
32
|
+
x = bounds.x + (bounds.width - estimated_width) / 2.0
|
|
33
|
+
text = TextRenderer.new(
|
|
34
|
+
content: subtitle, x: x, y: y,
|
|
35
|
+
family: context.family, size: context.size,
|
|
36
|
+
size_unit: context.size_unit, fill: fill,
|
|
37
|
+
style: "italic"
|
|
38
|
+
).to_svg
|
|
39
|
+
wrap(text, fill)
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
# Resolves the package's parent's name via the model index.
|
|
43
|
+
# Returns nil when:
|
|
44
|
+
# - the package has no parent
|
|
45
|
+
# - the parent IS the diagram's own package (already in context)
|
|
46
|
+
# - the parent is ALSO placed on the current diagram
|
|
47
|
+
# - every placed Package on the diagram shares the same
|
|
48
|
+
# parent_id (diagram is implicitly about that parent's
|
|
49
|
+
# children — EA omits the subtitle as redundant)
|
|
50
|
+
# - the parent's name equals the placed package's name
|
|
51
|
+
# (e.g. an inner "3D都市モデル" nested inside an outer
|
|
52
|
+
# "3D都市モデル" — the subtitle would be tautological)
|
|
53
|
+
# - the diagram's name contains any placed Package's name
|
|
54
|
+
# as a substring (the diagram is implicitly "about" that
|
|
55
|
+
# package — subtitles would be redundant). Verified
|
|
56
|
+
# against plateau's "3D都市モデル応用スキーマと他のスキーマとの関係"
|
|
57
|
+
# diagram, which contains the placed name "3D都市モデル"
|
|
58
|
+
# and renders 0 subtitles in EA's reference.
|
|
59
|
+
def parent_name_for(pkg, context)
|
|
60
|
+
parent_id = pkg.parent_id
|
|
61
|
+
return nil if parent_id.nil? || parent_id.empty?
|
|
62
|
+
return nil if parent_id == context.diagram&.package_id
|
|
63
|
+
return nil if parent_on_diagram?(parent_id, context)
|
|
64
|
+
return nil if uniform_package_parent?(context)
|
|
65
|
+
return nil if diagram_name_contains_placed_package?(context)
|
|
66
|
+
|
|
67
|
+
parent = context.model_index_for(parent_id)
|
|
68
|
+
return nil unless parent.is_a?(Ea::Model::Package)
|
|
69
|
+
return nil if parent.name.to_s == pkg.name.to_s
|
|
70
|
+
|
|
71
|
+
parent.name.to_s.empty? ? nil : parent.name
|
|
72
|
+
end
|
|
73
|
+
module_function :parent_name_for
|
|
74
|
+
|
|
75
|
+
# Returns true when the diagram has 2+ placed Packages and
|
|
76
|
+
# every placed Package shares the same parent_id. EA treats
|
|
77
|
+
# such diagrams as "children of X" overviews and suppresses
|
|
78
|
+
# the (from X) subtitle on every element.
|
|
79
|
+
def uniform_package_parent?(context)
|
|
80
|
+
diagram = context.diagram
|
|
81
|
+
return false unless diagram && context.model_index
|
|
82
|
+
|
|
83
|
+
placed_pkg_parents = (diagram.elements || []).filter_map do |el|
|
|
84
|
+
me = context.model_index[el.model_element_ref]
|
|
85
|
+
next nil unless me.is_a?(Ea::Model::Package)
|
|
86
|
+
|
|
87
|
+
me.parent_id
|
|
88
|
+
end
|
|
89
|
+
placed_pkg_parents.size > 1 && placed_pkg_parents.uniq.size == 1
|
|
90
|
+
end
|
|
91
|
+
module_function :uniform_package_parent?
|
|
92
|
+
|
|
93
|
+
def parent_on_diagram?(parent_id, context)
|
|
94
|
+
diagram = context.diagram
|
|
95
|
+
return false unless diagram
|
|
96
|
+
|
|
97
|
+
(diagram.elements || []).any? do |e|
|
|
98
|
+
e.model_element_ref == parent_id
|
|
99
|
+
end
|
|
100
|
+
end
|
|
101
|
+
module_function :parent_on_diagram?
|
|
102
|
+
|
|
103
|
+
# Returns true when the diagram's name contains any placed
|
|
104
|
+
# Package's name as a substring. EA omits all subtitles in
|
|
105
|
+
# such diagrams — the name itself signals which package is
|
|
106
|
+
# the subject, making subtitles redundant.
|
|
107
|
+
def diagram_name_contains_placed_package?(context)
|
|
108
|
+
diagram = context.diagram
|
|
109
|
+
return false unless diagram && context.model_index
|
|
110
|
+
|
|
111
|
+
name = diagram.name.to_s
|
|
112
|
+
return false if name.empty?
|
|
113
|
+
|
|
114
|
+
(diagram.elements || []).any? do |el|
|
|
115
|
+
me = context.model_index[el.model_element_ref]
|
|
116
|
+
next false unless me.is_a?(Ea::Model::Package)
|
|
117
|
+
|
|
118
|
+
pkg_name = me.name.to_s
|
|
119
|
+
!pkg_name.empty? && name.include?(pkg_name)
|
|
120
|
+
end
|
|
121
|
+
end
|
|
122
|
+
module_function :diagram_name_contains_placed_package?
|
|
123
|
+
|
|
124
|
+
def wrap(body, fill)
|
|
125
|
+
group_style = "stroke-width:1;stroke-linecap:round;" \
|
|
126
|
+
"stroke-linejoin:bevel; fill:#{fill};" \
|
|
127
|
+
"fill-opacity:1.00; stroke:#000000;" \
|
|
128
|
+
" stroke-opacity:0.00"
|
|
129
|
+
%(<g style="#{group_style}">\n#{body}\n</g>)
|
|
130
|
+
end
|
|
131
|
+
module_function :wrap
|
|
132
|
+
end
|
|
133
|
+
end
|
|
134
|
+
end
|
|
135
|
+
end
|
|
136
|
+
end
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Ea
|
|
4
|
+
module Svg
|
|
5
|
+
module EaEmitter
|
|
6
|
+
module Compartment
|
|
7
|
+
# Element shape: stroked rect for classifiers, folder
|
|
8
|
+
# silhouette for packages, note silhouette for notes.
|
|
9
|
+
module Shape
|
|
10
|
+
module_function
|
|
11
|
+
|
|
12
|
+
def render(context)
|
|
13
|
+
if legend?(context)
|
|
14
|
+
Element::LegendRenderer.render(
|
|
15
|
+
context.bounds,
|
|
16
|
+
legend: context.model_element.legend,
|
|
17
|
+
family: context.family,
|
|
18
|
+
canvas: context.canvas
|
|
19
|
+
)
|
|
20
|
+
elsif context.model_element.is_a?(Ea::Model::Package) ||
|
|
21
|
+
context.model_element.is_a?(Ea::Model::Note)
|
|
22
|
+
label = package_label(context.model_element)
|
|
23
|
+
stereotype = package_stereotype(context.model_element)
|
|
24
|
+
Element::PackageShapeRenderer.render(
|
|
25
|
+
context.bounds,
|
|
26
|
+
fill: context.fill, stroke: context.stroke,
|
|
27
|
+
stroke_width: context.stroke_width,
|
|
28
|
+
label: label,
|
|
29
|
+
stereotype: stereotype,
|
|
30
|
+
family: context.family, size: context.size,
|
|
31
|
+
size_unit: context.size_unit,
|
|
32
|
+
text_fill: context.text_fill
|
|
33
|
+
)
|
|
34
|
+
elsif hand_draw?(context)
|
|
35
|
+
Element::HandDrawShapeRenderer.render(
|
|
36
|
+
context.bounds,
|
|
37
|
+
fill: context.fill, stroke: context.stroke,
|
|
38
|
+
stroke_width: context.stroke_width
|
|
39
|
+
)
|
|
40
|
+
else
|
|
41
|
+
Element::ShapeRenderer.render(
|
|
42
|
+
context.bounds,
|
|
43
|
+
fill: context.fill, stroke: context.stroke,
|
|
44
|
+
stroke_width: context.stroke_width
|
|
45
|
+
)
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
# A Text element with LegendOpts= renders as the legend
|
|
50
|
+
# block rather than a folder silhouette. Dispatch on the
|
|
51
|
+
# presence of the attached Legend payload.
|
|
52
|
+
def legend?(context)
|
|
53
|
+
context.model_element.is_a?(Ea::Model::Note) &&
|
|
54
|
+
context.model_element.legend
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
# HandDraw=1 in the diagram StyleEx switches every element
|
|
58
|
+
# to EA's hand-drawn wavy silhouette.
|
|
59
|
+
def hand_draw?(context)
|
|
60
|
+
context.diagram && context.diagram.hand_draw
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
def package_label(model_element)
|
|
64
|
+
model_element.name.to_s
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
# EA renders a package's applied stereotype above the name
|
|
68
|
+
# inside the tab area when one is set. Returns nil when no
|
|
69
|
+
# stereotype is applied (the common case).
|
|
70
|
+
def package_stereotype(model_element)
|
|
71
|
+
return nil unless model_element.is_a?(Ea::Model::Package)
|
|
72
|
+
|
|
73
|
+
refs = model_element.stereotype_refs
|
|
74
|
+
return nil unless refs&.any?
|
|
75
|
+
|
|
76
|
+
refs.first.to_s
|
|
77
|
+
end
|
|
78
|
+
end
|
|
79
|
+
end
|
|
80
|
+
end
|
|
81
|
+
end
|
|
82
|
+
end
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Ea
|
|
4
|
+
module Svg
|
|
5
|
+
module EaEmitter
|
|
6
|
+
module Compartment
|
|
7
|
+
# Tagged value compartment. Skipped when no tagged values
|
|
8
|
+
# or when geometry cannot fit them.
|
|
9
|
+
module TaggedValues
|
|
10
|
+
DEFAULT_TEXT_COLOR = "#000000"
|
|
11
|
+
|
|
12
|
+
module_function
|
|
13
|
+
|
|
14
|
+
def render(context)
|
|
15
|
+
return nil unless context.tagged_values.any?
|
|
16
|
+
return nil unless context.geometry.tagged_value_first_y
|
|
17
|
+
|
|
18
|
+
Element::TaggedValueRenderer.render(
|
|
19
|
+
context.tagged_values,
|
|
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,58 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Ea
|
|
4
|
+
module Svg
|
|
5
|
+
module EaEmitter
|
|
6
|
+
# Compartment pipeline. Each Compartment is a small,
|
|
7
|
+
# single-purpose renderer that decides whether it applies to
|
|
8
|
+
# the current RenderContext and, if so, emits its SVG layer.
|
|
9
|
+
#
|
|
10
|
+
# Adding a new compartment = adding a class to `COMPARTMENTS`.
|
|
11
|
+
# The Elements orchestrator does not change — OCP-friendly.
|
|
12
|
+
module Compartment
|
|
13
|
+
autoload :Shape, "ea/svg/ea_emitter/compartment/shape"
|
|
14
|
+
autoload :NoteBody, "ea/svg/ea_emitter/compartment/note_body"
|
|
15
|
+
autoload :Header, "ea/svg/ea_emitter/compartment/header"
|
|
16
|
+
autoload :HeaderDivider, "ea/svg/ea_emitter/compartment/header_divider"
|
|
17
|
+
autoload :Attributes, "ea/svg/ea_emitter/compartment/attributes"
|
|
18
|
+
autoload :Operations, "ea/svg/ea_emitter/compartment/operations"
|
|
19
|
+
autoload :EnumLiterals, "ea/svg/ea_emitter/compartment/enum_literals"
|
|
20
|
+
autoload :TaggedValues, "ea/svg/ea_emitter/compartment/tagged_values"
|
|
21
|
+
autoload :Constraints, "ea/svg/ea_emitter/compartment/constraints"
|
|
22
|
+
autoload :PackageContents, "ea/svg/ea_emitter/compartment/package_contents"
|
|
23
|
+
autoload :InstanceUnderline, "ea/svg/ea_emitter/compartment/instance_underline"
|
|
24
|
+
autoload :InstanceSlots, "ea/svg/ea_emitter/compartment/instance_slots"
|
|
25
|
+
autoload :NoteText, "ea/svg/ea_emitter/compartment/note_text"
|
|
26
|
+
autoload :PackageFromParent, "ea/svg/ea_emitter/compartment/package_from_parent"
|
|
27
|
+
|
|
28
|
+
# Order matters: EA emits compartments top-to-bottom inside
|
|
29
|
+
# each element group.
|
|
30
|
+
ALL = [
|
|
31
|
+
Shape,
|
|
32
|
+
NoteBody,
|
|
33
|
+
Header,
|
|
34
|
+
HeaderDivider,
|
|
35
|
+
Attributes,
|
|
36
|
+
Operations,
|
|
37
|
+
EnumLiterals,
|
|
38
|
+
TaggedValues,
|
|
39
|
+
Constraints,
|
|
40
|
+
PackageContents,
|
|
41
|
+
InstanceSlots,
|
|
42
|
+
NoteText,
|
|
43
|
+
PackageFromParent,
|
|
44
|
+
InstanceUnderline
|
|
45
|
+
].freeze
|
|
46
|
+
|
|
47
|
+
module_function
|
|
48
|
+
|
|
49
|
+
# Renders every applicable compartment for the context.
|
|
50
|
+
# Returns an Array of SVG strings (some may be nil; the
|
|
51
|
+
# caller compacts).
|
|
52
|
+
def render_all(context)
|
|
53
|
+
ALL.map { |compartment| compartment.render(context) }
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
end
|