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
3 changes: 2 additions & 1 deletion .claude/settings.local.json
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,8 @@
"WebFetch(domain:www.nuget.org)",
"WebFetch(domain:www.anthropic.com)",
"Bash(gh run:*)",
"Bash(gh workflow:*)"
"Bash(gh workflow:*)",
"Bash(git rev-list *)"
],
"deny": [],
"ask": [],
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@
<ItemGroup>
<!-- MSBuild task dependencies -->
<PackageReference Include="EasyAF.MSBuild" Version="4.*" />
<PackageReference Include="System.Collections.Immutable" Version="9.*" PrivateAssets="all" />

<!-- Microsoft.CodeAnalysis.CSharp.Workspaces needs to be available for the task -->
<PackageReference Include="Microsoft.CodeAnalysis.CSharp.Workspaces" Version="4.*" />
Expand All @@ -30,14 +29,26 @@
<!-- Framework-specific dependencies -->
<ItemGroup Condition="'$(TargetFramework)' == 'net10.0'">
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="10.*" />
<PackageReference Include="System.Collections.Immutable" Version="10.*" PrivateAssets="all" />

<!-- Vulnerability fix -->
<PackageReference Include="System.Security.Cryptography.Xml" Version="10.*" />
</ItemGroup>

<ItemGroup Condition="'$(TargetFramework)' == 'net9.0'">
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="9.*" />
<PackageReference Include="System.Collections.Immutable" Version="9.*" PrivateAssets="all" />

<!-- Vulnerability fix -->
<PackageReference Include="System.Security.Cryptography.Xml" Version="9.*" />
</ItemGroup>

<ItemGroup Condition="'$(TargetFramework)' == 'net8.0'">
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="9.*" />
<PackageReference Include="System.Collections.Immutable" Version="9.*" PrivateAssets="all" />

<!-- Vulnerability fix -->
<PackageReference Include="System.Security.Cryptography.Xml" Version="9.*" />
</ItemGroup>

<ItemGroup Condition="'$(TargetFramework)' == 'net472'">
Expand Down
22 changes: 22 additions & 0 deletions src/CloudNimble.DotNetDocs.Sdk.Tasks/GenerateDocumentationTask.cs
Original file line number Diff line number Diff line change
Expand Up @@ -779,6 +779,20 @@ internal NavigationConfig ParseNavigationConfig(XElement navigationElement)
/// </summary>
/// <param name="groupElement">The group XML element.</param>
/// <returns>A GroupConfig instance, or null if parsing fails.</returns>
/// <remarks>
/// Requires a <c>Name</c> attribute. Optional attributes include <c>Icon</c>, <c>Tag</c>,
/// <c>Root</c> (the default page shown when the group is selected), and <c>Expanded</c>
/// (<c>true</c>/<c>false</c>, controlling the group's default expand/collapse state).
/// Child <c>&lt;Pages&gt;</c> and nested <c>&lt;Group&gt;</c> elements (optionally wrapped in
/// <c>&lt;Groups&gt;</c>) are also parsed.
/// </remarks>
/// <example>
/// <code>
/// &lt;Group Name="Episodes" Icon="microphone" Root="Brands/WhatsYourStory/Episodes/index" Expanded="false"&gt;
/// &lt;Pages&gt;Brands/WhatsYourStory/Episodes/index;Brands/WhatsYourStory/Episodes/analysis&lt;/Pages&gt;
/// &lt;/Group&gt;
/// </code>
/// </example>
internal GroupConfig? ParseGroupConfig(XElement groupElement)
{
var groupName = groupElement.Attribute("Name")?.Value;
Expand All @@ -793,9 +807,17 @@ internal NavigationConfig ParseNavigationConfig(XElement navigationElement)
Group = groupName,
Icon = groupElement.Attribute("Icon")?.Value,
Tag = groupElement.Attribute("Tag")?.Value,
Root = groupElement.Attribute("Root")?.Value,
Pages = []
};

// Parse the optional Expanded attribute, which controls the group's default expand/collapse state.
var expandedAttr = groupElement.Attribute("Expanded")?.Value;
if (!string.IsNullOrWhiteSpace(expandedAttr) && bool.TryParse(expandedAttr, out var expanded))
{
group.Expanded = expanded;
}

