tools/apiview/parsers/swagger-api-parser/SwaggerApiParser/SwaggerApiView/CodeFile.cs (96 lines of code) (raw):

using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Text.Json; using System.Threading.Tasks; namespace SwaggerApiParser.SwaggerApiView { public class CodeFile { private static readonly JsonSerializerOptions JsonSerializerOptions = new JsonSerializerOptions() { AllowTrailingCommas = true, ReadCommentHandling = JsonCommentHandling.Skip }; private static HashSet<string> _collapsibleLanguages = new HashSet<string>(new string[] { "Swagger" }); public string VersionString { get; set; } public string Name { get; set; } public string Language { get; set; } public string LanguageVariant { get; set; } public string PackageName { get; set; } public string ServiceName { get; set; } public string PackageDisplayName { get; set; } public string PackageVersion { get; set; } public CodeFileToken[] Tokens { get; set; } = Array.Empty<CodeFileToken>(); public List<CodeFileToken[]> LeafSections { get; set; } public NavigationItem[] Navigation { get; set; } public static bool IsCollapsibleSectionSSupported(string language) => _collapsibleLanguages.Contains(language); public static async Task<CodeFile> DeserializeAsync(Stream stream, bool hasSections = false) { var codeFile = await JsonSerializer.DeserializeAsync<CodeFile>( stream, JsonSerializerOptions); if (hasSections == false && codeFile.LeafSections == null && IsCollapsibleSectionSSupported(codeFile.Language)) hasSections = true; // Spliting out the 'leafSections' of the codeFile is done so as not to have to render large codeFiles at once // Rendering sections in part helps to improve page load time if (hasSections) { var index = 0; var tokens = codeFile.Tokens; var newTokens = new List<CodeFileToken>(); var leafSections = new List<CodeFileToken[]>(); var section = new List<CodeFileToken>(); var isLeaf = false; var numberOfLinesinLeafSection = 0; while (index < tokens.Length) { var token = tokens[index]; if (token.Kind == CodeFileTokenKind.FoldableSectionHeading) { section.Add(token); isLeaf = false; } else if (token.Kind == CodeFileTokenKind.FoldableSectionContentStart) { section.Add(token); newTokens.AddRange(section); section.Clear(); isLeaf = true; numberOfLinesinLeafSection = 0; } else if (token.Kind == CodeFileTokenKind.FoldableSectionContentEnd) { if (isLeaf) { leafSections.Add(section.ToArray()); section.Clear(); isLeaf = false; // leafSectionPlaceholder will be used to identify the appriopriate index and number of lines in the leafSections // numberOfLinesinLeafSection help keep line numbering consistent with the main 'non-leaf' sections var leafSectionPlaceholder = new CodeFileToken( $"{(leafSections.Count() - 1)}", CodeFileTokenKind.LeafSectionPlaceholder, numberOfLinesinLeafSection); var newLineToken = new CodeFileToken("", CodeFileTokenKind.Newline); section.Add(leafSectionPlaceholder); section.Add(newLineToken); } section.Add(token); } else { if (isLeaf && token.Kind == CodeFileTokenKind.Newline) { numberOfLinesinLeafSection++; } section.Add(token); } index++; } newTokens.AddRange(section); codeFile.Tokens = newTokens.ToArray(); codeFile.LeafSections = leafSections; } return codeFile; } public async Task SerializeAsync(Stream stream) { await JsonSerializer.SerializeAsync( stream, this, JsonSerializerOptions); } } }