Skip to content

Commit 5638e0f

Browse files
authored
[automated] Merge branch 'release/7.0.2xx' => 'main' (#29810)
2 parents 3fe3f79 + f5fd226 commit 5638e0f

File tree

11 files changed

+169
-34
lines changed

11 files changed

+169
-34
lines changed

src/Cli/Microsoft.DotNet.Cli.Utils/TypoCorrection.cs

Lines changed: 101 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -13,34 +13,97 @@ namespace Microsoft.DotNet.Cli.Utils
1313
public static class TypoCorrection
1414
{
1515
/// <summary>
16-
/// Gets the list of tokens similar to <paramref name="currentToken"/>.
16+
/// Gets the list of tokens similar to <paramref name="currentToken"/>
17+
/// based on priority search:
18+
/// 1. Starts with
19+
/// 2. Contains - the call is restricted with <paramref name="currentToken"/> length check, minLength:3 and <param name="maxLevenshteinDistance">
20+
/// 3. Levenshtein algorithm with <param name="maxLevenshteinDistance"> restriction
21+
/// max number of suggestion is restricted to 10 entries
1722
/// </summary>
1823
/// <param name="possibleTokens">List of tokens to select from.</param>
1924
/// <param name="currentToken">The token that is being compared.</param>
2025
/// <param name="maxLevenshteinDistance">the difference between two strings, default: 3.</param>
2126
/// <returns>The enumerator to tokens similar to <paramref name="currentToken"/>.</returns>
2227
public static IEnumerable<string> GetSimilarTokens(IEnumerable<string> possibleTokens, string currentToken, int maxLevenshteinDistance = 3)
2328
{
24-
int? bestDistance = null;
25-
return possibleTokens
26-
.Select(possibleMatch => (possibleMatch, distance: GetDistance(currentToken, possibleMatch)))
27-
.Where(tuple => tuple.distance <= maxLevenshteinDistance)
28-
.OrderBy(tuple => tuple.distance)
29-
.ThenByDescending(tuple => GetStartsWithDistance(currentToken, tuple.possibleMatch))
30-
.TakeWhile(tuple =>
29+
var minCurrentTokenLength = 3;
30+
var maxNumberOfSuggestions = 10;
31+
32+
var numberOfSuggestions = 0;
33+
var currentTokenLength = currentToken.Length;
34+
var possibleSuggestions = possibleTokens.Select((string possibleMatch) => new Suggestion(possibleMatch, possibleMatch.Length)).ToArray();
35+
36+
var matchByStartsWith = possibleSuggestions
37+
.Where(s => s.PossibleMatch.StartsWith(currentToken))
38+
.Select(SetSelection)
39+
.Take(maxNumberOfSuggestions)
40+
.OrderBy(s => s.Distance)
41+
.ToList();
42+
43+
numberOfSuggestions += matchByStartsWith.Count;
44+
if (numberOfSuggestions >= maxNumberOfSuggestions)
45+
{
46+
return matchByStartsWith.Select(s => s.PossibleMatch);
47+
}
48+
49+
var matchByContains = new List<Suggestion>();
50+
if (currentToken.Length >= minCurrentTokenLength)
51+
{
52+
matchByContains = possibleSuggestions
53+
.Where(s =>
54+
!s.IsSelected
55+
&& s.PossibleMatch.Contains(currentToken)
56+
&& s.Distance - currentTokenLength <= maxLevenshteinDistance)
57+
.OrderBy(s => s.Distance)
58+
.Take(maxNumberOfSuggestions - numberOfSuggestions)
59+
.Select(SetSelection)
60+
.ToList();
61+
62+
numberOfSuggestions += matchByContains.Count;
63+
if (numberOfSuggestions >= maxNumberOfSuggestions)
3164
{
32-
(string _, int distance) = tuple;
33-
bestDistance ??= distance;
34-
return distance == bestDistance;
35-
})
36-
.Select(tuple => tuple.possibleMatch);
65+
return matchByStartsWith
66+
.Concat(matchByContains)
67+
.Select(s => s.PossibleMatch);
68+
}
69+
}
70+
71+
var matchByLevenshteinDistance = possibleSuggestions
72+
.Where(s => !s.IsSelected)
73+
.Select(s => new Suggestion(s.PossibleMatch, GetDistance(s.PossibleMatch, currentToken)))
74+
.Where(s => s.Distance <= maxLevenshteinDistance)
75+
.OrderBy(s => s.Distance)
76+
.ThenByDescending(s => GetStartsWithDistance(currentToken, s.PossibleMatch))
77+
.FilterByShortestDistance()
78+
.Take(maxNumberOfSuggestions - numberOfSuggestions);
79+
80+
return matchByStartsWith
81+
.Concat(matchByContains
82+
.Concat(matchByLevenshteinDistance))
83+
.Select(s => s.PossibleMatch);
3784
}
3885

86+
// The method takes the matches with the shortest distance
87+
// e.g. (razor, 2), (pazor, 2), (pazors, 3) => (razor, 2), (pazor, 2)
88+
private static IEnumerable<Suggestion> FilterByShortestDistance(this IEnumerable<Suggestion> possibleMatches)
89+
{
90+
int? bestDistance = null;
91+
92+
return possibleMatches.TakeWhile(s =>
93+
{
94+
int distance = s.Distance;
95+
bestDistance ??= distance;
96+
return distance == bestDistance;
97+
});
98+
}
99+
100+
// The method finds the distance to the first mismatch between two strings
101+
// e.g. (cat, cap) => 2
39102
private static int GetStartsWithDistance(string first, string second)
40103
{
41104
int i;
42-
for (i = 0; i < first.Length && i < second.Length && first[i] == second[i]; i++)
43-
{ }
105+
for (i = 0; i < first.Length && i < second.Length && first[i] == second[i]; i++) ;
106+
44107
return i;
45108
}
46109

@@ -58,7 +121,6 @@ private static int GetDistance(string first, string second)
58121
throw new ArgumentNullException(nameof(second));
59122
}
60123

