using System; using System.Linq; using System.Text; using System.Xml.Linq; namespace QuestPDF.InteropGenerators; /// /// Helper class for extracting and processing XML documentation comments /// public static class DocumentationHelper { /// /// Extracts documentation from XML documentation comments. /// Processes summary and remarks sections, stripping XML tags and formatting. /// /// Raw XML documentation string from Roslyn symbol /// Cleaned documentation text, or empty string if no documentation exists public static string ExtractDocumentation(string? xmlDocumentation) { if (string.IsNullOrWhiteSpace(xmlDocumentation)) return string.Empty; var doc = new StringBuilder(); try { var xml = XDocument.Parse(xmlDocumentation); // Extract summary var summary = xml.Descendants("summary").FirstOrDefault(); if (summary != null) { var summaryText = CleanXmlContent(summary); if (!string.IsNullOrWhiteSpace(summaryText)) doc.AppendLine(summaryText); } // Extract remarks var remarks = xml.Descendants("remarks").FirstOrDefault(); if (remarks != null) { var remarksText = CleanXmlContent(remarks); if (!string.IsNullOrWhiteSpace(remarksText)) { if (doc.Length > 0) doc.AppendLine(); doc.Append(remarksText); } } } catch { // If XML parsing fails, return empty string return string.Empty; } return doc.ToString().Trim(); } /// /// Cleans XML content by removing tags like <see cref="..." /> and normalizing whitespace /// /// XML element to clean /// Cleaned text content private static string CleanXmlContent(XElement element) { var text = new StringBuilder(); foreach (var node in element.Nodes()) { if (node is XText textNode) { text.Append(textNode.Value); } else if (node is XElement childElement) { // Handle specific XML elements switch (childElement.Name.LocalName) { case "see": case "seealso": // Extract the referenced name from cref attribute var cref = childElement.Attribute("cref")?.Value; if (!string.IsNullOrEmpty(cref)) { // Extract just the member name (e.g., "Height" from "ConstrainedExtensions.Height") var parts = cref.Split('.'); var memberName = parts.Length > 0 ? parts[parts.Length - 1] : cref; text.Append(memberName); } else { // Fallback to inner text if no cref text.Append(childElement.Value); } break; case "paramref": case "typeparamref": // Extract parameter name var name = childElement.Attribute("name")?.Value ?? childElement.Value; text.Append(name); break; case "c": case "code": // Inline code or code blocks text.Append(childElement.Value); break; default: // For other elements, just get the text content text.Append(childElement.Value); break; } } } // Normalize whitespace: collapse multiple spaces/newlines into single spaces var result = text.ToString(); result = System.Text.RegularExpressions.Regex.Replace(result, @"\s+", " "); return result.Trim(); } }