diff --git a/THIRD-PARTY-NOTICES.txt b/THIRD-PARTY-NOTICES.txt
index 07217a9e5a..b7c3258db7 100644
--- a/THIRD-PARTY-NOTICES.txt
+++ b/THIRD-PARTY-NOTICES.txt
@@ -32,3 +32,20 @@ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
+License notice for NuGet.Client (NuGet.Frameworks)
+--------------------------------------------------
+Copyright (c) .NET Foundation and Contributors.
+
+All rights reserved.
+
+
+Licensed under the Apache License, Version 2.0 (the "License"); you may not use
+these files except in compliance with the License. You may obtain a copy of the
+License at
+
+http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software distributed
+under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
+CONDITIONS OF ANY KIND, either express or implied. See the License for the
+specific language governing permissions and limitations under the License.
\ No newline at end of file
diff --git a/eng/SourceBuildPrebuiltBaseline.xml b/eng/SourceBuildPrebuiltBaseline.xml
index 987c2d8b1c..7d038cd01e 100644
--- a/eng/SourceBuildPrebuiltBaseline.xml
+++ b/eng/SourceBuildPrebuiltBaseline.xml
@@ -6,7 +6,6 @@
-
diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml
index fafb1adf99..610c783221 100644
--- a/eng/Version.Details.xml
+++ b/eng/Version.Details.xml
@@ -24,10 +24,6 @@
0030d238c7929b0e9b06576837b60ad90037b1d2
-
- https://github.com/nuget/nuget.client
- 4ba7bfa82f894ec32a554ca8d2df143675c85735
-
https://github.com/dotnet/corefx
diff --git a/eng/Versions.props b/eng/Versions.props
index 06423ba803..dd8ae3364f 100644
--- a/eng/Versions.props
+++ b/eng/Versions.props
@@ -90,10 +90,6 @@
[16.6.1]
[16.11.0]
[15.9.2]
-
-
- 6.5.0
5.0.0
diff --git a/eng/verify-nupkgs.ps1 b/eng/verify-nupkgs.ps1
index be44eeefb7..8fe256dfe7 100644
--- a/eng/verify-nupkgs.ps1
+++ b/eng/verify-nupkgs.ps1
@@ -16,13 +16,13 @@ function Verify-Nuget-Packages {
$expectedNumOfFiles = @{
"Microsoft.CodeCoverage" = 59;
"Microsoft.NET.Test.Sdk" = 16;
- "Microsoft.TestPlatform" = 607;
+ "Microsoft.TestPlatform" = 605;
"Microsoft.TestPlatform.Build" = 21;
- "Microsoft.TestPlatform.CLI" = 472;
+ "Microsoft.TestPlatform.CLI" = 470;
"Microsoft.TestPlatform.Extensions.TrxLogger" = 35;
"Microsoft.TestPlatform.ObjectModel" = 93;
"Microsoft.TestPlatform.AdapterUtilities" = 34;
- "Microsoft.TestPlatform.Portable" = 595;
+ "Microsoft.TestPlatform.Portable" = 592;
"Microsoft.TestPlatform.TestHost" = 63;
"Microsoft.TestPlatform.TranslationLayer" = 123;
"Microsoft.TestPlatform.Internal.Uwp" = 39;
diff --git a/scripts/update-nuget-frameworks.ps1 b/scripts/update-nuget-frameworks.ps1
new file mode 100644
index 0000000000..6d6894b50e
--- /dev/null
+++ b/scripts/update-nuget-frameworks.ps1
@@ -0,0 +1,117 @@
+param (
+ [String] $VersionTag = "6.8.0.117"
+)
+
+$root = Resolve-Path "$PSScriptRoot/.."
+
+$source = "$root/artifacts/tmp/NuGet.Client"
+
+if (Test-Path $source) {
+ Remove-Item -Recurse -Force $source
+}
+
+git clone --depth 1 --branch $VersionTag https://github.com/NuGet/NuGet.Client.git $source
+if (0 -ne $LASTEXITCODE) {
+ throw "Cloning failed."
+}
+
+$commit = git -C $source log -1 --pretty=format:"%h"
+if (0 -ne $LASTEXITCODE) {
+ throw "Getting commit failed."
+}
+
+$destination = "$root/src/Microsoft.TestPlatform.ObjectModel/Nuget.Frameworks/"
+
+$frameworksPath = "$source/src/NuGet.Core/NuGet.Frameworks"
+$frameworkItems = @(
+ "DefaultFrameworkMappings.cs"
+ "DefaultFrameworkNameProvider.cs"
+ "DefaultPortableFrameworkMappings.cs"
+ "DefaultCompatibilityProvider.cs"
+ "CompatibilityProvider.cs"
+ "FrameworkConstants.cs"
+ "FrameworkException.cs"
+ "FrameworkNameProvider.cs"
+ "FrameworkRange.cs"
+ "FrameworkReducer.cs"
+ "FrameworkNameHelpers.cs",
+ "FrameworkSpecificMapping.cs"
+ "FallbackFramework.cs"
+ "FrameworkExpander.cs"
+ "CompatibilityCacheKey.cs"
+ "def/IFrameworkCompatibilityListProvider.cs"
+ "def/IFrameworkCompatibilityProvider.cs"
+ "def/IFrameworkMappings.cs"
+ "def/IFrameworkNameProvider.cs"
+ "def/IFrameworkSpecific.cs"
+ "def/IPortableFrameworkMappings.cs"
+ "NuGetFramework.cs"
+ "NuGetFrameworkFactory.cs"
+ "comparers/NuGetFrameworkFullComparer.cs"
+ "comparers/NuGetFrameworkNameComparer.cs"
+ "comparers/CompatibilityMappingComparer.cs"
+ "comparers/FrameworkRangeComparer.cs"
+ "comparers/NuGetFrameworkSorter.cs"
+ "comparers/FrameworkPrecedenceSorter.cs"
+ "NuGetFrameworkUtility.cs"
+ "OneWayCompatibilityMappingEntry.cs"
+) | ForEach-Object { "$frameworksPath/$_" }
+
+$extraItems = @(
+ ".editorconfig"
+ "build/Shared/HashCodeCombiner.cs"
+ "build/Shared/NoAllocEnumerateExtensions.cs"
+ "build/Shared/StringBuilderPool.cs"
+ "build/Shared/SimplePool.cs"
+) | ForEach-Object { "$source/$_" }
+
+if ((Test-Path $destination)) {
+ Remove-Item $destination -Force -Recurse
+}
+
+New-Item -ItemType Directory $destination -ErrorAction Ignore | Out-Null
+foreach ($item in $frameworkItems + $extraItems) {
+ if (-not (Test-Path $item)) {
+ throw "File not found $item"
+ }
+ $content = Get-Content $item
+ $name = (Get-Item $item).Name
+
+ $path = "$destination/$name"
+
+ # some types are directly in Nuget namespace, and if we would suffix
+ # .Clone, then Nuget.Frameworks.Clone is no longer autometicaly using
+ # Nuget.Clone, and we would have to add more usings into the files.
+ $finalContent = $content `
+ -replace 'public(.*)(class|interface)', 'internal$1$2' `
+ -replace 'namespace NuGet', 'namespace NuGetClone' `
+ -replace 'using NuGet', 'using NuGetClone' `
+ -replace 'NuGet.Frameworks.NuGetFramework', 'NuGetClone.Frameworks.NuGetFramework'
+
+ if ($name -eq ".editorconfig") {
+ $finalContent += @"
+
+[*.{cs,vb}]
+dotnet_diagnostic.IDE0001.severity = none
+dotnet_diagnostic.IDE0005.severity = none
+dotnet_diagnostic.IDE1006.severity = none
+"@
+ }
+ $finalContent | Set-Content -Path $path -Encoding utf8NoBOM
+}
+
+
+@"
+This directory contains code that is copied from https://github.com/NuGet/NuGet.Client/tree/dev/src/NuGet.Core/NuGet.Frameworks, with the namespaces changed
+and class visibility changed. This is done to ensure we are providing the same functionality as Nuget.Frameworks, without depending on the package explicitly.
+
+The files in this folder are coming from tag $VersionTag, on commit $commit.
+
+To update this code, run the script in: $($PSCommandPath -replace [regex]::Escape($root)) , with -VersionTag .
+
+"@ | Set-Content "$destination/README.md"
+
+$tpnPath = "$root/src/package/ThirdPartyNotices.txt"
+$tpn = Get-Content $tpnPath -Raw
+$tpn = $tpn -replace "Nuget.Client version.*\(", "Nuget.Client version $versionTag \("
+$tpn | Set-Content -Path $tpnPath -Encoding utf8NoBOM -NoNewline
\ No newline at end of file
diff --git a/src/Microsoft.TestPlatform.Extensions.BlameDataCollector/CrashDumperFactory.cs b/src/Microsoft.TestPlatform.Extensions.BlameDataCollector/CrashDumperFactory.cs
index 515065126b..d6d7826980 100644
--- a/src/Microsoft.TestPlatform.Extensions.BlameDataCollector/CrashDumperFactory.cs
+++ b/src/Microsoft.TestPlatform.Extensions.BlameDataCollector/CrashDumperFactory.cs
@@ -7,8 +7,6 @@
using Microsoft.VisualStudio.TestPlatform.ObjectModel;
using Microsoft.VisualStudio.TestPlatform.Utilities.Helpers;
-using NuGet.Frameworks;
-
namespace Microsoft.TestPlatform.Extensions.BlameDataCollector;
internal class CrashDumperFactory : ICrashDumperFactory
@@ -18,15 +16,15 @@ public ICrashDumper Create(string targetFramework)
ValidateArg.NotNull(targetFramework, nameof(targetFramework));
EqtTrace.Info($"CrashDumperFactory: Creating dumper for {RuntimeInformation.OSDescription} with target framework {targetFramework}.");
- var tfm = NuGetFramework.Parse(targetFramework);
+ var tfm = Framework.FromString(targetFramework);
- if (tfm == null || tfm.IsUnsupported)
+ if (tfm == null)
{
EqtTrace.Error($"CrashDumperFactory: Could not parse target framework {targetFramework}, to a supported framework version.");
throw new NotSupportedException($"Could not parse target framework {targetFramework}, to a supported framework version.");
}
- var isNet50OrNewer = tfm.Framework == ".NETCoreApp" && tfm.Version >= Version.Parse("5.0.0.0");
+ var isNet50OrNewer = tfm.FrameworkName == ".NETCoreApp" && Version.Parse(tfm.Version) >= Version.Parse("5.0.0.0");
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
{
diff --git a/src/Microsoft.TestPlatform.Extensions.BlameDataCollector/HangDumperFactory.cs b/src/Microsoft.TestPlatform.Extensions.BlameDataCollector/HangDumperFactory.cs
index d9f2352bc5..3ca7beb8c4 100644
--- a/src/Microsoft.TestPlatform.Extensions.BlameDataCollector/HangDumperFactory.cs
+++ b/src/Microsoft.TestPlatform.Extensions.BlameDataCollector/HangDumperFactory.cs
@@ -7,8 +7,6 @@
using Microsoft.VisualStudio.TestPlatform.ObjectModel;
using Microsoft.VisualStudio.TestPlatform.PlatformAbstractions;
-using NuGet.Frameworks;
-
namespace Microsoft.TestPlatform.Extensions.BlameDataCollector;
internal class HangDumperFactory : IHangDumperFactory
@@ -24,9 +22,9 @@ public IHangDumper Create(string targetFramework)
var netdumpOverride = Environment.GetEnvironmentVariable("VSTEST_DUMP_FORCENETDUMP")?.Trim();
EqtTrace.Verbose($"HangDumperFactory: Overrides for dumpers: VSTEST_DUMP_FORCEPROCDUMP={procdumpOverride};VSTEST_DUMP_FORCENETDUMP={netdumpOverride}");
- var tfm = NuGetFramework.Parse(targetFramework);
+ var tfm = Framework.FromString(targetFramework);
- if (tfm == null || tfm.IsUnsupported)
+ if (tfm == null)
{
EqtTrace.Error($"HangDumperFactory: Could not parse target framework {targetFramework}, to a supported framework version.");
throw new NotSupportedException($"Could not parse target framework {targetFramework}, to a supported framework version.");
@@ -46,15 +44,15 @@ public IHangDumper Create(string targetFramework)
var forceUsingNetdump = !netdumpOverride.IsNullOrWhiteSpace() && netdumpOverride != "0";
if (forceUsingNetdump)
{
- var isLessThan50 = tfm.Framework == ".NETCoreApp" && tfm.Version < Version.Parse("5.0.0.0");
+ var isLessThan50 = tfm.FrameworkName == ".NETCoreApp" && Version.Parse(tfm.Version) < Version.Parse("5.0.0.0");
if (!isLessThan50)
{
- EqtTrace.Info($"HangDumperFactory: This is Windows on {tfm.Framework} {tfm.Version}, VSTEST_DUMP_FORCENETDUMP={netdumpOverride} is active, forcing use of .NetClientHangDumper");
+ EqtTrace.Info($"HangDumperFactory: This is Windows on {tfm.FrameworkName} {tfm.Version}, VSTEST_DUMP_FORCENETDUMP={netdumpOverride} is active, forcing use of .NetClientHangDumper");
return new NetClientHangDumper();
}
else
{
- EqtTrace.Info($"HangDumperFactory: This is Windows on {tfm.Framework} {tfm.Version}, VSTEST_DUMP_FORCENETDUMP={netdumpOverride} is active, but only applies to .NET 5.0 and newer. Falling back to default hang dumper.");
+ EqtTrace.Info($"HangDumperFactory: This is Windows on {tfm.FrameworkName} {tfm.Version}, VSTEST_DUMP_FORCENETDUMP={netdumpOverride} is active, but only applies to .NET 5.0 and newer. Falling back to default hang dumper.");
}
}
@@ -64,7 +62,7 @@ public IHangDumper Create(string targetFramework)
if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
{
- var isLessThan31 = tfm.Framework == ".NETCoreApp" && tfm.Version < Version.Parse("3.1.0.0");
+ var isLessThan31 = tfm.FrameworkName == ".NETCoreApp" && Version.Parse(tfm.Version) < Version.Parse("3.1.0.0");
if (isLessThan31)
{
EqtTrace.Info($"HangDumperFactory: This is Linux on netcoreapp2.1, returning SigtrapDumper.");
@@ -78,7 +76,7 @@ public IHangDumper Create(string targetFramework)
if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX))
{
- var isLessThan50 = tfm.Framework == ".NETCoreApp" && tfm.Version < Version.Parse("5.0.0.0");
+ var isLessThan50 = tfm.FrameworkName == ".NETCoreApp" && Version.Parse(tfm.Version) < Version.Parse("5.0.0.0");
if (isLessThan50)
{
EqtTrace.Info($"HangDumperFactory: This is OSX on {targetFramework}, This combination of OS and framework is not supported.");
diff --git a/src/Microsoft.TestPlatform.Extensions.HtmlLogger/HtmlLogger.cs b/src/Microsoft.TestPlatform.Extensions.HtmlLogger/HtmlLogger.cs
index 6d979825b5..bf994ee5e2 100644
--- a/src/Microsoft.TestPlatform.Extensions.HtmlLogger/HtmlLogger.cs
+++ b/src/Microsoft.TestPlatform.Extensions.HtmlLogger/HtmlLogger.cs
@@ -18,8 +18,6 @@
using Microsoft.VisualStudio.TestPlatform.Utilities.Helpers;
using Microsoft.VisualStudio.TestPlatform.Utilities.Helpers.Interfaces;
-using NuGet.Frameworks;
-
using HtmlLoggerConstants = Microsoft.VisualStudio.TestPlatform.Extensions.HtmlLogger.Constants;
using HtmlResource = Microsoft.VisualStudio.TestPlatform.Extensions.HtmlLogger.Resources.Resources;
@@ -285,7 +283,7 @@ public void TestRunCompleteHandler(object? sender, TestRunCompleteEventArgs e)
var framework = _parametersDictionary[DefaultLoggerParameterNames.TargetFramework];
if (framework != null)
{
- framework = NuGetFramework.Parse(framework).GetShortFolderName();
+ framework = Framework.FromString(framework)?.ShortName ?? framework;
logFilePrefixValue = logFilePrefixValue + "_" + framework;
}
diff --git a/src/Microsoft.TestPlatform.Extensions.TrxLogger/TrxLogger.cs b/src/Microsoft.TestPlatform.Extensions.TrxLogger/TrxLogger.cs
index 436f965a2d..bcef64a85f 100644
--- a/src/Microsoft.TestPlatform.Extensions.TrxLogger/TrxLogger.cs
+++ b/src/Microsoft.TestPlatform.Extensions.TrxLogger/TrxLogger.cs
@@ -20,8 +20,6 @@
using Microsoft.VisualStudio.TestPlatform.Utilities;
using Microsoft.VisualStudio.TestPlatform.Utilities.Helpers.Interfaces;
-using NuGet.Frameworks;
-
using ObjectModelConstants = Microsoft.VisualStudio.TestPlatform.ObjectModel.Constants;
using TrxLoggerConstants = Microsoft.TestPlatform.Extensions.TrxLogger.Utility.Constants;
using TrxLoggerObjectModel = Microsoft.TestPlatform.Extensions.TrxLogger.ObjectModel;
@@ -489,7 +487,7 @@ private string AcquireTrxFileNamePath(out bool shouldOverwrite)
{
if (_parametersDictionary.TryGetValue(DefaultLoggerParameterNames.TargetFramework, out var framework) && framework != null)
{
- framework = NuGetFramework.Parse(framework).GetShortFolderName();
+ framework = Framework.FromString(framework)?.ShortName ?? framework;
logFilePrefixValue = logFilePrefixValue + "_" + framework;
}
diff --git a/src/Microsoft.TestPlatform.ObjectModel/Framework.cs b/src/Microsoft.TestPlatform.ObjectModel/Framework.cs
index 9e3b8fe100..64ed5f203c 100644
--- a/src/Microsoft.TestPlatform.ObjectModel/Framework.cs
+++ b/src/Microsoft.TestPlatform.ObjectModel/Framework.cs
@@ -5,9 +5,8 @@
using System.Globalization;
-using NuGet.Frameworks;
-
-using static NuGet.Frameworks.FrameworkConstants;
+using NuGetClone.Frameworks;
+using System;
namespace Microsoft.VisualStudio.TestPlatform.ObjectModel;
@@ -36,6 +35,16 @@ private Framework()
///
public string Name { get; private set; }
+ ///
+ /// Gets the framework name such as .NETCoreApp.
+ ///
+ public string FrameworkName { get; private set; }
+
+ ///
+ /// Common short name, as well as directory name, such as net5.0. Is null when the framework is not correct.
+ ///
+ public string? ShortName { get; private set; }
+
///
/// Gets the framework version.
///
@@ -53,56 +62,71 @@ private Framework()
return null;
}
- string name, version;
+ string name, frameworkName, version;
+ string? shortName = null;
try
{
// IDE always sends framework in form of ENUM, which always throws exception
// This throws up in first chance exception, refer Bug https://devdiv.visualstudio.com/DefaultCollection/DevDiv/_workitems/edit/591142
var formattedFrameworkString = frameworkString.Trim().ToLower(CultureInfo.InvariantCulture);
+ string? mappedShortName = null;
switch (formattedFrameworkString)
{
case "framework35":
- name = CommonFrameworks.Net35.DotNetFrameworkName;
- version = CommonFrameworks.Net35.Version.ToString();
+ mappedShortName = "net3.5";
break;
case "framework40":
- name = CommonFrameworks.Net4.DotNetFrameworkName;
- version = CommonFrameworks.Net4.Version.ToString();
+ mappedShortName = "net4.0";
break;
case "framework45":
- name = CommonFrameworks.Net45.DotNetFrameworkName;
- version = CommonFrameworks.Net45.Version.ToString();
+ mappedShortName = "net4.5";
break;
case "frameworkcore10":
- name = CommonFrameworks.NetCoreApp10.DotNetFrameworkName;
- version = CommonFrameworks.NetCoreApp10.Version.ToString();
+ mappedShortName = "netcoreapp1.0";
break;
case "frameworkuap10":
- name = CommonFrameworks.UAP10.DotNetFrameworkName;
- version = CommonFrameworks.UAP10.Version.ToString();
+ mappedShortName = "uap10.0";
break;
+ }
- default:
- var nugetFramework = NuGetFramework.Parse(frameworkString);
- if (nugetFramework.IsUnsupported)
- return null;
+ if (mappedShortName != null)
+ {
+ frameworkString = mappedShortName;
+ }
- name = nugetFramework.DotNetFrameworkName;
- version = nugetFramework.Version.ToString();
+ var nugetFramework = NuGetFramework.Parse(frameworkString);
+ if (nugetFramework.IsUnsupported)
+ return null;
- break;
+ // e.g. .NETFramework,Version=v3.5
+ name = nugetFramework.DotNetFrameworkName;
+ // e.g. net35
+ try
+ {
+ // .NETPortable4.5 for example, is not a valid framework
+ // and this will throw.
+ shortName = nugetFramework.GetShortFolderName();
}
+ catch (Exception ex)
+ {
+ EqtTrace.Error(ex);
+ }
+ // e.g. .NETFramework
+ frameworkName = nugetFramework.Framework;
+ // e.g. 3.5.0.0
+ version = nugetFramework.Version.ToString();
+
}
catch
{
return null;
}
- return new Framework() { Name = name, Version = version };
+ return new Framework() { Name = name, ShortName = shortName, FrameworkName = frameworkName, Version = version };
}
///
diff --git a/src/Microsoft.TestPlatform.ObjectModel/Microsoft.TestPlatform.ObjectModel.csproj b/src/Microsoft.TestPlatform.ObjectModel/Microsoft.TestPlatform.ObjectModel.csproj
index efa090d13b..0fb981d962 100644
--- a/src/Microsoft.TestPlatform.ObjectModel/Microsoft.TestPlatform.ObjectModel.csproj
+++ b/src/Microsoft.TestPlatform.ObjectModel/Microsoft.TestPlatform.ObjectModel.csproj
@@ -4,6 +4,8 @@
Microsoft.VisualStudio.TestPlatform.ObjectModel
net7.0;$(NetFrameworkMinimum);$(NetCoreAppMinimum);netstandard2.0;
+
+ $(NoWarn);SYSLIB0051
@@ -32,7 +34,6 @@
-
diff --git a/src/Microsoft.TestPlatform.ObjectModel/Microsoft.TestPlatform.ObjectModel.nuspec b/src/Microsoft.TestPlatform.ObjectModel/Microsoft.TestPlatform.ObjectModel.nuspec
index c4ec7526eb..105050657a 100644
--- a/src/Microsoft.TestPlatform.ObjectModel/Microsoft.TestPlatform.ObjectModel.nuspec
+++ b/src/Microsoft.TestPlatform.ObjectModel/Microsoft.TestPlatform.ObjectModel.nuspec
@@ -6,17 +6,14 @@
-
-
-
diff --git a/src/Microsoft.TestPlatform.ObjectModel/Nuget.Frameworks/.editorconfig b/src/Microsoft.TestPlatform.ObjectModel/Nuget.Frameworks/.editorconfig
new file mode 100644
index 0000000000..5e94bf7109
--- /dev/null
+++ b/src/Microsoft.TestPlatform.ObjectModel/Nuget.Frameworks/.editorconfig
@@ -0,0 +1,153 @@
+; EditorConfig to support per-solution formatting.
+; Use the EditorConfig VS add-in to make this work.
+; http://editorconfig.org/
+
+; This is the default for the codeline.
+root = true
+
+[*]
+; Don't use tabs for indentation.
+indent_style = space
+; (Please don't specify an indent_size here; that has too many unintended consequences.)
+charset = utf-8
+trim_trailing_whitespace = true
+insert_final_newline = true
+
+# Spell checker configuration
+spelling_exclusion_path = spelling.dic
+
+; Code files
+[*.{cs}]
+indent_size = 4
+
+; All XML-based file formats
+[*.{config,csproj,nuspec,props,resx,ruleset,targets,vsct,vsixmanifest,xaml,xml,vsmanproj,swixproj}]
+indent_size = 2
+
+; JSON files
+[*.json]
+indent_size = 2
+
+; PowerShell scripts
+[*.{ps1}]
+indent_size = 4
+
+[*.{sh}]
+indent_size = 4
+
+; Dotnet code style settings
+[*.{cs,vb}]
+; Sort using and Import directives with System.* appearing first
+dotnet_sort_system_directives_first = true
+dotnet_separate_import_directive_groups = false
+
+; IDE0003 Avoid "this." and "Me." if not necessary
+dotnet_style_qualification_for_field = false:warning
+dotnet_style_qualification_for_property = false:warning
+dotnet_style_qualification_for_method = false:warning
+dotnet_style_qualification_for_event = false:warning
+
+; IDE0012 Use language keywords instead of framework type names for type references
+dotnet_style_predefined_type_for_locals_parameters_members = true:warning
+; IDE0013
+dotnet_style_predefined_type_for_member_access = true:warning
+
+; Suggest more modern language features when available
+dotnet_style_object_initializer = true:suggestion
+dotnet_style_collection_initializer = true:suggestion
+dotnet_style_explicit_tuple_names = true:suggestion
+dotnet_style_coalesce_expression = true:suggestion
+dotnet_style_null_propagation = true:suggestion
+
+; Licence header
+file_header_template = Copyright (c) .NET Foundation. All rights reserved.\nLicensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+
+; CSharp code style settings
+[*.cs]
+; IDE0007 'var' preferences
+csharp_style_var_for_built_in_types = true:none
+csharp_style_var_when_type_is_apparent = true:none
+csharp_style_var_elsewhere = false:none
+
+; Prefer method-like constructs to have a block body
+csharp_style_expression_bodied_methods = false:none
+csharp_style_expression_bodied_constructors = false:none
+csharp_style_expression_bodied_operators = false:none
+
+; Prefer property-like constructs to have an expression-body
+csharp_style_expression_bodied_properties = true:suggestion
+csharp_style_expression_bodied_indexers = true:suggestion
+csharp_style_expression_bodied_accessors = true:suggestion
+
+; Suggest more modern language features when available
+csharp_style_pattern_matching_over_is_with_cast_check = true:none
+csharp_style_pattern_matching_over_as_with_null_check = true:none
+csharp_style_inlined_variable_declaration = true:none
+csharp_style_throw_expression = true:none
+csharp_style_conditional_delegate_call = true:suggestion
+
+; Newline settings
+csharp_new_line_before_open_brace = all
+csharp_new_line_before_else = true
+csharp_new_line_before_catch = true
+csharp_new_line_before_finally = true
+csharp_new_line_before_members_in_object_initializers = true
+csharp_new_line_before_members_in_anonymous_types = true
+
+; Naming styles
+dotnet_naming_style.pascal_case_style.capitalization = pascal_case
+dotnet_naming_style.camel_case_style.capitalization = camel_case
+
+; Naming rule: async methods end in Async
+dotnet_naming_style.async_method_style.capitalization = pascal_case
+dotnet_naming_style.async_method_style.required_suffix = Async
+dotnet_naming_symbols.async_method_symbols.applicable_kinds = method
+dotnet_naming_symbols.async_method_symbols.required_modifiers = async
+dotnet_naming_rule.async_methods_rule.severity = suggestion
+dotnet_naming_rule.async_methods_rule.symbols = async_method_symbols
+dotnet_naming_rule.async_methods_rule.style = async_method_style
+
+; Naming rule: Interfaces must be pascal-cased prefixed with I
+dotnet_naming_style.interface_style.capitalization = pascal_case
+dotnet_naming_style.interface_style.required_prefix = I
+dotnet_naming_symbols.interface_symbols.applicable_kinds = interface
+dotnet_naming_symbols.interface_symbols.applicable_accessibilities = *
+dotnet_naming_rule.interfaces_rule.severity = warning
+dotnet_naming_rule.interfaces_rule.symbols = interface_symbols
+dotnet_naming_rule.interfaces_rule.style = interface_style
+
+; Naming rule: All methods and properties must be pascal-cased
+dotnet_naming_symbols.method_and_property_symbols.applicable_kinds = method,property,class,struct,enum:property,namespace
+dotnet_naming_symbols.method_and_property_symbols.applicable_accessibilities = *
+dotnet_naming_rule.methods_and_properties_rule.severity = warning
+dotnet_naming_rule.methods_and_properties_rule.symbols = method_and_property_symbols
+dotnet_naming_rule.methods_and_properties_rule.style = pascal_case_style
+
+; Naming rule: Static fields must be pascal-cased
+dotnet_naming_symbols.static_member_symbols.applicable_kinds = field
+dotnet_naming_symbols.static_member_symbols.applicable_accessibilities = *
+dotnet_naming_symbols.static_member_symbols.required_modifiers = static
+dotnet_naming_symbols.const_member_symbols.applicable_kinds = field
+dotnet_naming_symbols.const_member_symbols.applicable_accessibilities = *
+dotnet_naming_symbols.const_member_symbols.required_modifiers = const
+dotnet_naming_rule.static_fields_rule.severity = warning
+dotnet_naming_rule.static_fields_rule.symbols = static_member_symbols
+dotnet_naming_rule.static_fields_rule.style = pascal_case_style
+
+; Naming rule: Private members must be camel-cased and prefixed with underscore
+dotnet_naming_style.private_member_style.capitalization = camel_case
+dotnet_naming_style.private_member_style.required_prefix = _
+dotnet_naming_symbols.private_field_symbols.applicable_kinds = field,event
+dotnet_naming_symbols.private_field_symbols.applicable_accessibilities = private,protected,internal
+dotnet_naming_rule.private_field_rule.severity = warning
+dotnet_naming_rule.private_field_rule.symbols = private_field_symbols
+dotnet_naming_rule.private_field_rule.style = private_member_style
+
+; Diagnostics rule: Don't leave unnecessary suppressions
+dotnet_diagnostic.IDE0076.severity = warning
+dotnet_diagnostic.IDE0005.severity = warning
+
+[*.{cs,vb}]
+dotnet_diagnostic.IDE0001.severity = none
+dotnet_diagnostic.IDE0005.severity = none
+dotnet_diagnostic.IDE1006.severity = none
diff --git a/src/Microsoft.TestPlatform.ObjectModel/Nuget.Frameworks/CompatibilityCacheKey.cs b/src/Microsoft.TestPlatform.ObjectModel/Nuget.Frameworks/CompatibilityCacheKey.cs
new file mode 100644
index 0000000000..a3ed7babc2
--- /dev/null
+++ b/src/Microsoft.TestPlatform.ObjectModel/Nuget.Frameworks/CompatibilityCacheKey.cs
@@ -0,0 +1,68 @@
+// 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.Globalization;
+using NuGetClone.Shared;
+
+namespace NuGetClone.Frameworks
+{
+ ///
+ /// Internal cache key used to store framework compatibility.
+ ///
+ internal readonly struct CompatibilityCacheKey : IEquatable
+ {
+ public NuGetFramework Target { get; }
+
+ public NuGetFramework Candidate { get; }
+
+ private readonly int _hashCode;
+
+ public CompatibilityCacheKey(NuGetFramework target, NuGetFramework candidate)
+ {
+ if (target == null)
+ {
+ throw new ArgumentNullException(nameof(target));
+ }
+
+ if (candidate == null)
+ {
+ throw new ArgumentNullException(nameof(candidate));
+ }
+
+ Target = target;
+ Candidate = candidate;
+
+ // This is designed to be cached, just get the hash up front
+ var combiner = new HashCodeCombiner();
+ combiner.AddObject(target);
+ combiner.AddObject(candidate);
+ _hashCode = combiner.CombinedHash;
+ }
+
+ public override int GetHashCode()
+ {
+ return _hashCode;
+ }
+
+ public bool Equals(CompatibilityCacheKey other)
+ {
+ return Target.Equals(other.Target)
+ && Candidate.Equals(other.Candidate);
+ }
+
+ public override bool Equals(object? obj)
+ {
+ return obj is CompatibilityCacheKey other && Equals(other);
+ }
+
+ public override string ToString()
+ {
+ return string.Format(
+ CultureInfo.CurrentCulture,
+ "{0} -> {1}",
+ Target.DotNetFrameworkName,
+ Candidate.DotNetFrameworkName);
+ }
+ }
+}
diff --git a/src/Microsoft.TestPlatform.ObjectModel/Nuget.Frameworks/CompatibilityMappingComparer.cs b/src/Microsoft.TestPlatform.ObjectModel/Nuget.Frameworks/CompatibilityMappingComparer.cs
new file mode 100644
index 0000000000..60399ce19f
--- /dev/null
+++ b/src/Microsoft.TestPlatform.ObjectModel/Nuget.Frameworks/CompatibilityMappingComparer.cs
@@ -0,0 +1,56 @@
+// 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;
+using NuGetClone.Shared;
+
+namespace NuGetClone.Frameworks
+{
+ internal class CompatibilityMappingComparer : IEqualityComparer
+ {
+#pragma warning disable CS0618 // Type or member is obsolete
+ public static CompatibilityMappingComparer Instance { get; } = new();
+#pragma warning restore CS0618 // Type or member is obsolete
+
+ [Obsolete("Use singleton CompatibilityMappingComparer.Instance instead")]
+ public CompatibilityMappingComparer()
+ {
+ }
+
+ public bool Equals(OneWayCompatibilityMappingEntry? x, OneWayCompatibilityMappingEntry? y)
+ {
+ if (ReferenceEquals(x, y))
+ {
+ return true;
+ }
+
+ if (ReferenceEquals(x, null)
+ || ReferenceEquals(y, null))
+ {
+ return false;
+ }
+
+ var comparer = FrameworkRangeComparer.Instance;
+
+ return comparer.Equals(x.TargetFrameworkRange, y.TargetFrameworkRange)
+ && comparer.Equals(x.SupportedFrameworkRange, y.SupportedFrameworkRange);
+ }
+
+ public int GetHashCode(OneWayCompatibilityMappingEntry obj)
+ {
+ if (ReferenceEquals(obj, null))
+ {
+ return 0;
+ }
+
+ var combiner = new HashCodeCombiner();
+ var comparer = FrameworkRangeComparer.Instance;
+
+ combiner.AddObject(comparer.GetHashCode(obj.TargetFrameworkRange));
+ combiner.AddObject(comparer.GetHashCode(obj.SupportedFrameworkRange));
+
+ return combiner.CombinedHash;
+ }
+ }
+}
diff --git a/src/Microsoft.TestPlatform.ObjectModel/Nuget.Frameworks/CompatibilityProvider.cs b/src/Microsoft.TestPlatform.ObjectModel/Nuget.Frameworks/CompatibilityProvider.cs
new file mode 100644
index 0000000000..332bb9cf35
--- /dev/null
+++ b/src/Microsoft.TestPlatform.ObjectModel/Nuget.Frameworks/CompatibilityProvider.cs
@@ -0,0 +1,260 @@
+// 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.Concurrent;
+using System.Collections.Generic;
+using System.Linq;
+
+namespace NuGetClone.Frameworks
+{
+ internal class CompatibilityProvider : IFrameworkCompatibilityProvider
+ {
+ private readonly IFrameworkNameProvider _mappings;
+ private readonly FrameworkExpander _expander;
+ private static readonly NuGetFrameworkFullComparer FullComparer = NuGetFrameworkFullComparer.Instance;
+ private readonly ConcurrentDictionary _cache;
+
+ public CompatibilityProvider(IFrameworkNameProvider mappings)
+ {
+ _mappings = mappings ?? throw new ArgumentNullException(nameof(mappings));
+ _expander = new FrameworkExpander(mappings);
+ _cache = new ConcurrentDictionary();
+ }
+
+ ///
+ /// Check if the frameworks are compatible.
+ ///
+ /// Project framework
+ /// Other framework to check against the project framework
+ /// True if framework supports other
+ public bool IsCompatible(NuGetFramework target, NuGetFramework candidate)
+ {
+ if (target == null) throw new ArgumentNullException(nameof(target));
+ if (candidate == null) throw new ArgumentNullException(nameof(candidate));
+
+ // check the cache for a solution
+ var cacheKey = new CompatibilityCacheKey(target, candidate);
+
+ if (!_cache.TryGetValue(cacheKey, out bool result))
+ {
+ result = IsCompatibleCore(target, candidate) == true;
+ _cache.TryAdd(cacheKey, result);
+ }
+
+ return result;
+ }
+
+ ///
+ /// Actual compatibility check without caching
+ ///
+ private bool? IsCompatibleCore(NuGetFramework target, NuGetFramework candidate)
+ {
+ bool? result = null;
+
+ // check if they are the exact same
+ if (FullComparer.Equals(target, candidate))
+ {
+ return true;
+ }
+
+ // special cased frameworks
+ if (!target.IsSpecificFramework
+ || !candidate.IsSpecificFramework)
+ {
+ result = IsSpecialFrameworkCompatible(target, candidate);
+ }
+
+ if (result == null)
+ {
+ if (target.IsPCL || candidate.IsPCL)
+ {
+ // PCL compat logic
+ result = IsPCLCompatible(target, candidate);
+ }
+ else
+ {
+ // regular framework compat check
+ result = IsCompatibleWithTarget(target, candidate);
+ }
+ }
+
+ return result;
+ }
+
+ private bool? IsSpecialFrameworkCompatible(NuGetFramework target, NuGetFramework candidate)
+ {
+ // TODO: Revist these
+ if (target.IsAny
+ || candidate.IsAny)
+ {
+ return true;
+ }
+
+ if (target.IsUnsupported)
+ {
+ return false;
+ }
+
+ if (candidate.IsAgnostic)
+ {
+ return true;
+ }
+
+ if (candidate.IsUnsupported)
+ {
+ return false;
+ }
+
+ return null;
+ }
+
+ private bool IsPCLCompatible(NuGetFramework target, NuGetFramework candidate)
+ {
+ if (target.IsPCL && !candidate.IsPCL)
+ {
+ return IsCompatibleWithTarget(target, candidate);
+ }
+
+ IEnumerable? targetFrameworks;
+ IEnumerable? candidateFrameworks;
+
+ if (target.IsPCL)
+ {
+ // do not include optional frameworks here since we might be unable to tell what is optional on the other framework
+ if (!_mappings.TryGetPortableFrameworks(target.Profile, includeOptional: false, out targetFrameworks))
+ {
+ targetFrameworks = Array.Empty();
+ }
+ }
+ else
+ {
+ targetFrameworks = new NuGetFramework[] { target };
+ }
+
+ if (candidate.IsPCL)
+ {
+ // include optional frameworks here, the larger the list the more compatible it is
+ if (!_mappings.TryGetPortableFrameworks(candidate.Profile, includeOptional: true, out candidateFrameworks))
+ {
+ candidateFrameworks = Array.Empty();
+ }
+ }
+ else
+ {
+ candidateFrameworks = new NuGetFramework[] { candidate };
+ }
+
+ // check if we this is a compatible superset
+ return PCLInnerCompare(targetFrameworks, candidateFrameworks);
+ }
+
+ private bool PCLInnerCompare(IEnumerable targetFrameworks, IEnumerable candidateFrameworks)
+ {
+ // TODO: Does this check need to make sure multiple frameworks aren't matched against a single framework from the other list?
+ return targetFrameworks.Count() <= candidateFrameworks.Count() && targetFrameworks.All(f => candidateFrameworks.Any(ff => IsCompatible(f, ff)));
+ }
+
+ private bool IsCompatibleWithTarget(NuGetFramework target, NuGetFramework candidate)
+ {
+ // find all possible substitutions
+ var targetSet = new List() { target };
+ targetSet.AddRange(_expander.Expand(target));
+
+ var candidateSet = new List() { candidate };
+ candidateSet.AddRange(GetEquivalentFrameworksClosure(candidate));
+
+ // check for compat
+ foreach (var currentCandidate in candidateSet)
+ {
+ if (targetSet.Any(framework => IsCompatibleWithTargetCore(framework, currentCandidate)))
+ {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ private static bool IsCompatibleWithTargetCore(NuGetFramework target, NuGetFramework candidate)
+ {
+ bool result = true;
+ bool isNet6Era = target.IsNet5Era && target.Version.Major >= 6;
+ if (isNet6Era && target.HasPlatform && !NuGetFramework.FrameworkNameComparer.Equals(target, candidate))
+ {
+ if (candidate.Framework.Equals(FrameworkConstants.FrameworkIdentifiers.MonoAndroid, StringComparison.OrdinalIgnoreCase))
+ {
+ result = result && StringComparer.OrdinalIgnoreCase.Equals(target.Platform, "android");
+ }
+ else if (candidate.Framework.Equals(FrameworkConstants.FrameworkIdentifiers.Tizen, StringComparison.OrdinalIgnoreCase))
+ {
+ result = result && StringComparer.OrdinalIgnoreCase.Equals(target.Platform, "tizen");
+ }
+ else
+ {
+ result = false;
+ }
+ }
+ else
+ {
+ result = NuGetFramework.FrameworkNameComparer.Equals(target, candidate)
+ && IsVersionCompatible(target.Version, candidate.Version)
+ && StringComparer.OrdinalIgnoreCase.Equals(target.Profile, candidate.Profile);
+
+ if (target.IsNet5Era && candidate.HasPlatform)
+ {
+ result = result
+ && StringComparer.OrdinalIgnoreCase.Equals(target.Platform, candidate.Platform)
+ && IsVersionCompatible(target.PlatformVersion, candidate.PlatformVersion);
+ }
+ }
+
+
+ return result;
+ }
+
+ private static bool IsVersionCompatible(Version target, Version candidate)
+ {
+ return candidate == FrameworkConstants.EmptyVersion || candidate <= target;
+ }
+
+ ///
+ /// Find all equivalent frameworks, and their equivalent frameworks.
+ /// Example:
+ /// Mappings:
+ /// A <‒> B
+ /// B <‒> C
+ /// C <‒> D
+ /// For A we need to find B, C, and D so we must retrieve equivalent frameworks for A, B, and C
+ /// also as we discover them.
+ ///
+ private IEnumerable GetEquivalentFrameworksClosure(NuGetFramework framework)
+ {
+ // add the current framework to the seen list to avoid returning it later
+ var seen = new HashSet() { framework };
+
+ var toExpand = new Stack();
+ toExpand.Push(framework);
+
+ while (toExpand.Count > 0)
+ {
+ var frameworkToExpand = toExpand.Pop();
+
+ if (_mappings.TryGetEquivalentFrameworks(frameworkToExpand, out IEnumerable? compatibleFrameworks))
+ {
+ foreach (var curFramework in compatibleFrameworks)
+ {
+ if (seen.Add(curFramework))
+ {
+ yield return curFramework;
+
+ toExpand.Push(curFramework);
+ }
+ }
+ }
+ }
+
+ yield break;
+ }
+ }
+}
diff --git a/src/Microsoft.TestPlatform.ObjectModel/Nuget.Frameworks/DefaultCompatibilityProvider.cs b/src/Microsoft.TestPlatform.ObjectModel/Nuget.Frameworks/DefaultCompatibilityProvider.cs
new file mode 100644
index 0000000000..ecc59c3ab2
--- /dev/null
+++ b/src/Microsoft.TestPlatform.ObjectModel/Nuget.Frameworks/DefaultCompatibilityProvider.cs
@@ -0,0 +1,28 @@
+// 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.
+
+namespace NuGetClone.Frameworks
+{
+ internal sealed class DefaultCompatibilityProvider : CompatibilityProvider
+ {
+ public DefaultCompatibilityProvider()
+ : base(DefaultFrameworkNameProvider.Instance)
+ {
+ }
+
+ private static IFrameworkCompatibilityProvider? _instance;
+
+ public static IFrameworkCompatibilityProvider Instance
+ {
+ get
+ {
+ if (_instance == null)
+ {
+ _instance = new DefaultCompatibilityProvider();
+ }
+
+ return _instance;
+ }
+ }
+ }
+}
diff --git a/src/Microsoft.TestPlatform.ObjectModel/Nuget.Frameworks/DefaultFrameworkMappings.cs b/src/Microsoft.TestPlatform.ObjectModel/Nuget.Frameworks/DefaultFrameworkMappings.cs
new file mode 100644
index 0000000000..28d6d26f9b
--- /dev/null
+++ b/src/Microsoft.TestPlatform.ObjectModel/Nuget.Frameworks/DefaultFrameworkMappings.cs
@@ -0,0 +1,664 @@
+// 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;
+using System.Linq;
+
+namespace NuGetClone.Frameworks
+{
+ internal sealed class DefaultFrameworkMappings : IFrameworkMappings
+ {
+ private static Lazy[]> IdentifierSynonymsLazy = new Lazy[]>(() =>
+ {
+ return new[]{
+ // .NET
+ new KeyValuePair("NETFramework", FrameworkConstants.FrameworkIdentifiers.Net),
+ new KeyValuePair(".NET", FrameworkConstants.FrameworkIdentifiers.Net),
+
+ // .NET Core
+ new KeyValuePair("NETCore", FrameworkConstants.FrameworkIdentifiers.NetCore),
+
+ // Portable
+ new KeyValuePair("NETPortable", FrameworkConstants.FrameworkIdentifiers.Portable),
+
+ // ASP
+ new KeyValuePair("asp.net", FrameworkConstants.FrameworkIdentifiers.AspNet),
+ new KeyValuePair("asp.netcore", FrameworkConstants.FrameworkIdentifiers.AspNetCore),
+
+ // Mono/Xamarin
+ new KeyValuePair("Xamarin.PlayStationThree", FrameworkConstants.FrameworkIdentifiers.XamarinPlayStation3),
+ new KeyValuePair("XamarinPlayStationThree", FrameworkConstants.FrameworkIdentifiers.XamarinPlayStation3),
+ new KeyValuePair("Xamarin.PlayStationFour", FrameworkConstants.FrameworkIdentifiers.XamarinPlayStation4),
+ new KeyValuePair("XamarinPlayStationFour", FrameworkConstants.FrameworkIdentifiers.XamarinPlayStation4),
+ new KeyValuePair("XamarinPlayStationVita", FrameworkConstants.FrameworkIdentifiers.XamarinPlayStationVita),
+ };
+ });
+
+ public IEnumerable> IdentifierSynonyms
+ {
+ get
+ {
+ return IdentifierSynonymsLazy.Value;
+ }
+ }
+
+ private static readonly Lazy[]> IdentifierShortNamesLazy = new Lazy[]>(() =>
+ {
+ return new[]
+ {
+ new KeyValuePair(FrameworkConstants.FrameworkIdentifiers.NetCoreApp, "netcoreapp"),
+ new KeyValuePair(FrameworkConstants.FrameworkIdentifiers.NetStandardApp, "netstandardapp"),
+ new KeyValuePair(FrameworkConstants.FrameworkIdentifiers.NetStandard, "netstandard"),
+ new KeyValuePair(FrameworkConstants.FrameworkIdentifiers.NetPlatform, "dotnet"),
+ new KeyValuePair(FrameworkConstants.FrameworkIdentifiers.Net, "net"),
+ new KeyValuePair(FrameworkConstants.FrameworkIdentifiers.NetMicro, "netmf"),
+ new KeyValuePair(FrameworkConstants.FrameworkIdentifiers.Silverlight, "sl"),
+ new KeyValuePair(FrameworkConstants.FrameworkIdentifiers.Portable, "portable"),
+ new KeyValuePair(FrameworkConstants.FrameworkIdentifiers.WindowsPhone, "wp"),
+ new KeyValuePair(FrameworkConstants.FrameworkIdentifiers.WindowsPhoneApp, "wpa"),
+ new KeyValuePair(FrameworkConstants.FrameworkIdentifiers.Windows, "win"),
+ new KeyValuePair(FrameworkConstants.FrameworkIdentifiers.AspNet, "aspnet"),
+ new KeyValuePair(FrameworkConstants.FrameworkIdentifiers.AspNetCore, "aspnetcore"),
+ new KeyValuePair(FrameworkConstants.FrameworkIdentifiers.Native, "native"),
+ new KeyValuePair(FrameworkConstants.FrameworkIdentifiers.MonoAndroid, "monoandroid"),
+ new KeyValuePair(FrameworkConstants.FrameworkIdentifiers.MonoTouch, "monotouch"),
+ new KeyValuePair(FrameworkConstants.FrameworkIdentifiers.MonoMac, "monomac"),
+ new KeyValuePair(FrameworkConstants.FrameworkIdentifiers.XamarinIOs, "xamarinios"),
+ new KeyValuePair(FrameworkConstants.FrameworkIdentifiers.XamarinMac, "xamarinmac"),
+ new KeyValuePair(FrameworkConstants.FrameworkIdentifiers.XamarinPlayStation3, "xamarinpsthree"),
+ new KeyValuePair(FrameworkConstants.FrameworkIdentifiers.XamarinPlayStation4, "xamarinpsfour"),
+ new KeyValuePair(FrameworkConstants.FrameworkIdentifiers.XamarinPlayStationVita, "xamarinpsvita"),
+ new KeyValuePair(FrameworkConstants.FrameworkIdentifiers.XamarinWatchOS, "xamarinwatchos"),
+ new KeyValuePair(FrameworkConstants.FrameworkIdentifiers.XamarinTVOS, "xamarintvos"),
+ new KeyValuePair(FrameworkConstants.FrameworkIdentifiers.XamarinXbox360, "xamarinxboxthreesixty"),
+ new KeyValuePair(FrameworkConstants.FrameworkIdentifiers.XamarinXboxOne, "xamarinxboxone"),
+ new KeyValuePair(FrameworkConstants.FrameworkIdentifiers.Dnx, "dnx"),
+ new KeyValuePair(FrameworkConstants.FrameworkIdentifiers.DnxCore, "dnxcore"),
+ new KeyValuePair(FrameworkConstants.FrameworkIdentifiers.NetCore, "netcore"),
+ new KeyValuePair(FrameworkConstants.FrameworkIdentifiers.WinRT, "winrt"), // legacy
+ new KeyValuePair(FrameworkConstants.FrameworkIdentifiers.UAP, "uap"),
+ new KeyValuePair(FrameworkConstants.FrameworkIdentifiers.Tizen, "tizen"),
+ new KeyValuePair(FrameworkConstants.FrameworkIdentifiers.NanoFramework, "netnano"),
+ };
+ });
+
+ public IEnumerable> IdentifierShortNames
+ {
+ get
+ {
+ return IdentifierShortNamesLazy.Value;
+ }
+ }
+
+ private static readonly Lazy ProfileShortNamesLazy = new Lazy(() =>
+ {
+ return new[]
+ {
+ new FrameworkSpecificMapping(FrameworkConstants.FrameworkIdentifiers.Net, "Client", "Client"),
+ new FrameworkSpecificMapping(FrameworkConstants.FrameworkIdentifiers.Net, "CF", "CompactFramework"),
+ new FrameworkSpecificMapping(FrameworkConstants.FrameworkIdentifiers.Net, "Full", string.Empty),
+ new FrameworkSpecificMapping(FrameworkConstants.FrameworkIdentifiers.Silverlight, "WP", "WindowsPhone"),
+ new FrameworkSpecificMapping(FrameworkConstants.FrameworkIdentifiers.Silverlight, "WP71", "WindowsPhone71"),
+ };
+ });
+
+ public IEnumerable ProfileShortNames
+ {
+ get
+ {
+ return ProfileShortNamesLazy.Value;
+ }
+ }
+
+ private static readonly Lazy[]> EquivalentFrameworksLazy = new Lazy[]>(() =>
+ {
+ return new[]
+ {
+ // UAP 0.0 <-> UAP 10.0
+ new KeyValuePair(
+ new NuGetFramework(FrameworkConstants.FrameworkIdentifiers.UAP, FrameworkConstants.EmptyVersion),
+ FrameworkConstants.CommonFrameworks.UAP10),
+
+ // win <-> win8
+ new KeyValuePair(
+ new NuGetFramework(FrameworkConstants.FrameworkIdentifiers.Windows, FrameworkConstants.EmptyVersion),
+ FrameworkConstants.CommonFrameworks.Win8),
+
+ // win8 <-> netcore45
+ new KeyValuePair(
+ FrameworkConstants.CommonFrameworks.Win8,
+ new NuGetFramework(FrameworkConstants.FrameworkIdentifiers.NetCore, new Version(4, 5, 0, 0))),
+
+ // netcore45 <-> winrt45
+ new KeyValuePair(
+ new NuGetFramework(FrameworkConstants.FrameworkIdentifiers.NetCore, new Version(4, 5, 0, 0)),
+ new NuGetFramework(FrameworkConstants.FrameworkIdentifiers.WinRT, new Version(4, 5, 0, 0))),
+
+ // netcore <-> netcore45
+ new KeyValuePair(
+ new NuGetFramework(FrameworkConstants.FrameworkIdentifiers.NetCore, FrameworkConstants.EmptyVersion),
+ new NuGetFramework(FrameworkConstants.FrameworkIdentifiers.NetCore, new Version(4, 5, 0, 0))),
+
+ // winrt <-> winrt45
+ new KeyValuePair(
+ new NuGetFramework(FrameworkConstants.FrameworkIdentifiers.WinRT, FrameworkConstants.EmptyVersion),
+ new NuGetFramework(FrameworkConstants.FrameworkIdentifiers.WinRT, new Version(4, 5, 0, 0))),
+
+ // win81 <-> netcore451
+ new KeyValuePair(
+ FrameworkConstants.CommonFrameworks.Win81,
+ new NuGetFramework(FrameworkConstants.FrameworkIdentifiers.NetCore, new Version(4, 5, 1, 0))),
+
+ // wp <-> wp7
+ new KeyValuePair(
+ new NuGetFramework(FrameworkConstants.FrameworkIdentifiers.WindowsPhone, FrameworkConstants.EmptyVersion),
+ FrameworkConstants.CommonFrameworks.WP7),
+
+ // wp7 <-> f:sl3-wp
+ new KeyValuePair(
+ FrameworkConstants.CommonFrameworks.WP7,
+ new NuGetFramework(FrameworkConstants.FrameworkIdentifiers.Silverlight, new Version(3, 0, 0, 0), "WindowsPhone")),
+
+ // wp71 <-> f:sl4-wp71
+ new KeyValuePair(
+ new NuGetFramework(FrameworkConstants.FrameworkIdentifiers.WindowsPhone, new Version(7, 1, 0, 0)),
+ new NuGetFramework(FrameworkConstants.FrameworkIdentifiers.Silverlight, new Version(4, 0, 0, 0), "WindowsPhone71")),
+
+ // wp8 <-> f:sl8-wp
+ new KeyValuePair(
+ FrameworkConstants.CommonFrameworks.WP8,
+ new NuGetFramework(FrameworkConstants.FrameworkIdentifiers.Silverlight, new Version(8, 0, 0, 0), "WindowsPhone")),
+
+ // wp81 <-> f:sl81-wp
+ new KeyValuePair(
+ FrameworkConstants.CommonFrameworks.WP81,
+ new NuGetFramework(FrameworkConstants.FrameworkIdentifiers.Silverlight, new Version(8, 1, 0, 0), "WindowsPhone")),
+
+ // wpa <-> wpa81
+ new KeyValuePair(
+ new NuGetFramework(FrameworkConstants.FrameworkIdentifiers.WindowsPhoneApp, FrameworkConstants.EmptyVersion),
+ FrameworkConstants.CommonFrameworks.WPA81),
+
+ // tizen <-> tizen3
+ new KeyValuePair(
+ new NuGetFramework(FrameworkConstants.FrameworkIdentifiers.Tizen, FrameworkConstants.EmptyVersion),
+ FrameworkConstants.CommonFrameworks.Tizen3),
+
+ // dnx <-> dnx45
+ new KeyValuePair(
+ FrameworkConstants.CommonFrameworks.Dnx,
+ FrameworkConstants.CommonFrameworks.Dnx45),
+
+ // dnxcore <-> dnxcore50
+ new KeyValuePair(
+ FrameworkConstants.CommonFrameworks.DnxCore,
+ FrameworkConstants.CommonFrameworks.DnxCore50),
+
+ // dotnet <-> dotnet50
+ new KeyValuePair(
+ FrameworkConstants.CommonFrameworks.DotNet,
+ FrameworkConstants.CommonFrameworks.DotNet50),
+
+ // TODO: remove these rules post-RC
+ // aspnet <-> aspnet50
+ new KeyValuePair(
+ FrameworkConstants.CommonFrameworks.AspNet,
+ FrameworkConstants.CommonFrameworks.AspNet50),
+
+ // aspnetcore <-> aspnetcore50
+ new KeyValuePair(
+ FrameworkConstants.CommonFrameworks.AspNetCore,
+ FrameworkConstants.CommonFrameworks.AspNetCore50),
+
+ // dnx451 <-> aspnet50
+ new KeyValuePair(
+ FrameworkConstants.CommonFrameworks.Dnx45,
+ FrameworkConstants.CommonFrameworks.AspNet50),
+
+ // dnxcore50 <-> aspnetcore50
+ new KeyValuePair(
+ FrameworkConstants.CommonFrameworks.DnxCore50,
+ FrameworkConstants.CommonFrameworks.AspNetCore50),
+ };
+ });
+
+ public IEnumerable> EquivalentFrameworks
+ {
+ get
+ {
+ return EquivalentFrameworksLazy.Value;
+ }
+ }
+
+ private static readonly Lazy EquivalentProfilesLazy = new Lazy(() =>
+ {
+ return new[]
+ {
+ // The client profile, for the purposes of NuGet, is the same as the full framework
+ new FrameworkSpecificMapping(FrameworkConstants.FrameworkIdentifiers.Net, "Client", string.Empty),
+ new FrameworkSpecificMapping(FrameworkConstants.FrameworkIdentifiers.Net, "Full", string.Empty),
+ new FrameworkSpecificMapping(FrameworkConstants.FrameworkIdentifiers.Silverlight, "WindowsPhone71", "WindowsPhone"),
+ new FrameworkSpecificMapping(FrameworkConstants.FrameworkIdentifiers.WindowsPhone, "WindowsPhone71", "WindowsPhone"),
+ };
+ });
+
+ public IEnumerable EquivalentProfiles
+ {
+ get
+ {
+ return EquivalentProfilesLazy.Value;
+ }
+ }
+
+ private static readonly Lazy[]> SubSetFrameworksLazy = new Lazy[]>(() =>
+ {
+ return new[]
+ {
+ // .NET is a subset of DNX
+ new KeyValuePair(
+ FrameworkConstants.FrameworkIdentifiers.Net,
+ FrameworkConstants.FrameworkIdentifiers.Dnx),
+
+ // NetPlatform is a subset of DNXCore
+ new KeyValuePair(
+ FrameworkConstants.FrameworkIdentifiers.NetPlatform,
+ FrameworkConstants.FrameworkIdentifiers.DnxCore),
+
+ // NetStandard is a subset of NetStandardApp
+ new KeyValuePair(
+ FrameworkConstants.FrameworkIdentifiers.NetStandard,
+ FrameworkConstants.FrameworkIdentifiers.NetStandardApp)
+ };
+ });
+
+ public IEnumerable> SubSetFrameworks
+ {
+ get
+ {
+ return SubSetFrameworksLazy.Value;
+ }
+ }
+
+ private static readonly Lazy CompatibilityMappingsLazy = new Lazy(() =>
+ {
+ return new[]
+ {
+ // UAP supports Win81
+ new OneWayCompatibilityMappingEntry(new FrameworkRange(
+ new NuGetFramework(FrameworkConstants.FrameworkIdentifiers.UAP, FrameworkConstants.EmptyVersion),
+ new NuGetFramework(FrameworkConstants.FrameworkIdentifiers.UAP, FrameworkConstants.MaxVersion)),
+ new FrameworkRange(
+ new NuGetFramework(FrameworkConstants.FrameworkIdentifiers.Windows, FrameworkConstants.EmptyVersion),
+ new NuGetFramework(FrameworkConstants.FrameworkIdentifiers.Windows, new Version(8, 1, 0, 0)))),
+
+ // UAP supports WPA81
+ new OneWayCompatibilityMappingEntry(new FrameworkRange(
+ new NuGetFramework(FrameworkConstants.FrameworkIdentifiers.UAP, FrameworkConstants.EmptyVersion),
+ new NuGetFramework(FrameworkConstants.FrameworkIdentifiers.UAP, FrameworkConstants.MaxVersion)),
+ new FrameworkRange(
+ new NuGetFramework(FrameworkConstants.FrameworkIdentifiers.WindowsPhoneApp, FrameworkConstants.EmptyVersion),
+ new NuGetFramework(FrameworkConstants.FrameworkIdentifiers.WindowsPhoneApp, new Version(8, 1, 0, 0)))),
+
+ // UAP supports NetCore50
+ new OneWayCompatibilityMappingEntry(new FrameworkRange(
+ new NuGetFramework(FrameworkConstants.FrameworkIdentifiers.UAP, FrameworkConstants.EmptyVersion),
+ new NuGetFramework(FrameworkConstants.FrameworkIdentifiers.UAP, FrameworkConstants.MaxVersion)),
+ new FrameworkRange(
+ new NuGetFramework(FrameworkConstants.FrameworkIdentifiers.NetCore, FrameworkConstants.Version5),
+ new NuGetFramework(FrameworkConstants.FrameworkIdentifiers.NetCore, FrameworkConstants.Version5))),
+
+ // Win projects support WinRT
+ new OneWayCompatibilityMappingEntry(new FrameworkRange(
+ new NuGetFramework(FrameworkConstants.FrameworkIdentifiers.Windows, FrameworkConstants.EmptyVersion),
+ new NuGetFramework(FrameworkConstants.FrameworkIdentifiers.Windows, FrameworkConstants.MaxVersion)),
+ new FrameworkRange(
+ new NuGetFramework(FrameworkConstants.FrameworkIdentifiers.WinRT, FrameworkConstants.EmptyVersion),
+ new NuGetFramework(FrameworkConstants.FrameworkIdentifiers.WinRT, new Version(4, 5, 0, 0)))),
+
+ // Tizen3 projects support NETStandard1.6
+ CreateStandardMapping(
+ FrameworkConstants.CommonFrameworks.Tizen3,
+ FrameworkConstants.CommonFrameworks.NetStandard16),
+
+ // Tizen4 projects support NETStandard2.0
+ CreateStandardMapping(
+ FrameworkConstants.CommonFrameworks.Tizen4,
+ FrameworkConstants.CommonFrameworks.NetStandard20),
+
+ // Tizen6 projects support NETStandard2.1
+ CreateStandardMapping(
+ FrameworkConstants.CommonFrameworks.Tizen6,
+ FrameworkConstants.CommonFrameworks.NetStandard21),
+
+ // UAP 10.0.15064.0 projects support NETStandard2.0
+ CreateStandardMapping(
+ new NuGetFramework(FrameworkConstants.FrameworkIdentifiers.UAP, new Version(10, 0, 15064, 0)),
+ FrameworkConstants.CommonFrameworks.NetStandard20),
+
+ // NetCoreApp1.0 projects support NetStandard1.6
+ CreateStandardMapping(
+ FrameworkConstants.CommonFrameworks.NetCoreApp10,
+ FrameworkConstants.CommonFrameworks.NetStandard16),
+
+ // NetCoreApp1.1 projects support NetStandard1.7
+ CreateStandardMapping(
+ FrameworkConstants.CommonFrameworks.NetCoreApp11,
+ FrameworkConstants.CommonFrameworks.NetStandard17),
+
+ // NetCoreApp2.0 projects support NetStandard2.0
+ CreateStandardMapping(
+ FrameworkConstants.CommonFrameworks.NetCoreApp20,
+ FrameworkConstants.CommonFrameworks.NetStandard20),
+
+ // NetCoreApp3.0 projects support NetStandard2.1
+ CreateStandardMapping(
+ FrameworkConstants.CommonFrameworks.NetCoreApp30,
+ FrameworkConstants.CommonFrameworks.NetStandard21),
+
+ // net463 projects support NetStandard2.0
+ CreateStandardMapping(
+ FrameworkConstants.CommonFrameworks.Net463,
+ FrameworkConstants.CommonFrameworks.NetStandard20)
+ }
+ .Concat(new[]
+ {
+ // dnxcore50 -> dotnet5.6, netstandard1.5
+ CreateGenerationAndStandardMappingForAllVersions(
+ FrameworkConstants.FrameworkIdentifiers.DnxCore,
+ FrameworkConstants.CommonFrameworks.DotNet56,
+ FrameworkConstants.CommonFrameworks.NetStandard15),
+
+ // uap -> dotnet5.5, netstandard1.4
+ CreateGenerationAndStandardMappingForAllVersions(
+ FrameworkConstants.FrameworkIdentifiers.UAP,
+ FrameworkConstants.CommonFrameworks.DotNet55,
+ FrameworkConstants.CommonFrameworks.NetStandard14),
+
+ // netcore50 -> dotnet5.5, netstandard1.4
+ CreateGenerationAndStandardMapping(
+ FrameworkConstants.CommonFrameworks.NetCore50,
+ FrameworkConstants.CommonFrameworks.DotNet55,
+ FrameworkConstants.CommonFrameworks.NetStandard14),
+
+ // wpa81 -> dotnet5.3, netstandard1.2
+ CreateGenerationAndStandardMapping(
+ FrameworkConstants.CommonFrameworks.WPA81,
+ FrameworkConstants.CommonFrameworks.DotNet53,
+ FrameworkConstants.CommonFrameworks.NetStandard12),
+
+ // wp8, wp81 -> dotnet5.1, netstandard1.0
+ CreateGenerationAndStandardMapping(
+ FrameworkConstants.CommonFrameworks.WP8,
+ FrameworkConstants.CommonFrameworks.DotNet51,
+ FrameworkConstants.CommonFrameworks.NetStandard10),
+
+ // net45 -> dotnet5.2, netstandard1.1
+ CreateGenerationAndStandardMapping(
+ FrameworkConstants.CommonFrameworks.Net45,
+ FrameworkConstants.CommonFrameworks.DotNet52,
+ FrameworkConstants.CommonFrameworks.NetStandard11),
+
+ // net451 -> dotnet5.3, netstandard1.2
+ CreateGenerationAndStandardMapping(
+ FrameworkConstants.CommonFrameworks.Net451,
+ FrameworkConstants.CommonFrameworks.DotNet53,
+ FrameworkConstants.CommonFrameworks.NetStandard12),
+
+ // net46 -> dotnet5.4, netstandard1.3
+ CreateGenerationAndStandardMapping(
+ FrameworkConstants.CommonFrameworks.Net46,
+ FrameworkConstants.CommonFrameworks.DotNet54,
+ FrameworkConstants.CommonFrameworks.NetStandard13),
+
+ // net461 -> dotnet5.5, netstandard2.0
+ CreateGenerationAndStandardMapping(
+ FrameworkConstants.CommonFrameworks.Net461,
+ FrameworkConstants.CommonFrameworks.DotNet55,
+ FrameworkConstants.CommonFrameworks.NetStandard20),
+
+ // net462 -> dotnet5.6, netstandard2.0
+ CreateGenerationAndStandardMapping(
+ FrameworkConstants.CommonFrameworks.Net462,
+ FrameworkConstants.CommonFrameworks.DotNet56,
+ FrameworkConstants.CommonFrameworks.NetStandard20),
+
+ // netcore45 -> dotnet5.2, netstandard1.1
+ CreateGenerationAndStandardMapping(
+ FrameworkConstants.CommonFrameworks.NetCore45,
+ FrameworkConstants.CommonFrameworks.DotNet52,
+ FrameworkConstants.CommonFrameworks.NetStandard11),
+
+ // netcore451 -> dotnet5.3, netstandard1.2
+ CreateGenerationAndStandardMapping(
+ FrameworkConstants.CommonFrameworks.NetCore451,
+ FrameworkConstants.CommonFrameworks.DotNet53,
+ FrameworkConstants.CommonFrameworks.NetStandard12),
+
+ // xamarin frameworks
+ CreateGenerationAndStandardMappingForAllVersions(
+ FrameworkConstants.FrameworkIdentifiers.MonoAndroid,
+ FrameworkConstants.CommonFrameworks.DotNet56,
+ FrameworkConstants.CommonFrameworks.NetStandard21),
+
+ CreateGenerationAndStandardMappingForAllVersions(
+ FrameworkConstants.FrameworkIdentifiers.MonoMac,
+ FrameworkConstants.CommonFrameworks.DotNet56,
+ FrameworkConstants.CommonFrameworks.NetStandard21),
+
+ CreateGenerationAndStandardMappingForAllVersions(
+ FrameworkConstants.FrameworkIdentifiers.MonoTouch,
+ FrameworkConstants.CommonFrameworks.DotNet56,
+ FrameworkConstants.CommonFrameworks.NetStandard21),
+
+ CreateGenerationAndStandardMappingForAllVersions(
+ FrameworkConstants.FrameworkIdentifiers.XamarinIOs,
+ FrameworkConstants.CommonFrameworks.DotNet56,
+ FrameworkConstants.CommonFrameworks.NetStandard21),
+
+ CreateGenerationAndStandardMappingForAllVersions(
+ FrameworkConstants.FrameworkIdentifiers.XamarinMac,
+ FrameworkConstants.CommonFrameworks.DotNet56,
+ FrameworkConstants.CommonFrameworks.NetStandard21),
+
+ CreateGenerationAndStandardMappingForAllVersions(
+ FrameworkConstants.FrameworkIdentifiers.XamarinPlayStation3,
+ FrameworkConstants.CommonFrameworks.DotNet56,
+ FrameworkConstants.CommonFrameworks.NetStandard20),
+
+ CreateGenerationAndStandardMappingForAllVersions(
+ FrameworkConstants.FrameworkIdentifiers.XamarinPlayStation4,
+ FrameworkConstants.CommonFrameworks.DotNet56,
+ FrameworkConstants.CommonFrameworks.NetStandard20),
+
+ CreateGenerationAndStandardMappingForAllVersions(
+ FrameworkConstants.FrameworkIdentifiers.XamarinPlayStationVita,
+ FrameworkConstants.CommonFrameworks.DotNet56,
+ FrameworkConstants.CommonFrameworks.NetStandard20),
+
+ CreateGenerationAndStandardMappingForAllVersions(
+ FrameworkConstants.FrameworkIdentifiers.XamarinXbox360,
+ FrameworkConstants.CommonFrameworks.DotNet56,
+ FrameworkConstants.CommonFrameworks.NetStandard20),
+
+ CreateGenerationAndStandardMappingForAllVersions(
+ FrameworkConstants.FrameworkIdentifiers.XamarinXboxOne,
+ FrameworkConstants.CommonFrameworks.DotNet56,
+ FrameworkConstants.CommonFrameworks.NetStandard20),
+
+ CreateGenerationAndStandardMappingForAllVersions(
+ FrameworkConstants.FrameworkIdentifiers.XamarinTVOS,
+ FrameworkConstants.CommonFrameworks.DotNet56,
+ FrameworkConstants.CommonFrameworks.NetStandard21),
+
+ CreateGenerationAndStandardMappingForAllVersions(
+ FrameworkConstants.FrameworkIdentifiers.XamarinWatchOS,
+ FrameworkConstants.CommonFrameworks.DotNet56,
+ FrameworkConstants.CommonFrameworks.NetStandard21)
+ }.SelectMany(mappings => mappings))
+ .ToArray();
+ });
+
+ public IEnumerable CompatibilityMappings
+ {
+ get
+ {
+ return CompatibilityMappingsLazy.Value;
+ }
+ }
+
+ private static OneWayCompatibilityMappingEntry CreateGenerationMapping(
+ NuGetFramework framework,
+ NuGetFramework netPlatform)
+ {
+ return new OneWayCompatibilityMappingEntry(
+ new FrameworkRange(
+ framework,
+ new NuGetFramework(framework.Framework, FrameworkConstants.MaxVersion)),
+ new FrameworkRange(
+ FrameworkConstants.CommonFrameworks.DotNet,
+ netPlatform));
+ }
+
+ private static OneWayCompatibilityMappingEntry CreateStandardMapping(
+ NuGetFramework framework,
+ NuGetFramework netPlatform)
+ {
+ return new OneWayCompatibilityMappingEntry(
+ new FrameworkRange(
+ framework,
+ new NuGetFramework(framework.Framework, FrameworkConstants.MaxVersion)),
+ new FrameworkRange(
+ FrameworkConstants.CommonFrameworks.NetStandard10,
+ netPlatform));
+ }
+
+ private static IEnumerable CreateGenerationAndStandardMapping(
+ NuGetFramework framework,
+ NuGetFramework netPlatform,
+ NuGetFramework netStandard)
+ {
+ yield return CreateGenerationMapping(framework, netPlatform);
+ yield return CreateStandardMapping(framework, netStandard);
+ }
+
+ private static IEnumerable CreateGenerationAndStandardMappingForAllVersions(
+ string framework,
+ NuGetFramework netPlatform,
+ NuGetFramework netStandard)
+ {
+ var lowestFramework = new NuGetFramework(framework, FrameworkConstants.EmptyVersion);
+ return CreateGenerationAndStandardMapping(lowestFramework, netPlatform, netStandard);
+ }
+
+ private static readonly Lazy NonPackageBasedFrameworkPrecedenceLazy = new Lazy(() =>
+ {
+ return new[]
+ {
+ FrameworkConstants.FrameworkIdentifiers.Net,
+ FrameworkConstants.FrameworkIdentifiers.NetCore,
+ FrameworkConstants.FrameworkIdentifiers.Windows,
+ FrameworkConstants.FrameworkIdentifiers.WindowsPhoneApp
+ };
+ });
+
+ public IEnumerable NonPackageBasedFrameworkPrecedence
+ {
+ get
+ {
+ return NonPackageBasedFrameworkPrecedenceLazy.Value;
+ }
+ }
+
+ private static readonly Lazy PackageBasedFrameworkPrecedenceLazy = new Lazy(() =>
+ {
+ return new[]
+ {
+ FrameworkConstants.FrameworkIdentifiers.NetCoreApp,
+ FrameworkConstants.FrameworkIdentifiers.NetStandardApp,
+ FrameworkConstants.FrameworkIdentifiers.NetStandard,
+ FrameworkConstants.FrameworkIdentifiers.NetPlatform
+ };
+ });
+
+ public IEnumerable PackageBasedFrameworkPrecedence
+ {
+ get
+ {
+ return PackageBasedFrameworkPrecedenceLazy.Value;
+ }
+ }
+
+ private static readonly Lazy EquivalentFrameworkPrecedenceLazy = new Lazy(() =>
+ {
+ return new[]
+ {
+ FrameworkConstants.FrameworkIdentifiers.Windows,
+ FrameworkConstants.FrameworkIdentifiers.NetCore,
+ FrameworkConstants.FrameworkIdentifiers.WinRT,
+
+ FrameworkConstants.FrameworkIdentifiers.WindowsPhone,
+ FrameworkConstants.FrameworkIdentifiers.Silverlight,
+
+ FrameworkConstants.FrameworkIdentifiers.DnxCore,
+ FrameworkConstants.FrameworkIdentifiers.AspNetCore,
+
+ FrameworkConstants.FrameworkIdentifiers.Dnx,
+ FrameworkConstants.FrameworkIdentifiers.AspNet
+ };
+ });
+
+ public IEnumerable EquivalentFrameworkPrecedence
+ {
+ get
+ {
+ return EquivalentFrameworkPrecedenceLazy.Value;
+ }
+ }
+
+ private static readonly Lazy[]> ShortNameReplacementsLazy = new Lazy[]>(() =>
+ {
+ return new[]
+ {
+ new KeyValuePair(FrameworkConstants.CommonFrameworks.DotNet50, FrameworkConstants.CommonFrameworks.DotNet)
+ };
+ });
+
+ public IEnumerable> ShortNameReplacements
+ {
+ get
+ {
+ return ShortNameReplacementsLazy.Value;
+ }
+ }
+
+ private static readonly Lazy[]> FullNameReplacementsLazy = new Lazy[]>(() =>
+ {
+ return new[]
+ {
+ new KeyValuePair(FrameworkConstants.CommonFrameworks.DotNet, FrameworkConstants.CommonFrameworks.DotNet50)
+ };
+ });
+
+ public IEnumerable> FullNameReplacements
+ {
+ get
+ {
+ return FullNameReplacementsLazy.Value;
+ }
+ }
+
+ private static readonly Lazy InstanceLazy = new Lazy(() => new DefaultFrameworkMappings());
+
+ ///
+ /// Singleton instance of the default framework mappings.
+ ///
+ public static IFrameworkMappings Instance
+ {
+ get
+ {
+ return InstanceLazy.Value;
+ }
+ }
+ }
+}
diff --git a/src/Microsoft.TestPlatform.ObjectModel/Nuget.Frameworks/DefaultFrameworkNameProvider.cs b/src/Microsoft.TestPlatform.ObjectModel/Nuget.Frameworks/DefaultFrameworkNameProvider.cs
new file mode 100644
index 0000000000..9bf5f12ecb
--- /dev/null
+++ b/src/Microsoft.TestPlatform.ObjectModel/Nuget.Frameworks/DefaultFrameworkNameProvider.cs
@@ -0,0 +1,23 @@
+// 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;
+
+namespace NuGetClone.Frameworks
+{
+ internal sealed class DefaultFrameworkNameProvider : FrameworkNameProvider
+ {
+ public DefaultFrameworkNameProvider()
+ : base(new IFrameworkMappings[] { DefaultFrameworkMappings.Instance },
+ new IPortableFrameworkMappings[] { DefaultPortableFrameworkMappings.Instance })
+ {
+ }
+
+ private static readonly Lazy InstanceLazy = new Lazy(() => new DefaultFrameworkNameProvider());
+
+ public static IFrameworkNameProvider Instance
+ {
+ get { return InstanceLazy.Value; }
+ }
+ }
+}
diff --git a/src/Microsoft.TestPlatform.ObjectModel/Nuget.Frameworks/DefaultPortableFrameworkMappings.cs b/src/Microsoft.TestPlatform.ObjectModel/Nuget.Frameworks/DefaultPortableFrameworkMappings.cs
new file mode 100644
index 0000000000..79b79a204d
--- /dev/null
+++ b/src/Microsoft.TestPlatform.ObjectModel/Nuget.Frameworks/DefaultPortableFrameworkMappings.cs
@@ -0,0 +1,186 @@
+// 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 NuGetClone.Frameworks
+{
+ ///
+ /// Contains the standard portable framework mappings
+ ///
+ internal class DefaultPortableFrameworkMappings : IPortableFrameworkMappings
+ {
+
+ private static readonly Lazy[]> ProfileFrameworksLazy = new Lazy[]>(() =>
+ {
+ var net4 = FrameworkConstants.CommonFrameworks.Net4;
+ var net403 = FrameworkConstants.CommonFrameworks.Net403;
+ var net45 = FrameworkConstants.CommonFrameworks.Net45;
+ var net451 = FrameworkConstants.CommonFrameworks.Net451;
+
+ var win8 = FrameworkConstants.CommonFrameworks.Win8;
+ var win81 = FrameworkConstants.CommonFrameworks.Win81;
+
+ var sl4 = FrameworkConstants.CommonFrameworks.SL4;
+ var sl5 = FrameworkConstants.CommonFrameworks.SL5;
+
+ var wp7 = FrameworkConstants.CommonFrameworks.WP7;
+ var wp75 = FrameworkConstants.CommonFrameworks.WP75;
+ var wp8 = FrameworkConstants.CommonFrameworks.WP8;
+ var wp81 = FrameworkConstants.CommonFrameworks.WP81;
+
+ var wpa81 = FrameworkConstants.CommonFrameworks.WPA81;
+
+ return new[]
+ {
+ // v4.6
+ CreateProfileFrameworks(31, win81, wp81),
+ CreateProfileFrameworks(32, win81, wpa81),
+ CreateProfileFrameworks(44, net451, win81),
+ CreateProfileFrameworks(84, wp81, wpa81),
+ CreateProfileFrameworks(151, net451, win81, wpa81),
+ CreateProfileFrameworks(157, win81, wp81, wpa81),
+
+ // v4.5
+ CreateProfileFrameworks(7, net45, win8),
+ CreateProfileFrameworks(49, net45, wp8),
+ CreateProfileFrameworks(78, net45, win8, wp8),
+ CreateProfileFrameworks(111, net45, win8, wpa81),
+ CreateProfileFrameworks(259, net45, win8, wpa81, wp8),
+
+ // v4.0
+ CreateProfileFrameworks(2, net4, win8, sl4, wp7),
+ CreateProfileFrameworks(3, net4, sl4),
+ CreateProfileFrameworks(4, net45, sl4, win8, wp7),
+ CreateProfileFrameworks(5, net4, win8),
+ CreateProfileFrameworks(6, net403, win8),
+ CreateProfileFrameworks(14, net4, sl5),
+ CreateProfileFrameworks(18, net403, sl4),
+ CreateProfileFrameworks(19, net403, sl5),
+ CreateProfileFrameworks(23, net45, sl4),
+ CreateProfileFrameworks(24, net45, sl5),
+ CreateProfileFrameworks(36, net4, sl4, win8, wp8),
+ CreateProfileFrameworks(37, net4, sl5, win8),
+ CreateProfileFrameworks(41, net403, sl4, win8),
+ CreateProfileFrameworks(42, net403, sl5, win8),
+ CreateProfileFrameworks(46, net45, sl4, win8),
+ CreateProfileFrameworks(47, net45, sl5, win8),
+ CreateProfileFrameworks(88, net4, sl4, win8, wp75),
+ CreateProfileFrameworks(92, net4, win8, wpa81),
+ CreateProfileFrameworks(95, net403, sl4, win8, wp7),
+ CreateProfileFrameworks(96, net403, sl4, win8, wp75),
+ CreateProfileFrameworks(102, net403, win8, wpa81),
+ CreateProfileFrameworks(104, net45, sl4, win8, wp75),
+ CreateProfileFrameworks(136, net4, sl5, win8, wp8),
+ CreateProfileFrameworks(143, net403, sl4, win8, wp8),
+ CreateProfileFrameworks(147, net403, sl5, win8, wp8),
+ CreateProfileFrameworks(154, net45, sl4, win8, wp8),
+ CreateProfileFrameworks(158, net45, sl5, win8, wp8),
+ CreateProfileFrameworks(225, net4, sl5, win8, wpa81),
+ CreateProfileFrameworks(240, net403, sl5, win8, wpa81),
+ CreateProfileFrameworks(255, net45, sl5, win8, wpa81),
+ CreateProfileFrameworks(328, net4, sl5, win8, wpa81, wp8),
+ CreateProfileFrameworks(336, net403, sl5, win8, wpa81, wp8),
+ CreateProfileFrameworks(344, net45, sl5, win8, wpa81, wp8),
+ };
+ });
+
+ public IEnumerable> ProfileFrameworks
+ {
+ get
+ {
+ return ProfileFrameworksLazy.Value;
+ }
+ }
+
+ private static KeyValuePair CreateProfileFrameworks(int profile, params NuGetFramework[] frameworks)
+ {
+ return new KeyValuePair(profile, frameworks);
+ }
+
+ // profiles that also support monotouch1+monoandroid1
+ private static readonly int[] ProfilesWithOptionalFrameworks =
+ {
+ 5, 6, 7, 14, 19, 24, 37, 42, 44, 47, 49, 78, 92, 102, 111, 136, 147, 151, 158, 225, 255, 259, 328, 336, 344
+ };
+
+ private static readonly Lazy>> ProfileOptionalFrameworksLazy = new Lazy>>(() =>
+ {
+ var monoandroid = new NuGetFramework(FrameworkConstants.FrameworkIdentifiers.MonoAndroid, new Version(0, 0));
+ var monotouch = new NuGetFramework(FrameworkConstants.FrameworkIdentifiers.MonoTouch, new Version(0, 0));
+ var xamarinIOs = new NuGetFramework(FrameworkConstants.FrameworkIdentifiers.XamarinIOs, new Version(0, 0));
+ var xamarinMac = new NuGetFramework(FrameworkConstants.FrameworkIdentifiers.XamarinMac, new Version(0, 0));
+ var xamarinTVOS = new NuGetFramework(FrameworkConstants.FrameworkIdentifiers.XamarinTVOS, new Version(0, 0));
+ var xamarinWatchOS = new NuGetFramework(FrameworkConstants.FrameworkIdentifiers.XamarinWatchOS, new Version(0, 0));
+ var monoFrameworks = new NuGetFramework[] { monoandroid, monotouch, xamarinIOs, xamarinMac, xamarinWatchOS, xamarinTVOS };
+
+ var profileOptionalFrameworks = new List>(ProfilesWithOptionalFrameworks.Length);
+
+ foreach (var profile in ProfilesWithOptionalFrameworks)
+ {
+ profileOptionalFrameworks.Add(new KeyValuePair(profile, monoFrameworks));
+ }
+
+ return profileOptionalFrameworks;
+ });
+
+ public IEnumerable> ProfileOptionalFrameworks
+ {
+ get
+ {
+ return ProfileOptionalFrameworksLazy.Value;
+ }
+ }
+
+ private static readonly Lazy[]> CompatibilityMappingsLazy = new Lazy[]>(() =>
+ {
+ return new[]
+ {
+ CreateStandardMapping(7, FrameworkConstants.CommonFrameworks.NetStandard11),
+ CreateStandardMapping(31, FrameworkConstants.CommonFrameworks.NetStandard10),
+ CreateStandardMapping(32, FrameworkConstants.CommonFrameworks.NetStandard12),
+ CreateStandardMapping(44, FrameworkConstants.CommonFrameworks.NetStandard12),
+ CreateStandardMapping(49, FrameworkConstants.CommonFrameworks.NetStandard10),
+ CreateStandardMapping(78, FrameworkConstants.CommonFrameworks.NetStandard10),
+ CreateStandardMapping(84, FrameworkConstants.CommonFrameworks.NetStandard10),
+ CreateStandardMapping(111, FrameworkConstants.CommonFrameworks.NetStandard11),
+ CreateStandardMapping(151, FrameworkConstants.CommonFrameworks.NetStandard12),
+ CreateStandardMapping(157, FrameworkConstants.CommonFrameworks.NetStandard10),
+ CreateStandardMapping(259, FrameworkConstants.CommonFrameworks.NetStandard10)
+ };
+ });
+
+ public IEnumerable> CompatibilityMappings
+ {
+ get
+ {
+ return CompatibilityMappingsLazy.Value;
+ }
+ }
+
+ private static KeyValuePair CreateStandardMapping(
+ int profileNumber,
+ NuGetFramework netStandard)
+ {
+ var range = new FrameworkRange(
+ FrameworkConstants.CommonFrameworks.NetStandard10,
+ netStandard);
+
+ return new KeyValuePair(profileNumber, range);
+ }
+
+ private static readonly Lazy InstanceLazy = new Lazy(() => new DefaultPortableFrameworkMappings());
+
+ ///
+ /// Static instance of the portable framework mappings
+ ///
+ public static IPortableFrameworkMappings Instance
+ {
+ get
+ {
+ return InstanceLazy.Value;
+ }
+ }
+ }
+}
diff --git a/src/Microsoft.TestPlatform.ObjectModel/Nuget.Frameworks/FallbackFramework.cs b/src/Microsoft.TestPlatform.ObjectModel/Nuget.Frameworks/FallbackFramework.cs
new file mode 100644
index 0000000000..71f191051a
--- /dev/null
+++ b/src/Microsoft.TestPlatform.ObjectModel/Nuget.Frameworks/FallbackFramework.cs
@@ -0,0 +1,82 @@
+// 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.Linq;
+using NuGetClone.Shared;
+
+using FallbackList = System.Collections.Generic.IReadOnlyList;
+
+namespace NuGetClone.Frameworks
+{
+ internal class FallbackFramework : NuGetFramework, IEquatable
+ {
+ ///
+ /// List framework to fall back to.
+ ///
+ public FallbackList Fallback { get; }
+
+ private int? _hashCode;
+
+ public FallbackFramework(NuGetFramework framework, FallbackList fallbackFrameworks)
+ : base(framework)
+ {
+ if (framework == null)
+ {
+ throw new ArgumentNullException(nameof(framework));
+ }
+
+ if (fallbackFrameworks == null)
+ {
+ throw new ArgumentNullException(nameof(fallbackFrameworks));
+ }
+
+ if (fallbackFrameworks.Count == 0)
+ {
+ throw new ArgumentException("Empty fallbackFrameworks is invalid", nameof(fallbackFrameworks));
+ }
+
+ Fallback = fallbackFrameworks;
+ }
+
+ public override bool Equals(object? obj)
+ {
+ return Equals(obj as FallbackFramework);
+ }
+
+ public override int GetHashCode()
+ {
+ if (_hashCode == null)
+ {
+ var combiner = new HashCodeCombiner();
+
+ combiner.AddObject(Comparer.GetHashCode(this));
+
+ foreach (var each in Fallback)
+ {
+ combiner.AddObject(Comparer.GetHashCode(each));
+ }
+
+ _hashCode = combiner.CombinedHash;
+ }
+
+ return _hashCode.Value;
+ }
+
+ public bool Equals(FallbackFramework? other)
+ {
+ if (other == null)
+ {
+ return false;
+ }
+
+ if (Object.ReferenceEquals(this, other))
+ {
+ return true;
+ }
+
+ return NuGetFramework.Comparer.Equals(this, other)
+ && Fallback.SequenceEqual(other.Fallback);
+ }
+ }
+}
diff --git a/src/Microsoft.TestPlatform.ObjectModel/Nuget.Frameworks/FrameworkConstants.cs b/src/Microsoft.TestPlatform.ObjectModel/Nuget.Frameworks/FrameworkConstants.cs
new file mode 100644
index 0000000000..21cb9c9c1f
--- /dev/null
+++ b/src/Microsoft.TestPlatform.ObjectModel/Nuget.Frameworks/FrameworkConstants.cs
@@ -0,0 +1,195 @@
+// 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 NuGetClone.Frameworks
+{
+ internal static class FrameworkConstants
+ {
+ public static readonly Version EmptyVersion = new Version(0, 0, 0, 0);
+ public static readonly Version MaxVersion = new Version(int.MaxValue, 0, 0, 0);
+ public static readonly Version Version5 = new Version(5, 0, 0, 0);
+ public static readonly Version Version6 = new Version(6, 0, 0, 0);
+ public static readonly Version Version7 = new Version(7, 0, 0, 0);
+ public static readonly Version Version10 = new Version(10, 0, 0, 0);
+ public static readonly FrameworkRange DotNetAll = new FrameworkRange(
+ new NuGetFramework(FrameworkIdentifiers.NetPlatform, FrameworkConstants.EmptyVersion),
+ new NuGetFramework(FrameworkIdentifiers.NetPlatform, FrameworkConstants.MaxVersion));
+
+ internal static class SpecialIdentifiers
+ {
+ public const string Any = "Any";
+ public const string Agnostic = "Agnostic";
+ public const string Unsupported = "Unsupported";
+ }
+
+ internal static class PlatformIdentifiers
+ {
+ public const string WindowsPhone = "WindowsPhone";
+ public const string Windows = "Windows";
+ }
+
+ internal static class FrameworkIdentifiers
+ {
+ public const string NetCoreApp = ".NETCoreApp";
+ public const string NetStandardApp = ".NETStandardApp";
+ public const string NetStandard = ".NETStandard";
+ public const string NetPlatform = ".NETPlatform";
+ public const string DotNet = "dotnet";
+ public const string Net = ".NETFramework";
+ public const string NetCore = ".NETCore";
+ public const string WinRT = "WinRT"; // deprecated
+ public const string NetMicro = ".NETMicroFramework";
+ public const string Portable = ".NETPortable";
+ public const string WindowsPhone = "WindowsPhone";
+ public const string Windows = "Windows";
+ public const string WindowsPhoneApp = "WindowsPhoneApp";
+ public const string Dnx = "DNX";
+ public const string DnxCore = "DNXCore";
+ public const string AspNet = "ASP.NET";
+ public const string AspNetCore = "ASP.NETCore";
+ public const string Silverlight = "Silverlight";
+ public const string Native = "native";
+ public const string MonoAndroid = "MonoAndroid";
+ public const string MonoTouch = "MonoTouch";
+ public const string MonoMac = "MonoMac";
+ public const string XamarinIOs = "Xamarin.iOS";
+ public const string XamarinMac = "Xamarin.Mac";
+ public const string XamarinPlayStation3 = "Xamarin.PlayStation3";
+ public const string XamarinPlayStation4 = "Xamarin.PlayStation4";
+ public const string XamarinPlayStationVita = "Xamarin.PlayStationVita";
+ public const string XamarinWatchOS = "Xamarin.WatchOS";
+ public const string XamarinTVOS = "Xamarin.TVOS";
+ public const string XamarinXbox360 = "Xamarin.Xbox360";
+ public const string XamarinXboxOne = "Xamarin.XboxOne";
+ public const string UAP = "UAP";
+ public const string Tizen = "Tizen";
+ public const string NanoFramework = ".NETnanoFramework";
+ }
+
+ ///
+ /// Interned frameworks that are commonly used in NuGet
+ ///
+ internal static class CommonFrameworks
+ {
+ public static readonly NuGetFramework Net11 = new NuGetFramework(FrameworkIdentifiers.Net, new Version(1, 1, 0, 0));
+ public static readonly NuGetFramework Net2 = new NuGetFramework(FrameworkIdentifiers.Net, new Version(2, 0, 0, 0));
+ public static readonly NuGetFramework Net35 = new NuGetFramework(FrameworkIdentifiers.Net, new Version(3, 5, 0, 0));
+ public static readonly NuGetFramework Net4 = new NuGetFramework(FrameworkIdentifiers.Net, new Version(4, 0, 0, 0));
+ public static readonly NuGetFramework Net403 = new NuGetFramework(FrameworkIdentifiers.Net, new Version(4, 0, 3, 0));
+ public static readonly NuGetFramework Net45 = new NuGetFramework(FrameworkIdentifiers.Net, new Version(4, 5, 0, 0));
+ public static readonly NuGetFramework Net451 = new NuGetFramework(FrameworkIdentifiers.Net, new Version(4, 5, 1, 0));
+ public static readonly NuGetFramework Net452 = new NuGetFramework(FrameworkIdentifiers.Net, new Version(4, 5, 2, 0));
+ public static readonly NuGetFramework Net46 = new NuGetFramework(FrameworkIdentifiers.Net, new Version(4, 6, 0, 0));
+ public static readonly NuGetFramework Net461 = new NuGetFramework(FrameworkIdentifiers.Net, new Version(4, 6, 1, 0));
+ public static readonly NuGetFramework Net462 = new NuGetFramework(FrameworkIdentifiers.Net, new Version(4, 6, 2, 0));
+ public static readonly NuGetFramework Net463 = new NuGetFramework(FrameworkIdentifiers.Net, new Version(4, 6, 3, 0));
+ public static readonly NuGetFramework Net47 = new NuGetFramework(FrameworkIdentifiers.Net, new Version(4, 7, 0, 0));
+ public static readonly NuGetFramework Net471 = new NuGetFramework(FrameworkIdentifiers.Net, new Version(4, 7, 1, 0));
+ public static readonly NuGetFramework Net472 = new NuGetFramework(FrameworkIdentifiers.Net, new Version(4, 7, 2, 0));
+
+ public static readonly NuGetFramework NetCore45 = new NuGetFramework(FrameworkIdentifiers.NetCore, new Version(4, 5, 0, 0));
+ public static readonly NuGetFramework NetCore451 = new NuGetFramework(FrameworkIdentifiers.NetCore, new Version(4, 5, 1, 0));
+ public static readonly NuGetFramework NetCore50 = new NuGetFramework(FrameworkIdentifiers.NetCore, new Version(5, 0, 0, 0));
+
+ public static readonly NuGetFramework Win8 = new NuGetFramework(FrameworkIdentifiers.Windows, new Version(8, 0, 0, 0));
+ public static readonly NuGetFramework Win81 = new NuGetFramework(FrameworkIdentifiers.Windows, new Version(8, 1, 0, 0));
+ public static readonly NuGetFramework Win10 = new NuGetFramework(FrameworkIdentifiers.Windows, new Version(10, 0, 0, 0));
+
+ public static readonly NuGetFramework SL4 = new NuGetFramework(FrameworkIdentifiers.Silverlight, new Version(4, 0, 0, 0));
+ public static readonly NuGetFramework SL5 = new NuGetFramework(FrameworkIdentifiers.Silverlight, new Version(5, 0, 0, 0));
+
+ public static readonly NuGetFramework WP7 = new NuGetFramework(FrameworkIdentifiers.WindowsPhone, new Version(7, 0, 0, 0));
+ public static readonly NuGetFramework WP75 = new NuGetFramework(FrameworkIdentifiers.WindowsPhone, new Version(7, 5, 0, 0));
+ public static readonly NuGetFramework WP8 = new NuGetFramework(FrameworkIdentifiers.WindowsPhone, new Version(8, 0, 0, 0));
+ public static readonly NuGetFramework WP81 = new NuGetFramework(FrameworkIdentifiers.WindowsPhone, new Version(8, 1, 0, 0));
+ public static readonly NuGetFramework WPA81 = new NuGetFramework(FrameworkIdentifiers.WindowsPhoneApp, new Version(8, 1, 0, 0));
+
+ public static readonly NuGetFramework Tizen3 = new NuGetFramework(FrameworkIdentifiers.Tizen, new Version(3, 0, 0, 0));
+ public static readonly NuGetFramework Tizen4 = new NuGetFramework(FrameworkIdentifiers.Tizen, new Version(4, 0, 0, 0));
+ public static readonly NuGetFramework Tizen6 = new NuGetFramework(FrameworkIdentifiers.Tizen, new Version(6, 0, 0, 0));
+
+ public static readonly NuGetFramework AspNet = new NuGetFramework(FrameworkIdentifiers.AspNet, EmptyVersion);
+ public static readonly NuGetFramework AspNetCore = new NuGetFramework(FrameworkIdentifiers.AspNetCore, EmptyVersion);
+ public static readonly NuGetFramework AspNet50 = new NuGetFramework(FrameworkIdentifiers.AspNet, Version5);
+ public static readonly NuGetFramework AspNetCore50 = new NuGetFramework(FrameworkIdentifiers.AspNetCore, Version5);
+
+ public static readonly NuGetFramework Dnx = new NuGetFramework(FrameworkIdentifiers.Dnx, EmptyVersion);
+ public static readonly NuGetFramework Dnx45 = new NuGetFramework(FrameworkIdentifiers.Dnx, new Version(4, 5, 0, 0));
+ public static readonly NuGetFramework Dnx451 = new NuGetFramework(FrameworkIdentifiers.Dnx, new Version(4, 5, 1, 0));
+ public static readonly NuGetFramework Dnx452 = new NuGetFramework(FrameworkIdentifiers.Dnx, new Version(4, 5, 2, 0));
+ public static readonly NuGetFramework DnxCore = new NuGetFramework(FrameworkIdentifiers.DnxCore, EmptyVersion);
+ public static readonly NuGetFramework DnxCore50 = new NuGetFramework(FrameworkIdentifiers.DnxCore, Version5);
+
+ public static readonly NuGetFramework DotNet
+ = new NuGetFramework(FrameworkIdentifiers.NetPlatform, EmptyVersion);
+ public static readonly NuGetFramework DotNet50
+ = new NuGetFramework(FrameworkIdentifiers.NetPlatform, Version5);
+ public static readonly NuGetFramework DotNet51
+ = new NuGetFramework(FrameworkIdentifiers.NetPlatform, new Version(5, 1, 0, 0));
+ public static readonly NuGetFramework DotNet52
+ = new NuGetFramework(FrameworkIdentifiers.NetPlatform, new Version(5, 2, 0, 0));
+ public static readonly NuGetFramework DotNet53
+ = new NuGetFramework(FrameworkIdentifiers.NetPlatform, new Version(5, 3, 0, 0));
+ public static readonly NuGetFramework DotNet54
+ = new NuGetFramework(FrameworkIdentifiers.NetPlatform, new Version(5, 4, 0, 0));
+ public static readonly NuGetFramework DotNet55
+ = new NuGetFramework(FrameworkIdentifiers.NetPlatform, new Version(5, 5, 0, 0));
+ public static readonly NuGetFramework DotNet56
+ = new NuGetFramework(FrameworkIdentifiers.NetPlatform, new Version(5, 6, 0, 0));
+
+ public static readonly NuGetFramework NetStandard
+ = new NuGetFramework(FrameworkIdentifiers.NetStandard, EmptyVersion);
+ public static readonly NuGetFramework NetStandard10
+ = new NuGetFramework(FrameworkIdentifiers.NetStandard, new Version(1, 0, 0, 0));
+ public static readonly NuGetFramework NetStandard11
+ = new NuGetFramework(FrameworkIdentifiers.NetStandard, new Version(1, 1, 0, 0));
+ public static readonly NuGetFramework NetStandard12
+ = new NuGetFramework(FrameworkIdentifiers.NetStandard, new Version(1, 2, 0, 0));
+ public static readonly NuGetFramework NetStandard13
+ = new NuGetFramework(FrameworkIdentifiers.NetStandard, new Version(1, 3, 0, 0));
+ public static readonly NuGetFramework NetStandard14
+ = new NuGetFramework(FrameworkIdentifiers.NetStandard, new Version(1, 4, 0, 0));
+ public static readonly NuGetFramework NetStandard15
+ = new NuGetFramework(FrameworkIdentifiers.NetStandard, new Version(1, 5, 0, 0));
+ public static readonly NuGetFramework NetStandard16
+ = new NuGetFramework(FrameworkIdentifiers.NetStandard, new Version(1, 6, 0, 0));
+ public static readonly NuGetFramework NetStandard17
+ = new NuGetFramework(FrameworkIdentifiers.NetStandard, new Version(1, 7, 0, 0));
+ public static readonly NuGetFramework NetStandard20
+ = new NuGetFramework(FrameworkIdentifiers.NetStandard, new Version(2, 0, 0, 0));
+ public static readonly NuGetFramework NetStandard21
+ = new NuGetFramework(FrameworkIdentifiers.NetStandard, new Version(2, 1, 0, 0));
+
+ public static readonly NuGetFramework NetStandardApp15
+ = new NuGetFramework(FrameworkIdentifiers.NetStandardApp, new Version(1, 5, 0, 0));
+
+ public static readonly NuGetFramework UAP10
+ = new NuGetFramework(FrameworkIdentifiers.UAP, Version10);
+
+ public static readonly NuGetFramework NetCoreApp10
+ = new NuGetFramework(FrameworkIdentifiers.NetCoreApp, new Version(1, 0, 0, 0));
+ public static readonly NuGetFramework NetCoreApp11
+ = new NuGetFramework(FrameworkIdentifiers.NetCoreApp, new Version(1, 1, 0, 0));
+ public static readonly NuGetFramework NetCoreApp20
+ = new NuGetFramework(FrameworkIdentifiers.NetCoreApp, new Version(2, 0, 0, 0));
+ public static readonly NuGetFramework NetCoreApp21
+ = new NuGetFramework(FrameworkIdentifiers.NetCoreApp, new Version(2, 1, 0, 0));
+ public static readonly NuGetFramework NetCoreApp22
+ = new NuGetFramework(FrameworkIdentifiers.NetCoreApp, new Version(2, 2, 0, 0));
+ public static readonly NuGetFramework NetCoreApp30
+ = new NuGetFramework(FrameworkIdentifiers.NetCoreApp, new Version(3, 0, 0, 0));
+ public static readonly NuGetFramework NetCoreApp31
+ = new NuGetFramework(FrameworkIdentifiers.NetCoreApp, new Version(3, 1, 0, 0));
+
+ // .NET 5.0 and later has NetCoreApp identifier
+ public static readonly NuGetFramework Net50 = new NuGetFramework(FrameworkIdentifiers.NetCoreApp, Version5);
+ public static readonly NuGetFramework Net60 = new NuGetFramework(FrameworkIdentifiers.NetCoreApp, Version6);
+ public static readonly NuGetFramework Net70 = new NuGetFramework(FrameworkIdentifiers.NetCoreApp, Version7);
+
+ public static readonly NuGetFramework Native = new NuGetFramework(FrameworkIdentifiers.Native, new Version(0, 0, 0, 0));
+ }
+ }
+}
diff --git a/src/Microsoft.TestPlatform.ObjectModel/Nuget.Frameworks/FrameworkException.cs b/src/Microsoft.TestPlatform.ObjectModel/Nuget.Frameworks/FrameworkException.cs
new file mode 100644
index 0000000000..101b2726cf
--- /dev/null
+++ b/src/Microsoft.TestPlatform.ObjectModel/Nuget.Frameworks/FrameworkException.cs
@@ -0,0 +1,21 @@
+// 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.Runtime.Serialization;
+
+namespace NuGetClone.Frameworks
+{
+ [Serializable]
+ internal class FrameworkException : Exception
+ {
+ public FrameworkException(string message)
+ : base(message)
+ {
+ }
+
+ protected FrameworkException(SerializationInfo info, StreamingContext context) : base(info, context)
+ {
+ }
+ }
+}
diff --git a/src/Microsoft.TestPlatform.ObjectModel/Nuget.Frameworks/FrameworkExpander.cs b/src/Microsoft.TestPlatform.ObjectModel/Nuget.Frameworks/FrameworkExpander.cs
new file mode 100644
index 0000000000..59e53543bc
--- /dev/null
+++ b/src/Microsoft.TestPlatform.ObjectModel/Nuget.Frameworks/FrameworkExpander.cs
@@ -0,0 +1,128 @@
+// 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 NuGetClone.Frameworks
+{
+ ///
+ /// FrameworkExpander finds all equivalent and compatible frameworks for a NuGetFramework
+ ///
+ internal class FrameworkExpander
+ {
+ private readonly IFrameworkNameProvider _mappings;
+
+ public FrameworkExpander()
+ : this(DefaultFrameworkNameProvider.Instance)
+ {
+ }
+
+ public FrameworkExpander(IFrameworkNameProvider mappings)
+ {
+ _mappings = mappings ?? throw new ArgumentNullException(nameof(mappings));
+ }
+
+ ///
+ /// Return all possible equivalent, subset, and known compatible frameworks.
+ ///
+ public IEnumerable Expand(NuGetFramework framework)
+ {
+ if (framework == null) throw new ArgumentNullException(nameof(framework));
+
+ var seen = new HashSet() { framework };
+ var toExpand = new Stack();
+ 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? ranges))
+ {
+ foreach (var range in ranges)
+ {
+ yield return range.Min;
+
+ if (!range.Min.Equals(range.Max))
+ {
+ yield return range.Max;
+ }
+ }
+ }
+ }
+ }
+
+ ///
+ /// Finds all expansions using the mapping provider
+ ///
+ private IEnumerable ExpandInternal(NuGetFramework framework)
+ {
+ // check the framework directly, this includes profiles which the range doesn't return
+ if (_mappings.TryGetEquivalentFrameworks(framework, out IEnumerable? 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? 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? 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? ranges))
+ {
+ foreach (var range in ranges)
+ {
+ yield return range.Min;
+
+ if (!range.Min.Equals(range.Max))
+ {
+ yield return range.Max;
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/src/Microsoft.TestPlatform.ObjectModel/Nuget.Frameworks/FrameworkNameHelpers.cs b/src/Microsoft.TestPlatform.ObjectModel/Nuget.Frameworks/FrameworkNameHelpers.cs
new file mode 100644
index 0000000000..9c6fa9bd1d
--- /dev/null
+++ b/src/Microsoft.TestPlatform.ObjectModel/Nuget.Frameworks/FrameworkNameHelpers.cs
@@ -0,0 +1,73 @@
+// 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.Globalization;
+using System.Linq;
+
+namespace NuGetClone.Frameworks
+{
+ internal static class FrameworkNameHelpers
+ {
+ public static string GetPortableProfileNumberString(int profileNumber)
+ {
+ return String.Format(CultureInfo.InvariantCulture, "Profile{0}", profileNumber);
+ }
+
+ public static string GetFolderName(string identifierShortName, string versionString, string? profileShortName)
+ {
+ return String.Format(CultureInfo.InvariantCulture, "{0}{1}{2}{3}", identifierShortName, versionString, String.IsNullOrEmpty(profileShortName) ? string.Empty : "-", profileShortName);
+ }
+
+ public static string GetVersionString(Version version)
+ {
+ string? versionString = null;
+
+ if (version != null)
+ {
+ if (version.Major > 9
+ || version.Minor > 9
+ || version.Build > 9
+ || version.Revision > 9)
+ {
+ versionString = version.ToString();
+ }
+ else
+ {
+ versionString = version.ToString().Replace(".", "").TrimEnd('0');
+ }
+ }
+
+ return versionString!;
+ }
+
+ public static Version GetVersion(string? versionString)
+ {
+ if (string.IsNullOrEmpty(versionString))
+ {
+ return FrameworkConstants.EmptyVersion;
+ }
+ else
+ {
+ if (versionString!.IndexOf('.') > -1)
+ {
+ // parse the version as a normal dot delimited version
+ return Version.Parse(versionString);
+ }
+ else
+ {
+ // make sure we have at least 2 digits
+ if (versionString.Length < 2)
+ {
+ versionString += "0";
+ }
+
+ // take only the first 4 digits and add dots
+ // 451 -> 4.5.1
+ // 81233 -> 8123
+ return Version.Parse(string.Join(".", versionString.ToCharArray().Take(4)));
+ }
+ }
+ }
+ }
+}
diff --git a/src/Microsoft.TestPlatform.ObjectModel/Nuget.Frameworks/FrameworkNameProvider.cs b/src/Microsoft.TestPlatform.ObjectModel/Nuget.Frameworks/FrameworkNameProvider.cs
new file mode 100644
index 0000000000..4c810b6564
--- /dev/null
+++ b/src/Microsoft.TestPlatform.ObjectModel/Nuget.Frameworks/FrameworkNameProvider.cs
@@ -0,0 +1,1185 @@
+// 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;
+using System.Diagnostics.CodeAnalysis;
+using System.Globalization;
+using System.Linq;
+using System.Text;
+
+namespace NuGetClone.Frameworks
+{
+ internal class FrameworkNameProvider : IFrameworkNameProvider
+ {
+ private static readonly HashSet EmptyFrameworkSet = new();
+
+ ///
+ /// Legacy frameworks that are allowed to have a single digit for the version number.
+ ///
+ private static readonly HashSet SingleDigitVersionFrameworks = new(StringComparer.OrdinalIgnoreCase)
+ {
+ FrameworkConstants.FrameworkIdentifiers.Windows,
+ FrameworkConstants.FrameworkIdentifiers.WindowsPhone,
+ FrameworkConstants.FrameworkIdentifiers.Silverlight
+ };
+
+ ///
+ /// Frameworks that must always include a decimal point (period) between numerical parts.
+ ///
+ private static readonly HashSet DecimalPointFrameworks = new(StringComparer.OrdinalIgnoreCase)
+ {
+ FrameworkConstants.FrameworkIdentifiers.NetCoreApp,
+ FrameworkConstants.FrameworkIdentifiers.NetStandard,
+ FrameworkConstants.FrameworkIdentifiers.NanoFramework
+ };
+
+ ///
+ /// Contains identifier -> identifier
+ /// Ex: .NET Framework -> .NET Framework
+ /// Ex: NET Framework -> .NET Framework
+ /// This includes self mappings.
+ ///
+ private readonly Dictionary _identifierSynonyms;
+
+ private readonly Dictionary _identifierToShortName;
+ private readonly Dictionary _profilesToShortName;
+ private readonly Dictionary _identifierShortToLong;
+ private readonly Dictionary _profileShortToLong;
+
+ // profile -> supported frameworks, optional frameworks
+ private readonly Dictionary> _portableFrameworks;
+ private readonly Dictionary> _portableOptionalFrameworks;
+
+ // PCL compatibility mappings
+ private readonly Dictionary> _portableCompatibilityMappings;
+
+ // equivalent frameworks
+ private readonly Dictionary> _equivalentFrameworks;
+
+ // equivalent profiles
+ private readonly Dictionary>> _equivalentProfiles;
+
+ // non-PCL compatibility mappings
+ private readonly Dictionary> _compatibilityMappings;
+
+ // subsets, net -> netcore
+ private readonly Dictionary> _subSetFrameworks;
+
+ // framework ordering (for non-package based frameworks)
+ private readonly Dictionary _nonPackageBasedFrameworkPrecedence;
+
+ // framework ordering (for package based frameworks)
+ private readonly Dictionary _packageBasedFrameworkPrecedence;
+
+ // framework ordering (when choosing between equivalent frameworks)
+ private readonly Dictionary _equivalentFrameworkPrecedence;
+
+ // Rewrite mappings
+ private readonly Dictionary _shortNameRewrites;
+ private readonly Dictionary _fullNameRewrites;
+
+ // NetStandard information
+ private readonly List _netStandardVersions;
+ private readonly List _compatibleCandidates;
+
+ public FrameworkNameProvider(IEnumerable? mappings, IEnumerable? portableMappings)
+ {
+ _identifierSynonyms = new Dictionary(StringComparer.OrdinalIgnoreCase);
+ _identifierToShortName = new Dictionary(StringComparer.OrdinalIgnoreCase);
+ _profilesToShortName = new Dictionary(StringComparer.OrdinalIgnoreCase);
+ _identifierShortToLong = new Dictionary(StringComparer.OrdinalIgnoreCase);
+ _profileShortToLong = new Dictionary(StringComparer.OrdinalIgnoreCase);
+ _portableFrameworks = new Dictionary>();
+ _portableOptionalFrameworks = new Dictionary>();
+ _equivalentFrameworks = new Dictionary>();
+ _equivalentProfiles = new Dictionary>>(StringComparer.OrdinalIgnoreCase);
+ _subSetFrameworks = new Dictionary>(StringComparer.OrdinalIgnoreCase);
+ _nonPackageBasedFrameworkPrecedence = new Dictionary(StringComparer.OrdinalIgnoreCase);
+ _packageBasedFrameworkPrecedence = new Dictionary(StringComparer.OrdinalIgnoreCase);
+ _equivalentFrameworkPrecedence = new Dictionary(StringComparer.OrdinalIgnoreCase);
+ _compatibilityMappings = new Dictionary>(StringComparer.OrdinalIgnoreCase);
+ _portableCompatibilityMappings = new Dictionary>();
+ _shortNameRewrites = new Dictionary();
+ _fullNameRewrites = new Dictionary();
+ _netStandardVersions = new List();
+ _compatibleCandidates = new List();
+
+ InitMappings(mappings);
+
+ InitPortableMappings(portableMappings);
+
+ InitNetStandard();
+ }
+
+ ///
+ /// Converts a key using the mappings, or if the key is already converted, finds the normalized form.
+ ///
+ private static bool TryConvertOrNormalize(string key, IDictionary mappings, IDictionary reverse, [NotNullWhen(true)] out string? value)
+ {
+ if (mappings.TryGetValue(key, out value))
+ {
+ return true;
+ }
+ else if (reverse.ContainsKey(key))
+ {
+ value = reverse.Where(p => StringComparer.OrdinalIgnoreCase.Equals(p.Key, key)).Select(s => s.Key).Single();
+ return true;
+ }
+
+ value = null;
+ return false;
+ }
+
+ public bool TryGetIdentifier(string framework, [NotNullWhen(true)] out string? identifier)
+ {
+ return TryConvertOrNormalize(framework, _identifierSynonyms, _identifierToShortName, out identifier);
+ }
+
+ public bool TryGetProfile(string frameworkIdentifier, string profileShortName, [NotNullWhen(true)] out string? profile)
+ {
+ return TryConvertOrNormalize(profileShortName, _profileShortToLong, _profilesToShortName, out profile);
+ }
+
+ public bool TryGetShortIdentifier(string identifier, [NotNullWhen(true)] out string? identifierShortName)
+ {
+ return TryConvertOrNormalize(identifier, _identifierToShortName, _identifierShortToLong, out identifierShortName);
+ }
+
+ public bool TryGetShortProfile(string frameworkIdentifier, string profile, [NotNullWhen(true)] out string? profileShortName)
+ {
+ return TryConvertOrNormalize(profile, _profilesToShortName, _profileShortToLong, out profileShortName);
+ }
+
+ public bool TryGetVersion(string versionString, [NotNullWhen(true)] out Version? version)
+ {
+ if (string.IsNullOrEmpty(versionString))
+ {
+ version = null;
+ return false;
+ }
+ else
+ {
+ if (versionString.IndexOf('.') > -1)
+ {
+ // parse the version as a normal dot delimited version
+ return Version.TryParse(versionString, out version);
+ }
+ else
+ {
+ // make sure we have at least 2 digits
+ if (versionString.Length < 2)
+ {
+ versionString += "0";
+ }
+
+ // take only the first 4 digits and add dots
+ // 451 -> 4.5.1
+ // 81233 -> 8123
+ return Version.TryParse(string.Join(".", versionString.ToCharArray().Take(4)), out version);
+ }
+ }
+ }
+
+ public bool TryGetPlatformVersion(string versionString, [NotNullWhen(true)] out Version? version)
+ {
+ if (string.IsNullOrEmpty(versionString))
+ {
+ version = null;
+ return false;
+ }
+ else
+ {
+ if (versionString.IndexOf('.') < 0)
+ {
+ versionString += ".0";
+ }
+ return Version.TryParse(versionString, out version);
+ }
+ }
+
+ public string GetVersionString(string framework, Version version)
+ {
+ if (version is null || IsZero(version))
+ {
+ return string.Empty;
+ }
+
+ int major = version.Major > 0 ? version.Major : 0;
+ int minor = version.Minor > 0 ? version.Minor : 0;
+ int build = version.Build > 0 ? version.Build : 0;
+ int revision = version.Revision > 0 ? version.Revision : 0;
+
+ // Remove all trailing zeros beyond the minor version.
+ int partCount = (minor == 0, build == 0, revision == 0) switch
+ {
+ (true, true, true) => 1,
+ (false, true, true) => 2,
+ (_, false, true) => 3,
+ (_, _, false) => 4
+ };
+
+ // Only some legacy frameworks are allowed to have one part in their version.
+ if (partCount == 1 && !SingleDigitVersionFrameworks.Contains(framework))
+ {
+ partCount = 2;
+ }
+
+ StringBuilder sb = StringBuilderPool.Shared.Rent(256);
+
+ // Some frameworks require a decimal point between parts.
+ // If any part is greater than 9 (requiring multiple digits), we add decimal points.
+ if (DecimalPointFrameworks.Contains(framework) || HasGreaterThanNinePart())
+ {
+ // An additional zero is needed for decimals.
+ if (partCount == 1)
+ partCount = 2;
+
+ sb.Append(major);
+ if (partCount > 1)
+ sb.Append('.').Append(minor);
+ if (partCount > 2)
+ sb.Append('.').Append(build);
+ if (partCount > 3)
+ sb.Append('.').Append(revision);
+ }
+ else
+ {
+ sb.Append(major);
+ if (partCount > 1)
+ sb.Append(minor);
+ if (partCount > 2)
+ sb.Append(build);
+ if (partCount > 3)
+ sb.Append(revision);
+ }
+
+ return StringBuilderPool.Shared.ToStringAndReturn(sb);
+
+ bool HasGreaterThanNinePart()
+ {
+ return major > 9 || minor > 9 || build > 9 || revision > 9;
+ }
+
+ static bool IsZero(Version version)
+ {
+ // Build and Revision can be -1 when only major & minor are specified.
+ // Out of caution, check all values for zero or less.
+ return version.Major <= 0
+ && version.Minor <= 0
+ && version.Build <= 0
+ && version.Revision <= 0;
+ }
+ }
+
+ public bool TryGetPortableProfile(IEnumerable supportedFrameworks, out int profileNumber)
+ {
+ if (supportedFrameworks == null)
+ {
+ throw new ArgumentNullException(nameof(supportedFrameworks));
+ }
+
+ profileNumber = -1;
+
+ // Remove duplicate frameworks, ex: win+win8 -> win
+ var profileFrameworks = RemoveDuplicateFramework(supportedFrameworks);
+
+ var reduced = new HashSet();
+ foreach (var pair in _portableFrameworks)
+ {
+ // to match the required set must be less than or the same count as the input
+ // if we knew which frameworks were optional in the input we could rule out the lesser ones also
+ if (pair.Value.Count <= profileFrameworks.Count)
+ {
+ foreach (var curFw in profileFrameworks)
+ {
+ var isOptional = false;
+
+ foreach (var optional in GetOptionalFrameworks(pair.Key))
+ {
+ // TODO: profile check? Is the version check correct here?
+ if (NuGetFramework.FrameworkNameComparer.Equals(optional, curFw)
+ && StringComparer.OrdinalIgnoreCase.Equals(optional.Profile, curFw.Profile)
+ && curFw.Version >= optional.Version)
+ {
+ isOptional = true;
+ }
+ }
+
+ if (!isOptional)
+ {
+ reduced.Add(curFw);
+ }
+ }
+
+ // check all frameworks while taking into account equivalent variations
+ foreach (var permutation in GetEquivalentPermutations(pair.Value))
+ {
+ if (SetEquals(reduced, permutation))
+ {
+ // found a match
+ profileNumber = pair.Key;
+ return true;
+ }
+ }
+ }
+
+ reduced.Clear();
+ }
+
+ return false;
+ }
+
+ private HashSet RemoveDuplicateFramework(IEnumerable supportedFrameworks)
+ {
+ var result = new HashSet();
+ var existingFrameworks = new HashSet();
+
+ foreach (var framework in supportedFrameworks)
+ {
+ if (!existingFrameworks.Contains(framework))
+ {
+ result.Add(framework);
+
+ // Add in the existing framework (included here) and all equivalent frameworks
+ var equivalentFrameworks = GetAllEquivalentFrameworks(framework);
+
+ UnionWith(existingFrameworks, equivalentFrameworks);
+ }
+ }
+
+ return result;
+ }
+
+ ///
+ /// Get all equivalent frameworks including the given framework
+ ///
+ private HashSet GetAllEquivalentFrameworks(NuGetFramework framework)
+ {
+ // Loop through the frameworks, all frameworks that are not in results yet
+ // will be added to toProcess to get the equivalent frameworks
+ var toProcess = new Stack();
+ var results = new HashSet();
+
+ toProcess.Push(framework);
+ results.Add(framework);
+
+ while (toProcess.Count > 0)
+ {
+ var current = toProcess.Pop();
+
+ if (_equivalentFrameworks.TryGetValue(current, out HashSet? currentEquivalent))
+ {
+ foreach (var equalFramework in currentEquivalent)
+ {
+ if (results.Add(equalFramework))
+ {
+ toProcess.Push(equalFramework);
+ }
+ }
+ }
+ }
+
+ return results;
+ }
+
+ // find all combinations that are equivalent
+ // ex: net4+win8 <-> net4+netcore45
+ private IEnumerable> GetEquivalentPermutations(HashSet frameworks)
+ {
+ if (frameworks.Count > 0)
+ {
+ NuGetFramework? current = null;
+ var remaining = frameworks.Count == 1 ? null : new HashSet();
+
+ var isFirst = true;
+ foreach (var fw in frameworks)
+ {
+ if (isFirst)
+ {
+ current = fw;
+ isFirst = false;
+ continue;
+ }
+
+ remaining!.Add(fw);
+ }
+
+ var equalFrameworks = new HashSet();
+ // include ourselves
+ equalFrameworks.Add(current!);
+
+ // find all equivalent frameworks for the current one
+ if (_equivalentFrameworks.TryGetValue(current!, out HashSet? curFrameworks))
+ {
+ UnionWith(equalFrameworks, curFrameworks);
+ }
+
+ foreach (var fw in equalFrameworks)
+ {
+ if (remaining != null && remaining.Count > 0)
+ {
+ foreach (var result in GetEquivalentPermutations(remaining))
+ {
+ // work backwards adding the frameworks into the sets
+ result.Add(fw);
+ yield return result;
+ }
+ }
+ else
+ {
+ var singleFramework = new HashSet();
+ singleFramework.Add(fw);
+ yield return singleFramework;
+ }
+ }
+ }
+
+ yield break;
+ }
+
+ private HashSet GetOptionalFrameworks(int profile)
+ {
+ if (_portableOptionalFrameworks.TryGetValue(profile, out HashSet? frameworks))
+ {
+ return frameworks;
+ }
+
+ return EmptyFrameworkSet;
+ }
+
+ public bool TryGetPortableFrameworks(int profile, [NotNullWhen(true)] out IEnumerable? frameworks)
+ {
+ return TryGetPortableFrameworks(profile, true, out frameworks);
+ }
+
+ public bool TryGetPortableFrameworks(int profile, bool includeOptional, [NotNullWhen(true)] out IEnumerable? frameworks)
+ {
+ var result = new HashSet();
+ if (_portableFrameworks.TryGetValue(profile, out HashSet? tmpFrameworks))
+ {
+ foreach (var fw in tmpFrameworks)
+ {
+ result.Add(fw);
+ }
+ }
+
+ if (includeOptional)
+ {
+ if (_portableOptionalFrameworks.TryGetValue(profile, out HashSet? optional))
+ {
+ foreach (var fw in optional)
+ {
+ result.Add(fw);
+ }
+ }
+ }
+
+ frameworks = result;
+ return result.Count > 0;
+ }
+
+ public bool TryGetPortableFrameworks(string shortPortableProfiles, [NotNullWhen(true)] out IEnumerable? frameworks)
+ {
+ if (shortPortableProfiles == null)
+ {
+ throw new ArgumentNullException(nameof(shortPortableProfiles));
+ }
+
+ var shortNames = shortPortableProfiles.Split(new char[] { '+' }, StringSplitOptions.RemoveEmptyEntries);
+
+ var result = new List();
+ foreach (var name in shortNames)
+ {
+ var framework = NuGetFramework.Parse(name, this);
+ if (framework.HasProfile)
+ {
+ // Frameworks within the portable profile are not allowed
+ // to have profiles themselves #1869
+ throw new ArgumentException(string.Format(
+ CultureInfo.CurrentCulture,
+ Strings.InvalidPortableFrameworksDueToHyphen,
+ shortPortableProfiles));
+ }
+
+ result.Add(framework);
+ }
+
+ frameworks = result;
+ return result.Count > 0;
+ }
+
+ public bool TryGetPortableCompatibilityMappings(int profile, [NotNullWhen(true)] out IEnumerable? supportedFrameworkRanges)
+ {
+ if (_portableCompatibilityMappings.TryGetValue(profile, out HashSet? entries))
+ {
+ supportedFrameworkRanges = entries;
+ return supportedFrameworkRanges.Any();
+ }
+
+ supportedFrameworkRanges = null;
+ return false;
+ }
+
+ public bool TryGetPortableProfileNumber(string profile, out int profileNumber)
+ {
+ // attempt to parse the profile for a number
+ if (profile.StartsWith("Profile", StringComparison.OrdinalIgnoreCase))
+ {
+ var trimmed = profile.Substring(7, profile.Length - 7);
+ return int.TryParse(trimmed, out profileNumber);
+ }
+
+ profileNumber = -1;
+ return false;
+ }
+
+ public bool TryGetPortableFrameworks(string profile, bool includeOptional, [NotNullWhen(true)] out IEnumerable? frameworks)
+ {
+ // attempt to parse the profile for a number
+ int profileNum;
+ if (TryGetPortableProfileNumber(profile, out profileNum))
+ {
+ if (TryGetPortableFrameworks(profileNum, includeOptional, out frameworks))
+ {
+ return true;
+ }
+
+ frameworks = Enumerable.Empty();
+ return false;
+ }
+
+ // treat the profile as a list of frameworks
+ return TryGetPortableFrameworks(profile, out frameworks);
+ }
+
+ public bool TryGetEquivalentFrameworks(NuGetFramework framework, [NotNullWhen(true)] out IEnumerable? frameworks)
+ {
+ var result = new HashSet();
+
+ // add in all framework aliases
+ if (_equivalentFrameworks.TryGetValue(framework, out HashSet? eqFrameworks))
+ {
+ foreach (var eqFw in eqFrameworks)
+ {
+ result.Add(eqFw);
+ }
+ }
+
+ var baseFrameworks = new List(result);
+ baseFrameworks.Add(framework);
+
+ // add in all profile aliases
+ foreach (var fw in baseFrameworks)
+ {
+ if (_equivalentProfiles.TryGetValue(fw.Framework, out Dictionary>? eqProfiles))
+ {
+ if (eqProfiles.TryGetValue(fw.Profile, out HashSet? matchingProfiles))
+ {
+ foreach (var eqProfile in matchingProfiles)
+ {
+ result.Add(new NuGetFramework(fw.Framework, fw.Version, eqProfile));
+ }
+ }
+ }
+ }
+
+ // do not include the original framework
+ result.Remove(framework);
+
+ frameworks = result;
+ return result.Count > 0;
+ }
+
+ public bool TryGetEquivalentFrameworks(FrameworkRange range, [NotNullWhen(true)] out IEnumerable? frameworks)
+ {
+ if (range == null)
+ {
+ throw new ArgumentNullException(nameof(range));
+ }
+
+ var relevant = new HashSet();
+
+ foreach (var framework in _equivalentFrameworks.Keys.Where(f => range.Satisfies(f)))
+ {
+ relevant.Add(framework);
+ }
+
+ var results = new HashSet();
+
+ foreach (var framework in relevant)
+ {
+ if (TryGetEquivalentFrameworks(framework, out IEnumerable? values))
+ {
+ foreach (var val in values)
+ {
+ results.Add(val);
+ }
+ }
+ }
+
+ frameworks = results;
+ return results.Count > 0;
+ }
+
+ private void InitMappings(IEnumerable? mappings)
+ {
+ if (mappings != null)
+ {
+ foreach (var mapping in mappings)
+ {
+ // eq profiles
+ AddEquivalentProfiles(mapping.EquivalentProfiles);
+
+ // equivalent frameworks
+ AddEquivalentFrameworks(mapping.EquivalentFrameworks);
+
+ // add synonyms
+ AddFrameworkSynonyms(mapping.IdentifierSynonyms);
+
+ // populate short <-> long
+ AddIdentifierShortNames(mapping.IdentifierShortNames);
+
+ // official profile short names
+ AddProfileShortNames(mapping.ProfileShortNames);
+
+ // add compatibility mappings
+ AddCompatibilityMappings(mapping.CompatibilityMappings);
+
+ // add subset frameworks
+ AddSubSetFrameworks(mapping.SubSetFrameworks);
+
+ // add framework ordering rules
+ AddFrameworkPrecedenceMappings(_nonPackageBasedFrameworkPrecedence, mapping.NonPackageBasedFrameworkPrecedence);
+ AddFrameworkPrecedenceMappings(_packageBasedFrameworkPrecedence, mapping.PackageBasedFrameworkPrecedence);
+ AddFrameworkPrecedenceMappings(_equivalentFrameworkPrecedence, mapping.EquivalentFrameworkPrecedence);
+
+ // add rewrite rules
+ AddShortNameRewriteMappings(mapping.ShortNameReplacements);
+ AddFullNameRewriteMappings(mapping.FullNameReplacements);
+ }
+ }
+ }
+
+ private void InitPortableMappings(IEnumerable? portableMappings)
+ {
+ if (portableMappings != null)
+ {
+ foreach (var portableMapping in portableMappings)
+ {
+ // populate portable framework names
+ AddPortableProfileMappings(portableMapping.ProfileFrameworks);
+
+ // populate portable optional frameworks
+ AddPortableOptionalFrameworks(portableMapping.ProfileOptionalFrameworks);
+
+ // populate portable compatibility mappings
+ AddPortableCompatibilityMappings(portableMapping.CompatibilityMappings);
+ }
+ }
+ }
+
+ private void InitNetStandard()
+ {
+ // populate the list of frameworks that could be compatible with NetStandard
+ AddCompatibleCandidates();
+
+ // populate the list of NetStandard versions
+ AddNetStandardVersions();
+ }
+
+ private void AddShortNameRewriteMappings(IEnumerable> mappings)
+ {
+ if (mappings != null)
+ {
+ foreach (var mapping in mappings)
+ {
+ if (!_shortNameRewrites.ContainsKey(mapping.Key))
+ {
+ _shortNameRewrites.Add(mapping.Key, mapping.Value);
+ }
+ }
+ }
+ }
+
+ private void AddFullNameRewriteMappings(IEnumerable> mappings)
+ {
+ if (mappings != null)
+ {
+ foreach (var mapping in mappings)
+ {
+ if (!_fullNameRewrites.ContainsKey(mapping.Key))
+ {
+ _fullNameRewrites.Add(mapping.Key, mapping.Value);
+ }
+ }
+ }
+ }
+
+ private void AddCompatibilityMappings(IEnumerable mappings)
+ {
+ if (mappings != null)
+ {
+ foreach (var mapping in mappings)
+ {
+ if (!_compatibilityMappings.TryGetValue(mapping.TargetFrameworkRange.Min.Framework, out HashSet? entries))
+ {
+ entries = new HashSet(OneWayCompatibilityMappingEntry.Comparer);
+ _compatibilityMappings.Add(mapping.TargetFrameworkRange.Min.Framework, entries);
+ }
+
+ entries.Add(mapping);
+ }
+ }
+ }
+
+ private void AddSubSetFrameworks(IEnumerable> mappings)
+ {
+ if (mappings != null)
+ {
+ foreach (var mapping in mappings)
+ {
+ if (!_subSetFrameworks.TryGetValue(mapping.Value, out HashSet? subSets))
+ {
+ subSets = new HashSet