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
|
@@ -8,12 +8,14 @@ module Ea
|
|
|
8
8
|
# consumers dispatch without `is_a?` ladders.
|
|
9
9
|
class Relationship < Base
|
|
10
10
|
attribute :qualified_name, :string
|
|
11
|
+
attribute :stereotype, :string
|
|
11
12
|
attribute :relationship_kind, :string, default: -> { "relationship" }
|
|
12
13
|
|
|
13
14
|
json do
|
|
14
15
|
map "id", to: :id
|
|
15
16
|
map "name", to: :name
|
|
16
17
|
map "qualifiedName", to: :qualified_name
|
|
18
|
+
map "stereotype", to: :stereotype
|
|
17
19
|
map "relationshipKind", to: :relationship_kind, render_default: true
|
|
18
20
|
end
|
|
19
21
|
end
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Ea
|
|
4
|
+
module Model
|
|
5
|
+
# UML Signal: a classifier whose instances represent
|
|
6
|
+
# asynchronous communications between objects. Distinct from
|
|
7
|
+
# Klass because EA renders its header with the «signal»
|
|
8
|
+
# stereotype fallback and supports a separate "receptions"
|
|
9
|
+
# compartment.
|
|
10
|
+
class Signal < Classifier
|
|
11
|
+
attribute :model_kind, :string, default: -> { "signal" }
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
end
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Ea
|
|
4
|
+
module Model
|
|
5
|
+
# A single slot (variable = value) on an InstanceSpecification.
|
|
6
|
+
class Slot < Base
|
|
7
|
+
attribute :name, :string
|
|
8
|
+
attribute :value, :string
|
|
9
|
+
attribute :op, :string, default: -> { "=" }
|
|
10
|
+
|
|
11
|
+
json do
|
|
12
|
+
map "id", to: :id
|
|
13
|
+
map "name", to: :name
|
|
14
|
+
map "value", to: :value
|
|
15
|
+
map "op", to: :op
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
end
|
data/lib/ea/model.rb
CHANGED
|
@@ -23,17 +23,25 @@ module Ea
|
|
|
23
23
|
autoload :Waypoint, "ea/model/waypoint"
|
|
24
24
|
autoload :Annotation, "ea/model/annotation"
|
|
25
25
|
autoload :TaggedValue, "ea/model/tagged_value"
|
|
26
|
+
autoload :Constraint, "ea/model/constraint"
|
|
27
|
+
autoload :Slot, "ea/model/slot"
|
|
28
|
+
autoload :InstanceSpecification, "ea/model/instance_specification"
|
|
26
29
|
autoload :Stereotype, "ea/model/stereotype"
|
|
27
30
|
autoload :EnumerationLiteral, "ea/model/enumeration_literal"
|
|
28
31
|
autoload :Parameter, "ea/model/parameter"
|
|
29
32
|
autoload :Property, "ea/model/property"
|
|
30
33
|
autoload :Operation, "ea/model/operation"
|
|
34
|
+
autoload :Note, "ea/model/note"
|
|
35
|
+
autoload :Legend, "ea/model/legend"
|
|
36
|
+
autoload :LegendItem, "ea/model/legend_item"
|
|
37
|
+
autoload :GhostLabel, "ea/model/ghost_label"
|
|
31
38
|
autoload :Classifier, "ea/model/classifier"
|
|
32
39
|
autoload :Klass, "ea/model/klass"
|
|
33
40
|
autoload :DataType, "ea/model/data_type"
|
|
34
41
|
autoload :PrimitiveType, "ea/model/primitive_type"
|
|
35
42
|
autoload :Interface, "ea/model/interface"
|
|
36
43
|
autoload :Enumeration, "ea/model/enumeration"
|
|
44
|
+
autoload :Signal, "ea/model/signal"
|
|
37
45
|
autoload :Package, "ea/model/package"
|
|
38
46
|
autoload :Relationship, "ea/model/relationship"
|
|
39
47
|
autoload :Association, "ea/model/association"
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Ea
|
|
4
|
+
module Ocl
|
|
5
|
+
# Evaluates an AST produced by Parser against a context object
|
|
6
|
+
# (the model element under test). Dispatches on node class.
|
|
7
|
+
module Evaluator
|
|
8
|
+
module_function
|
|
9
|
+
|
|
10
|
+
# @param ast [Nodes::*]
|
|
11
|
+
# @param context [Object] the model element (self)
|
|
12
|
+
# @return [Boolean, Object] result of evaluation
|
|
13
|
+
def evaluate(ast, context)
|
|
14
|
+
case ast
|
|
15
|
+
when Nodes::Literal then ast.value
|
|
16
|
+
when Nodes::AttributeAccess then attribute_value(context, ast.name)
|
|
17
|
+
when Nodes::StringMatches then eval_string_matches(ast, context)
|
|
18
|
+
when Nodes::CollectionExists then eval_exists(ast, context)
|
|
19
|
+
when Nodes::CollectionForAll then eval_for_all(ast, context)
|
|
20
|
+
when Nodes::BinaryOp then eval_binary(ast, context)
|
|
21
|
+
when Nodes::UnaryOp then eval_unary(ast, context)
|
|
22
|
+
else
|
|
23
|
+
raise UnsupportedError,
|
|
24
|
+
"Cannot evaluate AST node: #{ast.class}"
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def attribute_value(context, name)
|
|
29
|
+
return nil unless context
|
|
30
|
+
|
|
31
|
+
context.public_send(name)
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def eval_string_matches(ast, context)
|
|
35
|
+
target = evaluate(ast.string, context).to_s
|
|
36
|
+
Regexp.new(ast.pattern).match?(target)
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
def eval_exists(ast, context)
|
|
40
|
+
collection = evaluate(ast.collection, context)
|
|
41
|
+
return false unless collection.respond_to?(:each)
|
|
42
|
+
|
|
43
|
+
var_name = ast.var
|
|
44
|
+
predicate = ast.predicate
|
|
45
|
+
collection.any? do |element|
|
|
46
|
+
evaluate(predicate, var_binding(context, var_name, element))
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
def eval_for_all(ast, context)
|
|
51
|
+
collection = evaluate(ast.collection, context)
|
|
52
|
+
return true unless collection.respond_to?(:each)
|
|
53
|
+
|
|
54
|
+
var_name = ast.var
|
|
55
|
+
predicate = ast.predicate
|
|
56
|
+
collection.all? do |element|
|
|
57
|
+
evaluate(predicate, var_binding(context, var_name, element))
|
|
58
|
+
end
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
def eval_binary(ast, context)
|
|
62
|
+
left = evaluate(ast.left, context)
|
|
63
|
+
right = evaluate(ast.right, context)
|
|
64
|
+
case ast.op
|
|
65
|
+
when :and then left && right
|
|
66
|
+
when :or then left || right
|
|
67
|
+
else raise UnsupportedError, "Unknown binary op: #{ast.op}"
|
|
68
|
+
end
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
def eval_unary(ast, context)
|
|
72
|
+
case ast.op
|
|
73
|
+
when :not then !evaluate(ast.operand, context)
|
|
74
|
+
else raise UnsupportedError, "Unknown unary op: #{ast.op}"
|
|
75
|
+
end
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
# Bind a variable name in the evaluation context. Uses a small
|
|
79
|
+
# Struct wrapper so attribute lookups still fall through to the
|
|
80
|
+
# original context.
|
|
81
|
+
VarBinding = Struct.new(:context, :var_name, :value, keyword_init: true) do
|
|
82
|
+
def public_send(method_name, *args)
|
|
83
|
+
return value if method_name == var_name
|
|
84
|
+
|
|
85
|
+
context.public_send(method_name, *args)
|
|
86
|
+
end
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
def var_binding(context, var_name, value)
|
|
90
|
+
VarBinding.new(context: context, var_name: var_name, value: value)
|
|
91
|
+
end
|
|
92
|
+
end
|
|
93
|
+
end
|
|
94
|
+
end
|
data/lib/ea/ocl/nodes.rb
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Ea
|
|
4
|
+
module Ocl
|
|
5
|
+
# AST node types for the parser. Each is a small Struct that the
|
|
6
|
+
# Evaluator dispatches on by class.
|
|
7
|
+
module Nodes
|
|
8
|
+
# `self.<attr>` access — read attribute on the context object.
|
|
9
|
+
AttributeAccess = Struct.new(:name, keyword_init: true)
|
|
10
|
+
|
|
11
|
+
# Literal value (number, string, boolean).
|
|
12
|
+
Literal = Struct.new(:value, keyword_init: true)
|
|
13
|
+
|
|
14
|
+
# `<collection>->exists(var | <pred>)` — true if any element matches.
|
|
15
|
+
CollectionExists = Struct.new(:collection, :var, :predicate,
|
|
16
|
+
keyword_init: true)
|
|
17
|
+
|
|
18
|
+
# `<collection>->forAll(var | <pred>)` — true if all match.
|
|
19
|
+
CollectionForAll = Struct.new(:collection, :var, :predicate,
|
|
20
|
+
keyword_init: true)
|
|
21
|
+
|
|
22
|
+
# `<string>.matches('<regex>')`
|
|
23
|
+
StringMatches = Struct.new(:string, :pattern, keyword_init: true)
|
|
24
|
+
|
|
25
|
+
# `<a> and <b>`, `<a> or <b>`, `not <a>`
|
|
26
|
+
BinaryOp = Struct.new(:op, :left, :right, keyword_init: true)
|
|
27
|
+
UnaryOp = Struct.new(:op, :operand, keyword_init: true)
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
end
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Ea
|
|
4
|
+
module Ocl
|
|
5
|
+
# Tokenizer + parser for an OCL invariant subset. Returns an AST
|
|
6
|
+
# built from Nodes::* structs.
|
|
7
|
+
#
|
|
8
|
+
# Supported forms:
|
|
9
|
+
# inv: <expr>
|
|
10
|
+
# self.<attr>
|
|
11
|
+
# "<literal>"
|
|
12
|
+
# <collection>->exists(x | <pred>)
|
|
13
|
+
# <collection>->forAll(x | <pred>)
|
|
14
|
+
# <string>.matches('<regex>')
|
|
15
|
+
# <expr> and <expr>
|
|
16
|
+
# <expr> or <expr>
|
|
17
|
+
# not <expr>
|
|
18
|
+
module Parser
|
|
19
|
+
module_function
|
|
20
|
+
|
|
21
|
+
# @param source [String] OCL expression with optional `inv:` prefix
|
|
22
|
+
# @return [Array<Nodes::*>] AST nodes (one per top-level expression)
|
|
23
|
+
def parse(source)
|
|
24
|
+
return [] if source.nil? || source.empty?
|
|
25
|
+
|
|
26
|
+
body = strip_inv_prefix(source)
|
|
27
|
+
parse_expression(body)
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def strip_inv_prefix(source)
|
|
31
|
+
s = source.strip
|
|
32
|
+
s.sub(/\Ainv\s*:\s*/, "")
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
# Parse one expression. Returns a single AST node.
|
|
36
|
+
def parse_expression(source)
|
|
37
|
+
s = source.strip
|
|
38
|
+
|
|
39
|
+
# Strip outer parens
|
|
40
|
+
s = s[1..-2].strip while s.start_with?("(") && s.end_with?(")")
|
|
41
|
+
|
|
42
|
+
# 'not <expr>'
|
|
43
|
+
if s.start_with?("not ")
|
|
44
|
+
return Nodes::UnaryOp.new(op: :not,
|
|
45
|
+
operand: parse_expression(s[4..]))
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
# 'and' / 'or' at top level (find the operator not inside parens)
|
|
49
|
+
if (split = split_on_logical_op(s))
|
|
50
|
+
op, left, right = split
|
|
51
|
+
return Nodes::BinaryOp.new(op: op,
|
|
52
|
+
left: parse_expression(left),
|
|
53
|
+
right: parse_expression(right))
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
# Collection ->exists(...) or ->forAll(...)
|
|
57
|
+
if (m = s.match(/^(.+?)->(exists|forAll)\s*\(\s*(\w+)\s*\|\s*(.+?)\s*\)\z/))
|
|
58
|
+
return collection_node(m[2].to_sym, m[1], m[3], m[4])
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
# String.matches('regex')
|
|
62
|
+
if (m = s.match(/^(.+?)\.matches\(\s*['"](.+?)['"]\s*\)\z/))
|
|
63
|
+
return Nodes::StringMatches.new(string: parse_expression(m[1]),
|
|
64
|
+
pattern: m[2])
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
# Boolean literal — check BEFORE bare identifier
|
|
68
|
+
return Nodes::Literal.new(value: true) if s == "true"
|
|
69
|
+
return Nodes::Literal.new(value: false) if s == "false"
|
|
70
|
+
|
|
71
|
+
# Numeric literal
|
|
72
|
+
return Nodes::Literal.new(value: s.to_i) if s.match?(/\A-?\d+\z/)
|
|
73
|
+
return Nodes::Literal.new(value: s.to_f) if s.match?(/\A-?\d+\.\d+\z/)
|
|
74
|
+
|
|
75
|
+
# String literal
|
|
76
|
+
return Nodes::Literal.new(value: s[1..-2]) if s.match?(/\A['"].*['"]\z/)
|
|
77
|
+
|
|
78
|
+
# 'self.<attr>' or '<var>.<attr>' — both produce AttributeAccess.
|
|
79
|
+
if (m = s.match(/\A(?:self\.|[a-z_]\w*\.)([a-z_]\w*)\z/i))
|
|
80
|
+
return Nodes::AttributeAccess.new(name: m[1])
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
# Bare identifier — variable reference.
|
|
84
|
+
if (m = s.match(/\A([a-z_]\w*)\z/))
|
|
85
|
+
return Nodes::AttributeAccess.new(name: m[1])
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
raise UnsupportedError,
|
|
89
|
+
"Unsupported OCL expression: #{source.inspect}"
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
def collection_node(kind, collection_src, var, pred_src)
|
|
93
|
+
Nodes.const_get(kind == :exists ? :CollectionExists : :CollectionForAll)
|
|
94
|
+
.new(collection: parse_expression(collection_src),
|
|
95
|
+
var: var,
|
|
96
|
+
predicate: parse_expression(pred_src))
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
# Find the topmost ` and ` or ` or ` outside of parens.
|
|
100
|
+
# Returns [op, left_str, right_str] or nil.
|
|
101
|
+
def split_on_logical_op(source)
|
|
102
|
+
depth = 0
|
|
103
|
+
# Look for ' or ' first (lower precedence than 'and' in OCL?)
|
|
104
|
+
# Actually OCL: 'or' < 'xor' < 'and' < 'implies'. We pick the
|
|
105
|
+
# rightmost top-level operator (left-associative).
|
|
106
|
+
%i[and or].each do |op|
|
|
107
|
+
keyword = " #{op} "
|
|
108
|
+
idx = find_top_level(source, keyword)
|
|
109
|
+
next unless idx
|
|
110
|
+
|
|
111
|
+
return [op, source[0...idx], source[(idx + keyword.length)..]]
|
|
112
|
+
end
|
|
113
|
+
nil
|
|
114
|
+
end
|
|
115
|
+
|
|
116
|
+
# Find substring at depth 0 (not inside parens).
|
|
117
|
+
def find_top_level(source, substring)
|
|
118
|
+
depth = 0
|
|
119
|
+
i = 0
|
|
120
|
+
while i < source.length
|
|
121
|
+
c = source[i]
|
|
122
|
+
depth += 1 if c == "("
|
|
123
|
+
depth -= 1 if c == ")"
|
|
124
|
+
if depth.zero? && source[i, substring.length] == substring
|
|
125
|
+
return i
|
|
126
|
+
end
|
|
127
|
+
i += 1
|
|
128
|
+
end
|
|
129
|
+
nil
|
|
130
|
+
end
|
|
131
|
+
end
|
|
132
|
+
end
|
|
133
|
+
end
|
data/lib/ea/ocl.rb
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Ea
|
|
4
|
+
# OCL (Object Constraint Language) parser + evaluator namespace.
|
|
5
|
+
# Supports a subset of OCL invariant syntax sufficient for
|
|
6
|
+
# evaluating common EA constraints.
|
|
7
|
+
module Ocl
|
|
8
|
+
autoload :Parser, "ea/ocl/parser"
|
|
9
|
+
autoload :Evaluator, "ea/ocl/evaluator"
|
|
10
|
+
autoload :Nodes, "ea/ocl/nodes"
|
|
11
|
+
autoload :UnsupportedError, "ea/ocl/unsupported_error"
|
|
12
|
+
end
|
|
13
|
+
end
|
|
@@ -246,7 +246,7 @@ module Ea
|
|
|
246
246
|
# @param valid_ids [Set<String>] Set of valid xmi_ids
|
|
247
247
|
# @return [Boolean] True if valid or nil
|
|
248
248
|
def check_association_end_valid?(assoc, attr, valid_ids)
|
|
249
|
-
value = assoc
|
|
249
|
+
value = association_end_xmi_id(assoc, attr)
|
|
250
250
|
return true if value.nil?
|
|
251
251
|
|
|
252
252
|
valid_ids.include?(value)
|
|
@@ -258,20 +258,34 @@ module Ea
|
|
|
258
258
|
# @param valid_ids [Set<String>] Set of valid xmi_ids
|
|
259
259
|
# @param warnings [Array<String>] Warning accumulator
|
|
260
260
|
def add_invalid_end_warning(assoc, attr, valid_ids, warnings) # rubocop:disable Metrics/MethodLength
|
|
261
|
-
value = assoc
|
|
261
|
+
value = association_end_xmi_id(assoc, attr)
|
|
262
262
|
return if value.nil?
|
|
263
263
|
|
|
264
264
|
unless valid_ids.include?(value)
|
|
265
|
-
|
|
266
|
-
name_attr = attr.to_s.gsub("_xmi_id", "").to_sym
|
|
267
|
-
name_value = begin
|
|
268
|
-
assoc.public_send(name_attr)
|
|
269
|
-
rescue StandardError
|
|
270
|
-
nil
|
|
271
|
-
end
|
|
265
|
+
name_value = association_end_name(assoc, attr)
|
|
272
266
|
|
|
273
267
|
warnings << "Association #{assoc.xmi_id} references " \
|
|
274
|
-
"invalid #{
|
|
268
|
+
"invalid #{attr}: #{name_value}"
|
|
269
|
+
end
|
|
270
|
+
end
|
|
271
|
+
|
|
272
|
+
# Explicit dispatch for association end xmi_id attributes.
|
|
273
|
+
# Replaces dynamic `public_send(attr)` with a case statement
|
|
274
|
+
# so callers and types are statically known.
|
|
275
|
+
def association_end_xmi_id(assoc, attr)
|
|
276
|
+
case attr
|
|
277
|
+
when :member_end_xmi_id then assoc.member_end_xmi_id
|
|
278
|
+
when :owner_end_xmi_id then assoc.owner_end_xmi_id
|
|
279
|
+
else raise ArgumentError, "unknown association end: #{attr}"
|
|
280
|
+
end
|
|
281
|
+
end
|
|
282
|
+
|
|
283
|
+
# Explicit dispatch for association end display-name attributes.
|
|
284
|
+
def association_end_name(assoc, attr)
|
|
285
|
+
case attr
|
|
286
|
+
when :member_end_xmi_id then assoc.member_end
|
|
287
|
+
when :owner_end_xmi_id then assoc.owner_end
|
|
288
|
+
else raise ArgumentError, "unknown association end: #{attr}"
|
|
275
289
|
end
|
|
276
290
|
end
|
|
277
291
|
|
|
@@ -53,20 +53,18 @@ module Ea
|
|
|
53
53
|
end
|
|
54
54
|
|
|
55
55
|
def to_general_attribute(attr)
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
end
|
|
56
|
+
Lutaml::Uml::GeneralAttribute.new(
|
|
57
|
+
**base_attr_hash(attr),
|
|
58
|
+
is_derived: !!attr.is_derived,
|
|
59
|
+
has_association: !!attr.association
|
|
60
|
+
)
|
|
62
61
|
end
|
|
63
62
|
|
|
64
63
|
def to_top_element_attribute(attr)
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
end
|
|
64
|
+
Lutaml::Uml::TopElementAttribute.new(
|
|
65
|
+
**base_attr_hash(attr),
|
|
66
|
+
is_derived: !!attr.is_derived
|
|
67
|
+
)
|
|
70
68
|
end
|
|
71
69
|
|
|
72
70
|
def base_attr_hash(attr)
|
|
@@ -35,6 +35,15 @@ module Ea
|
|
|
35
35
|
@table_name = table_name
|
|
36
36
|
end
|
|
37
37
|
|
|
38
|
+
# @return [Boolean] true when the table exists in the database
|
|
39
|
+
def table_exists?
|
|
40
|
+
row = @database.get_first_row(
|
|
41
|
+
"SELECT name FROM sqlite_master WHERE type='table' AND name=?",
|
|
42
|
+
[@table_name]
|
|
43
|
+
)
|
|
44
|
+
!row.nil?
|
|
45
|
+
end
|
|
46
|
+
|
|
38
47
|
# Read all records from the table
|
|
39
48
|
#
|
|
40
49
|
# @param limit [Integer, nil] Maximum number of records to return
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Ea
|
|
4
|
+
module Qea
|
|
5
|
+
module Models
|
|
6
|
+
# Author / contributor from t_authors.
|
|
7
|
+
#
|
|
8
|
+
# Schema:
|
|
9
|
+
# (AuthorID INTEGER PRIMARY KEY, Name TEXT, Email TEXT,
|
|
10
|
+
# Notes TEXT, ...)
|
|
11
|
+
class EaAuthor < BaseModel
|
|
12
|
+
attribute :author_id, :integer
|
|
13
|
+
attribute :name, :string
|
|
14
|
+
attribute :email, :string
|
|
15
|
+
attribute :notes, :string
|
|
16
|
+
|
|
17
|
+
def self.primary_key_column
|
|
18
|
+
:author_id
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def self.table_name
|
|
22
|
+
"t_authors"
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
COLUMN_MAP = {
|
|
26
|
+
"AuthorID" => :author_id
|
|
27
|
+
}.freeze
|
|
28
|
+
|
|
29
|
+
def self.column_map
|
|
30
|
+
COLUMN_MAP
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
end
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Ea
|
|
4
|
+
module Qea
|
|
5
|
+
module Models
|
|
6
|
+
# Glossary term from t_glossary.
|
|
7
|
+
#
|
|
8
|
+
# Schema:
|
|
9
|
+
# (Term TEXT, Type TEXT, Meaning TEXT, GlossaryID INTEGER PRIMARY KEY)
|
|
10
|
+
class EaGlossary < BaseModel
|
|
11
|
+
attribute :glossary_id, :integer
|
|
12
|
+
attribute :term, :string
|
|
13
|
+
attribute :type, :string
|
|
14
|
+
attribute :meaning, :string
|
|
15
|
+
|
|
16
|
+
def self.primary_key_column
|
|
17
|
+
:glossary_id
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def self.table_name
|
|
21
|
+
"t_glossary"
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
COLUMN_MAP = {
|
|
25
|
+
"GlossaryID" => :glossary_id
|
|
26
|
+
}.freeze
|
|
27
|
+
|
|
28
|
+
def self.column_map
|
|
29
|
+
COLUMN_MAP
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
end
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Ea
|
|
4
|
+
module Qea
|
|
5
|
+
module Models
|
|
6
|
+
# Raw-row model for `t_image`. EA stores pasted images as EMF
|
|
7
|
+
# (Enhanced Metafile) blobs in this table.
|
|
8
|
+
#
|
|
9
|
+
# `type` values observed in real QEAs:
|
|
10
|
+
# - "ENHMetafile" — Enhanced Windows Metafile (most common)
|
|
11
|
+
# - "Metafile" — Old-style WMF
|
|
12
|
+
# - "Bitmap" — DIB / PNG bitmap
|
|
13
|
+
class EaImage < BaseModel
|
|
14
|
+
attribute :image_id, :integer
|
|
15
|
+
attribute :name, :string
|
|
16
|
+
attribute :type, :string
|
|
17
|
+
attribute :image, :string
|
|
18
|
+
|
|
19
|
+
def self.primary_key_column
|
|
20
|
+
:image_id
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def self.table_name
|
|
24
|
+
"t_image"
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
COLUMN_MAP = {
|
|
28
|
+
"ImageID" => :image_id
|
|
29
|
+
}.freeze
|
|
30
|
+
|
|
31
|
+
def self.column_map
|
|
32
|
+
COLUMN_MAP
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
# @return [Boolean] true when this row holds an EMF blob
|
|
36
|
+
def emf?
|
|
37
|
+
type&.casecmp?("ENHMetafile")
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
# @return [Boolean] true when this row holds a WMF blob
|
|
41
|
+
def wmf?
|
|
42
|
+
type&.casecmp?("Metafile")
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
# Raw image bytes. SQLite returns BLOB as ASCII-8BIT String.
|
|
46
|
+
# @return [String, nil] binary string
|
|
47
|
+
def bytes
|
|
48
|
+
image
|
|
49
|
+
end
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
end
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Ea
|
|
4
|
+
module Qea
|
|
5
|
+
module Models
|
|
6
|
+
# UML-to-code mapping hint from t_implement.
|
|
7
|
+
class EaImplement < BaseModel
|
|
8
|
+
attribute :implement_id, :integer
|
|
9
|
+
attribute :object_id, :integer
|
|
10
|
+
attribute :language, :string
|
|
11
|
+
attribute :code, :string
|
|
12
|
+
|
|
13
|
+
def self.primary_key_column
|
|
14
|
+
:implement_id
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def self.table_name
|
|
18
|
+
"t_implement"
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
COLUMN_MAP = {
|
|
22
|
+
"ImplementID" => :implement_id,
|
|
23
|
+
"Object_ID" => :object_id
|
|
24
|
+
}.freeze
|
|
25
|
+
|
|
26
|
+
def self.column_map
|
|
27
|
+
COLUMN_MAP
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
end
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Ea
|
|
4
|
+
module Qea
|
|
5
|
+
module Models
|
|
6
|
+
# Enumeration list value from t_lists.
|
|
7
|
+
#
|
|
8
|
+
# Schema:
|
|
9
|
+
# (ListID TEXT PRIMARY KEY, Category TEXT, Name TEXT,
|
|
10
|
+
# NVal INTEGER, Notes TEXT)
|
|
11
|
+
class EaList < BaseModel
|
|
12
|
+
attribute :list_id, :string
|
|
13
|
+
attribute :category, :string
|
|
14
|
+
attribute :name, :string
|
|
15
|
+
attribute :nval, :integer
|
|
16
|
+
attribute :notes, :string
|
|
17
|
+
|
|
18
|
+
def self.primary_key_column
|
|
19
|
+
:list_id
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def self.table_name
|
|
23
|
+
"t_lists"
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
COLUMN_MAP = {
|
|
27
|
+
"ListID" => :list_id,
|
|
28
|
+
"NVal" => :nval
|
|
29
|
+
}.freeze
|
|
30
|
+
|
|
31
|
+
def self.column_map
|
|
32
|
+
COLUMN_MAP
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
# @return [Boolean] true when this row carries a numeric value
|
|
36
|
+
def numeric?
|
|
37
|
+
!nval.nil?
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
end
|