|
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
#nullable disable
using Microsoft.Build.Framework;
namespace Microsoft.AspNetCore.StaticWebAssets.Tasks;
public class ResolveStaticWebAssetsEffectiveTargetFramework : Task
{
[Required] public ITaskItem[] TargetFrameworks { get; set; }
[Output] public string EffectiveTargetFramework { get; set; }
public override bool Execute()
{
// We inspect the target frameworks available to find out an appropriate candidate to use for computing the list of
// static web assets for packing.
// Target frameworks have the following pattern {FrameworkIdentifier,FrameworkVersion,PlatformIdentifier?,PlatformVersion?}
// for example: net6.0-windows.10.1980 or net-6.0-ios.14.2.
// We don't deal with any parsing because that's handled by MSBuild. We also don't care about the platform identifier or the
// platform version. The reason is explained below.
// Static web assets don't support having different content based on the target framework. If you are multitargeting (for example,
// in a Razor Class Library) we consider that all TFMs should produce the same set of static web assets and that we can, as a
// result, pick any target framework to act as a representative when we are packing the assets into the package.
// If a package is multitargeting across multiple versions of static web assets, (netstandard2.0 and net6.0 for example) we always
// use as representative the framework with the highest static web assets version (net6.0 in this case).
// Platform identifier and version, don't matter because as mentioned above, the list of assets should be identical in those cases
// and we can pick among any of them to act as a representative for packing purposes.
var (version, framework) = TargetFrameworks
.Select(tf => new FrameworkItem(tf))
.Select(fi => (version: fi.GetStaticWebAssetsVersion(), framework: fi))
.OrderByDescending(p => p.version)
.FirstOrDefault(p => p.version > 0);
EffectiveTargetFramework = framework?.Moniker;
return !Log.HasLoggedErrors;
}
private sealed class FrameworkItem(ITaskItem item)
{
public string Moniker { get; set; } = item.ItemSpec;
public string TargetFrameworkIdentifier { get; set; } = item.GetMetadata("TargetFrameworkIdentifier");
public string TargetFrameworkVersion { get; set; } = item.GetMetadata("TargetFrameworkVersion");
internal double GetStaticWebAssetsVersion() =>
(TargetFrameworkIdentifier, TargetFrameworkVersion) switch
{
(".NETStandard", "2.0") => 1,
(".NETStandard", "2.1") => 1,
(".NETCoreApp", "3.0") => 1,
(".NETCoreApp", "3.1") => 1,
// If there is a net5.0 target, prefer that over netstandard because it supports scoped CSS
(".NETCoreApp", "5.0") => 1.1,
(".NETCoreApp", "6.0") => 2,
(".NETCoreApp", "7.0") => 2,
// Any future netcoreapp or netstandard will be version 2. If in the future we make additional changes to static web assets
// that require a new version, some of our tests will fail to point out we need to change this value.
(".NETCoreApp", _) => 2,
(".NETStandard", _) => 2,
// For anything that we don't know, we return 0. This filters out things like full framework as we won't
// consider them.
(_, _) => 0,
};
}
}
|