diff --git a/.cspell.yaml b/.cspell.yaml index 2d32ea0e..c1d0b72f 100644 --- a/.cspell.yaml +++ b/.cspell.yaml @@ -119,6 +119,7 @@ ignorePaths: - "**/Stdlib/**" - "**/AGENT_REPORT_*.md" - "**/.agent-logs/**" + - "ROADMAP.md" - "**/bin/**" - "**/obj/**" - package-lock.json diff --git a/.markdownlint-cli2.yaml b/.markdownlint-cli2.yaml index 49427468..41435b54 100644 --- a/.markdownlint-cli2.yaml +++ b/.markdownlint-cli2.yaml @@ -53,3 +53,4 @@ ignores: - "**/generated/**" - "**/AGENT_REPORT_*.md" - "**/.agent-logs/**" + - "ROADMAP.md" diff --git a/ROADMAP.md b/ROADMAP.md new file mode 100644 index 00000000..32a70a05 --- /dev/null +++ b/ROADMAP.md @@ -0,0 +1,764 @@ +# SysML2Tools Rendering Roadmap + +This document tracks the planned rendering coverage for SysML2Tools relative to +the eight SysML v2 diagram view types defined in the OMG specification and +implemented by the SysON reference tool. + +## Implementation Status (Phases 0–5 Complete) + +Phases 0–5 described in `SysML2Tools-architecture.md` are complete. The tool +successfully parses all OMG example models, resolves the standard library, renders +`GeneralView` diagrams to SVG and PNG, and ships as a `dotnet tool` NuGet package. + +The remainder of this document describes the incremental rendering roadmap (Phase 6 +onward) needed to reach full SysML v2 view coverage. + +--- + +## SysML v2 View Types β€” Coverage Summary + +| # | View Type | Purpose | Our Status | +|---|-----------|---------|------------| +| 1 | **General View** | Any model element; foundational "catch-all" view | 🟑 Partial | +| 2 | **Interconnection View** | Structural contents of a Usage (parts, ports, connectors) | πŸ”΄ Unsupported | +| 3 | **Action Flow View** | Input/output flows between actions (behavioral dynamics) | πŸ”΄ Unsupported | +| 4 | **State Transition View** | States and transitions (behavioral dynamics) | πŸ”΄ Unsupported | +| 5 | **Sequence View** | Chronological event occurrences on lifelines | πŸ”΄ Unsupported | +| 6 | **Grid View** | Elements in structured rectangular grid (tabular/matrix) | πŸ”΄ Unsupported | +| 7 | **Browser View** | Hierarchical membership structure from a root element | πŸ”΄ Unsupported | +| 8 | **Geometry View** | Spatial items in 2D or 3D | πŸ”΄ Unsupported | + +--- + +## 1. General View β€” Detailed Gap Analysis + +The General View is the most broadly applicable view. SysON defines six categories of +representable elements. Our current implementation covers a fraction of one category. + +### 1.1 Definition Nodes + +| Definition Type | SysON Spec | We Render | AST Parsed | +|---|---|---|---| +| Part Definition | βœ… | βœ… | βœ… | +| Attribute Definition | βœ… | ❌ | βœ… | +| Item Definition | βœ… | ❌ | βœ… | +| Port Definition | βœ… | ❌ | ❌ | +| Interface Definition | βœ… | ❌ | ❌ | +| Connection Definition | βœ… | ❌ | ❌ | +| Requirement Definition | βœ… | ❌ | ❌ | +| Use Case Definition | βœ… | ❌ | ❌ | +| Action Definition | βœ… | ❌ | ❌ | +| Allocation Definition | βœ… | ❌ | ❌ | +| Constraint Definition | βœ… | ❌ | ❌ | +| Enumeration Definition | βœ… | ❌ | ❌ | +| Metadata Definition | βœ… | ❌ | ❌ | +| Occurrence Definition | βœ… | ❌ | ❌ | + +> **Note:** `attribute def` and `item def` are parsed by `AstBuilder` but not yet +> rendered. All other missing types require both AST visitor additions and rendering. + +### 1.2 Usage Nodes (rendered with rounded-corner rectangles in SysON) + +| Usage Type | SysON Spec | We Render | AST Parsed | +|---|---|---|---| +| Part Usage | βœ… | ❌ | Partial (`SysmlFeatureNode` β€” no keyword) | +| Attribute Usage | βœ… | ❌ | Partial | +| Port Usage | βœ… | ❌ | Partial | +| Interface Usage | βœ… | ❌ | Partial | +| Item Usage | βœ… | ❌ | Partial | +| Occurrence Usage | βœ… | ❌ | Partial | +| Constraint Usage | βœ… | ❌ | Partial | +| Requirement Usage | βœ… | ❌ | Partial | +| Use Case Usage | βœ… | ❌ | Partial | +| Action Usage | βœ… | ❌ | Partial | +| Allocation Usage | βœ… | ❌ | Partial | +| Accept Action Usage | βœ… | ❌ | Partial | + +> **Note:** `SysmlFeatureNode` exists and is populated but does not capture the +> feature keyword (e.g., `"part"`, `"port"`, `"attribute"`). All usage rendering +> requires that keyword to be tracked. + +### 1.3 Definition Compartments (attributes, ports, etc. inside a Definition node) + +| Compartment Content | SysON Spec | We Render | +|---|---|---| +| Attributes inside any Definition | βœ… | ❌ | +| Ports inside Part Def / Interface Def | βœ… | ❌ | +| Documentation inside any Definition | βœ… | ❌ | +| Enumerated Values inside Enum Def | βœ… | ❌ | +| Constraints inside Constraint Def | βœ… | ❌ | +| Actions inside Action Def | βœ… | ❌ | +| Assumed/Required Constraints in Requirement Def | βœ… | ❌ | + +### 1.4 Usage Compartments (attributes, ports, etc. inside a Usage node) + +| Compartment Content | SysON Spec | We Render | +|---|---|---| +| Attributes inside Part/Interface/Item/Port Usage | βœ… | ❌ | +| Ports inside Part / Interface Usage | βœ… | ❌ | +| Reference inside Attribute/Item/Port Usage | βœ… | ❌ | +| Documentation inside any Usage | βœ… | ❌ | + +### 1.5 Package Nodes + +| Element | SysON Spec | We Render | +|---|---|---| +| Package node (folder shape, `package` keyword label) | βœ… | ❌ (used as grouping label only) | + +### 1.6 Annotating Elements + +| Element | SysON Spec | We Render | +|---|---|---| +| Documentation node (note shape, `doc` keyword) | βœ… | ❌ | +| Comment node (note shape, `comment` keyword) | βœ… | ❌ | + +### 1.7 Relationship Edges + +| Relationship | SysON Spec | We Render | +|---|---|---| +| Subclassification | βœ… | βœ… | +| Dependency | βœ… | ❌ | +| Redefinition | βœ… | ❌ | +| Subsetting | βœ… | ❌ | +| Feature Typing | βœ… | ❌ | +| Allocation | βœ… | ❌ | +| Containment | βœ… | ❌ | +| Succession | βœ… | ❌ | +| Connection Usage | βœ… | ❌ | + +--- + +## 2. Interconnection View β€” Gap Analysis + +Shows the encapsulated structural contents of a **Usage** element: its owned parts, +ports, connectors, and interfaces. This is the "inside the box" view complementary +to the General View's "catalogue of definitions" perspective. + +| Element | SysON Spec | We Support | +|---|---|---| +| Root part Usage context box | βœ… | ❌ | +| Nested Part Usage nodes | βœ… | ❌ | +| Port nodes on boundary | βœ… | ❌ | +| Documentation/Comment annotations | βœ… | ❌ | +| Attribute compartment inside part | βœ… | ❌ | +| Nested parts compartment inside part | βœ… | ❌ | +| Port compartment inside part | βœ… | ❌ | +| Binding Connector (Usage) edge | βœ… | ❌ | +| Allocation edge | βœ… | ❌ | + +> **Note:** `LayoutPort` already exists in our `LayoutTree` vocabulary specifically +> for this view. + +--- + +## 3. Action Flow View β€” Gap Analysis + +Describes input/output flows between actions within a system. Useful for behavioral +analysis: action sequences, tokens, accept/send actions. + +| Element | SysON Spec | We Support | +|---|---|---| +| Action nodes | βœ… | ❌ | +| Start / Done / Fork / Join / Merge / Decision action nodes | βœ… | ❌ | +| Accept Action / Perform Action nodes | βœ… | ❌ | +| Succession flow edges | βœ… | ❌ | +| Item flow annotations on edges | βœ… | ❌ | + +> **Note:** `LayoutBand` in our vocabulary may be useful here for action swim-lanes. + +--- + +## 4. State Transition View β€” Gap Analysis + +Depicts states a system occupies and the guarded transitions between them. + +| Element | SysON Spec | We Support | +|---|---|---| +| State nodes | βœ… | ❌ | +| Initial / Final pseudo-states | βœ… | ❌ | +| Transition edges (with guard/trigger/effect labels) | βœ… | ❌ | +| Nested state regions | βœ… | ❌ | + +--- + +## 5. Sequence View β€” Gap Analysis + +Presents the chronological order of event occurrences on lifelines. + +| Element | SysON Spec | We Support | +|---|---|---| +| Lifeline columns | βœ… | ❌ | +| Occurrence / message arrows between lifelines | βœ… | ❌ | +| Combined fragment boxes (alt, loop, opt) | βœ… | ❌ | +| Execution occurrence bars on lifelines | βœ… | ❌ | + +> **Note:** `LayoutLifeline` already exists in our `LayoutTree` vocabulary for +> exactly this view. + +--- + +## 6. Grid View β€” Gap Analysis + +Presents elements in a structured rectangular grid β€” generalizes Tabular View, +Data Value Tabular View, and Relationship Matrix View. + +| Element | SysON Spec | We Support | +|---|---|---| +| Row/column header cells | βœ… | ❌ | +| Data value cells | βœ… | ❌ | +| Relationship matrix cells | βœ… | ❌ | + +> **Note:** `LayoutGrid` already exists in our `LayoutTree` vocabulary for this view. + +--- + +## 7. Browser View β€” Gap Analysis + +Presents the hierarchical membership structure of model elements from a root element. + +| Element | SysON Spec | We Support | +|---|---|---| +| Tree nodes with expand/collapse | βœ… | ❌ | +| Hierarchical containment edges | βœ… | ❌ | + +--- + +## 8. Geometry View β€” Gap Analysis + +Presents exposed spatial items in 2D or 3D. Primarily for spatial/physical layout +of system components. + +| Element | SysON Spec | We Support | +|---|---|---| +| 2D spatial item placement | βœ… | ❌ | +| 3D spatial item placement | βœ… | ❌ | +| Spatial relationship connectors | βœ… | ❌ | + +> This is the most complex view to implement and requires 2D/3D coordinate data +> from the model. Lowest priority. + +--- + +## Implementation Phases (Phase 6 onward) + +## Acceptance Criteria Pattern + +Each phase gate uses two complementary checks: + +**Automated checks** are run by `pwsh ./build.ps1` and any engine-specific unit +tests. These verify correctness (no crashes, no overlapping boxes by coordinate +arithmetic, correct layer ordering in DAGs). + +**Visual inspection** leverages the multimodal capability of the implementing agent. +After publishing the tool and rendering specific test models to PNG, the agent reads +each PNG back using the `view` tool (which returns the image for visual analysis) +and checks the listed visual criteria. This catches layout quality issues that are +invisible to coordinate-arithmetic tests β€” for example, an edge that technically has +valid waypoints but visually routes through the middle of an unrelated box. + +The published binary and rendered images in `_check\` are temporary and must be +deleted after inspection. They are not committed to the repository. + +--- + +Rather than embedding layout algorithms inside each view strategy, the non-trivial +algorithms are extracted into reusable, independently testable **layout engines**. +View strategies become thin "semantic model β†’ engine input β†’ LayoutTree" adapters. + +Each non-trivial engine is introduced in the same phase as its first consuming view, +so it is validated against real visual output immediately. Trivial layouts (Sequence, +Grid, Browser, Geometry) require no engine β€” pure arithmetic in the strategy class. + +**Engine inventory:** + +| Engine | Category | First Used In | Reused In | +|--------|----------|---------------|-----------| +| `ContainmentPacker` | Bottom-up size, bin packing | Phase 6 | Phase 7, 8 | +| `ChannelRouter` | Orthogonal edge routing around obstacles | Phase 6 | Phase 7, 8 | +| `ForceDirectedEngine` | Fruchterman-Reingold spring layout | Phase 8 | Phase 9 | +| `PortAssigner` | Port-side and slot heuristic | Phase 8 | β€” | +| `LayeredLayoutEngine` | Simplified Sugiyama DAG layout | Phase 10 | β€” | + +All engines live in `Layout/Engine/` and have their own unit tests with **synthetic +inputs** (no parser or view code required). Integration is validated through the +existing render integration tests. + +--- + +### Phase 6 β€” General View: All Definitions + Edges + ContainmentPacker + ChannelRouter (2–3 sessions) + +Highest-value incremental improvement: complete the General View to show all +Definition types and relationship edges, and simultaneously introduce the two layout +engines needed by all containment-based views. + +**Layout Engines introduced:** + +- `ContainmentPacker`: given a set of children with computed sizes, arranges them + within a parent container using a bin-packing pass; sizes the parent to fit. + Replaces the current hardcoded 2-column grid. +- `ChannelRouter`: given obstacle rectangles and source/target anchor points, routes + edges as horizontal/vertical segments through obstacle-free channels. Replaces the + current manual midpoint waypoint hack. + +**Semantic / AST scope:** + +- `AstBuilder`: add visitor methods for all missing Definition types (`port def`, + `interface def`, `connection def`, `requirement def`, `use case def`, `action def`, + `allocation def`, `constraint def`, `enum def`, `metadata def`, `occurrence def`) +- `SysmlDefinitionNode.DefinitionKeyword` is already generic β€” no changes needed + +**Layout / Rendering scope:** + +- `GeneralViewLayoutStrategy`: render all `SysmlDefinitionNode` types (not just + `"part def"`), with keyword prefix labels; use `ContainmentPacker` for placement +- Package nodes rendered as folder-tab shape instead of plain grouping label +- `SvgRenderer` / `PngRenderer`: keyword label rendering (e.g., `part def` on first + line of box in smaller italic font) +- Edges added: Dependency, Redefinition, Subsetting, Feature Typing, Containment; + all routed via `ChannelRouter` + +**Acceptance Criteria:** + +*Automated (must all pass):* + +- [ ] `pwsh ./build.ps1` β€” zero errors, zero warnings +- [ ] `ContainmentPacker` unit tests pass: given N boxes of mixed sizes, no two + output rectangles overlap; parent bounds contain all children +- [ ] `ChannelRouter` unit tests pass: routed waypoints form only horizontal/vertical + segments; no segment intersects any obstacle rectangle + +*Visual inspection β€” agent renders PNG and reads each image with the `view` tool:* + +``` +dotnet publish src\DemaConsulting.SysML2Tools.Tool -f net10.0 -c Release -o _check --nologo -q +dotnet _check\DemaConsulting.SysML2Tools.dll render test\SysMLModels\OMG\2a-PartsInterconnection.sysml --auto --format png -o _check\phase6-parts.png +dotnet _check\DemaConsulting.SysML2Tools.dll render test\SysMLModels\OMG\1c-PortsAndFlows.sysml --auto --format png -o _check\phase6-ports.png +``` + +Agent views each PNG and asserts: + +- [ ] `part def`, `port def`, and other keyword-prefixed box labels are visible, with + keyword text on a separate smaller first line above the element name +- [ ] No two definition boxes visually overlap +- [ ] Relationship edges route around boxes β€” no edge drawn through an unrelated box +- [ ] Package containers render with folder-tab shape, not a plain rectangle +- [ ] Canvas margins are proportionate β€” no excessive blank space around content +- [ ] Delete `_check\` after inspection + +--- + +### Phase 7 β€” General View: Usage Nodes, Compartments + Annotating Elements (2–3 sessions) + +Extend the semantic model and layout to capture Usage (feature) elements and render +compartments and annotation nodes. No new engines required. + +**Semantic / AST scope:** + +- `SysmlFeatureNode`: add `FeatureKeyword` property (`"part"`, `"port"`, + `"attribute"`, `"interface"`, `"action"`, etc.) +- `AstBuilder`: populate `FeatureKeyword` for all feature/usage visitor methods + +**Layout / Rendering scope:** + +- `GeneralViewLayoutStrategy`: render Usage nodes as rounded-corner boxes nested + inside their parent Definition or Package container (uses `ContainmentPacker`) +- `LayoutBox.Compartments`: populate attribute/port compartment rows from children +- `SvgRenderer` / `PngRenderer`: render compartment separator lines and row text +- Documentation / Comment nodes rendered as note-shape boxes +- Remaining edges: Allocation, Succession, Connection Usage (via `ChannelRouter`) + +**Acceptance Criteria:** + +*Automated (must all pass):* + +- [ ] `pwsh ./build.ps1` β€” zero errors, zero warnings + +*Visual inspection β€” create a test fixture `test\SysMLModels\Custom\vehicle-with-usages.sysml` +containing a `part def Vehicle` with nested `part engine : Engine`, `port fuel : FuelPort`, +and a doc comment; render it and view the PNG:* + +``` +dotnet publish src\DemaConsulting.SysML2Tools.Tool -f net10.0 -c Release -o _check --nologo -q +dotnet _check\DemaConsulting.SysML2Tools.dll render test\SysMLModels\Custom\vehicle-with-usages.sysml --auto --format png -o _check\phase7-vehicle.png +dotnet _check\DemaConsulting.SysML2Tools.dll render test\SysMLModels\OMG\2a-PartsInterconnection.sysml --auto --format png -o _check\phase7-interconnection.png +``` + +Agent views each PNG and asserts: + +- [ ] Usage nodes (`part`, `port`) appear as rounded-corner boxes inside their parent + definition box (not as top-level boxes alongside it) +- [ ] Attributes and ports are listed as rows within a compartment section, separated + from the definition name by a horizontal rule +- [ ] Documentation/Comment nodes appear as note-shaped boxes (folded corner) with body text +- [ ] Connection Usage and Allocation edges are drawn and labelled where present +- [ ] Delete `_check\` after inspection + +--- + +### Phase 8 β€” Interconnection View + ForceDirectedEngine + PortAssigner (2–3 sessions) + +Implement the Interconnection View, introducing two new engines that will also be +reused by the State Transition View in Phase 9. + +**Layout Engines introduced:** + +- `ForceDirectedEngine`: Fruchterman-Reingold spring layout; takes a graph of nodes + (with sizes) and edges, iterates repulsion/attraction forces until stable, returns + node centre positions. Used to arrange parts within the root Usage container. +- `PortAssigner`: given a box and its connections to other boxes, assigns each port + to a side (Left/Right/Top/Bottom) using a directional heuristic, then distributes + multiple ports evenly along the assigned side. + +**Semantic / AST scope:** + +- No new AST nodes required; `SysmlFeatureNode` (Phase 7) covers part/port usages + +**Layout / Rendering scope:** + +- New `InterconnectionViewLayoutStrategy` +- `DiagramTypeRouter`: recognize `InterconnectionView` viewpoint +- `LayoutPort`: wire into `SvgRenderer` / `PngRenderer` (small square on box boundary) +- Nested part boxes placed by `ForceDirectedEngine` inside the root Usage container +- Ports placed by `PortAssigner` on box boundaries +- Binding Connector and Allocation edges routed by `ChannelRouter` between ports + +**Acceptance Criteria:** + +*Automated (must all pass):* + +- [ ] `pwsh ./build.ps1` β€” zero errors, zero warnings +- [ ] `ForceDirectedEngine` unit tests pass: given N nodes with edges, output positions + have no two node bounding boxes overlapping after convergence +- [ ] `PortAssigner` unit tests pass: given a box with connections to boxes in each + cardinal direction, ports are assigned to the correct sides + +*Visual inspection β€” create `test\SysMLModels\Custom\vehicle-interconnection.sysml` +with a `vehicle : Vehicle` usage containing nested `engine`, `transmission`, `wheels` +parts with ports and connectors between them; declare an `InterconnectionView` on it:* + +``` +dotnet publish src\DemaConsulting.SysML2Tools.Tool -f net10.0 -c Release -o _check --nologo -q +dotnet _check\DemaConsulting.SysML2Tools.dll render test\SysMLModels\Custom\vehicle-interconnection.sysml --format png -o _check\phase8-interconnection.png +dotnet _check\DemaConsulting.SysML2Tools.dll render test\SysMLModels\OMG\2a-PartsInterconnection.sysml --format png -o _check\phase8-omg.png +``` + +Agent views each PNG and asserts: + +- [ ] Root usage renders as a large outer container box +- [ ] Nested part boxes float inside the container with no overlaps +- [ ] Port squares appear on the boundary edges of the boxes they belong to (not + floating in the interior or outside the parent) +- [ ] Connector lines travel from port to port β€” entering and leaving at the port + square position, not from box centre +- [ ] Connector lines do not cross through unrelated boxes +- [ ] Delete `_check\` after inspection + +--- + +### Phase 9 β€” State Transition View + Bezier Routing (2–3 sessions) + +Implement the State Transition View. Reuses `ForceDirectedEngine` from Phase 8; +adds curved/Bezier edge routing for the general-graph topology. + +**Semantic / AST scope:** + +- `AstBuilder`: capture state definitions (`state def`, `state`), transitions + (succession usages with guard/trigger/effect annotations) +- `SysmlDefinitionNode` / `SysmlFeatureNode` with appropriate keywords + +**Layout / Rendering scope:** + +- New `StateTransitionViewLayoutStrategy` +- `DiagramTypeRouter`: recognize `StateTransitionView` viewpoint +- State nodes (rounded rectangle), initial pseudo-state (filled circle), final + pseudo-state (bullseye) +- `ForceDirectedEngine`: place state nodes on canvas +- Bezier edge routing: compute control points from node centres and desired bend angle +- Self-loop routing: fixed arc bump offset above the node +- Parallel edge offset: opposite-direction edges between same pair offset perpendicularly +- Transition edge labels: guard/trigger/effect text at edge midpoint + +**Acceptance Criteria:** + +*Automated (must all pass):* + +- [ ] `pwsh ./build.ps1` β€” zero errors, zero warnings + +*Visual inspection β€” create `test\SysMLModels\Custom\traffic-light-states.sysml` +with a simple three-state machine (Red β†’ Green β†’ Yellow β†’ Red) with guard labels; +declare a `StateTransitionView` on it:* + +``` +dotnet publish src\DemaConsulting.SysML2Tools.Tool -f net10.0 -c Release -o _check --nologo -q +dotnet _check\DemaConsulting.SysML2Tools.dll render test\SysMLModels\Custom\traffic-light-states.sysml --format png -o _check\phase9-states.png +``` + +Agent views the PNG and asserts: + +- [ ] Three state nodes visible as rounded rectangles, clearly labelled Red/Green/Yellow +- [ ] An initial pseudo-state (filled circle) with an arrow entering the first state +- [ ] Transition arrows are curved, not straight horizontal/vertical β€” they have + visible curvature away from a direct straight-line path +- [ ] Transition guard labels appear beside the arrow midpoint, not overlapping any node +- [ ] No two state nodes overlap +- [ ] The overall layout is roughly circular or triangular β€” states are not all + stacked in a single column +- [ ] Delete `_check\` after inspection + +--- + +### Phase 10 β€” Action Flow View + LayeredLayoutEngine (2–3 sessions) + +Implement the Action Flow View, introducing the Sugiyama-style layered layout engine. + +**Layout Engine introduced:** + +- `LayeredLayoutEngine`: simplified Sugiyama framework for DAGs: + 1. **Cycle removal**: detect back-edges and temporarily reverse them + 2. **Layer assignment**: longest-path ranking assigns each node a rank/layer + 3. **Node ordering**: barycentre heuristic minimises edge crossings within layers + 4. **Coordinate assignment**: nodes centred over their edges (Brandes-KΓΆpf lite) + Returns absolute node positions; caller wraps in `LayoutBox`. + +**Semantic / AST scope:** + +- `AstBuilder`: capture action usages, succession flow edges, perform/accept actions, + start/done/fork/join/merge/decision action nodes + +**Layout / Rendering scope:** + +- New `ActionFlowViewLayoutStrategy` +- `DiagramTypeRouter`: recognize `ActionFlowView` viewpoint +- Action nodes, special node shapes (diamond for decision, horizontal bar for fork/join) +- `LayeredLayoutEngine`: determines layer and X position of each action node +- Succession flow edges with optional item flow annotation labels +- Back-edge routing: reversed edges drawn as curved back-arcs above the diagram +- Optional swim-lane bands (`LayoutBand`) partitioned by owning part/actor + +**Acceptance Criteria:** + +*Automated (must all pass):* + +- [ ] `pwsh ./build.ps1` β€” zero errors, zero warnings +- [ ] `LayeredLayoutEngine` unit tests pass: given a DAG, each node's Y is strictly + greater than all its predecessors' Y values (layer ordering preserved); no two + node bounding boxes in the same layer overlap horizontally + +*Visual inspection β€” create `test\SysMLModels\Custom\order-processing-actions.sysml` +with an action flow: Start β†’ Receive Order β†’ [Validate] β†’ (In Stock? β†’ Pick Items : +Back Order) β†’ Pack β†’ Ship β†’ Done; declare an `ActionFlowView`:* + +``` +dotnet publish src\DemaConsulting.SysML2Tools.Tool -f net10.0 -c Release -o _check --nologo -q +dotnet _check\DemaConsulting.SysML2Tools.dll render test\SysMLModels\Custom\order-processing-actions.sysml --format png -o _check\phase10-actions.png +``` + +Agent views the PNG and asserts: + +- [ ] Start node (filled circle) at the top; Done node (bullseye) at the bottom +- [ ] Action boxes arranged in clear top-to-bottom layers β€” no action at a higher Y + than any of its predecessors +- [ ] Decision node rendered as a diamond shape +- [ ] Flow edges enter boxes from the top and leave from the bottom (not from sides) +- [ ] Branch edges from the decision diamond go to two separate actions on the same + layer without crossing +- [ ] No two action boxes on the same layer overlap horizontally +- [ ] Delete `_check\` after inspection + +--- + +### Phase 11 β€” Sequence View (1–2 sessions) + +Implement the Sequence View. No new engines β€” pure column-and-time-axis arithmetic. + +**Semantic / AST scope:** + +- `AstBuilder`: capture occurrence usages, message sends, lifeline participants, + combined fragment occurrences (alt, loop, opt) + +**Layout / Rendering scope:** + +- New `SequenceViewLayoutStrategy` +- `DiagramTypeRouter`: recognize `SequenceView` viewpoint +- Lifeline columns: X = column index Γ— column pitch; `LayoutLifeline` with dashed stem +- Activation bars: `LayoutActivation` top/bottom derived from message ordinals +- Message arrows: horizontal `LayoutLine` between lifeline centres at message Y + (synchronous = filled arrowhead, asynchronous = open, reply = dashed) +- Combined fragment: `LayoutBox` spanning from leftmost to rightmost lifeline column, + height = Y range of covered occurrences; operator label (alt/loop/opt) in corner + +**Acceptance Criteria:** + +*Automated (must all pass):* + +- [ ] `pwsh ./build.ps1` β€” zero errors, zero warnings + +*Visual inspection β€” create `test\SysMLModels\Custom\order-sequence.sysml` with two +lifelines (Client, Server), a synchronous request, a reply, and an `alt` combined +fragment; declare a `SequenceView`:* + +``` +dotnet publish src\DemaConsulting.SysML2Tools.Tool -f net10.0 -c Release -o _check --nologo -q +dotnet _check\DemaConsulting.SysML2Tools.dll render test\SysMLModels\Custom\order-sequence.sysml --format png -o _check\phase11-sequence.png +``` + +Agent views the PNG and asserts: + +- [ ] Two vertical dashed lifeline stems, each with a header box at the top labelled + Client and Server respectively +- [ ] A horizontal solid arrow (filled arrowhead) from Client to Server labelled with + the request message name +- [ ] A horizontal dashed arrow (open arrowhead) from Server to Client labelled with + the reply message name, positioned below the request arrow +- [ ] An `alt` combined fragment box spanning both lifelines, with `[alt]` in the + top-left corner and a dashed divider between the two branches +- [ ] Activation bars visible on each lifeline for the duration they are active +- [ ] Delete `_check\` after inspection + +--- + +### Phase 12 β€” Grid View + Browser View (1–2 sessions) + +Implement tabular and tree views. No new engines β€” pure geometric arithmetic. + +**Layout / Rendering scope:** + +- `DiagramTypeRouter`: recognize `GridView` and `BrowserView` viewpoints +- `GridViewLayoutStrategy`: column widths = max content width per column; row heights + = max content height per row; header row styling; ColSpan expansion +- `BrowserViewLayoutStrategy`: DFS traversal β†’ depthΓ—indent for X; running cursor + for Y; optional parent-to-child tree lines +- `SvgRenderer` / `PngRenderer`: render `LayoutGrid` as bordered table with cell fills + +**Acceptance Criteria:** + +*Automated (must all pass):* + +- [ ] `pwsh ./build.ps1` β€” zero errors, zero warnings + +*Visual inspection β€” create `test\SysMLModels\Custom\requirements-matrix.sysml` with +five requirements and five parts, with allocation relationships between them; declare +a `GridView` (relationship matrix) and a `BrowserView`:* + +``` +dotnet publish src\DemaConsulting.SysML2Tools.Tool -f net10.0 -c Release -o _check --nologo -q +dotnet _check\DemaConsulting.SysML2Tools.dll render test\SysMLModels\Custom\requirements-matrix.sysml --view RequirementsMatrix --format png -o _check\phase12-grid.png +dotnet _check\DemaConsulting.SysML2Tools.dll render test\SysMLModels\Custom\requirements-matrix.sysml --view SystemHierarchy --format png -o _check\phase12-browser.png +``` + +Agent views each PNG and asserts: + +- [ ] Grid view: table with visible cell borders; header row and header column styled + distinctly (darker background); cells at allocation intersections contain a visible + mark (dot or cross); column widths are consistent per column +- [ ] Browser view: elements indented proportionally to their nesting depth; lines + connecting parent to children; deepest nested elements have the most indentation +- [ ] Delete `_check\` after inspection + +--- + +### Phase 13 β€” Geometry View (future / complex) + +Spatial visualization of model elements in 2D or 3D. Requires spatial coordinate +data embedded in the model (e.g., `GeometryValues` library) and a 2D layout engine. +Deferred until user demand justifies the complexity. + +**Layout scope:** Extract X, Y (optionally Z projected to 2D) from model attribute +values; scale/translate from model units to canvas pixels; compute canvas bounds from +placed elements. No auto-layout algorithm required β€” positions are model-specified. + +--- + +## LayoutTree Vocabulary Coverage + +The `LayoutTree` primitive vocabulary was designed in Phase 3 to cover all view kinds. +Current coverage: + +| Primitive | Used By | Status | +|---|---|---| +| `LayoutBox` | All views | βœ… Implemented + rendered | +| `LayoutLabel` | All views | βœ… Implemented + rendered | +| `LayoutLine` | General View (edges) | βœ… Implemented + rendered | +| `LayoutCompartment` | General View, Interconnection | βœ… Defined, not yet populated | +| `LayoutPort` | Interconnection View | βœ… Defined, not yet rendered | +| `LayoutLifeline` | Sequence View | βœ… Defined, not yet rendered | +| `LayoutBand` | Action Flow View (swim-lanes) | βœ… Defined, not yet rendered | +| `LayoutBadge` | Annotations / decorators | βœ… Defined, not yet rendered | +| `LayoutGrid` | Grid View, Browser View | βœ… Defined, not yet rendered | + +The vocabulary is complete. No structural breaking changes to `IRenderer` are expected +as new view implementations are added. + +--- + +## Layout Engine Architecture + +The five non-trivial layout algorithms are implemented as independent, stateless +engines in `Layout/Engine/`. Each engine accepts a plain data input (no SysML model +references) and returns computed geometry. This makes them independently unit-testable +with synthetic inputs before any view strategy uses them. + +``` +Layout/ + Engine/ + ContainmentPacker.cs ← Phase 6: bin-packs children inside a container + ChannelRouter.cs ← Phase 6: orthogonal edges routing around obstacles + PortAssigner.cs ← Phase 8: assigns ports to box sides + distributes slots + ForceDirectedEngine.cs ← Phase 8: Fruchterman-Reingold spring layout + LayeredLayoutEngine.cs ← Phase 10: simplified Sugiyama for DAGs + Internal/ + GeneralViewLayoutStrategy.cs (C1 + C2 + C6) + InterconnectionViewLayoutStrategy.cs (C1 + C3 + C4 + C5 + C6) + ActionFlowViewLayoutStrategy.cs (C7 + C6) + StateTransitionViewLayoutStrategy.cs (C8 + C9 + C10 + C11) + SequenceViewLayoutStrategy.cs (arithmetic only) + GridViewLayoutStrategy.cs (arithmetic only) + BrowserViewLayoutStrategy.cs (arithmetic only) + GeometryViewLayoutStrategy.cs (coordinate mapping only) +``` + +### Layout Capability Categories + +| ID | Capability | Engine | Views | +|----|-----------|--------|-------| +| C1 | Bottom-up containment sizing (size parent to fit children) | `ContainmentPacker` | General, Interconnection, State (nested) | +| C2 | Bin-packing (arrange variable-size boxes in N columns) | `ContainmentPacker` | General | +| C3 | Floating child placement (place children inside container without overlap) | `ForceDirectedEngine` | Interconnection | +| C4 | Port-side assignment (Left/Right/Top/Bottom from connectivity direction) | `PortAssigner` | Interconnection | +| C5 | Port slot distribution (evenly space multiple ports along a side) | `PortAssigner` | Interconnection | +| C6 | Orthogonal edge routing (right-angle segments around obstacle boxes) | `ChannelRouter` | General, Interconnection | +| C7 | Layered DAG layout β€” Sugiyama (layer assignment + barycentre ordering + coordinate assignment) | `LayeredLayoutEngine` | Action Flow | +| C8 | Force-directed node placement β€” Fruchterman-Reingold | `ForceDirectedEngine` | State Transition, Interconnection | +| C9 | Bezier/curved edge routing (control points from node centres) | inline in strategy | State Transition | +| C10 | Self-loop routing (fixed arc bump above/below node) | inline in strategy | State Transition | +| C11 | Parallel edge offset (opposite-direction edges offset perpendicularly) | inline in strategy | State Transition | +| C12 | Fixed-column/timeline layout | arithmetic | Sequence | +| C13 | Spanning region box | arithmetic | Sequence | +| C14 | Table layout (max-width columns, max-height rows) | arithmetic | Grid | +| C15 | Tree layout (DFS + indent + running cursor) | arithmetic | Browser | +| C16 | Fixed-coordinate placement (model units β†’ canvas pixels) | arithmetic | Geometry | + +--- + +## Architecture Status vs `SysML2Tools-architecture.md` + +| Architecture Item | Status | Notes | +|---|---|---| +| Phase 0 β€” Scaffold | βœ… Complete | | +| Phase 1 β€” Parser + Stdlib | βœ… Complete | | +| Phase 2 β€” Semantic Model | βœ… Complete | | +| Phase 3 β€” LayoutTree Design | βœ… Complete | All 8 view primitives defined | +| Phase 4 β€” GeneralView + Renderers | βœ… Complete | `part def` only | +| Phase 5 β€” Polish + Self-test | βœ… Complete | `--validate`, `--auto`, themes | +| Open Concern #1 β€” LayoutTree covers all 8 views | βœ… Resolved | Vocabulary is sufficient | +| Open Concern #2 β€” IRenderer API stability | βœ… Stable | No breaking changes needed | +| Open Concern #3 β€” SkiaSharp native assets | 🟑 Documented | Needs package README | +| Open Concern #4 β€” Noto Sans OFL attribution | 🟑 Pending | Needs `--licenses` output | +| Open Concern #5 β€” spec42 competitive risk | 🟒 Low | Unchanged | +| Open Concern #6 β€” Theme file format for v2 | 🟒 Deferred | YAML/JSON, Phase 6+ | +| SARIF output | 🟒 Deferred | Infrastructure ready | +| Loadable theme files | 🟒 Deferred | Phase 6+ | +| `export` verb | 🟒 Deferred | Phase 6+ | +| Non-`GeneralView` rendering | πŸ”΄ Not started | Phases 8–13 | +| Full OMG graphical notation conformance | 🟑 In progress | Phases 6–13 | +| `feature/auto-flag` branch | 🟑 Open PR | Needs lint + PR | diff --git a/SysML2Tools-architecture.md b/SysML2Tools-architecture.md deleted file mode 100644 index 44638780..00000000 --- a/SysML2Tools-architecture.md +++ /dev/null @@ -1,407 +0,0 @@ -# SysML2Tools Architecture - -## Purpose - -SysML2Tools is a free, open-source .NET CLI tool and library that parses SysML v2 -textual model files and renders them as professional nested block diagrams suitable -for architecture documentation, CI/CD pipelines, and AI-assisted modeling workflows. - -Target stakeholders are .NET teams in regulated industries who author SysML v2 models -as part of a Model-Based Systems Engineering (MBSE) practice and need to generate -diagram images programmatically β€” without a paid GUI tool or a non-.NET runtime -dependency. - -A secondary stakeholder is AI agents iterating on SysML v2 models: the `lint` command -provides structured diagnostic output that enables a model-fix loop without requiring -a rendered diagram. - -## Scope - -**Included:** - -- Parsing SysML v2 textual syntax (`.sysml` files) via an ANTLR4-generated parser -- Loading and pre-resolving the OMG standard library (stdlib) from embedded resources -- Multi-file workspace model (glob patterns; stdlib is always implicitly included) -- Semantic model: symbol table, reference resolution, supertype chain walking -- Structured diagnostic model with file, line, and column information -- `lint` command: load workspace and report all diagnostics (no rendering) -- `render` command: load workspace, resolve a view, render to SVG or PNG -- `--validate` flag: self-test using embedded test models, results via `DemaConsulting.TestResults` -- Standard DEMA CLI argument contract (`-v`, `-?/-h`, `--silent`, `--validate`, - `--result/--results`, `--depth`, `--log`) -- `GeneralView` layout (nested rectangular blocks with compartments) in v1 -- SVG output (zero external dependencies) -- PNG output (SkiaSharp, MIT license; pixel-identical across platforms with embedded font) -- Publishable NuGet library with a stable public API -- `dotnet tool` packaging - -**Excluded from v1:** - -- GUI, interactive editor, or language server -- SysML v1 syntax or semantics -- Non-SysML input formats -- SARIF output (diagnostic infrastructure supports it; surface in v2) -- Loadable theme files (Theme record ships as compile-time constants in v1) -- Non-`GeneralView` diagram rendering (other view kinds produce an "unsupported" diagnostic) -- Full OMG graphical notation conformance (targeting practical correctness, not spec - exhaustiveness) - -## Package Structure - -```text -SysML2Tools -β”œβ”€β”€ DemaConsulting.SysML2Tools - core library: parse, semantic model, layout, IRenderer -β”œβ”€β”€ DemaConsulting.SysML2Tools.Svg - SvgRenderer : IRenderer (zero external deps) -β”œβ”€β”€ DemaConsulting.SysML2Tools.Png - PngRenderer : IRenderer (SkiaSharp, MIT) -└── DemaConsulting.SysML2Tools.Tool - dotnet tool (thin CLI wrapper) -``` - -## Inter-Package Interfaces - -### Core β†’ Svg / Png - -The core library defines the `IRenderer` interface and the `LayoutTree` primitive -vocabulary. Renderer packages implement `IRenderer` and consume `LayoutTree` only β€” -they have no dependency on parsing or semantic model internals. - -```csharp -// DemaConsulting.SysML2Tools (public API surface) - -// Low-level: one LayoutTree β†’ one output stream. Pure, stateless, no filesystem access. -// Callers pass a FileStream, MemoryStream, or Console.OpenStandardOutput() as needed. -public interface IRenderer -{ - string MediaType { get; } // e.g. "image/svg+xml" - string DefaultExtension { get; } // e.g. ".svg" - void Render(LayoutTree layout, RenderOptions options, Stream output); -} - -// High-level orchestration: walks views, calls ILayoutStrategy + IRenderer per view. -// Lives in the core library β€” not in renderer packages. -public sealed class DiagramRenderer -{ - public IReadOnlyList RenderWorkspace( - SysmlWorkspace workspace, - IRenderer renderer, - RenderOptions options); -} - -public sealed record RenderOutput( - string SuggestedFileName, // e.g. "structure.svg" (derived from view name) - string MediaType, // e.g. "image/svg+xml" - Stream Data); // caller decides where to write - -public sealed record RenderOptions(/* scale, dpi, theme, depth limit, etc. */); - -public sealed record LayoutTree(/* positioned primitives: boxes, lines, arrows, text */); -public sealed record SysmlWorkspace(/* resolved semantic model */); -public sealed record SysmlLoadResult(SysmlWorkspace? Workspace, IReadOnlyList Diagnostics); -public sealed record SysmlDiagnostic(string Location, DiagnosticSeverity Severity, string Message); -// ^ "file.sysml:12:5" -public enum DiagnosticSeverity { Error, Warning, Information } -``` - -### Core β†’ Tool - -The tool references all three packages. It owns only argument parsing, console -output formatting, file I/O, and exit codes. All substantive logic is delegated to -the core library and renderer packages. - -### Renderer package isolation - -Library consumers who need only the parsed semantic model or `LayoutTree` take a -dependency on `DemaConsulting.SysML2Tools` only β€” no SkiaSharp native binaries, -no rendering overhead. Consumers who need SVG or PNG opt into the respective -renderer package explicitly. - -## Technology Stack - -| Concern | Choice | License | -| --- | --- | --- | -| Language / runtime | C# / .NET 8+ | MIT | -| Parser generator | ANTLR4 (`Antlr4.Runtime.Standard`) | BSD-3-Clause | -| SysML v2 grammar | `antlr/grammars-v4` (official OMG KEBNF) | MIT | -| PNG rendering | SkiaSharp | MIT | -| Embedded font | Noto Sans | SIL OFL 1.1 | -| Test results output | `DemaConsulting.TestResults` | β€” | -| Unit testing | xUnit v3 | Apache 2.0 | - -No ImageSharp dependency. SkiaSharp is chosen over ImageSharp to avoid the Six Labors -Split License, which would impose licensing obligations on library consumers embedding -`DemaConsulting.SysML2Tools.Png` in commercial products. - -## Software Structure - -### Parse Pipeline - -```text -.sysml files (user) + embedded stdlib resources - ↓ -Lexer + Parser (ANTLR4-generated, per file, independent) - ↓ CST -AST Walker (produces typed AST nodes) - ↓ AST per file -Symbol Table Population (all files merged) - ↓ -Reference Resolver (resolves names to declarations, walks import chains) - ↓ -Supertype Walker (resolves specializes / typing chains) - ↓ -SysmlWorkspace (fully resolved semantic model) -``` - -Errors at any stage produce `SysmlDiagnostic` entries. If errors exist, `Workspace` -is null in `SysmlLoadResult`. - -### Render Pipeline - -```text -SysmlWorkspace + view name (or auto-selection) - ↓ -DiagramTypeRouter - - resolves view's viewpoint type to stdlib qualified name - - walks supertype chain to find nearest stdlib ancestor - - dispatches to ILayoutStrategy - ↓ -ILayoutStrategy (one implementation per view kind) - - v1: GeneralViewLayoutStrategy - - others: UnsupportedViewLayoutStrategy (returns diagnostic) - ↓ -LayoutTree (positioned primitives) - ↓ -IRenderer (SvgRenderer or PngRenderer) - ↓ -Output stream (SVG or PNG) -``` - -### CLI Arguments - -All DEMA CLI tools share a standard global argument contract: - -```text -sysml2tools [-v|--version] [-?|-h|--help []] [--silent] - [--validate] [--result|--results ] [--depth <#>] [--log ] - [ [verb-options] []] -``` - -`--validate` runs self-test against embedded test models and writes pass/fail -results to `--results ` as TRX/JUnit via `DemaConsulting.TestResults`. This -flag is part of a shared CI contract executed uniformly across all DEMA tools β€” -the same `--validate --results --depth <#>` invocation works for every tool. - -Verb-specific help is available via either `sysml2tools --help ` or -`sysml2tools --help`. - -### CLI Verbs - -| Verb | Behavior | -| --- | --- | -| `lint` | Load workspace, report all diagnostics, exit non-zero if errors | -| `render` | Load workspace, resolve view, render to SVG or PNG | -| `export` | *(future)* Export model data to structured formats | - -### View Selection Logic - -| Condition | Behavior | -| --- | --- | -| Exactly one view in workspace | Render it | -| Zero views, `--auto` specified | Auto-render BDD of top-level `part def`, no warning | -| Zero views, no `--auto` | Warn with "define a view or use --auto", then auto-render | -| Multiple views, none specified | Error: list available view names and exit | -| Multiple views, `--view name` | Render the named view | - -### Depth Limiting - -`--depth ` limits the nesting depth rendered. Parts beyond the limit are replaced -with an ellipsis footer: `+N more…`. Silent omission is not permitted β€” truncation -must always be visible. - -### Theme - -A `Theme` record holds all visual parameters: depth-coded fill colors, stroke -widths, font sizes, label padding, and font descriptor. Three compile-time constants -are provided: `Themes.Light`, `Themes.Dark`, `Themes.Print`. - -The `FontDescriptor` within a theme specifies a font family name and optionally an -embedded resource path. Default themes reference the embedded Noto Sans font, -ensuring pixel-identical PNG output across all platforms. User-specified themes -(v2) may override with system fonts or external `.ttf` files; pixel-identity is -then the user's responsibility. - -## Test Strategy - -Tests are layered by complexity to create a gradient the implementation agent can -climb incrementally. Each level only becomes reachable once the previous levels pass. - -### Leveled Semantic Model Tests (unit, agent-written) - -| Level | Content | -| --- | --- | -| 1 | Empty package parses cleanly | -| 2 | Single `part def` with `doc` comment | -| 3 | Inline nested parts | -| 4 | Typed parts (`part p : SomeType`) | -| 5 | Cross-file references | -| 6 | Stdlib type references (`GeneralView`, `SequenceView`) | -| 7 | Supertype chains (`specializes`) | -| 8 | View definitions with `expose` | -| 9 | Circular import detection (expected diagnostic) | -| 10 | `software-structure.sysml` (real-world; zero diagnostics expected) | - -### OMG Reference Models (CC BY 4.0) - -The OMG [`SysML-v2-Release`](https://github.com/Systems-Modeling/SysML-v2-Release) -repository provides normative example models (vehicle systems, mass rollup, -behaviors, state machines, requirements patterns). These are included in the test -suite with attribution and serve as ground-truth inputs the implementation agent -cannot game. - -### spec42 Cross-Validation - -For every `.sysml` test file, `spec42` is run in parallel. If spec42 parses a file -cleanly, SysML2Tools must parse it cleanly too. View identification results are -compared between the two tools. - -### Render Regression Tests - -Reference SVG and PNG outputs for the standard test models are committed. CI fails -if rendered output changes unexpectedly. PNG comparisons use pixel-exact diff (valid -because of the embedded font guarantee). - -## Implementation Phases - -### Phase 0 β€” Repository Scaffold (1 session) - -Stand up repo, solution, project structure, dotnet tool packaging, CI pipeline, -ReviewMark / ReqStream configuration. No logic. - -**Gate:** `dotnet tool install` works; tool prints version and exits cleanly. - -### Phase 1 β€” Parser + Stdlib (2–3 sessions) - -Wire ANTLR4 MSBuild code generation against the official grammar. Embed OMG stdlib -files as assembly resources. Implement parse pipeline to CST only. Implement `lint` -command stub (syntax errors only). - -**Gate:** All OMG example models parse without syntax errors. Stdlib loads silently. - -### Phase 2 β€” Semantic Model (3–5 sessions) - -Build symbol table, reference resolver, import chain, and supertype walker using the -leveled test progression as the iteration driver. - -**Gate:** All OMG example `.sysml` files resolve cleanly. Circular import produces -the correct diagnostic. `software-structure.sysml` resolves with zero diagnostics. - -### Phase 3 β€” LayoutTree Design (1 session β€” human review required) - -Design and freeze the `LayoutTree` primitive vocabulary. Review all 8 SysML v2 view -kinds and confirm the primitives cover them. This is a design session producing an -interface, not an implementation. - -**Gate:** Human sign-off on `LayoutTree` primitives before proceeding. - -### Phase 4 β€” GeneralView Layout + Renderers (3–4 sessions) - -Implement `GeneralViewLayoutStrategy`, `SvgRenderer`, `PngRenderer`. Wire -`DiagramTypeRouter` with unsupported-view-kind diagnostics for the other seven view -kinds. Implement `render` command fully. - -**Gate:** `software-structure.sysml` renders to a visually correct SVG and -pixel-identical PNG across Windows, Linux, and macOS. - -### Phase 5 β€” Polish + Self-test (1–2 sessions) - -Implement `--validate` self-test. Add `--depth` with ellipsis indicator. Add view -enumeration on multiple-view error. Finalize theme record. Wire embedded Noto Sans -font. Attribution notices in NuGet metadata. - -**Gate:** `--validate` passes. Lint CI clean. All OMG example models render without -crash (unsupported view kinds produce clean diagnostics, not exceptions). - -## Architectural Decisions - -**Multi-package from day one.** Separating the core library from renderer packages -allows library consumers to take a dependency on parsing and layout without pulling -in native graphics binaries. The `IRenderer` interface is the extension point. - -**Multi-file workspace.** The OMG stdlib is pre-loaded from embedded resources before -any user files are parsed. Single-file input is the degenerate case of a multi-file -workspace; there is no single-file mode. - -**SkiaSharp over ImageSharp.** SkiaSharp is MIT-licensed. ImageSharp v2+ uses the -Six Labors Split License which imposes obligations on commercial library consumers. -SkiaSharp's native asset requirement is transparent for tool consumers (handled by -NuGet at publish time) and is a known, documented constraint for library consumers. - -**Embedded Noto Sans font.** Ensures pixel-identical PNG output across all platforms. -Noto Sans is licensed SIL OFL 1.1 which explicitly permits embedding in software. -Default themes use the embedded font; user-overridden themes may use system or -external fonts at the cost of the pixel-identity guarantee. - -**`IRenderer` is low-level and pure β€” no filesystem access.** It receives a -`LayoutTree` and writes to a caller-supplied `Stream`. Passing a `FileStream` -writes directly to disk with no intermediate buffer; passing a `MemoryStream` -keeps output in memory for testing or in-process use; passing -`Console.OpenStandardOutput()` supports stdout piping. Multi-view orchestration -(`DiagramRenderer`) lives in the core library and calls `IRenderer` once per view β€” -renderer packages have no concept of workspaces or view iteration. - -**DiagramTypeRouter uses resolved qualified names.** The router dispatches on the -stdlib-resolved qualified name of a view's viewpoint type (e.g., -`SystemsModelingLibrary::Views::GeneralView`), not the raw token. User aliases and -local imports therefore do not break dispatch. The router walks the supertype chain -to handle custom viewpoints that specialize stdlib viewpoints. - -**Diagnostic model mirrors ReviewMark.** `SysmlDiagnostic` mirrors ReviewMark's -`LintIssue` in structure and philosophy: file/line/col location, severity enum, -human-readable message. The `lint` command makes this output useful for AI-assisted -model authoring loops. - -**Theme record is a compile-time constant in v1.** Loadable theme files are deferred -to v2. The Theme record data structure is defined in v1 so that v2 loadable themes -are additive and non-breaking. - -**`--auto` flag.** When a workspace has no view definitions, `--auto` renders the BDD -of the top-level `part def` silently. Without `--auto`, the same auto-render occurs -but a warning is emitted advising the user to define an explicit view. This keeps v1 -immediately useful for unstructured models while encouraging good authoring practice. - -**Self-test via `--validate` flag.** Uses the same `Program.Run` pattern as -ReviewMark: invokes the full CLI pipeline against embedded test models with a test -context, then asserts expected outputs. Results are written as TRX/JUnit via -`DemaConsulting.TestResults`, consistent with the shared DEMA CI contract. This -tests the integrated tool, not just unit-level components. - -**SARIF deferred.** The `SysmlDiagnostic` list is structurally compatible with SARIF. -SARIF output can be added as a formatting option on the existing infrastructure -without any breaking changes. - -## Open Concerns - -1. πŸ”΄ **HIGH** LayoutTree vocabulary: the primitive set must cover all 8 SysML v2 - view kinds from day one. Designing it only for `GeneralView` risks structural - breaking changes when sequence, state-machine, or interconnection views are added. - **Requires human review in Phase 3 before implementation proceeds.** - -2. 🟑 **MEDIUM** IRenderer public API stability: once `DemaConsulting.SysML2Tools` - is published, changes to `IRenderer` or `LayoutTree` are semver-major breaking - changes. The Phase 3 design review is the primary mitigation. - -3. 🟑 **MEDIUM** SkiaSharp native assets for library consumers: consumers referencing - `DemaConsulting.SysML2Tools.Png` must ensure the appropriate - `SkiaSharp.NativeAssets.*` package is included in their publish output. This must - be documented clearly in the package README. - -4. 🟑 **MEDIUM** Noto Sans SIL OFL attribution: OFL requires the copyright notice and - license text to be included in distributions. Must appear in NuGet package notices - and the tool's `--licenses` output (or equivalent). - -5. 🟒 **LOW** spec42 competitive risk: if Elan8 improves spec42's `GeneralView` - renderer to produce professional nested block diagrams, the primary rendering - differentiator is reduced. The .NET-native integration story and the AI-loop - diagnostic design remain defensible regardless. - -6. 🟒 **LOW** Theme file format for v2: the format for loadable theme files - (YAML, JSON, or TOML) is undecided. This is internal to v2 and non-breaking - relative to v1's public API. diff --git a/docs/design/introduction.md b/docs/design/introduction.md index 3bbc44ac..03e03c90 100644 --- a/docs/design/introduction.md +++ b/docs/design/introduction.md @@ -175,7 +175,99 @@ OTS items have integration/usage design documentation parallel to system folders Review-sets: defined in `.reviewmark.yaml` +## Technology Stack + +| Concern | Choice | License | +| --- | --- | --- | +| Language / runtime | C# / .NET 8+ | MIT | +| Parser generator | ANTLR4 (`Antlr4.Runtime.Standard`) | BSD-3-Clause | +| SysML v2 grammar | `antlr/grammars-v4` (official OMG KEBNF) | MIT | +| PNG rendering | SkiaSharp | MIT | +| Embedded font | Noto Sans | SIL OFL 1.1 | +| Test results output | `DemaConsulting.TestResults` | β€” | +| Unit testing | xUnit v3 | Apache 2.0 | + +No ImageSharp dependency. SkiaSharp is chosen over ImageSharp to avoid the Six Labors +Split License, which would impose licensing obligations on library consumers embedding +`DemaConsulting.SysML2Tools.Png` in commercial products. + +## Architectural Decisions + +**Multi-package from day one.** Separating the core library from renderer packages +allows library consumers to take a dependency on parsing and layout without pulling +in native graphics binaries. The `IRenderer` interface is the extension point. + +**Multi-file workspace.** The OMG stdlib is pre-loaded from embedded resources before +any user files are parsed. Single-file input is the degenerate case of a multi-file +workspace; there is no single-file mode. + +**SkiaSharp over ImageSharp.** SkiaSharp is MIT-licensed. ImageSharp v2+ uses the +Six Labors Split License which imposes obligations on commercial library consumers. +SkiaSharp's native asset requirement is transparent for tool consumers (handled by +NuGet at publish time) and is a known, documented constraint for library consumers. + +**Embedded Noto Sans font.** Ensures pixel-identical PNG output across all platforms. +Noto Sans is licensed SIL OFL 1.1 which explicitly permits embedding in software. +Default themes use the embedded font; user-overridden themes may use system or +external fonts at the cost of the pixel-identity guarantee. + +**`IRenderer` is low-level and pure β€” no filesystem access.** It receives a +`LayoutTree` and writes to a caller-supplied `Stream`. Passing a `FileStream` +writes directly to disk with no intermediate buffer; passing a `MemoryStream` +keeps output in memory for testing or in-process use; passing +`Console.OpenStandardOutput()` supports stdout piping. Multi-view orchestration +(`DiagramRenderer`) lives in the core library and calls `IRenderer` once per view β€” +renderer packages have no concept of workspaces or view iteration. + +**DiagramTypeRouter uses resolved qualified names.** The router dispatches on the +stdlib-resolved qualified name of a view's viewpoint type (e.g., +`SystemsModelingLibrary::Views::GeneralView`), not the raw token. User aliases and +local imports therefore do not break dispatch. The router walks the supertype chain +to handle custom viewpoints that specialize stdlib viewpoints. + +**Diagnostic model mirrors ReviewMark.** `SysmlDiagnostic` mirrors ReviewMark's +`LintIssue` in structure and philosophy: file/line/col location, severity enum, +human-readable message. The `lint` command makes this output useful for AI-assisted +model authoring loops. + +**Layout engines are independent and reusable.** Non-trivial layout algorithms +(`ContainmentPacker`, `ChannelRouter`, `ForceDirectedEngine`, `PortAssigner`, +`LayeredLayoutEngine`) live in `Layout/Engine/` with no dependency on the SysML +semantic model. Each engine accepts plain geometric input and returns computed +geometry, making them independently testable and reusable across multiple view +strategies. See `ROADMAP.md` for the phased introduction of each engine. + +**Theme record is a compile-time constant in v1.** Loadable theme files are deferred +to v2. The Theme record data structure is defined in v1 so that v2 loadable themes +are additive and non-breaking. + +**`--auto` flag.** When a workspace has no view definitions, `--auto` renders the +general view of the top-level `part def` silently. Without `--auto`, the same +auto-render occurs but a warning is emitted advising the user to define an explicit +view. This keeps v1 immediately useful for unstructured models while encouraging +good authoring practice. + +**Self-test via `--validate` flag.** Uses the same `Program.Run` pattern as +ReviewMark: invokes the full CLI pipeline against embedded test models with a test +context, then asserts expected outputs. Results are written as TRX/JUnit via +`DemaConsulting.TestResults`, consistent with the shared DEMA CI contract. This +tests the integrated tool, not just unit-level components. + +**SARIF deferred.** The `SysmlDiagnostic` list is structurally compatible with SARIF. +SARIF output can be added as a formatting option on the existing infrastructure +without any breaking changes. + +**SkiaSharp native assets for library consumers.** Consumers referencing +`DemaConsulting.SysML2Tools.Png` must ensure the appropriate +`SkiaSharp.NativeAssets.*` package is included in their publish output. This must +be documented clearly in the package README. + +**Noto Sans SIL OFL attribution.** OFL requires the copyright notice and license +text to be included in distributions. Must appear in NuGet package notices and the +tool's `--licenses` output (or equivalent). + ## References - SysML2 Tools User Guide - SysML2 Tools Repository () +- SysML2 Tools Rendering Roadmap (`ROADMAP.md`) diff --git a/src/DemaConsulting.SysML2Tools.Core/Rendering/DiagramRenderer.cs b/src/DemaConsulting.SysML2Tools.Core/Rendering/DiagramRenderer.cs index 4e4d2666..ea99276e 100644 --- a/src/DemaConsulting.SysML2Tools.Core/Rendering/DiagramRenderer.cs +++ b/src/DemaConsulting.SysML2Tools.Core/Rendering/DiagramRenderer.cs @@ -150,6 +150,81 @@ public IReadOnlyList RenderWorkspace( return results; } + /// + /// Synthesizes a that targets the most representative + /// top-level element in the workspace, for use when the user passes --auto + /// and no user-defined views are present. + /// + /// + /// The SysML workspace to inspect. Must not be null. + /// + /// + /// A synthetic whose Name is derived from the chosen + /// element (e.g. "VehicleA" β†’ "VehicleAView"), or + /// when the workspace contains no non-stdlib declarations to target. + /// + /// + /// Selection priority: + /// + /// The non-stdlib part def with the highest direct-child count. + /// The first non-stdlib definition when no part def exists. + /// + /// The returned node has empty and + /// because the GeneralView layout strategy + /// derives its content from workspace declarations rather than the view's own children. + /// + public static SysmlViewNode? SynthesizeAutoView(SysmlWorkspace workspace) + { + // Validate input β€” null workspace would cause a NullReferenceException + ArgumentNullException.ThrowIfNull(workspace); + + // Collect all non-stdlib definition nodes as candidates for the auto view target + SysmlDefinitionNode? bestPartDef = null; + SysmlDefinitionNode? firstDefinition = null; + + foreach (var (qualifiedName, node) in workspace.Declarations) + { + // Skip stdlib elements β€” only user-defined declarations are considered + if (Internal.StdlibFilter.IsStdlibElement(qualifiedName)) + { + continue; + } + + // Consider only definition nodes (part def, attribute def, etc.) + if (node is not SysmlDefinitionNode defNode) + { + continue; + } + + // Record the first non-stdlib definition as the fallback target + firstDefinition ??= defNode; + + // Prefer a part def, and among part defs prefer the one with the most direct children + if (string.Equals(defNode.DefinitionKeyword, "part def", StringComparison.Ordinal) && + (bestPartDef is null || defNode.Children.Count > bestPartDef.Children.Count)) + { + bestPartDef = defNode; + } + } + + // Choose the best candidate: part def with most children, then any definition, then none + var target = bestPartDef ?? firstDefinition; + if (target is null) + { + return null; + } + + // Build the synthesized view name by appending "View" to the element's simple name + var viewName = (target.Name ?? target.QualifiedName ?? "AutoView") + "View"; + var viewQualifiedName = (target.QualifiedName ?? target.Name ?? "AutoView") + "View"; + + return new SysmlViewNode + { + Name = viewName, + QualifiedName = viewQualifiedName + }; + } + /// /// Produces a file-system-safe name by replacing any character that is invalid /// in a file name with an underscore. diff --git a/src/DemaConsulting.SysML2Tools.Language/Semantic/SysmlWorkspace.cs b/src/DemaConsulting.SysML2Tools.Language/Semantic/SysmlWorkspace.cs index 9f37383d..64620941 100644 --- a/src/DemaConsulting.SysML2Tools.Language/Semantic/SysmlWorkspace.cs +++ b/src/DemaConsulting.SysML2Tools.Language/Semantic/SysmlWorkspace.cs @@ -10,6 +10,13 @@ namespace DemaConsulting.SysML2Tools.Semantic; /// public sealed class SysmlWorkspace { + /// + /// Mutable backing store for ; allows post-construction + /// injection of synthetic nodes (e.g., auto-generated views) without requiring a + /// full workspace rebuild. + /// + private Dictionary _declarations = []; + /// /// Gets the list of loaded source file paths (virtual paths for stdlib, real paths for user files). /// @@ -18,6 +25,36 @@ public sealed class SysmlWorkspace /// /// Gets the qualified-name registry mapping fully-qualified names to their declaration nodes. /// - public IReadOnlyDictionary Declarations { get; init; } = - new Dictionary(); + /// + /// The property is backed by a mutable so that + /// can inject synthetic nodes after the workspace is constructed. + /// The init accessor copies the supplied dictionary so that construction-time + /// collection expressions are fully supported. + /// + public IReadOnlyDictionary Declarations + { + get => _declarations; + init => _declarations = new Dictionary(value); + } + + /// + /// Injects a synthetic declaration into the workspace under the given qualified name. + /// + /// + /// The fully-qualified name that will key the new entry in . + /// If the key already exists it is overwritten. + /// + /// The node to register. Must not be null. + /// + /// This method is intended for post-load augmentation only (e.g., the --auto flag + /// synthesizing a GeneralView). It should not be used during normal workspace construction. + /// + public void AddDeclaration(string qualifiedName, SysmlNode node) + { + // Validate inputs β€” a null key or node would silently corrupt the declaration table + ArgumentNullException.ThrowIfNull(qualifiedName); + ArgumentNullException.ThrowIfNull(node); + + _declarations[qualifiedName] = node; + } } diff --git a/src/DemaConsulting.SysML2Tools.Tool/Cli/Context.cs b/src/DemaConsulting.SysML2Tools.Tool/Cli/Context.cs index 5a5fccb9..026e4d35 100644 --- a/src/DemaConsulting.SysML2Tools.Tool/Cli/Context.cs +++ b/src/DemaConsulting.SysML2Tools.Tool/Cli/Context.cs @@ -115,6 +115,16 @@ internal sealed class Context : IDisposable /// public string? RendererFormat { get; private init; } + /// + /// Gets a value indicating whether the --auto flag was specified. + /// + /// + /// When and the workspace has no user-defined view declarations, + /// the render command synthesizes a GeneralView targeting the most representative + /// top-level element. The flag is silently ignored when views already exist. + /// + public bool AutoView { get; private init; } + /// /// Gets the proposed exit code for the application (0 for success, 1 for errors). /// @@ -155,7 +165,8 @@ public static Context Create(string[] args) Command = parser.Command, Files = parser.Files, OutputDirectory = parser.OutputDirectory, - RendererFormat = parser.RendererFormat + RendererFormat = parser.RendererFormat, + AutoView = parser.AutoView }; // Open log file if specified @@ -263,6 +274,11 @@ private sealed class ArgumentParser /// public string? RendererFormat { get; private set; } + /// + /// Gets a value indicating whether the --auto flag was specified. + /// + public bool AutoView { get; private set; } + /// /// Parses command-line arguments /// @@ -337,6 +353,10 @@ private int ParseArgument(string arg, string[] args, int index) ViewName = GetRequiredStringArgument(arg, args, index, "a view name argument"); return index + 1; + case "--auto": + AutoView = true; + return index; + case "lint": Command = SysmlCommand.Lint; return index; diff --git a/src/DemaConsulting.SysML2Tools.Tool/Program.cs b/src/DemaConsulting.SysML2Tools.Tool/Program.cs index b37c506e..e51ab282 100644 --- a/src/DemaConsulting.SysML2Tools.Tool/Program.cs +++ b/src/DemaConsulting.SysML2Tools.Tool/Program.cs @@ -170,6 +170,7 @@ private static void PrintHelp(Context context) context.WriteLine(" --output Output directory for rendered files (render command)"); context.WriteLine(" --format Renderer format: svg (default) or png (render command)"); context.WriteLine(" --view Select a specific view to render (render command)"); + context.WriteLine(" --auto Auto-generate a view when none are defined (render command)"); } /// diff --git a/src/DemaConsulting.SysML2Tools.Tool/Render/RenderCommand.cs b/src/DemaConsulting.SysML2Tools.Tool/Render/RenderCommand.cs index 9b85ab2b..12c946b1 100644 --- a/src/DemaConsulting.SysML2Tools.Tool/Render/RenderCommand.cs +++ b/src/DemaConsulting.SysML2Tools.Tool/Render/RenderCommand.cs @@ -74,6 +74,21 @@ public static async Task RunAsync(Context context) return; } + // When --auto is requested and no user-defined views exist, synthesize a GeneralView + // targeting the most representative top-level element in the workspace + if (viewNames.Count == 0 && context.AutoView) + { + var autoView = DiagramRenderer.SynthesizeAutoView(loadResult.Workspace); + if (autoView != null) + { + context.WriteLine($" Auto-generating view for '{autoView.Name}'..."); + + // Inject the synthetic view node into the workspace so the rendering pipeline + // discovers it via the normal declaration-iteration path in RenderWorkspace + loadResult.Workspace.AddDeclaration(autoView.QualifiedName!, autoView); + } + } + // Select the renderer based on the format option (default: svg) var format = context.RendererFormat ?? "svg"; IRenderer renderer = format.Equals("png", StringComparison.OrdinalIgnoreCase) diff --git a/test/DemaConsulting.SysML2Tools.Tests/Rendering/RenderIntegrationTests.cs b/test/DemaConsulting.SysML2Tools.Tests/Rendering/RenderIntegrationTests.cs index 12463776..80b73c4f 100644 --- a/test/DemaConsulting.SysML2Tools.Tests/Rendering/RenderIntegrationTests.cs +++ b/test/DemaConsulting.SysML2Tools.Tests/Rendering/RenderIntegrationTests.cs @@ -16,10 +16,35 @@ namespace DemaConsulting.SysML2Tools.Tests.Rendering; public sealed class RenderIntegrationTests { /// - /// Path to the software-structure test model that contains no view definitions. + /// Locates the test/SysMLModels root by walking up from the assembly's base directory. /// - private static readonly string SoftwareStructureModel = - Path.Combine("SysMLModels", "software-structure.sysml"); + /// + /// The absolute path to the test/SysMLModels directory, or + /// when the directory cannot be found (e.g., the test is running from an unexpected location). + /// + private static string? FindSysMLModelsRoot() + { + var dir = AppContext.BaseDirectory; + while (dir is not null) + { + var candidate = Path.Combine(dir, "test", "SysMLModels"); + if (Directory.Exists(candidate)) + { + return candidate; + } + + dir = Directory.GetParent(dir)?.FullName; + } + + return null; + } + + /// + /// Path to the nested-packages-with-view test fixture: two nested packages, + /// several part defs, and one view def. + /// + private static string SoftwareStructureModel => + Path.Combine(FindSysMLModelsRoot() ?? "SysMLModels", "Custom", "nested-packages-with-view.sysml"); /// /// Inline SysML source for the general-view end-to-end tests. The package contains two @@ -34,13 +59,13 @@ view def GeneralView {} """; /// - /// DiagramRenderer.RenderWorkspace on a workspace loaded from the software-structure - /// model (which has no view definitions) returns an empty list of render outputs. + /// DiagramRenderer.RenderWorkspace on a workspace loaded from the sysml2tools-architecture + /// model produces SVG output for the declared view. /// [Fact] - public async Task DiagramRenderer_RenderWorkspace_SoftwareStructureModel_ReturnsEmptyList() + public async Task DiagramRenderer_RenderWorkspace_SoftwareStructureModel_ReturnsSvgOutput() { - // Arrange: load workspace from the software-structure model file + // Arrange: load workspace from the sysml2tools-architecture model file var (stdlibTable, _) = StdlibProvider.GetSymbolTable(); var result = await WorkspaceLoader.LoadAsync([SoftwareStructureModel], stdlibTable); Assert.NotNull(result.Workspace); // Pre-condition: workspace must load @@ -48,22 +73,21 @@ public async Task DiagramRenderer_RenderWorkspace_SoftwareStructureModel_Returns var svgRenderer = new SvgRenderer(); var options = new RenderOptions(Themes.Light); - // Act: render the workspace (which has no views) + // Act: render the workspace var outputs = diagramRenderer.RenderWorkspace(result.Workspace, svgRenderer, options); - // Assert: no outputs because the model has no view declarations - Assert.Empty(outputs); + // Assert: one output for the declared view + Assert.NotEmpty(outputs); } /// - /// DiagramRenderer.RenderWorkspace on a workspace loaded from the software-structure - /// model produces no PNG outputs either, confirming the empty-list result is - /// renderer-agnostic. + /// DiagramRenderer.RenderWorkspace on a workspace loaded from the sysml2tools-architecture + /// model produces PNG output for the declared view. /// [Fact] - public async Task DiagramRenderer_RenderWorkspace_SoftwareStructureModel_PngRenderer_ReturnsEmptyList() + public async Task DiagramRenderer_RenderWorkspace_SoftwareStructureModel_PngRenderer_ReturnsPngOutput() { - // Arrange: load workspace from the software-structure model file + // Arrange: load workspace from the sysml2tools-architecture model file var (stdlibTable, _) = StdlibProvider.GetSymbolTable(); var result = await WorkspaceLoader.LoadAsync([SoftwareStructureModel], stdlibTable); Assert.NotNull(result.Workspace); // Pre-condition: workspace must load @@ -71,11 +95,11 @@ public async Task DiagramRenderer_RenderWorkspace_SoftwareStructureModel_PngRend var pngRenderer = new PngRenderer(); var options = new RenderOptions(Themes.Light); - // Act: render the workspace (which has no views) + // Act: render the workspace var outputs = diagramRenderer.RenderWorkspace(result.Workspace, pngRenderer, options); - // Assert: no outputs because the model has no view declarations - Assert.Empty(outputs); + // Assert: one output for the declared view + Assert.NotEmpty(outputs); } /// diff --git a/test/DemaConsulting.SysML2Tools.Tests/Semantic/SemanticOmgModelsTests.cs b/test/DemaConsulting.SysML2Tools.Tests/Semantic/SemanticOmgModelsTests.cs index e3cf21f8..a9b4ce68 100644 --- a/test/DemaConsulting.SysML2Tools.Tests/Semantic/SemanticOmgModelsTests.cs +++ b/test/DemaConsulting.SysML2Tools.Tests/Semantic/SemanticOmgModelsTests.cs @@ -7,7 +7,7 @@ namespace DemaConsulting.SysML2Tools.Tests.Semantic; /// -/// Level 10 gate: all OMG example models and software-structure.sysml resolve with zero errors. +/// Level 10 gate: all OMG example models and custom test models resolve with zero errors. /// public sealed class SemanticOmgModelsTests { @@ -31,7 +31,7 @@ public sealed class SemanticOmgModelsTests } /// - /// All OMG reference model files (including software-structure.sysml) should load with zero errors. + /// All OMG reference model files and custom test models should load with zero errors. /// [Fact] public async Task SemanticOmgModels_AllModels_ResolveWithZeroErrors() diff --git a/test/SysMLModels/Custom/nested-packages-with-view.sysml b/test/SysMLModels/Custom/nested-packages-with-view.sysml new file mode 100644 index 00000000..c73337cf --- /dev/null +++ b/test/SysMLModels/Custom/nested-packages-with-view.sysml @@ -0,0 +1,18 @@ +// Test fixture: two nested packages each containing several part defs and one top-level view def. +// Used to verify rendering of multi-package workspaces with a declared view. + +package SystemA { + + view def SystemAView {} + + package Subsystem1 { + part def ComponentA {} + part def ComponentB {} + part def ComponentC {} + part def ComponentD {} + } + + package Subsystem2 { + part def WidgetX {} + } +} diff --git a/test/SysMLModels/general-view-test.sysml b/test/SysMLModels/Custom/simple-components-with-view.sysml similarity index 100% rename from test/SysMLModels/general-view-test.sysml rename to test/SysMLModels/Custom/simple-components-with-view.sysml diff --git a/test/SysMLModels/software-structure.sysml b/test/SysMLModels/software-structure.sysml deleted file mode 100644 index 8afd0e28..00000000 --- a/test/SysMLModels/software-structure.sysml +++ /dev/null @@ -1,43 +0,0 @@ -// SysML2Tools software structure model -// Describes the SysML2Tools software components using SysML v2 part definitions. - -package SysML2Tools { - - view def SoftwareStructureView {} - - // Core library subsystems - package Core { - - // Parser subsystem: parses SysML/KerML source files - part def WorkspaceParser { - } - - // Semantic subsystem: builds symbol table and resolves references - part def WorkspaceLoader { - } - - // Internal: builds AST from CST - part def AstBuilder { - } - - // Internal: registers qualified names - part def SymbolTable { - } - - // Internal: resolves references and imports - part def ReferenceResolver { - } - - // Internal: walks specialization chains - part def SupertypeWalker { - } - } - - // Tool subsystem: CLI commands - package Tool { - - // Lint command: validates SysML/KerML files - part def LintCommand { - } - } -}