Пример #1
0
        private void WriteReturns(RenderingState state)
        {
            if (state.Id.Type == "JsMethod" || state.Returns == null)
            {
                return;
            }

            state.AppendString($"<span class=\"table-of-contents-item-inline-returns\"> : ");

            if (!string.IsNullOrWhiteSpace(state.Returns.Href) && !state.Returns.IsVirtual)
            {
                state.AppendString($"<a href=\"{EscapeHtml(RelativePathHelper.GetRelativePath(state.CurrentPath, state.Returns.Href, "html"))}\">");
            }

            var title = state.Returns.Title;

            // If this is a List<T> or IList<T>, transform the return value to read "List of T" or "IList of T"
            if (title.StartsWith("List<") || title.StartsWith("IList<"))
            {
                var prefix   = title.Substring(0, title.IndexOf("<"));
                var generics = title.Substring(prefix.Length + 1).TrimEnd('>');
                title = $"{prefix} of {generics}";
            }

            state.AppendString(EscapeHtml(title));

            if (!string.IsNullOrWhiteSpace(state.Returns.Href) && !state.Returns.IsVirtual)
            {
                state.AppendString($"</a>");
            }

            state.AppendString($"</span>");
        }
Пример #2
0
        private async Task WriteValuesAsync(RenderingState state)
        {
            if ((state.Document.Entity.Values?.Count ?? 0) == 0)
            {
                return;
            }

            state.AppendString($"<section class=\"values\">");
            state.AppendString($"<h3 id=\"section-values\">Possible Values</h3>");
            state.AppendString($"<dl>");

            foreach (var value in state.Document.Entity.Values)
            {
                state.AppendString($"<dt>");
                state.AppendString($"<a href=\"{EscapeHtml(RelativePathHelper.GetRelativePath(state.Document.Entity.Uri.Href, value.Uri, "html"))}\">");
                state.AppendString(EscapeHtml(value.Title));
                state.AppendString($"</a>");
                state.AppendString($"</dt>");
                state.AppendString($"<dd>");

                if (!string.IsNullOrWhiteSpace(value.Comment?.Brief))
                {
                    var result = await RenderMarkdownAsync(value.Comment.Brief);

                    state.MarkdownDeferredIds.Add(result.Id);
                    state.AppendString(result.Html);
                }

                state.AppendString($"</dd>");
            }

            state.AppendString($"</dl>");
            state.AppendString($"</section>");
        }
Пример #3
0
        private void WriteAttachedBy(RenderingState state)
        {
            if (!state.Id.Type.StartsWith("AttachedUx"))
            {
                return;
            }

            if (!state.EntityCache.ContainsKey(state.Uri.Href))
            {
                throw new ArgumentException($"TOC item {state.Uri.Href} was not found in entity cache");
            }
            var underlyingEntity = state.EntityCache[state.Uri.Href];

            if (!state.EntityCache.ContainsKey(underlyingEntity.Id.ParentId))
            {
                throw new ArgumentException($"Parent of TOC item {state.Id.Id} ({underlyingEntity.Id.ParentId} was not found in entity cache");
            }
            var attachedBy = state.EntityCache[underlyingEntity.Id.ParentId];

            var attachedByName = attachedBy.Titles.IndexTitle;
            var attachedByHref = attachedBy.Uri.Href;

            state.AppendString($"<span class=\"table-of-contents-item-inline-attached-by\">");
            state.AppendString($"(attached by <a href=\"{EscapeHtml(RelativePathHelper.GetRelativePath(state.CurrentPath, attachedByHref, "html"))}\">{EscapeHtml(attachedByName)}</a>)");
            state.AppendString($"</span>");
        }
