| File: FrameworkExpander.cs | Web Access |
| Project: src\nuget-client\src\NuGet.Core\NuGet.Frameworks\NuGet.Frameworks.csproj (NuGet.Frameworks) |
// 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. using System; using System.Collections.Generic; namespace NuGet.Frameworks { /// <summary> /// FrameworkExpander finds all equivalent and compatible frameworks for a NuGetFramework /// </summary> public class FrameworkExpander { private readonly IFrameworkNameProvider _mappings; public FrameworkExpander() : this(DefaultFrameworkNameProvider.Instance) { } public FrameworkExpander(IFrameworkNameProvider mappings) { _mappings = mappings ?? throw new ArgumentNullException(nameof(mappings)); } /// <summary> /// Return all possible equivalent, subset, and known compatible frameworks. /// </summary> public IEnumerable<NuGetFramework> Expand(NuGetFramework framework) { if (framework == null) throw new ArgumentNullException(nameof(framework)); var seen = new HashSet<NuGetFramework>() { framework }; var toExpand = new Stack<NuGetFramework>(); toExpand.Push(framework); while (toExpand.Count > 0) { foreach (var expansion in ExpandInternal(toExpand.Pop())) { // only return distinct frameworks if (seen.Add(expansion)) { yield return expansion; toExpand.Push(expansion); } } } // This PCL check is done outside of the loop because we do not want // to recurse (via the stack above) on this PCL equivalence. The // intent here is to ensure that PCL should expand to netstandard, // but NOT to dotnet (which is deprecated). if (framework.IsPCL) { if (_mappings.TryGetPortableProfileNumber(framework.Profile, out int profileNumber) && _mappings.TryGetPortableCompatibilityMappings(profileNumber, out IEnumerable<FrameworkRange>? ranges)) { foreach (var range in ranges) { yield return range.Min; if (!range.Min.Equals(range.Max)) { yield return range.Max; } } } } } /// <summary> /// Finds all expansions using the mapping provider /// </summary> private IEnumerable<NuGetFramework> ExpandInternal(NuGetFramework framework) { // check the framework directly, this includes profiles which the range doesn't return if (_mappings.TryGetEquivalentFrameworks(framework, out IEnumerable<NuGetFramework>? directlyEquivalent)) { foreach (var eqFw in directlyEquivalent) { yield return eqFw; } } // 0.0 through the current framework var frameworkRange = new FrameworkRange( new NuGetFramework(framework.Framework, new Version(0, 0), framework.Profile), framework); if (_mappings.TryGetEquivalentFrameworks(frameworkRange, out IEnumerable<NuGetFramework>? equivalent)) { foreach (var eqFw in equivalent) { yield return eqFw; } } // find all possible sub set frameworks if no profile is used if (!framework.HasProfile) { if (_mappings.TryGetSubSetFrameworks(framework.Framework, out IEnumerable<string>? subSetFrameworks)) { foreach (var subFramework in subSetFrameworks) { // clone the framework but use the sub framework instead yield return new NuGetFramework(subFramework, framework.Version, framework.Profile); } } } // explicit compatiblity mappings if (_mappings.TryGetCompatibilityMappings(framework, out IEnumerable<FrameworkRange>? ranges)) { foreach (var range in ranges) { yield return range.Min; if (!range.Min.Equals(range.Max)) { yield return range.Max; } } } } } }