| File: ListPackage\ListPackageJsonRenderer.cs | Web Access |
| Project: src\nuget-client\src\NuGet.Core\NuGet.CommandLine.XPlat\NuGet.CommandLine.XPlat.csproj (NuGet.CommandLine.XPlat) |
// Copyright (c) .NET Foundation. All rights reserved. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. #nullable disable using System; using System.Collections.Generic; using System.IO; using System.Linq; using Newtonsoft.Json; using NuGet.Common; using NuGet.Configuration; using NuGet.Protocol; using NuGet.Versioning; namespace NuGet.CommandLine.XPlat.ListPackage { /// <summary> /// json format renderer for dotnet list package command /// </summary> internal class ListPackageJsonRenderer : IReportRenderer { private const int ReportOutputVersion = 1; private const string VersionProperty = "version"; private const string ParametersProperty = "parameters"; private const string ProblemsProperty = "problems"; private const string SourcesProperty = "sources"; private const string ProjectProperty = "project"; private const string ProjectsProperty = "projects"; private const string FrameworksProperty = "frameworks"; private const string FrameworkProperty = "framework"; private const string PathProperty = "path"; private const string TopLevelPackagesProperty = "topLevelPackages"; private const string TransitivePackagesProperty = "transitivePackages"; private const string IdProperty = "id"; private const string RequestedVersionProperty = "requestedVersion"; private const string ResolvedVersionProperty = "resolvedVersion"; private const string AutoReferencedProperty = "autoReferenced"; private const string SeverityProperty = "severity"; private const string AdvisoryUrlProperty = "advisoryurl"; private const string VulnerabilitiesProperty = "vulnerabilities"; private const string LatestVersionProperty = "latestVersion"; private const string DeprecationReasonsProperty = "deprecationReasons"; private const string AlternativePackageProperty = "alternativePackage"; private const string VersionRangeProperty = "versionRange"; private const string LevelProperty = "level"; private const string WarningProperty = "warning"; private const string TextProperty = "text"; private const string ErrorProperty = "error"; protected readonly List<ReportProblem> _problems = new(); protected TextWriter _writer; public ListPackageJsonRenderer(TextWriter textWriter = null) { _writer = textWriter ?? Console.Out; } public void AddProblem(ProblemType problemType, string text) { _problems.Add(new ReportProblem(problemType, string.Empty, text)); } public IEnumerable<ReportProblem> GetProblems() { return _problems; } public void Render(ListPackageReportModel listPackageReportModel) { // Aggregate problems from projects. _problems.AddRange(listPackageReportModel.Projects.Where(p => p.ProjectProblems != null).SelectMany(p => p.ProjectProblems)); var jsonRenderedOutput = WriteJson(listPackageReportModel); _writer.WriteLine(jsonRenderedOutput); } internal string WriteJson(ListPackageReportModel listPackageReportModel) { using (var writer = new StringWriter()) { using (var jsonWriter = new JsonTextWriter(writer)) { jsonWriter.Formatting = Formatting.Indented; WriteJson(jsonWriter, listPackageReportModel); } return writer.ToString(); } } private void WriteJson(JsonWriter writer, ListPackageReportModel listPackageReportModel) { ListPackageArgs listPackageArgs = listPackageReportModel.ListPackageArgs; writer.WriteStartObject(); writer.WritePropertyName(VersionProperty); writer.WriteValue(ReportOutputVersion); writer.WritePropertyName(ParametersProperty); writer.WriteValue(PathUtility.GetPathWithForwardSlashes(listPackageArgs.ArgumentText)); if (_problems?.Count > 0) { WriteProblems(writer, _problems); } WriteSources(writer, listPackageReportModel); WriteProjects(writer, listPackageReportModel.Projects, listPackageReportModel.ListPackageArgs); writer.WriteEndObject(); } private static void WriteProblems(JsonWriter writer, IEnumerable<ReportProblem> reportProblems) { writer.WritePropertyName(ProblemsProperty); writer.WriteStartArray(); foreach (ReportProblem reportProblem in reportProblems) { writer.WriteStartObject(); if (!string.IsNullOrEmpty(reportProblem.Project)) { writer.WritePropertyName(ProjectProperty); writer.WriteValue(PathUtility.GetPathWithForwardSlashes(reportProblem.Project)); } writer.WritePropertyName(LevelProperty); writer.WriteValue(reportProblem.ProblemType == ProblemType.Error ? ErrorProperty : WarningProperty); writer.WritePropertyName(TextProperty); writer.WriteValue(PathUtility.GetPathWithForwardSlashes(reportProblem.Text)); writer.WriteEndObject(); } writer.WriteEndArray(); } private static void WriteSources(JsonWriter writer, ListPackageReportModel listPackageReportModel) { if (listPackageReportModel.ListPackageArgs.ReportType == ReportType.Default) { // generic list is offline. return; } writer.WritePropertyName(SourcesProperty); writer.WriteStartArray(); if (listPackageReportModel.ListPackageArgs.ReportType == ReportType.Vulnerable && listPackageReportModel.AuditSourcesUsed.Count > 0) { foreach (PackageSource packageSource in listPackageReportModel.AuditSourcesUsed) { writer.WriteValue(PathUtility.GetPathWithForwardSlashes(packageSource.Source)); } } else { foreach (PackageSource packageSource in listPackageReportModel.ListPackageArgs.PackageSources) { writer.WriteValue(PathUtility.GetPathWithForwardSlashes(packageSource.Source)); } } writer.WriteEndArray(); } private static void WriteProjects(JsonWriter writer, List<ListPackageProjectModel> reportProjects, ListPackageArgs listPackageArgs) { writer.WritePropertyName(ProjectsProperty); writer.WriteStartArray(); foreach (ListPackageProjectModel reportProject in reportProjects) { writer.WriteStartObject(); writer.WritePropertyName(PathProperty); writer.WriteValue(PathUtility.GetPathWithForwardSlashes(reportProject.ProjectPath)); if (reportProject.TargetFrameworkPackages?.Count > 0) { writer.WritePropertyName(FrameworksProperty); WriteFrameworkPackage(writer, reportProject.TargetFrameworkPackages, listPackageArgs); } writer.WriteEndObject(); } writer.WriteEndArray(); } private static void WriteFrameworkPackage(JsonWriter writer, List<ListPackageReportFrameworkPackage> reportFrameworkPackages, ListPackageArgs listPackageArgs) { writer.WriteStartArray(); foreach (ListPackageReportFrameworkPackage reportFrameworkPackage in reportFrameworkPackages) { writer.WriteStartObject(); writer.WritePropertyName(FrameworkProperty); writer.WriteValue(reportFrameworkPackage.TargetAlias); WriteTopLevelPackages(writer, TopLevelPackagesProperty, reportFrameworkPackage.TopLevelPackages, listPackageArgs); WriteTransitivePackages(writer, TransitivePackagesProperty, reportFrameworkPackage.TransitivePackages, listPackageArgs); writer.WriteEndObject(); } writer.WriteEndArray(); } private static void WriteTopLevelPackages(JsonWriter writer, string property, List<ListReportPackage> topLevelPackages, ListPackageArgs listPackageArgs) { if (topLevelPackages != null) { writer.WritePropertyName(property); writer.WriteStartArray(); foreach (ListReportPackage topLevelPackage in topLevelPackages) { writer.WriteStartObject(); writer.WritePropertyName(IdProperty); writer.WriteValue(topLevelPackage.PackageId); writer.WritePropertyName(RequestedVersionProperty); writer.WriteValue(topLevelPackage.RequestedVersion); writer.WritePropertyName(ResolvedVersionProperty); writer.WriteValue(topLevelPackage.ResolvedVersion); if (topLevelPackage.AutoReference) { writer.WritePropertyName(AutoReferencedProperty); writer.WriteValue("true"); } switch (listPackageArgs.ReportType) { case ReportType.Outdated: writer.WritePropertyName(LatestVersionProperty); writer.WriteValue(topLevelPackage.LatestVersion); break; case ReportType.Deprecated: WriteDeprecations(writer, topLevelPackage); break; case ReportType.Vulnerable: WriteVulnerabilities(writer, topLevelPackage.Vulnerabilities); break; default: break; } writer.WriteEndObject(); } writer.WriteEndArray(); } } private static void WriteTransitivePackages(JsonWriter writer, string property, List<ListReportPackage> transitivePackages, ListPackageArgs listPackageArgs) { if (!listPackageArgs.IncludeTransitive) { return; } if (transitivePackages?.Count > 0) { writer.WritePropertyName(property); writer.WriteStartArray(); foreach (ListReportPackage transitivePackage in transitivePackages) { writer.WriteStartObject(); writer.WritePropertyName(IdProperty); writer.WriteValue(transitivePackage.PackageId); writer.WritePropertyName(ResolvedVersionProperty); writer.WriteValue(transitivePackage.ResolvedVersion); switch (listPackageArgs.ReportType) { case ReportType.Outdated: writer.WritePropertyName(LatestVersionProperty); writer.WriteValue(transitivePackage.LatestVersion); break; case ReportType.Deprecated: WriteDeprecations(writer, transitivePackage); break; case ReportType.Vulnerable: WriteVulnerabilities(writer, transitivePackage.Vulnerabilities); break; default: break; } writer.WriteEndObject(); } writer.WriteEndArray(); } } private static void WriteDeprecations(JsonWriter writer, ListReportPackage listPackage) { if (listPackage.DeprecationReasons != null) { writer.WritePropertyName(DeprecationReasonsProperty); writer.WriteStartArray(); foreach (var deprecationReason in listPackage.DeprecationReasons?.Reasons) { writer.WriteValue(deprecationReason); } writer.WriteEndArray(); } if (listPackage.AlternativePackage != null) { writer.WritePropertyName(AlternativePackageProperty); writer.WriteStartObject(); writer.WritePropertyName(IdProperty); writer.WriteValue(listPackage.AlternativePackage.PackageId); writer.WritePropertyName(VersionRangeProperty); var versionRangeString = VersionRangeFormatter.Instance.Format( "p", listPackage.AlternativePackage.Range, VersionRangeFormatter.Instance); writer.WriteValue(versionRangeString); writer.WriteEndObject(); } } private static void WriteVulnerabilities(JsonWriter writer, List<PackageVulnerabilityMetadata> vulnerabilities) { if (vulnerabilities == null) { return; } writer.WritePropertyName(VulnerabilitiesProperty); writer.WriteStartArray(); foreach (PackageVulnerabilityMetadata vulnerability in vulnerabilities) { writer.WriteStartObject(); var severity = (vulnerability?.Severity ?? -1) switch { 0 => "Low", 1 => "Moderate", 2 => "High", 3 => "Critical", _ => string.Empty, }; writer.WritePropertyName(SeverityProperty); writer.WriteValue(severity); writer.WritePropertyName(AdvisoryUrlProperty); writer.WriteValue(vulnerability.AdvisoryUrl); writer.WriteEndObject(); } writer.WriteEndArray(); } } }