Пример #4
0
        private async Task WriteTocByDeclaredInAsync(List <TocDeclaredInGroup> groups, RenderingState state)
        {
            state.AppendString($"<h3 id=\"section-table-of-contents\">");
            state.AppendString($"Interface of {EscapeHtml(state.Document.Entity.Titles.IndexTitle)}");
            state.AppendString($"</h3>");

            foreach (var group in groups)
            {
                var hasAdvanced  = group.Items.Any(e => e.IsAdvanced(state.Document.Entity.Id));
                var onlyAdvanced = group.Items.All(e => e.IsAdvanced(state.Document.Entity.Id));

                var cssClasses = new List <string> {
                    "table-of-contents-section"
                };
                if (hasAdvanced)
                {
                    cssClasses.Add("has-advanced-items");
                }
                if (onlyAdvanced)
                {
                    cssClasses.Add("only-advanced-items");
                }
                if (group.DeclaredIn != null && group.DeclaredIn.Uri != null && group.DeclaredIn.Uri.IdUri != state.Document.Entity.Uri.IdUri)
                {
                    cssClasses.Add("inherited");
                }
                if (group.Attached)
                {
                    cssClasses.Add("attached");
                }

                state.AppendString($"<section class=\"{string.Join(" ", cssClasses)}\">");

                if (group.DeclaredIn != null && group.DeclaredIn.Id != null && group.DeclaredIn.Id.Id != state.Document.Entity.Id.Id)
                {
                    state.AppendString($"<h4 id=\"section-table-of-contents-inherited-from-{group.DeclaredIn.Uri.Href.Replace("/", "-")}\">");
                    state.AppendString($"Inherited from");
                    state.AppendString($"<a href=\"{EscapeHtml(RelativePathHelper.GetRelativePath(state.Document.Entity.Uri.Href, group.DeclaredIn.Uri.Href, "html"))}\">");
                    state.AppendString(EscapeHtml(group.DeclaredIn.Titles.IndexTitle));
                    state.AppendString($"</a>");
                    state.AppendString($"</h4>");
                }
                else if (group.Attached)
                {
                    state.AppendString($"<h4 id=\"section-table-of-contents-attached-ux-attributes\">Attached UX Attributes</h4>");
                }

                foreach (var item in group.Items)
                {
                    var result = await _tocRenderer.RenderAsync(item, state.EntityCache, state.Document.Entity.Uri.Href, item.IsAdvanced(state.Document.Entity.Id));

                    state.MarkdownDeferredIds.AddRange(result.DeferredMarkdownIds);
                    state.AppendString(result.Html);
                    state.Quality.TableOfContentsCommentLines.Add(item.Uri.IdUri, result.NumberOfCommentLines);
                }

                state.AppendString($"</section>");
            }
        }
Пример #5
0
        private async Task WriteParametersAsync(RenderingState state)
        {
            var parameters = BuildParameterCollection(state.Document.Entity);

            if (parameters.Count == 0)
            {
                return;
            }

            state.AppendString($"<section class=\"parameters\">");
            state.AppendString($"<h3 id=\"section-parameters\">Parameters</h3>");
            state.AppendString($"<dl>");

            foreach (var param in parameters)
            {
                state.AppendString($"<dt>{EscapeHtml(param.Name)}</dt>");
                state.AppendString($"<dd>");

                if (!string.IsNullOrWhiteSpace(param.ReturnsTitle))
                {
                    state.AppendString($"<p>");

                    if (!string.IsNullOrWhiteSpace(param.ReturnsHref))
                    {
                        state.AppendString($"<a href=\"{EscapeHtml(RelativePathHelper.GetRelativePath(state.Document.Entity.Uri.Href, param.ReturnsHref, "html"))}\">");
                    }

                    state.AppendString(EscapeHtml(param.ReturnsTitle));

                    if (!string.IsNullOrWhiteSpace(param.ReturnsHref))
                    {
                        state.AppendString($"</a>");
                    }

                    state.AppendString("</p>");
                }
                else if (!string.IsNullOrWhiteSpace(param.TypeHint))
                {
                    state.AppendString($"<p>{EscapeHtml(param.TypeHint)}</p>");
                }

                if (!string.IsNullOrWhiteSpace(param.Comment))
                {
                    var result = await RenderMarkdownAsync(param.Comment);

                    state.MarkdownDeferredIds.Add(result.Id);
                    state.AppendString(result.Html);
                }

                state.AppendString($"</dd>");
            }

            state.AppendString($"</dl>");
            state.AppendString($"</section>");
        }
Пример #6
0
        private void WriteAttachedAttributeDetails(RenderingState state)
        {
            var attachedInfo = ApiRenderingHelper.GetAttachedAttributeInfo(state.Document.Entity.Id,
                                                                           state.Document.Entity.Titles,
                                                                           state.Document.Entity.Parameters,
                                                                           state.Document.Entity.Attributes,
                                                                           state.EntityCache);

            if (attachedInfo == null)
            {
                return;
            }

            state.AppendString($"<p><em>");
            state.AppendString($"Attached by <a href=\"{EscapeHtml(RelativePathHelper.GetRelativePath(state.Document.Entity.Uri.Href, attachedInfo.AttachedByHref, "html"))}\">{EscapeHtml(attachedInfo.AttachedByType)}</a>.");
            state.AppendString($"Use full name <code>{EscapeHtml(attachedInfo.FullName)}</code> in UX markup if ambiguous.");
            state.AppendString("</em></p>");
        }
