File: Utility\JsonConfigUtility.cs
Web Access
Project: src\src\nuget-client\src\NuGet.Core\NuGet.PackageManagement\NuGet.PackageManagement.csproj (NuGet.PackageManagement)
// 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.Globalization;
using System.Linq;
using Newtonsoft.Json.Linq;
using NuGet.Frameworks;
using NuGet.PackageManagement;
using NuGet.Packaging.Core;
using NuGet.Versioning;

namespace NuGet.ProjectManagement
{
    /// <summary>
    /// project.json utils
    /// </summary>
    public static class JsonConfigUtility
    {
        private const string DEPENDENCIES_TAG = "dependencies";
        private const string FRAMEWORKS_TAG = "frameworks";

        /// <summary>
        /// Read dependencies from a project.json file
        /// </summary>
        public static IEnumerable<PackageDependency> GetDependencies(JObject json)
        {
            JToken node = null;
            if (json.TryGetValue(DEPENDENCIES_TAG, out node))
            {
                foreach (var dependency in node)
                {
                    yield return ParseDependency(dependency);
                }
            }
        }

        /// <summary>
        /// Convert a dependency entry into an id and version range
        /// </summary>
        public static PackageDependency ParseDependency(JToken dependencyToken)
        {
            var property = dependencyToken as JProperty;

            var id = property.Name;

            string version = null;
            if (property.Value.Type == JTokenType.String)
            {
                version = (string)property.Value;
            }
            else if (property.Value.Type == JTokenType.Object)
            {
                version = (string)property.Value["version"];
            }

            if (string.IsNullOrEmpty(version))
            {
                throw new FormatException(
                    string.Format(CultureInfo.CurrentCulture, Strings.DependencyDoesNotHaveValidVersion, dependencyToken.ToString()));
            }

            var range = VersionRange.Parse(version);
            return new PackageDependency(id, range);
        }

        /// <summary>
        /// Add a dependency to a project.json file
        /// </summary>
        public static void AddDependency(JObject json, PackageIdentity package)
        {
            var range = VersionRange.All;

            if (package.Version != null)
            {
                range = new VersionRange(
                    minVersion: package.Version,
                    includeMinVersion: true,
                    maxVersion: null,
                    includeMaxVersion: false);
            }

            var dependency = new PackageDependency(package.Id, range);

            AddDependency(json, dependency);
        }

        /// <summary>
        /// Add a dependency to a project.json file
        /// </summary>
        public static void AddDependency(JObject json, PackageDependency dependency)
        {
            // Removing the older package if it exists
            RemoveDependency(json, dependency.Id);

            JObject dependencySet = null;

            JToken node = null;
            if (json.TryGetValue(DEPENDENCIES_TAG, out node))
            {
                dependencySet = node as JObject;
            }

            if (dependencySet == null)
            {
                dependencySet = new JObject();
            }

            var packageProperty = new JProperty(dependency.Id, dependency.VersionRange.MinVersion.ToNormalizedString());
            dependencySet.Add(packageProperty);

            // order dependencies to reduce merge conflicts
            dependencySet = SortProperties(dependencySet);

            json[DEPENDENCIES_TAG] = dependencySet;
        }

        /// <summary>
        /// Remove a dependency from a project.json file
        /// </summary>
        public static void RemoveDependency(JObject json, string packageId)
        {
            JToken node = null;
            if (json.TryGetValue(DEPENDENCIES_TAG, out node))
            {
                foreach (var dependency in node.ToArray())
                {
                    var dependencyProperty = dependency as JProperty;
                    if (StringComparer.OrdinalIgnoreCase.Equals(dependencyProperty.Name, packageId))
                    {
                        dependency.Remove();
                    }
                }
            }
        }

        /// <summary>
        /// Retrieve the NuGetFrameworks under frameworks
        /// </summary>
        public static IEnumerable<NuGetFramework> GetFrameworks(JObject json)
        {
            var results = new List<NuGetFramework>();

            JToken node = null;
            if (json.TryGetValue(FRAMEWORKS_TAG, out node))
            {
                foreach (var frameworkNode in node.ToArray())
                {
                    var frameworkProperty = frameworkNode as JProperty;

                    if (frameworkProperty != null)
                    {
                        results.Add(NuGetFramework.Parse(frameworkProperty.Name));
                    }
                }
            }

            return results;
        }

        /// <summary>
        /// Add the specified framework to JSON object
        /// </summary>
        public static void AddFramework(JObject json, NuGetFramework framework)
        {
            var frameworksList = GetFrameworks(json);
            if (HasFramework(frameworksList, framework))
            {
                return;
            }

            JObject frameworkSet = null;

            JToken node = null;
            if (json.TryGetValue(FRAMEWORKS_TAG, out node))
            {
                frameworkSet = node as JObject;
            }

            if (frameworkSet == null)
            {
                frameworkSet = new JObject();
            }

            var frameworkProperty = new JProperty(framework.GetShortFolderName(), new JObject());
            frameworkSet.Add(frameworkProperty);

            // order frameworks to reduce merge conflicts
            frameworkSet = SortProperties(frameworkSet);

            json[FRAMEWORKS_TAG] = frameworkSet;
        }

        /// <summary>
        ///  Clear all frameworks from the JSON object
        /// </summary>
        public static void ClearFrameworks(JObject json)
        {
            json[FRAMEWORKS_TAG] = new JObject();
        }

        /// <summary>
        ///  Sort child properties
        /// </summary>
        private static JObject SortProperties(JObject parent)
        {
            var sortedParent = new JObject();

            var sortedChildren = parent.Children().OrderByDescending(child => GetChildKey(child), StringComparer.OrdinalIgnoreCase);

            foreach (var child in sortedChildren)
            {
                sortedParent.AddFirst(child);
            }

            return sortedParent;
        }

        private static bool HasFramework(IEnumerable<NuGetFramework> list, NuGetFramework framework)
        {
            return list.Contains(framework);
        }

        private static string GetChildKey(JToken token)
        {
            var property = token as JProperty;

            if (property != null)
            {
                return property.Name;
            }

            return string.Empty;
        }
    }
}