Skip to content

Commit e379154

Browse files
committed
Add UML interaction fragment classes and extensions
1 parent ad7a0d8 commit e379154

File tree

7 files changed

+269
-0
lines changed

7 files changed

+269
-0
lines changed
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
using DendroDocs.Extensions;
2+
using PlantUml.Builder;
3+
4+
namespace DendroDocs.Uml.Extensions;
5+
6+
/// <summary>
7+
/// Provides extension methods for objects implementing the <see cref="IHaveModifiers"/> interface, enabling conversion
8+
/// of visibility modifiers to their PlantUML equivalents.
9+
/// </summary>
10+
/// <remarks>This class contains methods that simplify the process of mapping visibility modifiers from objects
11+
/// implementing <see cref="IHaveModifiers"/> to corresponding UML visibility representations, such as public,
12+
/// protected, private, and internal.</remarks>
13+
public static class IHaveModifiersExtensions
14+
{
15+
/// <summary>
16+
/// Converts the visibility modifiers of the specified object to a PlantUML visibility modifier.
17+
/// </summary>
18+
/// <param name="modifiers">An object implementing <see cref="IHaveModifiers"/> that provides access to visibility modifiers.</param>
19+
/// <returns>A <see cref="VisibilityModifier"/> value representing the UML visibility equivalent of the object's modifiers.
20+
/// Returns <see cref="VisibilityModifier.Public"/> for public visibility, <see
21+
/// cref="VisibilityModifier.PackagePrivate"/> for internal visibility, <see cref="VisibilityModifier.Protected"/>
22+
/// for protected visibility, <see cref="VisibilityModifier.Private"/> for private visibility, or <see
23+
/// cref="VisibilityModifier.None"/> if no visibility modifier is applicable.</returns>
24+
public static VisibilityModifier ToPlantUmlVisibility(this IHaveModifiers modifiers)
25+
{
26+
ArgumentNullException.ThrowIfNull(modifiers);
27+
28+
if (modifiers.IsPublic())
29+
{
30+
return VisibilityModifier.Public;
31+
}
32+
33+
if (modifiers.IsInternal())
34+
{
35+
return VisibilityModifier.PackagePrivate;
36+
}
37+
38+
if (modifiers.IsProtected())
39+
{
40+
return VisibilityModifier.Protected;
41+
}
42+
43+
if (modifiers.IsPrivate())
44+
{
45+
return VisibilityModifier.Private;
46+
}
47+
48+
return VisibilityModifier.None;
49+
}
50+
}
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
using System.Diagnostics;
2+
3+
namespace DendroDocs.Uml.Fragments;
4+
5+
/// <summary>
6+
/// Represents a group with 1 or more sections, like <c>alt</c>, <c>par</c>, <c>loop</c>, etc..
7+
/// </summary>
8+
[DebuggerDisplay("Alt")]
9+
public class Alt : InteractionFragment
10+
{
11+
private readonly List<AltSection> sections = [];
12+
13+
/// <summary>
14+
/// Gets all sections.
15+
/// </summary>
16+
public IReadOnlyList<AltSection> Sections => this.sections;
17+
18+
/// <summary>
19+
/// Add a sections to this alt.
20+
/// </summary>
21+
/// <param name="section">The section to add.</param>
22+
public void AddSection(AltSection section)
23+
{
24+
ArgumentNullException.ThrowIfNull(section);
25+
26+
section.Parent = this;
27+
28+
this.sections.Add(section);
29+
}
30+
}
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
using System.Diagnostics;
2+
3+
namespace DendroDocs.Uml.Fragments;
4+
5+
/// <summary>
6+
/// Represents a section in a larger group.
7+
/// </summary>
8+
[DebuggerDisplay("AltSection {GroupType} {Label}")]
9+
public class AltSection : InteractionFragment
10+
{
11+
/// <summary>
12+
/// The type of group, like <c>alt</c>, <c>else</c>, etc..
13+
/// </summary>
14+
public string? GroupType { get; set; }
15+
16+
/// <summary>
17+
/// The label of this section.
18+
/// </summary>
19+
public string? Label { get; set; }
20+
}
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
using System.Diagnostics;
2+
3+
namespace DendroDocs.Uml.Fragments;
4+
5+
/// <summary>
6+
/// Represents an arrow between 2 participants.
7+
/// </summary>
8+
[DebuggerDisplay("{Source} -> {Target} : {Name}")]
9+
public class Arrow : InteractionFragment
10+
{
11+
/// <summary>
12+
/// The left participant of the arrow.
13+
/// </summary>
14+
public string? Source { get; set; }
15+
16+
/// <summary>
17+
/// The right participant of the arrow.
18+
/// </summary>
19+
public string? Target { get; set; }
20+
21+
/// <summary>
22+
/// The optional color of the arrow.
23+
/// </summary>
24+
public string? Color { get; set; }
25+
26+
/// <summary>
27+
/// Whether the arrow is dashed.
28+
/// </summary>
29+
public bool Dashed { get; set; }
30+
31+
/// <summary>
32+
/// The message with the arrow.
33+
/// </summary>
34+
public string? Name { get; set; }
35+
}
Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
namespace DendroDocs.Uml.Fragments.Extensions;
2+
3+
/// <summary>
4+
/// Provides extension methods for querying and navigating through collections of <see cref="InteractionFragment"/>
5+
/// objects.
6+
/// </summary>
7+
/// <remarks>This static class includes methods for retrieving descendants, ancestors, and sibling fragments
8+
/// within a hierarchy of <see cref="InteractionFragment"/> objects. These methods are designed to facilitate traversal
9+
/// and filtering of interaction fragments in a structured manner.</remarks>
10+
public static class InteractionFragmentExtensions
11+
{
12+
/// <summary>
13+
/// Query all descendants from this level down.
14+
/// </summary>
15+
/// <typeparam name="TFragment">The type of fragment to filter on.</typeparam>
16+
/// <returns>Returns a readonly list of child fragments.</returns>
17+
public static IReadOnlyList<TFragment> Descendants<TFragment>(this IEnumerable<InteractionFragment> nodes)
18+
where TFragment : InteractionFragment
19+
{
20+
ArgumentNullException.ThrowIfNull(nodes);
21+
22+
var result = new List<TFragment>();
23+
24+
foreach (var node in nodes)
25+
{
26+
switch (node)
27+
{
28+
case TFragment t:
29+
result.Add(t);
30+
break;
31+
32+
case Alt a:
33+
result.AddRange(a.Sections.SelectMany(s => s.Fragments).Descendants<TFragment>());
34+
break;
35+
36+
default:
37+
break;
38+
}
39+
}
40+
41+
return result;
42+
}
43+
44+
/// <summary>
45+
/// Query all parent fragments from this fragment up.
46+
/// </summary>
47+
/// <returns>Returns a list of parent fragments.</returns>
48+
public static IReadOnlyList<InteractionFragment> Ancestors(this InteractionFragment fragment)
49+
{
50+
ArgumentNullException.ThrowIfNull(fragment);
51+
52+
var result = new List<InteractionFragment>();
53+
54+
var parent = fragment.Parent;
55+
while (parent is not null)
56+
{
57+
result.Add(parent);
58+
59+
parent = parent.Parent;
60+
}
61+
62+
return result;
63+
}
64+
65+
/// <summary>
66+
/// Query all sibling before the current fragment.
67+
/// </summary>
68+
/// <returns>Returns a readonly list of siblings comming before this fragment.</returns>
69+
public static IReadOnlyList<InteractionFragment> StatementsBeforeSelf(this InteractionFragment fragment)
70+
{
71+
ArgumentNullException.ThrowIfNull(fragment);
72+
73+
if (fragment.Parent != null)
74+
{
75+
return [.. fragment.Parent.Fragments.TakeWhile(s => s != fragment)];
76+
}
77+
78+
return [];
79+
}
80+
}
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
namespace DendroDocs.Uml.Fragments;
2+
3+
/// <summary>
4+
/// Represents interaction fragments in a sequence diagram.
5+
/// </summary>
6+
public abstract class InteractionFragment
7+
{
8+
private readonly List<InteractionFragment> interactionFragments = [];
9+
10+
/// <summary>
11+
/// The parent of this fragment.
12+
/// </summary>
13+
public InteractionFragment? Parent { get; set; }
14+
15+
/// <summary>
16+
/// The children of this fragment.
17+
/// </summary>
18+
public virtual IReadOnlyList<InteractionFragment> Fragments => this.interactionFragments;
19+
20+
/// <summary>
21+
/// Add a fragment to this level.
22+
/// </summary>
23+
/// <param name="fragment">The fragment to add.</param>
24+
public void AddFragment(InteractionFragment fragment)
25+
{
26+
ArgumentNullException.ThrowIfNull(fragment);
27+
28+
fragment.Parent = this;
29+
30+
this.interactionFragments.Add(fragment);
31+
}
32+
33+
/// <summary>
34+
/// Add a list of fragments to this level.
35+
/// </summary>
36+
/// <param name="fragments">The fragments to add.</param>
37+
public void AddFragments(IEnumerable<InteractionFragment> fragments)
38+
{
39+
ArgumentNullException.ThrowIfNull(fragments);
40+
41+
foreach (var fragment in fragments)
42+
{
43+
this.AddFragment(fragment);
44+
}
45+
}
46+
}
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
namespace DendroDocs.Uml.Fragments;
2+
3+
/// <summary>
4+
/// Represents a list of fragments on the same level.
5+
/// </summary>
6+
public class Interactions : InteractionFragment
7+
{
8+
}

0 commit comments

Comments
 (0)