Пример #7
0
        private void WriteLink(RenderingState state)
        {
            var title = ApiRenderingHelper.GetTitle(state.Id, state.Title, state.Comment, null, null, new Dictionary <string, ApiReferenceEntity>(), true);

            if (string.IsNullOrWhiteSpace(title))
            {
                throw new ArgumentException($"No title could be generated for {state.Id.Id} in {state.CurrentPath} (type {state.Id.Type})");
            }

            state.AppendString($"<h5>");
            state.AppendString($"<a href=\"{EscapeHtml(RelativePathHelper.GetRelativePath(state.CurrentPath, state.Uri.Href, "html"))}\">");
            state.AppendString(EscapeHtml(title));
            state.AppendString($"</a>");
            WriteAttachedBy(state);
            WriteReturns(state);
            WriteLanguage(state);
            state.AppendString($"</h5>");
        }
Пример #8
0
        private async Task WriteReturnsAsync(RenderingState state)
        {
            var returns = BuildReturns(state.Document.Entity);

            if (returns == null)
            {
                return;
            }

            state.AppendString($"<section class=\"returns\">");
            state.AppendString($"<h3 id=\"section-returns\">Returns</h3>");
            state.AppendString($"<p>");

            if (!string.IsNullOrWhiteSpace(returns.ReturnsTitle))
            {
                if (!string.IsNullOrWhiteSpace(returns.ReturnsHref))
                {
                    state.AppendString($"<a href=\"{EscapeHtml(RelativePathHelper.GetRelativePath(state.Document.Entity.Uri.Href, returns.ReturnsHref, "html"))}\">");
                }

                state.AppendString(EscapeHtml(returns.ReturnsTitle));

                if (!string.IsNullOrWhiteSpace(returns.ReturnsHref))
                {
                    state.AppendString($"</a>");
                }
            }
            else if (!string.IsNullOrWhiteSpace(returns.TypeHint))
            {
                state.AppendString(EscapeHtml(returns.TypeHint));
            }

            state.AppendString($"</p>");

            if (!string.IsNullOrWhiteSpace(returns.Comment))
            {
                var result = await RenderMarkdownAsync(returns.Comment);

                state.MarkdownDeferredIds.Add(result.Id);
                state.AppendString(result.Html);
            }

            state.AppendString($"</section>");
        }
Пример #9
0
        private string RewriteTypePrefixedLinks(string input, string currentPath)
        {
            var prefixes = new[] { "articles", "api" };
            var links    = _linkCollector.GetLinksFrom(input);

            foreach (var prefix in prefixes)
            {
                var linksForPrefix = links.Where(e => e.StartsWith($"{prefix}:"))
                                     .OrderByDescending(e => e.Length);
                foreach (var link in linksForPrefix)
                {
                    var path               = link.Substring(prefix.Length + 1);
                    var relativePath       = RelativePathHelper.GetRelativePath(currentPath, path, null);
                    var fragmentIdentifier = "";
                    {
                        var hashIndex = relativePath.IndexOf('#');
                        if (hashIndex >= 0)
                        {
                            fragmentIdentifier = relativePath.Substring(hashIndex);
                            relativePath       = relativePath.Substring(0, hashIndex);
                        }
                    }
                    if (relativePath.EndsWith(".md"))
                    {
                        relativePath = relativePath.Substring(0, relativePath.Length - 2) + "html";
                    }
                    else if (relativePath.EndsWith(".json"))
                    {
                        relativePath = relativePath.Substring(0, relativePath.Length - 4) + "html";
                    }
                    if (!relativePath.EndsWith(".html"))
                    {
                        relativePath += ".html";
                    }

                    input = input.Replace(link, relativePath + fragmentIdentifier);
                }
            }

            return(input);
        }