61-
62124
// Get the length of both. If either is 0, return
63125
// the length of the other, since that number of insertions
64126
// would be required.
@@ -67,7 +129,6 @@ private static int GetDistance(string first, string second)
67129
if (n == 0) return m;
68130
if (m == 0) return n;
69131

70-
71132
// Rather than maintain an entire matrix (which would require O(n*m) space),
72133
// just store the current row and the next row, each of which has a length m+1,
73134
// so just O(m) space. Initialize the current row.
@@ -94,7 +155,6 @@ private static int GetDistance(string first, string second)
94155
rows[nextRow][j] = Math.Min(dist1, Math.Min(dist2, dist3));
95156
}
96157

97-
98158
// Swap the current and next rows
99159
if (curRow == 0)
100160
{
@@ -110,7 +170,30 @@ private static int GetDistance(string first, string second)
110170

111171
// Return the computed edit distance
112172
return rows[curRow][m];
173+
}
174+
175+
private static Suggestion SetSelection(Suggestion s)
176+
{
177+
s.IsSelected = true;
178+
179+
return s;
180+
}
181+
182+
// The class describes properties of a possible match token
183+
// and based on these the decision for the token selection is made
184+
internal sealed class Suggestion
185+
{
186+
public Suggestion(string possibleMatch, int distance)
187+
{
188+
PossibleMatch = possibleMatch;
189+
Distance = distance;
190+
}
191+
192+
public bool IsSelected { get; set; }
193+
194+
public string PossibleMatch { get; }
113195

196+
public int Distance { get; set; }
114197
}
115198
}
116199
}

src/RazorSdk/Tasks/Microsoft.NET.Sdk.Razor.Tasks.csproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,7 @@
101101
</Target>
102102

103103
<Target Name="CopyAdditionalFilesToLayout"
104+
Condition="'$(TargetFramework)' == ''"
104105
DependsOnTargets="PrepareAdditionalFilesToLayout"
105106
AfterTargets="Build" Inputs="@(LayoutFile)"
106107
Outputs="@(LayoutFile->'$(PackageLayoutOutputPath)%(TargetPath)')">

src/Tests/Microsoft.DotNet.Cli.Utils.Tests/TypoCorrectionTests.cs