// Parse direct pages (semicolon-separated list)
var pagesElement = groupElement.Element(nameof(GroupConfig.Pages));
if (pagesElement is not null && !string.IsNullOrWhiteSpace(pagesElement.Value))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,14 +48,14 @@ public void TestCleanup()
#region MintlifyTemplate XML Parsing Tests

/// <summary>
/// Tests that ParseGroupConfig correctly extracts group name, icon, and tag from XML.
/// Tests that ParseGroupConfig correctly extracts group name, icon, tag, root, and expanded from XML.
/// </summary>
[TestMethod]
public void ParseGroupConfig_WithCompleteAttributes_ParsesAllProperties()
{
// Arrange
var xml = """
<Group Name="Getting Started" Icon="stars" Tag="CORE">
<Group Name="Getting Started" Icon="stars" Tag="CORE" Root="getting-started/index" Expanded="false">
<Pages>index;quickstart</Pages>
</Group>
""";
Expand All @@ -69,11 +69,109 @@ public void ParseGroupConfig_WithCompleteAttributes_ParsesAllProperties()
result!.Group.Should().Be("Getting Started");
result.Icon!.Name.Should().Be("stars");
result.Tag.Should().Be("CORE");
result.Root.Should().Be("getting-started/index");
result.Expanded.Should().BeFalse();
result.Pages.Should().HaveCount(2);
result.Pages![0].Should().Be("index");
result.Pages![1].Should().Be("quickstart");
}

/// <summary>
/// Tests that ParseGroupConfig parses the Root attribute, used to disambiguate identically-named
/// groups across sections and to provide a landing page when the group is selected.
/// </summary>
[TestMethod]
public void ParseGroupConfig_WithRootAttribute_ParsesRoot()
{
// Arrange
var xml = """
<Group Name="Episodes" Icon="microphone" Root="Brands/WhatsYourStory/Episodes/index">
<Pages>Brands/WhatsYourStory/Episodes/index</Pages>
</Group>
""";
var groupElement = XElement.Parse(xml);

// Act
var result = _task.ParseGroupConfig(groupElement);

// Assert
result.Should().NotBeNull();
result!.Root.Should().Be("Brands/WhatsYourStory/Episodes/index");
}

/// <summary>
/// Tests that ParseGroupConfig leaves Root null when the attribute is absent.
/// </summary>
[TestMethod]
public void ParseGroupConfig_WithoutRoot_HasNullRoot()
{
// Arrange
var xml = """
<Group Name="Episodes" Icon="microphone">
<Pages>index</Pages>
</Group>
""";
var groupElement = XElement.Parse(xml);

// Act
var result = _task.ParseGroupConfig(groupElement);

// Assert
result.Should().NotBeNull();
result!.Root.Should().BeNull();
}

/// <summary>
/// Tests that ParseGroupConfig parses the Expanded attribute for both true and false values.
/// </summary>
[TestMethod]
[DataRow("true", true)]
[DataRow("false", false)]
[DataRow("True", true)]
public void ParseGroupConfig_WithExpandedAttribute_ParsesExpanded(string value, bool expected)
{
// Arrange
var xml = $"""
<Group Name="Episodes" Icon="microphone" Expanded="{value}">
<Pages>index</Pages>
</Group>
""";
var groupElement = XElement.Parse(xml);

// Act
var result = _task.ParseGroupConfig(groupElement);

// Assert
result.Should().NotBeNull();
result!.Expanded.Should().Be(expected);
}

/// <summary>
/// Tests that ParseGroupConfig leaves Expanded null when the attribute is absent or not a valid boolean.
/// </summary>
[TestMethod]
[DataRow(null)]
[DataRow("")]
[DataRow("yes")]
public void ParseGroupConfig_WithMissingOrInvalidExpanded_LeavesExpandedNull(string? value)
{
// Arrange
var attr = value is null ? "" : $@" Expanded=""{value}""";
var xml = $"""
<Group Name="Episodes" Icon="microphone"{attr}>
<Pages>index</Pages>
</Group>
""";
var groupElement = XElement.Parse(xml);

// Act
var result = _task.ParseGroupConfig(groupElement);

// Assert
result.Should().NotBeNull();
result!.Expanded.Should().BeNull();
}

/// <summary>
/// Tests that ParseGroupConfig preserves the exact order of groups as defined in the template.
/// </summary>
Expand Down
2 changes: 1 addition & 1 deletion src/global.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"sdk": {
"version": "10.0.100",
"version": "10.0.300",
"rollForward": "latestPatch"
},
"test": {
Expand Down
Loading