From 976361f4466739580632d2c478596f8502650169 Mon Sep 17 00:00:00 2001 From: Tim <47110241+timunie@users.noreply.github.com> Date: Sun, 19 Oct 2025 20:13:22 +0200 Subject: [PATCH 1/8] Updates - update HelpFileBuilder - Fix some errors and warnings after update - improve ReadMe --- README.md | 8 +- .../ApiDocumentation.shfbproj | 4 +- .../AvaloniaAttributesPlugIn.csproj | 4 +- .../DocusaurusExportPlugin.csproj | 4 +- .../DocusaurusMarkdownPresentationStyle.cs | 2 +- .../DocusaurusMarkdownTransformation.cs | 90 ++++++++++--------- .../Elements/MdxListElement.cs | 1 - .../DocusaurusPresentationStyle.csproj | 4 +- 8 files changed, 62 insertions(+), 55 deletions(-) diff --git a/README.md b/README.md index 49285b3..42e9d20 100644 --- a/README.md +++ b/README.md @@ -21,12 +21,10 @@ It is important to mind the build order. > ``` ## Generate the API docs for newer Avalonia version -Use the `set-version.ps1` script to update the version. +Use the `update-submodule.ps1` script to update the version to the latest stable. if you need any other branch version, you need to link the branch name for the submodule by hand. -```ps1 -# -version: specify the Avalonia version to document. If this parameter is not set, `AvaloniaVersion.txt` will be used instead. -.\set-version.ps1 11.2.0 -``` +> [!NOTE] +> The file `./ext/Avalonia/build/SharedVersion.props` stores the current version info. > [!WARNING] > Remember to commit all updates made to the submodule. diff --git a/src/ApiDocumentation/ApiDocumentation.shfbproj b/src/ApiDocumentation/ApiDocumentation.shfbproj index 0e75d8a..d5574e6 100644 --- a/src/ApiDocumentation/ApiDocumentation.shfbproj +++ b/src/ApiDocumentation/ApiDocumentation.shfbproj @@ -135,8 +135,8 @@ - - + + diff --git a/src/AvaloniaAttributesPlugin/AvaloniaAttributesPlugIn.csproj b/src/AvaloniaAttributesPlugin/AvaloniaAttributesPlugIn.csproj index df0d3d2..927e6e7 100644 --- a/src/AvaloniaAttributesPlugin/AvaloniaAttributesPlugIn.csproj +++ b/src/AvaloniaAttributesPlugin/AvaloniaAttributesPlugIn.csproj @@ -62,8 +62,8 @@ - - + + diff --git a/src/DocusaurusExportPlugin/DocusaurusExportPlugin.csproj b/src/DocusaurusExportPlugin/DocusaurusExportPlugin.csproj index 528233c..fcd7875 100644 --- a/src/DocusaurusExportPlugin/DocusaurusExportPlugin.csproj +++ b/src/DocusaurusExportPlugin/DocusaurusExportPlugin.csproj @@ -63,8 +63,8 @@ - - + + diff --git a/src/DocusaurusPresentationStyle/DocusaurusMarkdown/DocusaurusMarkdownPresentationStyle.cs b/src/DocusaurusPresentationStyle/DocusaurusMarkdown/DocusaurusMarkdownPresentationStyle.cs index 9fac58c..1388476 100644 --- a/src/DocusaurusPresentationStyle/DocusaurusMarkdown/DocusaurusMarkdownPresentationStyle.cs +++ b/src/DocusaurusPresentationStyle/DocusaurusMarkdown/DocusaurusMarkdownPresentationStyle.cs @@ -18,12 +18,12 @@ // 02/27/2025 TU Adjusted the code to support the MDX-format //=============================================================================================================== -using System; using System.Collections.Generic; using System.IO; using System.Reflection; using Sandcastle.Core; using Sandcastle.Core.PresentationStyle; +using Sandcastle.Core.Project; namespace DocusaurusPresentationStyle.DocusaurusMarkdown { diff --git a/src/DocusaurusPresentationStyle/DocusaurusMarkdown/DocusaurusMarkdownTransformation.cs b/src/DocusaurusPresentationStyle/DocusaurusMarkdown/DocusaurusMarkdownTransformation.cs index 430f2fe..130e76d 100644 --- a/src/DocusaurusPresentationStyle/DocusaurusMarkdown/DocusaurusMarkdownTransformation.cs +++ b/src/DocusaurusPresentationStyle/DocusaurusMarkdown/DocusaurusMarkdownTransformation.cs @@ -20,16 +20,15 @@ using System; using System.Collections.Generic; -using System.Collections.ObjectModel; using System.Diagnostics; using System.Linq; using System.Xml.Linq; using DocusaurusPresentationStyle.DocusaurusMarkdown.Elements; -using Sandcastle.Core; using Sandcastle.Core.PresentationStyle.Transformation; using Sandcastle.Core.PresentationStyle.Transformation.Elements; using Sandcastle.Core.PresentationStyle.Transformation.Elements.Html; using Sandcastle.Core.PresentationStyle.Transformation.Elements.Markdown; +using Sandcastle.Core.Project; using Sandcastle.Core.Reflection; using CodeElement = DocusaurusPresentationStyle.DocusaurusMarkdown.Elements.CodeElement; using MarkdownGlossaryElement = Sandcastle.Core.PresentationStyle.Transformation.Elements.Markdown.GlossaryElement; @@ -44,9 +43,9 @@ public class DocusaurusMarkdownTransformation : TopicTransformationCore { //===================================================================== - private XDocument? pageTemplate; + private XDocument? _pageTemplate; - private static readonly HashSet spacePreservedElements = new HashSet( + private static readonly HashSet SpacePreservedElements = new HashSet( new[] { "code", "pre", "snippet" }, StringComparer.OrdinalIgnoreCase); //===================================================================== @@ -471,10 +470,10 @@ protected override void CreateNoticeDefinitions() /// protected override XDocument RenderTopic() { - if(pageTemplate == null) - pageTemplate = LoadTemplateFile(this.TopicTemplatePath, null); + if(_pageTemplate == null) + _pageTemplate = LoadTemplateFile(this.TopicTemplatePath, null); - var document = new XDocument(pageTemplate); + var document = new XDocument(_pageTemplate); this.CurrentElement = document.Root; @@ -527,7 +526,7 @@ public override void RenderTextNode(XElement? content, XText? textNode) // list of elements that should preserve space, just add the text as-is. Otherwise,normalize the // whitespace. if(text.Length == 0 || (content.Name != "document" && content.Attribute(Element.XmlSpace) != null) || - spacePreservedElements.Contains(textNode.Parent?.Name.LocalName ?? string.Empty) || + SpacePreservedElements.Contains(textNode.Parent?.Name.LocalName ?? string.Empty) || ((textNode.Parent?.Name.LocalName == "div" || textNode.Parent?.Name.LocalName == "span") && textNode.Ancestors("syntax").Any())) { @@ -650,7 +649,7 @@ private static void RenderNotices(TopicTransformationCore transformation) if(element != null) { if(n.UseValueForText) - noticeText = element.Value?.NormalizeWhiteSpace(); + noticeText = element.Value.NormalizeWhiteSpace(); if(String.IsNullOrWhiteSpace(noticeText)) noticeText = n.NoticeMessage; @@ -670,7 +669,7 @@ private static void RenderNotices(TopicTransformationCore transformation) if(attr != null) { if(n.UseValueForText) - noticeText = attr.Element("argument")?.Element("value")?.Value?.NormalizeWhiteSpace(); + noticeText = attr.Element("argument")?.Element("value")?.Value.NormalizeWhiteSpace(); if(String.IsNullOrWhiteSpace(noticeText)) noticeText = n.NoticeMessage; @@ -692,7 +691,7 @@ private static void RenderNotices(TopicTransformationCore transformation) message.Add("\n"); // If the notice text starts with '@', it's a content item - if(noticeText[0] == '@') + if(noticeText is {Length: > 0} && noticeText[0] == '@') message.Add(new XElement("include", new XAttribute("item", noticeText.Substring(1)))); else message.Add(noticeText); @@ -751,7 +750,7 @@ private static void RenderNoticeTags(TopicTransformationCore transformation, XEl var tag = new XElement("Tag", new XAttribute("type", n.TagStyleClasses ?? "is-warning")); // If the notice text starts with '@', it's a content item - if(noticeText[0] == '@') + if(noticeText is {Length: > 0} && noticeText[0] == '@') tag.Add(new XElement("include", new XAttribute("item", noticeText.Substring(1)))); else tag.Add(noticeText); @@ -909,7 +908,7 @@ private static void RenderApiNamespaceAndAssemblyInformation(TopicTransformation } var containers = transformation.ReferenceNode.Element("containers"); - var libraries = containers?.Elements("library"); + var libraries = containers?.Elements("library").ToArray() ?? []; content.Add("**", new XElement("include", new XAttribute("item", "boilerplate_requirementsNamespace")), "** ", @@ -919,13 +918,13 @@ private static void RenderApiNamespaceAndAssemblyInformation(TopicTransformation int separatorSize = 1; bool first = true; - if(libraries?.Count() > 1) + if(libraries is {Length: > 1}) { content.Add("**", new XElement("include", new XAttribute("item", "boilerplate_requirementsAssemblies")), "**"); separatorSize = 2; } - else + else { content.Add("**", new XElement("include", new XAttribute("item", "boilerplate_requirementsAssemblyLabel")), "**"); @@ -963,21 +962,26 @@ private static void RenderApiNamespaceAndAssemblyInformation(TopicTransformation // Show XAML XML namespaces for APIs that support XAML. All topics that have auto-generated XAML // syntax get an "XMLNS for XAML" line in the Requirements section. Topics with boilerplate XAML // syntax, e.g. "Not applicable", do NOT get this line. - var xamlCode = transformation.SyntaxNode.Elements("div").Where(d => d.Attribute("codeLanguage")?.Value.Equals( - "XAML", StringComparison.Ordinal) ?? false); + var xamlCode = transformation.SyntaxNode + .Elements("div") + .Where(d => d.Attribute("codeLanguage")?.Value.Equals("XAML", StringComparison.Ordinal) ?? false) + .ToArray(); - if(xamlCode.Any()) + if(xamlCode.Length != 0) { - var xamlXmlNS = xamlCode.Elements("div").Where(d => d.Attribute("class")?.Value == "xamlXmlnsUri"); + var xamlXmlNs = xamlCode + .Elements("div") + .Where(d => d.Attribute("class")?.Value == "xamlXmlnsUri") + .ToArray(); content.Add(" \n", "**", new XElement("include", new XAttribute("item", "boilerplate_xamlXmlnsRequirements")), "** "); - if(xamlXmlNS.Any()) + if(xamlXmlNs.Length != 0) { first = true; - foreach(var d in xamlXmlNS) + foreach(var d in xamlXmlNs) { if(!first) content.Add(", "); @@ -1048,10 +1052,10 @@ private static void RenderApiRootList(TopicTransformationCore transformation) var elements = transformation.ReferenceNode.Element("elements")?.Elements("element").OrderBy( e => e.Element("apidata")?.Attribute("name")?.Value).ToList(); - if((elements?.Count ?? 0) == 0) + if(elements is null or { Count: 0 }) return; - var (title, _) = transformation.CreateSection(elements?[0].GenerateUniqueId(), true, "title_namespaces", null); + var (title, _) = transformation.CreateSection(elements[0].GenerateUniqueId(), true, "title_namespaces", null); transformation.CurrentElement.Add(title); @@ -1095,10 +1099,10 @@ private static void RenderApiNamespaceGroupList(TopicTransformationCore transfor return name.Substring(name.IndexOf(':') + 1); }).ToList(); - if((elements?.Count ?? 0) == 0) + if(elements is null or {Count : 0}) return; - var (title, _) = transformation.CreateSection(elements?[0].GenerateUniqueId(), true, + var (title, _) = transformation.CreateSection(elements[0].GenerateUniqueId(), true, "tableTitle_namespace", null); transformation.CurrentElement.Add(title); @@ -1226,7 +1230,7 @@ private static void RenderApiEnumerationMembersList(TopicTransformationCore tran { EnumValueFormat enumFormat = thisTransform.FlagsEnumValueFormat; int groupSize = thisTransform.IncludeIntegerEnumSeparators ? 3 : 0, minWidth = 0; - bool signedValues = enumValues.Any(v => v.Length > 0 && v[0] == '-'); + bool signedValues = enumValues.Any(v => v?.Length > 0 && v[0] == '-'); if(enumFormat != EnumValueFormat.IntegerValue && thisTransform.ReferenceNode.AttributeOfType("T:System.FlagsAttribute") != null) @@ -1335,17 +1339,20 @@ private static void RenderApiTypeMemberLists(TopicTransformationCore transformat { var allMembers = transformation.ReferenceNode.Element("elements")?.Elements("element").ToList(); - if((allMembers?.Count ?? 0) == 0) + if(allMembers is null or {Count: 0}) return; - var overloads = allMembers?.Where(e => e.Attribute("api")!.Value.StartsWith("Overload:", + var overloads = allMembers.Where(e => e.Attribute("api")!.Value.StartsWith("Overload:", StringComparison.Ordinal)).ToList(); // Remove overload topics and add their members to the full member list foreach(var overload in overloads) { - allMembers.Remove(overload); - allMembers.AddRange(overload.Elements("element")); + if (overload != null) + { + allMembers.Remove(overload); + allMembers.AddRange(overload.Elements("element")); + } } var memberGroups = new Dictionary> @@ -1369,7 +1376,7 @@ private static void RenderApiTypeMemberLists(TopicTransformationCore transformat // Group the members by section type foreach(var m in allMembers) { - XElement? apiData = m.Element("apidata"), memberData = m.Element("memberdata"), + XElement? apiData = m.Element("apidata"), procedureData = m.Element("proceduredata"); // Some members such as inherited interface members on a derived interface, contain no @@ -1476,7 +1483,6 @@ private static void RenderApiTypeMemberLists(TopicTransformationCore transformat e.Element("memberdata")?.Attribute("overload") == null && !(e.Parent?.Attribute("api")?.Value ?? String.Empty).StartsWith( "Overload:", StringComparison.Ordinal)) ? "false" : "true"; - bool isExtensionMethod = e.AttributeOfType("T:System.Runtime.CompilerServices.ExtensionAttribute") != null; var summaryCell = new XElement("td"); @@ -1577,9 +1583,11 @@ private static void RenderApiTypeMemberLists(TopicTransformationCore transformat private static void RenderApiSectionTable(TopicTransformationCore transformation, string sectionTitleItem, IEnumerable sectionElements) { - if(sectionElements.Any()) + var sections = sectionElements as XElement[] ?? sectionElements.ToArray(); + + if(sections.Length != 0) { - var (title, _) = transformation.CreateSection(sectionElements.First().GenerateUniqueId(), true, + var (title, _) = transformation.CreateSection(sections.First().GenerateUniqueId(), true, sectionTitleItem, null); transformation.CurrentElement.Add(title); @@ -1588,7 +1596,7 @@ private static void RenderApiSectionTable(TopicTransformationCore transformation transformation.CurrentElement.Add(table); - foreach(var se in sectionElements) + foreach(var se in sections) { var descCell = new XElement("td"); @@ -1669,10 +1677,12 @@ private static void RenderApiRevisionHistorySection(TopicTransformationCore tran if(revisionHistory == null || revisionHistory.Attribute("visible")?.Value == "false") return; - var revisions = revisionHistory.Elements("revision").Where( - h => h.Attribute("visible")?.Value != "false"); + var revisions = revisionHistory + .Elements("revision") + .Where(h => h.Attribute("visible")?.Value != "false") + .ToArray(); - if(revisions.Any()) + if(revisions.Length != 0) { var (title, _) = transformation.CreateSection(revisionHistory.GenerateUniqueId(), true, "title_revisionHistory", null); @@ -1849,9 +1859,9 @@ private static void RenderApiAutoGeneratedSeeAlsoLinks(TopicTransformationCore t } // Add a link to the namespace topic - string namespaceId = transformation.ReferenceNode.Element("containers")?.Element("namespace")?.Attribute("api")?.Value; + var namespaceId = transformation.ReferenceNode.Element("containers")?.Element("namespace")?.Attribute("api")?.Value; - if(!String.IsNullOrWhiteSpace(namespaceId)) + if(!string.IsNullOrWhiteSpace(namespaceId)) { subsection.Add(new XElement("referenceLink", new XAttribute("target", namespaceId), diff --git a/src/DocusaurusPresentationStyle/DocusaurusMarkdown/Elements/MdxListElement.cs b/src/DocusaurusPresentationStyle/DocusaurusMarkdown/Elements/MdxListElement.cs index 3320c4f..fe71d51 100644 --- a/src/DocusaurusPresentationStyle/DocusaurusMarkdown/Elements/MdxListElement.cs +++ b/src/DocusaurusPresentationStyle/DocusaurusMarkdown/Elements/MdxListElement.cs @@ -79,7 +79,6 @@ public override void Render(TopicTransformationCore? transformation, XElement? e default: throw new ArgumentException($"Invalid element type {element.Attribute("type")?.Value}"); - break; } } } \ No newline at end of file diff --git a/src/DocusaurusPresentationStyle/DocusaurusPresentationStyle.csproj b/src/DocusaurusPresentationStyle/DocusaurusPresentationStyle.csproj index 63d548b..7046869 100644 --- a/src/DocusaurusPresentationStyle/DocusaurusPresentationStyle.csproj +++ b/src/DocusaurusPresentationStyle/DocusaurusPresentationStyle.csproj @@ -62,8 +62,8 @@ - - + + From d53d14b75707c508b8024e660de5df402607d1de Mon Sep 17 00:00:00 2001 From: Tim <47110241+timunie@users.noreply.github.com> Date: Sun, 19 Oct 2025 20:40:35 +0200 Subject: [PATCH 2/8] update shfb tools path --- build.ps1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.ps1 b/build.ps1 index edb0b0f..661810e 100644 --- a/build.ps1 +++ b/build.ps1 @@ -20,7 +20,7 @@ New-item ./website/AvaloniaVersion.txt -ItemType File -Value $version -Force Write-Host "Avalonia version is $version" # set SHFBRoot -$env:SHFBRoot = ".\src\packages\ewsoftware.shfb\2025.3.22\tools\" +$env:SHFBRoot = ".\src\packages\ewsoftware.shfb\2025.9.30\tools\" # Define a list of dotNET projects to build $projectsToBuild = @( From 90c87f21296bdda24e526257d91cfcc03da9d2b1 Mon Sep 17 00:00:00 2001 From: Tim <47110241+timunie@users.noreply.github.com> Date: Tue, 21 Oct 2025 11:14:54 +0200 Subject: [PATCH 3/8] Follow SHFB migration guide After update there were some breaking changes. Files were updated accordingly (see: https://ewsoftware.github.io/SHFB/html/bc933f8f-e792-45bf-afec-62aa2c46aa3b.htm) --- README.md | 9 +++++++++ .../AvaloniaAttributesPlugIn.cs | 8 ++++---- .../AvaloniaAttributesPlugIn.csproj | 1 - .../DocusaurusContentGenerator.cs | 6 +++--- ...ortPluginPlugIn.cs => DocusaurusExportPlugIn.cs} | 13 ++++++------- .../DocusaurusExportPlugin.csproj | 2 +- .../Sidebar/SidebarGenerator.cs | 2 +- .../Sidebar/SidebarSection.cs | 3 +++ 8 files changed, 27 insertions(+), 17 deletions(-) rename src/DocusaurusExportPlugin/{DocusaurusExportPluginPlugIn.cs => DocusaurusExportPlugIn.cs} (93%) diff --git a/README.md b/README.md index 42e9d20..6e5dece 100644 --- a/README.md +++ b/README.md @@ -20,6 +20,15 @@ It is important to mind the build order. > .\build.ps1 -preview > ``` +## Updating the Sandcastle tools + +> [WARNING] if you update the SHFB-nuget packages you also need to update the tools path in `build.ps1` +> ```ps1 +> # set SHFBRoot +> $env:SHFBRoot = ".\src\packages\ewsoftware.shfb\2025.9.30\tools\" +> ``` + + ## Generate the API docs for newer Avalonia version Use the `update-submodule.ps1` script to update the version to the latest stable. if you need any other branch version, you need to link the branch name for the submodule by hand. diff --git a/src/AvaloniaAttributesPlugin/AvaloniaAttributesPlugIn.cs b/src/AvaloniaAttributesPlugin/AvaloniaAttributesPlugIn.cs index 27c55a0..b3236bf 100644 --- a/src/AvaloniaAttributesPlugin/AvaloniaAttributesPlugIn.cs +++ b/src/AvaloniaAttributesPlugin/AvaloniaAttributesPlugIn.cs @@ -1,5 +1,3 @@ -using SandcastleBuilder.Utils.BuildComponent; -using SandcastleBuilder.Utils.BuildEngine; using System; using System.Collections.Generic; using System.IO; @@ -7,6 +5,8 @@ using System.Text.RegularExpressions; using System.Xml.Linq; using System.Xml.XPath; +using Sandcastle.Core.BuildEngine; +using Sandcastle.Core.PlugIn; namespace AvaloniaAttributes { @@ -36,7 +36,7 @@ public sealed class AvaloniaAttributesPlugIn : IPlugIn private List? _executionPoints; - private BuildProcess? _builder; + private IBuildProcess? _builder; //===================================================================== @@ -61,7 +61,7 @@ public IEnumerable ExecutionPoints /// /// A reference to the current build process /// The configuration data that the plug-in should use to initialize itself - public void Initialize(BuildProcess buildProcess, XElement configuration) + public void Initialize(IBuildProcess buildProcess, XElement configuration) { _builder = buildProcess; diff --git a/src/AvaloniaAttributesPlugin/AvaloniaAttributesPlugIn.csproj b/src/AvaloniaAttributesPlugin/AvaloniaAttributesPlugIn.csproj index 927e6e7..3b34970 100644 --- a/src/AvaloniaAttributesPlugin/AvaloniaAttributesPlugIn.csproj +++ b/src/AvaloniaAttributesPlugin/AvaloniaAttributesPlugIn.csproj @@ -64,7 +64,6 @@ -