Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions .github/workflows/tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,12 @@ jobs:
- name: Run Validation Tooling tests
run: |
bazel test //validation/...
- name: Run Tools clippy
run: |
bazel build //tools/... --config=clippy
- name: Run Tools tests
run: |
bazel test //tools/...
- name: Ensure correct dependency resolution
run: |
bazel mod deps --lockfile_mode=update
Expand Down
32 changes: 29 additions & 3 deletions plantuml/parser/docs/element-identifiers.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,31 @@ to author diagrams so that the links actually resolve.

---

## 0. Implementation status

This guide describes the target design. As of this writing, only part of it is
implemented on `main`; the rest lands incrementally. The
[cross-diagram test suite](../integration_test/cross_diagram/) pins down
exactly what is true today with executable goldens — when a row below changes,
that suite's goldens change with it.

| Topic | Today (`main`) | Target (this guide) | Test case |
|-------|----------------|----------------------|-----------|
| Root anchor ([§1](#1-the-three-inputs), [Rule D](#rule-d)) | **not implemented** — identifiers have no Bazel-package prefix | `ctx.label.package` prepended to every identifier | — |
| Component id leaf ([§2](#2-component-diagrams), [Rule A](#rule-a)) | implemented — alias when present, else name | (same) | `component_nesting` |
| Class id leaf ([§3](#3-class-diagrams), [Rule A](#rule-a)) | **not implemented** — the label/internal name is used, not the alias | alias wins over the label | `class_alias_wins` |
| Class/component reference resolution ([§5](#5-linking-the-three-diagrams), [Rule C](#rule-c)) | first match, qualified names accepted unchecked | nearest enclosing scope, existence and ambiguity checked | `qualified_reference` |
| Sequence participant identity ([§4](#4-sequence-diagrams), [Rule B](#rule-b)) | **not implemented** — identity is the alias, else the display name, verbatim (none of the label forms are parsed) | `uid` derived from the label per the label forms | `sequence_forms`, `prose_without_alias` |
| Sequence ↔ component/class linking ([§5](#5-linking-the-three-diagrams)) | works only by coincidence when both sides use a plain, un-nested alias | component/class id == participant uid | `linking_three_diagrams`, `component_nesting` |
| `ExternalEndpoint` marker ([§6](#6-special-cases), [Rule E](#rule-e)) | **not implemented** — no such reserved participant exists | emitted verbatim, never anchored | — |
| Errors in [§7](#7-errors-you-may-hit) (`free-text participant display names require an alias…`, `multiple standalone ':' separators…`, `Duplicate entity id`, `duplicate sequence participant id`) | **not implemented** — none of these diagnostics exist yet; the rejected forms currently parse without error | as described | `prose_without_alias` |
| Id normalization (`::` / `.` equivalence, [Definitions](#definitions)) | implemented for scope paths inside one class diagram; `::` in class and component relationship endpoints (`A --> ns::B`) is rejected, not normalized | works everywhere an identifier is read or written | `namespace_and_package`, `qualified_reference` |
| Label markup stripping (creole tags in labels) | implemented for activity diagram labels only | also strips markup from sequence participant labels before Rule B derivation | — |
| Qualified name inside a nested declaration ([§9](#9-current-limitations)) | **bug** — appended to the enclosing scope instead of replacing it | replaces the enclosing scope | — |
| Cross-diagram hyperlinks (`idmap`) for sequence participants ([§9](#9-current-limitations)) | not identifier-based; links from a sequence participant may not resolve | identifier-based, same as component/class | — |

---

## 1. The three inputs

An identifier is assembled from exactly three things:
Expand Down Expand Up @@ -136,7 +161,7 @@ up.
Sequence diagrams have no nesting, so the whole scope has to be written into
the label.

### The four forms
### The label forms

| What you write | Identity is taken from | Resulting identifier |
|----------------|------------------------|----------------------|
Expand Down Expand Up @@ -331,7 +356,9 @@ participant "Display Service" as DisplayService

## 9. Current limitations

Known gaps between this guide and the present implementation:
See the [implementation status table](#0-implementation-status) for what is and
isn't implemented yet. The two rows below are bugs rather than pending work —
they have no planned test case and no target-design row of their own:

- **A qualified name used in a *declaration* inside a block is appended to the
enclosing scope instead of replacing it.** For example
Expand All @@ -341,7 +368,6 @@ Known gaps between this guide and the present implementation:
- **Cross-diagram hyperlinks (`idmap`) are not yet identifier-based for
sequence diagrams**, so clickable links from a sequence participant to its
component may not resolve.
- **Cross-diagrams in Class Diagrams** also have a bug currently

---

Expand Down
4 changes: 4 additions & 0 deletions plantuml/parser/docs/sequence-diagram.md
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,8 @@ The alias form is recommended. Although `participant OrderService as "Order Serv

A quoted free-text display name **requires** an alias — `participant "Order Service"` on its own is rejected, because the resolver cannot derive an identifier from it. See [Element Identifiers](element-identifiers.md) for how the identifier is built from the display name and why the qualified form `"instance : package::Component::Unit"` is preferred for diagrams that must link to a component or class diagram.

> **Not yet implemented.** Today `participant "Order Service"` without an alias is accepted; the display name itself becomes the participant's identity. The rejection described above, and the label-derived `uid` it depends on, land with Rule B — see [Element Identifiers §0](element-identifiers.md#0-implementation-status).

The display name, alias, participant type, and stereotype are written to the logical model.

```text
Expand All @@ -76,6 +78,8 @@ Client -> OrderService : correct()

After declaring an alias, subsequent messages, lifecycle commands, and `ref` blocks must use that alias consistently. Referring to the quoted display name instead is rejected when that display name is free text.

> **Not yet implemented.** Today, referring to the quoted display name instead of the declared alias does not error — it silently creates a second, separate implicit participant keyed by that display name. See [Element Identifiers §0](element-identifiers.md#0-implementation-status).

Undeclared message endpoints are automatically created as regular `participant` instances. This is convenient for short diagrams, but explicit declarations are recommended for production diagrams to preserve participant type, stereotype, and stable source locations.

### Messages and arrow direction
Expand Down
39 changes: 39 additions & 0 deletions plantuml/parser/integration_test/cross_diagram/BUILD
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
# *******************************************************************************
# Copyright (c) 2026 Contributors to the Eclipse Foundation
#
# See the NOTICE file(s) distributed with this work for additional
# information regarding copyright ownership.
#
# This program and the accompanying materials are made available under the
# terms of the Apache License Version 2.0 which is available at
# https://www.apache.org/licenses/LICENSE-2.0
#
# SPDX-License-Identifier: Apache-2.0
# *******************************************************************************

load("@rules_rust//rust:defs.bzl", "rust_test")

filegroup(
name = "cross_diagram_files",
srcs = glob([
"**/*.json",
"**/*.puml",
"**/*.yaml",
]),
)

rust_test(
name = "cross_diagram_test",
srcs = ["cross_diagram_test.rs"],
crate_root = "cross_diagram_test.rs",
data = [
":cross_diagram_files",
"//plantuml/parser/puml_cli",
],
deps = [
"//plantuml/parser/integration_test:test_framework",
"@crates//:serde",
"@crates//:serde_json",
"@crates//:serde_yaml",
],
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
# *******************************************************************************
# Copyright (c) 2026 Contributors to the Eclipse Foundation
#
# See the NOTICE file(s) distributed with this work for additional
# information regarding copyright ownership.
#
# This program and the accompanying materials are made available under the
# terms of the Apache License Version 2.0 which is available at
# https://www.apache.org/licenses/LICENSE-2.0
#
# SPDX-License-Identifier: Apache-2.0
# *******************************************************************************
# Regression baseline: today a class's idmap id is derived from its label
# text, not its alias, so an aliased class with a display label still
# surfaces the label as the id. This is expected to change once Rule A
# (alias wins) is implemented; the golden then becomes
# `SampleLibraryAPI: "SampleLibraryAPI"`.
diagram_types:
class_diagram.puml: class
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
' *******************************************************************************
' Copyright (c) 2026 Contributors to the Eclipse Foundation
'
' See the NOTICE file(s) distributed with this work for additional
' information regarding copyright ownership.
'
' This program and the accompanying materials are made available under the
' terms of the Apache License Version 2.0 which is available at
' https://www.apache.org/licenses/LICENSE-2.0
'
' SPDX-License-Identifier: Apache-2.0
' *******************************************************************************
@startuml
class "Sample Library API" as SampleLibraryAPI {
+GetNumber() : int
}
@enduml
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
{
"class_diagram.puml": {
"defines": {
"SampleLibraryAPI": "Sample Library API"
},
"references": {}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
# *******************************************************************************
# Copyright (c) 2026 Contributors to the Eclipse Foundation
#
# See the NOTICE file(s) distributed with this work for additional
# information regarding copyright ownership.
#
# This program and the accompanying materials are made available under the
# terms of the Apache License Version 2.0 which is available at
# https://www.apache.org/licenses/LICENSE-2.0
#
# SPDX-License-Identifier: Apache-2.0
# *******************************************************************************
# Nested package -> component -> component. Each enclosing scope (package,
# outer component) is itself a "define" so it can be referenced/linked to,
# and the leaf components (aliased and bare) are "reference"s. The label
# ("Log Recorder") differs from the alias (Recorder) to prove the id is
# built from the alias, not the label. `distinct` records that a nested
# component does not accidentally link to a same-named sequence participant
# today, since the component's id carries the full nesting chain and the
# participant's does not (no root anchor yet).
diagram_types:
component_diagram.puml: component
sequence_diagram.puml: sequence
distinct:
- ["component_diagram.puml#Backend", "sequence_diagram.puml#Backend"]
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
' *******************************************************************************
' Copyright (c) 2026 Contributors to the Eclipse Foundation
'
' See the NOTICE file(s) distributed with this work for additional
' information regarding copyright ownership.
'
' This program and the accompanying materials are made available under the
' terms of the Apache License Version 2.0 which is available at
' https://www.apache.org/licenses/LICENSE-2.0
'
' SPDX-License-Identifier: Apache-2.0
' *******************************************************************************
@startuml
package "score.mw.log" as logging {
component "Log Recorder" as Recorder {
component "Backend" as Backend
component Frontend
}
}
@enduml
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
{
"component_diagram.puml": {
"defines": {
"logging": "logging",
"Recorder": "logging.Recorder"
},
"references": {
"Backend": "logging.Recorder.Backend",
"Frontend": "logging.Recorder.Frontend"
}
},
"sequence_diagram.puml": {
"defines": {},
"references": {
"Backend": "Backend"
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
' *******************************************************************************
' Copyright (c) 2026 Contributors to the Eclipse Foundation
'
' See the NOTICE file(s) distributed with this work for additional
' information regarding copyright ownership.
'
' This program and the accompanying materials are made available under the
' terms of the Apache License Version 2.0 which is available at
' https://www.apache.org/licenses/LICENSE-2.0
'
' SPDX-License-Identifier: Apache-2.0
' *******************************************************************************
@startuml
participant Backend
@enduml
Loading
Loading