| File: src\Generators\Microsoft.Gen.ComplianceReports\Emitter.cs | Web Access |
| Project: src\src\Generators\Microsoft.Gen.MetadataExtractor\Microsoft.Gen.MetadataExtractor.csproj (Microsoft.Gen.MetadataExtractor) |
// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. using System; using System.Collections.Generic; using System.Diagnostics.CodeAnalysis; using System.Globalization; using System.Linq; using Microsoft.Gen.Shared; namespace Microsoft.Gen.ComplianceReports; internal sealed class Emitter : EmitterBase { private readonly Stack<int> _itemCounts = new(); private int _itemCount; public Emitter() : base(false) { } [SuppressMessage("Performance", "LA0002:Use 'Microsoft.Extensions.Text.NumericExtensions.ToInvariantString' for improved performance", Justification = "Can't use that in a generator")] public string Emit(IReadOnlyCollection<ClassifiedType> classifiedTypes, string assemblyName, bool includeName = true) // show or hide assemblyName in the report,defaulted to true. { OutObject(() => { // this is only for not displaying a name as part of ComplianceReport properties,it should be at the root of the report, defaulted to true for beackward compatibility if (includeName) { OutNameValue("Name", assemblyName); } OutArray("Types", () => { foreach (var classifiedType in classifiedTypes.OrderBy(ct => ct.TypeName, StringComparer.Ordinal)) { OutObject(() => { OutNameValue("Name", classifiedType.TypeName); if (classifiedType.Members != null) { OutArray("Members", () => { foreach (var member in classifiedType.Members.OrderBy(m => m.Name, StringComparer.Ordinal)) { OutObject(() => { OutNameValue("Name", member.Name); OutNameValue("Type", member.TypeName); OutNameValue("File", member.SourceFilePath); OutNameValue("Line", member.SourceLine.ToString(CultureInfo.InvariantCulture)); if (member.Classifications.Count > 0) { OutArray("Classifications", () => { foreach (var c in member.Classifications.OrderBy(c => c.Name, StringComparer.Ordinal)) { OutObject(() => { OutNameValue("Name", c.Name); if (!string.IsNullOrEmpty(c.Notes)) { OutNameValue("Notes", c.Notes!); } }); } }); } }); } }); } if (classifiedType.LogMethods != null) { OutArray("Logging Methods", () => { foreach (var method in classifiedType.LogMethods.OrderBy(m => m.MethodName, StringComparer.Ordinal)) { OutObject(() => { OutNameValue("Name", method.MethodName); OutArray("Parameters", () => { foreach (var p in method.Parameters) { OutObject(() => { OutNameValue("Name", p.Name); OutNameValue("Type", p.TypeName); OutNameValue("File", p.SourceFilePath); OutNameValue("Line", p.SourceLine.ToString(CultureInfo.InvariantCulture)); if (p.Classifications.Count > 0) { OutArray("Classifications", () => { foreach (var c in p.Classifications.OrderBy(c => c.Name, StringComparer.Ordinal)) { OutObject(() => { OutNameValue("Name", c.Name); if (!string.IsNullOrEmpty(c.Notes)) { OutNameValue("Notes", c.Notes!); } }); } }); } }); } }); }); } }); } }); } }); }); return Capture(); } private void NewItem() { if (_itemCount > 0) { Out(","); } OutLn(); _itemCount++; } private void OutObject(Action action) { NewItem(); _itemCounts.Push(_itemCount); _itemCount = 0; OutIndent(); Out("{"); Indent(); action(); OutLn(); Unindent(); OutIndent(); Out("}"); _itemCount = _itemCounts.Pop(); } private void OutArray(string name, Action action) { NewItem(); _itemCounts.Push(_itemCount); _itemCount = 0; OutIndent(); Out($"\"{name}\": ["); Indent(); action(); OutLn(); Unindent(); OutIndent(); Out("]"); _itemCount = _itemCounts.Pop(); } private void OutNameValue(string name, string value) { value = value .Replace("\\", "\\\\") .Replace("\"", "\\\""); NewItem(); OutIndent(); Out($"\"{name}\": \"{value}\""); } }