File: ItemGroupParser.cs
Web Access
Project: ..\..\..\src\Samples\XmlFileLogger\XmlFileLogger.csproj (XmlFileLogger)
// 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;
 
#nullable disable
 
namespace Microsoft.Build.Logging.StructuredLogger
{
    internal static class ItemGroupParser
    {
        /// <summary>
        /// Parses a log output string to a list of Items (e.g. ItemGroup with metadata or property string).
        /// </summary>
        /// <param name="message">The message output from the logger.</param>
        /// <param name="prefix">The prefix parsed out (e.g. 'Output Item(s): '.).</param>
        /// <param name="name">Out: The name of the list.</param>
        /// <returns>List of items within the list and all metadata.</returns>
        public static IList<Item> ParseItemList(string message, string prefix, out string name)
        {
            name = null;
 
            var items = new List<Item>();
            var lines = message.Split('\n');
 
            if (lines.Length == 1)
            {
                var line = lines[0];
                line = line.Substring(prefix.Length);
                var nameValue = ParseNameValue(line);
                name = nameValue.Key;
                items.Add(new Item(nameValue.Value));
                return items;
            }
 
            if (lines[0].Length > prefix.Length)
            {
                // we have a weird case of multi-line value
                var nameValue = ParseNameValue(lines[0].Substring(prefix.Length));
                name = nameValue.Key;
 
                items.Add(new Item(nameValue.Value.Replace("\r", "")));
                for (int i = 1; i < lines.Length; i++)
                {
                    items.Add(new Item(lines[i].Replace("\r", "")));
                }
 
                return items;
            }
 
            Item currentItem = null;
            foreach (var line in lines)
            {
                switch (GetNumberOfLeadingSpaces(line))
                {
                    case 4:
                        if (line.EndsWith("=", StringComparison.Ordinal))
                        {
                            name = line.Substring(4, line.Length - 5);
                        }
                        break;
                    case 8:
                        currentItem = new Item(line.Substring(8));
                        items.Add(currentItem);
                        break;
                    case 16:
                        if (currentItem != null)
                        {
                            var nameValue = ParseNameValue(line.Substring(16));
                            currentItem.AddMetadata(nameValue.Key, nameValue.Value);
                        }
                        break;
                }
            }
 
            return items;
        }
 
        /// <summary>
        /// Parse a string for a name value pair (name=value).
        /// </summary>
        /// <param name="nameEqualsValue">The (name = value) string to parse.</param>
        /// <returns>KeyValuePair name and value</returns>
        private static KeyValuePair<string, string> ParseNameValue(string nameEqualsValue)
        {
            var equals = nameEqualsValue.IndexOf('=');
            var name = nameEqualsValue.Substring(0, equals);
            var value = nameEqualsValue.Substring(equals + 1);
            return new KeyValuePair<string, string>(name, value);
        }
 
        /// <summary>
        /// Gets the number of leading spaces from a string
        /// </summary>
        /// <param name="line">The string.</param>
        /// <returns>Number of spaces in the beginning of the string.</returns>
        private static int GetNumberOfLeadingSpaces(string line)
        {
            int result = 0;
            while (result < line.Length && line[result] == ' ')
            {
                result++;
            }
 
            return result;
        }
    }
}