public static BaseNode ParsePropertyOrItemList()

in src/StructuredLogger/Construction/ItemGroupParser.cs [17:195]


        public static BaseNode ParsePropertyOrItemList(string message, string prefix, StringCache stringTable, bool isOutputItem = false)
        {
            if (!TextUtilities.ContainsLineBreak(message))
            {
                var nameValue = TextUtilities.ParseNameValue(message, trimFromStart: prefix.Length);
                if (!isOutputItem)
                {
                    var property = new Property
                    {
                        Name = stringTable.Intern(nameValue.Key),
                        Value = stringTable.Intern(nameValue.Value)
                    };
                    return property;
                }
                else
                {
                    var singleItem = new AddItem { Name = stringTable.Intern(nameValue.Key) };
                    var item = new Item { Text = stringTable.Intern(nameValue.Value) };
                    singleItem.AddChild(item);
                    return singleItem;
                }
            }

            // Can't use a field initializer with ThreadStatic.
            if (lineSpans == null)
            {
                lineSpans = new List<Span>(10240);
            }

            lineSpans.Clear();
            message.CollectLineSpans(lineSpans, includeLineBreakInSpan: false);

            NamedNode parameter = isOutputItem ? new AddItem() : new Parameter();

            if (lineSpans[0].Length > prefix.Length)
            {
                // we have a weird case of multi-line value
                var nameValue = TextUtilities.ParseNameValue(message, lineSpans[0].Skip(prefix.Length));

                parameter.Name = stringTable.Intern(nameValue.Key);

                parameter.AddChild(new Item
                {
                    Text = stringTable.Intern(nameValue.Value)
                });

                for (int i = 1; i < lineSpans.Count; i++)
                {
                    parameter.AddChild(new Item
                    {
                        Text = stringTable.Intern(message.Substring(lineSpans[i]))
                    });
                }

                return parameter;
            }

            Item currentItem = null;
            Property currentProperty = null;
            foreach (var lineSpan in lineSpans)
            {
                if (TextUtilities.IsWhitespace(message, lineSpan))
                {
                    continue;
                }

                var numberOfLeadingSpaces = TextUtilities.GetNumberOfLeadingSpaces(message, lineSpan);
                switch (numberOfLeadingSpaces)
                {
                    case 4:
                        if (message[lineSpan.End - 1] == '=')
                        {
                            parameter.Name = stringTable.Intern(message.Substring(lineSpan.Start + 4, lineSpan.Length - 5));
                        }
                        break;
                    case 8:
                        var skip8 = message.Substring(lineSpan.Skip(8));
                        var equals = skip8.IndexOf('=');
                        if (equals != -1)
                        {
                            var kvp = TextUtilities.ParseNameValueWithEqualsPosition(skip8, equals);
                            currentProperty = new Property
                            {
                                Name = stringTable.Intern(kvp.Key),
                                Value = stringTable.Intern(kvp.Value)
                            };
                            parameter.AddChild(currentProperty);
                            currentItem = null;
                        }
                        else
                        {
                            currentItem = new Item
                            {
                                Text = stringTable.Intern(skip8)
                            };
                            parameter.AddChild(currentItem);
                            currentProperty = null;
                        }
                        break;
                    case 16:
                        if (currentItem == null && currentProperty != null)
                        {
                            // we incorrectly interpreted the previous line as Property, not Item (because it had '=')
                            // and so we created a property out of name/value.
                            // Fix this by turning it into an Item.
                            if (parameter.LastChild == currentProperty)
                            {
                                currentItem = new Item
                                {
                                    Text = stringTable.Intern(currentProperty.Name + "=" + currentProperty.Value)
                                };
                                parameter.Children.RemoveAt(parameter.Children.Count - 1);
                                currentProperty = null;
                                parameter.AddChild(currentItem);
                            }
                        }

                        if (currentItem != null)
                        {
                            var span16 = lineSpan.Skip(16);
                            var equals16 = message.IndexOf(span16, '=');
                            if (equals16 == -1)
                            {
                                // must be a continuation of the metadata value from the previous line
                                if (currentItem.HasChildren)
                                {
                                    var metadata = currentItem.Children[currentItem.Children.Count - 1] as Metadata;
                                    if (metadata != null)
                                    {
                                        var currentLine = message.Substring(span16);
                                        if (!string.IsNullOrEmpty(metadata.Value))
                                        {
                                            metadata.Value = metadata.Value + currentLine;
                                        }
                                        else
                                        {
                                            metadata.Value = currentLine;
                                        }
                                    }
                                }
                            }
                            else
                            {
                                var nameValue = TextUtilities.ParseNameValueWithEqualsPosition(message, span16, equals16);
                                var metadata = new Metadata
                                {
                                    Name = stringTable.Intern(nameValue.Key),
                                    Value = stringTable.Intern(nameValue.Value)
                                };
                                currentItem.AddChild(metadata);
                            }
                        }
                        break;
                    default:
                        var line = message.Substring(lineSpan);
                        if (numberOfLeadingSpaces == 0 && line == prefix)
                        {
                            continue;
                        }

                        // must be a continuation of a multi-line value
                        if (currentProperty != null)
                        {
                            currentProperty.Value += "\n" + line;
                        }
                        else if (currentItem != null && currentItem.HasChildren)
                        {
                            var metadata = currentItem.Children[currentItem.Children.Count - 1] as Metadata;
                            if (metadata != null)
                            {
                                metadata.Value = (metadata.Value ?? "") + line;
                            }
                        }
                        break;
                }
            }

            return parameter;
        }