Lines changed: 20 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -11,14 +11,29 @@ namespace Microsoft.DotNet.Cli.Utils.Tests
1111
{
1212
public class TypoCorrectionTests
1313
{
14-
[InlineData("wbe", "web|webapp|wpf|install|uninstall", "web|wpf")]
15-
[InlineData("uninstal", "web|webapp|install|uninstall", "uninstall")]
16-
[InlineData("console", "web|webapp|install|uninstall", "")]
14+
[InlineData("wbe", "web|webapp|wpf|install|uninstall", "web|wpf", "Levanshtein algorithm")]
15+
[InlineData("uninstal", "web|webapp|install|uninstall", "uninstall|install", "StartsWith & Contains")]
16+
[InlineData("console", "web|webapp|install|uninstall", "", "No matches")]
17+
[InlineData("blazor", "razor|pazor|blazorweb|blazorservice|uninstall|pizor", "blazorweb|blazorservice|razor|pazor", "StartsWith & Levanshtein algorithm")]
18+
[InlineData("blazor", "razor|pazor|pazors", "razor|pazor", "Levanshtein algorithm with shortest distance filtering")]
19+
[InlineData("con", "lacon|test|consoleweb|precon|uninstall|ponsole|pons", "consoleweb|lacon|precon|pons", "StartsWith & Contains & Levanshtein algorithm")]
20+
[InlineData("c", "lacon|test|consoleweb|preconsole|uninstall|ponsole|pons|ccs", "consoleweb|ccs", "StartsWith & Levanshtein algorithm")]
21+
[InlineData("c", "peacon|lecture|beacon", "", "No matches due to Contains restriction on input length")]
22+
[InlineData(
23+
"eac",
24+
"peac|lect|beac|zeac|dect|meac|qeac|aect|oeac|xeac|necte|geacy|gueac",
25+
"peac|beac|zeac|meac|qeac|oeac|xeac|geacy|gueac|lect",
26+
"Contains due to max number of suggestions restriction")]
27+
[InlineData(
28+
"eacy",
29+
"eacyy|eacyl|eacys|eacyt|eacyp|eacyzz|eacyqwe|eacyasd|eacyaa|eacynbv|eacyrfd|peacy|peacp",
30+
"eacyy|eacyl|eacys|eacyt|eacyp|eacyzz|eacyaa|eacyqwe|eacyasd|eacynbv",
31+
"StartsWith due to max number of suggestions restriction")]
1732
[Theory]
18-
public void TypoCorrection_BasicTest(string token, string possibleTokens, string expectedTokens)
33+
public void TypoCorrection_BasicTest(string token, string possibleTokens, string expectedTokens, string checkedScenario)
1934
{
2035
TypoCorrection.GetSimilarTokens(possibleTokens.Split('|'), token)
21-
.Should().BeEquivalentTo(expectedTokens.Split('|', System.StringSplitOptions.RemoveEmptyEntries));
36+
.Should().BeEquivalentTo(expectedTokens.Split('|', System.StringSplitOptions.RemoveEmptyEntries), checkedScenario);
2237
}
2338
}
2439
}

src/Tests/Microsoft.NET.Build.Tests/GivenThatWeWantToBuildALibrary.cs

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -189,7 +189,7 @@ public void It_creates_a_documentation_file(string language)
189189
[InlineData("vb", false)]
190190
public void It_allows_us_to_override_the_documentation_file_name(string language, bool setGenerateDocumentationFileProperty)
191191
{
192-
var testAsset = CreateDocumentationFileLibraryAsset(setGenerateDocumentationFileProperty ? (bool?)true : null, "TestLibDoc.xml", language, "OverrideDocFileName");
192+
var testAsset = CreateDocumentationFileLibraryAsset(setGenerateDocumentationFileProperty ? (bool?)true : null, "TestLibDoc.xml", language, "OverrideDocFileName");
193193

194194
var libraryProjectDirectory = Path.Combine(testAsset.TestRoot, "TestLibrary");
195195

@@ -218,7 +218,8 @@ public void It_allows_us_to_override_the_documentation_file_name(string language
218218
};
219219

220220
// vb uses DocumentationFile relative to the IntermediateOutputPath
221-
if (language != "vb") {
221+
if (language != "vb")
222+
{
222223
expectedProjectDirectoryFiles.Add("TestLibDoc.xml");
223224
}
224225

@@ -437,7 +438,7 @@ public void It_implicitly_defines_compilation_constants_for_the_target_platform(
437438
});
438439

439440
AssertDefinedConstantsOutput(testAsset, targetFramework,
440-
new[] { "NETCOREAPP", "NETCOREAPP1_0_OR_GREATER", "NETCOREAPP1_1_OR_GREATER", "NETCOREAPP2_0_OR_GREATER", "NETCOREAPP2_1_OR_GREATER", "NETCOREAPP2_2_OR_GREATER", "NETCOREAPP3_0_OR_GREATER", "NETCOREAPP3_1_OR_GREATER", "NET", "NET5_0", "NET5_0_OR_GREATER" }
441+
new[] { "NETCOREAPP", "NETCOREAPP1_0_OR_GREATER", "NETCOREAPP1_1_OR_GREATER", "NETCOREAPP2_0_OR_GREATER", "NETCOREAPP2_1_OR_GREATER", "NETCOREAPP2_2_OR_GREATER", "NETCOREAPP3_0_OR_GREATER", "NETCOREAPP3_1_OR_GREATER", "NET", "NET5_0", "NET5_0_OR_GREATER" }
441442
.Concat(expectedDefines).ToArray());
442443
}
443444

