diff --git a/modules/docs/src/Volo.Docs.Web/HtmlConverting/ScribanDocumentSectionRenderer.cs b/modules/docs/src/Volo.Docs.Web/HtmlConverting/ScribanDocumentSectionRenderer.cs index b95966ea282..e8d0149cf81 100644 --- a/modules/docs/src/Volo.Docs.Web/HtmlConverting/ScribanDocumentSectionRenderer.cs +++ b/modules/docs/src/Volo.Docs.Web/HtmlConverting/ScribanDocumentSectionRenderer.cs @@ -13,8 +13,11 @@ namespace Volo.Docs.HtmlConverting { public class ScribanDocumentSectionRenderer : IDocumentSectionRenderer { - private const string JsonOpener = "````json"; - private const string JsonCloser = "````"; + private readonly static List DocsJsonSections = new List + { + new DocsJsonSection("````json", "````"), + new DocsJsonSection("```json", "```") + }; private const string DocsParam = "//[doc-params]"; private const string DocsTemplates = "//[doc-template]"; private const string DocsNav = "//[doc-nav]"; @@ -59,12 +62,12 @@ public Task GetDocumentNavigationsAsync(string documentC { try { - if (!document.Contains(JsonOpener) || !document.Contains(sectionName)) + if (!HasJsonSection(document) || !document.Contains(sectionName)) { return new T(); } - var (jsonBeginningIndex, jsonEndingIndex, insideJsonSection) = GetJsonBeginEndIndexesAndPureJson(document, sectionName); + var (jsonBeginningIndex, jsonEndingIndex, insideJsonSection, _) = GetJsonBeginEndIndexesAndPureJson(document, sectionName); if (jsonBeginningIndex < 0 || jsonEndingIndex <= 0 || string.IsNullOrWhiteSpace(insideJsonSection)) { @@ -96,12 +99,12 @@ private static string RemoveOptionsJson(string document, params string[] section try { - if (!document.Contains(JsonOpener) || !document.Contains(sectionName)) + if (!HasJsonSection(document) || !document.Contains(sectionName)) { continue; } - var (jsonBeginningIndex, jsonEndingIndex, insideJsonSection) = GetJsonBeginEndIndexesAndPureJson(document, sectionName); + var (jsonBeginningIndex, jsonEndingIndex, insideJsonSection, jsonSection) = GetJsonBeginEndIndexesAndPureJson(document, sectionName); if (jsonBeginningIndex < 0 || jsonEndingIndex <= 0 || string.IsNullOrWhiteSpace(insideJsonSection)) { @@ -109,8 +112,8 @@ private static string RemoveOptionsJson(string document, params string[] section } document = document.Remove( - jsonBeginningIndex - JsonOpener.Length, - (jsonEndingIndex + JsonCloser.Length) - (jsonBeginningIndex - JsonOpener.Length) + jsonBeginningIndex - jsonSection.Opener.Length, + (jsonEndingIndex + jsonSection.Closer.Length) - (jsonBeginningIndex - jsonSection.Opener.Length) ); } catch (Exception) @@ -121,122 +124,193 @@ private static string RemoveOptionsJson(string document, params string[] section return document; } - - private static (int, int, string) GetJsonBeginEndIndexesAndPureJson(string document, string sectionName) + + private static bool HasJsonSection(string document) { - var searchedIndex = 0; + return DocsJsonSections.Any(section => document.Contains(section.Opener) && document.Contains(section.Closer)); + } - while (searchedIndex < document.Length) + private static (int, int, string, DocsJsonSection) GetJsonBeginEndIndexesAndPureJson(string document, string sectionName) + { + foreach (var section in DocsJsonSections) { - var jsonBeginningIndex = document.Substring(searchedIndex).IndexOf(JsonOpener, StringComparison.Ordinal) + JsonOpener.Length + searchedIndex; - - if (jsonBeginningIndex < 0) - { - return (-1, -1, ""); - } - - var jsonEndingIndex = document.Substring(jsonBeginningIndex).IndexOf(JsonCloser, StringComparison.Ordinal) + jsonBeginningIndex; - var insideJsonSection = document[jsonBeginningIndex..jsonEndingIndex]; + var (jsonBeginningIndex, jsonEndingIndex, insideJsonSection) = section.GetJsonBeginEndIndexesAndPureJson(document, sectionName); - if (insideJsonSection.IndexOf(sectionName, StringComparison.Ordinal) < 0) + if (jsonBeginningIndex >= 0 && jsonEndingIndex > 0 && !string.IsNullOrWhiteSpace(insideJsonSection)) { - searchedIndex = jsonEndingIndex + JsonCloser.Length; - continue; + return (jsonBeginningIndex, jsonEndingIndex, insideJsonSection, section); } - - return (jsonBeginningIndex, jsonEndingIndex, insideJsonSection); } - return (-1, -1, ""); + return (-1, -1, "", null); } public async Task> GetPartialTemplatesInDocumentAsync(string documentContent) { var templates = new List(); - while (documentContent.Contains(JsonOpener)) + foreach (var section in DocsJsonSections) { - var afterJsonOpener = documentContent.Substring( - documentContent.IndexOf(JsonOpener, StringComparison.Ordinal) + JsonOpener.Length - ); + templates.AddRange(await section.GetPartialTemplatesInDocumentAsync(documentContent)); + } - var betweenJsonOpenerAndCloser = afterJsonOpener.Substring(0, - afterJsonOpener.IndexOf(JsonCloser, StringComparison.Ordinal) - ); + return templates; + } + + private static string SetPartialTemplates(string document, IReadOnlyCollection templates) + { + foreach (var section in DocsJsonSections) + { + document = section.SetPartialTemplates(document, templates); + } + + return document; + } + + private class DocsJsonSection + { + public string Opener { get; } + public string Closer { get; } + + public DocsJsonSection(string opener, string closer) + { + Opener = opener; + Closer = closer; + } - documentContent = afterJsonOpener.Substring( - afterJsonOpener.IndexOf(JsonCloser, StringComparison.Ordinal) + JsonCloser.Length - ); + public (int, int, string) GetJsonBeginEndIndexesAndPureJson(string document, string sectionName) + { + var searchedIndex = 0; - if (!betweenJsonOpenerAndCloser.Contains(DocsTemplates)) + while (searchedIndex < document.Length) { - continue; - } + var jsonBeginningIndex = document.Substring(searchedIndex).IndexOf(Opener, StringComparison.Ordinal); - var json = betweenJsonOpenerAndCloser.Substring(betweenJsonOpenerAndCloser.IndexOf(DocsTemplates, StringComparison.Ordinal) + DocsTemplates.Length); + if (jsonBeginningIndex < 0) + { + return (-1, -1, ""); + } + + jsonBeginningIndex += Opener.Length + searchedIndex; - if (!DocsJsonSerializerHelper.TryDeserialize(json, out var template)) - { - throw new UserFriendlyException($"ERROR-20200327: Cannot validate JSON content for `AvailableParameters`!"); - } + var jsonEndingIndex = document.Substring(jsonBeginningIndex).IndexOf(Closer, StringComparison.Ordinal); + if (jsonEndingIndex < 0) + { + return (-1, -1, ""); + } + + jsonEndingIndex += jsonBeginningIndex; + var insideJsonSection = document[jsonBeginningIndex..jsonEndingIndex]; - templates.Add(template); - } + if (insideJsonSection.IndexOf(sectionName, StringComparison.Ordinal) < 0) + { + searchedIndex = jsonEndingIndex + Closer.Length; + continue; + } - return await Task.FromResult(templates); - } + return (jsonBeginningIndex, jsonEndingIndex, insideJsonSection); + } - private static string SetPartialTemplates(string document, IReadOnlyCollection templates) - { - var newDocument = new StringBuilder(); + return (-1, -1, ""); + } - while (document.Contains(JsonOpener)) + public async Task> GetPartialTemplatesInDocumentAsync( + string documentContent) { - var beforeJson = document.Substring(0, - document.IndexOf(JsonOpener, StringComparison.Ordinal) + JsonOpener.Length - ); + var templates = new List(); - var afterJsonOpener = document.Substring( - document.IndexOf(JsonOpener, StringComparison.Ordinal) + JsonOpener.Length - ); + while (documentContent.Contains(Opener)) + { + var afterJsonOpener = documentContent.Substring( + documentContent.IndexOf(Opener, StringComparison.Ordinal) + Opener.Length + ); - var betweenJsonOpenerAndCloser = afterJsonOpener.Substring(0, - afterJsonOpener.IndexOf(JsonCloser, StringComparison.Ordinal) - ); + var betweenJsonOpenerAndCloser = afterJsonOpener.Substring(0, + afterJsonOpener.IndexOf(Closer, StringComparison.Ordinal) + ); - if (!betweenJsonOpenerAndCloser.Contains(DocsTemplates)) - { - document = afterJsonOpener.Substring( - afterJsonOpener.IndexOf(JsonCloser, StringComparison.Ordinal) + JsonCloser.Length + documentContent = afterJsonOpener.Substring( + afterJsonOpener.IndexOf(Closer, StringComparison.Ordinal) + Closer.Length ); - newDocument.Append(beforeJson + betweenJsonOpenerAndCloser + JsonCloser); - continue; + if (!betweenJsonOpenerAndCloser.Contains(DocsTemplates)) + { + continue; + } + + var json = betweenJsonOpenerAndCloser.Substring( + betweenJsonOpenerAndCloser.IndexOf(DocsTemplates, StringComparison.Ordinal) + + DocsTemplates.Length); + + if (!DocsJsonSerializerHelper.TryDeserialize(json, + out var template)) + { + throw new UserFriendlyException( + $"ERROR-20200327: Cannot validate JSON content for `AvailableParameters`!"); + } + + templates.Add(template); } - var json = betweenJsonOpenerAndCloser.Substring( - betweenJsonOpenerAndCloser.IndexOf(DocsTemplates, StringComparison.Ordinal) + DocsTemplates.Length - ); + return await Task.FromResult(templates); + } + + public string SetPartialTemplates(string document, + IReadOnlyCollection templates) + { + var newDocument = new StringBuilder(); - if (DocsJsonSerializerHelper.TryDeserialize(json, out var documentPartialTemplateWithValuesDto)) + while (document.Contains(Opener)) { - var template = templates.FirstOrDefault(t => t.Path == documentPartialTemplateWithValuesDto.Path); + var beforeJson = document.Substring(0, + document.IndexOf(Opener, StringComparison.Ordinal) + Opener.Length + ); - var beforeTemplate = document.Substring(0, - document.IndexOf(JsonOpener, StringComparison.Ordinal) + var afterJsonOpener = document.Substring( + document.IndexOf(Opener, StringComparison.Ordinal) + Opener.Length ); - newDocument.Append(beforeTemplate + template?.Content + JsonCloser); + var betweenJsonOpenerAndCloser = afterJsonOpener.Substring(0, + afterJsonOpener.IndexOf(Closer, StringComparison.Ordinal) + ); + + if (!betweenJsonOpenerAndCloser.Contains(DocsTemplates)) + { + document = afterJsonOpener.Substring( + afterJsonOpener.IndexOf(Closer, StringComparison.Ordinal) + Closer.Length + ); + + newDocument.Append(beforeJson + betweenJsonOpenerAndCloser + Closer); + continue; + } - document = afterJsonOpener.Substring( - afterJsonOpener.IndexOf(JsonCloser, StringComparison.Ordinal) + JsonCloser.Length + var json = betweenJsonOpenerAndCloser.Substring( + betweenJsonOpenerAndCloser.IndexOf(DocsTemplates, StringComparison.Ordinal) + + DocsTemplates.Length ); + + if (DocsJsonSerializerHelper.TryDeserialize(json, + out var documentPartialTemplateWithValuesDto)) + { + var template = + templates.FirstOrDefault(t => t.Path == documentPartialTemplateWithValuesDto.Path); + + var beforeTemplate = document.Substring(0, + document.IndexOf(Opener, StringComparison.Ordinal) + ); + + newDocument.Append(beforeTemplate + template?.Content + Closer); + + document = afterJsonOpener.Substring( + afterJsonOpener.IndexOf(Closer, StringComparison.Ordinal) + Closer.Length + ); + } } - } - newDocument.Append(document); + newDocument.Append(document); - return newDocument.ToString(); + return newDocument.ToString(); + } } } }