File: JsonOutputFormatter.cs
Web Access
Project: ..\..\..\src\MSBuild\MSBuild.csproj (MSBuild)
// 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.Text.Json;
using System.Text.Json.Nodes;
using Microsoft.Build.Evaluation;
using Microsoft.Build.Execution;
using Microsoft.Build.Framework;
using Microsoft.Build.Shared;
 
namespace Microsoft.Build.CommandLine
{
    /// <summary>
    /// This class is intended to take in names of properties, items, and/or target results and some means of computing
    /// those data, then format them in a json object and provide a convenient means to stringify them.
    /// </summary>
    internal sealed class JsonOutputFormatter
    {
        private static readonly JsonSerializerOptions s_options = new() { AllowTrailingCommas = false, WriteIndented = true };
        private readonly JsonNode _topLevelNode = new JsonObject();
 
        public override string ToString()
        {
            return _topLevelNode.ToJsonString(s_options);
        }
 
        internal void AddPropertiesInJsonFormat(string[] propertyNames, Func<string, string> getProperty)
        {
            if (propertyNames.Length == 0)
            {
                return;
            }
 
            ErrorUtilities.VerifyThrow(_topLevelNode["Properties"] is null, "Should not add multiple lists of properties to the json format.");
 
            JsonNode propertiesNode = new JsonObject();
            foreach (string property in propertyNames)
            {
                propertiesNode[property] = getProperty(property);
            }
 
            _topLevelNode["Properties"] = propertiesNode;
        }
 
        internal void AddItemInstancesInJsonFormat(string[] itemNames, ProjectInstance project)
        {
            if (itemNames.Length == 0)
            {
                return;
            }
 
            ErrorUtilities.VerifyThrow(_topLevelNode["Items"] is null, "Should not add multiple lists of items to the json format.");
 
            JsonNode itemsNode = new JsonObject();
            foreach (string itemName in itemNames)
            {
                JsonArray itemArray = new();
                foreach (ProjectItemInstance item in project.GetItems(itemName))
                {
                    JsonObject jsonItem = new();
                    jsonItem["Identity"] = item.GetMetadataValue("Identity");
                    foreach (string metadatumName in item.MetadataNames)
                    {
                        if (metadatumName.Equals("Identity"))
                        {
                            continue;
                        }
 
                        jsonItem[metadatumName] = item.GetMetadataValue(metadatumName);
                    }
 
                    itemArray.Add(jsonItem);
                }
 
                itemsNode[itemName] = itemArray;
            }
 
            _topLevelNode["Items"] = itemsNode;
        }
 
        internal void AddItemsInJsonFormat(string[] itemNames, Project project)
        {
            if (itemNames.Length == 0)
            {
                return;
            }
 
            ErrorUtilities.VerifyThrow(_topLevelNode["Items"] is null, "Should not add multiple lists of items to the json format.");
 
            JsonObject itemsNode = new();
            foreach (string itemName in itemNames)
            {
                JsonArray itemArray = new();
                foreach (ProjectItem item in project.GetItems(itemName))
                {
                    JsonObject jsonItem = new();
                    jsonItem["Identity"] = item.GetMetadataValue("Identity");
                    foreach (ProjectMetadata metadatum in item.Metadata)
                    {
                        jsonItem[metadatum.Name] = metadatum.EvaluatedValue;
                    }
 
                    foreach (string metadatumName in FileUtilities.ItemSpecModifiers.All)
                    {
                        if (metadatumName.Equals("Identity"))
                        {
                            continue;
                        }
 
                        jsonItem[metadatumName] = item.GetMetadataValue(metadatumName);
                    }
 
                    itemArray.Add(jsonItem);
                }
 
                itemsNode[itemName] = itemArray;
            }
 
            _topLevelNode["Items"] = itemsNode;
        }
 
        internal void AddTargetResultsInJsonFormat(string[] targetNames, BuildResult result)
        {
            if (targetNames.Length == 0)
            {
                return;
            }
 
            ErrorUtilities.VerifyThrow(_topLevelNode["TargetResults"] is null, "Should not add multiple lists of target results to the json format.");
 
            JsonObject targetResultsNode = new();
            foreach (string targetName in targetNames)
            {
                TargetResult targetResult = result.ResultsByTarget![targetName];
                JsonObject targetResults = new();
                targetResults["Result"] = targetResult.ResultCode.ToString();
                JsonArray outputArray = new();
                foreach (ITaskItem item in targetResult.Items)
                {
                    JsonObject jsonItem = new();
                    jsonItem["Identity"] = item.GetMetadata("Identity");
                    foreach (string metadatumName in item.MetadataNames)
                    {
                        if (metadatumName.Equals("Identity"))
                        {
                            continue;
                        }
 
                        jsonItem[metadatumName] = item.GetMetadata(metadatumName);
                    }
 
                    outputArray.Add(jsonItem);
                }
 
                targetResults["Items"] = outputArray;
                targetResultsNode[targetName] = targetResults;
            }
 
            _topLevelNode["TargetResults"] = targetResultsNode;
        }
    }
}