@@ -934,7 +935,7 @@ public void It_can_build_with_dynamic_loading_enabled(string targetFramework, st
934935
testProject.AdditionalProperties["CopyLocalLockFileAssemblies"] = copyLocal.ToString().ToLower();
935936
}
936937

937-
var identifier = targetFramework + shouldSetRollForward + shouldCopyLocal + (rollForwardValue == null? "Null" : rollForwardValue);
938+
var identifier = targetFramework + shouldSetRollForward + shouldCopyLocal + (rollForwardValue == null ? "Null" : rollForwardValue);
938939
var testAsset = _testAssetsManager.CreateTestProject(testProject, identifier: identifier);
939940

940941
var buildCommand = new BuildCommand(testAsset);
@@ -963,7 +964,7 @@ public void It_can_build_with_dynamic_loading_enabled(string targetFramework, st
963964
string runtimeConfigFile = Path.Combine(outputDirectory.FullName, runtimeConfigName);
964965
string runtimeConfigContents = File.ReadAllText(runtimeConfigFile);
965966
JObject runtimeConfig = JObject.Parse(runtimeConfigContents);
966-
JToken rollForward= runtimeConfig["runtimeOptions"]["rollForward"];
967+
JToken rollForward = runtimeConfig["runtimeOptions"]["rollForward"];
967968
if (shouldSetRollForward)
968969
{
969970
rollForward.Value<string>().Should().Be(string.IsNullOrEmpty(rollForwardValue) ? "LatestMinor" : rollForwardValue);
@@ -1004,7 +1005,7 @@ public class ProjectNameWithSpacesClass
10041005
}");
10051006
string projectFolder = Path.Combine(testAsset.Path, testProject.Name);
10061007

1007-
var buildCommand = new BuildCommand(testAsset, $"{ testProject.Name}");
1008+
var buildCommand = new BuildCommand(testAsset, $"{testProject.Name}");
10081009
buildCommand
10091010
.Execute()
10101011
.Should()

src/Tests/Microsoft.NET.Build.Tests/GivenThatWeWantToBuildAWindowsDesktopProject.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ namespace Microsoft.NET.Build.Tests
1919
public class GivenThatWeWantToBuildAWindowsDesktopProject : SdkTest
2020
{
2121
public GivenThatWeWantToBuildAWindowsDesktopProject(ITestOutputHelper log) : base(log)
22-
{}
22+
{ }
2323

2424
[WindowsOnlyRequiresMSBuildVersionTheory("16.7.0")]
2525
[InlineData("UseWindowsForms")]
@@ -418,7 +418,7 @@ public void ItUsesCorrectWindowsSdkPackVersion(string targetFramework, bool? use
418418

419419
var testAsset = _testAssetsManager.CreateTestProject(testProject, identifier: targetFramework + useWindowsSDKPreview + windowsSdkPackageVersion);
420420

421-
string referencedWindowsSdkVersion = GetReferencedWindowsSdkVersion(testAsset);
421+
string referencedWindowsSdkVersion = GetReferencedWindowsSdkVersion(testAsset);
422422

423423
// The patch version of the Windows SDK Ref pack will change over time, so we use a '*' in the expected version to indicate that and replace it with
424424
// the 4th part of the version number of the resolved package.

src/Tests/Microsoft.NET.Build.Tests/WorkloadTests.cs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
using Microsoft.NET.TestFramework.Assertions;
1515
using Microsoft.NET.TestFramework.Commands;
1616
using Microsoft.NET.TestFramework.ProjectConstruction;
17+
using NuGet.Versioning;
1718
using Xunit;
1819
using Xunit.Abstractions;
1920

@@ -276,6 +277,11 @@ public void It_should_get_suggested_workload_by_GetRequiredWorkloads_target()
276277
[InlineData(ToolsetInfo.CurrentTargetFramework, ToolsetInfo.CurrentTargetFramework, "macos")]
277278
public void Given_multi_target_It_should_get_suggested_workload_by_GetRequiredWorkloads_target(string mainTfm, string referencingTfm, string expected)
278279
{
280+
// Skip Test if SDK is < 6.0.400
281+
var sdkVersion = SemanticVersion.Parse(TestContext.Current.ToolsetUnderTest.SdkVersion);
282+
if (new SemanticVersion(sdkVersion.Major, sdkVersion.Minor, sdkVersion.Patch) < new SemanticVersion(6, 0, 400))
283+
return; // MAUI was removed from earlier versions of the SDK
284+
279285
var mainProject = new TestProject()
280286
{
281287
Name = "MainProject",

src/Tests/dotnet-new.Tests/Approvals/DotnetNewHelpTests.CannotShowHelpForTemplate_PartialNameMatch.verified.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
No templates or subcommands found matching: 'classli'.
22
Did you mean one of the following templates?
33
dotnet new classlib -h
4+
dotnet new class -h
45

56
To list installed templates similar to 'classli', run:
67
dotnet new list classli

src/Tests/dotnet-new.Tests/Approvals/DotnetNewInstantiateTests.CanSuggestTypoCorrection_Command.verified.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
No templates or subcommands found matching: 'uninstal'.
22
Did you mean one of the following subcommands?
33
dotnet new uninstall
4+
dotnet new install
45

56
To list installed templates similar to 'uninstal', run:
67
dotnet new list uninstal

src/WebSdk/Publish/Targets/ComputeTargets/Microsoft.NET.Sdk.Publish.ComputeFiles.targets

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ Copyright (C) Microsoft Corporation. All rights reserved.
3030
<_IsAspNetCoreProject Condition="%(ProjectCapability.Identity) == 'AspNetCore'">true</_IsAspNetCoreProject>
3131
<_PublishProjectType Condition="'$(_PublishProjectType)' == '' and '$(_IsAspNetCoreProject)' == 'true' ">AspNetCore</_PublishProjectType>
3232
<_PublishProjectType Condition="'$(_PublishProjectType)' == '' and '$(WebJobName)' != '' and '$(WebJobType)' != ''">WebJob</_PublishProjectType>
33-
<_PublishProjectType Condition="'$(_PublishProjectType)' == '' ">UnKnown</_PublishProjectType>
33+
<_PublishProjectType Condition="'$(_PublishProjectType)' == '' ">Console</_PublishProjectType>
3434
</PropertyGroup>
3535
</Target>
3636

src/WebSdk/Publish/Targets/CopyTargets/Microsoft.NET.Sdk.Publish.CopyFiles.targets

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ Copyright (C) Microsoft Corporation. All rights reserved.
2020
_CopyFilesToPublishIntermediateOutputPath;
2121
_CopyAspNetCoreFilesToIntermediateOutputPath;
2222
_CopyWebJobFilesToIntermediateOutputPath;
23+
_CopyConsoleFilesToIntermediateOutputPath;
2324
</_DotNetPublishCopyFiles>
2425
</PropertyGroup>
2526

@@ -90,7 +91,7 @@ Copyright (C) Microsoft Corporation. All rights reserved.
9091
</PropertyGroup>
9192
</Target>
9293

93-
<!--********************************************************************-->
94+
<!--********************************************************************-->
9495
<!-- Target _CopyWebJobFilesToIntermediateOutputPath -->
9596
<!--********************************************************************-->
9697
<PropertyGroup>
@@ -116,6 +117,32 @@ Copyright (C) Microsoft Corporation. All rights reserved.
116117
</PropertyGroup>
117118
</Target>
118119

120+
<!--********************************************************************-->
121+
<!-- Target _CopyConsoleFilesToIntermediateOutputPath -->
122+
<!--********************************************************************-->
123+
<PropertyGroup>
124+
<_CopyConsoleFilesToIntermediateOutputPathDependsOn>
125+
$(_CopyConsoleFilesToIntermediateOutputPathDependsOn);
126+
_PrepareForConsolePublish;
127+
Publish;
128+
</_CopyConsoleFilesToIntermediateOutputPathDependsOn>
129+
</PropertyGroup>
130+
131+
<Target Name="_CopyConsoleFilesToIntermediateOutputPath"
132+
Condition="'$(_PublishProjectType)' == 'Console'"
133+
DependsOnTargets="$(_CopyConsoleFilesToIntermediateOutputPathDependsOn)">
134+
</Target>
135+
136+
<!--********************************************************************-->
137+
<!-- Target _PrepareForConsolePublish -->
138+
<!--********************************************************************-->
139+
<Target Name="_PrepareForConsolePublish">
140+
<PropertyGroup>
141+
<PublishDir>$(PublishIntermediateOutputPath)</PublishDir>
142+
<Configuration>$(PublishConfiguration)</Configuration>
143+
</PropertyGroup>
144+
</Target>
145+
119146
<!--********************************************************************-->
120147
<!-- This will ensure that all values have the required metadata -->
121148
<!--********************************************************************-->

0 commit comments

Comments
 (0)