ea 0.4.0 → 0.5.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +128 -1
- data/Rakefile +3 -0
- data/TODO.complete/01-t-xref-parsing.md +91 -0
- data/TODO.complete/02-per-label-geometry.md +50 -0
- data/TODO.complete/03-object-properties-constraints.md +57 -0
- data/TODO.complete/04-operation-params.md +37 -0
- data/TODO.complete/05-pdata-flag-matrix.md +52 -0
- data/TODO.complete/06-emf-image-rendering.md +34 -0
- data/TODO.complete/07-auxiliary-tables.md +47 -0
- data/TODO.complete/10-mdg-stereotype-registry.md +40 -0
- data/TODO.complete/11-gml-xsd-generation.md +42 -0
- data/TODO.complete/13-shapescript-interpreter.md +28 -0
- data/TODO.complete/20-cli-diff.md +46 -0
- data/TODO.complete/21-cli-render.md +26 -0
- data/TODO.complete/22-cli-export.md +29 -0
- data/TODO.complete/23-cli-mdg.md +23 -0
- data/TODO.complete/30-headerlines-ocp-refactor.md +72 -0
- data/TODO.complete/31-public-send-cleanup.md +61 -0
- data/TODO.complete/32-spec-coverage.md +33 -0
- data/TODO.complete/33-blocked-parity-gaps.md +41 -0
- data/TODO.complete/36-stereotype-icon-wiring.md +32 -0
- data/TODO.complete/37-cli-lint.md +32 -0
- data/TODO.complete/38-cli-query.md +26 -0
- data/TODO.complete/39-cli-info.md +23 -0
- data/TODO.complete/40-ocl-evaluator.md +31 -0
- data/TODO.complete/41-round-trip-spec.md +18 -0
- data/TODO.complete/42-html-diff-report.md +18 -0
- data/TODO.complete/43-json-schema-export.md +20 -0
- data/TODO.complete/44-remaining-qea-tables.md +40 -0
- data/TODO.complete/45-shapescript-extensions.md +25 -0
- data/TODO.complete/46-xsd-consolidation.md +20 -0
- data/TODO.complete/47-headerlines-legacy-removal.md +20 -0
- data/TODO.complete/51-remove-respond-to.md +25 -0
- data/TODO.complete/52-xsd-decouple-fixtures.md +23 -0
- data/TODO.complete/53-xmi-public-send-cleanup.md +26 -0
- data/TODO.complete/54-wire-stereotype-icon-renderer.md +20 -0
- data/TODO.complete/55-wire-shapescript.md +20 -0
- data/TODO.complete/56-wire-emf-renderer.md +27 -0
- data/TODO.complete/57-wire-ocl-evaluator.md +23 -0
- data/TODO.complete/58-diff-modifications.md +21 -0
- data/TODO.complete/59-delete-toy-xmi-export.md +30 -0
- data/TODO.complete/60-curate-json-export.md +20 -0
- data/TODO.complete/61-plantuml-relationships.md +22 -0
- data/TODO.complete/62-changelog.md +17 -0
- data/TODO.complete/63-dependabot-fix.md +18 -0
- data/TODO.complete/STATUS.md +85 -0
- data/TODO.diagrams/01-svg-measurement-harness.md +31 -0
- data/TODO.diagrams/02-polygon-over-rendering.md +29 -0
- data/TODO.diagrams/03-text-over-rendering.md +30 -0
- data/TODO.diagrams/04-rect-under-rendering.md +33 -0
- data/TODO.diagrams/05-canvas-dimension-parity.md +51 -0
- data/TODO.diagrams/06-group-layering-parity.md +39 -0
- data/TODO.diagrams/07-text-content-fidelity.md +65 -0
- data/TODO.diagrams/08-qea-direct-pipeline.md +46 -0
- data/TODO.diagrams/12-connector-labels.md +40 -0
- data/TODO.diagrams/12-per-entity-svg-layer-ordering.md +24 -0
- data/TODO.diagrams/13-marker-polygon-vs-path-dispatch.md +20 -0
- data/TODO.diagrams/13-per-text-type-font-sizes.md +33 -0
- data/TODO.diagrams/14-center-header-text.md +33 -0
- data/TODO.diagrams/14-filter-diagram-frame-elements.md +18 -0
- data/TODO.diagrams/15-deep-dead-code-audit.md +47 -0
- data/TODO.diagrams/15-per-element-font-from-style.md +24 -0
- data/TODO.diagrams/16-canvas-marker-extent.md +30 -0
- data/TODO.diagrams/16-document-remaining-parity-gaps.md +91 -0
- data/TODO.diagrams/17-italic-abstract-classes.md +28 -0
- data/TODO.diagrams/17-remaining-parity-gaps.md +90 -0
- data/TODO.diagrams/18-canvas-from-image-bounds.md +20 -0
- data/TODO.diagrams/18-property-lookup-index.md +42 -0
- data/TODO.diagrams/19-connector-sx-sy-routing.md +27 -0
- data/TODO.diagrams/19-replace-respond-to-with-is-a.md +31 -0
- data/TODO.diagrams/20-split-labels-emitter.md +56 -0
- data/TODO.diagrams/20-visibility-glyph-font-encoding.md +27 -0
- data/TODO.diagrams/21-aggregation-navigability-arrow.md +21 -0
- data/TODO.diagrams/21-auto-generated-legend-block.md +65 -0
- data/TODO.diagrams/22-ghost-element-discriminator.md +57 -0
- data/TODO.diagrams/22-style-based-path-grouping.md +28 -0
- data/TODO.diagrams/23-marker-polygon-deduplication.md +47 -0
- data/TODO.diagrams/23-multiplicity-label-positioning.md +29 -0
- data/TODO.diagrams/24-marker-anchor-structural.md +35 -0
- data/TODO.diagrams/24-track-marker-anchors-structurally.md +66 -0
- data/TODO.diagrams/24-truncate-properties-to-fit-box.md +24 -0
- data/TODO.diagrams/26-phantom-general-parent-rendering.md +59 -0
- data/TODO.diagrams/27-path-grouping-mode-detection.md +43 -0
- data/TODO.diagrams/28-architecture-cleanup-batch.md +47 -0
- data/TODO.diagrams/30-decompose-elements-groups-for.md +52 -0
- data/TODO.diagrams/32-examples-coverage-batch.md +78 -0
- data/TODO.diagrams/36-instance-specification-model.md +42 -0
- data/TODO.diagrams/37-element-icon-decorations.md +41 -0
- data/TODO.diagrams/38-html-note-and-receptions.md +32 -0
- data/TODO.diagrams/39-property-stereotype-discriminator.md +40 -0
- data/TODO.diagrams/40-standalone-1-discriminator.md +38 -0
- data/TODO.diagrams/41-xmi-to-svg-pipeline.md +113 -0
- data/TODO.diagrams/42-close-all-parity-deltas.md +69 -0
- data/TODO.diagrams/43-marker-deduplication-strategy.md +54 -0
- data/TODO.diagrams/44-element-icon-decorations.md +34 -0
- data/TODO.diagrams/45-phantom-parent-class-boxes.md +40 -0
- data/TODO.diagrams/46-user-drawn-legend-swatches.md +44 -0
- data/TODO.diagrams/47-attribute-line-fidelity.md +72 -0
- data/TODO.diagrams/48-spec-coverage-critical-emitter-components.md +45 -0
- data/TODO.diagrams/49-spec-coverage-orchestrators.md +25 -0
- data/TODO.diagrams/50-examples-parity.md +85 -0
- data/TODO.diagrams/51-property-oy-gap-and-remaining-gaps.md +48 -0
- data/TODO.diagrams/52-marker-registration-architecture.md +89 -0
- data/TODO.diagrams/53-remaining-example-gaps.md +86 -0
- data/TODO.diagrams/54-display-name-nested-classes.md +40 -0
- data/TODO.diagrams/55-visibility-icon-discriminator.md +58 -0
- data/TODO.diagrams/56-package-contents-rendering.md +148 -0
- data/TODO.diagrams/57-instance-specification-model.md +100 -0
- data/TODO.diagrams/58-domain-model-note-text.md +67 -0
- data/TODO.diagrams/59-classes-arrow-discriminator.md +57 -0
- data/TODO.diagrams/60-testschema-association-marker.md +40 -0
- data/TODO.diagrams/61-legend-block-rendering.md +55 -0
- data/TODO.diagrams/61-plateau-parity-gaps.md +59 -0
- data/TODO.diagrams/62-ghost-element-rendering.md +56 -0
- data/TODO.diagrams/63-qualified-name-wrap.md +36 -0
- data/TODO.diagrams/64-property-stereotype-labels.md +22 -0
- data/TODO.diagrams/65-path-coordinate-frame.md +62 -0
- data/TODO.diagrams/67-path-coordinate-frame.md +62 -0
- data/TODO.diagrams/68-inherited-attributes.md +65 -0
- data/TODO.diagrams/69-package-anchor-conditional.md +29 -0
- data/TODO.diagrams/70-mdg-technology-support.md +68 -0
- data/TODO.diagrams/71-off-canvas-parent-ghost.md +45 -0
- data/TODO.diagrams/72-basic-attr-divider-paths.md +39 -0
- data/TODO.diagrams/73-plateau-polygon-gap.md +69 -0
- data/TODO.diagrams/74-plateau-rect-gap.md +22 -0
- data/TODO.diagrams/75-plateau-text-gap.md +39 -0
- data/TODO.diagrams/76-basic-poly-path-gaps.md +41 -0
- data/TODO.diagrams/77-basic-text-overrender.md +40 -0
- data/TODO.diagrams/78-headerlines-ocp-refactor.md +65 -0
- data/TODO.diagrams/79-architecture-backlog.md +65 -0
- data/TODO.diagrams/80-basic-triangle-polygons.md +51 -0
- data/TODO.diagrams/81-plateau-path-overrender.md +53 -0
- data/TODO.diagrams/82-appearance-canvas-offset.md +54 -0
- data/TODO.diagrams/83-3d-diagram-subtitle.md +58 -0
- data/TODO.diagrams/84-canvas-offset-mismatches.md +61 -0
- data/TODO.diagrams/85-phantom-property-overrender.md +95 -0
- data/TODO.diagrams/86-foreign-package-rule.md +62 -0
- data/TODO.diagrams/87-internal-tech-encryption.md +80 -0
- data/TODO.diagrams/EXAMPLES_STATUS.md +88 -0
- data/TODO.diagrams/README.md +69 -0
- data/TODO.diagrams/STATUS.md +73 -0
- data/TODO.fixup/01-default-grouped-paths.md +34 -0
- data/TODO.fixup/02-marker-consolidation-per-connector.md +20 -0
- data/TODO.fixup/03-diagram-font-inference.md +28 -0
- data/TODO.fixup/04-extract-bounds-calculator.md +25 -0
- data/TODO.fixup/05-marker-registry-ocp.md +32 -0
- data/TODO.fixup/06-connector-path-bend-routing.md +28 -0
- data/TODO.fixup/07-edge-attachment-formula.md +22 -0
- data/TODO.fixup/08-visual-diff-harness.md +28 -0
- data/TODO.fixup/09-extract-element-compartments.md +34 -0
- data/TODO.fixup/10-canvas-width-overshoot-fix.md +20 -0
- data/TODO.fixup/11-layer-sequencer-extraction.md +18 -0
- data/TODO.fixup/12-path-style-harmony.md +23 -0
- data/TODO.fixup/13-datatype-stereotype-fallback.md +28 -0
- data/TODO.fixup/14-ea-exe-reverse-engineering-notes.md +56 -0
- data/TODO.fixup/15-enumeration-literal-rendering.md +30 -0
- data/TODO.fixup/16-operation-compartment-rendering.md +42 -0
- data/TODO.fixup/17-path-count-calibration.md +27 -0
- data/TODO.fixup/18-polygon-count-calibration.md +32 -0
- data/TODO.fixup/19-rect-count-undershoot-investigation.md +40 -0
- data/TODO.fixup/20-stereotype-color-from-classifier.md +18 -0
- data/TODO.fixup/21-visibility-filter-for-properties.md +24 -0
- data/TODO.fixup/22-multiplicity-display-rule-calibration.md +25 -0
- data/TODO.fixup/23-diagram-frame-title-element.md +31 -0
- data/TODO.fixup/24-note-element-rendering.md +23 -0
- data/TODO.fixup/25-ea-exe-disassembly-findings.md +177 -0
- data/TODO.fixup/26-svg-renderer-architecture.md +78 -0
- data/TODO.fixup/27-svg-element-emitters-disassembly.md +135 -0
- data/TODO.fixup/28-geometry-parser-identification.md +57 -0
- data/TODO.fixup/29-qea-svg-xmi-triple-comparison.md +185 -0
- data/TODO.fixup/30-theme-system-stub.md +46 -0
- data/TODO.fixup/31-theme-value-object-registry.md +17 -0
- data/TODO.fixup/32-styleex-on-diagram-model.md +22 -0
- data/TODO.fixup/33-text-encoding-decimals-rotation.md +29 -0
- data/TODO.fixup/34-per-type-fill-via-theme.md +18 -0
- data/TODO.fixup/35-stroke-width-per-theme.md +7 -0
- data/TODO.fixup/36-qea-rect-coord-normalization.md +24 -0
- data/TODO.fixup/37-package-shape-rendering.md +22 -0
- data/TODO.fixup/38-note-element-rendering.md +15 -0
- data/TODO.fixup/39-styleex-flag-honoring.md +25 -0
- data/TODO.fixup/40-connector-dashed-lines.md +15 -0
- data/TODO.fixup/41-diagram-frame-showborder-detection.md +23 -0
- data/TODO.fixup/42-textrenderer-centralization.md +10 -0
- data/TODO.fixup/43-colorresolver-unification.md +24 -0
- data/TODO.fixup/44-theme-aware-textrenderer.md +17 -0
- data/TODO.fixup/45-theme-aware-fontresolver.md +22 -0
- data/TODO.fixup/46-style-parameterized-by-theme.md +21 -0
- data/TODO.fixup/47-canvas-frame-inset.md +19 -0
- data/TODO.fixup/48-background-rect-format.md +15 -0
- data/TODO.fixup/49-all-samples-integration-test.md +17 -0
- data/TODO.fixup/50-svg-emitter-architecture-docs.md +33 -0
- data/TODO.fixup/51-promote-theme-to-ea-namespace.md +28 -0
- data/TODO.fixup/52-theme-definition-integrated-fills.md +26 -0
- data/TODO.fixup/53-theme-registry-yaml-loading.md +50 -0
- data/TODO.fixup/54-diagram-theme-api.md +50 -0
- data/TODO.fixup/55-update-eaemitter-to-ea-theme.md +23 -0
- data/TODO.fixup/56-theme-yaml-files.md +65 -0
- data/TODO.fixup/57-theme-specs-and-integration.md +27 -0
- data/TODO.fixup/58-ea-entry-point-theme-autoload.md +20 -0
- data/TODO.fixup/59-thread-theme-through-all-renderers.md +29 -0
- data/TODO.fixup/60-cli-theme-option.md +22 -0
- data/TODO.fixup/61-theme-validation.md +28 -0
- data/TODO.fixup/62-theme-builder-dsl.md +31 -0
- data/TODO.fixup/63-theme-integration-rendering-spec.md +24 -0
- data/TODO.fixup/64-theme-writeback-styleex.md +21 -0
- data/TODO.fixup/65-remove-dead-eaemitter-theme-files.md +30 -0
- data/TODO.fixup/66-styleex-writeback.md +22 -0
- data/TODO.fixup/67-delete-dead-code.md +28 -0
- data/TODO.fixup/68-figure-parity-status.md +82 -0
- data/TODO.fixup/69-package-polygon-rendering.md +54 -0
- data/TODO.fixup/70-tagged-values-compartment.md +39 -0
- data/TODO.fixup/71-auto-detect-theme-from-xmi.md +37 -0
- data/TODO.fixup/72-sample-exports-as-regression-specs.md +37 -0
- data/TODO.fixup/73-delete-dead-transformations.md +14 -0
- data/TODO.fixup/74-delete-dead-diagram-renderers.md +18 -0
- data/TODO.fixup/75-visibility-legend-icons.md +23 -0
- data/TODO.fixup/76-plateau-text-undershoot.md +27 -0
- data/TODO.fixup/77-canvas-frame-margins.md +28 -0
- data/TODO.fixup/78-note-element-rendering.md +30 -0
- data/TODO.fixup/79-operation-compartment-rendering.md +27 -0
- data/TODO.fixup/80-tagged-value-stereotype-visibility.md +37 -0
- data/TODO.fixup/81-figure-parity-current-state.md +63 -0
- data/config/qea_schema.yml +356 -0
- data/config/themes/119.yml +98 -0
- data/config/themes/default.yml +14 -0
- data/examples/exports/20251010_current_plateau_v5/UML_EA.DTD +6856 -0
- data/examples/exports/20251010_current_plateau_v5/model.xml +96709 -0
- data/examples/exports/ArcGISWorkspace_template/UML_EA.DTD +6856 -0
- data/examples/exports/ArcGISWorkspace_template/model.xml +1427 -0
- data/examples/exports/UmlModel_template/UML_EA.DTD +6856 -0
- data/examples/exports/UmlModel_template/model.xml +23 -0
- data/examples/exports/basic/UML_EA.DTD +6856 -0
- data/examples/exports/basic/model.xml +8039 -0
- data/examples/exports/simple/UML_EA.DTD +6856 -0
- data/examples/exports/simple/model.xml +585 -0
- data/examples/exports/simple_example/UML_EA.DTD +6856 -0
- data/examples/exports/simple_example/model.xml +23 -0
- data/examples/exports/test/UML_EA.DTD +6856 -0
- data/examples/exports/test/model.xml +1638 -0
- data/examples/qea/basic.qea +0 -0
- data/frontend/README.md +51 -0
- data/frontend/dist/app.iife.js +24 -0
- data/frontend/dist/style.css +1 -0
- data/frontend/index.html +26 -0
- data/frontend/package-lock.json +2359 -0
- data/frontend/package.json +26 -0
- data/frontend/src/App.vue +59 -0
- data/frontend/src/app.ts +8 -0
- data/frontend/src/components/AppHeader.vue +127 -0
- data/frontend/src/components/AppSidebar.vue +119 -0
- data/frontend/src/components/ClassDetails.vue +247 -0
- data/frontend/src/components/DiagramView.vue +79 -0
- data/frontend/src/components/PackageDetails.vue +92 -0
- data/frontend/src/components/PackageTreeNode.vue +64 -0
- data/frontend/src/components/SearchResults.vue +48 -0
- data/frontend/src/components/WelcomeView.vue +87 -0
- data/frontend/src/shims-vue.d.ts +5 -0
- data/frontend/src/stores/dataStore.ts +79 -0
- data/frontend/src/stores/uiStore.ts +167 -0
- data/frontend/src/styles/main.css +1566 -0
- data/frontend/src/types.ts +221 -0
- data/frontend/tests/e2e/__screenshots__/new-dark-mode.png +0 -0
- data/frontend/tests/e2e/__screenshots__/new-package-details.png +0 -0
- data/frontend/tests/e2e/__screenshots__/new-search-modal.png +0 -0
- data/frontend/tests/e2e/__screenshots__/new-sidebar-collapsed.png +0 -0
- data/frontend/tests/e2e/__screenshots__/new-welcome.png +0 -0
- data/frontend/tests/e2e/render.spec.ts +188 -0
- data/frontend/tsconfig.json +20 -0
- data/frontend/vite.config.ts +26 -0
- data/frontend/vitest.config.ts +8 -0
- data/lib/ea/cli/app.rb +57 -2
- data/lib/ea/cli/command/diagrams.rb +37 -28
- data/lib/ea/cli/command/diff.rb +46 -0
- data/lib/ea/cli/command/export.rb +101 -0
- data/lib/ea/cli/command/info.rb +75 -0
- data/lib/ea/cli/command/lint.rb +48 -0
- data/lib/ea/cli/command/mdg.rb +98 -0
- data/lib/ea/cli/command/query.rb +34 -0
- data/lib/ea/cli/command/render.rb +135 -0
- data/lib/ea/cli/command/svg.rb +8 -15
- data/lib/ea/cli/command.rb +7 -0
- data/lib/ea/diagram/display_config.rb +184 -0
- data/lib/ea/diagram.rb +4 -41
- data/lib/ea/diff/change.rb +30 -0
- data/lib/ea/diff/comparator.rb +109 -0
- data/lib/ea/diff/html_reporter.rb +91 -0
- data/lib/ea/diff.rb +15 -0
- data/lib/ea/export/json/generator.rb +118 -0
- data/lib/ea/export/json.rb +12 -0
- data/lib/ea/export/json_schema/generator.rb +77 -0
- data/lib/ea/export/json_schema.rb +12 -0
- data/lib/ea/export/plantuml/generator.rb +140 -0
- data/lib/ea/export/plantuml.rb +12 -0
- data/lib/ea/export/xsd/class_mapping.rb +65 -0
- data/lib/ea/export/xsd/generator.rb +137 -0
- data/lib/ea/export/xsd/namespace_registry.rb +82 -0
- data/lib/ea/export/xsd.rb +19 -0
- data/lib/ea/export.rb +13 -0
- data/lib/ea/image/emf_renderer.rb +42 -0
- data/lib/ea/image.rb +12 -0
- data/lib/ea/lint/engine.rb +30 -0
- data/lib/ea/lint/lint_rule.rb +38 -0
- data/lib/ea/lint/offense.rb +18 -0
- data/lib/ea/lint/rules/cyclic_generalization.rb +62 -0
- data/lib/ea/lint/rules/duplicate_name.rb +28 -0
- data/lib/ea/lint/rules/missing_stereotype.rb +40 -0
- data/lib/ea/lint/rules/naming_convention.rb +44 -0
- data/lib/ea/lint/rules/orphan_element.rb +28 -0
- data/lib/ea/lint/rules.rb +14 -0
- data/lib/ea/lint.rb +13 -0
- data/lib/ea/mdg/document.rb +120 -0
- data/lib/ea/mdg/loader.rb +118 -0
- data/lib/ea/mdg/registry.rb +98 -0
- data/lib/ea/mdg/stereotype_alias_registry.rb +77 -0
- data/lib/ea/mdg/xml/applies_to.rb +18 -0
- data/lib/ea/mdg/xml/apply.rb +18 -0
- data/lib/ea/mdg/xml/content.rb +18 -0
- data/lib/ea/mdg/xml/documentation.rb +24 -0
- data/lib/ea/mdg/xml/stereotype.rb +28 -0
- data/lib/ea/mdg/xml/stereotypes.rb +18 -0
- data/lib/ea/mdg/xml/tag.rb +28 -0
- data/lib/ea/mdg/xml/tagged_values.rb +18 -0
- data/lib/ea/mdg/xml/technology.rb +28 -0
- data/lib/ea/mdg/xml/uml_profile.rb +22 -0
- data/lib/ea/mdg/xml/uml_profiles.rb +18 -0
- data/lib/ea/mdg/xml.rb +24 -0
- data/lib/ea/mdg.rb +25 -0
- data/lib/ea/model/classifier.rb +4 -0
- data/lib/ea/model/constraint.rb +24 -0
- data/lib/ea/model/diagram.rb +85 -0
- data/lib/ea/model/diagram_connector.rb +34 -0
- data/lib/ea/model/diagram_element.rb +16 -0
- data/lib/ea/model/document.rb +47 -2
- data/lib/ea/model/ghost_label.rb +32 -0
- data/lib/ea/model/instance_specification.rb +34 -0
- data/lib/ea/model/legend.rb +43 -0
- data/lib/ea/model/legend_item.rb +26 -0
- data/lib/ea/model/note.rb +28 -0
- data/lib/ea/model/operation.rb +2 -0
- data/lib/ea/model/property.rb +2 -0
- data/lib/ea/model/relationship.rb +2 -0
- data/lib/ea/model/signal.rb +14 -0
- data/lib/ea/model/slot.rb +19 -0
- data/lib/ea/model.rb +8 -0
- data/lib/ea/ocl/evaluator.rb +94 -0
- data/lib/ea/ocl/nodes.rb +30 -0
- data/lib/ea/ocl/parser.rb +133 -0
- data/lib/ea/ocl/unsupported_error.rb +7 -0
- data/lib/ea/ocl.rb +13 -0
- data/lib/ea/qea/factory/document_builder.rb +24 -10
- data/lib/ea/qea/factory/generalization_builder.rb +9 -11
- data/lib/ea/qea/infrastructure/table_reader.rb +9 -0
- data/lib/ea/qea/models/ea_author.rb +35 -0
- data/lib/ea/qea/models/ea_glossary.rb +34 -0
- data/lib/ea/qea/models/ea_image.rb +53 -0
- data/lib/ea/qea/models/ea_implement.rb +32 -0
- data/lib/ea/qea/models/ea_list.rb +42 -0
- data/lib/ea/qea/models/ea_object_effort.rb +34 -0
- data/lib/ea/qea/models/ea_object_problem.rb +37 -0
- data/lib/ea/qea/models/ea_object_require.rb +34 -0
- data/lib/ea/qea/models/ea_object_resource.rb +34 -0
- data/lib/ea/qea/models/ea_object_risk.rb +34 -0
- data/lib/ea/qea/models/ea_object_scenario.rb +34 -0
- data/lib/ea/qea/models/ea_object_test.rb +35 -0
- data/lib/ea/qea/models/ea_object_trx.rb +34 -0
- data/lib/ea/qea/models/ea_operation.rb +7 -0
- data/lib/ea/qea/models/ea_palette.rb +30 -0
- data/lib/ea/qea/models/ea_palette_item.rb +36 -0
- data/lib/ea/qea/models/ea_phase.rb +40 -0
- data/lib/ea/qea/models/ea_role_constraint.rb +32 -0
- data/lib/ea/qea/models/ea_secrypt.rb +34 -0
- data/lib/ea/qea/models/ea_version.rb +39 -0
- data/lib/ea/qea/models/ea_xref.rb +11 -1
- data/lib/ea/qea/models.rb +19 -0
- data/lib/ea/qea/services/database_loader.rb +22 -1
- data/lib/ea/qea/validation/database/ocl_constraint_validator.rb +65 -0
- data/lib/ea/qea/validation/database.rb +2 -0
- data/lib/ea/qea/validation/validation_engine.rb +2 -0
- data/lib/ea/qea/validation.rb +2 -0
- data/lib/ea/query/builder.rb +127 -0
- data/lib/ea/query.rb +9 -0
- data/lib/ea/render/image_converter.rb +101 -0
- data/lib/ea/render.rb +10 -0
- data/lib/ea/shapescript/parser.rb +208 -0
- data/lib/ea/shapescript/renderer.rb +74 -0
- data/lib/ea/shapescript/shape.rb +34 -0
- data/lib/ea/shapescript.rb +24 -0
- data/lib/ea/sources/qea/adapter.rb +22 -5
- data/lib/ea/sources/qea/classifier_builder.rb +184 -7
- data/lib/ea/sources/qea/diagram_builder.rb +352 -24
- data/lib/ea/sources/qea/id_normalizer.rb +16 -1
- data/lib/ea/sources/qea/instance_builder.rb +113 -0
- data/lib/ea/sources/qea/legend_builder.rb +137 -0
- data/lib/ea/sources/qea/note_builder.rb +58 -0
- data/lib/ea/sources/qea/object_classifier_map.rb +6 -1
- data/lib/ea/sources/qea/operation_builder.rb +1 -0
- data/lib/ea/sources/qea/package_builder.rb +16 -0
- data/lib/ea/sources/qea/relationship_builder.rb +21 -5
- data/lib/ea/sources/qea/tagged_value_builder.rb +28 -9
- data/lib/ea/sources/qea/xref/legend_definition.rb +35 -0
- data/lib/ea/sources/qea/xref/parser.rb +150 -0
- data/lib/ea/sources/qea/xref/property_definition.rb +29 -0
- data/lib/ea/sources/qea/xref/record.rb +41 -0
- data/lib/ea/sources/qea/xref/stereotype_application.rb +37 -0
- data/lib/ea/sources/qea/xref.rb +27 -0
- data/lib/ea/sources/qea.rb +4 -0
- data/lib/ea/sources/xmi/adapter.rb +80 -2
- data/lib/ea/sources/xmi/classifier_builder.rb +10 -1
- data/lib/ea/sources/xmi/diagram_builder.rb +95 -18
- data/lib/ea/sources/xmi/extension_geometry_parser.rb +19 -2
- data/lib/ea/sources/xmi/extension_style_parser.rb +15 -2
- data/lib/ea/sources/xmi/note_builder.rb +46 -0
- data/lib/ea/sources/xmi/property_builder.rb +9 -0
- data/lib/ea/sources/xmi/stereotype_builder.rb +54 -0
- data/lib/ea/sources/xmi/tag_builder.rb +45 -0
- data/lib/ea/sources/xmi/umldi_keyword_extractor.rb +87 -0
- data/lib/ea/sources/xmi.rb +4 -0
- data/lib/ea/spa/output/sharded_multi_file_strategy.rb +18 -3
- data/lib/ea/spa/output/single_file_strategy.rb +8 -2
- data/lib/ea/spa/output/strategy.rb +34 -0
- data/lib/ea/svg/connector_router.rb +134 -0
- data/lib/ea/svg/ea_emitter/background.rb +2 -3
- data/lib/ea/svg/ea_emitter/bounds_calculator.rb +142 -0
- data/lib/ea/svg/ea_emitter/canvas.rb +56 -33
- data/lib/ea/svg/ea_emitter/color_resolver.rb +56 -0
- data/lib/ea/svg/ea_emitter/compartment/attributes.rb +28 -0
- data/lib/ea/svg/ea_emitter/compartment/constraints.rb +30 -0
- data/lib/ea/svg/ea_emitter/compartment/enum_literals.rb +86 -0
- data/lib/ea/svg/ea_emitter/compartment/header.rb +32 -0
- data/lib/ea/svg/ea_emitter/compartment/header_divider.rb +57 -0
- data/lib/ea/svg/ea_emitter/compartment/instance_slots.rb +96 -0
- data/lib/ea/svg/ea_emitter/compartment/instance_underline.rb +67 -0
- data/lib/ea/svg/ea_emitter/compartment/note_body.rb +52 -0
- data/lib/ea/svg/ea_emitter/compartment/note_text.rb +102 -0
- data/lib/ea/svg/ea_emitter/compartment/operations.rb +38 -0
- data/lib/ea/svg/ea_emitter/compartment/package_contents.rb +72 -0
- data/lib/ea/svg/ea_emitter/compartment/package_from_parent.rb +136 -0
- data/lib/ea/svg/ea_emitter/compartment/shape.rb +82 -0
- data/lib/ea/svg/ea_emitter/compartment/stereotype_icon.rb +32 -0
- data/lib/ea/svg/ea_emitter/compartment/tagged_values.rb +30 -0
- data/lib/ea/svg/ea_emitter/compartment.rb +60 -0
- data/lib/ea/svg/ea_emitter/connectors.rb +46 -12
- data/lib/ea/svg/ea_emitter/diagram_frame.rb +143 -0
- data/lib/ea/svg/ea_emitter/document.rb +49 -25
- data/lib/ea/svg/ea_emitter/element/attribute_line_builder.rb +117 -0
- data/lib/ea/svg/ea_emitter/element/attribute_renderer.rb +119 -0
- data/lib/ea/svg/ea_emitter/element/bcol_decoder.rb +29 -0
- data/lib/ea/svg/ea_emitter/element/compartment_geometry.rb +113 -0
- data/lib/ea/svg/ea_emitter/element/constraint_renderer.rb +53 -0
- data/lib/ea/svg/ea_emitter/element/divider_renderer.rb +17 -0
- data/lib/ea/svg/ea_emitter/element/enumeration_literal_renderer.rb +34 -0
- data/lib/ea/svg/ea_emitter/element/filter.rb +44 -0
- data/lib/ea/svg/ea_emitter/element/hand_draw_shape_renderer.rb +77 -0
- data/lib/ea/svg/ea_emitter/element/header_line_pipeline.rb +43 -0
- data/lib/ea/svg/ea_emitter/element/header_line_provider/instance_spec.rb +27 -0
- data/lib/ea/svg/ea_emitter/element/header_line_provider/name.rb +76 -0
- data/lib/ea/svg/ea_emitter/element/header_line_provider/parent_ghost.rb +25 -0
- data/lib/ea/svg/ea_emitter/element/header_line_provider/stereotype_label.rb +68 -0
- data/lib/ea/svg/ea_emitter/element/header_line_provider.rb +19 -0
- data/lib/ea/svg/ea_emitter/element/header_lines.rb +27 -0
- data/lib/ea/svg/ea_emitter/element/header_renderer.rb +48 -0
- data/lib/ea/svg/ea_emitter/element/icon_renderer.rb +109 -0
- data/lib/ea/svg/ea_emitter/element/legend_renderer.rb +177 -0
- data/lib/ea/svg/ea_emitter/element/note_shape_renderer.rb +112 -0
- data/lib/ea/svg/ea_emitter/element/operation_renderer.rb +100 -0
- data/lib/ea/svg/ea_emitter/element/package_shape_renderer.rb +181 -0
- data/lib/ea/svg/ea_emitter/element/row_icon_renderer.rb +156 -0
- data/lib/ea/svg/ea_emitter/element/shape_renderer.rb +17 -0
- data/lib/ea/svg/ea_emitter/element/stereotype_icon_renderer.rb +119 -0
- data/lib/ea/svg/ea_emitter/element/tagged_value_renderer.rb +50 -0
- data/lib/ea/svg/ea_emitter/element/text_escape.rb +20 -0
- data/lib/ea/svg/ea_emitter/element.rb +37 -0
- data/lib/ea/svg/ea_emitter/elements.rb +283 -95
- data/lib/ea/svg/ea_emitter/font_resolver.rb +111 -0
- data/lib/ea/svg/ea_emitter/ghost_labels.rb +66 -0
- data/lib/ea/svg/ea_emitter/label/end_label.rb +266 -0
- data/lib/ea/svg/ea_emitter/label/midpoint_label.rb +101 -0
- data/lib/ea/svg/ea_emitter/label/registry.rb +50 -0
- data/lib/ea/svg/ea_emitter/label.rb +23 -0
- data/lib/ea/svg/ea_emitter/labels.rb +93 -27
- data/lib/ea/svg/ea_emitter/layer.rb +20 -0
- data/lib/ea/svg/ea_emitter/layer_sequencer.rb +93 -0
- data/lib/ea/svg/ea_emitter/marker/arrow_path.rb +52 -0
- data/lib/ea/svg/ea_emitter/marker/diamond.rb +57 -0
- data/lib/ea/svg/ea_emitter/marker/kind.rb +35 -0
- data/lib/ea/svg/ea_emitter/marker/open_triangle.rb +27 -0
- data/lib/ea/svg/ea_emitter/marker/package_import.rb +39 -0
- data/lib/ea/svg/ea_emitter/marker/plus.rb +40 -0
- data/lib/ea/svg/ea_emitter/marker/registry.rb +42 -0
- data/lib/ea/svg/ea_emitter/marker.rb +37 -0
- data/lib/ea/svg/ea_emitter/markers.rb +351 -64
- data/lib/ea/svg/ea_emitter/render_context.rb +52 -0
- data/lib/ea/svg/ea_emitter/style.rb +15 -0
- data/lib/ea/svg/ea_emitter/text_renderer.rb +92 -0
- data/lib/ea/svg/ea_emitter.rb +33 -11
- data/lib/ea/svg/parity/checker.rb +105 -0
- data/lib/ea/svg/parity/source.rb +59 -0
- data/lib/ea/svg/parity/suite.rb +113 -0
- data/lib/ea/svg/parity.rb +14 -0
- data/lib/ea/svg.rb +2 -15
- data/lib/ea/theme/definition.rb +176 -0
- data/lib/ea/theme/loader.rb +125 -0
- data/lib/ea/theme/registry.rb +96 -0
- data/lib/ea/theme.rb +37 -0
- data/lib/ea/transformations.rb +5 -88
- data/lib/ea/validation/xmi_parity.rb +80 -0
- data/lib/ea/validation.rb +12 -0
- data/lib/ea/version.rb +4 -1
- data/lib/ea.rb +15 -4
- data/lib/tasks/svg_bench.rake +87 -0
- data/lutaml-uml-0.5.1.gem +0 -0
- data/reference-docs/enterprise-architect-appearance-dialogs/appearance-1-diagram-1-themes-list.png +0 -0
- data/reference-docs/enterprise-architect-appearance-dialogs/appearance-1-diagram-1-themes.png +0 -0
- data/reference-docs/enterprise-architect-appearance-dialogs/appearance-1-diagram-2-gradients.png +0 -0
- data/reference-docs/enterprise-architect-appearance-dialogs/appearance-1-diagram-3-colors.png +0 -0
- data/reference-docs/enterprise-architect-appearance-dialogs/appearance-1-diagram-4-appearance-fonts.png +0 -0
- data/reference-docs/enterprise-architect-appearance-dialogs/appearance-1-diagram-4-appearance.png +0 -0
- data/reference-docs/enterprise-architect-appearance-dialogs/appearance-1-diagram-5-behavior.png +0 -0
- data/reference-docs/enterprise-architect-appearance-dialogs/appearance-1-diagram-6-sequence.png +0 -0
- data/reference-docs/enterprise-architect-appearance-dialogs/appearance-1-diagram.png +0 -0
- data/reference-docs/enterprise-architect-appearance-dialogs/appearance-2-objects.png +0 -0
- data/reference-docs/enterprise-architect-appearance-dialogs/appearance-3-links.png +0 -0
- metadata +464 -26
- data/lib/ea/diagram/configuration.rb +0 -379
- data/lib/ea/diagram/element_renderers/base_renderer.rb +0 -77
- data/lib/ea/diagram/element_renderers/class_renderer.rb +0 -323
- data/lib/ea/diagram/element_renderers/connector_renderer.rb +0 -41
- data/lib/ea/diagram/element_renderers/package_renderer.rb +0 -61
- data/lib/ea/diagram/element_renderers.rb +0 -43
- data/lib/ea/diagram/extractor.rb +0 -566
- data/lib/ea/diagram/layout_engine.rb +0 -170
- data/lib/ea/diagram/path_builder.rb +0 -202
- data/lib/ea/diagram/style_parser.rb +0 -42
- data/lib/ea/diagram/style_resolver.rb +0 -291
- data/lib/ea/diagram/svg_renderer.rb +0 -274
- data/lib/ea/diagram/util.rb +0 -73
- data/lib/ea/svg/bounds_calculator.rb +0 -74
- data/lib/ea/svg/connector_path.rb +0 -138
- data/lib/ea/svg/element_box.rb +0 -256
- data/lib/ea/svg/renderer.rb +0 -77
- data/lib/ea/svg/style_resolver.rb +0 -72
- data/lib/ea/transformations/configuration.rb +0 -333
- data/lib/ea/transformations/format_registry.rb +0 -366
- data/lib/ea/transformations/parsers/base_parser.rb +0 -482
- data/lib/ea/transformations/parsers/qea_parser.rb +0 -401
- data/lib/ea/transformations/parsers/xmi_parser.rb +0 -243
- data/lib/ea/transformations/transformation_engine.rb +0 -390
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Ea
|
|
4
|
+
module Sources
|
|
5
|
+
module Qea
|
|
6
|
+
# Builds an `Ea::Model::Legend` for a Text element by parsing
|
|
7
|
+
# the sibling `t_xref` row of name="CustomProperties" on the
|
|
8
|
+
# same GUID. EA encodes legend configuration in the xref's
|
|
9
|
+
# Description field using `@PROP=...@ENDPROP;` blocks, one
|
|
10
|
+
# per item plus one for the title (`LEGEND_STYLE_SETTINGS`).
|
|
11
|
+
#
|
|
12
|
+
# Returns nil when no matching xref exists (the Text element
|
|
13
|
+
# is not a legend — caller should render it as a plain note).
|
|
14
|
+
class LegendBuilder
|
|
15
|
+
LEGEND_XREF_NAME = "CustomProperties"
|
|
16
|
+
LEGEND_TYPE_OBJECT_STYLE = "LEGEND_OBJECTSTYLE"
|
|
17
|
+
LEGEND_TYPE_STYLE_SETTINGS = "LEGEND_STYLE_SETTINGS"
|
|
18
|
+
|
|
19
|
+
PROP_PATTERN = /
|
|
20
|
+
@PROP=
|
|
21
|
+
@NAME=(?<name>[^@]*?)@ENDNAME;
|
|
22
|
+
@TYPE=(?<type>[^@]*?)@ENDTYPE;
|
|
23
|
+
@VALU=(?<value>[^@]*?)@ENDVALU;
|
|
24
|
+
(?:@PRMT=(?<prmt>[^@]*?)@ENDPRMT;)?
|
|
25
|
+
@ENDPROP;
|
|
26
|
+
/x.freeze
|
|
27
|
+
|
|
28
|
+
attr_reader :database
|
|
29
|
+
|
|
30
|
+
def initialize(database)
|
|
31
|
+
@database = database
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def build_for(ea_guid)
|
|
35
|
+
description = legend_description_for(ea_guid)
|
|
36
|
+
return nil unless description
|
|
37
|
+
|
|
38
|
+
build_from_description(description)
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
private
|
|
42
|
+
|
|
43
|
+
def legend_description_for(ea_guid)
|
|
44
|
+
xref = database.xrefs_for_client(ea_guid).find { |row| row.name == LEGEND_XREF_NAME }
|
|
45
|
+
return nil unless xref
|
|
46
|
+
|
|
47
|
+
xref.description
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
def build_from_description(description)
|
|
51
|
+
props = description.scan(PROP_PATTERN)
|
|
52
|
+
return nil if props.empty?
|
|
53
|
+
|
|
54
|
+
items = items_from(props)
|
|
55
|
+
style = style_settings_from(props)
|
|
56
|
+
|
|
57
|
+
build_legend(items: items, style: style)
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
def items_from(props)
|
|
61
|
+
props.select { |_, type, _, _| type == LEGEND_TYPE_OBJECT_STYLE }
|
|
62
|
+
.each_with_index
|
|
63
|
+
.map do |(name, _, value, prmt), display_index|
|
|
64
|
+
build_item(name: name, value: value, prmt: prmt,
|
|
65
|
+
display_index: display_index)
|
|
66
|
+
end
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
def style_settings_from(props)
|
|
70
|
+
entry = props.find { |_, type, _, _| type == LEGEND_TYPE_STYLE_SETTINGS }
|
|
71
|
+
return {} unless entry
|
|
72
|
+
|
|
73
|
+
parse_kv(entry[2])
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
def build_legend(items:, style:)
|
|
77
|
+
Ea::Model::Legend.new(
|
|
78
|
+
title: style["TITLE"] || Ea::Model::Legend::DEFAULT_TITLE,
|
|
79
|
+
heading_size: int_or_nil(style["HEADINGSIZE"]),
|
|
80
|
+
font_color: int_or(style["FONTCOLOR"],
|
|
81
|
+
Ea::Model::Legend::DEFAULT_FONT_COLOR),
|
|
82
|
+
background_color: int_or(style["BACKGROUNDCOLOR"],
|
|
83
|
+
Ea::Model::Legend::DEFAULT_BACKGROUND_COLOR),
|
|
84
|
+
border_color: int_or(style["BORDERCOLOR"],
|
|
85
|
+
Ea::Model::Legend::DEFAULT_BORDER_COLOR),
|
|
86
|
+
background_is_default: background_is_default?(style),
|
|
87
|
+
items: items
|
|
88
|
+
)
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
def build_item(name:, value:, prmt:, display_index:)
|
|
92
|
+
attrs = parse_kv(value)
|
|
93
|
+
Ea::Model::LegendItem.new(
|
|
94
|
+
name: name.to_s,
|
|
95
|
+
background_color: int_or(attrs["Back_Ground_Color"], 0),
|
|
96
|
+
pen_color: int_or(attrs["Pen_Color"], 0),
|
|
97
|
+
pen_size: int_or(attrs["Pen_Size"], 1),
|
|
98
|
+
sort_index: int_or(prmt, display_index)
|
|
99
|
+
)
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
# EA packs key=value pairs as `#KEY#=VAL;` inside the @VALU
|
|
103
|
+
# payload. Both KEY and VAL are delimited by `#` or `;`.
|
|
104
|
+
def parse_kv(payload)
|
|
105
|
+
return {} if payload.nil? || payload.empty?
|
|
106
|
+
|
|
107
|
+
payload.to_s.split(";").each_with_object({}) do |pair, hash|
|
|
108
|
+
key, val = pair.split("=", 2)
|
|
109
|
+
next unless key && val
|
|
110
|
+
next if val.empty?
|
|
111
|
+
|
|
112
|
+
hash[key.delete("#")] = val
|
|
113
|
+
end
|
|
114
|
+
end
|
|
115
|
+
|
|
116
|
+
def background_is_default?(style)
|
|
117
|
+
value = style["BACKGROUNDISDEFAULT"]
|
|
118
|
+
return true if value.nil?
|
|
119
|
+
|
|
120
|
+
value == "1" || value.to_s.downcase == "true"
|
|
121
|
+
end
|
|
122
|
+
|
|
123
|
+
def int_or(raw, fallback)
|
|
124
|
+
Integer(raw.to_s)
|
|
125
|
+
rescue ArgumentError, TypeError
|
|
126
|
+
fallback
|
|
127
|
+
end
|
|
128
|
+
|
|
129
|
+
def int_or_nil(raw)
|
|
130
|
+
Integer(raw.to_s)
|
|
131
|
+
rescue ArgumentError, TypeError
|
|
132
|
+
nil
|
|
133
|
+
end
|
|
134
|
+
end
|
|
135
|
+
end
|
|
136
|
+
end
|
|
137
|
+
end
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Ea
|
|
4
|
+
module Sources
|
|
5
|
+
module Qea
|
|
6
|
+
# Extracts Note elements from EA's t_object table. Notes have
|
|
7
|
+
# object_type="Note" and are filtered out by ClassifierBuilder.
|
|
8
|
+
# Their body text lives in t_object.Note; the diagram renderer
|
|
9
|
+
# emits them as dog-eared rects with the body wrapped inside.
|
|
10
|
+
#
|
|
11
|
+
# Text elements (object_type="Text") with LegendOpts= in
|
|
12
|
+
# StyleEx are auto-generated legend blocks rather than notes;
|
|
13
|
+
# their configuration is parsed from t_xref and attached as
|
|
14
|
+
# an `Ea::Model::Legend` payload on the Note.
|
|
15
|
+
class NoteBuilder
|
|
16
|
+
NOTE_OBJECT_TYPE = "Note".freeze
|
|
17
|
+
TEXT_OBJECT_TYPE = "Text".freeze
|
|
18
|
+
LEGEND_STYLEEX_TOKEN = "LegendOpts=".freeze
|
|
19
|
+
|
|
20
|
+
attr_reader :database
|
|
21
|
+
|
|
22
|
+
def initialize(database)
|
|
23
|
+
@database = database
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def build_all
|
|
27
|
+
objects = database.collections[:objects] || []
|
|
28
|
+
objects.filter_map { |obj| build_one(obj) }
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
private
|
|
32
|
+
|
|
33
|
+
def build_one(obj)
|
|
34
|
+
return nil unless note_type?(obj.object_type)
|
|
35
|
+
|
|
36
|
+
Ea::Model::Note.new(
|
|
37
|
+
id: IdNormalizer.from_guid(obj.ea_guid),
|
|
38
|
+
name: obj.name,
|
|
39
|
+
body: obj.note,
|
|
40
|
+
note_type: obj.object_type,
|
|
41
|
+
legend: legend_for(obj)
|
|
42
|
+
)
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
def note_type?(object_type)
|
|
46
|
+
object_type == NOTE_OBJECT_TYPE || object_type == TEXT_OBJECT_TYPE
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
def legend_for(obj)
|
|
50
|
+
return nil unless obj.object_type == TEXT_OBJECT_TYPE
|
|
51
|
+
return nil unless obj.styleex.to_s.include?(LEGEND_STYLEEX_TOKEN)
|
|
52
|
+
|
|
53
|
+
LegendBuilder.new(database).build_for(obj.ea_guid)
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
end
|
|
@@ -18,7 +18,12 @@ module Ea
|
|
|
18
18
|
"Enumeration" => "Ea::Model::Enumeration",
|
|
19
19
|
"Interface" => "Ea::Model::Interface",
|
|
20
20
|
"PrimitiveType" => "Ea::Model::PrimitiveType",
|
|
21
|
-
"Primitive" => "Ea::Model::PrimitiveType"
|
|
21
|
+
"Primitive" => "Ea::Model::PrimitiveType",
|
|
22
|
+
"Signal" => "Ea::Model::Signal",
|
|
23
|
+
# EA "Object" rows are UML InstanceSpecifications. We
|
|
24
|
+
# don't yet model InstanceSpecification as a distinct
|
|
25
|
+
# class — they render like a simple named Klass.
|
|
26
|
+
"Object" => "Ea::Model::Klass"
|
|
22
27
|
}.freeze
|
|
23
28
|
|
|
24
29
|
def class_for(object_type)
|
|
@@ -27,6 +27,7 @@ module Ea
|
|
|
27
27
|
visibility: visibility_from_scope(row.scope),
|
|
28
28
|
is_static: boolean(row.isstatic),
|
|
29
29
|
is_abstract: boolean(row.abstract),
|
|
30
|
+
is_reception: row.reception?,
|
|
30
31
|
parameters: build_parameters(row),
|
|
31
32
|
annotations: AnnotationBuilder.from_note(row.notes, row.ea_guid,
|
|
32
33
|
kind: "documentation")
|
|
@@ -24,6 +24,7 @@ module Ea
|
|
|
24
24
|
name: pkg.name,
|
|
25
25
|
parent_id: parent_id_for(pkg),
|
|
26
26
|
qualified_name: pkg.xmlpath,
|
|
27
|
+
stereotype_refs: stereotype_refs_for(pkg),
|
|
27
28
|
annotations: AnnotationBuilder.from_note(pkg.notes, pkg.ea_guid)
|
|
28
29
|
)
|
|
29
30
|
end
|
|
@@ -38,6 +39,21 @@ module Ea
|
|
|
38
39
|
|
|
39
40
|
IdNormalizer.from_guid(parent.ea_guid)
|
|
40
41
|
end
|
|
42
|
+
|
|
43
|
+
# EA stores the package's applied stereotype on the t_object
|
|
44
|
+
# row that mirrors the t_package entry (matched by ea_guid).
|
|
45
|
+
# t_package itself has no Stereotype column — only t_object
|
|
46
|
+
# does. Returns [] when no t_object row exists or no
|
|
47
|
+
# stereotype is set.
|
|
48
|
+
def stereotype_refs_for(pkg)
|
|
49
|
+
obj = database.find_object_by_guid(pkg.ea_guid)
|
|
50
|
+
return [] unless obj
|
|
51
|
+
|
|
52
|
+
stereotype = obj.stereotype
|
|
53
|
+
return [] if stereotype.nil? || stereotype.to_s.empty?
|
|
54
|
+
|
|
55
|
+
[stereotype.to_s]
|
|
56
|
+
end
|
|
41
57
|
end
|
|
42
58
|
end
|
|
43
59
|
end
|
|
@@ -22,6 +22,7 @@ module Ea
|
|
|
22
22
|
klass = ConnectorRelationshipMap.class_for(row.connector_type)
|
|
23
23
|
args = common_args(row)
|
|
24
24
|
args.merge!(association_args(row)) if klass == Ea::Model::Association
|
|
25
|
+
args.merge!(generalization_args(row)) if klass == Ea::Model::Generalization
|
|
25
26
|
klass.new(**args)
|
|
26
27
|
end
|
|
27
28
|
|
|
@@ -32,11 +33,23 @@ module Ea
|
|
|
32
33
|
id: IdNormalizer.from_guid(row.ea_guid),
|
|
33
34
|
name: row.name,
|
|
34
35
|
qualified_name: row.name,
|
|
36
|
+
stereotype: row.stereotype,
|
|
35
37
|
annotations: AnnotationBuilder.from_note(row.notes, row.ea_guid,
|
|
36
38
|
kind: "documentation")
|
|
37
39
|
}
|
|
38
40
|
end
|
|
39
41
|
|
|
42
|
+
# EA's Generalization connector points from the specific
|
|
43
|
+
# (child) to the general (parent): Start_Object_ID is the
|
|
44
|
+
# child, End_Object_ID is the parent. Direction is
|
|
45
|
+
# conventionally "Source -> Destination".
|
|
46
|
+
def generalization_args(row)
|
|
47
|
+
{
|
|
48
|
+
specific_id: id_for_object_id(row.start_object_id),
|
|
49
|
+
general_id: id_for_object_id(row.end_object_id)
|
|
50
|
+
}
|
|
51
|
+
end
|
|
52
|
+
|
|
40
53
|
def association_args(row)
|
|
41
54
|
{
|
|
42
55
|
source_id: id_for_object_id(row.start_object_id),
|
|
@@ -63,19 +76,22 @@ module Ea
|
|
|
63
76
|
IdNormalizer.from_guid(obj.ea_guid)
|
|
64
77
|
end
|
|
65
78
|
|
|
79
|
+
# Returns nil when cardinality is absent so the renderer can
|
|
80
|
+
# distinguish "no multiplicity specified" from an explicit
|
|
81
|
+
# "1". EA only renders the "1" label when the modeller set it
|
|
82
|
+
# explicitly (SourceCard/DestCard = "1").
|
|
66
83
|
def parse_lower(cardinality)
|
|
67
|
-
return
|
|
84
|
+
return nil if cardinality.nil? || cardinality.empty?
|
|
68
85
|
|
|
69
|
-
# EA format: "1", "0..*", "1..1", etc. Take the first number.
|
|
70
86
|
begin
|
|
71
87
|
Integer(cardinality.split("..").first)
|
|
72
88
|
rescue StandardError
|
|
73
|
-
|
|
89
|
+
nil
|
|
74
90
|
end
|
|
75
91
|
end
|
|
76
92
|
|
|
77
93
|
def parse_upper(cardinality)
|
|
78
|
-
return
|
|
94
|
+
return nil if cardinality.nil? || cardinality.empty?
|
|
79
95
|
|
|
80
96
|
upper = cardinality.split("..").last
|
|
81
97
|
return -1 if upper == "*"
|
|
@@ -83,7 +99,7 @@ module Ea
|
|
|
83
99
|
begin
|
|
84
100
|
Integer(upper)
|
|
85
101
|
rescue StandardError
|
|
86
|
-
|
|
102
|
+
nil
|
|
87
103
|
end
|
|
88
104
|
end
|
|
89
105
|
|
|
@@ -4,9 +4,11 @@ module Ea
|
|
|
4
4
|
module Sources
|
|
5
5
|
module Qea
|
|
6
6
|
# Builds Ea::Model::TaggedValue instances from EA's
|
|
7
|
-
# t_objectproperties
|
|
8
|
-
# tagged values
|
|
9
|
-
#
|
|
7
|
+
# t_taggedvalue AND t_objectproperties tables. EA stores UML
|
|
8
|
+
# profile tagged values in t_taggedvalue (keyed by ElementID
|
|
9
|
+
# GUID), and per-object custom properties in t_objectproperties
|
|
10
|
+
# (keyed by Object_ID integer). Both surface as tagged values
|
|
11
|
+
# in the SVG output and merge into one list per classifier.
|
|
10
12
|
class TaggedValueBuilder
|
|
11
13
|
attr_reader :database
|
|
12
14
|
|
|
@@ -14,21 +16,38 @@ module Ea
|
|
|
14
16
|
@database = database
|
|
15
17
|
end
|
|
16
18
|
|
|
17
|
-
|
|
19
|
+
# Build tagged values for an EA object. Pass both the
|
|
20
|
+
# GUID (for t_taggedvalue lookups) and the integer EA
|
|
21
|
+
# Object_ID (for t_objectproperties lookups).
|
|
22
|
+
def for_object(ea_guid, ea_object_id: nil)
|
|
18
23
|
rows = database.tagged_values_for_element(ea_guid) || []
|
|
19
|
-
rows.map { |row|
|
|
24
|
+
tv = rows.map { |row| build_from_tagged_value(row, ea_guid) }
|
|
25
|
+
return tv unless ea_object_id
|
|
26
|
+
|
|
27
|
+
prop_rows = database.properties_for_object(ea_object_id) || []
|
|
28
|
+
tv + prop_rows.map { |row| build_from_object_property(row) }
|
|
20
29
|
end
|
|
21
30
|
|
|
22
31
|
def for_attribute(attribute_row)
|
|
23
|
-
return [] unless attribute_row.
|
|
32
|
+
return [] unless attribute_row.is_a?(Ea::Qea::Models::EaAttribute)
|
|
24
33
|
|
|
25
34
|
rows = database.tagged_values_for_element(attribute_row.ea_guid) || []
|
|
26
|
-
rows.map { |row|
|
|
35
|
+
rows.map { |row| build_from_tagged_value(row, attribute_row.ea_guid) }
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
def build_from_tagged_value(row, owner_guid)
|
|
39
|
+
Ea::Model::TaggedValue.new(
|
|
40
|
+
id: IdNormalizer.synthetic("tv", owner_guid,
|
|
41
|
+
row.tag&.gsub(/\W+/, "_")),
|
|
42
|
+
key: row.tag,
|
|
43
|
+
value: row.value
|
|
44
|
+
)
|
|
27
45
|
end
|
|
28
46
|
|
|
29
|
-
def
|
|
47
|
+
def build_from_object_property(row)
|
|
30
48
|
Ea::Model::TaggedValue.new(
|
|
31
|
-
id: IdNormalizer.synthetic("
|
|
49
|
+
id: IdNormalizer.synthetic("op", row.ea_object_id.to_s,
|
|
50
|
+
row.property&.gsub(/\W+/, "_")),
|
|
32
51
|
key: row.property,
|
|
33
52
|
value: row.value
|
|
34
53
|
)
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Ea
|
|
4
|
+
module Sources
|
|
5
|
+
module Qea
|
|
6
|
+
module Xref
|
|
7
|
+
# Legend definition record. Produced when the Description contains
|
|
8
|
+
# `@PROP=` blocks with `@TYPE=LEGEND_*`. EA encodes legend
|
|
9
|
+
# entries as color/style rules keyed by name.
|
|
10
|
+
#
|
|
11
|
+
# Example source:
|
|
12
|
+
# @PROP=@NAME=GMLに定義されたクラス@ENDNAME;
|
|
13
|
+
# @TYPE=LEGEND_OBJECTSTYLE@ENDTYPE;
|
|
14
|
+
# @VALU=#Back_Ground_Color#=13434828;#Pen_Color#=0;
|
|
15
|
+
# #Pen_Size#=1;#Legend_Type#=LEGEND_OBJECTSTYLE;
|
|
16
|
+
# @ENDVALU;@PRMT=0@ENDPRMT;@ENDPROP;
|
|
17
|
+
LegendDefinition = Struct.new(:name, :legend_type, :colors,
|
|
18
|
+
:parameter, keyword_init: true) do
|
|
19
|
+
# EA encodes colors as signed 32-bit integers (VB-style).
|
|
20
|
+
# Convert to `#RRGGBB` hex string for SVG consumption.
|
|
21
|
+
# @param key [Symbol] color key, e.g. :back_ground_color
|
|
22
|
+
# @return [String, nil] hex color (`#RRGGBB`) or nil
|
|
23
|
+
def hex_color(key)
|
|
24
|
+
value = colors&.dig(key)
|
|
25
|
+
return nil if value.nil?
|
|
26
|
+
|
|
27
|
+
int = value.to_i
|
|
28
|
+
int = (int + 2**32) % 2**32 if int.negative?
|
|
29
|
+
format("#%06X", int & 0xFFFFFF)
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
end
|
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Ea
|
|
4
|
+
module Sources
|
|
5
|
+
module Qea
|
|
6
|
+
module Xref
|
|
7
|
+
# Pure parser for EA's `t_xref.Description` mini-language.
|
|
8
|
+
# Stateless — every call returns a fresh `Xref::Record`.
|
|
9
|
+
#
|
|
10
|
+
# Supported formats:
|
|
11
|
+
# @STEREO;Name=X;FQName=Y;@ENDSTEREO;
|
|
12
|
+
# @PROP=@NAME=..@ENDNAME;@TYPE=..@ENDTYPE;@VALU=..@ENDVALU;@PRMT=..@ENDPRMT;@ENDPROP;
|
|
13
|
+
# <key>=<value>;<key>=<value>;
|
|
14
|
+
#
|
|
15
|
+
# Unknown formats fall through to key=value parsing.
|
|
16
|
+
module Parser
|
|
17
|
+
module_function
|
|
18
|
+
|
|
19
|
+
# Parse one Description string into a typed Record.
|
|
20
|
+
# @param description [String, nil]
|
|
21
|
+
# @return [Ea::Sources::Qea::Xref::Record]
|
|
22
|
+
def parse(description)
|
|
23
|
+
return Record.new if description.nil? || description.empty?
|
|
24
|
+
|
|
25
|
+
Record.new(
|
|
26
|
+
stereotype: parse_stereotype(description),
|
|
27
|
+
properties: parse_properties(description),
|
|
28
|
+
legends: parse_legends(description),
|
|
29
|
+
key_values: parse_key_values(description),
|
|
30
|
+
raw: description
|
|
31
|
+
)
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
# -- per-format extractors ----------------------------------
|
|
35
|
+
|
|
36
|
+
# Matches both legacy `@STEREO;Name=X;GUID={..};` and the
|
|
37
|
+
# plateau form `@STEREO;Name=X;FQName=Y;@ENDSTEREO;`.
|
|
38
|
+
STEREO_REGEX = /
|
|
39
|
+
@STEREO;
|
|
40
|
+
(.*?)
|
|
41
|
+
(?:@ENDSTEREO;|\z)
|
|
42
|
+
/mx.freeze
|
|
43
|
+
|
|
44
|
+
def parse_stereotype(description)
|
|
45
|
+
match = description.match(STEREO_REGEX)
|
|
46
|
+
return nil unless match
|
|
47
|
+
|
|
48
|
+
fields = parse_semicolon_fields(match[1])
|
|
49
|
+
StereotypeApplication.new(
|
|
50
|
+
name: fields["Name"],
|
|
51
|
+
fqname: fields["FQName"]
|
|
52
|
+
)
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
# One Description can carry multiple @PROP=...@ENDPROP; blocks.
|
|
56
|
+
# Split, then classify each as PropertyDefinition or LegendDefinition.
|
|
57
|
+
PROP_REGEX = /
|
|
58
|
+
@PROP=
|
|
59
|
+
(.*?)
|
|
60
|
+
@ENDPROP;
|
|
61
|
+
/mx.freeze
|
|
62
|
+
|
|
63
|
+
def parse_properties(description)
|
|
64
|
+
blocks = description.scan(PROP_REGEX).flatten
|
|
65
|
+
blocks.each_with_object([]) do |block, acc|
|
|
66
|
+
record = build_prop_record(block)
|
|
67
|
+
acc << record if record
|
|
68
|
+
end
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
def parse_legends(description)
|
|
72
|
+
parse_properties(description).select do |prop|
|
|
73
|
+
prop.is_a?(LegendDefinition)
|
|
74
|
+
end
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
def build_prop_record(block)
|
|
78
|
+
name = extract_tagged_value(block, "NAME")
|
|
79
|
+
type = extract_tagged_value(block, "TYPE")
|
|
80
|
+
value = extract_tagged_value(block, "VALU")
|
|
81
|
+
parameter = extract_tagged_value(block, "PRMT")
|
|
82
|
+
|
|
83
|
+
if type&.start_with?("LEGEND_")
|
|
84
|
+
LegendDefinition.new(
|
|
85
|
+
name: name,
|
|
86
|
+
legend_type: type,
|
|
87
|
+
colors: parse_color_value(value),
|
|
88
|
+
parameter: parameter
|
|
89
|
+
)
|
|
90
|
+
else
|
|
91
|
+
PropertyDefinition.new(
|
|
92
|
+
name: name,
|
|
93
|
+
type: type,
|
|
94
|
+
value: value,
|
|
95
|
+
parameter: parameter
|
|
96
|
+
)
|
|
97
|
+
end
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
# Extracts the content between @TAG=...@ENDTAG; markers.
|
|
101
|
+
# Returns nil when the tag is absent.
|
|
102
|
+
def extract_tagged_value(block, tag)
|
|
103
|
+
pattern = /@#{tag}=(.*?)@END#{tag};/m.freeze
|
|
104
|
+
match = block.match(pattern)
|
|
105
|
+
match ? match[1] : nil
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
# EA encodes legend VALU as `#key#=value;` pairs.
|
|
109
|
+
# Returns a hash keyed by underscored symbol.
|
|
110
|
+
def parse_color_value(value)
|
|
111
|
+
return {} if value.nil? || value.empty?
|
|
112
|
+
|
|
113
|
+
value.scan(/#([^#=]+)#=([^;]*);/).each_with_object({}) do |(k, v), acc|
|
|
114
|
+
acc[k.downcase.to_sym] = v
|
|
115
|
+
end
|
|
116
|
+
end
|
|
117
|
+
|
|
118
|
+
# Legacy `Key=Value;Key=Value;` parsing. Skips content that
|
|
119
|
+
# looks like @STEREO or @PROP blocks to avoid noise.
|
|
120
|
+
def parse_key_values(description)
|
|
121
|
+
stripped = description
|
|
122
|
+
.gsub(/@STEREO;.*?(?:@ENDSTEREO;|\z)/m, "")
|
|
123
|
+
.gsub(/@PROP=.*?@ENDPROP;/m, "")
|
|
124
|
+
pairs = stripped.split(";").map { |s| s.split("=", 2) }
|
|
125
|
+
pairs.each_with_object({}) do |(k, v), acc|
|
|
126
|
+
next if k.nil? || k.empty? || v.nil?
|
|
127
|
+
|
|
128
|
+
acc[k.downcase.to_sym] = v
|
|
129
|
+
end
|
|
130
|
+
end
|
|
131
|
+
|
|
132
|
+
# Parse `Key=Value;Key=value;` into a string-keyed hash.
|
|
133
|
+
# Used internally for the @STEREO body fields.
|
|
134
|
+
def parse_semicolon_fields(body)
|
|
135
|
+
body.split(";").each_with_object({}) do |part, acc|
|
|
136
|
+
key, value = part.split("=", 2)
|
|
137
|
+
next if key.nil? || key.empty? || value.nil?
|
|
138
|
+
|
|
139
|
+
# Strip @END* terminators that may be attached when the
|
|
140
|
+
# body wasn't cleanly split (defensive — usually already
|
|
141
|
+
# consumed by STEREO_REGEX).
|
|
142
|
+
cleaned = value.sub(/@END\w+\z/, "")
|
|
143
|
+
acc[key] = cleaned
|
|
144
|
+
end
|
|
145
|
+
end
|
|
146
|
+
end
|
|
147
|
+
end
|
|
148
|
+
end
|
|
149
|
+
end
|
|
150
|
+
end
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Ea
|
|
4
|
+
module Sources
|
|
5
|
+
module Qea
|
|
6
|
+
module Xref
|
|
7
|
+
# Tagged-value / property definition record. Produced when the
|
|
8
|
+
# Description contains one or more `@PROP=@NAME=..@ENDNAME;`
|
|
9
|
+
# blocks for non-legend properties.
|
|
10
|
+
#
|
|
11
|
+
# Example source:
|
|
12
|
+
# @PROP=@NAME=isActive@ENDNAME;@TYPE=Boolean@ENDTYPE;
|
|
13
|
+
# @VALU=@ENDVALU;@PRMT=@ENDPRMT;@ENDPROP;
|
|
14
|
+
PropertyDefinition = Struct.new(:name, :type, :value, :parameter,
|
|
15
|
+
keyword_init: true) do
|
|
16
|
+
# @return [Boolean] true when the value field is non-empty
|
|
17
|
+
def default_value?
|
|
18
|
+
!value.nil? && !value.empty?
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
# @return [Boolean] true when the property is declared as Boolean
|
|
22
|
+
def boolean?
|
|
23
|
+
type == "Boolean"
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
end
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Ea
|
|
4
|
+
module Sources
|
|
5
|
+
module Qea
|
|
6
|
+
module Xref
|
|
7
|
+
# Parsed t_xref.Description. Holds typed records for each block
|
|
8
|
+
# found in the source string. One Description can carry multiple
|
|
9
|
+
# records (e.g., several `@PROP=` blocks defining a stereotype's
|
|
10
|
+
# tagged-value set).
|
|
11
|
+
#
|
|
12
|
+
# Consumers branch on record type without re-parsing strings.
|
|
13
|
+
Record = Struct.new(:stereotype, :properties, :legends,
|
|
14
|
+
:key_values, :raw, keyword_init: true) do
|
|
15
|
+
def initialize(*)
|
|
16
|
+
super
|
|
17
|
+
self.properties ||= []
|
|
18
|
+
self.legends ||= []
|
|
19
|
+
self.key_values ||= {}
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
# @return [Boolean] true when a stereotype application is present
|
|
23
|
+
def stereotype?
|
|
24
|
+
!stereotype.nil?
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
# @return [Boolean] true when at least one legend is present
|
|
28
|
+
def legend?
|
|
29
|
+
!legends.empty?
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
# Convenience: first legend's name (the legend's title).
|
|
33
|
+
# @return [String, nil]
|
|
34
|
+
def legend_title
|
|
35
|
+
legends.first&.name
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
end
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Ea
|
|
4
|
+
module Sources
|
|
5
|
+
module Qea
|
|
6
|
+
module Xref
|
|
7
|
+
# Stereotype application record. Produced when the Description
|
|
8
|
+
# starts with `@STEREO;`. Captures the short name and the
|
|
9
|
+
# fully-qualified `tech::Stereo` form when present.
|
|
10
|
+
#
|
|
11
|
+
# Example source:
|
|
12
|
+
# @STEREO;Name=FeatureType;FQName=GML::FeatureType;@ENDSTEREO;
|
|
13
|
+
StereotypeApplication = Struct.new(:name, :fqname, keyword_init: true) do
|
|
14
|
+
# Returns the technology prefix from FQName, or nil.
|
|
15
|
+
# @return [String, nil]
|
|
16
|
+
def technology
|
|
17
|
+
return nil unless fqname
|
|
18
|
+
|
|
19
|
+
idx = fqname.index("::")
|
|
20
|
+
idx ? fqname[0, idx] : nil
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
# Returns the stereotype name without technology prefix.
|
|
24
|
+
# Falls back to +name+ when FQName is absent.
|
|
25
|
+
# @return [String, nil]
|
|
26
|
+
def unqualified_name
|
|
27
|
+
if fqname && fqname.include?("::")
|
|
28
|
+
fqname.split("::", 2).last
|
|
29
|
+
else
|
|
30
|
+
name
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
end
|