/// <summary> /// Renders the <see cref="List"/> and its content to string containing the markup provided by <paramref name="markupProvider"/> /// </summary> /// <remarks> /// Gets content of the all child <see cref="ListItem"/> elements and renders them into the list of required <see cref="ListType"/>. ///<list type="bullet"> /// <item> /// <term>Bullet list</term> /// <description>Each item contains "Term" in bold and "Description" (separated by dash). Both parts are optional. /// This includes the list header item if present, however, there is no special handling for such item.</description> /// </item> /// <item> /// <term>Numbered list</term> /// <description>Each item contains "Term" in bold and "Description" (separated by dash). Both parts are optional. /// This includes the list header item if present, however, there is no special handling for such item.</description></item> /// <item> /// <term>Table</term> /// <description>Rendered as two column table (term and description). Both parts are optional. /// Header item should be provided to define the table header ("Term" and "Description" are used as defaults)</description></item> /// </list> ///The rendering uses <see cref="IMarkupProvider.List{T}"/> to render the lists and <see cref="IMarkupProvider.TableHeader"/>, /// <see cref="IMarkupProvider.TableCols"/> and<see cref="IMarkupProvider.TableFooter"/> for table rendering. /// Pseudo-tags <see cref="ModelElement.TagKeepLineBreak"/> and <see cref="ModelElement.TagKeepSpace"/> are used in the rendering output, to preserve the whitespaces /// when the parent element is to be rendered (and its content trimmed) /// </remarks> /// <param name="markupProvider"><see cref="IMarkupProvider"/> allowing using the markup within the rendered content</param> /// <param name="member">Code model <see cref="Member"/> to render the XML Documentation Comment for</param> /// <param name="trim">Flag whether to (full) trim the rendered content</param> /// <returns>Rendered list element of XML Documentation Comments</returns> protected override string RenderElement(IMarkupProvider markupProvider, Member member, bool trim = true) { switch (ListType) { case ListTypeEnum.Bullet: case ListTypeEnum.Number: var content = markupProvider.List(li => { { var term = li.Term?.Render(markupProvider, member); var description = li.Description?.Render(markupProvider, member) ?? ""; return(!string.IsNullOrEmpty(term) ? $"{markupProvider.Bold(term)}{(!string.IsNullOrEmpty(description) ? $" - {description}" : "")}" : description); } }, Elements.OfType <ListItem>().ToList(), ListType == ListTypeEnum.Number); content = $"{Environment.NewLine}{Environment.NewLine}{content}{Environment.NewLine}{Environment.NewLine}" //ensure proper separation from the text .Replace("\r\n", TagKeepLineBreak) .Replace("\r", TagKeepLineBreak) .Replace("\n", TagKeepLineBreak) .Replace(" ", TagKeepSpace); //preserve whitespaces return(content); case ListTypeEnum.Table: var headerItem = Elements.OfType <ListItem>().FirstOrDefault(li => li.IsHeader); var headerTerm = headerItem?.Term?.Render(markupProvider, member) ?? "Term"; var headerDescription = headerItem?.Description?.Render(markupProvider, member) ?? "Description"; var contentTbl = markupProvider.TableHeader(headerTerm, headerDescription); foreach (var listItem in Elements.OfType <ListItem>().Where(li => !li.IsHeader)) { var term = listItem.Term?.Render(markupProvider, member) ?? ""; var description = listItem.Description?.Render(markupProvider, member) ?? ""; contentTbl += markupProvider.TableCols(term, description); } contentTbl += markupProvider.TableFooter(); contentTbl = $"{Environment.NewLine}{Environment.NewLine}{contentTbl}{Environment.NewLine}{Environment.NewLine}" //ensure proper separation from the text .Replace("\r\n", TagKeepLineBreak) .Replace("\r", TagKeepLineBreak) .Replace("\n", TagKeepLineBreak) .Replace(" ", TagKeepSpace); //preserve whitespaces return(contentTbl); default: return(""); } }
/// <summary> /// Renders the <see cref="TypeParamRef"/> and its content to string containing the markup provided by <paramref name="markupProvider"/> /// </summary> /// <remarks> /// When the element has the content (text), the content is rendered, otherwise the <c>name</c> attribute value in bold is rendered. /// </remarks> /// <param name="markupProvider"><see cref="IMarkupProvider"/> allowing using the markup within the rendered content</param> /// <param name="member">Code model <see cref="Member"/> to render the XML Documentation Comment for</param> /// <param name="trim">Flag whether to (full) trim the rendered content</param> /// <returns>Rendered content of <typeparamref> element of XML Documentation Comments</returns> protected override string RenderElement(IMarkupProvider markupProvider, Member member, bool trim = true) { var content = base.RenderElement(markupProvider, member, trim); return(!string.IsNullOrEmpty(content) ? content : markupProvider.Bold(Name)); }
/// <summary> /// Writes the source-only packages pages into the output /// </summary> /// <param name="root">Code model root</param> /// <param name="markup">Markup provider</param> /// <param name="generator">Markup generator</param> /// <returns>Async task</returns> public async Task WriteOwnPagesAsync(RootMember root, IMarkupProvider markup, MarkupGenerator generator) { if (SourceOnlyPackages == null || SourceOnlyPackages.Count < 1) { return; } if (OutputOptions.SplitNs && !OutputOptions.SplitType) { //split by Ns only -> all source only packages will be on single page await generator.SplitAsync(GetPackagePagesFileName()); } foreach (var nuProps in SourceOnlyPackages.OrderBy(p => p.PackageId)) { if (OutputOptions.SplitType) { //split by Type -> each source only packages will be on dedicated page await generator.SplitAsync(GetPackagePageFileName(nuProps)); } await markup.WriteH2Async($"{nuProps.PackageId} Source only package", GetPackageAnchor(nuProps)); await markup.WriteParaAsync( markup.Small( new Txt() .AddIf($"Version: {nuProps.PackageVersion}", !string.IsNullOrEmpty(nuProps.PackageVersion)) .AddIf(markup.LineBreak(), !string.IsNullOrEmpty(nuProps.PackageVersion)) .AddIf($"Tags: {nuProps.PackageTags}", !string.IsNullOrEmpty(nuProps.PackageTags)) .AddIf(markup.LineBreak(), !string.IsNullOrEmpty(nuProps.PackageTags)) .Add($"Includes: {nuProps.IncludesType}") .Add(markup.LineBreak()) .Add($"Declaring file: { PathUtils.GetRelativeSourceFile(nuProps.DeclaringFile,root.ProjectRootDir)}") )); await markup.WriteParaAsync(nuProps.PackageDescription); if (nuProps.Usings != null && nuProps.Usings.Count > 0) { await markup.WriteParaAsync(new Txt() .Add(markup.Bold("Usings")) .Add(markup.DescriptionList( u => { var refPkg = SourceOnlyPackages.FirstOrDefault(p => p.PackageId == u.PackageId); return(refPkg == null ? u.PackageId : Link(u.PackageId, refPkg, markup)); }, u => string.IsNullOrEmpty(u.PackageVersion) ? string.Empty : $"version: {u.PackageVersion}", nuProps.Usings))); } if (nuProps.ExternalReferences != null && nuProps.ExternalReferences.Count > 0) { await markup.WriteParaAsync(new Txt() .Add(markup.Bold("References needed")) .Add(markup.DescriptionList( er => er, er => string.Empty, nuProps.ExternalReferences))); } if (nuProps.PackageRemarksSource != null && root.AllMembersByDocId.TryGetValue(nuProps.PackageRemarksSource, out var member)) { var remarksDocumentation = member.Documentation?.GetRemarks(member)?.Render(markup, member); if (!string.IsNullOrEmpty(remarksDocumentation)) { await markup.WriteH3Async("Remarks"); await markup.WriteParaAsync(remarksDocumentation); } } if (MembersBySourceOnlyPackage.TryGetValue(nuProps, out var members) && members.Count > 0) { await markup.WriteParaAsync(new Txt() .Add(markup.Bold("Package members")) .Add(markup.DescriptionList( m => markup.Link($"{m.Name} ({m.MemberKind})", m), m => m.Documentation?.GetSummary(m)?.Render(markup, m), members))); } await markup.WriteParaAsync(new Txt() .Add(markup.Bold("Sources")) .Add(markup.DescriptionList( f => $"{PathUtils.GetRelativeSourceFile(f,root.ProjectRootDir)}", f => string.Empty, nuProps.PackageFiles))); await generator.WritePageFooterAsync(); } }