File: JsonTextReaderExtensions.cs
Web Access
Project: src\nuget-client\src\NuGet.Core\NuGet.ProjectModel\NuGet.ProjectModel.csproj (NuGet.ProjectModel)
// 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 Newtonsoft.Json;

namespace NuGet.ProjectModel
{
    internal static class JsonTextReaderExtensions
    {
        private static readonly char[] DelimitedStringDelimiters = new char[] { ' ', ',' };

        internal static IReadOnlyList<string> ReadDelimitedString(this JsonTextReader reader)
        {
            if (reader == null)
            {
                throw new ArgumentNullException(nameof(reader));
            }

            if (ReadNextToken(reader))
            {
                switch (reader.TokenType)
                {
                    case JsonToken.String:
                        var value = (string)reader.Value;

                        return value.Split(DelimitedStringDelimiters, StringSplitOptions.RemoveEmptyEntries);

                    default:
                        throw new InvalidCastException();
                }
            }

            return null;
        }

        internal static bool ReadNextToken(this JsonTextReader reader)
        {
            if (reader == null)
            {
                throw new ArgumentNullException(nameof(reader));
            }

            bool wasRead;

            while ((wasRead = reader.Read()) && reader.TokenType == JsonToken.Comment)
            {
            }

            return wasRead;
        }

        internal static string ReadNextTokenAsString(this JsonTextReader reader)
        {
            if (ReadNextToken(reader))
            {
                return ReadTokenAsString(reader);
            }

            return null;
        }

        internal static bool ReadObject(this JsonTextReader reader, Action<string> onProperty)
        {
            return ReadObject(reader, onProperty, out int _0, out int _1);
        }

        internal static bool ReadObject(this JsonTextReader reader, Action<string> onProperty, out int startObjectLine, out int startObjectColumn)
        {
            startObjectLine = 0;
            startObjectColumn = 0;

            if (reader == null)
            {
                throw new ArgumentNullException(nameof(reader));
            }

            if (onProperty == null)
            {
                throw new ArgumentNullException(nameof(onProperty));
            }

            if (ReadNextToken(reader) && reader.TokenType == JsonToken.StartObject)
            {
                startObjectLine = reader.LineNumber;
                startObjectColumn = reader.LinePosition;

                ReadProperties(reader, onProperty);

                return true;
            }

            return false;
        }

        internal static void ReadProperties(this JsonTextReader reader, Action<string> onProperty)
        {
            if (reader == null)
            {
                throw new ArgumentNullException(nameof(reader));
            }

            if (onProperty == null)
            {
                throw new ArgumentNullException(nameof(onProperty));
            }

            while (ReadNextToken(reader) && reader.TokenType == JsonToken.PropertyName)
            {
                var propertyName = (string)reader.Value;

                int lineNumber = reader.LineNumber;
                int linePosition = reader.LinePosition;

                onProperty(propertyName);

                if (reader.LineNumber == lineNumber && reader.LinePosition == linePosition)
                {
                    reader.Skip();
                }
            }
        }

        internal static List<string> ReadStringArrayAsList(this JsonTextReader reader)
        {
            if (reader == null)
            {
                throw new ArgumentNullException(nameof(reader));
            }

            List<string> strings = null;

            if (ReadNextToken(reader) && reader.TokenType == JsonToken.StartArray)
            {
                while (ReadNextToken(reader) && reader.TokenType != JsonToken.EndArray)
                {
                    string value = ReadTokenAsString(reader);

                    strings = strings ?? new List<string>();

                    strings.Add(value);
                }
            }

            return strings;
        }

        internal static IReadOnlyList<string> ReadStringOrArrayOfStringsAsReadOnlyList(this JsonTextReader reader)
        {
            if (reader == null)
            {
                throw new ArgumentNullException(nameof(reader));
            }

            if (ReadNextToken(reader))
            {
                switch (reader.TokenType)
                {
                    case JsonToken.String:
                        return new[] { (string)reader.Value };

                    case JsonToken.StartArray:
                        return ReadStringArrayAsReadOnlyListFromArrayStart(reader);
                }
            }

            return null;
        }

        internal static IReadOnlyList<string> ReadStringArrayAsReadOnlyListFromArrayStart(this JsonTextReader reader)
        {
            if (reader == null)
            {
                throw new ArgumentNullException(nameof(reader));
            }

            List<string> strings = null;

            while (ReadNextToken(reader) && reader.TokenType != JsonToken.EndArray)
            {
                string value = ReadTokenAsString(reader);

                strings = strings ?? new List<string>();

                strings.Add(value);
            }

            return (IReadOnlyList<string>)strings ?? Array.Empty<string>();
        }

        private static string ReadTokenAsString(this JsonTextReader reader)
        {
            switch (reader.TokenType)
            {
                case JsonToken.Boolean:
                case JsonToken.Float:
                case JsonToken.Integer:
                case JsonToken.String:
                    return reader.Value.ToString();

                case JsonToken.Null:
                    return null;

                default:
                    throw new InvalidCastException();
            }
        }
    }
}