using Microsoft.CodeAnalysis; using RobotNet10.ScriptEditor.Helpers.Monaco.Documentation; using System.Text; using System.Xml; namespace RobotNet10.ScriptEditor.Helpers.Monaco; public class DocumentationConverter {/// /// Converts the xml documentation string into a plain text string. /// public static string ConvertDocumentation(string xmlDocumentation, string lineEnding) { if (string.IsNullOrEmpty(xmlDocumentation)) return string.Empty; var reader = new StringReader("" + xmlDocumentation + ""); using var xml = XmlReader.Create(reader); var ret = new StringBuilder(); try { xml.Read(); string? elementName = null; do { if (xml.NodeType == XmlNodeType.Element) { elementName = xml.Name.ToLowerInvariant(); switch (elementName) { case "filterpriority": xml.Skip(); break; case "remarks": ret.Append(lineEnding); ret.Append("Remarks:"); ret.Append(lineEnding); break; case "example": ret.Append(lineEnding); ret.Append("Example:"); ret.Append(lineEnding); break; case "exception": ret.Append(lineEnding); ret.Append(GetCref(xml["cref"]).TrimEnd()); ret.Append(": "); break; case "returns": ret.Append(lineEnding); ret.Append("Returns: "); break; case "see": ret.Append(GetCref(xml["cref"])); ret.Append(xml["langword"]); break; case "seealso": ret.Append(lineEnding); ret.Append("See also: "); ret.Append(GetCref(xml["cref"])); break; case "paramref": ret.Append(xml["name"]); ret.Append(' '); break; case "typeparam": ret.Append(lineEnding); ret.Append('<'); ret.Append(TrimMultiLineString(xml["name"], lineEnding)); ret.Append(">: "); break; case "param": ret.Append(lineEnding); ret.Append(TrimMultiLineString(xml["name"], lineEnding)); ret.Append(": "); break; case "value": ret.Append(lineEnding); ret.Append("Value: "); ret.Append(lineEnding); break; case "br": case "para": ret.Append(lineEnding); break; } } else if (xml.NodeType == XmlNodeType.Text) { if (elementName == "code") { ret.Append(xml.Value); } else { ret.Append(TrimMultiLineString(xml.Value, lineEnding)); } } } while (xml.Read()); } catch (Exception) { return xmlDocumentation; } return ret.ToString(); } private static readonly string[] separator = ["\n", "\r\n"]; private static string TrimMultiLineString(string? input, string lineEnding) { if (string.IsNullOrEmpty(input)) return ""; var lines = input.Split(separator, StringSplitOptions.RemoveEmptyEntries); return string.Join(lineEnding, lines.Select(l => l.TrimStart())); } private static string GetCref(string? cref) { if (cref == null || cref.Trim().Length == 0) { return ""; } if (cref.Length < 2) { return cref; } if (cref.Substring(1, 1) == ":") { return cref[2..] + " "; } return cref + " "; } public static DocumentationComment? GetStructuredDocumentation(string? xmlDocumentation, string lineEnding) { if (string.IsNullOrEmpty(xmlDocumentation)) return null; return DocumentationComment.From(xmlDocumentation, lineEnding); } public static DocumentationComment? GetStructuredDocumentation(ISymbol symbol, string lineEnding = "\n") { return symbol switch { IParameterSymbol parameter => new DocumentationComment(summaryText: GetParameterDocumentation(parameter, lineEnding) ?? ""), ITypeParameterSymbol typeParam => new DocumentationComment(summaryText: GetTypeParameterDocumentation(typeParam, lineEnding) ?? ""), IAliasSymbol alias => new DocumentationComment(summaryText: GetAliasDocumentation(alias, lineEnding) ?? ""), _ => GetStructuredDocumentation(symbol.GetDocumentationCommentXml(), lineEnding), }; } private static string? GetParameterDocumentation(IParameterSymbol parameter, string lineEnding = "\n") { var contaningSymbolDef = parameter.ContainingSymbol.OriginalDefinition; return GetStructuredDocumentation(contaningSymbolDef.GetDocumentationCommentXml(), lineEnding) ?.GetParameterText(parameter.Name); } private static string? GetTypeParameterDocumentation(ITypeParameterSymbol typeParam, string lineEnding = "\n") { var contaningSymbol = typeParam.ContainingSymbol; return GetStructuredDocumentation(contaningSymbol.GetDocumentationCommentXml(), lineEnding) ?.GetTypeParameterText(typeParam.Name); } private static string? GetAliasDocumentation(IAliasSymbol alias, string lineEnding = "\n") { return GetStructuredDocumentation(alias.Target.GetDocumentationCommentXml(), lineEnding)?.SummaryText; } }