Пример #10
0
        private void WriteLocation(RenderingState state)
        {
            if (string.IsNullOrWhiteSpace(state.Document.Entity.Location?.NamespaceUri) && string.IsNullOrWhiteSpace(state.Document.Entity.Location?.PackageName))
            {
                return;
            }

            var cssClasses = new List <string> {
                "type-location"
            };

            if (state.Document.TableOfContents.Count == 0)
            {
                cssClasses.Add("type-location-leaf");
            }

            state.AppendString($"<section class=\"{string.Join(" ", cssClasses)}\">");
            state.AppendString($"<h3 id=\"section-location\">Location</h3>");
            state.AppendString($"<dl>");

            if (!string.IsNullOrWhiteSpace(state.Document.Entity.Location.NamespaceUri))
            {
                state.AppendString($"<dt>Namespace</dt>");
                state.AppendString($"<dd>");
                state.AppendString($"<a href=\"{EscapeHtml(RelativePathHelper.GetRelativePath(state.Document.Entity.Uri.Href, state.Document.Entity.Location.NamespaceUri, "html"))}\">");
                state.AppendString(EscapeHtml(state.Document.Entity.Location.NamespaceTitle));
                state.AppendString($"</a>");
                state.AppendString($"</dd>");
            }

            if (!string.IsNullOrWhiteSpace(state.Document.Entity.Location.PackageName))
            {
                state.AppendString($"<dt>Package</dt>");
                state.AppendString($"<dd>{EscapeHtml(state.Document.Entity.Location.PackageName + " " + state.Document.Entity.Location.PackageVersion)}</dd>");
            }

            state.AppendString($"</dl>");
            state.AppendString($"</section>");
        }
Пример #11
0
        private async Task WriteCommentAsync(RenderingState state)
        {
            if (string.IsNullOrWhiteSpace(state.Comment?.Brief))
            {
                return;
            }
            state.NumberOfCommentLines = CountNumberOfLines(string.IsNullOrWhiteSpace(state.Comment?.Full) ? "" : state.Comment.Full);

            var brief = state.Comment.Brief;

            if (state.Comment.Brief != state.Comment.Full)
            {
                brief += $" <a href=\"{EscapeHtml(RelativePathHelper.GetRelativePath(state.CurrentPath, state.Uri.Href, "html"))}\" class=\"table-of-contents-item-has-more\" title=\"There is more information available for this entry\"><i class=\"fa fa-ellipsis-h\"></i></a>";
            }

            state.AppendString($"<div class=\"table-of-contents-item-brief\">");
            var parsed = await _markdown.DeferredRenderAsync(brief);

            state.DeferredMarkdownIds.Add(parsed.Id);
            state.AppendString(parsed.Html);

            state.AppendString($"</div>");
        }
Пример #12
0
        public Task <string> FormatAsync(string input, string currentPath)
        {
            Match match;
            var   i = 0;

            do
            {
                i++;
                match = _lookupMatchPattern.Match(input);
                if (!match.Success)
                {
                    break;
                }

                var exactMatch = match.Groups[0].Value;
                var keyword    = exactMatch.TrimStart('@');
                var title      = keyword;

                // Hack: If the match is within a code block, replace the leading @ symbol with __CODE_BLOCK_SYMBOL_AT__ and then replace that back
                // after the run. This ensures that we don't mess with code blocks, and by replacing the @ we also make sure we don't get stuck
                // in an infinite loop here where it will just continue to match on this unhandled match every iteration.
                if (IsWithinCodeBlock(match.Index, input))
                {
                    input = input.Substring(0, match.Index) + "__CODE_BLOCK_SYMBOL_AT__" + input.Substring(match.Index + 1);
                    continue;
                }

                // Handle legacy links @(Keyword) and @(Keyword:title)
                if (keyword.StartsWith("(") && keyword.EndsWith(")"))
                {
                    keyword = keyword.TrimStart('(').TrimEnd(')');
                    title   = keyword;

                    if (title.Contains(":"))
                    {
                        keyword = keyword.Substring(0, keyword.IndexOf(":"));
                        title   = title.Substring(title.IndexOf(":") + 1);
                    }
                }

                if (!_lookups.ContainsKey(keyword))
                {
                    _failedLookups.AddOrUpdate(exactMatch, new HashSet <string>(new[] { currentPath }), (kw, e) =>
                    {
                        e.Add(currentPath);
                        return(e);
                    });
                    input = ReplaceReferenceMatch(match, input, title);
                    continue;
                }

                var uri         = _lookups[keyword];
                var replacement = $"<a href=\"{EscapeHtml(RelativePathHelper.GetRelativePath(currentPath, uri, "html"))}\">{EscapeHtml(title)}</a>";
                input = ReplaceReferenceMatch(match, input, replacement);

                // Just some stuff to test that this works since it's such a f****d up implementation
                if (i > 10000)
                {
                    throw new Exception($"Problems parsing references in {currentPath} - inifinite recursion bug: {input}");
                }
            } while (true);

            // Replace any __CODE_BLOCK_SYMBOL_AT__ values with @ to correct the content
            input = input.Replace("__CODE_BLOCK_SYMBOL_AT__", "@");

            return(Task.FromResult(input));
        }