diff --git a/src/Compiler/Microsoft.AspNetCore.Mvc.Razor.Extensions.Version2_X/test/IntegrationTests/InstrumentationPassIntegrationTest.cs b/src/Compiler/Microsoft.AspNetCore.Mvc.Razor.Extensions.Version2_X/test/IntegrationTests/InstrumentationPassIntegrationTest.cs index 77a5e4f75a1..322997c72f2 100644 --- a/src/Compiler/Microsoft.AspNetCore.Mvc.Razor.Extensions.Version2_X/test/IntegrationTests/InstrumentationPassIntegrationTest.cs +++ b/src/Compiler/Microsoft.AspNetCore.Mvc.Razor.Extensions.Version2_X/test/IntegrationTests/InstrumentationPassIntegrationTest.cs @@ -31,36 +31,36 @@ public InstrumentationPassIntegrationTest() public void BasicTest() { // Arrange - var descriptors = new[] - { - CreateTagHelperDescriptor( - tagName: "p", - typeName: "PTagHelper", - assemblyName: "TestAssembly"), - CreateTagHelperDescriptor( - tagName: "form", - typeName: "FormTagHelper", - assemblyName: "TestAssembly"), - CreateTagHelperDescriptor( - tagName: "input", - typeName: "InputTagHelper", - assemblyName: "TestAssembly", - attributes: new Action[] - { - builder => builder - .Name("value") - .PropertyName("FooProp") - .TypeName("System.String"), // Gets preallocated - builder => builder - .Name("date") - .PropertyName("BarProp") - .TypeName("System.DateTime"), // Doesn't get preallocated - }) - }; + TagHelperCollection tagHelpers = + [ + CreateTagHelperDescriptor( + tagName: "p", + typeName: "PTagHelper", + assemblyName: "TestAssembly"), + CreateTagHelperDescriptor( + tagName: "form", + typeName: "FormTagHelper", + assemblyName: "TestAssembly"), + CreateTagHelperDescriptor( + tagName: "input", + typeName: "InputTagHelper", + assemblyName: "TestAssembly", + attributes: + [ + builder => builder + .Name("value") + .PropertyName("FooProp") + .TypeName("System.String"), // Gets preallocated + builder => builder + .Name("date") + .PropertyName("BarProp") + .TypeName("System.DateTime"), // Doesn't get preallocated + ]) + ]; var engine = CreateProjectEngine(b => { - b.AddTagHelpers(descriptors); + b.SetTagHelpers(tagHelpers); b.Features.Add(new InstrumentationPass()); // This test includes templates diff --git a/src/Compiler/Microsoft.AspNetCore.Razor.Language/legacyTest/Legacy/TagHelperBlockRewriterTest.cs b/src/Compiler/Microsoft.AspNetCore.Razor.Language/legacyTest/Legacy/TagHelperBlockRewriterTest.cs index 0f8aaf1d83e..6ffcfd2aa46 100644 --- a/src/Compiler/Microsoft.AspNetCore.Razor.Language/legacyTest/Legacy/TagHelperBlockRewriterTest.cs +++ b/src/Compiler/Microsoft.AspNetCore.Razor.Language/legacyTest/Legacy/TagHelperBlockRewriterTest.cs @@ -3,7 +3,6 @@ using System; using System.Collections.Generic; -using System.Collections.Immutable; using System.Globalization; using Microsoft.AspNetCore.Razor.Language.Components; using Xunit; @@ -12,7 +11,7 @@ namespace Microsoft.AspNetCore.Razor.Language.Legacy; public class TagHelperBlockRewriterTest : TagHelperRewritingTestBase { - public static ImmutableArray SymbolBoundAttributes_Descriptors = + public static readonly TagHelperCollection SymbolBoundAttributes_TagHelpers = [ TagHelperDescriptorBuilder.CreateTagHelper("CatchAllTagHelper", "SomeAssembly") .TagMatchingRuleDescriptor(rule => rule @@ -48,46 +47,46 @@ public class TagHelperBlockRewriterTest : TagHelperRewritingTestBase [Fact] public void CanHandleSymbolBoundAttributes1() { - EvaluateData(SymbolBoundAttributes_Descriptors, ""); + EvaluateData(SymbolBoundAttributes_TagHelpers, ""); } [Fact] public void CanHandleSymbolBoundAttributes2() { - EvaluateData(SymbolBoundAttributes_Descriptors, ""); + EvaluateData(SymbolBoundAttributes_TagHelpers, ""); } [Fact] public void CanHandleSymbolBoundAttributes3() { - EvaluateData(SymbolBoundAttributes_Descriptors, ""); + EvaluateData(SymbolBoundAttributes_TagHelpers, ""); } [Fact] public void CanHandleSymbolBoundAttributes4() { - EvaluateData(SymbolBoundAttributes_Descriptors, ""); + EvaluateData(SymbolBoundAttributes_TagHelpers, ""); } [Fact] public void CanHandleSymbolBoundAttributes5() { - EvaluateData(SymbolBoundAttributes_Descriptors, ""); + EvaluateData(SymbolBoundAttributes_TagHelpers, ""); } [Fact] public void CanHandleSymbolBoundAttributes6() { - EvaluateData(SymbolBoundAttributes_Descriptors, "
"); + EvaluateData(SymbolBoundAttributes_TagHelpers, "
"); } [Fact] public void CanHandleSymbolBoundAttributes7() { - EvaluateData(SymbolBoundAttributes_Descriptors, "
"); + EvaluateData(SymbolBoundAttributes_TagHelpers, "
"); } - public static ImmutableArray WithoutEndTag_Descriptors = + public static readonly TagHelperCollection WithoutEndTag_TagHelpers = [ TagHelperDescriptorBuilder.CreateTagHelper("InputTagHelper", "SomeAssembly") .TagMatchingRuleDescriptor(rule => rule @@ -99,34 +98,34 @@ public void CanHandleSymbolBoundAttributes7() [Fact] public void CanHandleWithoutEndTagTagStructure1() { - EvaluateData(WithoutEndTag_Descriptors, ""); + EvaluateData(WithoutEndTag_TagHelpers, ""); } [Fact] public void CanHandleWithoutEndTagTagStructure2() { - EvaluateData(WithoutEndTag_Descriptors, ""); + EvaluateData(WithoutEndTag_TagHelpers, ""); } [Fact] public void CanHandleWithoutEndTagTagStructure3() { - EvaluateData(WithoutEndTag_Descriptors, ""); + EvaluateData(WithoutEndTag_TagHelpers, ""); } [Fact] public void CanHandleWithoutEndTagTagStructure4() { - EvaluateData(WithoutEndTag_Descriptors, ""); + EvaluateData(WithoutEndTag_TagHelpers, ""); } [Fact] public void CanHandleWithoutEndTagTagStructure5() { - EvaluateData(WithoutEndTag_Descriptors, "
"); + EvaluateData(WithoutEndTag_TagHelpers, "
"); } - public static ImmutableArray GetTagStructureCompatibilityDescriptors(TagStructure structure1, TagStructure structure2) + public static TagHelperCollection GetTagStructureCompatibilityTagHelpers(TagStructure structure1, TagStructure structure2) { return [ @@ -147,87 +146,87 @@ public static ImmutableArray GetTagStructureCompatibilityDe public void AllowsCompatibleTagStructures1() { // Arrange - var descriptors = GetTagStructureCompatibilityDescriptors(TagStructure.Unspecified, TagStructure.Unspecified); + var tagHelpers = GetTagStructureCompatibilityTagHelpers(TagStructure.Unspecified, TagStructure.Unspecified); // Act & Assert - EvaluateData(descriptors, ""); + EvaluateData(tagHelpers, ""); } [Fact] public void AllowsCompatibleTagStructures2() { // Arrange - var descriptors = GetTagStructureCompatibilityDescriptors(TagStructure.Unspecified, TagStructure.Unspecified); + var tagHelpers = GetTagStructureCompatibilityTagHelpers(TagStructure.Unspecified, TagStructure.Unspecified); // Act & Assert - EvaluateData(descriptors, ""); + EvaluateData(tagHelpers, ""); } [Fact] public void AllowsCompatibleTagStructures3() { // Arrange - var descriptors = GetTagStructureCompatibilityDescriptors(TagStructure.Unspecified, TagStructure.WithoutEndTag); + var tagHelpers = GetTagStructureCompatibilityTagHelpers(TagStructure.Unspecified, TagStructure.WithoutEndTag); // Act & Assert - EvaluateData(descriptors, ""); + EvaluateData(tagHelpers, ""); } [Fact] public void AllowsCompatibleTagStructures4() { // Arrange - var descriptors = GetTagStructureCompatibilityDescriptors(TagStructure.WithoutEndTag, TagStructure.WithoutEndTag); + var tagHelpers = GetTagStructureCompatibilityTagHelpers(TagStructure.WithoutEndTag, TagStructure.WithoutEndTag); // Act & Assert - EvaluateData(descriptors, ""); + EvaluateData(tagHelpers, ""); } [Fact] public void AllowsCompatibleTagStructures5() { // Arrange - var descriptors = GetTagStructureCompatibilityDescriptors(TagStructure.Unspecified, TagStructure.NormalOrSelfClosing); + var tagHelpers = GetTagStructureCompatibilityTagHelpers(TagStructure.Unspecified, TagStructure.NormalOrSelfClosing); // Act & Assert - EvaluateData(descriptors, ""); + EvaluateData(tagHelpers, ""); } [Fact] public void AllowsCompatibleTagStructures6() { // Arrange - var descriptors = GetTagStructureCompatibilityDescriptors(TagStructure.Unspecified, TagStructure.WithoutEndTag); + var tagHelpers = GetTagStructureCompatibilityTagHelpers(TagStructure.Unspecified, TagStructure.WithoutEndTag); // Act & Assert - EvaluateData(descriptors, ""); + EvaluateData(tagHelpers, ""); } [Fact] public void AllowsCompatibleTagStructures7() { // Arrange - var descriptors = GetTagStructureCompatibilityDescriptors(TagStructure.NormalOrSelfClosing, TagStructure.Unspecified); + var tagHelpers = GetTagStructureCompatibilityTagHelpers(TagStructure.NormalOrSelfClosing, TagStructure.Unspecified); // Act & Assert - EvaluateData(descriptors, ""); + EvaluateData(tagHelpers, ""); } [Fact] public void AllowsCompatibleTagStructures8() { // Arrange - var descriptors = GetTagStructureCompatibilityDescriptors(TagStructure.WithoutEndTag, TagStructure.Unspecified); + var tagHelpers = GetTagStructureCompatibilityTagHelpers(TagStructure.WithoutEndTag, TagStructure.Unspecified); // Act & Assert - EvaluateData(descriptors, ""); + EvaluateData(tagHelpers, ""); } [Fact] public void AllowsCompatibleTagStructures_DirectiveAttribute_SelfClosing() { // Arrange - ImmutableArray descriptors = + TagHelperCollection tagHelpers = [ TagHelperDescriptorBuilder.CreateEventHandler("InputTagHelper1", "SomeAssembly") .TagMatchingRuleDescriptor(rule => rule @@ -239,14 +238,14 @@ public void AllowsCompatibleTagStructures_DirectiveAttribute_SelfClosing() ]; // Act & Assert - EvaluateData(descriptors, ""); + EvaluateData(tagHelpers, ""); } [Fact] public void AllowsCompatibleTagStructures_DirectiveAttribute_Void() { // Arrange - ImmutableArray descriptors = + TagHelperCollection tagHelpers = [ TagHelperDescriptorBuilder.CreateEventHandler("InputTagHelper1", "SomeAssembly") .TagMatchingRuleDescriptor(rule => rule @@ -258,7 +257,7 @@ public void AllowsCompatibleTagStructures_DirectiveAttribute_Void() ]; // Act & Assert - EvaluateData(descriptors, ""); + EvaluateData(tagHelpers, ""); } [Fact] @@ -429,7 +428,7 @@ public void CreatesErrorForMalformedTagHelper8() RunParseTreeRewriterTest("

", "strong", "p"); } - public static ImmutableArray CodeTagHelperAttributes_Descriptors = + public static readonly TagHelperCollection CodeTagHelperAttributes_TagHelpers = [ TagHelperDescriptorBuilder.CreateTagHelper("PersonTagHelper", "personAssembly") .TagMatchingRuleDescriptor(rule => rule.RequireTagName("person")) @@ -451,79 +450,79 @@ public void CreatesErrorForMalformedTagHelper8() [Fact] public void UnderstandsMultipartNonStringTagHelperAttributes() { - EvaluateData(CodeTagHelperAttributes_Descriptors, " 123)()\" />"); + EvaluateData(CodeTagHelperAttributes_TagHelpers, " 123)()\" />"); } [Fact] public void CreatesMarkupCodeSpansForNonStringTagHelperAttributes1() { - EvaluateData(CodeTagHelperAttributes_Descriptors, ""); + EvaluateData(CodeTagHelperAttributes_TagHelpers, ""); } [Fact] public void CreatesMarkupCodeSpansForNonStringTagHelperAttributes2() { - EvaluateData(CodeTagHelperAttributes_Descriptors, ""); + EvaluateData(CodeTagHelperAttributes_TagHelpers, ""); } [Fact] public void CreatesMarkupCodeSpansForNonStringTagHelperAttributes3() { - EvaluateData(CodeTagHelperAttributes_Descriptors, ""); + EvaluateData(CodeTagHelperAttributes_TagHelpers, ""); } [Fact] public void CreatesMarkupCodeSpansForNonStringTagHelperAttributes4() { - EvaluateData(CodeTagHelperAttributes_Descriptors, ""); + EvaluateData(CodeTagHelperAttributes_TagHelpers, ""); } [Fact] public void CreatesMarkupCodeSpansForNonStringTagHelperAttributes5() { - EvaluateData(CodeTagHelperAttributes_Descriptors, ""); + EvaluateData(CodeTagHelperAttributes_TagHelpers, ""); } [Fact] public void CreatesMarkupCodeSpansForNonStringTagHelperAttributes6() { - EvaluateData(CodeTagHelperAttributes_Descriptors, ""); + EvaluateData(CodeTagHelperAttributes_TagHelpers, ""); } [Fact] public void CreatesMarkupCodeSpansForNonStringTagHelperAttributes7() { - EvaluateData(CodeTagHelperAttributes_Descriptors, ""); + EvaluateData(CodeTagHelperAttributes_TagHelpers, ""); } [Fact] public void CreatesMarkupCodeSpansForNonStringTagHelperAttributes8() { - EvaluateData(CodeTagHelperAttributes_Descriptors, ""); + EvaluateData(CodeTagHelperAttributes_TagHelpers, ""); } [Fact] public void CreatesMarkupCodeSpansForNonStringTagHelperAttributes9() { - EvaluateData(CodeTagHelperAttributes_Descriptors, ""); + EvaluateData(CodeTagHelperAttributes_TagHelpers, ""); } [Fact] public void CreatesMarkupCodeSpansForNonStringTagHelperAttributes10() { - EvaluateData(CodeTagHelperAttributes_Descriptors, ""); + EvaluateData(CodeTagHelperAttributes_TagHelpers, ""); } [Fact] public void CreatesMarkupCodeSpansForNonStringTagHelperAttributes11() { - EvaluateData(CodeTagHelperAttributes_Descriptors, ""); + EvaluateData(CodeTagHelperAttributes_TagHelpers, ""); } [Fact] public void CreatesMarkupCodeSpansForNonStringTagHelperAttributes12() { - EvaluateData(CodeTagHelperAttributes_Descriptors, ""); + EvaluateData(CodeTagHelperAttributes_TagHelpers, ""); } [Fact] @@ -838,7 +837,7 @@ public void UnderstandsEmptyAttributeTagHelpers5() RunParseTreeRewriterTest("

", "p"); } - public static ImmutableArray EmptyTagHelperBoundAttribute_Descriptors = + public static readonly TagHelperCollection EmptyTagHelperBoundAttribute_TagHelpers = [ TagHelperDescriptorBuilder.CreateTagHelper("mythTagHelper", "SomeAssembly") .TagMatchingRuleDescriptor(rule => rule.RequireTagName("myth")) @@ -856,85 +855,85 @@ public void UnderstandsEmptyAttributeTagHelpers5() [Fact] public void CreatesErrorForEmptyTagHelperBoundAttributes1() { - EvaluateData(EmptyTagHelperBoundAttribute_Descriptors, ""); + EvaluateData(EmptyTagHelperBoundAttribute_TagHelpers, ""); } [Fact] public void CreatesErrorForEmptyTagHelperBoundAttributes2() { - EvaluateData(EmptyTagHelperBoundAttribute_Descriptors, ""); + EvaluateData(EmptyTagHelperBoundAttribute_TagHelpers, ""); } [Fact] public void CreatesErrorForEmptyTagHelperBoundAttributes3() { - EvaluateData(EmptyTagHelperBoundAttribute_Descriptors, ""); + EvaluateData(EmptyTagHelperBoundAttribute_TagHelpers, ""); } [Fact] public void CreatesErrorForEmptyTagHelperBoundAttributes4() { - EvaluateData(EmptyTagHelperBoundAttribute_Descriptors, ""); + EvaluateData(EmptyTagHelperBoundAttribute_TagHelpers, ""); } [Fact] public void CreatesErrorForEmptyTagHelperBoundAttributes5() { - EvaluateData(EmptyTagHelperBoundAttribute_Descriptors, ""); + EvaluateData(EmptyTagHelperBoundAttribute_TagHelpers, ""); } [Fact] public void CreatesErrorForEmptyTagHelperBoundAttributes6() { - EvaluateData(EmptyTagHelperBoundAttribute_Descriptors, ""); + EvaluateData(EmptyTagHelperBoundAttribute_TagHelpers, ""); } [Fact] public void CreatesErrorForEmptyTagHelperBoundAttributes7() { - EvaluateData(EmptyTagHelperBoundAttribute_Descriptors, ""); + EvaluateData(EmptyTagHelperBoundAttribute_TagHelpers, ""); } [Fact] public void CreatesErrorForEmptyTagHelperBoundAttributes8() { - EvaluateData(EmptyTagHelperBoundAttribute_Descriptors, ""); + EvaluateData(EmptyTagHelperBoundAttribute_TagHelpers, ""); } [Fact] public void CreatesErrorForEmptyTagHelperBoundAttributes9() { - EvaluateData(EmptyTagHelperBoundAttribute_Descriptors, ""); + EvaluateData(EmptyTagHelperBoundAttribute_TagHelpers, ""); } [Fact] public void CreatesErrorForEmptyTagHelperBoundAttributes10() { - EvaluateData(EmptyTagHelperBoundAttribute_Descriptors, ""); + EvaluateData(EmptyTagHelperBoundAttribute_TagHelpers, ""); } [Fact] public void CreatesErrorForEmptyTagHelperBoundAttributes11() { - EvaluateData(EmptyTagHelperBoundAttribute_Descriptors, ""); + EvaluateData(EmptyTagHelperBoundAttribute_TagHelpers, ""); } [Fact] public void CreatesErrorForEmptyTagHelperBoundAttributes12() { - EvaluateData(EmptyTagHelperBoundAttribute_Descriptors, ""); + EvaluateData(EmptyTagHelperBoundAttribute_TagHelpers, ""); } [Fact] public void CreatesErrorForEmptyTagHelperBoundAttributes13() { - EvaluateData(EmptyTagHelperBoundAttribute_Descriptors, ""); + EvaluateData(EmptyTagHelperBoundAttribute_TagHelpers, ""); } [Fact] public void CreatesErrorForEmptyTagHelperBoundAttributes14() { - EvaluateData(EmptyTagHelperBoundAttribute_Descriptors, ""); + EvaluateData(EmptyTagHelperBoundAttribute_TagHelpers, ""); } [Fact] @@ -1250,7 +1249,7 @@ public void GeneratesExpectedOutputForUnboundDataDashAttributes_Block7() RunParseTreeRewriterTest(document, "input"); } - public static ImmutableArray MinimizedAttribute_Descriptors = + public static readonly TagHelperCollection MinimizedAttribute_TagHelpers = [ TagHelperDescriptorBuilder.CreateTagHelper("InputTagHelper1", "SomeAssembly") .TagMatchingRuleDescriptor(rule => rule @@ -1306,7 +1305,7 @@ public void UnderstandsMinimizedAttributes_Document1() var document = ""; // Act & Assert - EvaluateData(MinimizedAttribute_Descriptors, document); + EvaluateData(MinimizedAttribute_TagHelpers, document); } [Fact] @@ -1316,7 +1315,7 @@ public void UnderstandsMinimizedAttributes_Document2() var document = "

"; // Act & Assert - EvaluateData(MinimizedAttribute_Descriptors, document); + EvaluateData(MinimizedAttribute_TagHelpers, document); } [Fact] @@ -1326,7 +1325,7 @@ public void UnderstandsMinimizedAttributes_Document3() var document = ""; // Act & Assert - EvaluateData(MinimizedAttribute_Descriptors, document); + EvaluateData(MinimizedAttribute_TagHelpers, document); } [Fact] @@ -1336,7 +1335,7 @@ public void UnderstandsMinimizedAttributes_Document4() var document = ""; // Act & Assert - EvaluateData(MinimizedAttribute_Descriptors, document); + EvaluateData(MinimizedAttribute_TagHelpers, document); } [Fact] @@ -1346,7 +1345,7 @@ public void UnderstandsMinimizedAttributes_Document5() var document = "

"; // Act & Assert - EvaluateData(MinimizedAttribute_Descriptors, document); + EvaluateData(MinimizedAttribute_TagHelpers, document); } [Fact] @@ -1356,7 +1355,7 @@ public void UnderstandsMinimizedAttributes_Document6() var document = ""; // Act & Assert - EvaluateData(MinimizedAttribute_Descriptors, document); + EvaluateData(MinimizedAttribute_TagHelpers, document); } [Fact] @@ -1366,7 +1365,7 @@ public void UnderstandsMinimizedAttributes_Document7() var document = ""; // Act & Assert - EvaluateData(MinimizedAttribute_Descriptors, document); + EvaluateData(MinimizedAttribute_TagHelpers, document); } [Fact] @@ -1376,7 +1375,7 @@ public void UnderstandsMinimizedAttributes_Document8() var document = ""; // Act & Assert - EvaluateData(MinimizedAttribute_Descriptors, document); + EvaluateData(MinimizedAttribute_TagHelpers, document); } [Fact] @@ -1386,7 +1385,7 @@ public void UnderstandsMinimizedAttributes_Document9() var document = ""; // Act & Assert - EvaluateData(MinimizedAttribute_Descriptors, document); + EvaluateData(MinimizedAttribute_TagHelpers, document); } [Fact] @@ -1396,7 +1395,7 @@ public void UnderstandsMinimizedAttributes_Document10() var document = ""; // Act & Assert - EvaluateData(MinimizedAttribute_Descriptors, document); + EvaluateData(MinimizedAttribute_TagHelpers, document); } [Fact] @@ -1406,7 +1405,7 @@ public void UnderstandsMinimizedAttributes_Document11() var document = ""; // Act & Assert - EvaluateData(MinimizedAttribute_Descriptors, document); + EvaluateData(MinimizedAttribute_TagHelpers, document); } [Fact] @@ -1416,7 +1415,7 @@ public void UnderstandsMinimizedAttributes_Document12() var document = ""; // Act & Assert - EvaluateData(MinimizedAttribute_Descriptors, document); + EvaluateData(MinimizedAttribute_TagHelpers, document); } [Fact] @@ -1426,7 +1425,7 @@ public void UnderstandsMinimizedAttributes_Document13() var document = ""; // Act & Assert - EvaluateData(MinimizedAttribute_Descriptors, document); + EvaluateData(MinimizedAttribute_TagHelpers, document); } [Fact] @@ -1436,7 +1435,7 @@ public void UnderstandsMinimizedAttributes_Document14() var document = ""; // Act & Assert - EvaluateData(MinimizedAttribute_Descriptors, document); + EvaluateData(MinimizedAttribute_TagHelpers, document); } [Fact] @@ -1446,7 +1445,7 @@ public void UnderstandsMinimizedAttributes_Document15() var document = ""; // Act & Assert - EvaluateData(MinimizedAttribute_Descriptors, document); + EvaluateData(MinimizedAttribute_TagHelpers, document); } [Fact] @@ -1456,7 +1455,7 @@ public void UnderstandsMinimizedAttributes_Document16() var document = ""; // Act & Assert - EvaluateData(MinimizedAttribute_Descriptors, document); + EvaluateData(MinimizedAttribute_TagHelpers, document); } [Fact] @@ -1466,7 +1465,7 @@ public void UnderstandsMinimizedAttributes_Document17() var document = "

"; // Act & Assert - EvaluateData(MinimizedAttribute_Descriptors, document); + EvaluateData(MinimizedAttribute_TagHelpers, document); } [Fact] @@ -1476,7 +1475,7 @@ public void UnderstandsMinimizedAttributes_Document18() var document = ""; // Act & Assert - EvaluateData(MinimizedAttribute_Descriptors, document); + EvaluateData(MinimizedAttribute_TagHelpers, document); } [Fact] @@ -1486,7 +1485,7 @@ public void UnderstandsMinimizedAttributes_Document19() var document = "

"; // Act & Assert - EvaluateData(MinimizedAttribute_Descriptors, document); + EvaluateData(MinimizedAttribute_TagHelpers, document); } [Fact] @@ -1496,7 +1495,7 @@ public void UnderstandsMinimizedAttributes_Document20() var document = ""; // Act & Assert - EvaluateData(MinimizedAttribute_Descriptors, document); + EvaluateData(MinimizedAttribute_TagHelpers, document); } [Fact] @@ -1506,7 +1505,7 @@ public void UnderstandsMinimizedAttributes_Document21() var document = "

"; // Act & Assert - EvaluateData(MinimizedAttribute_Descriptors, document); + EvaluateData(MinimizedAttribute_TagHelpers, document); } [Fact] @@ -1516,7 +1515,7 @@ public void UnderstandsMinimizedAttributes_Document22() var document = ""; // Act & Assert - EvaluateData(MinimizedAttribute_Descriptors, document); + EvaluateData(MinimizedAttribute_TagHelpers, document); } [Fact] @@ -1526,7 +1525,7 @@ public void UnderstandsMinimizedAttributes_Document23() var document = "

"; // Act & Assert - EvaluateData(MinimizedAttribute_Descriptors, document); + EvaluateData(MinimizedAttribute_TagHelpers, document); } [Fact] @@ -1536,7 +1535,7 @@ public void UnderstandsMinimizedAttributes_Document24() var document = ""; // Act & Assert - EvaluateData(MinimizedAttribute_Descriptors, document); + EvaluateData(MinimizedAttribute_TagHelpers, document); } [Fact] @@ -1546,7 +1545,7 @@ public void UnderstandsMinimizedAttributes_Document25() var document = ""; // Act & Assert - EvaluateData(MinimizedAttribute_Descriptors, document); + EvaluateData(MinimizedAttribute_TagHelpers, document); } [Fact] @@ -1556,7 +1555,7 @@ public void UnderstandsMinimizedAttributes_Document26() var document = ""; // Act & Assert - EvaluateData(MinimizedAttribute_Descriptors, document); + EvaluateData(MinimizedAttribute_TagHelpers, document); } [Fact] @@ -1566,7 +1565,7 @@ public void UnderstandsMinimizedAttributes_Document27() var document = "

"; // Act & Assert - EvaluateData(MinimizedAttribute_Descriptors, document); + EvaluateData(MinimizedAttribute_TagHelpers, document); } [Fact] @@ -1576,7 +1575,7 @@ public void UnderstandsMinimizedAttributes_Document28() var document = ""; // Act & Assert - EvaluateData(MinimizedAttribute_Descriptors, document); + EvaluateData(MinimizedAttribute_TagHelpers, document); } [Fact] @@ -1586,7 +1585,7 @@ public void UnderstandsMinimizedAttributes_Document29() var document = "

"; // Act & Assert - EvaluateData(MinimizedAttribute_Descriptors, document); + EvaluateData(MinimizedAttribute_TagHelpers, document); } [Fact] @@ -1597,7 +1596,7 @@ public void UnderstandsMinimizedAttributes_Document30() var document = $""; // Act & Assert - EvaluateData(MinimizedAttribute_Descriptors, document); + EvaluateData(MinimizedAttribute_TagHelpers, document); } [Fact] @@ -1608,7 +1607,7 @@ public void UnderstandsMinimizedAttributes_Document31() var document = $"

"; // Act & Assert - EvaluateData(MinimizedAttribute_Descriptors, document); + EvaluateData(MinimizedAttribute_TagHelpers, document); } [Fact] @@ -1619,7 +1618,7 @@ public void UnderstandsMinimizedAttributes_Document32() var document = $""; // Act & Assert - EvaluateData(MinimizedAttribute_Descriptors, document); + EvaluateData(MinimizedAttribute_TagHelpers, document); } [Fact] @@ -1630,7 +1629,7 @@ public void UnderstandsMinimizedAttributes_Document33() var document = $"

"; // Act & Assert - EvaluateData(MinimizedAttribute_Descriptors, document); + EvaluateData(MinimizedAttribute_TagHelpers, document); } [Fact] @@ -1643,7 +1642,7 @@ public void UnderstandsMinimizedAttributes_Block1() document = $$"""@{{{document}}}"""; // Act & Assert - EvaluateData(MinimizedAttribute_Descriptors, document); + EvaluateData(MinimizedAttribute_TagHelpers, document); } [Fact] @@ -1656,7 +1655,7 @@ public void UnderstandsMinimizedAttributes_Block2() document = $$"""@{{{document}}}"""; // Act & Assert - EvaluateData(MinimizedAttribute_Descriptors, document); + EvaluateData(MinimizedAttribute_TagHelpers, document); } [Fact] @@ -1669,7 +1668,7 @@ public void UnderstandsMinimizedAttributes_Block3() document = $$"""@{{{document}}}"""; // Act & Assert - EvaluateData(MinimizedAttribute_Descriptors, document); + EvaluateData(MinimizedAttribute_TagHelpers, document); } [Fact] @@ -1682,7 +1681,7 @@ public void UnderstandsMinimizedAttributes_Block4() document = $$"""@{{{document}}}"""; // Act & Assert - EvaluateData(MinimizedAttribute_Descriptors, document); + EvaluateData(MinimizedAttribute_TagHelpers, document); } [Fact] @@ -1695,7 +1694,7 @@ public void UnderstandsMinimizedAttributes_Block5() document = $$"""@{{{document}}}"""; // Act & Assert - EvaluateData(MinimizedAttribute_Descriptors, document); + EvaluateData(MinimizedAttribute_TagHelpers, document); } [Fact] @@ -1708,7 +1707,7 @@ public void UnderstandsMinimizedAttributes_Block6() document = $$"""@{{{document}}}"""; // Act & Assert - EvaluateData(MinimizedAttribute_Descriptors, document); + EvaluateData(MinimizedAttribute_TagHelpers, document); } [Fact] @@ -1721,7 +1720,7 @@ public void UnderstandsMinimizedAttributes_Block7() document = $$"""@{{{document}}}"""; // Act & Assert - EvaluateData(MinimizedAttribute_Descriptors, document); + EvaluateData(MinimizedAttribute_TagHelpers, document); } [Fact] @@ -1734,7 +1733,7 @@ public void UnderstandsMinimizedAttributes_Block8() document = $$"""@{{{document}}}"""; // Act & Assert - EvaluateData(MinimizedAttribute_Descriptors, document); + EvaluateData(MinimizedAttribute_TagHelpers, document); } [Fact] @@ -1747,7 +1746,7 @@ public void UnderstandsMinimizedAttributes_Block9() document = $$"""@{{{document}}}"""; // Act & Assert - EvaluateData(MinimizedAttribute_Descriptors, document); + EvaluateData(MinimizedAttribute_TagHelpers, document); } [Fact] @@ -1760,7 +1759,7 @@ public void UnderstandsMinimizedAttributes_Block10() document = $$"""@{{{document}}}"""; // Act & Assert - EvaluateData(MinimizedAttribute_Descriptors, document); + EvaluateData(MinimizedAttribute_TagHelpers, document); } [Fact] @@ -1773,7 +1772,7 @@ public void UnderstandsMinimizedAttributes_Block11() document = $$"""@{{{document}}}"""; // Act & Assert - EvaluateData(MinimizedAttribute_Descriptors, document); + EvaluateData(MinimizedAttribute_TagHelpers, document); } [Fact] @@ -1786,7 +1785,7 @@ public void UnderstandsMinimizedAttributes_Block12() document = $$"""@{{{document}}}"""; // Act & Assert - EvaluateData(MinimizedAttribute_Descriptors, document); + EvaluateData(MinimizedAttribute_TagHelpers, document); } [Fact] @@ -1799,7 +1798,7 @@ public void UnderstandsMinimizedAttributes_Block13() document = $$"""@{{{document}}}"""; // Act & Assert - EvaluateData(MinimizedAttribute_Descriptors, document); + EvaluateData(MinimizedAttribute_TagHelpers, document); } [Fact] @@ -1812,7 +1811,7 @@ public void UnderstandsMinimizedAttributes_Block14() document = $$"""@{{{document}}}"""; // Act & Assert - EvaluateData(MinimizedAttribute_Descriptors, document); + EvaluateData(MinimizedAttribute_TagHelpers, document); } [Fact] @@ -1825,7 +1824,7 @@ public void UnderstandsMinimizedAttributes_Block15() document = $$"""@{{{document}}}"""; // Act & Assert - EvaluateData(MinimizedAttribute_Descriptors, document); + EvaluateData(MinimizedAttribute_TagHelpers, document); } [Fact] @@ -1838,7 +1837,7 @@ public void UnderstandsMinimizedAttributes_Block16() document = $$"""@{{{document}}}"""; // Act & Assert - EvaluateData(MinimizedAttribute_Descriptors, document); + EvaluateData(MinimizedAttribute_TagHelpers, document); } [Fact] @@ -1851,7 +1850,7 @@ public void UnderstandsMinimizedAttributes_Block17() document = $$"""@{{{document}}}"""; // Act & Assert - EvaluateData(MinimizedAttribute_Descriptors, document); + EvaluateData(MinimizedAttribute_TagHelpers, document); } [Fact] @@ -1864,7 +1863,7 @@ public void UnderstandsMinimizedAttributes_Block18() document = $$"""@{{{document}}}"""; // Act & Assert - EvaluateData(MinimizedAttribute_Descriptors, document); + EvaluateData(MinimizedAttribute_TagHelpers, document); } [Fact] @@ -1877,7 +1876,7 @@ public void UnderstandsMinimizedAttributes_Block19() document = $$"""@{{{document}}}"""; // Act & Assert - EvaluateData(MinimizedAttribute_Descriptors, document); + EvaluateData(MinimizedAttribute_TagHelpers, document); } [Fact] @@ -1890,7 +1889,7 @@ public void UnderstandsMinimizedAttributes_Block20() document = $$"""@{{{document}}}"""; // Act & Assert - EvaluateData(MinimizedAttribute_Descriptors, document); + EvaluateData(MinimizedAttribute_TagHelpers, document); } [Fact] @@ -1903,7 +1902,7 @@ public void UnderstandsMinimizedAttributes_Block21() document = $$"""@{{{document}}}"""; // Act & Assert - EvaluateData(MinimizedAttribute_Descriptors, document); + EvaluateData(MinimizedAttribute_TagHelpers, document); } [Fact] @@ -1916,7 +1915,7 @@ public void UnderstandsMinimizedAttributes_Block22() document = $$"""@{{{document}}}"""; // Act & Assert - EvaluateData(MinimizedAttribute_Descriptors, document); + EvaluateData(MinimizedAttribute_TagHelpers, document); } [Fact] @@ -1929,7 +1928,7 @@ public void UnderstandsMinimizedAttributes_Block23() document = $$"""@{{{document}}}"""; // Act & Assert - EvaluateData(MinimizedAttribute_Descriptors, document); + EvaluateData(MinimizedAttribute_TagHelpers, document); } [Fact] @@ -1942,7 +1941,7 @@ public void UnderstandsMinimizedAttributes_Block24() document = $$"""@{{{document}}}"""; // Act & Assert - EvaluateData(MinimizedAttribute_Descriptors, document); + EvaluateData(MinimizedAttribute_TagHelpers, document); } [Fact] @@ -1955,7 +1954,7 @@ public void UnderstandsMinimizedAttributes_Block25() document = $$"""@{{{document}}}"""; // Act & Assert - EvaluateData(MinimizedAttribute_Descriptors, document); + EvaluateData(MinimizedAttribute_TagHelpers, document); } [Fact] @@ -1968,7 +1967,7 @@ public void UnderstandsMinimizedAttributes_Block26() document = $$"""@{{{document}}}"""; // Act & Assert - EvaluateData(MinimizedAttribute_Descriptors, document); + EvaluateData(MinimizedAttribute_TagHelpers, document); } [Fact] @@ -1981,7 +1980,7 @@ public void UnderstandsMinimizedAttributes_Block27() document = $$"""@{{{document}}}"""; // Act & Assert - EvaluateData(MinimizedAttribute_Descriptors, document); + EvaluateData(MinimizedAttribute_TagHelpers, document); } [Fact] @@ -1994,7 +1993,7 @@ public void UnderstandsMinimizedAttributes_Block28() document = $$"""@{{{document}}}"""; // Act & Assert - EvaluateData(MinimizedAttribute_Descriptors, document); + EvaluateData(MinimizedAttribute_TagHelpers, document); } [Fact] @@ -2007,7 +2006,7 @@ public void UnderstandsMinimizedAttributes_Block29() document = $$"""@{{{document}}}"""; // Act & Assert - EvaluateData(MinimizedAttribute_Descriptors, document); + EvaluateData(MinimizedAttribute_TagHelpers, document); } [Fact] @@ -2021,7 +2020,7 @@ public void UnderstandsMinimizedAttributes_Block30() document = $$"""@{{{document}}}"""; // Act & Assert - EvaluateData(MinimizedAttribute_Descriptors, document); + EvaluateData(MinimizedAttribute_TagHelpers, document); } [Fact] @@ -2035,7 +2034,7 @@ public void UnderstandsMinimizedAttributes_Block31() document = $$"""@{{{document}}}"""; // Act & Assert - EvaluateData(MinimizedAttribute_Descriptors, document); + EvaluateData(MinimizedAttribute_TagHelpers, document); } [Fact] @@ -2049,7 +2048,7 @@ public void UnderstandsMinimizedAttributes_Block32() document = $$"""@{{{document}}}"""; // Act & Assert - EvaluateData(MinimizedAttribute_Descriptors, document); + EvaluateData(MinimizedAttribute_TagHelpers, document); } [Fact] @@ -2063,55 +2062,55 @@ public void UnderstandsMinimizedAttributes_Block33() document = $$"""@{{{document}}}"""; // Act & Assert - EvaluateData(MinimizedAttribute_Descriptors, document); + EvaluateData(MinimizedAttribute_TagHelpers, document); } [Fact] public void UnderstandsMinimizedAttributes_PartialTags1() { - EvaluateData(MinimizedAttribute_Descriptors, " descriptors = + TagHelperCollection tagHelpers = [ TagHelperDescriptorBuilder.CreateTagHelper("InputTagHelper", "SomeAssembly") .TagMatchingRuleDescriptor(rule => rule @@ -2137,7 +2136,7 @@ public void UnderstandsMinimizedBooleanBoundAttributes() ]; // Act & Assert - EvaluateData(descriptors, document); + EvaluateData(tagHelpers, document); } [Fact] @@ -2145,7 +2144,7 @@ public void FeatureDisabled_AddsErrorForMinimizedBooleanBoundAttributes() { // Arrange var document = ""; - ImmutableArray descriptors = + TagHelperCollection tagHelpers = [ TagHelperDescriptorBuilder.CreateTagHelper("InputTagHelper", "SomeAssembly") .TagMatchingRuleDescriptor(rule => rule @@ -2163,7 +2162,7 @@ public void FeatureDisabled_AddsErrorForMinimizedBooleanBoundAttributes() ]; // Act & Assert - EvaluateData(descriptors, document, languageVersion: RazorLanguageVersion.Version_2_0, fileKind: RazorFileKind.Legacy); + EvaluateData(tagHelpers, document, languageVersion: RazorLanguageVersion.Version_2_0, fileKind: RazorFileKind.Legacy); } [Fact] @@ -2171,7 +2170,7 @@ public void Rewrites_ComponentDirectiveAttributes() { // Arrange var document = @""; - ImmutableArray descriptors = + TagHelperCollection tagHelpers = [ TagHelperDescriptorBuilder.Create(TagHelperKind.Bind, "Bind", ComponentsApi.AssemblyName) .TypeName( @@ -2204,7 +2203,7 @@ public void Rewrites_ComponentDirectiveAttributes() ]; // Act & Assert - EvaluateData(descriptors, document, configureParserOptions: builder => + EvaluateData(tagHelpers, document, configureParserOptions: builder => { builder.AllowCSharpInMarkupAttributeArea = false; }); @@ -2215,7 +2214,7 @@ public void Rewrites_MinimizedComponentDirectiveAttributes() { // Arrange var document = @""; - ImmutableArray descriptors = + TagHelperCollection tagHelpers = [ TagHelperDescriptorBuilder.Create(TagHelperKind.Bind, "Bind", ComponentsApi.AssemblyName) .TypeName( @@ -2248,7 +2247,7 @@ public void Rewrites_MinimizedComponentDirectiveAttributes() ]; // Act & Assert - EvaluateData(descriptors, document, configureParserOptions: builder => + EvaluateData(tagHelpers, document, configureParserOptions: builder => { builder.AllowCSharpInMarkupAttributeArea = false; }); diff --git a/src/Compiler/Microsoft.AspNetCore.Razor.Language/legacyTest/Legacy/TagHelperParseTreeRewriterTest.cs b/src/Compiler/Microsoft.AspNetCore.Razor.Language/legacyTest/Legacy/TagHelperParseTreeRewriterTest.cs index b93f0cadbd5..bb03a301559 100644 --- a/src/Compiler/Microsoft.AspNetCore.Razor.Language/legacyTest/Legacy/TagHelperParseTreeRewriterTest.cs +++ b/src/Compiler/Microsoft.AspNetCore.Razor.Language/legacyTest/Legacy/TagHelperParseTreeRewriterTest.cs @@ -3,7 +3,6 @@ using System; using System.Collections.Generic; -using System.Collections.Immutable; using System.Linq; using Microsoft.AspNetCore.Razor.Language.Syntax; using Xunit; @@ -66,7 +65,7 @@ public void GetAttributeNameValuePairs_ParsesPairsCorrectly( Assert.Equal(expectedPairs, pairs); } - public static ImmutableArray PartialRequiredParentTags_Descriptors = + public static readonly TagHelperCollection PartialRequiredParentTags_TagHelpers = [ TagHelperDescriptorBuilder.CreateTagHelper("StrongTagHelper", "SomeAssembly") .TagMatchingRuleDescriptor(rule => rule.RequireTagName("strong")) @@ -84,45 +83,45 @@ public void GetAttributeNameValuePairs_ParsesPairsCorrectly( public void UnderstandsPartialRequiredParentTags1() { var document = "

"; - EvaluateData(PartialRequiredParentTags_Descriptors, document); + EvaluateData(PartialRequiredParentTags_TagHelpers, document); } [Fact] public void UnderstandsPartialRequiredParentTags2() { var document = "

"; - EvaluateData(PartialRequiredParentTags_Descriptors, document); + EvaluateData(PartialRequiredParentTags_TagHelpers, document); } [Fact] public void UnderstandsPartialRequiredParentTags3() { var document = "

"; - EvaluateData(PartialRequiredParentTags_Descriptors, document); + EvaluateData(PartialRequiredParentTags_TagHelpers, document); } [Fact] public void UnderstandsPartialRequiredParentTags4() { var document = "<

<

"; - EvaluateData(PartialRequiredParentTags_Descriptors, document); + EvaluateData(PartialRequiredParentTags_TagHelpers, document); } [Fact] public void UnderstandsPartialRequiredParentTags5() { var document = "<

<

"; - EvaluateData(PartialRequiredParentTags_Descriptors, document); + EvaluateData(PartialRequiredParentTags_TagHelpers, document); } [Fact] public void UnderstandsPartialRequiredParentTags6() { var document = "<

<

"; - EvaluateData(PartialRequiredParentTags_Descriptors, document); + EvaluateData(PartialRequiredParentTags_TagHelpers, document); } - public static ImmutableArray NestedVoidSelfClosingRequiredParent_Descriptors = + public static readonly TagHelperCollection NestedVoidSelfClosingRequiredParent_TagHelpers = [ TagHelperDescriptorBuilder.CreateTagHelper("InputTagHelper", "SomeAssembly") .TagMatchingRuleDescriptor(rule => rule @@ -142,7 +141,7 @@ public void UnderstandsPartialRequiredParentTags6() .Build(), ]; - public static ImmutableArray CatchAllAttribute_Descriptors = + public static readonly TagHelperCollection CatchAllAttribute_TagHelpers = [ TagHelperDescriptorBuilder.CreateEventHandler("InputTagHelper1", "SomeAssembly") .TagMatchingRuleDescriptor(rule => rule @@ -158,66 +157,66 @@ public void UnderstandsPartialRequiredParentTags6() public void UnderstandsInvalidHtml() { var document = @" {}"">Miscolored!"; - EvaluateData(CatchAllAttribute_Descriptors, document); + EvaluateData(CatchAllAttribute_TagHelpers, document); } [Fact] public void UnderstandsNestedVoidSelfClosingRequiredParent1() { var document = ""; - EvaluateData(NestedVoidSelfClosingRequiredParent_Descriptors, document); + EvaluateData(NestedVoidSelfClosingRequiredParent_TagHelpers, document); } [Fact] public void UnderstandsNestedVoidSelfClosingRequiredParent2() { var document = "

"; - EvaluateData(NestedVoidSelfClosingRequiredParent_Descriptors, document); + EvaluateData(NestedVoidSelfClosingRequiredParent_TagHelpers, document); } [Fact] public void UnderstandsNestedVoidSelfClosingRequiredParent3() { var document = "


"; - EvaluateData(NestedVoidSelfClosingRequiredParent_Descriptors, document); + EvaluateData(NestedVoidSelfClosingRequiredParent_TagHelpers, document); } [Fact] public void UnderstandsNestedVoidSelfClosingRequiredParent4() { var document = "


"; - EvaluateData(NestedVoidSelfClosingRequiredParent_Descriptors, document); + EvaluateData(NestedVoidSelfClosingRequiredParent_TagHelpers, document); } [Fact] public void UnderstandsNestedVoidSelfClosingRequiredParent5() { var document = ""; - EvaluateData(NestedVoidSelfClosingRequiredParent_Descriptors, document); + EvaluateData(NestedVoidSelfClosingRequiredParent_TagHelpers, document); } [Fact] public void UnderstandsNestedVoidSelfClosingRequiredParent6() { var document = "

"; - EvaluateData(NestedVoidSelfClosingRequiredParent_Descriptors, document); + EvaluateData(NestedVoidSelfClosingRequiredParent_TagHelpers, document); } [Fact] public void UnderstandsNestedVoidSelfClosingRequiredParent7() { var document = "


"; - EvaluateData(NestedVoidSelfClosingRequiredParent_Descriptors, document); + EvaluateData(NestedVoidSelfClosingRequiredParent_TagHelpers, document); } [Fact] public void UnderstandsNestedVoidSelfClosingRequiredParent8() { var document = "


"; - EvaluateData(NestedVoidSelfClosingRequiredParent_Descriptors, document); + EvaluateData(NestedVoidSelfClosingRequiredParent_TagHelpers, document); } - public static ImmutableArray NestedRequiredParent_Descriptors = + public static readonly TagHelperCollection NestedRequiredParent_TagHelpers = [ TagHelperDescriptorBuilder.CreateTagHelper("StrongTagHelper", "SomeAssembly") .TagMatchingRuleDescriptor(rule => @@ -238,35 +237,35 @@ public void UnderstandsNestedVoidSelfClosingRequiredParent8() public void UnderstandsNestedRequiredParent1() { var document = ""; - EvaluateData(NestedRequiredParent_Descriptors, document); + EvaluateData(NestedRequiredParent_TagHelpers, document); } [Fact] public void UnderstandsNestedRequiredParent2() { var document = "

"; - EvaluateData(NestedRequiredParent_Descriptors, document); + EvaluateData(NestedRequiredParent_TagHelpers, document); } [Fact] public void UnderstandsNestedRequiredParent3() { var document = "
"; - EvaluateData(NestedRequiredParent_Descriptors, document); + EvaluateData(NestedRequiredParent_TagHelpers, document); } [Fact] public void UnderstandsNestedRequiredParent4() { var document = ""; - EvaluateData(NestedRequiredParent_Descriptors, document); + EvaluateData(NestedRequiredParent_TagHelpers, document); } [Fact] public void UnderstandsNestedRequiredParent5() { var document = "

"; - EvaluateData(NestedRequiredParent_Descriptors, document); + EvaluateData(NestedRequiredParent_TagHelpers, document); } [Fact] @@ -274,7 +273,7 @@ public void UnderstandsTagHelperPrefixAndAllowedChildren() { // Arrange var documentContent = ""; - ImmutableArray descriptors = + TagHelperCollection tagHelpers = [ TagHelperDescriptorBuilder.CreateTagHelper("PTagHelper", "SomeAssembly") .TagMatchingRuleDescriptor(rule => rule.RequireTagName("p")) @@ -287,7 +286,7 @@ public void UnderstandsTagHelperPrefixAndAllowedChildren() // Act & Assert EvaluateData( - descriptors, + tagHelpers, documentContent, tagHelperPrefix: "th:"); } @@ -297,7 +296,7 @@ public void UnderstandsTagHelperPrefixAndAllowedChildrenAndRequireParent() { // Arrange var documentContent = ""; - ImmutableArray descriptors = + TagHelperCollection tagHelpers = [ TagHelperDescriptorBuilder.CreateTagHelper("PTagHelper", "SomeAssembly") .TagMatchingRuleDescriptor(rule => rule.RequireTagName("p")) @@ -310,7 +309,7 @@ public void UnderstandsTagHelperPrefixAndAllowedChildrenAndRequireParent() // Act & Assert EvaluateData( - descriptors, + tagHelpers, documentContent, tagHelperPrefix: "th:"); } @@ -321,7 +320,7 @@ public void InvalidStructure_UnderstandsTHPrefixAndAllowedChildrenAndRequirePare // Rewrite_InvalidStructure_UnderstandsTagHelperPrefixAndAllowedChildrenAndRequireParent // Arrange var documentContent = ""; - ImmutableArray descriptors = + TagHelperCollection tagHelpers = [ TagHelperDescriptorBuilder.CreateTagHelper("PTagHelper", "SomeAssembly") .TagMatchingRuleDescriptor(rule => rule.RequireTagName("p")) @@ -334,7 +333,7 @@ public void InvalidStructure_UnderstandsTHPrefixAndAllowedChildrenAndRequirePare // Act & Assert EvaluateData( - descriptors, + tagHelpers, documentContent, tagHelperPrefix: "th:"); } @@ -344,7 +343,7 @@ public void NonTagHelperChild_UnderstandsTagHelperPrefixAndAllowedChildren() { // Arrange var documentContent = ""; - ImmutableArray descriptors = + TagHelperCollection tagHelpers = [ TagHelperDescriptorBuilder.CreateTagHelper("PTagHelper", "SomeAssembly") .TagMatchingRuleDescriptor(rule => rule.RequireTagName("p")) @@ -354,7 +353,7 @@ public void NonTagHelperChild_UnderstandsTagHelperPrefixAndAllowedChildren() // Act & Assert EvaluateData( - descriptors, + tagHelpers, documentContent, tagHelperPrefix: "th:"); } @@ -426,7 +425,7 @@ public void CanHandleInvalidChildrenWithWhitespace()

"""; - ImmutableArray descriptors = + TagHelperCollection tagHelpers = [ TagHelperDescriptorBuilder.CreateTagHelper("PTagHelper", "SomeAssembly") .TagMatchingRuleDescriptor(rule => rule.RequireTagName("p")) @@ -435,7 +434,7 @@ public void CanHandleInvalidChildrenWithWhitespace() ]; // Act & Assert - EvaluateData(descriptors, documentContent); + EvaluateData(tagHelpers, documentContent); } [Fact] @@ -443,7 +442,7 @@ public void RecoversWhenRequiredAttributeMismatchAndRestrictedChildren() { // Arrange var documentContent = ""; - ImmutableArray descriptors = + TagHelperCollection tagHelpers = [ TagHelperDescriptorBuilder.CreateTagHelper("StrongTagHelper", "SomeAssembly") .TagMatchingRuleDescriptor(rule => @@ -455,7 +454,7 @@ public void RecoversWhenRequiredAttributeMismatchAndRestrictedChildren() ]; // Act & Assert - EvaluateData(descriptors, documentContent); + EvaluateData(tagHelpers, documentContent); } [Fact] @@ -463,7 +462,7 @@ public void CanHandleMultipleTagHelpersWithAllowedChildren_OneNull() { // Arrange var documentContent = "

Hello World

"; - ImmutableArray descriptors = + TagHelperCollection tagHelpers = [ TagHelperDescriptorBuilder.CreateTagHelper("PTagHelper1", "SomeAssembly") .TagMatchingRuleDescriptor(rule => rule.RequireTagName("p")) @@ -485,7 +484,7 @@ public void CanHandleMultipleTagHelpersWithAllowedChildren_OneNull() ]; // Act & Assert - EvaluateData(descriptors, documentContent); + EvaluateData(tagHelpers, documentContent); } [Fact] @@ -493,7 +492,7 @@ public void CanHandleMultipleTagHelpersWithAllowedChildren() { // Arrange var documentContent = "

Hello World

"; - ImmutableArray descriptors = + TagHelperCollection tagHelpers = [ TagHelperDescriptorBuilder.CreateTagHelper("PTagHelper1", "SomeAssembly") .TagMatchingRuleDescriptor(rule => rule.RequireTagName("p")) @@ -515,7 +514,7 @@ public void CanHandleMultipleTagHelpersWithAllowedChildren() ]; // Act & Assert - EvaluateData(descriptors, documentContent); + EvaluateData(tagHelpers, documentContent); } [Fact] @@ -523,10 +522,10 @@ public void UnderstandsAllowedChildren1() { // Arrange var documentContent = "


"; - var descriptors = GetAllowedChildrenTagHelperDescriptors(["br"]); + var tagHelpers = GetAllowedChildrenTagHelpers(["br"]); // Act & Assert - EvaluateData(descriptors, documentContent); + EvaluateData(tagHelpers, documentContent); } [Fact] @@ -538,10 +537,10 @@ public void UnderstandsAllowedChildren2()

"""; - var descriptors = GetAllowedChildrenTagHelperDescriptors(["br"]); + var tagHelpers = GetAllowedChildrenTagHelpers(["br"]); // Act & Assert - EvaluateData(descriptors, documentContent); + EvaluateData(tagHelpers, documentContent); } [Fact] @@ -549,10 +548,10 @@ public void UnderstandsAllowedChildren3() { // Arrange var documentContent = "


"; - var descriptors = GetAllowedChildrenTagHelperDescriptors(["strong"]); + var tagHelpers = GetAllowedChildrenTagHelpers(["strong"]); // Act & Assert - EvaluateData(descriptors, documentContent); + EvaluateData(tagHelpers, documentContent); } [Fact] @@ -560,10 +559,10 @@ public void UnderstandsAllowedChildren4() { // Arrange var documentContent = "

Hello

"; - var descriptors = GetAllowedChildrenTagHelperDescriptors(["strong"]); + var tagHelpers = GetAllowedChildrenTagHelpers(["strong"]); // Act & Assert - EvaluateData(descriptors, documentContent); + EvaluateData(tagHelpers, documentContent); } [Fact] @@ -571,10 +570,10 @@ public void UnderstandsAllowedChildren5() { // Arrange var documentContent = "


"; - var descriptors = GetAllowedChildrenTagHelperDescriptors(["br", "strong"]); + var tagHelpers = GetAllowedChildrenTagHelpers(["br", "strong"]); // Act & Assert - EvaluateData(descriptors, documentContent); + EvaluateData(tagHelpers, documentContent); } [Fact] @@ -582,10 +581,10 @@ public void UnderstandsAllowedChildren6() { // Arrange var documentContent = "


Hello

"; - var descriptors = GetAllowedChildrenTagHelperDescriptors(["strong"]); + var tagHelpers = GetAllowedChildrenTagHelpers(["strong"]); // Act & Assert - EvaluateData(descriptors, documentContent); + EvaluateData(tagHelpers, documentContent); } [Fact] @@ -593,10 +592,10 @@ public void UnderstandsAllowedChildren7() { // Arrange var documentContent = "

Title:
Something

"; - var descriptors = GetAllowedChildrenTagHelperDescriptors(["strong"]); + var tagHelpers = GetAllowedChildrenTagHelpers(["strong"]); // Act & Assert - EvaluateData(descriptors, documentContent); + EvaluateData(tagHelpers, documentContent); } [Fact] @@ -604,10 +603,10 @@ public void UnderstandsAllowedChildren8() { // Arrange var documentContent = "

Title:
Something

"; - var descriptors = GetAllowedChildrenTagHelperDescriptors(["strong", "br"]); + var tagHelpers = GetAllowedChildrenTagHelpers(["strong", "br"]); // Act & Assert - EvaluateData(descriptors, documentContent); + EvaluateData(tagHelpers, documentContent); } [Fact] @@ -615,10 +614,10 @@ public void UnderstandsAllowedChildren9() { // Arrange var documentContent = "

Title:
Something

"; - var descriptors = GetAllowedChildrenTagHelperDescriptors(["strong", "br"]); + var tagHelpers = GetAllowedChildrenTagHelpers(["strong", "br"]); // Act & Assert - EvaluateData(descriptors, documentContent); + EvaluateData(tagHelpers, documentContent); } [Fact] @@ -626,10 +625,10 @@ public void UnderstandsAllowedChildren10() { // Arrange var documentContent = "

Title:
A Very Cool

Something

"; - var descriptors = GetAllowedChildrenTagHelperDescriptors(["strong"]); + var tagHelpers = GetAllowedChildrenTagHelpers(["strong"]); // Act & Assert - EvaluateData(descriptors, documentContent); + EvaluateData(tagHelpers, documentContent); } [Fact] @@ -637,10 +636,10 @@ public void UnderstandsAllowedChildren11() { // Arrange var documentContent = "

Title:
A Very Cool

Something

"; - var descriptors = GetAllowedChildrenTagHelperDescriptors(["custom"]); + var tagHelpers = GetAllowedChildrenTagHelpers(["custom"]); // Act & Assert - EvaluateData(descriptors, documentContent); + EvaluateData(tagHelpers, documentContent); } [Fact] @@ -648,10 +647,10 @@ public void UnderstandsAllowedChildren12() { // Arrange var documentContent = "

"; - var descriptors = GetAllowedChildrenTagHelperDescriptors(["custom"]); + var tagHelpers = GetAllowedChildrenTagHelpers(["custom"]); // Act & Assert - EvaluateData(descriptors, documentContent); + EvaluateData(tagHelpers, documentContent); } [Fact] @@ -659,10 +658,10 @@ public void UnderstandsAllowedChildren13() { // Arrange var documentContent = "

<

"; - var descriptors = GetAllowedChildrenTagHelperDescriptors(["custom"]); + var tagHelpers = GetAllowedChildrenTagHelpers(["custom"]); // Act & Assert - EvaluateData(descriptors, documentContent); + EvaluateData(tagHelpers, documentContent); } [Fact] @@ -670,13 +669,13 @@ public void UnderstandsAllowedChildren14() { // Arrange var documentContent = "


:Hello:

"; - var descriptors = GetAllowedChildrenTagHelperDescriptors(["custom", "strong"]); + var tagHelpers = GetAllowedChildrenTagHelpers(["custom", "strong"]); // Act & Assert - EvaluateData(descriptors, documentContent); + EvaluateData(tagHelpers, documentContent); } - private static ImmutableArray GetAllowedChildrenTagHelperDescriptors(string[] allowedChildren) + private static TagHelperCollection GetAllowedChildrenTagHelpers(string[] allowedChildren) { var pTagHelperBuilder = TagHelperDescriptorBuilder.CreateTagHelper("PTagHelper", "SomeAssembly") .TagMatchingRuleDescriptor(rule => rule.RequireTagName("p")); @@ -718,13 +717,13 @@ public void AllowsSimpleHtmlCommentsAsChildren() pTagHelperBuilder.AllowChildTag(childTag); } - ImmutableArray descriptors = + TagHelperCollection tagHelpers = [ pTagHelperBuilder.Build() ]; // Act & Assert - EvaluateData(descriptors, document); + EvaluateData(tagHelpers, document); } [Fact] @@ -742,14 +741,14 @@ public void DoesntAllowSimpleHtmlCommentsAsChildrenWhenFeatureFlagIsOff() pTagHelperBuilder.AllowChildTag(childTag); } - ImmutableArray descriptors = + TagHelperCollection tagHelpers = [ pTagHelperBuilder.Build() ]; // Act & Assert EvaluateData( - descriptors, + tagHelpers, document, languageVersion: RazorLanguageVersion.Version_2_0, fileKind: RazorFileKind.Legacy); @@ -772,13 +771,13 @@ public void FailsForContentWithCommentsAsChildren() pTagHelperBuilder.AllowChildTag(childTag); } - ImmutableArray descriptors = + TagHelperCollection tagHelpers = [ pTagHelperBuilder.Build() ]; // Act & Assert - EvaluateData(descriptors, document); + EvaluateData(tagHelpers, document); } [Fact] @@ -797,13 +796,13 @@ public void AllowsRazorCommentsAsChildren() pTagHelperBuilder.AllowChildTag(childTag); } - ImmutableArray descriptors = + TagHelperCollection tagHelpers = [ pTagHelperBuilder.Build() ]; // Act & Assert - EvaluateData(descriptors, document); + EvaluateData(tagHelpers, document); } [Fact] @@ -825,13 +824,13 @@ public void AllowsRazorMarkupInHtmlComment() pTagHelperBuilder.AllowChildTag(childTag); } - ImmutableArray descriptors = + TagHelperCollection tagHelpers = [ pTagHelperBuilder.Build() ]; // Act & Assert - EvaluateData(descriptors, document); + EvaluateData(tagHelpers, document); } [Fact] @@ -839,7 +838,7 @@ public void UnderstandsNullTagNameWithAllowedChildrenForCatchAll() { // Arrange var documentContent = "

"; - ImmutableArray descriptors = + TagHelperCollection tagHelpers = [ TagHelperDescriptorBuilder.CreateTagHelper("PTagHelper", "SomeAssembly") .TagMatchingRuleDescriptor(rule => rule.RequireTagName("p")) @@ -851,7 +850,7 @@ public void UnderstandsNullTagNameWithAllowedChildrenForCatchAll() ]; // Act & Assert - EvaluateData(descriptors, documentContent); + EvaluateData(tagHelpers, documentContent); } [Fact] @@ -859,7 +858,7 @@ public void UnderstandsNullTagNameWithAllowedChildrenForCatchAllWithPrefix() { // Arrange var documentContent = ""; - ImmutableArray descriptors = + TagHelperCollection tagHelpers = [ TagHelperDescriptorBuilder.CreateTagHelper("PTagHelper", "SomeAssembly") .TagMatchingRuleDescriptor(rule => rule.RequireTagName("p")) @@ -871,7 +870,7 @@ public void UnderstandsNullTagNameWithAllowedChildrenForCatchAllWithPrefix() ]; // Act & Assert - EvaluateData(descriptors, documentContent, "th:"); + EvaluateData(tagHelpers, documentContent, "th:"); } [Fact] @@ -879,7 +878,7 @@ public void CanHandleStartTagOnlyTagTagMode() { // Arrange var documentContent = ""; - ImmutableArray descriptors = + TagHelperCollection tagHelpers = [ TagHelperDescriptorBuilder.CreateTagHelper("InputTagHelper", "SomeAssembly") .TagMatchingRuleDescriptor(rule => @@ -890,7 +889,7 @@ public void CanHandleStartTagOnlyTagTagMode() ]; // Act & Assert - EvaluateData(descriptors, documentContent); + EvaluateData(tagHelpers, documentContent); } [Fact] @@ -898,7 +897,7 @@ public void CreatesErrorForWithoutEndTagTagStructureForEndTags() { // Arrange var documentContent = ""; - ImmutableArray descriptors = + TagHelperCollection tagHelpers = [ TagHelperDescriptorBuilder.CreateTagHelper("InputTagHelper", "SomeAssembly") .TagMatchingRuleDescriptor(rule => @@ -909,7 +908,7 @@ public void CreatesErrorForWithoutEndTagTagStructureForEndTags() ]; // Act & Assert - EvaluateData(descriptors, documentContent); + EvaluateData(tagHelpers, documentContent); } [Fact] @@ -917,7 +916,7 @@ public void CreatesErrorForInconsistentTagStructures() { // Arrange var documentContent = ""; - ImmutableArray descriptors = + TagHelperCollection tagHelpers = [ TagHelperDescriptorBuilder.CreateTagHelper("InputTagHelper1", "SomeAssembly") .TagMatchingRuleDescriptor(rule => @@ -934,10 +933,10 @@ public void CreatesErrorForInconsistentTagStructures() ]; // Act & Assert - EvaluateData(descriptors, documentContent); + EvaluateData(tagHelpers, documentContent); } - public static ImmutableArray RequiredAttribute_Descriptors = + public static readonly TagHelperCollection RequiredAttribute_TagHelpers = [ TagHelperDescriptorBuilder.CreateTagHelper("pTagHelper", "SomeAssembly") .TagMatchingRuleDescriptor(rule => @@ -963,184 +962,184 @@ public void CreatesErrorForInconsistentTagStructures() [Fact] public void RequiredAttributeDescriptorsCreateTagHelperBlocksCorrectly1() { - EvaluateData(RequiredAttribute_Descriptors, "

"); + EvaluateData(RequiredAttribute_TagHelpers, "

"); } [Fact] public void RequiredAttributeDescriptorsCreateTagHelperBlocksCorrectly2() { - EvaluateData(RequiredAttribute_Descriptors, "

"); + EvaluateData(RequiredAttribute_TagHelpers, "

"); } [Fact] public void RequiredAttributeDescriptorsCreateTagHelperBlocksCorrectly3() { - EvaluateData(RequiredAttribute_Descriptors, "
"); + EvaluateData(RequiredAttribute_TagHelpers, "
"); } [Fact] public void RequiredAttributeDescriptorsCreateTagHelperBlocksCorrectly4() { - EvaluateData(RequiredAttribute_Descriptors, "
"); + EvaluateData(RequiredAttribute_TagHelpers, "
"); } [Fact] public void RequiredAttributeDescriptorsCreateTagHelperBlocksCorrectly5() { - EvaluateData(RequiredAttribute_Descriptors, "

"); + EvaluateData(RequiredAttribute_TagHelpers, "

"); } [Fact] public void RequiredAttributeDescriptorsCreateTagHelperBlocksCorrectly6() { - EvaluateData(RequiredAttribute_Descriptors, "

"); + EvaluateData(RequiredAttribute_TagHelpers, "

"); } [Fact] public void RequiredAttributeDescriptorsCreateTagHelperBlocksCorrectly7() { - EvaluateData(RequiredAttribute_Descriptors, "

words and spaces

"); + EvaluateData(RequiredAttribute_TagHelpers, "

words and spaces

"); } [Fact] public void RequiredAttributeDescriptorsCreateTagHelperBlocksCorrectly8() { - EvaluateData(RequiredAttribute_Descriptors, "

words and spaces

"); + EvaluateData(RequiredAttribute_TagHelpers, "

words and spaces

"); } [Fact] public void RequiredAttributeDescriptorsCreateTagHelperBlocksCorrectly9() { - EvaluateData(RequiredAttribute_Descriptors, "

wordsandspaces

"); + EvaluateData(RequiredAttribute_TagHelpers, "

wordsandspaces

"); } [Fact] public void RequiredAttributeDescriptorsCreateTagHelperBlocksCorrectly10() { - EvaluateData(RequiredAttribute_Descriptors, ""); + EvaluateData(RequiredAttribute_TagHelpers, ""); } [Fact] public void RequiredAttributeDescriptorsCreateTagHelperBlocksCorrectly11() { - EvaluateData(RequiredAttribute_Descriptors, ""); + EvaluateData(RequiredAttribute_TagHelpers, ""); } [Fact] public void RequiredAttributeDescriptorsCreateTagHelperBlocksCorrectly12() { - EvaluateData(RequiredAttribute_Descriptors, "words and spaces"); + EvaluateData(RequiredAttribute_TagHelpers, "words and spaces"); } [Fact] public void RequiredAttributeDescriptorsCreateTagHelperBlocksCorrectly13() { - EvaluateData(RequiredAttribute_Descriptors, "words and spaces"); + EvaluateData(RequiredAttribute_TagHelpers, "words and spaces"); } [Fact] public void RequiredAttributeDescriptorsCreateTagHelperBlocksCorrectly14() { - EvaluateData(RequiredAttribute_Descriptors, "
"); + EvaluateData(RequiredAttribute_TagHelpers, "
"); } [Fact] public void RequiredAttributeDescriptorsCreateTagHelperBlocksCorrectly15() { - EvaluateData(RequiredAttribute_Descriptors, "
"); + EvaluateData(RequiredAttribute_TagHelpers, "
"); } [Fact] public void RequiredAttributeDescriptorsCreateTagHelperBlocksCorrectly16() { - EvaluateData(RequiredAttribute_Descriptors, "

"); + EvaluateData(RequiredAttribute_TagHelpers, "

"); } [Fact] public void RequiredAttributeDescriptorsCreateTagHelperBlocksCorrectly17() { - EvaluateData(RequiredAttribute_Descriptors, "

"); + EvaluateData(RequiredAttribute_TagHelpers, "

"); } [Fact] public void RequiredAttributeDescriptorsCreateTagHelperBlocksCorrectly18() { - EvaluateData(RequiredAttribute_Descriptors, "

words and spaces

"); + EvaluateData(RequiredAttribute_TagHelpers, "

words and spaces

"); } [Fact] public void RequiredAttributeDescriptorsCreateTagHelperBlocksCorrectly19() { - EvaluateData(RequiredAttribute_Descriptors, "
"); + EvaluateData(RequiredAttribute_TagHelpers, "
"); } [Fact] public void RequiredAttributeDescriptorsCreateTagHelperBlocksCorrectly20() { - EvaluateData(RequiredAttribute_Descriptors, "
"); + EvaluateData(RequiredAttribute_TagHelpers, "
"); } [Fact] public void RequiredAttributeDescriptorsCreateTagHelperBlocksCorrectly21() { - EvaluateData(RequiredAttribute_Descriptors, "
words and spaces
"); + EvaluateData(RequiredAttribute_TagHelpers, "
words and spaces
"); } [Fact] public void RequiredAttributeDescriptorsCreateTagHelperBlocksCorrectly22() { - EvaluateData(RequiredAttribute_Descriptors, "
words and spaces
"); + EvaluateData(RequiredAttribute_TagHelpers, "
words and spaces
"); } [Fact] public void RequiredAttributeDescriptorsCreateTagHelperBlocksCorrectly23() { - EvaluateData(RequiredAttribute_Descriptors, "
wordsandspaces
"); + EvaluateData(RequiredAttribute_TagHelpers, "
wordsandspaces
"); } [Fact] public void RequiredAttributeDescriptorsCreateTagHelperBlocksCorrectly24() { - EvaluateData(RequiredAttribute_Descriptors, "

"); + EvaluateData(RequiredAttribute_TagHelpers, "

"); } [Fact] public void RequiredAttributeDescriptorsCreateTagHelperBlocksCorrectly25() { - EvaluateData(RequiredAttribute_Descriptors, "

words and spaces

"); + EvaluateData(RequiredAttribute_TagHelpers, "

words and spaces

"); } [Fact] public void RequiredAttributeDescriptorsCreateTagHelperBlocksCorrectly26() { - EvaluateData(RequiredAttribute_Descriptors, "
"); + EvaluateData(RequiredAttribute_TagHelpers, "
"); } [Fact] public void RequiredAttributeDescriptorsCreateTagHelperBlocksCorrectly27() { - EvaluateData(RequiredAttribute_Descriptors, "
words and spaces
"); + EvaluateData(RequiredAttribute_TagHelpers, "
words and spaces
"); } [Fact] public void RequiredAttributeDescriptorsCreateTagHelperBlocksCorrectly28() { - EvaluateData(RequiredAttribute_Descriptors, "
words and spaces
"); + EvaluateData(RequiredAttribute_TagHelpers, "
words and spaces
"); } [Fact] public void RequiredAttributeDescriptorsCreateTagHelperBlocksCorrectly29() { - EvaluateData(RequiredAttribute_Descriptors, "
words and spaces
"); + EvaluateData(RequiredAttribute_TagHelpers, "
words and spaces
"); } [Fact] public void RequiredAttributeDescriptorsCreateTagHelperBlocksCorrectly30() { - EvaluateData(RequiredAttribute_Descriptors, "
wordsandspaces
"); + EvaluateData(RequiredAttribute_TagHelpers, "
wordsandspaces
"); } - public static ImmutableArray NestedRequiredAttribute_Descriptors = + public static readonly TagHelperCollection NestedRequiredAttribute_TagHelpers = [ TagHelperDescriptorBuilder.CreateTagHelper("pTagHelper", "SomeAssembly") .TagMatchingRuleDescriptor(rule => @@ -1159,64 +1158,64 @@ public void RequiredAttributeDescriptorsCreateTagHelperBlocksCorrectly30() [Fact] public void NestedRequiredAttributeDescriptorsCreateTagHelperBlocksCorrectly1() { - EvaluateData(NestedRequiredAttribute_Descriptors, "

"); + EvaluateData(NestedRequiredAttribute_TagHelpers, "

"); } [Fact] public void NestedRequiredAttributeDescriptorsCreateTagHelperBlocksCorrectly2() { - EvaluateData(NestedRequiredAttribute_Descriptors, ""); + EvaluateData(NestedRequiredAttribute_TagHelpers, ""); } [Fact] public void NestedRequiredAttributeDescriptorsCreateTagHelperBlocksCorrectly3() { - EvaluateData(NestedRequiredAttribute_Descriptors, "

"); + EvaluateData(NestedRequiredAttribute_TagHelpers, "

"); } [Fact] public void NestedRequiredAttributeDescriptorsCreateTagHelperBlocksCorrectly4() { - EvaluateData(NestedRequiredAttribute_Descriptors, "

"); + EvaluateData(NestedRequiredAttribute_TagHelpers, "

"); } [Fact] public void NestedRequiredAttributeDescriptorsCreateTagHelperBlocksCorrectly5() { - EvaluateData(NestedRequiredAttribute_Descriptors, "

"); + EvaluateData(NestedRequiredAttribute_TagHelpers, "

"); } [Fact] public void NestedRequiredAttributeDescriptorsCreateTagHelperBlocksCorrectly6() { - EvaluateData(NestedRequiredAttribute_Descriptors, "

"); + EvaluateData(NestedRequiredAttribute_TagHelpers, "

"); } [Fact] public void NestedRequiredAttributeDescriptorsCreateTagHelperBlocksCorrectly7() { - EvaluateData(NestedRequiredAttribute_Descriptors, "

"); + EvaluateData(NestedRequiredAttribute_TagHelpers, "

"); } [Fact] public void NestedRequiredAttributeDescriptorsCreateTagHelperBlocksCorrectly8() { - EvaluateData(NestedRequiredAttribute_Descriptors, ""); + EvaluateData(NestedRequiredAttribute_TagHelpers, ""); } [Fact] public void NestedRequiredAttributeDescriptorsCreateTagHelperBlocksCorrectly9() { - EvaluateData(NestedRequiredAttribute_Descriptors, "

"); + EvaluateData(NestedRequiredAttribute_TagHelpers, "

"); } [Fact] public void NestedRequiredAttributeDescriptorsCreateTagHelperBlocksCorrectly10() { - EvaluateData(NestedRequiredAttribute_Descriptors, ""); + EvaluateData(NestedRequiredAttribute_TagHelpers, ""); } - public static ImmutableArray MalformedRequiredAttribute_Descriptors = + public static readonly TagHelperCollection MalformedRequiredAttribute_TagHelpers = [ TagHelperDescriptorBuilder.CreateTagHelper("pTagHelper", "SomeAssembly") .TagMatchingRuleDescriptor(rule => @@ -1229,71 +1228,71 @@ public void NestedRequiredAttributeDescriptorsCreateTagHelperBlocksCorrectly10() [Fact] public void RequiredAttributeDescriptorsCreateMalformedTagHelperBlocksCorrectly1() { - EvaluateData(MalformedRequiredAttribute_Descriptors, ""); + EvaluateData(MalformedRequiredAttribute_TagHelpers, "

"); } [Fact] public void RequiredAttributeDescriptorsCreateMalformedTagHelperBlocksCorrectly8() { - EvaluateData(MalformedRequiredAttribute_Descriptors, "

"); + EvaluateData(MalformedRequiredAttribute_TagHelpers, "

"); } [Fact] public void RequiredAttributeDescriptorsCreateMalformedTagHelperBlocksCorrectly9() { - EvaluateData(MalformedRequiredAttribute_Descriptors, "

PrefixedTagHelperColon_Descriptors = + public static readonly TagHelperCollection PrefixedTagHelperColon_TagHelpers = [ TagHelperDescriptorBuilder.CreateTagHelper("mythTagHelper", "SomeAssembly") .TagMatchingRuleDescriptor(rule => rule.RequireTagName("myth")) @@ -1308,7 +1307,7 @@ public void RequiredAttributeDescriptorsCreateMalformedTagHelperBlocksCorrectly1 .Build() ]; - public static ImmutableArray PrefixedTagHelperCatchAll_Descriptors = + public static readonly TagHelperCollection PrefixedTagHelperCatchAll_TagHelpers = [ TagHelperDescriptorBuilder.CreateTagHelper("mythTagHelper", "SomeAssembly") .TagMatchingRuleDescriptor(rule => rule.RequireTagName("*")) @@ -1318,67 +1317,67 @@ public void RequiredAttributeDescriptorsCreateMalformedTagHelperBlocksCorrectly1 [Fact] public void AllowsPrefixedTagHelpers1() { - EvaluateData(PrefixedTagHelperCatchAll_Descriptors, "", tagHelperPrefix: "th:"); + EvaluateData(PrefixedTagHelperCatchAll_TagHelpers, "", tagHelperPrefix: "th:"); } [Fact] public void AllowsPrefixedTagHelpers2() { - EvaluateData(PrefixedTagHelperCatchAll_Descriptors, "words and spaces", tagHelperPrefix: "th:"); + EvaluateData(PrefixedTagHelperCatchAll_TagHelpers, "words and spaces", tagHelperPrefix: "th:"); } [Fact] public void AllowsPrefixedTagHelpers3() { - EvaluateData(PrefixedTagHelperColon_Descriptors, "", tagHelperPrefix: "th:"); + EvaluateData(PrefixedTagHelperColon_TagHelpers, "", tagHelperPrefix: "th:"); } [Fact] public void AllowsPrefixedTagHelpers4() { - EvaluateData(PrefixedTagHelperColon_Descriptors, "", tagHelperPrefix: "th:"); + EvaluateData(PrefixedTagHelperColon_TagHelpers, "", tagHelperPrefix: "th:"); } [Fact] public void AllowsPrefixedTagHelpers5() { - EvaluateData(PrefixedTagHelperColon_Descriptors, "", tagHelperPrefix: "th:"); + EvaluateData(PrefixedTagHelperColon_TagHelpers, "", tagHelperPrefix: "th:"); } [Fact] public void AllowsPrefixedTagHelpers6() { - EvaluateData(PrefixedTagHelperColon_Descriptors, "", tagHelperPrefix: "th:"); + EvaluateData(PrefixedTagHelperColon_TagHelpers, "", tagHelperPrefix: "th:"); } [Fact] public void AllowsPrefixedTagHelpers7() { - EvaluateData(PrefixedTagHelperColon_Descriptors, "", tagHelperPrefix: "th:"); + EvaluateData(PrefixedTagHelperColon_TagHelpers, "", tagHelperPrefix: "th:"); } [Fact] public void AllowsPrefixedTagHelpers8() { - EvaluateData(PrefixedTagHelperColon_Descriptors, "", tagHelperPrefix: "th:"); + EvaluateData(PrefixedTagHelperColon_TagHelpers, "", tagHelperPrefix: "th:"); } [Fact] public void AllowsPrefixedTagHelpers9() { - EvaluateData(PrefixedTagHelperColon_Descriptors, "", tagHelperPrefix: "th:"); + EvaluateData(PrefixedTagHelperColon_TagHelpers, "", tagHelperPrefix: "th:"); } [Fact] public void AllowsPrefixedTagHelpers10() { - EvaluateData(PrefixedTagHelperColon_Descriptors, "words and spaces", tagHelperPrefix: "th:"); + EvaluateData(PrefixedTagHelperColon_TagHelpers, "words and spaces", tagHelperPrefix: "th:"); } [Fact] public void AllowsPrefixedTagHelpers11() { - EvaluateData(PrefixedTagHelperColon_Descriptors, "", tagHelperPrefix: "th:"); + EvaluateData(PrefixedTagHelperColon_TagHelpers, "", tagHelperPrefix: "th:"); } [Fact] @@ -1903,7 +1902,7 @@ public void HandlesNonTagHelperStartAndEndVoidTags_Correctly() RunParseTreeRewriterTest("Foo"); } - public static ImmutableArray CaseSensitive_Descriptors = + public static readonly TagHelperCollection CaseSensitive_TagHelpers = [ TagHelperDescriptorBuilder.CreateTagHelper("pTagHelper", "SomeAssembly") .SetCaseSensitive() @@ -1928,30 +1927,30 @@ public void HandlesNonTagHelperStartAndEndVoidTags_Correctly() [Fact] public void HandlesCaseSensitiveTagHelpersCorrectly1() { - EvaluateData(CaseSensitive_Descriptors, "

"); + EvaluateData(CaseSensitive_TagHelpers, "

"); } [Fact] public void HandlesCaseSensitiveTagHelpersCorrectly2() { - EvaluateData(CaseSensitive_Descriptors, "

"); + EvaluateData(CaseSensitive_TagHelpers, "

"); } [Fact] public void HandlesCaseSensitiveTagHelpersCorrectly3() { - EvaluateData(CaseSensitive_Descriptors, "

"); + EvaluateData(CaseSensitive_TagHelpers, "

"); } [Fact] public void HandlesCaseSensitiveTagHelpersCorrectly4() { - EvaluateData(CaseSensitive_Descriptors, "

"); + EvaluateData(CaseSensitive_TagHelpers, "

"); } [Fact] public void HandlesCaseSensitiveTagHelpersCorrectly5() { - EvaluateData(CaseSensitive_Descriptors, "

"); + EvaluateData(CaseSensitive_TagHelpers, "

"); } } diff --git a/src/Compiler/Microsoft.AspNetCore.Razor.Language/legacyTest/Legacy/TagHelperRewritingTestBase.cs b/src/Compiler/Microsoft.AspNetCore.Razor.Language/legacyTest/Legacy/TagHelperRewritingTestBase.cs index 84b85331014..06dc27ec4d4 100644 --- a/src/Compiler/Microsoft.AspNetCore.Razor.Language/legacyTest/Legacy/TagHelperRewritingTestBase.cs +++ b/src/Compiler/Microsoft.AspNetCore.Razor.Language/legacyTest/Legacy/TagHelperRewritingTestBase.cs @@ -1,10 +1,7 @@ // 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 System; -using System.Collections.Generic; using System.Collections.Immutable; using Xunit; @@ -12,39 +9,38 @@ namespace Microsoft.AspNetCore.Razor.Language.Legacy; public class TagHelperRewritingTestBase() : ParserTestBase(layer: TestProject.Layer.Compiler, validateSpanEditHandlers: true, useLegacyTokenizer: true) { - internal void RunParseTreeRewriterTest(string documentContent, params string[] tagNames) + internal void RunParseTreeRewriterTest(string documentContent, params ImmutableArray tagNames) { - var descriptors = BuildDescriptors(tagNames); + var tagHelpers = BuildTagHelpers(tagNames); - EvaluateData(descriptors, documentContent); + EvaluateData(tagHelpers, documentContent); } - internal ImmutableArray BuildDescriptors(params string[] tagNames) + internal static TagHelperCollection BuildTagHelpers(params ImmutableArray tagNames) { - var descriptors = new List(); - - foreach (var tagName in tagNames) + return TagHelperCollection.Build(tagNames, (ref builder, tagNames) => { - var descriptor = TagHelperDescriptorBuilder.CreateTagHelper(tagName + "taghelper", "SomeAssembly") - .TagMatchingRuleDescriptor(rule => rule.RequireTagName(tagName)) - .Build(); - descriptors.Add(descriptor); - } - - return descriptors.ToImmutableArray(); + foreach (var tagName in tagNames) + { + var tagHelper = TagHelperDescriptorBuilder.CreateTagHelper(tagName + "taghelper", "SomeAssembly") + .TagMatchingRuleDescriptor(rule => rule.RequireTagName(tagName)) + .Build(); + builder.Add(tagHelper); + } + }); } internal void EvaluateData( - ImmutableArray descriptors, + TagHelperCollection tagHelpers, string documentContent, - string tagHelperPrefix = null, - RazorLanguageVersion languageVersion = null, + string? tagHelperPrefix = null, + RazorLanguageVersion? languageVersion = null, RazorFileKind? fileKind = null, - Action configureParserOptions = null) + Action? configureParserOptions = null) { var syntaxTree = ParseDocument(languageVersion, documentContent, directives: default, fileKind: fileKind, configureParserOptions: configureParserOptions); - var binder = new TagHelperBinder(tagHelperPrefix, descriptors); + var binder = new TagHelperBinder(tagHelperPrefix, tagHelpers); var rewrittenTree = TagHelperParseTreeRewriter.Rewrite(syntaxTree, binder); Assert.Equal(syntaxTree.Root.Width, rewrittenTree.Root.Width); diff --git a/src/Compiler/Microsoft.AspNetCore.Razor.Language/test/DefaultRazorProjectEngineIntegrationTest.cs b/src/Compiler/Microsoft.AspNetCore.Razor.Language/test/DefaultRazorProjectEngineIntegrationTest.cs index d9952f763f7..bd32906760a 100644 --- a/src/Compiler/Microsoft.AspNetCore.Razor.Language/test/DefaultRazorProjectEngineIntegrationTest.cs +++ b/src/Compiler/Microsoft.AspNetCore.Razor.Language/test/DefaultRazorProjectEngineIntegrationTest.cs @@ -124,11 +124,11 @@ public void Process_WithImportsAndTagHelpers_SetsOnCodeDocument() var projectItem = new TestRazorProjectItem("Index.cshtml"); var importItem = new TestRazorProjectItem("_import.cshtml"); var expectedImports = ImmutableArray.Create(RazorSourceDocument.ReadFrom(importItem)); - var expectedTagHelpers = new[] - { + TagHelperCollection expectedTagHelpers = + [ TagHelperDescriptorBuilder.CreateTagHelper("TestTagHelper", "TestAssembly").Build(), TagHelperDescriptorBuilder.CreateTagHelper("Test2TagHelper", "TestAssembly").Build(), - }; + ]; var projectEngine = RazorProjectEngine.Create(RazorConfiguration.Default, TestRazorProjectFileSystem.Empty); @@ -243,11 +243,11 @@ public void ProcessDesignTime_WithImportsAndTagHelpers_SetsOnCodeDocument() var projectItem = new TestRazorProjectItem("Index.cshtml"); var importItem = new TestRazorProjectItem("_import.cshtml"); var expectedImports = ImmutableArray.Create(RazorSourceDocument.ReadFrom(importItem)); - var expectedTagHelpers = new[] - { + TagHelperCollection expectedTagHelpers = + [ TagHelperDescriptorBuilder.CreateTagHelper("TestTagHelper", "TestAssembly").Build(), TagHelperDescriptorBuilder.CreateTagHelper("Test2TagHelper", "TestAssembly").Build(), - }; + ]; var projectEngine = RazorProjectEngine.Create(RazorConfiguration.Default, TestRazorProjectFileSystem.Empty); diff --git a/src/Compiler/Microsoft.AspNetCore.Razor.Language/test/DefaultRazorTagHelperBinderPhaseTest.cs b/src/Compiler/Microsoft.AspNetCore.Razor.Language/test/DefaultRazorTagHelperBinderPhaseTest.cs index b6cd1878a71..fc2a4bdea95 100644 --- a/src/Compiler/Microsoft.AspNetCore.Razor.Language/test/DefaultRazorTagHelperBinderPhaseTest.cs +++ b/src/Compiler/Microsoft.AspNetCore.Razor.Language/test/DefaultRazorTagHelperBinderPhaseTest.cs @@ -124,7 +124,7 @@ public void Execute_RewritesTagHelpers() var projectEngine = RazorProjectEngine.Create(builder => { - builder.AddTagHelpers(tagHelper1, tagHelper2); + builder.SetTagHelpers(tagHelper1, tagHelper2); }); var source = CreateTestSourceDocument(); @@ -194,7 +194,7 @@ public void Execute_NullTagHelperDescriptorsFromCodeDocument_FallsBackToTagHelpe var projectEngine = RazorProjectEngine.Create(builder => { - builder.AddTagHelpers(tagHelper1, tagHelper2); + builder.SetTagHelpers(tagHelper1, tagHelper2); }); var source = CreateTestSourceDocument(); @@ -232,7 +232,7 @@ public void Execute_EmptyTagHelperDescriptorsFromCodeDocument_DoesNotFallbackToT var projectEngine = RazorProjectEngine.Create(builder => { - builder.AddTagHelpers(tagHelper1, tagHelper2); + builder.SetTagHelpers(tagHelper1, tagHelper2); }); var source = CreateTestSourceDocument(); @@ -347,7 +347,7 @@ public void Execute_TagHelpersFromCodeDocumentAndFeature_PrefersCodeDocument() var projectEngine = RazorProjectEngine.Create(builder => { - builder.AddTagHelpers(featureTagHelper); + builder.SetTagHelpers(featureTagHelper); }); var source = CreateTestSourceDocument(); @@ -454,7 +454,7 @@ public void Execute_CombinesErrorsOnRewritingErrors() var projectEngine = RazorProjectEngine.Create(builder => { - builder.AddTagHelpers(tagHelper1, tagHelper2); + builder.SetTagHelpers(tagHelper1, tagHelper2); }); var content = @@ -594,7 +594,7 @@ public void DirectiveVisitor_ExtractsPrefixFromSyntaxTree( var parser = new RazorParser(); var syntaxTree = parser.Parse(sourceDocument); var visitor = new DefaultRazorTagHelperContextDiscoveryPhase.TagHelperDirectiveVisitor(); - visitor.Initialize(descriptors: [], sourceDocument.FilePath); + visitor.Initialize(tagHelpers: [], sourceDocument.FilePath); // Act visitor.Visit(syntaxTree.Root); @@ -603,157 +603,142 @@ public void DirectiveVisitor_ExtractsPrefixFromSyntaxTree( Assert.Equal(expectedPrefix, visitor.TagHelperPrefix); } - public static TheoryData ProcessTagHelperMatchesData - { - get + public static TheoryData ProcessTagHelperMatchesData + // source, taghelpers, expected descriptors + => new() { - // source, taghelpers, expected descriptors - return new TheoryData { - { - $@" + $@" @addTagHelper *, {AssemblyA}", - new [] { Valid_PlainTagHelperDescriptor, }, - new [] { Valid_PlainTagHelperDescriptor } - }, - { - $@" + [Valid_PlainTagHelperDescriptor], + [Valid_PlainTagHelperDescriptor] + }, + { + $@" @addTagHelper *, {AssemblyA} @addTagHelper *, {AssemblyB}", - new [] { Valid_PlainTagHelperDescriptor, String_TagHelperDescriptor }, - new [] { Valid_PlainTagHelperDescriptor, String_TagHelperDescriptor } - }, - { - $@" + [Valid_PlainTagHelperDescriptor, String_TagHelperDescriptor], + [Valid_PlainTagHelperDescriptor, String_TagHelperDescriptor] + }, + { + $@" @addTagHelper *, {AssemblyA} @removeTagHelper *, {AssemblyB}", - new [] { Valid_PlainTagHelperDescriptor, String_TagHelperDescriptor }, - new [] { Valid_PlainTagHelperDescriptor } - }, - { - $@" + [Valid_PlainTagHelperDescriptor, String_TagHelperDescriptor], + [Valid_PlainTagHelperDescriptor] + }, + { + $@" @addTagHelper *, {AssemblyA} @addTagHelper *, {AssemblyB} @removeTagHelper *, {AssemblyA}", - new [] { Valid_PlainTagHelperDescriptor, Valid_InheritedTagHelperDescriptor, String_TagHelperDescriptor }, - new [] { String_TagHelperDescriptor } - }, - { - $@" + [Valid_PlainTagHelperDescriptor, Valid_InheritedTagHelperDescriptor, String_TagHelperDescriptor], + [String_TagHelperDescriptor] + }, + { + $@" @addTagHelper {Valid_PlainTagHelperDescriptor.Name}, {AssemblyA} @addTagHelper *, {AssemblyA}", - new [] { Valid_PlainTagHelperDescriptor, Valid_InheritedTagHelperDescriptor, }, - new [] { Valid_PlainTagHelperDescriptor, Valid_InheritedTagHelperDescriptor } - }, - { - $@" + [Valid_PlainTagHelperDescriptor, Valid_InheritedTagHelperDescriptor], + [Valid_PlainTagHelperDescriptor, Valid_InheritedTagHelperDescriptor] + }, + { + $@" @addTagHelper *, {AssemblyA} @removeTagHelper {Valid_PlainTagHelperDescriptor.Name}, {AssemblyA}", - new [] { Valid_PlainTagHelperDescriptor, Valid_InheritedTagHelperDescriptor, }, - new [] { Valid_InheritedTagHelperDescriptor } - }, - { - $@" + [Valid_PlainTagHelperDescriptor, Valid_InheritedTagHelperDescriptor], + [Valid_InheritedTagHelperDescriptor] + }, + { + $@" @addTagHelper *, {AssemblyA} @removeTagHelper *, {AssemblyA} @addTagHelper *, {AssemblyA}", - new [] { Valid_PlainTagHelperDescriptor, Valid_InheritedTagHelperDescriptor, }, - new [] { Valid_InheritedTagHelperDescriptor, Valid_PlainTagHelperDescriptor } - }, - { - $@" + [Valid_PlainTagHelperDescriptor, Valid_InheritedTagHelperDescriptor], + [Valid_InheritedTagHelperDescriptor, Valid_PlainTagHelperDescriptor] + }, + { + $@" @addTagHelper *, {AssemblyA} @addTagHelper *, {AssemblyA}", - new [] { Valid_PlainTagHelperDescriptor, Valid_InheritedTagHelperDescriptor, }, - new [] { Valid_InheritedTagHelperDescriptor, Valid_PlainTagHelperDescriptor } - }, - { - $@" + [Valid_PlainTagHelperDescriptor, Valid_InheritedTagHelperDescriptor], + [Valid_InheritedTagHelperDescriptor, Valid_PlainTagHelperDescriptor] + }, + { + $@" @addTagHelper Microsoft.AspNetCore.Razor.TagHelpers.ValidPlain*, {AssemblyA}", - new [] { Valid_PlainTagHelperDescriptor, Valid_InheritedTagHelperDescriptor, }, - new [] { Valid_PlainTagHelperDescriptor } - }, - { - $@" + [Valid_PlainTagHelperDescriptor, Valid_InheritedTagHelperDescriptor], + [Valid_PlainTagHelperDescriptor] + }, + { + $@" @addTagHelper Microsoft.AspNetCore.Razor.TagHelpers.*, {AssemblyA}", - new [] { Valid_PlainTagHelperDescriptor, Valid_InheritedTagHelperDescriptor, }, - new [] { Valid_PlainTagHelperDescriptor, Valid_PlainTagHelperDescriptor } - }, - { - $@" + [Valid_PlainTagHelperDescriptor, Valid_InheritedTagHelperDescriptor], + [Valid_PlainTagHelperDescriptor, Valid_InheritedTagHelperDescriptor] + }, + { + $@" @addTagHelper *, {AssemblyA} @removeTagHelper Microsoft.AspNetCore.Razor.TagHelpers.ValidP*, {AssemblyA} @addTagHelper *, {AssemblyA}", - new [] { Valid_PlainTagHelperDescriptor, Valid_InheritedTagHelperDescriptor, }, - new [] { Valid_InheritedTagHelperDescriptor, Valid_PlainTagHelperDescriptor } - }, - { - $@" + [Valid_PlainTagHelperDescriptor, Valid_InheritedTagHelperDescriptor], + [Valid_InheritedTagHelperDescriptor, Valid_PlainTagHelperDescriptor] + }, + { + $@" @addTagHelper *, {AssemblyA} @removeTagHelper Str*, {AssemblyB}", - new [] { Valid_PlainTagHelperDescriptor, String_TagHelperDescriptor, }, - new [] { Valid_PlainTagHelperDescriptor } - }, - { - $@" + [Valid_PlainTagHelperDescriptor, String_TagHelperDescriptor], + [Valid_PlainTagHelperDescriptor] + }, + { + $@" @addTagHelper *, {AssemblyA} @removeTagHelper *, {AssemblyB}", - new [] { Valid_PlainTagHelperDescriptor, String_TagHelperDescriptor, }, - new [] { Valid_PlainTagHelperDescriptor } - }, - { - $@" + [Valid_PlainTagHelperDescriptor, String_TagHelperDescriptor], + [Valid_PlainTagHelperDescriptor] + }, + { + $@" @addTagHelper *, {AssemblyA} @addTagHelper System.{String_TagHelperDescriptor.Name}, {AssemblyB}", - new [] { Valid_PlainTagHelperDescriptor, String_TagHelperDescriptor, }, - new [] { Valid_PlainTagHelperDescriptor } - }, - { - $@" + [Valid_PlainTagHelperDescriptor, String_TagHelperDescriptor], + [Valid_PlainTagHelperDescriptor] + }, + { + $@" @addTagHelper *, {AssemblyA} @addTagHelper *, {AssemblyB} @removeTagHelper Microsoft.*, {AssemblyA}", - new [] { Valid_PlainTagHelperDescriptor, Valid_InheritedTagHelperDescriptor, String_TagHelperDescriptor }, - new [] { String_TagHelperDescriptor } - }, - { - $@" + [Valid_PlainTagHelperDescriptor, Valid_InheritedTagHelperDescriptor, String_TagHelperDescriptor], + [String_TagHelperDescriptor] + }, + { + $@" @addTagHelper *, {AssemblyA} @addTagHelper *, {AssemblyB} @removeTagHelper ?Microsoft*, {AssemblyA} @removeTagHelper System.{String_TagHelperDescriptor.Name}, {AssemblyB}", - new [] { Valid_PlainTagHelperDescriptor, Valid_InheritedTagHelperDescriptor, String_TagHelperDescriptor }, - new [] - { - Valid_InheritedTagHelperDescriptor, - Valid_PlainTagHelperDescriptor, - String_TagHelperDescriptor - } - }, - { - $@" + [Valid_PlainTagHelperDescriptor, Valid_InheritedTagHelperDescriptor, String_TagHelperDescriptor], + [Valid_InheritedTagHelperDescriptor, Valid_PlainTagHelperDescriptor, String_TagHelperDescriptor] + }, + { + $@" @addTagHelper *, {AssemblyA} @addTagHelper *, {AssemblyB} @removeTagHelper TagHelper*, {AssemblyA} @removeTagHelper System.{String_TagHelperDescriptor.Name}, {AssemblyB}", - new [] { Valid_PlainTagHelperDescriptor, Valid_InheritedTagHelperDescriptor, String_TagHelperDescriptor }, - new [] - { - Valid_InheritedTagHelperDescriptor, - Valid_PlainTagHelperDescriptor, - String_TagHelperDescriptor - } - }, - }; - } - } + [Valid_PlainTagHelperDescriptor, Valid_InheritedTagHelperDescriptor, String_TagHelperDescriptor], + [Valid_InheritedTagHelperDescriptor, Valid_PlainTagHelperDescriptor, String_TagHelperDescriptor] + } + }; [Theory] [MemberData(nameof(ProcessTagHelperMatchesData))] public void DirectiveVisitor_FiltersTagHelpersByDirectives( string source, - TagHelperDescriptor[] tagHelpers, - TagHelperDescriptor[] expectedTagHelpers) + TagHelperCollection tagHelpers, + TagHelperCollection expectedTagHelpers) { // Arrange var sourceDocument = TestRazorSourceDocument.Create(source, filePath: "TestFile"); @@ -767,7 +752,7 @@ public void DirectiveVisitor_FiltersTagHelpersByDirectives( var results = visitor.GetResults(); // Assert - Assert.Equal(expectedTagHelpers.Length, results.Length); + Assert.Equal(expectedTagHelpers.Count, results.Count); foreach (var expectedTagHelper in expectedTagHelpers) { @@ -775,131 +760,88 @@ public void DirectiveVisitor_FiltersTagHelpersByDirectives( } } - public static TheoryData> ProcessTagHelperMatches_EmptyResultData - { - get + public static TheoryData ProcessTagHelperMatches_EmptyResultData + // source, taghelpers + => new() { - // source, taghelpers - return new TheoryData> { - { - $@" + $@" @addTagHelper *, {AssemblyA} @removeTagHelper *, {AssemblyA}", - new TagHelperDescriptor[] - { - Valid_PlainTagHelperDescriptor, - } - }, - { - $@" + [Valid_PlainTagHelperDescriptor] + }, + { + $@" @addTagHelper *, {AssemblyA} @removeTagHelper {Valid_PlainTagHelperDescriptor.Name}, {AssemblyA} @removeTagHelper {Valid_InheritedTagHelperDescriptor.Name}, {AssemblyA}", - new TagHelperDescriptor[] - { - Valid_PlainTagHelperDescriptor, - Valid_InheritedTagHelperDescriptor, - } - }, - { - $@" + [Valid_PlainTagHelperDescriptor, Valid_InheritedTagHelperDescriptor] + }, + { + $@" @addTagHelper *, {AssemblyA} @addTagHelper *, {AssemblyB} @removeTagHelper *, {AssemblyA} @removeTagHelper *, {AssemblyB}", - new TagHelperDescriptor[] - { - Valid_PlainTagHelperDescriptor, - Valid_InheritedTagHelperDescriptor, - String_TagHelperDescriptor, - } - }, - { - $@" + [Valid_PlainTagHelperDescriptor, Valid_InheritedTagHelperDescriptor, String_TagHelperDescriptor] + }, + { + $@" @addTagHelper *, {AssemblyA} @addTagHelper *, {AssemblyB} @removeTagHelper {Valid_PlainTagHelperDescriptor.Name}, {AssemblyA} @removeTagHelper {Valid_InheritedTagHelperDescriptor.Name}, {AssemblyA} @removeTagHelper {String_TagHelperDescriptor.Name}, {AssemblyB}", - new TagHelperDescriptor[] - { - Valid_PlainTagHelperDescriptor, - Valid_InheritedTagHelperDescriptor, - String_TagHelperDescriptor, - } - }, - { - $@" + [Valid_PlainTagHelperDescriptor, Valid_InheritedTagHelperDescriptor, String_TagHelperDescriptor] + }, + { + $@" @removeTagHelper *, {AssemblyA} @removeTagHelper {Valid_PlainTagHelperDescriptor.Name}, {AssemblyA}", - new TagHelperDescriptor[0] - }, - { - $@" + [] + }, + { + $@" @addTagHelper *, {AssemblyA} @removeTagHelper Mic*, {AssemblyA}", - new TagHelperDescriptor[] - { - Valid_PlainTagHelperDescriptor, - } - }, - { - $@" + [Valid_PlainTagHelperDescriptor] + }, + { + $@" @addTagHelper Mic*, {AssemblyA} @removeTagHelper {Valid_PlainTagHelperDescriptor.Name}, {AssemblyA} @removeTagHelper {Valid_InheritedTagHelperDescriptor.Name}, {AssemblyA}", - new TagHelperDescriptor[] - { - Valid_PlainTagHelperDescriptor, Valid_InheritedTagHelperDescriptor - } - }, - { - $@" + [Valid_PlainTagHelperDescriptor, Valid_InheritedTagHelperDescriptor] + }, + { + $@" @addTagHelper Microsoft.*, {AssemblyA} @addTagHelper System.*, {AssemblyB} @removeTagHelper Microsoft.AspNetCore.Razor.TagHelpers*, {AssemblyA} @removeTagHelper System.*, {AssemblyB}", - new TagHelperDescriptor[] - { - Valid_PlainTagHelperDescriptor, - Valid_InheritedTagHelperDescriptor, - String_TagHelperDescriptor, - } - }, - { - $@" + [Valid_PlainTagHelperDescriptor, Valid_InheritedTagHelperDescriptor, String_TagHelperDescriptor] + }, + { + $@" @addTagHelper ?icrosoft.*, {AssemblyA} @addTagHelper ?ystem.*, {AssemblyB} @removeTagHelper *?????r, {AssemblyA} @removeTagHelper Sy??em.*, {AssemblyB}", - new TagHelperDescriptor[] - { - Valid_PlainTagHelperDescriptor, - Valid_InheritedTagHelperDescriptor, - String_TagHelperDescriptor, - } - }, - { - $@" + [Valid_PlainTagHelperDescriptor, Valid_InheritedTagHelperDescriptor, String_TagHelperDescriptor] + }, + { + $@" @addTagHelper ?i?crosoft.*, {AssemblyA} @addTagHelper ??ystem.*, {AssemblyB}", - new TagHelperDescriptor[] - { - Valid_PlainTagHelperDescriptor, - Valid_InheritedTagHelperDescriptor, - String_TagHelperDescriptor, - } - }, - }; - } - } + [Valid_PlainTagHelperDescriptor, Valid_InheritedTagHelperDescriptor, String_TagHelperDescriptor] + } + }; [Theory] [MemberData(nameof(ProcessTagHelperMatches_EmptyResultData))] public void ProcessDirectives_CanReturnEmptyDescriptorsBasedOnDirectiveDescriptors( string source, - IReadOnlyList tagHelpers) + TagHelperCollection tagHelpers) { // Arrange var sourceDocument = TestRazorSourceDocument.Create(source, filePath: "TestFile"); @@ -922,11 +864,11 @@ public void TagHelperDirectiveVisitor_DoesNotMatch_Components() // Arrange var componentDescriptor = CreateComponentDescriptor("counter", "SomeProject.Counter", AssemblyA); var legacyDescriptor = Valid_PlainTagHelperDescriptor; - var tagHelpers = new[] - { + TagHelperCollection tagHelpers = + [ legacyDescriptor, - componentDescriptor, - }; + componentDescriptor + ]; var visitor = new DefaultRazorTagHelperContextDiscoveryPhase.TagHelperDirectiveVisitor(); visitor.Initialize(tagHelpers, filePath: null); @@ -975,15 +917,15 @@ public void ComponentDirectiveVisitor_DoesNotMatch_LegacyTagHelpers() var currentNamespace = "SomeProject"; var componentDescriptor = CreateComponentDescriptor("counter", "SomeProject.Counter", AssemblyA); var legacyDescriptor = Valid_PlainTagHelperDescriptor; - var descriptors = new[] - { + TagHelperCollection tagHelpers = + [ legacyDescriptor, - componentDescriptor, - }; + componentDescriptor + ]; var sourceDocument = CreateComponentTestSourceDocument(@"", "C:\\SomeFolder\\SomeProject\\Counter.cshtml"); var tree = RazorSyntaxTree.Parse(sourceDocument); var visitor = new DefaultRazorTagHelperContextDiscoveryPhase.ComponentDirectiveVisitor(); - visitor.Initialize(descriptors, sourceDocument.FilePath, currentNamespace); + visitor.Initialize(tagHelpers, sourceDocument.FilePath, currentNamespace); // Act visitor.Visit(tree); @@ -1001,11 +943,11 @@ public void ComponentDirectiveVisitor_AddsErrorOnLegacyTagHelperDirectives() var currentNamespace = "SomeProject"; var componentDescriptor = CreateComponentDescriptor("counter", "SomeProject.Counter", AssemblyA); var legacyDescriptor = Valid_PlainTagHelperDescriptor; - var descriptors = new[] - { + TagHelperCollection tagHelpers = + [ legacyDescriptor, - componentDescriptor, - }; + componentDescriptor + ]; var filePath = "C:\\SomeFolder\\SomeProject\\Counter.cshtml"; var content = @" @tagHelperPrefix th: @@ -1015,7 +957,7 @@ public void ComponentDirectiveVisitor_AddsErrorOnLegacyTagHelperDirectives() var sourceDocument = CreateComponentTestSourceDocument(content, filePath); var tree = RazorSyntaxTree.Parse(sourceDocument); var visitor = new DefaultRazorTagHelperContextDiscoveryPhase.ComponentDirectiveVisitor(); - visitor.Initialize(descriptors, sourceDocument.FilePath, currentNamespace); + visitor.Initialize(tagHelpers, sourceDocument.FilePath, currentNamespace); // Act visitor.Visit(tree); @@ -1040,17 +982,17 @@ public void ComponentDirectiveVisitor_MatchesFullyQualifiedComponents() "SomeProject.SomeOtherFolder.Counter", AssemblyA, fullyQualified: true); - var descriptors = new[] - { - componentDescriptor, - }; + TagHelperCollection tagHelpers = + [ + componentDescriptor + ]; var filePath = "C:\\SomeFolder\\SomeProject\\Counter.cshtml"; var content = @" "; var sourceDocument = CreateComponentTestSourceDocument(content, filePath); var tree = RazorSyntaxTree.Parse(sourceDocument); var visitor = new DefaultRazorTagHelperContextDiscoveryPhase.ComponentDirectiveVisitor(); - visitor.Initialize(descriptors, sourceDocument.FilePath, currentNamespace); + visitor.Initialize(tagHelpers, sourceDocument.FilePath, currentNamespace); // Act visitor.Visit(tree); @@ -1077,25 +1019,25 @@ public void ComponentDirectiveVisitor_ComponentInScope_MatchesChildContent() "SomeProject", "Counter", childContent: true); - var descriptors = new[] - { + TagHelperCollection tagHelpers = + [ componentDescriptor, - childContentDescriptor, - }; + childContentDescriptor + ]; var filePath = "C:\\SomeFolder\\SomeProject\\Counter.cshtml"; var content = @" "; var sourceDocument = CreateComponentTestSourceDocument(content, filePath); var tree = RazorSyntaxTree.Parse(sourceDocument); var visitor = new DefaultRazorTagHelperContextDiscoveryPhase.ComponentDirectiveVisitor(); - visitor.Initialize(descriptors, sourceDocument.FilePath, currentNamespace); + visitor.Initialize(tagHelpers, sourceDocument.FilePath, currentNamespace); // Act visitor.Visit(tree); var results = visitor.GetResults(); // Assert - Assert.Equal(2, results.Length); + Assert.Equal(2, results.Count); } [Fact] @@ -1112,18 +1054,18 @@ public void ComponentDirectiveVisitor_NullCurrentNamespace_MatchesOnlyFullyQuali "SomeProject.SomeOtherFolder.Counter", AssemblyA, fullyQualified: true); - var descriptors = new[] - { + TagHelperCollection tagHelpers = + [ componentDescriptor, - fullyQualifiedComponent, - }; + fullyQualifiedComponent + ]; var filePath = "C:\\SomeFolder\\SomeProject\\Counter.cshtml"; var content = @" "; var sourceDocument = CreateComponentTestSourceDocument(content, filePath); var tree = RazorSyntaxTree.Parse(sourceDocument); var visitor = new DefaultRazorTagHelperContextDiscoveryPhase.ComponentDirectiveVisitor(); - visitor.Initialize(descriptors, sourceDocument.FilePath, currentNamespace); + visitor.Initialize(tagHelpers, sourceDocument.FilePath, currentNamespace); // Act visitor.Visit(tree); @@ -1147,11 +1089,11 @@ public void ComponentDirectiveVisitor_MatchesIfNamespaceInUsing() "Foo", "SomeProject.SomeOtherFolder.Foo", AssemblyA); - var descriptors = new[] - { + TagHelperCollection tagHelpers = + [ componentDescriptor, - anotherComponentDescriptor, - }; + anotherComponentDescriptor + ]; var filePath = "C:\\SomeFolder\\SomeProject\\Counter.cshtml"; var content = @" @using SomeProject.SomeOtherFolder @@ -1159,14 +1101,14 @@ @using SomeProject.SomeOtherFolder var sourceDocument = CreateComponentTestSourceDocument(content, filePath); var tree = RazorSyntaxTree.Parse(sourceDocument); var visitor = new DefaultRazorTagHelperContextDiscoveryPhase.ComponentDirectiveVisitor(); - visitor.Initialize(descriptors, sourceDocument.FilePath, currentNamespace); + visitor.Initialize(tagHelpers, sourceDocument.FilePath, currentNamespace); // Act visitor.Visit(tree); var results = visitor.GetResults(); // Assert - Assert.Equal(2, results.Length); + Assert.Equal(2, results.Count); } [Fact] @@ -1178,10 +1120,10 @@ public void ComponentDirectiveVisitor_MatchesIfNamespaceInUsing_GlobalPrefix() "Counter", "SomeProject.SomeOtherFolder.Counter", AssemblyA); - var descriptors = new[] - { - componentDescriptor, - }; + TagHelperCollection tagHelpers = + [ + componentDescriptor + ]; var filePath = "C:\\SomeFolder\\SomeProject\\Counter.cshtml"; var content = """ @using global::SomeProject.SomeOtherFolder @@ -1189,7 +1131,7 @@ public void ComponentDirectiveVisitor_MatchesIfNamespaceInUsing_GlobalPrefix() var sourceDocument = CreateComponentTestSourceDocument(content, filePath); var tree = RazorSyntaxTree.Parse(sourceDocument); var visitor = new DefaultRazorTagHelperContextDiscoveryPhase.ComponentDirectiveVisitor(); - visitor.Initialize(descriptors, sourceDocument.FilePath, currentNamespace); + visitor.Initialize(tagHelpers, sourceDocument.FilePath, currentNamespace); // Act visitor.Visit(tree); @@ -1213,11 +1155,11 @@ public void ComponentDirectiveVisitor_DoesNotMatchForUsingAliasAndStaticUsings() "Foo", "SomeProject.SomeOtherFolder.Foo", AssemblyA); - var descriptors = new[] - { - componentDescriptor, - anotherComponentDescriptor, - }; + TagHelperCollection tagHelpers = + [ + componentDescriptor, + anotherComponentDescriptor + ]; var filePath = "C:\\SomeFolder\\SomeProject\\Counter.cshtml"; var content = @" @using Bar = SomeProject.SomeOtherFolder @@ -1226,7 +1168,7 @@ @using static SomeProject.SomeOtherFolder.Foo var sourceDocument = CreateComponentTestSourceDocument(content, filePath); var tree = RazorSyntaxTree.Parse(sourceDocument); var visitor = new DefaultRazorTagHelperContextDiscoveryPhase.ComponentDirectiveVisitor(); - visitor.Initialize(descriptors, sourceDocument.FilePath, currentNamespace); + visitor.Initialize(tagHelpers, sourceDocument.FilePath, currentNamespace); // Act visitor.Visit(tree); diff --git a/src/Compiler/Microsoft.AspNetCore.Razor.Language/test/IntegrationTests/CodeGenerationIntegrationTest.cs b/src/Compiler/Microsoft.AspNetCore.Razor.Language/test/IntegrationTests/CodeGenerationIntegrationTest.cs index c9a50288e04..849f4beaa13 100644 --- a/src/Compiler/Microsoft.AspNetCore.Razor.Language/test/IntegrationTests/CodeGenerationIntegrationTest.cs +++ b/src/Compiler/Microsoft.AspNetCore.Razor.Language/test/IntegrationTests/CodeGenerationIntegrationTest.cs @@ -1,7 +1,6 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -using System.Collections.Generic; using System.Collections.Immutable; using System.Linq; using System.Runtime.CompilerServices; @@ -371,19 +370,19 @@ private void RunTimeTest(string testName) AssertCSharpDiagnosticsMatchBaseline(codeDocument, testName); } - private void RunTagHelpersTest(IEnumerable descriptors, [CallerMemberName] string testName = "") + private void RunTagHelpersTest(TagHelperCollection tagHelpers, [CallerMemberName] string testName = "") { if (designTime) { - RunDesignTimeTagHelpersTest(descriptors, testName); + RunDesignTimeTagHelpersTest(tagHelpers, testName); } else { - RunRuntimeTagHelpersTest(descriptors, testName); + RunRuntimeTagHelpersTest(tagHelpers, testName); } } - private void RunRuntimeTagHelpersTest(IEnumerable descriptors, string testName) + private void RunRuntimeTagHelpersTest(TagHelperCollection tagHelpers, string testName) { // Arrange var projectEngine = CreateProjectEngine(RazorExtensions.Register); @@ -391,10 +390,10 @@ private void RunRuntimeTagHelpersTest(IEnumerable descripto var projectItem = CreateProjectItemFromFile(testName: testName); var imports = GetImports(projectEngine, projectItem); - AddTagHelperStubs(descriptors); + AddTagHelperStubs(tagHelpers); // Act - var codeDocument = projectEngine.Process(RazorSourceDocument.ReadFrom(projectItem), RazorFileKind.Legacy, imports, descriptors.ToList()); + var codeDocument = projectEngine.Process(RazorSourceDocument.ReadFrom(projectItem), RazorFileKind.Legacy, imports, tagHelpers); // Assert AssertDocumentNodeMatchesBaseline(codeDocument.GetRequiredDocumentNode(), testName); @@ -402,7 +401,7 @@ private void RunRuntimeTagHelpersTest(IEnumerable descripto AssertCSharpDiagnosticsMatchBaseline(codeDocument, testName); } - private void RunDesignTimeTagHelpersTest(IEnumerable descriptors, string testName) + private void RunDesignTimeTagHelpersTest(TagHelperCollection tagHelpers, string testName) { // Arrange var projectEngine = CreateProjectEngine(RazorExtensions.Register); @@ -410,10 +409,10 @@ private void RunDesignTimeTagHelpersTest(IEnumerable descri var projectItem = CreateProjectItemFromFile(testName: testName); var imports = GetImports(projectEngine, projectItem); - AddTagHelperStubs(descriptors); + AddTagHelperStubs(tagHelpers); // Act - var codeDocument = projectEngine.ProcessDesignTime(RazorSourceDocument.ReadFrom(projectItem), RazorFileKind.Legacy, imports, descriptors.ToList()); + var codeDocument = projectEngine.ProcessDesignTime(RazorSourceDocument.ReadFrom(projectItem), RazorFileKind.Legacy, imports, tagHelpers); // Assert AssertDocumentNodeMatchesBaseline(codeDocument.GetRequiredDocumentNode(), testName); @@ -435,9 +434,9 @@ private static ImmutableArray GetImports(RazorProjectEngine return result.ToImmutable(); } - private void AddTagHelperStubs(IEnumerable descriptors) + private void AddTagHelperStubs(TagHelperCollection tagHelpers) { - var tagHelperClasses = descriptors.Select(descriptor => + var tagHelperClasses = tagHelpers.Select(descriptor => { var typeName = descriptor.TypeName; var namespaceSeparatorIndex = typeName.LastIndexOf('.'); diff --git a/src/Compiler/Microsoft.AspNetCore.Razor.Language/test/IntegrationTests/TagHelpersIntegrationTest.cs b/src/Compiler/Microsoft.AspNetCore.Razor.Language/test/IntegrationTests/TagHelpersIntegrationTest.cs index 7aae3295dbc..37440b08e53 100644 --- a/src/Compiler/Microsoft.AspNetCore.Razor.Language/test/IntegrationTests/TagHelpersIntegrationTest.cs +++ b/src/Compiler/Microsoft.AspNetCore.Razor.Language/test/IntegrationTests/TagHelpersIntegrationTest.cs @@ -4,6 +4,7 @@ using System; using System.Collections.Generic; using Xunit; +using static Microsoft.AspNetCore.Mvc.Razor.Extensions.ViewComponentsApi; namespace Microsoft.AspNetCore.Razor.Language.IntegrationTests; @@ -13,15 +14,15 @@ public class TagHelpersIntegrationTest() : IntegrationTestBase(layer: TestProjec public void SimpleTagHelpers() { // Arrange - var descriptors = new[] - { + TagHelperCollection tagHelpers = + [ CreateTagHelperDescriptor( tagName: "input", typeName: "InputTagHelper", assemblyName: "TestAssembly") - }; + ]; - var projectEngine = CreateProjectEngine(builder => builder.AddTagHelpers(descriptors)); + var projectEngine = CreateProjectEngine(builder => builder.SetTagHelpers(tagHelpers)); var projectItem = CreateProjectItemFromFile(); // Act @@ -35,22 +36,22 @@ public void SimpleTagHelpers() public void TagHelpersWithBoundAttributes() { // Arrange - var descriptors = new[] - { + TagHelperCollection tagHelpers = + [ CreateTagHelperDescriptor( tagName: "input", typeName: "InputTagHelper", assemblyName: "TestAssembly", - attributes: new Action[] - { + attributes: + [ builder => builder .Name("bound") .PropertyName("FooProp") .TypeName("System.String"), - }) - }; + ]) + ]; - var projectEngine = CreateProjectEngine(builder => builder.AddTagHelpers(descriptors)); + var projectEngine = CreateProjectEngine(builder => builder.SetTagHelpers(tagHelpers)); var projectItem = CreateProjectItemFromFile(); // Act @@ -64,8 +65,8 @@ public void TagHelpersWithBoundAttributes() public void NestedTagHelpers() { // Arrange - var descriptors = new[] - { + TagHelperCollection tagHelpers = + [ CreateTagHelperDescriptor( tagName: "p", typeName: "PTagHelper", @@ -78,16 +79,16 @@ public void NestedTagHelpers() tagName: "input", typeName: "InputTagHelper", assemblyName: "TestAssembly", - attributes: new Action[] - { + attributes: + [ builder => builder .Name("value") .PropertyName("FooProp") .TypeName("System.String"), - }) - }; + ]) + ]; - var projectEngine = CreateProjectEngine(builder => builder.AddTagHelpers(descriptors)); + var projectEngine = CreateProjectEngine(builder => builder.SetTagHelpers(tagHelpers)); var projectItem = CreateProjectItemFromFile(); // Act diff --git a/src/Compiler/Microsoft.AspNetCore.Razor.Language/test/IntegrationTests/TestTagHelperDescriptors.cs b/src/Compiler/Microsoft.AspNetCore.Razor.Language/test/IntegrationTests/TestTagHelperDescriptors.cs index eaa229621bb..85d9d549423 100644 --- a/src/Compiler/Microsoft.AspNetCore.Razor.Language/test/IntegrationTests/TestTagHelperDescriptors.cs +++ b/src/Compiler/Microsoft.AspNetCore.Razor.Language/test/IntegrationTests/TestTagHelperDescriptors.cs @@ -1,460 +1,461 @@ // 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 System; using System.Collections.Generic; using System.Reflection; +using Xunit; namespace Microsoft.AspNetCore.Razor.Language.IntegrationTests; public class TestTagHelperDescriptors { - public static IEnumerable SimpleTagHelperDescriptors + public static TagHelperCollection SimpleTagHelperDescriptors { get { - return new[] - { - CreateTagHelperDescriptor( - tagName: "span", - typeName: "SpanTagHelper", - assemblyName: "TestAssembly"), - CreateTagHelperDescriptor( - tagName: "div", - typeName: "DivTagHelper", - assemblyName: "TestAssembly"), - CreateTagHelperDescriptor( - tagName: "input", - typeName: "InputTagHelper", - assemblyName: "TestAssembly", - attributes: new Action[] - { - builder => builder - .Name("value") - .PropertyName("FooProp") - .TypeName("System.String"), - builder => builder - .Name("bound") - .PropertyName("BoundProp") - .TypeName("System.String"), - builder => builder - .Name("age") - .PropertyName("AgeProp") - .TypeName("System.Int32"), - builder => builder - .Name("alive") - .PropertyName("AliveProp") - .TypeName("System.Boolean"), - builder => builder - .Name("tag") - .PropertyName("TagProp") - .TypeName("System.Object"), - builder => builder - .Name("tuple-dictionary") - .PropertyName("DictionaryOfBoolAndStringTupleProperty") - .TypeName(typeof(IDictionary).Namespace + ".IDictionary") - .AsDictionaryAttribute("tuple-prefix-", typeof((bool, string)).FullName) - }) - }; + return + [ + CreateTagHelperDescriptor( + tagName: "span", + typeName: "SpanTagHelper", + assemblyName: "TestAssembly"), + CreateTagHelperDescriptor( + tagName: "div", + typeName: "DivTagHelper", + assemblyName: "TestAssembly"), + CreateTagHelperDescriptor( + tagName: "input", + typeName: "InputTagHelper", + assemblyName: "TestAssembly", + attributes: + [ + builder => builder + .Name("value") + .PropertyName("FooProp") + .TypeName("System.String"), + builder => builder + .Name("bound") + .PropertyName("BoundProp") + .TypeName("System.String"), + builder => builder + .Name("age") + .PropertyName("AgeProp") + .TypeName("System.Int32"), + builder => builder + .Name("alive") + .PropertyName("AliveProp") + .TypeName("System.Boolean"), + builder => builder + .Name("tag") + .PropertyName("TagProp") + .TypeName("System.Object"), + builder => builder + .Name("tuple-dictionary") + .PropertyName("DictionaryOfBoolAndStringTupleProperty") + .TypeName(typeof(IDictionary).Namespace + ".IDictionary") + .AsDictionaryAttribute("tuple-prefix-", typeof((bool, string)).FullName) + ]) + ]; } } - public static IEnumerable MinimizedBooleanTagHelperDescriptors + public static TagHelperCollection MinimizedBooleanTagHelperDescriptors { get { - return new[] - { - CreateTagHelperDescriptor( - tagName: "span", - typeName: "SpanTagHelper", - assemblyName: "TestAssembly"), - CreateTagHelperDescriptor( - tagName: "div", - typeName: "DivTagHelper", - assemblyName: "TestAssembly"), - CreateTagHelperDescriptor( - tagName: "input", - typeName: "InputTagHelper", - assemblyName: "TestAssembly", - attributes: new Action[] - { - builder => builder - .Name("value") - .PropertyName("FooProp") - .TypeName("System.String"), - builder => builder - .Name("bound") - .PropertyName("BoundProp") - .TypeName("System.Boolean"), - builder => builder - .Name("age") - .PropertyName("AgeProp") - .TypeName("System.Int32"), - }) - }; + return + [ + CreateTagHelperDescriptor( + tagName: "span", + typeName: "SpanTagHelper", + assemblyName: "TestAssembly"), + CreateTagHelperDescriptor( + tagName: "div", + typeName: "DivTagHelper", + assemblyName: "TestAssembly"), + CreateTagHelperDescriptor( + tagName: "input", + typeName: "InputTagHelper", + assemblyName: "TestAssembly", + attributes: + [ + builder => builder + .Name("value") + .PropertyName("FooProp") + .TypeName("System.String"), + builder => builder + .Name("bound") + .PropertyName("BoundProp") + .TypeName("System.Boolean"), + builder => builder + .Name("age") + .PropertyName("AgeProp") + .TypeName("System.Int32"), + ]) + ]; } } - public static IEnumerable CssSelectorTagHelperDescriptors + public static TagHelperCollection CssSelectorTagHelperDescriptors { get { - var inputTypePropertyInfo = typeof(TestType).GetRuntimeProperty("Type"); - var inputCheckedPropertyInfo = typeof(TestType).GetRuntimeProperty("Checked"); + var inputTypePropertyInfo = GetTestTypeRuntimeProperty("Type"); + var inputCheckedPropertyInfo = GetTestTypeRuntimeProperty("Checked"); - return new[] - { - CreateTagHelperDescriptor( - tagName: "a", - typeName: "TestNamespace.ATagHelper", - assemblyName: "TestAssembly", - ruleBuilders: new Action[] - { - builder => builder - .RequireAttributeDescriptor(attribute => attribute - .Name("href", RequiredAttributeNameComparison.FullMatch) - .Value("~/", RequiredAttributeValueComparison.FullMatch)), - }), - CreateTagHelperDescriptor( - tagName: "a", - typeName: "TestNamespace.ATagHelperMultipleSelectors", - assemblyName: "TestAssembly", - ruleBuilders: new Action[] - { - builder => builder - .RequireAttributeDescriptor(attribute => attribute - .Name("href", RequiredAttributeNameComparison.FullMatch) - .Value("~/", RequiredAttributeValueComparison.PrefixMatch)) - .RequireAttributeDescriptor(attribute => attribute - .Name("href", RequiredAttributeNameComparison.FullMatch) - .Value("?hello=world", RequiredAttributeValueComparison.SuffixMatch)), - }), - CreateTagHelperDescriptor( - tagName: "input", - typeName: "TestNamespace.InputTagHelper", - assemblyName: "TestAssembly", - attributes: new Action[] - { - builder => BuildBoundAttributeDescriptorFromPropertyInfo(builder, "type", inputTypePropertyInfo), - }, - ruleBuilders: new Action[] - { - builder => builder - .RequireAttributeDescriptor(attribute => attribute - .Name("type", RequiredAttributeNameComparison.FullMatch) - .Value("text", RequiredAttributeValueComparison.FullMatch)), - }), - CreateTagHelperDescriptor( - tagName: "input", - typeName: "TestNamespace.InputTagHelper2", - assemblyName: "TestAssembly", - attributes: new Action[] - { - builder => BuildBoundAttributeDescriptorFromPropertyInfo(builder, "type", inputTypePropertyInfo), - }, - ruleBuilders: new Action[] - { - builder => builder - .RequireAttributeDescriptor(attribute => attribute - .Name("ty", RequiredAttributeNameComparison.PrefixMatch)), - }), - CreateTagHelperDescriptor( - tagName: "*", - typeName: "TestNamespace.CatchAllTagHelper", - assemblyName: "TestAssembly", - ruleBuilders: new Action[] - { - builder => builder - .RequireAttributeDescriptor(attribute => attribute - .Name("href", RequiredAttributeNameComparison.FullMatch) - .Value("~/", RequiredAttributeValueComparison.PrefixMatch)), - }), - CreateTagHelperDescriptor( - tagName: "*", - typeName: "TestNamespace.CatchAllTagHelper2", - assemblyName: "TestAssembly", - ruleBuilders: new Action[] - { - builder => builder - .RequireAttributeDescriptor(attribute => attribute - .Name("type", RequiredAttributeNameComparison.FullMatch)), - }), - }; + return + [ + CreateTagHelperDescriptor( + tagName: "a", + typeName: "TestNamespace.ATagHelper", + assemblyName: "TestAssembly", + ruleBuilders: + [ + builder => builder + .RequireAttributeDescriptor(attribute => attribute + .Name("href", RequiredAttributeNameComparison.FullMatch) + .Value("~/", RequiredAttributeValueComparison.FullMatch)), + ]), + CreateTagHelperDescriptor( + tagName: "a", + typeName: "TestNamespace.ATagHelperMultipleSelectors", + assemblyName: "TestAssembly", + ruleBuilders: + [ + builder => builder + .RequireAttributeDescriptor(attribute => attribute + .Name("href", RequiredAttributeNameComparison.FullMatch) + .Value("~/", RequiredAttributeValueComparison.PrefixMatch)) + .RequireAttributeDescriptor(attribute => attribute + .Name("href", RequiredAttributeNameComparison.FullMatch) + .Value("?hello=world", RequiredAttributeValueComparison.SuffixMatch)), + ]), + CreateTagHelperDescriptor( + tagName: "input", + typeName: "TestNamespace.InputTagHelper", + assemblyName: "TestAssembly", + attributes: + [ + builder => BuildBoundAttributeDescriptorFromPropertyInfo(builder, "type", inputTypePropertyInfo), + ], + ruleBuilders: + [ + builder => builder + .RequireAttributeDescriptor(attribute => attribute + .Name("type", RequiredAttributeNameComparison.FullMatch) + .Value("text", RequiredAttributeValueComparison.FullMatch)), + ]), + CreateTagHelperDescriptor( + tagName: "input", + typeName: "TestNamespace.InputTagHelper2", + assemblyName: "TestAssembly", + attributes: + [ + builder => BuildBoundAttributeDescriptorFromPropertyInfo(builder, "type", inputTypePropertyInfo), + ], + ruleBuilders: + [ + builder => builder + .RequireAttributeDescriptor(attribute => attribute + .Name("ty", RequiredAttributeNameComparison.PrefixMatch)), + ]), + CreateTagHelperDescriptor( + tagName: "*", + typeName: "TestNamespace.CatchAllTagHelper", + assemblyName: "TestAssembly", + ruleBuilders: + [ + builder => builder + .RequireAttributeDescriptor(attribute => attribute + .Name("href", RequiredAttributeNameComparison.FullMatch) + .Value("~/", RequiredAttributeValueComparison.PrefixMatch)), + ]), + CreateTagHelperDescriptor( + tagName: "*", + typeName: "TestNamespace.CatchAllTagHelper2", + assemblyName: "TestAssembly", + ruleBuilders: + [ + builder => builder + .RequireAttributeDescriptor(attribute => attribute + .Name("type", RequiredAttributeNameComparison.FullMatch)), + ]), + ]; } } - public static IEnumerable EnumTagHelperDescriptors + public static TagHelperCollection EnumTagHelperDescriptors { get { - return new[] - { + return + [ CreateTagHelperDescriptor( tagName: "*", typeName: "TestNamespace.CatchAllTagHelper", assemblyName: "TestAssembly", - attributes: new Action[] - { + attributes: + [ builder => builder .Name("catch-all") .PropertyName("CatchAll") .AsEnum() .TypeName("Microsoft.AspNetCore.Razor.Language.IntegrationTests.TestTagHelperDescriptors.MyEnum"), - }), + ]), CreateTagHelperDescriptor( tagName: "input", typeName: "TestNamespace.InputTagHelper", assemblyName: "TestAssembly", - attributes: new Action[] - { + attributes: + [ builder => builder .Name("value") .PropertyName("Value") .AsEnum() .TypeName("Microsoft.AspNetCore.Razor.Language.IntegrationTests.TestTagHelperDescriptors.MyEnum"), - }), - }; + ]), + ]; } } - public static IEnumerable SymbolBoundTagHelperDescriptors + public static TagHelperCollection SymbolBoundTagHelperDescriptors { get { - return new[] - { - CreateTagHelperDescriptor( - tagName: "*", - typeName: "TestNamespace.CatchAllTagHelper", - assemblyName: "TestAssembly", - attributes: new Action[] - { - builder => builder - .Name("[item]") - .PropertyName("ListItems") - .TypeName("System.Collections.Generic.List"), - builder => builder - .Name("[(item)]") - .PropertyName("ArrayItems") - .TypeName(typeof(string[]).FullName), - builder => builder - .Name("(click)") - .PropertyName("Event1") - .TypeName(typeof(Action).FullName), - builder => builder - .Name("(^click)") - .PropertyName("Event2") - .TypeName(typeof(Action).FullName), - builder => builder - .Name("*something") - .PropertyName("StringProperty1") - .TypeName(typeof(string).FullName), - builder => builder - .Name("#local") - .PropertyName("StringProperty2") - .TypeName(typeof(string).FullName), - }, - ruleBuilders: new Action[] - { - builder => builder.RequireAttributeDescriptor(attribute => attribute.Name("bound")), - }), - }; + return + [ + CreateTagHelperDescriptor( + tagName: "*", + typeName: "TestNamespace.CatchAllTagHelper", + assemblyName: "TestAssembly", + attributes: + [ + builder => builder + .Name("[item]") + .PropertyName("ListItems") + .TypeName("System.Collections.Generic.List"), + builder => builder + .Name("[(item)]") + .PropertyName("ArrayItems") + .TypeName(typeof(string[]).FullName), + builder => builder + .Name("(click)") + .PropertyName("Event1") + .TypeName(typeof(Action).FullName), + builder => builder + .Name("(^click)") + .PropertyName("Event2") + .TypeName(typeof(Action).FullName), + builder => builder + .Name("*something") + .PropertyName("StringProperty1") + .TypeName(typeof(string).FullName), + builder => builder + .Name("#local") + .PropertyName("StringProperty2") + .TypeName(typeof(string).FullName), + ], + ruleBuilders: + [ + builder => builder.RequireAttributeDescriptor(attribute => attribute.Name("bound")), + ]), + ]; } } - public static IEnumerable MinimizedTagHelpers_Descriptors + public static TagHelperCollection MinimizedTagHelpers_Descriptors { get { - return new[] - { - CreateTagHelperDescriptor( - tagName: "*", - typeName: "TestNamespace.CatchAllTagHelper", - assemblyName: "TestAssembly", - attributes: new Action[] - { - builder => builder - .Name("catchall-bound-string") - .PropertyName("BoundRequiredString") - .TypeName(typeof(string).FullName), - }, - ruleBuilders: new Action[] - { - builder => builder.RequireAttributeDescriptor(attribute => attribute.Name("catchall-unbound-required")), - }), - CreateTagHelperDescriptor( - tagName: "input", - typeName: "TestNamespace.InputTagHelper", - assemblyName: "TestAssembly", - attributes: new Action[] - { - builder => builder - .Name("input-bound-required-string") - .PropertyName("BoundRequiredString") - .TypeName(typeof(string).FullName), - builder => builder - .Name("input-bound-string") - .PropertyName("BoundString") - .TypeName(typeof(string).FullName), - }, - ruleBuilders: new Action[] - { - builder => builder - .RequireAttributeDescriptor(attribute => attribute.Name("input-bound-required-string")) - .RequireAttributeDescriptor(attribute => attribute.Name("input-unbound-required")), - }), - CreateTagHelperDescriptor( - tagName: "div", - typeName: "DivTagHelper", - assemblyName: "TestAssembly", - attributes: new Action[] - { - builder => builder - .Name("boundbool") - .PropertyName("BoundBoolProp") - .TypeName(typeof(bool).FullName), - builder => builder - .Name("booldict") - .PropertyName("BoolDictProp") - .TypeName("System.Collections.Generic.IDictionary") - .AsDictionaryAttribute("booldict-prefix-", typeof(bool).FullName), - }), - }; + return + [ + CreateTagHelperDescriptor( + tagName: "*", + typeName: "TestNamespace.CatchAllTagHelper", + assemblyName: "TestAssembly", + attributes: + [ + builder => builder + .Name("catchall-bound-string") + .PropertyName("BoundRequiredString") + .TypeName(typeof(string).FullName), + ], + ruleBuilders: + [ + builder => builder.RequireAttributeDescriptor(attribute => attribute.Name("catchall-unbound-required")), + ]), + CreateTagHelperDescriptor( + tagName: "input", + typeName: "TestNamespace.InputTagHelper", + assemblyName: "TestAssembly", + attributes: + [ + builder => builder + .Name("input-bound-required-string") + .PropertyName("BoundRequiredString") + .TypeName(typeof(string).FullName), + builder => builder + .Name("input-bound-string") + .PropertyName("BoundString") + .TypeName(typeof(string).FullName), + ], + ruleBuilders: + [ + builder => builder + .RequireAttributeDescriptor(attribute => attribute.Name("input-bound-required-string")) + .RequireAttributeDescriptor(attribute => attribute.Name("input-unbound-required")), + ]), + CreateTagHelperDescriptor( + tagName: "div", + typeName: "DivTagHelper", + assemblyName: "TestAssembly", + attributes: + [ + builder => builder + .Name("boundbool") + .PropertyName("BoundBoolProp") + .TypeName(typeof(bool).FullName), + builder => builder + .Name("booldict") + .PropertyName("BoolDictProp") + .TypeName("System.Collections.Generic.IDictionary") + .AsDictionaryAttribute("booldict-prefix-", typeof(bool).FullName), + ]), + ]; } } - public static IEnumerable DynamicAttributeTagHelpers_Descriptors + public static TagHelperCollection DynamicAttributeTagHelpers_Descriptors { get { - return new[] - { + return + [ CreateTagHelperDescriptor( tagName: "input", typeName: "TestNamespace.InputTagHelper", assemblyName: "TestAssembly", - attributes: new Action[] - { + attributes: + [ builder => builder .Name("bound") .PropertyName("Bound") .TypeName(typeof(string).FullName) - }), - }; + ]), + ]; } } - public static IEnumerable DuplicateTargetTagHelperDescriptors + public static TagHelperCollection DuplicateTargetTagHelperDescriptors { get { - var typePropertyInfo = typeof(TestType).GetRuntimeProperty("Type"); - var checkedPropertyInfo = typeof(TestType).GetRuntimeProperty("Checked"); - return new[] - { - CreateTagHelperDescriptor( - tagName: "*", - typeName: "TestNamespace.CatchAllTagHelper", - assemblyName: "TestAssembly", - attributes: new Action[] - { - builder => BuildBoundAttributeDescriptorFromPropertyInfo(builder, "type", typePropertyInfo), - builder => BuildBoundAttributeDescriptorFromPropertyInfo(builder, "checked", checkedPropertyInfo), - }, - ruleBuilders: new Action[] - { - builder => builder.RequireAttributeDescriptor(attribute => attribute.Name("type")), - builder => builder.RequireAttributeDescriptor(attribute => attribute.Name("checked")) - }), - CreateTagHelperDescriptor( - tagName: "input", - typeName: "TestNamespace.InputTagHelper", - assemblyName: "TestAssembly", - attributes: new Action[] - { - builder => BuildBoundAttributeDescriptorFromPropertyInfo(builder, "type", typePropertyInfo), - builder => BuildBoundAttributeDescriptorFromPropertyInfo(builder, "checked", checkedPropertyInfo), - }, - ruleBuilders: new Action[] - { - builder => builder.RequireAttributeDescriptor(attribute => attribute.Name("type")), - builder => builder.RequireAttributeDescriptor(attribute => attribute.Name("checked")) - }) - }; + var typePropertyInfo = GetTestTypeRuntimeProperty("Type"); + var checkedPropertyInfo = GetTestTypeRuntimeProperty("Checked"); + + return + [ + CreateTagHelperDescriptor( + tagName: "*", + typeName: "TestNamespace.CatchAllTagHelper", + assemblyName: "TestAssembly", + attributes: + [ + builder => BuildBoundAttributeDescriptorFromPropertyInfo(builder, "type", typePropertyInfo), + builder => BuildBoundAttributeDescriptorFromPropertyInfo(builder, "checked", checkedPropertyInfo), + ], + ruleBuilders: + [ + builder => builder.RequireAttributeDescriptor(attribute => attribute.Name("type")), + builder => builder.RequireAttributeDescriptor(attribute => attribute.Name("checked")) + ]), + CreateTagHelperDescriptor( + tagName: "input", + typeName: "TestNamespace.InputTagHelper", + assemblyName: "TestAssembly", + attributes: + [ + builder => BuildBoundAttributeDescriptorFromPropertyInfo(builder, "type", typePropertyInfo), + builder => BuildBoundAttributeDescriptorFromPropertyInfo(builder, "checked", checkedPropertyInfo), + ], + ruleBuilders: + [ + builder => builder.RequireAttributeDescriptor(attribute => attribute.Name("type")), + builder => builder.RequireAttributeDescriptor(attribute => attribute.Name("checked")) + ]) + ]; } } - public static IEnumerable AttributeTargetingTagHelperDescriptors + public static TagHelperCollection AttributeTargetingTagHelperDescriptors { get { - var inputTypePropertyInfo = typeof(TestType).GetRuntimeProperty("Type"); - var inputCheckedPropertyInfo = typeof(TestType).GetRuntimeProperty("Checked"); - return new[] - { - CreateTagHelperDescriptor( - tagName: "p", - typeName: "TestNamespace.PTagHelper", - assemblyName: "TestAssembly", - ruleBuilders: new Action[] - { - builder => builder.RequireAttributeDescriptor(attribute => attribute.Name("class")), - }), - CreateTagHelperDescriptor( - tagName: "input", - typeName: "TestNamespace.InputTagHelper", - assemblyName: "TestAssembly", - attributes: new Action[] - { - builder => BuildBoundAttributeDescriptorFromPropertyInfo(builder, "type", inputTypePropertyInfo), - }, - ruleBuilders: new Action[] - { - builder => builder.RequireAttributeDescriptor(attribute => attribute.Name("type")), - }), - CreateTagHelperDescriptor( - tagName: "input", - typeName: "TestNamespace.InputTagHelper2", - assemblyName: "TestAssembly", - attributes: new Action[] - { - builder => BuildBoundAttributeDescriptorFromPropertyInfo(builder, "type", inputTypePropertyInfo), - builder => BuildBoundAttributeDescriptorFromPropertyInfo(builder, "checked", inputCheckedPropertyInfo), - }, - ruleBuilders: new Action[] - { - builder => builder - .RequireAttributeDescriptor(attribute => attribute.Name("type")) - .RequireAttributeDescriptor(attribute => attribute.Name("checked")), - }), - CreateTagHelperDescriptor( - tagName: "*", - typeName: "TestNamespace.CatchAllTagHelper", - assemblyName: "TestAssembly", - ruleBuilders: new Action[] - { - builder => builder.RequireAttributeDescriptor(attribute => attribute.Name("catchAll")), - }), - }; + var inputTypePropertyInfo = GetTestTypeRuntimeProperty("Type"); + var inputCheckedPropertyInfo = GetTestTypeRuntimeProperty("Checked"); + + return + [ + CreateTagHelperDescriptor( + tagName: "p", + typeName: "TestNamespace.PTagHelper", + assemblyName: "TestAssembly", + ruleBuilders: + [ + builder => builder.RequireAttributeDescriptor(attribute => attribute.Name("class")), + ]), + CreateTagHelperDescriptor( + tagName: "input", + typeName: "TestNamespace.InputTagHelper", + assemblyName: "TestAssembly", + attributes: + [ + builder => BuildBoundAttributeDescriptorFromPropertyInfo(builder, "type", inputTypePropertyInfo), + ], + ruleBuilders: + [ + builder => builder.RequireAttributeDescriptor(attribute => attribute.Name("type")), + ]), + CreateTagHelperDescriptor( + tagName: "input", + typeName: "TestNamespace.InputTagHelper2", + assemblyName: "TestAssembly", + attributes: + [ + builder => BuildBoundAttributeDescriptorFromPropertyInfo(builder, "type", inputTypePropertyInfo), + builder => BuildBoundAttributeDescriptorFromPropertyInfo(builder, "checked", inputCheckedPropertyInfo), + ], + ruleBuilders: + [ + builder => builder + .RequireAttributeDescriptor(attribute => attribute.Name("type")) + .RequireAttributeDescriptor(attribute => attribute.Name("checked")), + ]), + CreateTagHelperDescriptor( + tagName: "*", + typeName: "TestNamespace.CatchAllTagHelper", + assemblyName: "TestAssembly", + ruleBuilders: + [ + builder => builder.RequireAttributeDescriptor(attribute => attribute.Name("catchAll")), + ]), + ]; } } - public static IEnumerable PrefixedAttributeTagHelperDescriptors + public static TagHelperCollection PrefixedAttributeTagHelperDescriptors { get { - return new[] - { + return + [ CreateTagHelperDescriptor( tagName: "input", typeName: "TestNamespace.InputTagHelper1", assemblyName: "TestAssembly", - attributes: new Action[] - { + attributes: + [ builder => builder .Name("int-prefix-grabber") .PropertyName("IntProperty") @@ -473,13 +474,13 @@ public static IEnumerable PrefixedAttributeTagHelperDescrip .PropertyName("StringDictionaryProperty") .TypeName("Namespace.DictionaryWithoutParameterlessConstructor") .AsDictionaryAttribute("string-prefix-", typeof(string).FullName), - }), + ]), CreateTagHelperDescriptor( tagName: "input", typeName: "TestNamespace.InputTagHelper2", assemblyName: "TestAssembly", - attributes: new Action[] - { + attributes: + [ builder => builder .Name("int-dictionary") .PropertyName("IntDictionaryProperty") @@ -490,78 +491,79 @@ public static IEnumerable PrefixedAttributeTagHelperDescrip .PropertyName("StringDictionaryProperty") .TypeName("Namespace.DictionaryWithoutParameterlessConstructor") .AsDictionaryAttribute("string-prefix-", typeof(string).FullName), - }), - }; + ]), + ]; } } - public static IEnumerable TagHelpersInSectionDescriptors + public static TagHelperCollection TagHelpersInSectionDescriptors { get { - var propertyInfo = typeof(TestType).GetRuntimeProperty("BoundProperty"); - return new[] - { - CreateTagHelperDescriptor( - tagName: "MyTagHelper", - typeName: "TestNamespace.MyTagHelper", - assemblyName: "TestAssembly", - attributes: new Action[] - { - builder => BuildBoundAttributeDescriptorFromPropertyInfo(builder, "BoundProperty", propertyInfo), - }), - CreateTagHelperDescriptor( - tagName: "NestedTagHelper", - typeName: "TestNamespace.NestedTagHelper", - assemblyName: "TestAssembly"), - }; + var propertyInfo = GetTestTypeRuntimeProperty("BoundProperty"); + + return + [ + CreateTagHelperDescriptor( + tagName: "MyTagHelper", + typeName: "TestNamespace.MyTagHelper", + assemblyName: "TestAssembly", + attributes: + [ + builder => BuildBoundAttributeDescriptorFromPropertyInfo(builder, "BoundProperty", propertyInfo), + ]), + CreateTagHelperDescriptor( + tagName: "NestedTagHelper", + typeName: "TestNamespace.NestedTagHelper", + assemblyName: "TestAssembly"), + ]; } } - public static IEnumerable DefaultPAndInputTagHelperDescriptors + public static TagHelperCollection DefaultPAndInputTagHelperDescriptors { get { - var pAgePropertyInfo = typeof(TestType).GetRuntimeProperty("Age"); - var inputTypePropertyInfo = typeof(TestType).GetRuntimeProperty("Type"); - var checkedPropertyInfo = typeof(TestType).GetRuntimeProperty("Checked"); + var pAgePropertyInfo = GetTestTypeRuntimeProperty("Age"); + var inputTypePropertyInfo = GetTestTypeRuntimeProperty("Type"); + var checkedPropertyInfo = GetTestTypeRuntimeProperty("Checked"); - return new[] - { - CreateTagHelperDescriptor( - tagName: "p", - typeName: "TestNamespace.PTagHelper", - assemblyName: "TestAssembly", - attributes: new Action[] - { - builder => BuildBoundAttributeDescriptorFromPropertyInfo(builder, "age", pAgePropertyInfo), - }, - ruleBuilders: new Action[] - { - builder => builder.RequireTagStructure(TagStructure.NormalOrSelfClosing) - }), - CreateTagHelperDescriptor( - tagName: "input", - typeName: "TestNamespace.InputTagHelper", - assemblyName: "TestAssembly", - attributes: new Action[] - { - builder => BuildBoundAttributeDescriptorFromPropertyInfo(builder, "type", inputTypePropertyInfo), - }, - ruleBuilders: new Action[] - { - builder => builder.RequireTagStructure(TagStructure.WithoutEndTag) - }), - CreateTagHelperDescriptor( - tagName: "input", - typeName: "TestNamespace.InputTagHelper2", - assemblyName: "TestAssembly", - attributes: new Action[] - { - builder => BuildBoundAttributeDescriptorFromPropertyInfo(builder, "type", inputTypePropertyInfo), - builder => BuildBoundAttributeDescriptorFromPropertyInfo(builder, "checked", checkedPropertyInfo), - }), - }; + return + [ + CreateTagHelperDescriptor( + tagName: "p", + typeName: "TestNamespace.PTagHelper", + assemblyName: "TestAssembly", + attributes: + [ + builder => BuildBoundAttributeDescriptorFromPropertyInfo(builder, "age", pAgePropertyInfo), + ], + ruleBuilders: + [ + builder => builder.RequireTagStructure(TagStructure.NormalOrSelfClosing) + ]), + CreateTagHelperDescriptor( + tagName: "input", + typeName: "TestNamespace.InputTagHelper", + assemblyName: "TestAssembly", + attributes: + [ + builder => BuildBoundAttributeDescriptorFromPropertyInfo(builder, "type", inputTypePropertyInfo), + ], + ruleBuilders: + [ + builder => builder.RequireTagStructure(TagStructure.WithoutEndTag) + ]), + CreateTagHelperDescriptor( + tagName: "input", + typeName: "TestNamespace.InputTagHelper2", + assemblyName: "TestAssembly", + attributes: + [ + builder => BuildBoundAttributeDescriptorFromPropertyInfo(builder, "type", inputTypePropertyInfo), + builder => BuildBoundAttributeDescriptorFromPropertyInfo(builder, "checked", checkedPropertyInfo), + ]), + ]; } } @@ -569,8 +571,8 @@ private static TagHelperDescriptor CreateTagHelperDescriptor( string tagName, string typeName, string assemblyName, - IEnumerable> attributes = null, - IEnumerable> ruleBuilders = null) + IEnumerable>? attributes = null, + IEnumerable>? ruleBuilders = null) { var builder = TagHelperDescriptorBuilder.CreateTagHelper(typeName, assemblyName); builder.SetTypeName(typeName, typeNamespace: null, typeNameIdentifier: null); @@ -604,6 +606,14 @@ private static TagHelperDescriptor CreateTagHelperDescriptor( return descriptor; } + private static PropertyInfo GetTestTypeRuntimeProperty(string name) + { + var result = typeof(TestType).GetRuntimeProperty(name); + Assert.NotNull(result); + + return result; + } + private static void BuildBoundAttributeDescriptorFromPropertyInfo( BoundAttributeDescriptorBuilder builder, string name, @@ -624,11 +634,11 @@ private class TestType { public int Age { get; set; } - public string Type { get; set; } + public string? Type { get; set; } public bool Checked { get; set; } - public string BoundProperty { get; set; } + public string? BoundProperty { get; set; } } public static readonly string Code = """ diff --git a/src/Compiler/Microsoft.AspNetCore.Razor.Language/test/Legacy/TagHelperBlockRewriterTest.cs b/src/Compiler/Microsoft.AspNetCore.Razor.Language/test/Legacy/TagHelperBlockRewriterTest.cs index 3bbcb7584ee..b1c2d8b7d0f 100644 --- a/src/Compiler/Microsoft.AspNetCore.Razor.Language/test/Legacy/TagHelperBlockRewriterTest.cs +++ b/src/Compiler/Microsoft.AspNetCore.Razor.Language/test/Legacy/TagHelperBlockRewriterTest.cs @@ -3,7 +3,6 @@ using System; using System.Collections.Generic; -using System.Collections.Immutable; using System.Globalization; using Microsoft.AspNetCore.Razor.Language.Components; using Roslyn.Test.Utilities; @@ -13,7 +12,7 @@ namespace Microsoft.AspNetCore.Razor.Language.Legacy; public class TagHelperBlockRewriterTest : TagHelperRewritingTestBase { - public static ImmutableArray SymbolBoundAttributes_Descriptors = + public static readonly TagHelperCollection SymbolBoundAttributes_TagHelpers = [ TagHelperDescriptorBuilder.CreateTagHelper("CatchAllTagHelper", "SomeAssembly") .TagMatchingRuleDescriptor(rule => rule @@ -49,46 +48,46 @@ public class TagHelperBlockRewriterTest : TagHelperRewritingTestBase [Fact] public void CanHandleSymbolBoundAttributes1() { - EvaluateData(SymbolBoundAttributes_Descriptors, "
    "); + EvaluateData(SymbolBoundAttributes_TagHelpers, "
      "); } [Fact] public void CanHandleSymbolBoundAttributes2() { - EvaluateData(SymbolBoundAttributes_Descriptors, "
        "); + EvaluateData(SymbolBoundAttributes_TagHelpers, "
          "); } [Fact] public void CanHandleSymbolBoundAttributes3() { - EvaluateData(SymbolBoundAttributes_Descriptors, ""); + EvaluateData(SymbolBoundAttributes_TagHelpers, ""); } [Fact] public void CanHandleSymbolBoundAttributes4() { - EvaluateData(SymbolBoundAttributes_Descriptors, ""); + EvaluateData(SymbolBoundAttributes_TagHelpers, ""); } [Fact] public void CanHandleSymbolBoundAttributes5() { - EvaluateData(SymbolBoundAttributes_Descriptors, ""); + EvaluateData(SymbolBoundAttributes_TagHelpers, ""); } [Fact] public void CanHandleSymbolBoundAttributes6() { - EvaluateData(SymbolBoundAttributes_Descriptors, "
          "); + EvaluateData(SymbolBoundAttributes_TagHelpers, "
          "); } [Fact] public void CanHandleSymbolBoundAttributes7() { - EvaluateData(SymbolBoundAttributes_Descriptors, "
          "); + EvaluateData(SymbolBoundAttributes_TagHelpers, "
          "); } - public static ImmutableArray WithoutEndTag_Descriptors = + public static readonly TagHelperCollection WithoutEndTag_TagHelpers = [ TagHelperDescriptorBuilder.CreateTagHelper("InputTagHelper", "SomeAssembly") .TagMatchingRuleDescriptor(rule => rule @@ -100,34 +99,34 @@ public void CanHandleSymbolBoundAttributes7() [Fact] public void CanHandleWithoutEndTagTagStructure1() { - EvaluateData(WithoutEndTag_Descriptors, ""); + EvaluateData(WithoutEndTag_TagHelpers, ""); } [Fact] public void CanHandleWithoutEndTagTagStructure2() { - EvaluateData(WithoutEndTag_Descriptors, ""); + EvaluateData(WithoutEndTag_TagHelpers, ""); } [Fact] public void CanHandleWithoutEndTagTagStructure3() { - EvaluateData(WithoutEndTag_Descriptors, ""); + EvaluateData(WithoutEndTag_TagHelpers, ""); } [Fact] public void CanHandleWithoutEndTagTagStructure4() { - EvaluateData(WithoutEndTag_Descriptors, ""); + EvaluateData(WithoutEndTag_TagHelpers, ""); } [Fact] public void CanHandleWithoutEndTagTagStructure5() { - EvaluateData(WithoutEndTag_Descriptors, "
          "); + EvaluateData(WithoutEndTag_TagHelpers, "
          "); } - public static ImmutableArray GetTagStructureCompatibilityDescriptors(TagStructure structure1, TagStructure structure2) + public static TagHelperCollection GetTagStructureCompatibilityTagHelpers(TagStructure structure1, TagStructure structure2) { return [ @@ -148,7 +147,7 @@ public static ImmutableArray GetTagStructureCompatibilityDe public void AllowsCompatibleTagStructures1() { // Arrange - var descriptors = GetTagStructureCompatibilityDescriptors(TagStructure.Unspecified, TagStructure.Unspecified); + var descriptors = GetTagStructureCompatibilityTagHelpers(TagStructure.Unspecified, TagStructure.Unspecified); // Act & Assert EvaluateData(descriptors, ""); @@ -158,7 +157,7 @@ public void AllowsCompatibleTagStructures1() public void AllowsCompatibleTagStructures2() { // Arrange - var descriptors = GetTagStructureCompatibilityDescriptors(TagStructure.Unspecified, TagStructure.Unspecified); + var descriptors = GetTagStructureCompatibilityTagHelpers(TagStructure.Unspecified, TagStructure.Unspecified); // Act & Assert EvaluateData(descriptors, ""); @@ -168,7 +167,7 @@ public void AllowsCompatibleTagStructures2() public void AllowsCompatibleTagStructures3() { // Arrange - var descriptors = GetTagStructureCompatibilityDescriptors(TagStructure.Unspecified, TagStructure.WithoutEndTag); + var descriptors = GetTagStructureCompatibilityTagHelpers(TagStructure.Unspecified, TagStructure.WithoutEndTag); // Act & Assert EvaluateData(descriptors, ""); @@ -178,7 +177,7 @@ public void AllowsCompatibleTagStructures3() public void AllowsCompatibleTagStructures4() { // Arrange - var descriptors = GetTagStructureCompatibilityDescriptors(TagStructure.WithoutEndTag, TagStructure.WithoutEndTag); + var descriptors = GetTagStructureCompatibilityTagHelpers(TagStructure.WithoutEndTag, TagStructure.WithoutEndTag); // Act & Assert EvaluateData(descriptors, ""); @@ -188,7 +187,7 @@ public void AllowsCompatibleTagStructures4() public void AllowsCompatibleTagStructures5() { // Arrange - var descriptors = GetTagStructureCompatibilityDescriptors(TagStructure.Unspecified, TagStructure.NormalOrSelfClosing); + var descriptors = GetTagStructureCompatibilityTagHelpers(TagStructure.Unspecified, TagStructure.NormalOrSelfClosing); // Act & Assert EvaluateData(descriptors, ""); @@ -198,7 +197,7 @@ public void AllowsCompatibleTagStructures5() public void AllowsCompatibleTagStructures6() { // Arrange - var descriptors = GetTagStructureCompatibilityDescriptors(TagStructure.Unspecified, TagStructure.WithoutEndTag); + var descriptors = GetTagStructureCompatibilityTagHelpers(TagStructure.Unspecified, TagStructure.WithoutEndTag); // Act & Assert EvaluateData(descriptors, ""); @@ -208,7 +207,7 @@ public void AllowsCompatibleTagStructures6() public void AllowsCompatibleTagStructures7() { // Arrange - var descriptors = GetTagStructureCompatibilityDescriptors(TagStructure.NormalOrSelfClosing, TagStructure.Unspecified); + var descriptors = GetTagStructureCompatibilityTagHelpers(TagStructure.NormalOrSelfClosing, TagStructure.Unspecified); // Act & Assert EvaluateData(descriptors, ""); @@ -218,7 +217,7 @@ public void AllowsCompatibleTagStructures7() public void AllowsCompatibleTagStructures8() { // Arrange - var descriptors = GetTagStructureCompatibilityDescriptors(TagStructure.WithoutEndTag, TagStructure.Unspecified); + var descriptors = GetTagStructureCompatibilityTagHelpers(TagStructure.WithoutEndTag, TagStructure.Unspecified); // Act & Assert EvaluateData(descriptors, ""); @@ -228,7 +227,7 @@ public void AllowsCompatibleTagStructures8() public void AllowsCompatibleTagStructures_DirectiveAttribute_SelfClosing() { // Arrange - ImmutableArray descriptors = + TagHelperCollection descriptors = [ TagHelperDescriptorBuilder.CreateEventHandler("InputTagHelper1", "SomeAssembly") .TagMatchingRuleDescriptor(rule => rule @@ -247,7 +246,7 @@ public void AllowsCompatibleTagStructures_DirectiveAttribute_SelfClosing() public void AllowsCompatibleTagStructures_DirectiveAttribute_Void() { // Arrange - ImmutableArray descriptors = + TagHelperCollection descriptors = [ TagHelperDescriptorBuilder.CreateEventHandler("InputTagHelper1", "SomeAssembly") .TagMatchingRuleDescriptor(rule => rule @@ -430,7 +429,7 @@ public void CreatesErrorForMalformedTagHelper8() RunParseTreeRewriterTest("

          ", "strong", "p"); } - public static ImmutableArray CodeTagHelperAttributes_Descriptors = + public static TagHelperCollection CodeTagHelperAttributes_TagHelpers = [ TagHelperDescriptorBuilder.CreateTagHelper("PersonTagHelper", "personAssembly") .TagMatchingRuleDescriptor(rule => rule.RequireTagName("person")) @@ -460,85 +459,85 @@ public void CreatesErrorForMalformedTagHelper8() [Fact] public void UnderstandsMultipartNonStringTagHelperAttributes() { - EvaluateData(CodeTagHelperAttributes_Descriptors, " 123)()\" />"); + EvaluateData(CodeTagHelperAttributes_TagHelpers, " 123)()\" />"); } [Fact] public void CreatesMarkupCodeSpansForNonStringTagHelperAttributes1() { - EvaluateData(CodeTagHelperAttributes_Descriptors, ""); + EvaluateData(CodeTagHelperAttributes_TagHelpers, ""); } [Fact] public void CreatesMarkupCodeSpansForNonStringTagHelperAttributes2() { - EvaluateData(CodeTagHelperAttributes_Descriptors, ""); + EvaluateData(CodeTagHelperAttributes_TagHelpers, ""); } [Fact] public void CreatesMarkupCodeSpansForNonStringTagHelperAttributes3() { - EvaluateData(CodeTagHelperAttributes_Descriptors, ""); + EvaluateData(CodeTagHelperAttributes_TagHelpers, ""); } [Fact] public void CreatesMarkupCodeSpansForNonStringTagHelperAttributes4() { - EvaluateData(CodeTagHelperAttributes_Descriptors, ""); + EvaluateData(CodeTagHelperAttributes_TagHelpers, ""); } [Fact] public void CreatesMarkupCodeSpansForNonStringTagHelperAttributes5() { - EvaluateData(CodeTagHelperAttributes_Descriptors, ""); + EvaluateData(CodeTagHelperAttributes_TagHelpers, ""); } [Fact] public void CreatesMarkupCodeSpansForNonStringTagHelperAttributes6() { - EvaluateData(CodeTagHelperAttributes_Descriptors, ""); + EvaluateData(CodeTagHelperAttributes_TagHelpers, ""); } [Fact] public void CreatesMarkupCodeSpansForNonStringTagHelperAttributes7() { - EvaluateData(CodeTagHelperAttributes_Descriptors, ""); + EvaluateData(CodeTagHelperAttributes_TagHelpers, ""); } [Fact] public void CreatesMarkupCodeSpansForNonStringTagHelperAttributes8() { - EvaluateData(CodeTagHelperAttributes_Descriptors, ""); + EvaluateData(CodeTagHelperAttributes_TagHelpers, ""); } [Fact] public void CreatesMarkupCodeSpansForNonStringTagHelperAttributes9() { - EvaluateData(CodeTagHelperAttributes_Descriptors, ""); + EvaluateData(CodeTagHelperAttributes_TagHelpers, ""); } [Fact] public void CreatesMarkupCodeSpansForNonStringTagHelperAttributes10() { - EvaluateData(CodeTagHelperAttributes_Descriptors, ""); + EvaluateData(CodeTagHelperAttributes_TagHelpers, ""); } [Fact] public void CreatesMarkupCodeSpansForNonStringTagHelperAttributes11() { - EvaluateData(CodeTagHelperAttributes_Descriptors, ""); + EvaluateData(CodeTagHelperAttributes_TagHelpers, ""); } [Fact] public void CreatesMarkupCodeSpansForNonStringTagHelperAttributes12() { - EvaluateData(CodeTagHelperAttributes_Descriptors, ""); + EvaluateData(CodeTagHelperAttributes_TagHelpers, ""); } [Fact, WorkItem("https://github.com/dotnet/razor/issues/10186")] public void CreatesMarkupCodeSpansForNonStringTagHelperAttributes13() { - EvaluateData(CodeTagHelperAttributes_Descriptors, """ + EvaluateData(CodeTagHelperAttributes_TagHelpers, """ @{ var count = "1"; } @@ -549,7 +548,7 @@ public void CreatesMarkupCodeSpansForNonStringTagHelperAttributes13() [Fact, WorkItem("https://github.com/dotnet/razor/issues/10186")] public void CreatesMarkupCodeSpansForNonStringTagHelperAttributes14() { - EvaluateData(CodeTagHelperAttributes_Descriptors, """ + EvaluateData(CodeTagHelperAttributes_TagHelpers, """ @{ var @string = "1"; } @@ -560,7 +559,7 @@ public void CreatesMarkupCodeSpansForNonStringTagHelperAttributes14() [Fact, WorkItem("https://github.com/dotnet/razor/issues/10186")] public void CreatesMarkupCodeSpansForNonStringTagHelperAttributes15() { - EvaluateData(CodeTagHelperAttributes_Descriptors, """ + EvaluateData(CodeTagHelperAttributes_TagHelpers, """ @{ var count = "1"; } @@ -571,7 +570,7 @@ public void CreatesMarkupCodeSpansForNonStringTagHelperAttributes15() [Fact, WorkItem("https://github.com/dotnet/razor/issues/10186")] public void CreatesMarkupCodeSpansForNonStringTagHelperAttributes16() { - EvaluateData(CodeTagHelperAttributes_Descriptors, """ + EvaluateData(CodeTagHelperAttributes_TagHelpers, """ @{ var count = "1"; } @@ -582,7 +581,7 @@ public void CreatesMarkupCodeSpansForNonStringTagHelperAttributes16() [Fact, WorkItem("https://github.com/dotnet/razor/issues/10186")] public void CreatesMarkupCodeSpansForNonStringTagHelperAttributes17() { - EvaluateData(CodeTagHelperAttributes_Descriptors, """ + EvaluateData(CodeTagHelperAttributes_TagHelpers, """ @{ var count = 1; } @@ -593,7 +592,7 @@ public void CreatesMarkupCodeSpansForNonStringTagHelperAttributes17() [Fact, WorkItem("https://github.com/dotnet/razor/issues/10186")] public void CreatesMarkupCodeSpansForNonStringTagHelperAttributes18() { - EvaluateData(CodeTagHelperAttributes_Descriptors, """ + EvaluateData(CodeTagHelperAttributes_TagHelpers, """ @{ var count = 1; } @@ -604,7 +603,7 @@ public void CreatesMarkupCodeSpansForNonStringTagHelperAttributes18() [Fact, WorkItem("https://github.com/dotnet/razor/issues/10186")] public void CreatesMarkupCodeSpansForNonStringTagHelperAttributes19() { - EvaluateData(CodeTagHelperAttributes_Descriptors, """ + EvaluateData(CodeTagHelperAttributes_TagHelpers, """ @{ var count = 1; } @@ -615,7 +614,7 @@ public void CreatesMarkupCodeSpansForNonStringTagHelperAttributes19() [Fact, WorkItem("https://github.com/dotnet/razor/issues/10186")] public void CreatesMarkupCodeSpansForNonStringTagHelperAttributes20() { - EvaluateData(CodeTagHelperAttributes_Descriptors, """ + EvaluateData(CodeTagHelperAttributes_TagHelpers, """ @{ var isAlive = true; } @@ -626,7 +625,7 @@ public void CreatesMarkupCodeSpansForNonStringTagHelperAttributes20() [Fact, WorkItem("https://github.com/dotnet/razor/issues/10186")] public void CreatesMarkupCodeSpansForNonStringTagHelperAttributes21() { - EvaluateData(CodeTagHelperAttributes_Descriptors, """ + EvaluateData(CodeTagHelperAttributes_TagHelpers, """ @{ var obj = new { Prop = (object)1 }; } @@ -637,7 +636,7 @@ public void CreatesMarkupCodeSpansForNonStringTagHelperAttributes21() [Fact, WorkItem("https://github.com/dotnet/razor/issues/10186")] public void CreatesMarkupCodeSpansForNonStringTagHelperAttributes22() { - EvaluateData(CodeTagHelperAttributes_Descriptors, """ + EvaluateData(CodeTagHelperAttributes_TagHelpers, """ @{ var obj = new { Prop = (object)1 }; } @@ -668,7 +667,7 @@ public void CreatesMarkupCodeSpansForNonStringTagHelperAttributes23() [Fact, WorkItem("https://github.com/dotnet/razor/issues/10426")] public void CreatesMarkupCodeSpans_EscapedExpression_01() { - EvaluateData(CodeTagHelperAttributes_Descriptors, """ + EvaluateData(CodeTagHelperAttributes_TagHelpers, """ """); } @@ -676,7 +675,7 @@ public void CreatesMarkupCodeSpans_EscapedExpression_01() [Fact, WorkItem("https://github.com/dotnet/razor/issues/10426")] public void CreatesMarkupCodeSpans_EscapedExpression_02() { - EvaluateData(CodeTagHelperAttributes_Descriptors, """ + EvaluateData(CodeTagHelperAttributes_TagHelpers, """ """); } @@ -684,7 +683,7 @@ public void CreatesMarkupCodeSpans_EscapedExpression_02() [Fact, WorkItem("https://github.com/dotnet/razor/issues/10426")] public void CreatesMarkupCodeSpans_EscapedExpression_03() { - EvaluateData(CodeTagHelperAttributes_Descriptors, """ + EvaluateData(CodeTagHelperAttributes_TagHelpers, """ """); } @@ -692,7 +691,7 @@ public void CreatesMarkupCodeSpans_EscapedExpression_03() [Fact, WorkItem("https://github.com/dotnet/razor/issues/10426")] public void CreatesMarkupCodeSpans_EscapedExpression_04() { - EvaluateData(CodeTagHelperAttributes_Descriptors, """ + EvaluateData(CodeTagHelperAttributes_TagHelpers, """ """); } @@ -700,7 +699,7 @@ public void CreatesMarkupCodeSpans_EscapedExpression_04() [Fact, WorkItem("https://github.com/dotnet/razor/issues/10426")] public void CreatesMarkupCodeSpans_EscapedExpression_05() { - EvaluateData(CodeTagHelperAttributes_Descriptors, """ + EvaluateData(CodeTagHelperAttributes_TagHelpers, """ """); } @@ -708,7 +707,7 @@ public void CreatesMarkupCodeSpans_EscapedExpression_05() [Fact, WorkItem("https://github.com/dotnet/razor/issues/10426")] public void CreatesMarkupCodeSpans_EscapedExpression_06() { - EvaluateData(CodeTagHelperAttributes_Descriptors, """ + EvaluateData(CodeTagHelperAttributes_TagHelpers, """ """); } @@ -716,7 +715,7 @@ public void CreatesMarkupCodeSpans_EscapedExpression_06() [Fact, WorkItem("https://github.com/dotnet/razor/issues/10426")] public void CreatesMarkupCodeSpans_EscapedExpression_07() { - EvaluateData(CodeTagHelperAttributes_Descriptors, """ + EvaluateData(CodeTagHelperAttributes_TagHelpers, """ """); } @@ -724,7 +723,7 @@ public void CreatesMarkupCodeSpans_EscapedExpression_07() [Fact, WorkItem("https://github.com/dotnet/razor/issues/10426")] public void CreatesMarkupCodeSpans_EscapedExpression_08() { - EvaluateData(CodeTagHelperAttributes_Descriptors, """ + EvaluateData(CodeTagHelperAttributes_TagHelpers, """ """); } @@ -732,7 +731,7 @@ public void CreatesMarkupCodeSpans_EscapedExpression_08() [Fact, WorkItem("https://github.com/dotnet/razor/issues/10426")] public void CreatesMarkupCodeSpans_EscapedExpression_09() { - EvaluateData(CodeTagHelperAttributes_Descriptors, """ + EvaluateData(CodeTagHelperAttributes_TagHelpers, """ """); } @@ -740,7 +739,7 @@ public void CreatesMarkupCodeSpans_EscapedExpression_09() [Fact, WorkItem("https://github.com/dotnet/razor/issues/10426")] public void CreatesMarkupCodeSpans_EscapedExpression_10() { - EvaluateData(CodeTagHelperAttributes_Descriptors, """ + EvaluateData(CodeTagHelperAttributes_TagHelpers, """ """); } @@ -1057,7 +1056,7 @@ public void UnderstandsEmptyAttributeTagHelpers5() RunParseTreeRewriterTest("

          ", "p"); } - public static ImmutableArray EmptyTagHelperBoundAttribute_Descriptors = + public static TagHelperCollection EmptyTagHelperBoundAttribute_TagHelpers = [ TagHelperDescriptorBuilder.CreateTagHelper("mythTagHelper", "SomeAssembly") .TagMatchingRuleDescriptor(rule => rule.RequireTagName("myth")) @@ -1075,85 +1074,85 @@ public void UnderstandsEmptyAttributeTagHelpers5() [Fact] public void CreatesErrorForEmptyTagHelperBoundAttributes1() { - EvaluateData(EmptyTagHelperBoundAttribute_Descriptors, ""); + EvaluateData(EmptyTagHelperBoundAttribute_TagHelpers, ""); } [Fact] public void CreatesErrorForEmptyTagHelperBoundAttributes2() { - EvaluateData(EmptyTagHelperBoundAttribute_Descriptors, ""); + EvaluateData(EmptyTagHelperBoundAttribute_TagHelpers, ""); } [Fact] public void CreatesErrorForEmptyTagHelperBoundAttributes3() { - EvaluateData(EmptyTagHelperBoundAttribute_Descriptors, ""); + EvaluateData(EmptyTagHelperBoundAttribute_TagHelpers, ""); } [Fact] public void CreatesErrorForEmptyTagHelperBoundAttributes4() { - EvaluateData(EmptyTagHelperBoundAttribute_Descriptors, ""); + EvaluateData(EmptyTagHelperBoundAttribute_TagHelpers, ""); } [Fact] public void CreatesErrorForEmptyTagHelperBoundAttributes5() { - EvaluateData(EmptyTagHelperBoundAttribute_Descriptors, ""); + EvaluateData(EmptyTagHelperBoundAttribute_TagHelpers, ""); } [Fact] public void CreatesErrorForEmptyTagHelperBoundAttributes6() { - EvaluateData(EmptyTagHelperBoundAttribute_Descriptors, ""); + EvaluateData(EmptyTagHelperBoundAttribute_TagHelpers, ""); } [Fact] public void CreatesErrorForEmptyTagHelperBoundAttributes7() { - EvaluateData(EmptyTagHelperBoundAttribute_Descriptors, ""); + EvaluateData(EmptyTagHelperBoundAttribute_TagHelpers, ""); } [Fact] public void CreatesErrorForEmptyTagHelperBoundAttributes8() { - EvaluateData(EmptyTagHelperBoundAttribute_Descriptors, ""); + EvaluateData(EmptyTagHelperBoundAttribute_TagHelpers, ""); } [Fact] public void CreatesErrorForEmptyTagHelperBoundAttributes9() { - EvaluateData(EmptyTagHelperBoundAttribute_Descriptors, ""); + EvaluateData(EmptyTagHelperBoundAttribute_TagHelpers, ""); } [Fact] public void CreatesErrorForEmptyTagHelperBoundAttributes10() { - EvaluateData(EmptyTagHelperBoundAttribute_Descriptors, ""); + EvaluateData(EmptyTagHelperBoundAttribute_TagHelpers, ""); } [Fact] public void CreatesErrorForEmptyTagHelperBoundAttributes11() { - EvaluateData(EmptyTagHelperBoundAttribute_Descriptors, ""); + EvaluateData(EmptyTagHelperBoundAttribute_TagHelpers, ""); } [Fact] public void CreatesErrorForEmptyTagHelperBoundAttributes12() { - EvaluateData(EmptyTagHelperBoundAttribute_Descriptors, ""); + EvaluateData(EmptyTagHelperBoundAttribute_TagHelpers, ""); } [Fact] public void CreatesErrorForEmptyTagHelperBoundAttributes13() { - EvaluateData(EmptyTagHelperBoundAttribute_Descriptors, ""); + EvaluateData(EmptyTagHelperBoundAttribute_TagHelpers, ""); } [Fact] public void CreatesErrorForEmptyTagHelperBoundAttributes14() { - EvaluateData(EmptyTagHelperBoundAttribute_Descriptors, ""); + EvaluateData(EmptyTagHelperBoundAttribute_TagHelpers, ""); } [Fact] @@ -1469,7 +1468,7 @@ public void GeneratesExpectedOutputForUnboundDataDashAttributes_Block7() RunParseTreeRewriterTest(document, "input"); } - public static ImmutableArray MinimizedAttribute_Descriptors = + public static TagHelperCollection MinimizedAttribute_TagHelpers = [ TagHelperDescriptorBuilder.CreateTagHelper("InputTagHelper1", "SomeAssembly") .TagMatchingRuleDescriptor(rule => rule @@ -1525,7 +1524,7 @@ public void UnderstandsMinimizedAttributes_Document1() var document = ""; // Act & Assert - EvaluateData(MinimizedAttribute_Descriptors, document); + EvaluateData(MinimizedAttribute_TagHelpers, document); } [Fact] @@ -1535,7 +1534,7 @@ public void UnderstandsMinimizedAttributes_Document2() var document = "

          "; // Act & Assert - EvaluateData(MinimizedAttribute_Descriptors, document); + EvaluateData(MinimizedAttribute_TagHelpers, document); } [Fact] @@ -1545,7 +1544,7 @@ public void UnderstandsMinimizedAttributes_Document3() var document = ""; // Act & Assert - EvaluateData(MinimizedAttribute_Descriptors, document); + EvaluateData(MinimizedAttribute_TagHelpers, document); } [Fact] @@ -1555,7 +1554,7 @@ public void UnderstandsMinimizedAttributes_Document4() var document = ""; // Act & Assert - EvaluateData(MinimizedAttribute_Descriptors, document); + EvaluateData(MinimizedAttribute_TagHelpers, document); } [Fact] @@ -1565,7 +1564,7 @@ public void UnderstandsMinimizedAttributes_Document5() var document = "

          "; // Act & Assert - EvaluateData(MinimizedAttribute_Descriptors, document); + EvaluateData(MinimizedAttribute_TagHelpers, document); } [Fact] @@ -1575,7 +1574,7 @@ public void UnderstandsMinimizedAttributes_Document6() var document = ""; // Act & Assert - EvaluateData(MinimizedAttribute_Descriptors, document); + EvaluateData(MinimizedAttribute_TagHelpers, document); } [Fact] @@ -1585,7 +1584,7 @@ public void UnderstandsMinimizedAttributes_Document7() var document = ""; // Act & Assert - EvaluateData(MinimizedAttribute_Descriptors, document); + EvaluateData(MinimizedAttribute_TagHelpers, document); } [Fact] @@ -1595,7 +1594,7 @@ public void UnderstandsMinimizedAttributes_Document8() var document = ""; // Act & Assert - EvaluateData(MinimizedAttribute_Descriptors, document); + EvaluateData(MinimizedAttribute_TagHelpers, document); } [Fact] @@ -1605,7 +1604,7 @@ public void UnderstandsMinimizedAttributes_Document9() var document = ""; // Act & Assert - EvaluateData(MinimizedAttribute_Descriptors, document); + EvaluateData(MinimizedAttribute_TagHelpers, document); } [Fact] @@ -1615,7 +1614,7 @@ public void UnderstandsMinimizedAttributes_Document10() var document = ""; // Act & Assert - EvaluateData(MinimizedAttribute_Descriptors, document); + EvaluateData(MinimizedAttribute_TagHelpers, document); } [Fact] @@ -1625,7 +1624,7 @@ public void UnderstandsMinimizedAttributes_Document11() var document = ""; // Act & Assert - EvaluateData(MinimizedAttribute_Descriptors, document); + EvaluateData(MinimizedAttribute_TagHelpers, document); } [Fact] @@ -1635,7 +1634,7 @@ public void UnderstandsMinimizedAttributes_Document12() var document = ""; // Act & Assert - EvaluateData(MinimizedAttribute_Descriptors, document); + EvaluateData(MinimizedAttribute_TagHelpers, document); } [Fact] @@ -1645,7 +1644,7 @@ public void UnderstandsMinimizedAttributes_Document13() var document = ""; // Act & Assert - EvaluateData(MinimizedAttribute_Descriptors, document); + EvaluateData(MinimizedAttribute_TagHelpers, document); } [Fact] @@ -1655,7 +1654,7 @@ public void UnderstandsMinimizedAttributes_Document14() var document = ""; // Act & Assert - EvaluateData(MinimizedAttribute_Descriptors, document); + EvaluateData(MinimizedAttribute_TagHelpers, document); } [Fact] @@ -1665,7 +1664,7 @@ public void UnderstandsMinimizedAttributes_Document15() var document = ""; // Act & Assert - EvaluateData(MinimizedAttribute_Descriptors, document); + EvaluateData(MinimizedAttribute_TagHelpers, document); } [Fact] @@ -1675,7 +1674,7 @@ public void UnderstandsMinimizedAttributes_Document16() var document = ""; // Act & Assert - EvaluateData(MinimizedAttribute_Descriptors, document); + EvaluateData(MinimizedAttribute_TagHelpers, document); } [Fact] @@ -1685,7 +1684,7 @@ public void UnderstandsMinimizedAttributes_Document17() var document = "

          "; // Act & Assert - EvaluateData(MinimizedAttribute_Descriptors, document); + EvaluateData(MinimizedAttribute_TagHelpers, document); } [Fact] @@ -1695,7 +1694,7 @@ public void UnderstandsMinimizedAttributes_Document18() var document = ""; // Act & Assert - EvaluateData(MinimizedAttribute_Descriptors, document); + EvaluateData(MinimizedAttribute_TagHelpers, document); } [Fact] @@ -1705,7 +1704,7 @@ public void UnderstandsMinimizedAttributes_Document19() var document = "

          "; // Act & Assert - EvaluateData(MinimizedAttribute_Descriptors, document); + EvaluateData(MinimizedAttribute_TagHelpers, document); } [Fact] @@ -1715,7 +1714,7 @@ public void UnderstandsMinimizedAttributes_Document20() var document = ""; // Act & Assert - EvaluateData(MinimizedAttribute_Descriptors, document); + EvaluateData(MinimizedAttribute_TagHelpers, document); } [Fact] @@ -1725,7 +1724,7 @@ public void UnderstandsMinimizedAttributes_Document21() var document = "

          "; // Act & Assert - EvaluateData(MinimizedAttribute_Descriptors, document); + EvaluateData(MinimizedAttribute_TagHelpers, document); } [Fact] @@ -1735,7 +1734,7 @@ public void UnderstandsMinimizedAttributes_Document22() var document = ""; // Act & Assert - EvaluateData(MinimizedAttribute_Descriptors, document); + EvaluateData(MinimizedAttribute_TagHelpers, document); } [Fact] @@ -1745,7 +1744,7 @@ public void UnderstandsMinimizedAttributes_Document23() var document = "

          "; // Act & Assert - EvaluateData(MinimizedAttribute_Descriptors, document); + EvaluateData(MinimizedAttribute_TagHelpers, document); } [Fact] @@ -1755,7 +1754,7 @@ public void UnderstandsMinimizedAttributes_Document24() var document = ""; // Act & Assert - EvaluateData(MinimizedAttribute_Descriptors, document); + EvaluateData(MinimizedAttribute_TagHelpers, document); } [Fact] @@ -1765,7 +1764,7 @@ public void UnderstandsMinimizedAttributes_Document25() var document = ""; // Act & Assert - EvaluateData(MinimizedAttribute_Descriptors, document); + EvaluateData(MinimizedAttribute_TagHelpers, document); } [Fact] @@ -1775,7 +1774,7 @@ public void UnderstandsMinimizedAttributes_Document26() var document = ""; // Act & Assert - EvaluateData(MinimizedAttribute_Descriptors, document); + EvaluateData(MinimizedAttribute_TagHelpers, document); } [Fact] @@ -1785,7 +1784,7 @@ public void UnderstandsMinimizedAttributes_Document27() var document = "

          "; // Act & Assert - EvaluateData(MinimizedAttribute_Descriptors, document); + EvaluateData(MinimizedAttribute_TagHelpers, document); } [Fact] @@ -1795,7 +1794,7 @@ public void UnderstandsMinimizedAttributes_Document28() var document = ""; // Act & Assert - EvaluateData(MinimizedAttribute_Descriptors, document); + EvaluateData(MinimizedAttribute_TagHelpers, document); } [Fact] @@ -1805,7 +1804,7 @@ public void UnderstandsMinimizedAttributes_Document29() var document = "

          "; // Act & Assert - EvaluateData(MinimizedAttribute_Descriptors, document); + EvaluateData(MinimizedAttribute_TagHelpers, document); } [Fact] @@ -1816,7 +1815,7 @@ public void UnderstandsMinimizedAttributes_Document30() var document = $""; // Act & Assert - EvaluateData(MinimizedAttribute_Descriptors, document); + EvaluateData(MinimizedAttribute_TagHelpers, document); } [Fact] @@ -1827,7 +1826,7 @@ public void UnderstandsMinimizedAttributes_Document31() var document = $"

          "; // Act & Assert - EvaluateData(MinimizedAttribute_Descriptors, document); + EvaluateData(MinimizedAttribute_TagHelpers, document); } [Fact] @@ -1838,7 +1837,7 @@ public void UnderstandsMinimizedAttributes_Document32() var document = $""; // Act & Assert - EvaluateData(MinimizedAttribute_Descriptors, document); + EvaluateData(MinimizedAttribute_TagHelpers, document); } [Fact] @@ -1849,7 +1848,7 @@ public void UnderstandsMinimizedAttributes_Document33() var document = $"

          "; // Act & Assert - EvaluateData(MinimizedAttribute_Descriptors, document); + EvaluateData(MinimizedAttribute_TagHelpers, document); } [Fact] @@ -1862,7 +1861,7 @@ public void UnderstandsMinimizedAttributes_Block1() document = $"@{{{document}}}"; // Act & Assert - EvaluateData(MinimizedAttribute_Descriptors, document); + EvaluateData(MinimizedAttribute_TagHelpers, document); } [Fact] @@ -1875,7 +1874,7 @@ public void UnderstandsMinimizedAttributes_Block2() document = $"@{{{document}}}"; // Act & Assert - EvaluateData(MinimizedAttribute_Descriptors, document); + EvaluateData(MinimizedAttribute_TagHelpers, document); } [Fact] @@ -1888,7 +1887,7 @@ public void UnderstandsMinimizedAttributes_Block3() document = $"@{{{document}}}"; // Act & Assert - EvaluateData(MinimizedAttribute_Descriptors, document); + EvaluateData(MinimizedAttribute_TagHelpers, document); } [Fact] @@ -1901,7 +1900,7 @@ public void UnderstandsMinimizedAttributes_Block4() document = $"@{{{document}}}"; // Act & Assert - EvaluateData(MinimizedAttribute_Descriptors, document); + EvaluateData(MinimizedAttribute_TagHelpers, document); } [Fact] @@ -1914,7 +1913,7 @@ public void UnderstandsMinimizedAttributes_Block5() document = $"@{{{document}}}"; // Act & Assert - EvaluateData(MinimizedAttribute_Descriptors, document); + EvaluateData(MinimizedAttribute_TagHelpers, document); } [Fact] @@ -1927,7 +1926,7 @@ public void UnderstandsMinimizedAttributes_Block6() document = $"@{{{document}}}"; // Act & Assert - EvaluateData(MinimizedAttribute_Descriptors, document); + EvaluateData(MinimizedAttribute_TagHelpers, document); } [Fact] @@ -1940,7 +1939,7 @@ public void UnderstandsMinimizedAttributes_Block7() document = $"@{{{document}}}"; // Act & Assert - EvaluateData(MinimizedAttribute_Descriptors, document); + EvaluateData(MinimizedAttribute_TagHelpers, document); } [Fact] @@ -1953,7 +1952,7 @@ public void UnderstandsMinimizedAttributes_Block8() document = $"@{{{document}}}"; // Act & Assert - EvaluateData(MinimizedAttribute_Descriptors, document); + EvaluateData(MinimizedAttribute_TagHelpers, document); } [Fact] @@ -1966,7 +1965,7 @@ public void UnderstandsMinimizedAttributes_Block9() document = $"@{{{document}}}"; // Act & Assert - EvaluateData(MinimizedAttribute_Descriptors, document); + EvaluateData(MinimizedAttribute_TagHelpers, document); } [Fact] @@ -1979,7 +1978,7 @@ public void UnderstandsMinimizedAttributes_Block10() document = $"@{{{document}}}"; // Act & Assert - EvaluateData(MinimizedAttribute_Descriptors, document); + EvaluateData(MinimizedAttribute_TagHelpers, document); } [Fact] @@ -1992,7 +1991,7 @@ public void UnderstandsMinimizedAttributes_Block11() document = $"@{{{document}}}"; // Act & Assert - EvaluateData(MinimizedAttribute_Descriptors, document); + EvaluateData(MinimizedAttribute_TagHelpers, document); } [Fact] @@ -2005,7 +2004,7 @@ public void UnderstandsMinimizedAttributes_Block12() document = $"@{{{document}}}"; // Act & Assert - EvaluateData(MinimizedAttribute_Descriptors, document); + EvaluateData(MinimizedAttribute_TagHelpers, document); } [Fact] @@ -2018,7 +2017,7 @@ public void UnderstandsMinimizedAttributes_Block13() document = $"@{{{document}}}"; // Act & Assert - EvaluateData(MinimizedAttribute_Descriptors, document); + EvaluateData(MinimizedAttribute_TagHelpers, document); } [Fact] @@ -2031,7 +2030,7 @@ public void UnderstandsMinimizedAttributes_Block14() document = $"@{{{document}}}"; // Act & Assert - EvaluateData(MinimizedAttribute_Descriptors, document); + EvaluateData(MinimizedAttribute_TagHelpers, document); } [Fact] @@ -2044,7 +2043,7 @@ public void UnderstandsMinimizedAttributes_Block15() document = $"@{{{document}}}"; // Act & Assert - EvaluateData(MinimizedAttribute_Descriptors, document); + EvaluateData(MinimizedAttribute_TagHelpers, document); } [Fact] @@ -2057,7 +2056,7 @@ public void UnderstandsMinimizedAttributes_Block16() document = $"@{{{document}}}"; // Act & Assert - EvaluateData(MinimizedAttribute_Descriptors, document); + EvaluateData(MinimizedAttribute_TagHelpers, document); } [Fact] @@ -2070,7 +2069,7 @@ public void UnderstandsMinimizedAttributes_Block17() document = $"@{{{document}}}"; // Act & Assert - EvaluateData(MinimizedAttribute_Descriptors, document); + EvaluateData(MinimizedAttribute_TagHelpers, document); } [Fact] @@ -2083,7 +2082,7 @@ public void UnderstandsMinimizedAttributes_Block18() document = $"@{{{document}}}"; // Act & Assert - EvaluateData(MinimizedAttribute_Descriptors, document); + EvaluateData(MinimizedAttribute_TagHelpers, document); } [Fact] @@ -2096,7 +2095,7 @@ public void UnderstandsMinimizedAttributes_Block19() document = $"@{{{document}}}"; // Act & Assert - EvaluateData(MinimizedAttribute_Descriptors, document); + EvaluateData(MinimizedAttribute_TagHelpers, document); } [Fact] @@ -2109,7 +2108,7 @@ public void UnderstandsMinimizedAttributes_Block20() document = $"@{{{document}}}"; // Act & Assert - EvaluateData(MinimizedAttribute_Descriptors, document); + EvaluateData(MinimizedAttribute_TagHelpers, document); } [Fact] @@ -2122,7 +2121,7 @@ public void UnderstandsMinimizedAttributes_Block21() document = $"@{{{document}}}"; // Act & Assert - EvaluateData(MinimizedAttribute_Descriptors, document); + EvaluateData(MinimizedAttribute_TagHelpers, document); } [Fact] @@ -2135,7 +2134,7 @@ public void UnderstandsMinimizedAttributes_Block22() document = $"@{{{document}}}"; // Act & Assert - EvaluateData(MinimizedAttribute_Descriptors, document); + EvaluateData(MinimizedAttribute_TagHelpers, document); } [Fact] @@ -2148,7 +2147,7 @@ public void UnderstandsMinimizedAttributes_Block23() document = $"@{{{document}}}"; // Act & Assert - EvaluateData(MinimizedAttribute_Descriptors, document); + EvaluateData(MinimizedAttribute_TagHelpers, document); } [Fact] @@ -2161,7 +2160,7 @@ public void UnderstandsMinimizedAttributes_Block24() document = $"@{{{document}}}"; // Act & Assert - EvaluateData(MinimizedAttribute_Descriptors, document); + EvaluateData(MinimizedAttribute_TagHelpers, document); } [Fact] @@ -2174,7 +2173,7 @@ public void UnderstandsMinimizedAttributes_Block25() document = $"@{{{document}}}"; // Act & Assert - EvaluateData(MinimizedAttribute_Descriptors, document); + EvaluateData(MinimizedAttribute_TagHelpers, document); } [Fact] @@ -2187,7 +2186,7 @@ public void UnderstandsMinimizedAttributes_Block26() document = $"@{{{document}}}"; // Act & Assert - EvaluateData(MinimizedAttribute_Descriptors, document); + EvaluateData(MinimizedAttribute_TagHelpers, document); } [Fact] @@ -2200,7 +2199,7 @@ public void UnderstandsMinimizedAttributes_Block27() document = $"@{{{document}}}"; // Act & Assert - EvaluateData(MinimizedAttribute_Descriptors, document); + EvaluateData(MinimizedAttribute_TagHelpers, document); } [Fact] @@ -2213,7 +2212,7 @@ public void UnderstandsMinimizedAttributes_Block28() document = $"@{{{document}}}"; // Act & Assert - EvaluateData(MinimizedAttribute_Descriptors, document); + EvaluateData(MinimizedAttribute_TagHelpers, document); } [Fact] @@ -2226,7 +2225,7 @@ public void UnderstandsMinimizedAttributes_Block29() document = $"@{{{document}}}"; // Act & Assert - EvaluateData(MinimizedAttribute_Descriptors, document); + EvaluateData(MinimizedAttribute_TagHelpers, document); } [Fact] @@ -2240,7 +2239,7 @@ public void UnderstandsMinimizedAttributes_Block30() document = $"@{{{document}}}"; // Act & Assert - EvaluateData(MinimizedAttribute_Descriptors, document); + EvaluateData(MinimizedAttribute_TagHelpers, document); } [Fact] @@ -2254,7 +2253,7 @@ public void UnderstandsMinimizedAttributes_Block31() document = $"@{{{document}}}"; // Act & Assert - EvaluateData(MinimizedAttribute_Descriptors, document); + EvaluateData(MinimizedAttribute_TagHelpers, document); } [Fact] @@ -2268,7 +2267,7 @@ public void UnderstandsMinimizedAttributes_Block32() document = $"@{{{document}}}"; // Act & Assert - EvaluateData(MinimizedAttribute_Descriptors, document); + EvaluateData(MinimizedAttribute_TagHelpers, document); } [Fact] @@ -2282,55 +2281,55 @@ public void UnderstandsMinimizedAttributes_Block33() document = $"@{{{document}}}"; // Act & Assert - EvaluateData(MinimizedAttribute_Descriptors, document); + EvaluateData(MinimizedAttribute_TagHelpers, document); } [Fact] public void UnderstandsMinimizedAttributes_PartialTags1() { - EvaluateData(MinimizedAttribute_Descriptors, " descriptors = + TagHelperCollection descriptors = [ TagHelperDescriptorBuilder.CreateTagHelper("InputTagHelper", "SomeAssembly") .TagMatchingRuleDescriptor(rule => rule @@ -2364,7 +2363,7 @@ public void FeatureDisabled_AddsErrorForMinimizedBooleanBoundAttributes() { // Arrange var document = ""; - ImmutableArray descriptors = + TagHelperCollection descriptors = [ TagHelperDescriptorBuilder.CreateTagHelper("InputTagHelper", "SomeAssembly") .TagMatchingRuleDescriptor(rule => rule @@ -2390,7 +2389,7 @@ public void Rewrites_ComponentDirectiveAttributes() { // Arrange var document = @""; - ImmutableArray descriptors = + TagHelperCollection descriptors = [ TagHelperDescriptorBuilder.Create(TagHelperKind.Bind, "Bind", ComponentsApi.AssemblyName) .TypeName( @@ -2434,7 +2433,7 @@ public void Rewrites_MinimizedComponentDirectiveAttributes() { // Arrange var document = @""; - ImmutableArray descriptors = + TagHelperCollection descriptors = [ TagHelperDescriptorBuilder.Create(TagHelperKind.Bind, "Bind", ComponentsApi.AssemblyName) .TypeName( @@ -2477,7 +2476,8 @@ public void Rewrites_MinimizedComponentDirectiveAttributes() public void TagHelper_AttributeAfterRazorComment() { // Arrange - var descriptors = ImmutableArray.Create( + TagHelperCollection tagHelpers = + [ TagHelperDescriptorBuilder.CreateTagHelper("PTagHelper", "TestAssembly") .TagMatchingRuleDescriptor(rule => rule.RequireTagName("p")) .BoundAttributeDescriptor(attribute => attribute @@ -2488,10 +2488,11 @@ public void TagHelper_AttributeAfterRazorComment() .Name("not-visible") .PropertyName("NotVisible") .TypeName(typeof(bool).FullName)) - .Build()); + .Build() + ]; // Act & Assert - EvaluateData(descriptors, """ + EvaluateData(tagHelpers, """

          rule.RequireTagName("p")) .BoundAttributeDescriptor(attribute => attribute @@ -2519,10 +2521,11 @@ public void TagHelper_MultipleAttributesAfterRazorComment() .Name("attr-3") .PropertyName("Attr3") .TypeName(typeof(string).FullName)) - .Build()); + .Build() + ]; // Act & Assert - EvaluateData(descriptors, """ + EvaluateData(tagHelpers, """

          """); } @@ -2531,7 +2534,8 @@ public void TagHelper_MultipleAttributesAfterRazorComment() public void TagHelper_MultipleInterleavedRazorComments() { // Arrange - var descriptors = ImmutableArray.Create( + TagHelperCollection tagHelpers = + [ TagHelperDescriptorBuilder.CreateTagHelper("InputTagHelper", "TestAssembly") .TagMatchingRuleDescriptor(rule => rule.RequireTagName("input")) .BoundAttributeDescriptor(attribute => attribute @@ -2542,10 +2546,11 @@ public void TagHelper_MultipleInterleavedRazorComments() .Name("value") .PropertyName("Value") .TypeName(typeof(string).FullName)) - .Build()); + .Build() + ]; // Act & Assert - EvaluateData(descriptors, """ + EvaluateData(tagHelpers, """ """); } @@ -2554,7 +2559,8 @@ public void TagHelper_MultipleInterleavedRazorComments() public void TagHelper_MinimizedAttributeAfterRazorComment() { // Arrange - var descriptors = ImmutableArray.Create( + TagHelperCollection tagHelpers = + [ TagHelperDescriptorBuilder.CreateTagHelper("InputTagHelper", "TestAssembly") .TagMatchingRuleDescriptor(rule => rule.RequireTagName("input")) .BoundAttributeDescriptor(attribute => attribute @@ -2565,10 +2571,11 @@ public void TagHelper_MinimizedAttributeAfterRazorComment() .Name("checked") .PropertyName("Checked") .TypeName(typeof(bool).FullName)) - .Build()); + .Build() + ]; // Act & Assert - EvaluateData(descriptors, """ + EvaluateData(tagHelpers, """ """); } diff --git a/src/Compiler/Microsoft.AspNetCore.Razor.Language/test/Legacy/TagHelperParseTreeRewriterTest.cs b/src/Compiler/Microsoft.AspNetCore.Razor.Language/test/Legacy/TagHelperParseTreeRewriterTest.cs index 1af193083e2..5047a11285b 100644 --- a/src/Compiler/Microsoft.AspNetCore.Razor.Language/test/Legacy/TagHelperParseTreeRewriterTest.cs +++ b/src/Compiler/Microsoft.AspNetCore.Razor.Language/test/Legacy/TagHelperParseTreeRewriterTest.cs @@ -3,7 +3,6 @@ using System; using System.Collections.Generic; -using System.Collections.Immutable; using System.Linq; using Microsoft.AspNetCore.Razor.Language.Syntax; using Xunit; @@ -66,7 +65,7 @@ public void GetAttributeNameValuePairs_ParsesPairsCorrectly( Assert.Equal(expectedPairs, pairs); } - public static ImmutableArray PartialRequiredParentTags_Descriptors = + public static readonly TagHelperCollection PartialRequiredParentTags_TagHelpers = [ TagHelperDescriptorBuilder.CreateTagHelper("StrongTagHelper", "SomeAssembly") .TagMatchingRuleDescriptor(rule => rule.RequireTagName("strong")) @@ -84,45 +83,45 @@ public void GetAttributeNameValuePairs_ParsesPairsCorrectly( public void UnderstandsPartialRequiredParentTags1() { var document = "

          "; - EvaluateData(PartialRequiredParentTags_Descriptors, document); + EvaluateData(PartialRequiredParentTags_TagHelpers, document); } [Fact] public void UnderstandsPartialRequiredParentTags2() { var document = "

          "; - EvaluateData(PartialRequiredParentTags_Descriptors, document); + EvaluateData(PartialRequiredParentTags_TagHelpers, document); } [Fact] public void UnderstandsPartialRequiredParentTags3() { var document = "

          "; - EvaluateData(PartialRequiredParentTags_Descriptors, document); + EvaluateData(PartialRequiredParentTags_TagHelpers, document); } [Fact] public void UnderstandsPartialRequiredParentTags4() { var document = "<

          <

          "; - EvaluateData(PartialRequiredParentTags_Descriptors, document); + EvaluateData(PartialRequiredParentTags_TagHelpers, document); } [Fact] public void UnderstandsPartialRequiredParentTags5() { var document = "<

          <

          "; - EvaluateData(PartialRequiredParentTags_Descriptors, document); + EvaluateData(PartialRequiredParentTags_TagHelpers, document); } [Fact] public void UnderstandsPartialRequiredParentTags6() { var document = "<

          <

          "; - EvaluateData(PartialRequiredParentTags_Descriptors, document); + EvaluateData(PartialRequiredParentTags_TagHelpers, document); } - public static ImmutableArray NestedVoidSelfClosingRequiredParent_Descriptors = + public static readonly TagHelperCollection NestedVoidSelfClosingRequiredParent_TagHelpers = [ TagHelperDescriptorBuilder.CreateTagHelper("InputTagHelper", "SomeAssembly") .TagMatchingRuleDescriptor(rule => @@ -145,7 +144,7 @@ public void UnderstandsPartialRequiredParentTags6() .Build(), ]; - public static ImmutableArray CatchAllAttribute_Descriptors = + public static readonly TagHelperCollection CatchAllAttribute_TagHelpers = [ TagHelperDescriptorBuilder.CreateEventHandler("InputTagHelper1", "SomeAssembly") .TagMatchingRuleDescriptor(rule => rule @@ -161,66 +160,66 @@ public void UnderstandsPartialRequiredParentTags6() public void UnderstandsInvalidHtml() { var document = @" {}"">Miscolored!"; - EvaluateData(CatchAllAttribute_Descriptors, document); + EvaluateData(CatchAllAttribute_TagHelpers, document); } [Fact] public void UnderstandsNestedVoidSelfClosingRequiredParent1() { var document = ""; - EvaluateData(NestedVoidSelfClosingRequiredParent_Descriptors, document); + EvaluateData(NestedVoidSelfClosingRequiredParent_TagHelpers, document); } [Fact] public void UnderstandsNestedVoidSelfClosingRequiredParent2() { var document = "

          "; - EvaluateData(NestedVoidSelfClosingRequiredParent_Descriptors, document); + EvaluateData(NestedVoidSelfClosingRequiredParent_TagHelpers, document); } [Fact] public void UnderstandsNestedVoidSelfClosingRequiredParent3() { var document = "


          "; - EvaluateData(NestedVoidSelfClosingRequiredParent_Descriptors, document); + EvaluateData(NestedVoidSelfClosingRequiredParent_TagHelpers, document); } [Fact] public void UnderstandsNestedVoidSelfClosingRequiredParent4() { var document = "


          "; - EvaluateData(NestedVoidSelfClosingRequiredParent_Descriptors, document); + EvaluateData(NestedVoidSelfClosingRequiredParent_TagHelpers, document); } [Fact] public void UnderstandsNestedVoidSelfClosingRequiredParent5() { var document = ""; - EvaluateData(NestedVoidSelfClosingRequiredParent_Descriptors, document); + EvaluateData(NestedVoidSelfClosingRequiredParent_TagHelpers, document); } [Fact] public void UnderstandsNestedVoidSelfClosingRequiredParent6() { var document = "

          "; - EvaluateData(NestedVoidSelfClosingRequiredParent_Descriptors, document); + EvaluateData(NestedVoidSelfClosingRequiredParent_TagHelpers, document); } [Fact] public void UnderstandsNestedVoidSelfClosingRequiredParent7() { var document = "


          "; - EvaluateData(NestedVoidSelfClosingRequiredParent_Descriptors, document); + EvaluateData(NestedVoidSelfClosingRequiredParent_TagHelpers, document); } [Fact] public void UnderstandsNestedVoidSelfClosingRequiredParent8() { var document = "


          "; - EvaluateData(NestedVoidSelfClosingRequiredParent_Descriptors, document); + EvaluateData(NestedVoidSelfClosingRequiredParent_TagHelpers, document); } - public static ImmutableArray NestedRequiredParent_Descriptors = + public static readonly TagHelperCollection NestedRequiredParent_TagHelpers = [ TagHelperDescriptorBuilder.CreateTagHelper("StrongTagHelper", "SomeAssembly") .TagMatchingRuleDescriptor(rule => @@ -241,35 +240,35 @@ public void UnderstandsNestedVoidSelfClosingRequiredParent8() public void UnderstandsNestedRequiredParent1() { var document = ""; - EvaluateData(NestedRequiredParent_Descriptors, document); + EvaluateData(NestedRequiredParent_TagHelpers, document); } [Fact] public void UnderstandsNestedRequiredParent2() { var document = "

          "; - EvaluateData(NestedRequiredParent_Descriptors, document); + EvaluateData(NestedRequiredParent_TagHelpers, document); } [Fact] public void UnderstandsNestedRequiredParent3() { var document = "
          "; - EvaluateData(NestedRequiredParent_Descriptors, document); + EvaluateData(NestedRequiredParent_TagHelpers, document); } [Fact] public void UnderstandsNestedRequiredParent4() { var document = ""; - EvaluateData(NestedRequiredParent_Descriptors, document); + EvaluateData(NestedRequiredParent_TagHelpers, document); } [Fact] public void UnderstandsNestedRequiredParent5() { var document = "

          "; - EvaluateData(NestedRequiredParent_Descriptors, document); + EvaluateData(NestedRequiredParent_TagHelpers, document); } [Fact] @@ -277,7 +276,7 @@ public void UnderstandsTagHelperPrefixAndAllowedChildren() { // Arrange var documentContent = ""; - ImmutableArray descriptors = + TagHelperCollection tagHelpers = [ TagHelperDescriptorBuilder.CreateTagHelper("PTagHelper", "SomeAssembly") .TagMatchingRuleDescriptor(rule => rule.RequireTagName("p")) @@ -290,7 +289,7 @@ public void UnderstandsTagHelperPrefixAndAllowedChildren() // Act & Assert EvaluateData( - descriptors, + tagHelpers, documentContent, tagHelperPrefix: "th:"); } @@ -300,7 +299,7 @@ public void UnderstandsTagHelperPrefixAndAllowedChildrenAndRequireParent() { // Arrange var documentContent = ""; - ImmutableArray descriptors = + TagHelperCollection tagHelpers = [ TagHelperDescriptorBuilder.CreateTagHelper("PTagHelper", "SomeAssembly") .TagMatchingRuleDescriptor(rule => rule.RequireTagName("p")) @@ -313,7 +312,7 @@ public void UnderstandsTagHelperPrefixAndAllowedChildrenAndRequireParent() // Act & Assert EvaluateData( - descriptors, + tagHelpers, documentContent, tagHelperPrefix: "th:"); } @@ -324,7 +323,7 @@ public void InvalidStructure_UnderstandsTHPrefixAndAllowedChildrenAndRequirePare // Rewrite_InvalidStructure_UnderstandsTagHelperPrefixAndAllowedChildrenAndRequireParent // Arrange var documentContent = ""; - ImmutableArray descriptors = + TagHelperCollection tagHelpers = [ TagHelperDescriptorBuilder.CreateTagHelper("PTagHelper", "SomeAssembly") .TagMatchingRuleDescriptor(rule => rule.RequireTagName("p")) @@ -337,7 +336,7 @@ public void InvalidStructure_UnderstandsTHPrefixAndAllowedChildrenAndRequirePare // Act & Assert EvaluateData( - descriptors, + tagHelpers, documentContent, tagHelperPrefix: "th:"); } @@ -347,7 +346,7 @@ public void NonTagHelperChild_UnderstandsTagHelperPrefixAndAllowedChildren() { // Arrange var documentContent = ""; - ImmutableArray descriptors = + TagHelperCollection tagHelpers = [ TagHelperDescriptorBuilder.CreateTagHelper("PTagHelper", "SomeAssembly") .TagMatchingRuleDescriptor(rule => rule.RequireTagName("p")) @@ -357,7 +356,7 @@ public void NonTagHelperChild_UnderstandsTagHelperPrefixAndAllowedChildren() // Act & Assert EvaluateData( - descriptors, + tagHelpers, documentContent, tagHelperPrefix: "th:"); } @@ -429,7 +428,7 @@ public void CanHandleInvalidChildrenWithWhitespace()

          """; - ImmutableArray descriptors = + TagHelperCollection tagHelpers = [ TagHelperDescriptorBuilder.CreateTagHelper("PTagHelper", "SomeAssembly") .TagMatchingRuleDescriptor(rule => rule.RequireTagName("p")) @@ -438,7 +437,7 @@ public void CanHandleInvalidChildrenWithWhitespace() ]; // Act & Assert - EvaluateData(descriptors, documentContent); + EvaluateData(tagHelpers, documentContent); } [Fact] @@ -446,7 +445,7 @@ public void RecoversWhenRequiredAttributeMismatchAndRestrictedChildren() { // Arrange var documentContent = ""; - ImmutableArray descriptors = + TagHelperCollection tagHelpers = [ TagHelperDescriptorBuilder.CreateTagHelper("StrongTagHelper", "SomeAssembly") .TagMatchingRuleDescriptor(rule => @@ -458,7 +457,7 @@ public void RecoversWhenRequiredAttributeMismatchAndRestrictedChildren() ]; // Act & Assert - EvaluateData(descriptors, documentContent); + EvaluateData(tagHelpers, documentContent); } [Fact] @@ -466,7 +465,7 @@ public void CanHandleMultipleTagHelpersWithAllowedChildren_OneNull() { // Arrange var documentContent = "

          Hello World

          "; - ImmutableArray descriptors = + TagHelperCollection tagHelpers = [ TagHelperDescriptorBuilder.CreateTagHelper("PTagHelper1", "SomeAssembly") .TagMatchingRuleDescriptor(rule => rule.RequireTagName("p")) @@ -488,7 +487,7 @@ public void CanHandleMultipleTagHelpersWithAllowedChildren_OneNull() ]; // Act & Assert - EvaluateData(descriptors, documentContent); + EvaluateData(tagHelpers, documentContent); } [Fact] @@ -496,7 +495,7 @@ public void CanHandleMultipleTagHelpersWithAllowedChildren() { // Arrange var documentContent = "

          Hello World

          "; - ImmutableArray descriptors = + TagHelperCollection tagHelpers = [ TagHelperDescriptorBuilder.CreateTagHelper("PTagHelper1", "SomeAssembly") .TagMatchingRuleDescriptor(rule => rule.RequireTagName("p")) @@ -518,7 +517,7 @@ public void CanHandleMultipleTagHelpersWithAllowedChildren() ]; // Act & Assert - EvaluateData(descriptors, documentContent); + EvaluateData(tagHelpers, documentContent); } [Fact] @@ -526,10 +525,10 @@ public void UnderstandsAllowedChildren1() { // Arrange var documentContent = "


          "; - var descriptors = GetAllowedChildrenTagHelperDescriptors(["br"]); + var tagHelpers = GetAllowedChildrenTagHelpers(["br"]); // Act & Assert - EvaluateData(descriptors, documentContent); + EvaluateData(tagHelpers, documentContent); } [Fact] @@ -541,10 +540,10 @@ public void UnderstandsAllowedChildren2()

          """; - var descriptors = GetAllowedChildrenTagHelperDescriptors(["br"]); + var tagHelpers = GetAllowedChildrenTagHelpers(["br"]); // Act & Assert - EvaluateData(descriptors, documentContent); + EvaluateData(tagHelpers, documentContent); } [Fact] @@ -552,10 +551,10 @@ public void UnderstandsAllowedChildren3() { // Arrange var documentContent = "


          "; - var descriptors = GetAllowedChildrenTagHelperDescriptors(["strong"]); + var tagHelpers = GetAllowedChildrenTagHelpers(["strong"]); // Act & Assert - EvaluateData(descriptors, documentContent); + EvaluateData(tagHelpers, documentContent); } [Fact] @@ -563,10 +562,10 @@ public void UnderstandsAllowedChildren4() { // Arrange var documentContent = "

          Hello

          "; - var descriptors = GetAllowedChildrenTagHelperDescriptors(["strong"]); + var tagHelpers = GetAllowedChildrenTagHelpers(["strong"]); // Act & Assert - EvaluateData(descriptors, documentContent); + EvaluateData(tagHelpers, documentContent); } [Fact] @@ -574,10 +573,10 @@ public void UnderstandsAllowedChildren5() { // Arrange var documentContent = "


          "; - var descriptors = GetAllowedChildrenTagHelperDescriptors(["br", "strong"]); + var tagHelpers = GetAllowedChildrenTagHelpers(["br", "strong"]); // Act & Assert - EvaluateData(descriptors, documentContent); + EvaluateData(tagHelpers, documentContent); } [Fact] @@ -585,10 +584,10 @@ public void UnderstandsAllowedChildren6() { // Arrange var documentContent = "


          Hello

          "; - var descriptors = GetAllowedChildrenTagHelperDescriptors(["strong"]); + var tagHelpers = GetAllowedChildrenTagHelpers(["strong"]); // Act & Assert - EvaluateData(descriptors, documentContent); + EvaluateData(tagHelpers, documentContent); } [Fact] @@ -596,10 +595,10 @@ public void UnderstandsAllowedChildren7() { // Arrange var documentContent = "

          Title:
          Something

          "; - var descriptors = GetAllowedChildrenTagHelperDescriptors(["strong"]); + var tagHelpers = GetAllowedChildrenTagHelpers(["strong"]); // Act & Assert - EvaluateData(descriptors, documentContent); + EvaluateData(tagHelpers, documentContent); } [Fact] @@ -607,10 +606,10 @@ public void UnderstandsAllowedChildren8() { // Arrange var documentContent = "

          Title:
          Something

          "; - var descriptors = GetAllowedChildrenTagHelperDescriptors(["strong", "br"]); + var tagHelpers = GetAllowedChildrenTagHelpers(["strong", "br"]); // Act & Assert - EvaluateData(descriptors, documentContent); + EvaluateData(tagHelpers, documentContent); } [Fact] @@ -618,10 +617,10 @@ public void UnderstandsAllowedChildren9() { // Arrange var documentContent = "

          Title:
          Something

          "; - var descriptors = GetAllowedChildrenTagHelperDescriptors(["strong", "br"]); + var tagHelpers = GetAllowedChildrenTagHelpers(["strong", "br"]); // Act & Assert - EvaluateData(descriptors, documentContent); + EvaluateData(tagHelpers, documentContent); } [Fact] @@ -629,10 +628,10 @@ public void UnderstandsAllowedChildren10() { // Arrange var documentContent = "

          Title:
          A Very Cool

          Something

          "; - var descriptors = GetAllowedChildrenTagHelperDescriptors(["strong"]); + var tagHelpers = GetAllowedChildrenTagHelpers(["strong"]); // Act & Assert - EvaluateData(descriptors, documentContent); + EvaluateData(tagHelpers, documentContent); } [Fact] @@ -640,10 +639,10 @@ public void UnderstandsAllowedChildren11() { // Arrange var documentContent = "

          Title:
          A Very Cool

          Something

          "; - var descriptors = GetAllowedChildrenTagHelperDescriptors(["custom"]); + var tagHelpers = GetAllowedChildrenTagHelpers(["custom"]); // Act & Assert - EvaluateData(descriptors, documentContent); + EvaluateData(tagHelpers, documentContent); } [Fact] @@ -651,10 +650,10 @@ public void UnderstandsAllowedChildren12() { // Arrange var documentContent = "

          "; - var descriptors = GetAllowedChildrenTagHelperDescriptors(["custom"]); + var tagHelpers = GetAllowedChildrenTagHelpers(["custom"]); // Act & Assert - EvaluateData(descriptors, documentContent); + EvaluateData(tagHelpers, documentContent); } [Fact] @@ -662,10 +661,10 @@ public void UnderstandsAllowedChildren13() { // Arrange var documentContent = "

          <

          "; - var descriptors = GetAllowedChildrenTagHelperDescriptors(["custom"]); + var tagHelpers = GetAllowedChildrenTagHelpers(["custom"]); // Act & Assert - EvaluateData(descriptors, documentContent); + EvaluateData(tagHelpers, documentContent); } [Fact] @@ -673,13 +672,13 @@ public void UnderstandsAllowedChildren14() { // Arrange var documentContent = "


          :Hello:

          "; - var descriptors = GetAllowedChildrenTagHelperDescriptors(["custom", "strong"]); + var tagHelpers = GetAllowedChildrenTagHelpers(["custom", "strong"]); // Act & Assert - EvaluateData(descriptors, documentContent); + EvaluateData(tagHelpers, documentContent); } - private static ImmutableArray GetAllowedChildrenTagHelperDescriptors(string[] allowedChildren) + private static TagHelperCollection GetAllowedChildrenTagHelpers(string[] allowedChildren) { var pTagHelperBuilder = TagHelperDescriptorBuilder.CreateTagHelper("PTagHelper", "SomeAssembly") .TagMatchingRuleDescriptor(rule => rule.RequireTagName("p")); @@ -722,13 +721,13 @@ public void AllowsSimpleHtmlCommentsAsChildren() pTagHelperBuilder.AllowChildTag(childTag); } - ImmutableArray descriptors = + TagHelperCollection tagHelpers = [ pTagHelperBuilder.Build() ]; // Act & Assert - EvaluateData(descriptors, document); + EvaluateData(tagHelpers, document); } [Fact] @@ -747,14 +746,14 @@ public void DoesntAllowSimpleHtmlCommentsAsChildrenWhenFeatureFlagIsOff() pTagHelperBuilder.AllowChildTag(childTag); } - ImmutableArray descriptors = + TagHelperCollection tagHelpers = [ pTagHelperBuilder.Build() ]; // Act & Assert EvaluateData( - descriptors, + tagHelpers, document, languageVersion: RazorLanguageVersion.Version_2_0, fileKind: RazorFileKind.Legacy); @@ -778,13 +777,13 @@ public void FailsForContentWithCommentsAsChildren() pTagHelperBuilder.AllowChildTag(childTag); } - ImmutableArray descriptors = + TagHelperCollection tagHelpers = [ pTagHelperBuilder.Build() ]; // Act & Assert - EvaluateData(descriptors, document); + EvaluateData(tagHelpers, document); } [Fact] @@ -804,13 +803,13 @@ public void AllowsRazorCommentsAsChildren() pTagHelperBuilder.AllowChildTag(childTag); } - ImmutableArray descriptors = + TagHelperCollection tagHelpers = [ pTagHelperBuilder.Build() ]; // Act & Assert - EvaluateData(descriptors, document); + EvaluateData(tagHelpers, document); } [Fact] @@ -833,13 +832,13 @@ public void AllowsRazorMarkupInHtmlComment() pTagHelperBuilder.AllowChildTag(childTag); } - ImmutableArray descriptors = + TagHelperCollection tagHelpers = [ pTagHelperBuilder.Build() ]; // Act & Assert - EvaluateData(descriptors, document); + EvaluateData(tagHelpers, document); } [Fact] @@ -847,7 +846,7 @@ public void UnderstandsNullTagNameWithAllowedChildrenForCatchAll() { // Arrange var documentContent = "

          "; - ImmutableArray descriptors = + TagHelperCollection tagHelpers = [ TagHelperDescriptorBuilder.CreateTagHelper("PTagHelper", "SomeAssembly") .TagMatchingRuleDescriptor(rule => rule.RequireTagName("p")) @@ -859,7 +858,7 @@ public void UnderstandsNullTagNameWithAllowedChildrenForCatchAll() ]; // Act & Assert - EvaluateData(descriptors, documentContent); + EvaluateData(tagHelpers, documentContent); } [Fact] @@ -867,7 +866,7 @@ public void UnderstandsNullTagNameWithAllowedChildrenForCatchAllWithPrefix() { // Arrange var documentContent = ""; - ImmutableArray descriptors = + TagHelperCollection tagHelpers = [ TagHelperDescriptorBuilder.CreateTagHelper("PTagHelper", "SomeAssembly") .TagMatchingRuleDescriptor(rule => rule.RequireTagName("p")) @@ -879,7 +878,7 @@ public void UnderstandsNullTagNameWithAllowedChildrenForCatchAllWithPrefix() ]; // Act & Assert - EvaluateData(descriptors, documentContent, "th:"); + EvaluateData(tagHelpers, documentContent, "th:"); } [Fact] @@ -887,7 +886,7 @@ public void CanHandleStartTagOnlyTagTagMode() { // Arrange var documentContent = ""; - ImmutableArray descriptors = + TagHelperCollection tagHelpers = [ TagHelperDescriptorBuilder.CreateTagHelper("InputTagHelper", "SomeAssembly") .TagMatchingRuleDescriptor(rule => @@ -898,7 +897,7 @@ public void CanHandleStartTagOnlyTagTagMode() ]; // Act & Assert - EvaluateData(descriptors, documentContent); + EvaluateData(tagHelpers, documentContent); } [Fact] @@ -906,7 +905,7 @@ public void CreatesErrorForWithoutEndTagTagStructureForEndTags() { // Arrange var documentContent = ""; - ImmutableArray descriptors = + TagHelperCollection tagHelpers = [ TagHelperDescriptorBuilder.CreateTagHelper("InputTagHelper", "SomeAssembly") .TagMatchingRuleDescriptor(rule => @@ -917,7 +916,7 @@ public void CreatesErrorForWithoutEndTagTagStructureForEndTags() ]; // Act & Assert - EvaluateData(descriptors, documentContent); + EvaluateData(tagHelpers, documentContent); } [Fact] @@ -925,7 +924,7 @@ public void CreatesErrorForInconsistentTagStructures() { // Arrange var documentContent = ""; - ImmutableArray descriptors = + TagHelperCollection tagHelpers = [ TagHelperDescriptorBuilder.CreateTagHelper("InputTagHelper1", "SomeAssembly") .TagMatchingRuleDescriptor(rule => @@ -942,10 +941,10 @@ public void CreatesErrorForInconsistentTagStructures() ]; // Act & Assert - EvaluateData(descriptors, documentContent); + EvaluateData(tagHelpers, documentContent); } - public static ImmutableArray RequiredAttribute_Descriptors = + public static readonly TagHelperCollection RequiredAttribute_TagHelpers = [ TagHelperDescriptorBuilder.CreateTagHelper("pTagHelper", "SomeAssembly") .TagMatchingRuleDescriptor(rule => @@ -971,184 +970,184 @@ public void CreatesErrorForInconsistentTagStructures() [Fact] public void RequiredAttributeDescriptorsCreateTagHelperBlocksCorrectly1() { - EvaluateData(RequiredAttribute_Descriptors, "

          "); + EvaluateData(RequiredAttribute_TagHelpers, "

          "); } [Fact] public void RequiredAttributeDescriptorsCreateTagHelperBlocksCorrectly2() { - EvaluateData(RequiredAttribute_Descriptors, "

          "); + EvaluateData(RequiredAttribute_TagHelpers, "

          "); } [Fact] public void RequiredAttributeDescriptorsCreateTagHelperBlocksCorrectly3() { - EvaluateData(RequiredAttribute_Descriptors, "
          "); + EvaluateData(RequiredAttribute_TagHelpers, "
          "); } [Fact] public void RequiredAttributeDescriptorsCreateTagHelperBlocksCorrectly4() { - EvaluateData(RequiredAttribute_Descriptors, "
          "); + EvaluateData(RequiredAttribute_TagHelpers, "
          "); } [Fact] public void RequiredAttributeDescriptorsCreateTagHelperBlocksCorrectly5() { - EvaluateData(RequiredAttribute_Descriptors, "

          "); + EvaluateData(RequiredAttribute_TagHelpers, "

          "); } [Fact] public void RequiredAttributeDescriptorsCreateTagHelperBlocksCorrectly6() { - EvaluateData(RequiredAttribute_Descriptors, "

          "); + EvaluateData(RequiredAttribute_TagHelpers, "

          "); } [Fact] public void RequiredAttributeDescriptorsCreateTagHelperBlocksCorrectly7() { - EvaluateData(RequiredAttribute_Descriptors, "

          words and spaces

          "); + EvaluateData(RequiredAttribute_TagHelpers, "

          words and spaces

          "); } [Fact] public void RequiredAttributeDescriptorsCreateTagHelperBlocksCorrectly8() { - EvaluateData(RequiredAttribute_Descriptors, "

          words and spaces

          "); + EvaluateData(RequiredAttribute_TagHelpers, "

          words and spaces

          "); } [Fact] public void RequiredAttributeDescriptorsCreateTagHelperBlocksCorrectly9() { - EvaluateData(RequiredAttribute_Descriptors, "

          wordsandspaces

          "); + EvaluateData(RequiredAttribute_TagHelpers, "

          wordsandspaces

          "); } [Fact] public void RequiredAttributeDescriptorsCreateTagHelperBlocksCorrectly10() { - EvaluateData(RequiredAttribute_Descriptors, ""); + EvaluateData(RequiredAttribute_TagHelpers, ""); } [Fact] public void RequiredAttributeDescriptorsCreateTagHelperBlocksCorrectly11() { - EvaluateData(RequiredAttribute_Descriptors, ""); + EvaluateData(RequiredAttribute_TagHelpers, ""); } [Fact] public void RequiredAttributeDescriptorsCreateTagHelperBlocksCorrectly12() { - EvaluateData(RequiredAttribute_Descriptors, "words and spaces"); + EvaluateData(RequiredAttribute_TagHelpers, "words and spaces"); } [Fact] public void RequiredAttributeDescriptorsCreateTagHelperBlocksCorrectly13() { - EvaluateData(RequiredAttribute_Descriptors, "words and spaces"); + EvaluateData(RequiredAttribute_TagHelpers, "words and spaces"); } [Fact] public void RequiredAttributeDescriptorsCreateTagHelperBlocksCorrectly14() { - EvaluateData(RequiredAttribute_Descriptors, "
          "); + EvaluateData(RequiredAttribute_TagHelpers, "
          "); } [Fact] public void RequiredAttributeDescriptorsCreateTagHelperBlocksCorrectly15() { - EvaluateData(RequiredAttribute_Descriptors, "
          "); + EvaluateData(RequiredAttribute_TagHelpers, "
          "); } [Fact] public void RequiredAttributeDescriptorsCreateTagHelperBlocksCorrectly16() { - EvaluateData(RequiredAttribute_Descriptors, "

          "); + EvaluateData(RequiredAttribute_TagHelpers, "

          "); } [Fact] public void RequiredAttributeDescriptorsCreateTagHelperBlocksCorrectly17() { - EvaluateData(RequiredAttribute_Descriptors, "

          "); + EvaluateData(RequiredAttribute_TagHelpers, "

          "); } [Fact] public void RequiredAttributeDescriptorsCreateTagHelperBlocksCorrectly18() { - EvaluateData(RequiredAttribute_Descriptors, "

          words and spaces

          "); + EvaluateData(RequiredAttribute_TagHelpers, "

          words and spaces

          "); } [Fact] public void RequiredAttributeDescriptorsCreateTagHelperBlocksCorrectly19() { - EvaluateData(RequiredAttribute_Descriptors, "
          "); + EvaluateData(RequiredAttribute_TagHelpers, "
          "); } [Fact] public void RequiredAttributeDescriptorsCreateTagHelperBlocksCorrectly20() { - EvaluateData(RequiredAttribute_Descriptors, "
          "); + EvaluateData(RequiredAttribute_TagHelpers, "
          "); } [Fact] public void RequiredAttributeDescriptorsCreateTagHelperBlocksCorrectly21() { - EvaluateData(RequiredAttribute_Descriptors, "
          words and spaces
          "); + EvaluateData(RequiredAttribute_TagHelpers, "
          words and spaces
          "); } [Fact] public void RequiredAttributeDescriptorsCreateTagHelperBlocksCorrectly22() { - EvaluateData(RequiredAttribute_Descriptors, "
          words and spaces
          "); + EvaluateData(RequiredAttribute_TagHelpers, "
          words and spaces
          "); } [Fact] public void RequiredAttributeDescriptorsCreateTagHelperBlocksCorrectly23() { - EvaluateData(RequiredAttribute_Descriptors, "
          wordsandspaces
          "); + EvaluateData(RequiredAttribute_TagHelpers, "
          wordsandspaces
          "); } [Fact] public void RequiredAttributeDescriptorsCreateTagHelperBlocksCorrectly24() { - EvaluateData(RequiredAttribute_Descriptors, "

          "); + EvaluateData(RequiredAttribute_TagHelpers, "

          "); } [Fact] public void RequiredAttributeDescriptorsCreateTagHelperBlocksCorrectly25() { - EvaluateData(RequiredAttribute_Descriptors, "

          words and spaces

          "); + EvaluateData(RequiredAttribute_TagHelpers, "

          words and spaces

          "); } [Fact] public void RequiredAttributeDescriptorsCreateTagHelperBlocksCorrectly26() { - EvaluateData(RequiredAttribute_Descriptors, "
          "); + EvaluateData(RequiredAttribute_TagHelpers, "
          "); } [Fact] public void RequiredAttributeDescriptorsCreateTagHelperBlocksCorrectly27() { - EvaluateData(RequiredAttribute_Descriptors, "
          words and spaces
          "); + EvaluateData(RequiredAttribute_TagHelpers, "
          words and spaces
          "); } [Fact] public void RequiredAttributeDescriptorsCreateTagHelperBlocksCorrectly28() { - EvaluateData(RequiredAttribute_Descriptors, "
          words and spaces
          "); + EvaluateData(RequiredAttribute_TagHelpers, "
          words and spaces
          "); } [Fact] public void RequiredAttributeDescriptorsCreateTagHelperBlocksCorrectly29() { - EvaluateData(RequiredAttribute_Descriptors, "
          words and spaces
          "); + EvaluateData(RequiredAttribute_TagHelpers, "
          words and spaces
          "); } [Fact] public void RequiredAttributeDescriptorsCreateTagHelperBlocksCorrectly30() { - EvaluateData(RequiredAttribute_Descriptors, "
          wordsandspaces
          "); + EvaluateData(RequiredAttribute_TagHelpers, "
          wordsandspaces
          "); } - public static ImmutableArray NestedRequiredAttribute_Descriptors = + public static readonly TagHelperCollection NestedRequiredAttribute_TagHelpers = [ TagHelperDescriptorBuilder.CreateTagHelper("pTagHelper", "SomeAssembly") .TagMatchingRuleDescriptor(rule => @@ -1167,64 +1166,64 @@ public void RequiredAttributeDescriptorsCreateTagHelperBlocksCorrectly30() [Fact] public void NestedRequiredAttributeDescriptorsCreateTagHelperBlocksCorrectly1() { - EvaluateData(NestedRequiredAttribute_Descriptors, "

          "); + EvaluateData(NestedRequiredAttribute_TagHelpers, "

          "); } [Fact] public void NestedRequiredAttributeDescriptorsCreateTagHelperBlocksCorrectly2() { - EvaluateData(NestedRequiredAttribute_Descriptors, ""); + EvaluateData(NestedRequiredAttribute_TagHelpers, ""); } [Fact] public void NestedRequiredAttributeDescriptorsCreateTagHelperBlocksCorrectly3() { - EvaluateData(NestedRequiredAttribute_Descriptors, "

          "); + EvaluateData(NestedRequiredAttribute_TagHelpers, "

          "); } [Fact] public void NestedRequiredAttributeDescriptorsCreateTagHelperBlocksCorrectly4() { - EvaluateData(NestedRequiredAttribute_Descriptors, "

          "); + EvaluateData(NestedRequiredAttribute_TagHelpers, "

          "); } [Fact] public void NestedRequiredAttributeDescriptorsCreateTagHelperBlocksCorrectly5() { - EvaluateData(NestedRequiredAttribute_Descriptors, "

          "); + EvaluateData(NestedRequiredAttribute_TagHelpers, "

          "); } [Fact] public void NestedRequiredAttributeDescriptorsCreateTagHelperBlocksCorrectly6() { - EvaluateData(NestedRequiredAttribute_Descriptors, "

          "); + EvaluateData(NestedRequiredAttribute_TagHelpers, "

          "); } [Fact] public void NestedRequiredAttributeDescriptorsCreateTagHelperBlocksCorrectly7() { - EvaluateData(NestedRequiredAttribute_Descriptors, "

          "); + EvaluateData(NestedRequiredAttribute_TagHelpers, "

          "); } [Fact] public void NestedRequiredAttributeDescriptorsCreateTagHelperBlocksCorrectly8() { - EvaluateData(NestedRequiredAttribute_Descriptors, ""); + EvaluateData(NestedRequiredAttribute_TagHelpers, ""); } [Fact] public void NestedRequiredAttributeDescriptorsCreateTagHelperBlocksCorrectly9() { - EvaluateData(NestedRequiredAttribute_Descriptors, "

          "); + EvaluateData(NestedRequiredAttribute_TagHelpers, "

          "); } [Fact] public void NestedRequiredAttributeDescriptorsCreateTagHelperBlocksCorrectly10() { - EvaluateData(NestedRequiredAttribute_Descriptors, ""); + EvaluateData(NestedRequiredAttribute_TagHelpers, ""); } - public static ImmutableArray MalformedRequiredAttribute_Descriptors = + public static readonly TagHelperCollection MalformedRequiredAttribute_TagHelpers = [ TagHelperDescriptorBuilder.CreateTagHelper("pTagHelper", "SomeAssembly") .TagMatchingRuleDescriptor(rule => @@ -1237,71 +1236,71 @@ public void NestedRequiredAttributeDescriptorsCreateTagHelperBlocksCorrectly10() [Fact] public void RequiredAttributeDescriptorsCreateMalformedTagHelperBlocksCorrectly1() { - EvaluateData(MalformedRequiredAttribute_Descriptors, ""); + EvaluateData(MalformedRequiredAttribute_TagHelpers, "

          "); } [Fact] public void RequiredAttributeDescriptorsCreateMalformedTagHelperBlocksCorrectly8() { - EvaluateData(MalformedRequiredAttribute_Descriptors, "

          "); + EvaluateData(MalformedRequiredAttribute_TagHelpers, "

          "); } [Fact] public void RequiredAttributeDescriptorsCreateMalformedTagHelperBlocksCorrectly9() { - EvaluateData(MalformedRequiredAttribute_Descriptors, "

          PrefixedTagHelperColon_Descriptors = + public static readonly TagHelperCollection PrefixedTagHelperColon_TagHelpers = [ TagHelperDescriptorBuilder.CreateTagHelper("mythTagHelper", "SomeAssembly") .TagMatchingRuleDescriptor(rule => rule.RequireTagName("myth")) @@ -1316,7 +1315,7 @@ public void RequiredAttributeDescriptorsCreateMalformedTagHelperBlocksCorrectly1 .Build() ]; - public static ImmutableArray PrefixedTagHelperCatchAll_Descriptors = + public static readonly TagHelperCollection PrefixedTagHelperCatchAll_TagHelpers = [ TagHelperDescriptorBuilder.CreateTagHelper("mythTagHelper", "SomeAssembly") .TagMatchingRuleDescriptor(rule => rule.RequireTagName("*")) @@ -1326,67 +1325,67 @@ public void RequiredAttributeDescriptorsCreateMalformedTagHelperBlocksCorrectly1 [Fact] public void AllowsPrefixedTagHelpers1() { - EvaluateData(PrefixedTagHelperCatchAll_Descriptors, "", tagHelperPrefix: "th:"); + EvaluateData(PrefixedTagHelperCatchAll_TagHelpers, "", tagHelperPrefix: "th:"); } [Fact] public void AllowsPrefixedTagHelpers2() { - EvaluateData(PrefixedTagHelperCatchAll_Descriptors, "words and spaces", tagHelperPrefix: "th:"); + EvaluateData(PrefixedTagHelperCatchAll_TagHelpers, "words and spaces", tagHelperPrefix: "th:"); } [Fact] public void AllowsPrefixedTagHelpers3() { - EvaluateData(PrefixedTagHelperColon_Descriptors, "", tagHelperPrefix: "th:"); + EvaluateData(PrefixedTagHelperColon_TagHelpers, "", tagHelperPrefix: "th:"); } [Fact] public void AllowsPrefixedTagHelpers4() { - EvaluateData(PrefixedTagHelperColon_Descriptors, "", tagHelperPrefix: "th:"); + EvaluateData(PrefixedTagHelperColon_TagHelpers, "", tagHelperPrefix: "th:"); } [Fact] public void AllowsPrefixedTagHelpers5() { - EvaluateData(PrefixedTagHelperColon_Descriptors, "", tagHelperPrefix: "th:"); + EvaluateData(PrefixedTagHelperColon_TagHelpers, "", tagHelperPrefix: "th:"); } [Fact] public void AllowsPrefixedTagHelpers6() { - EvaluateData(PrefixedTagHelperColon_Descriptors, "", tagHelperPrefix: "th:"); + EvaluateData(PrefixedTagHelperColon_TagHelpers, "", tagHelperPrefix: "th:"); } [Fact] public void AllowsPrefixedTagHelpers7() { - EvaluateData(PrefixedTagHelperColon_Descriptors, "", tagHelperPrefix: "th:"); + EvaluateData(PrefixedTagHelperColon_TagHelpers, "", tagHelperPrefix: "th:"); } [Fact] public void AllowsPrefixedTagHelpers8() { - EvaluateData(PrefixedTagHelperColon_Descriptors, "", tagHelperPrefix: "th:"); + EvaluateData(PrefixedTagHelperColon_TagHelpers, "", tagHelperPrefix: "th:"); } [Fact] public void AllowsPrefixedTagHelpers9() { - EvaluateData(PrefixedTagHelperColon_Descriptors, "", tagHelperPrefix: "th:"); + EvaluateData(PrefixedTagHelperColon_TagHelpers, "", tagHelperPrefix: "th:"); } [Fact] public void AllowsPrefixedTagHelpers10() { - EvaluateData(PrefixedTagHelperColon_Descriptors, "words and spaces", tagHelperPrefix: "th:"); + EvaluateData(PrefixedTagHelperColon_TagHelpers, "words and spaces", tagHelperPrefix: "th:"); } [Fact] public void AllowsPrefixedTagHelpers11() { - EvaluateData(PrefixedTagHelperColon_Descriptors, "", tagHelperPrefix: "th:"); + EvaluateData(PrefixedTagHelperColon_TagHelpers, "", tagHelperPrefix: "th:"); } [Fact] @@ -1911,7 +1910,7 @@ public void HandlesNonTagHelperStartAndEndVoidTags_Correctly() RunParseTreeRewriterTest("Foo"); } - public static ImmutableArray CaseSensitive_Descriptors = + public static readonly TagHelperCollection CaseSensitive_TagHelpers = [ TagHelperDescriptorBuilder.CreateTagHelper("pTagHelper", "SomeAssembly") .SetCaseSensitive() @@ -1936,30 +1935,30 @@ public void HandlesNonTagHelperStartAndEndVoidTags_Correctly() [Fact] public void HandlesCaseSensitiveTagHelpersCorrectly1() { - EvaluateData(CaseSensitive_Descriptors, "

          "); + EvaluateData(CaseSensitive_TagHelpers, "

          "); } [Fact] public void HandlesCaseSensitiveTagHelpersCorrectly2() { - EvaluateData(CaseSensitive_Descriptors, "

          "); + EvaluateData(CaseSensitive_TagHelpers, "

          "); } [Fact] public void HandlesCaseSensitiveTagHelpersCorrectly3() { - EvaluateData(CaseSensitive_Descriptors, "

          "); + EvaluateData(CaseSensitive_TagHelpers, "

          "); } [Fact] public void HandlesCaseSensitiveTagHelpersCorrectly4() { - EvaluateData(CaseSensitive_Descriptors, "

          "); + EvaluateData(CaseSensitive_TagHelpers, "

          "); } [Fact] public void HandlesCaseSensitiveTagHelpersCorrectly5() { - EvaluateData(CaseSensitive_Descriptors, "

          "); + EvaluateData(CaseSensitive_TagHelpers, "

          "); } } diff --git a/src/Compiler/Microsoft.AspNetCore.Razor.Language/test/Legacy/TagHelperRewritingTestBase.cs b/src/Compiler/Microsoft.AspNetCore.Razor.Language/test/Legacy/TagHelperRewritingTestBase.cs index aca41009202..6b163169ab5 100644 --- a/src/Compiler/Microsoft.AspNetCore.Razor.Language/test/Legacy/TagHelperRewritingTestBase.cs +++ b/src/Compiler/Microsoft.AspNetCore.Razor.Language/test/Legacy/TagHelperRewritingTestBase.cs @@ -1,10 +1,7 @@ // 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 System; -using System.Collections.Generic; using System.Collections.Immutable; using Xunit; @@ -12,39 +9,38 @@ namespace Microsoft.AspNetCore.Razor.Language.Legacy; public class TagHelperRewritingTestBase() : ParserTestBase(layer: TestProject.Layer.Compiler) { - internal void RunParseTreeRewriterTest(string documentContent, params string[] tagNames) + internal void RunParseTreeRewriterTest(string documentContent, params ImmutableArray tagNames) { - var descriptors = BuildDescriptors(tagNames); + var tagHelpers = BuildTagHelpers(tagNames); - EvaluateData(descriptors, documentContent); + EvaluateData(tagHelpers, documentContent); } - internal ImmutableArray BuildDescriptors(params string[] tagNames) + internal static TagHelperCollection BuildTagHelpers(params ImmutableArray tagNames) { - var descriptors = new List(); - - foreach (var tagName in tagNames) + return TagHelperCollection.Build(tagNames, (ref builder, tagNames) => { - var descriptor = TagHelperDescriptorBuilder.CreateTagHelper(tagName + "taghelper", "SomeAssembly") - .TagMatchingRuleDescriptor(rule => rule.RequireTagName(tagName)) - .Build(); - descriptors.Add(descriptor); - } - - return descriptors.ToImmutableArray(); + foreach (var tagName in tagNames) + { + var tagHelper = TagHelperDescriptorBuilder.CreateTagHelper(tagName + "taghelper", "SomeAssembly") + .TagMatchingRuleDescriptor(rule => rule.RequireTagName(tagName)) + .Build(); + builder.Add(tagHelper); + } + }); } internal void EvaluateData( - ImmutableArray descriptors, + TagHelperCollection tagHelpers, string documentContent, - string tagHelperPrefix = null, - RazorLanguageVersion languageVersion = null, + string? tagHelperPrefix = null, + RazorLanguageVersion? languageVersion = null, RazorFileKind? fileKind = null, - Action configureParserOptions = null) + Action? configureParserOptions = null) { var syntaxTree = ParseDocument(languageVersion, documentContent, directives: default, fileKind: fileKind, configureParserOptions: configureParserOptions); - var binder = new TagHelperBinder(tagHelperPrefix, descriptors); + var binder = new TagHelperBinder(tagHelperPrefix, tagHelpers); var rewrittenTree = TagHelperParseTreeRewriter.Rewrite(syntaxTree, binder); Assert.Equal(syntaxTree.Root.Width, rewrittenTree.Root.Width); diff --git a/src/Compiler/Microsoft.AspNetCore.Razor.Language/test/RazorCodeDocumentExtensionsTest.cs b/src/Compiler/Microsoft.AspNetCore.Razor.Language/test/RazorCodeDocumentExtensionsTest.cs index 0948fa7b0d7..22865048809 100644 --- a/src/Compiler/Microsoft.AspNetCore.Razor.Language/test/RazorCodeDocumentExtensionsTest.cs +++ b/src/Compiler/Microsoft.AspNetCore.Razor.Language/test/RazorCodeDocumentExtensionsTest.cs @@ -32,10 +32,10 @@ public void GetAndSetTagHelpers_ReturnsTagHelpers() // Arrange var codeDocument = TestRazorCodeDocument.CreateEmpty(); - var expected = new[] - { + TagHelperCollection expected = + [ TagHelperDescriptorBuilder.CreateTagHelper("TestTagHelper", "TestAssembly").Build() - }; + ]; codeDocument.SetTagHelpers(expected); @@ -52,7 +52,7 @@ public void GetAndSetTagHelperContext_ReturnsTagHelperContext() // Arrange var codeDocument = TestRazorCodeDocument.CreateEmpty(); - var expected = TagHelperDocumentContext.Create(prefix: null, tagHelpers: []); + var expected = TagHelperDocumentContext.Create(tagHelpers: []); codeDocument.SetTagHelperContext(expected); // Act diff --git a/src/Compiler/Microsoft.AspNetCore.Razor.Language/test/TagHelperBinderTest.cs b/src/Compiler/Microsoft.AspNetCore.Razor.Language/test/TagHelperBinderTest.cs index b5e72bb7d24..6c9f4738086 100644 --- a/src/Compiler/Microsoft.AspNetCore.Razor.Language/test/TagHelperBinderTest.cs +++ b/src/Compiler/Microsoft.AspNetCore.Razor.Language/test/TagHelperBinderTest.cs @@ -1,12 +1,9 @@ // 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 System; using System.Collections.Generic; using System.Collections.Immutable; -using System.Linq; using Xunit; namespace Microsoft.AspNetCore.Razor.Language; @@ -20,25 +17,26 @@ public void GetBinding_ReturnsBindingWithInformation() var divTagHelper = TagHelperDescriptorBuilder.CreateTagHelper("DivTagHelper", "SomeAssembly") .TagMatchingRuleDescriptor(rule => rule.RequireTagName("div")) .Build(); - ImmutableArray expectedDescriptors = [divTagHelper]; + TagHelperCollection expectedTagHelpers = [divTagHelper]; var expectedAttributes = ImmutableArray.Create( new KeyValuePair("class", "something")); - var tagHelperBinder = new TagHelperBinder("th:", expectedDescriptors); + var binder = new TagHelperBinder("th:", expectedTagHelpers); // Act - var bindingResult = tagHelperBinder.GetBinding( + var binding = binder.GetBinding( tagName: "th:div", attributes: expectedAttributes, parentTagName: "body", parentIsTagHelper: false); // Assert - Assert.Equal(expectedDescriptors, bindingResult.Descriptors); - Assert.Equal("th:div", bindingResult.TagName); - Assert.Equal("body", bindingResult.ParentTagName); - Assert.Equal>(expectedAttributes, bindingResult.Attributes); - Assert.Equal("th:", bindingResult.TagNamePrefix); - Assert.Equal(divTagHelper.TagMatchingRules, bindingResult.GetBoundRules(divTagHelper)); + Assert.NotNull(binding); + Assert.Equal(expectedTagHelpers, binding.TagHelpers); + Assert.Equal("th:div", binding.TagName); + Assert.Equal("body", binding.ParentTagName); + Assert.Equal>(expectedAttributes, binding.Attributes); + Assert.Equal("th:", binding.TagNamePrefix); + Assert.Equal(divTagHelper.TagMatchingRules, binding.GetBoundRules(divTagHelper)); } [Fact] @@ -50,37 +48,37 @@ public void GetBinding_With_Multiple_TagNameRules_SingleHelper() .TagMatchingRuleDescriptor(rule => rule.RequireTagName("a")) .TagMatchingRuleDescriptor(rule => rule.RequireTagName("img")) .Build(); - ImmutableArray expectedDescriptors = [multiTagHelper]; - var tagHelperBinder = new TagHelperBinder("", expectedDescriptors); + TagHelperCollection expectedTagHelpers = [multiTagHelper]; + var binder = new TagHelperBinder("", expectedTagHelpers); TestTagName("div", multiTagHelper.TagMatchingRules[0]); TestTagName("a", multiTagHelper.TagMatchingRules[1]); TestTagName("img", multiTagHelper.TagMatchingRules[2]); TestTagName("p", null); TestTagName("*", null); - void TestTagName(string tagName, TagMatchingRuleDescriptor expectedBindingResult) + + void TestTagName(string tagName, TagMatchingRuleDescriptor? expectedBindingResult) { // Act - var bindingResult = tagHelperBinder.GetBinding( - + var binding = binder.GetBinding( tagName: tagName, - attributes: ImmutableArray>.Empty, + attributes: [], parentTagName: "body", parentIsTagHelper: false); // Assert if (expectedBindingResult == null) { - Assert.Null(bindingResult); + Assert.Null(binding); return; } else { - Assert.NotNull(bindingResult); - Assert.Equal(expectedDescriptors, bindingResult.Descriptors); + Assert.NotNull(binding); + Assert.Equal(expectedTagHelpers, binding.TagHelpers); - Assert.Equal(tagName, bindingResult.TagName); - var mapping = Assert.Single(bindingResult.GetBoundRules(multiTagHelper)); + Assert.Equal(tagName, binding.TagName); + var mapping = Assert.Single(binding.GetBoundRules(multiTagHelper)); Assert.Equal(expectedBindingResult, mapping); } } @@ -102,7 +100,7 @@ public void GetBinding_With_Multiple_TagNameRules_MultipleHelpers() .TagMatchingRuleDescriptor(rule => rule.RequireTagName("table")) .Build(); - var tagHelperBinder = new TagHelperBinder("", [multiTagHelper1, multiTagHelper2]); + var binder = new TagHelperBinder("", [multiTagHelper1, multiTagHelper2]); TestTagName("div", [multiTagHelper1, multiTagHelper2], [multiTagHelper1.TagMatchingRules[0], multiTagHelper2.TagMatchingRules[0]]); TestTagName("a", [multiTagHelper1], [multiTagHelper1.TagMatchingRules[1]]); @@ -111,38 +109,38 @@ public void GetBinding_With_Multiple_TagNameRules_MultipleHelpers() TestTagName("table", [multiTagHelper2], [multiTagHelper2.TagMatchingRules[2]]); TestTagName("*", null, null); - - void TestTagName(string tagName, TagHelperDescriptor[] expectedDescriptors, TagMatchingRuleDescriptor[] expectedBindingResults) + void TestTagName(string tagName, TagHelperCollection? expectedTagHelpers, TagMatchingRuleDescriptor[]? expectedBindingResults) { // Act - var bindingResult = tagHelperBinder.GetBinding( + var binding = binder.GetBinding( tagName: tagName, attributes: [], parentTagName: "body", parentIsTagHelper: false); // Assert - if (expectedDescriptors is null) + if (expectedTagHelpers is null) { - Assert.Null(bindingResult); + Assert.Null(binding); } else { - Assert.NotNull(bindingResult); - Assert.Equal(expectedDescriptors, bindingResult.Descriptors); + Assert.NotNull(binding); + Assert.Equal(expectedTagHelpers, binding.TagHelpers); + Assert.NotNull(expectedBindingResults); - Assert.Equal(tagName, bindingResult.TagName); + Assert.Equal(tagName, binding.TagName); - for (int i = 0; i < expectedDescriptors.Length; i++) + for (var i = 0; i < expectedTagHelpers.Count; i++) { - var mapping = Assert.Single(bindingResult.GetBoundRules(expectedDescriptors[i])); + var mapping = Assert.Single(binding.GetBoundRules(expectedTagHelpers[i])); Assert.Equal(expectedBindingResults[i], mapping); } } } } - public static TheoryData RequiredParentData + public static TheoryData RequiredParentData { get { @@ -163,37 +161,34 @@ public static TheoryData RequiredParentData .RequireParentTag("p")) .Build(); - return new TheoryData< - string, // tagName - string, // parentTagName - ImmutableArray, // availableDescriptors - ImmutableArray> // expectedDescriptors + // tagName, parentTagName, availableTagHelpers, expectedTagHelpers + return new() + { + { + "strong", + "p", + [strongPDivParent], + [strongPDivParent] + }, { - { - "strong", - "p", - [strongPDivParent], - [strongPDivParent] - }, - { - "strong", - "div", - [strongPDivParent, catchAllPParent], - [strongPDivParent] - }, - { - "strong", - "p", - [strongPDivParent, catchAllPParent], - [strongPDivParent, catchAllPParent] - }, - { - "custom", - "p", - [strongPDivParent, catchAllPParent], - [catchAllPParent] - }, - }; + "strong", + "div", + [strongPDivParent, catchAllPParent], + [strongPDivParent] + }, + { + "strong", + "p", + [strongPDivParent, catchAllPParent], + [strongPDivParent, catchAllPParent] + }, + { + "custom", + "p", + [strongPDivParent, catchAllPParent], + [catchAllPParent] + } + }; } } @@ -202,24 +197,25 @@ public static TheoryData RequiredParentData public void GetBinding_ReturnsBindingResultWithDescriptorsParentTags( string tagName, string parentTagName, - ImmutableArray availableDescriptors, - ImmutableArray expectedDescriptors) + TagHelperCollection availableTagHelpers, + TagHelperCollection expectedTagHelpers) { // Arrange - var tagHelperBinder = new TagHelperBinder(null, availableDescriptors); + var binder = new TagHelperBinder(null, availableTagHelpers); // Act - var bindingResult = tagHelperBinder.GetBinding( + var binding = binder.GetBinding( tagName, - attributes: ImmutableArray>.Empty, + attributes: [], parentTagName: parentTagName, parentIsTagHelper: false); // Assert - Assert.Equal(expectedDescriptors, bindingResult.Descriptors); + Assert.NotNull(binding); + Assert.Equal(expectedTagHelpers, binding.TagHelpers); } - public static TheoryData RequiredAttributeData + public static TheoryData>, TagHelperCollection, TagHelperCollection?> RequiredAttributeData { get { @@ -257,100 +253,97 @@ public static TheoryData RequiredAttributeData .RequireAttributeDescriptor(attribute => attribute .Name("prefix-", RequiredAttributeNameComparison.PrefixMatch))) .Build(); - ImmutableArray defaultAvailableDescriptors = + TagHelperCollection defaultAvailableDescriptors = [divDescriptor, inputDescriptor, catchAllDescriptor, catchAllDescriptor2]; - ImmutableArray defaultWildcardDescriptors = + TagHelperCollection defaultWildcardDescriptors = [inputWildcardPrefixDescriptor, catchAllWildcardPrefixDescriptor]; Func> kvp = (name) => new KeyValuePair(name, "test value"); - return new TheoryData< - string, // tagName - ImmutableArray>, // providedAttributes - ImmutableArray, // availableDescriptors - ImmutableArray> // expectedDescriptors + // tagName, providedAttributes, availableTagHelpers, expectedTagHelpers + return new() + { + { + "div", + ImmutableArray.Create(kvp("custom")), + defaultAvailableDescriptors, + default + }, + { "div", ImmutableArray.Create(kvp("style")), defaultAvailableDescriptors, [divDescriptor] }, + { "div", ImmutableArray.Create(kvp("class")), defaultAvailableDescriptors, [catchAllDescriptor] }, + { + "div", + ImmutableArray.Create(kvp("class"), kvp("style")), + defaultAvailableDescriptors, + [divDescriptor, catchAllDescriptor] + }, + { + "div", + ImmutableArray.Create(kvp("class"), kvp("style"), kvp("custom")), + defaultAvailableDescriptors, + [divDescriptor, catchAllDescriptor, catchAllDescriptor2] + }, { - { - "div", - ImmutableArray.Create(kvp("custom")), - defaultAvailableDescriptors, - default - }, - { "div", ImmutableArray.Create(kvp("style")), defaultAvailableDescriptors, [divDescriptor] }, - { "div", ImmutableArray.Create(kvp("class")), defaultAvailableDescriptors, [catchAllDescriptor] }, - { - "div", - ImmutableArray.Create(kvp("class"), kvp("style")), - defaultAvailableDescriptors, - [divDescriptor, catchAllDescriptor] - }, - { - "div", - ImmutableArray.Create(kvp("class"), kvp("style"), kvp("custom")), - defaultAvailableDescriptors, - [divDescriptor, catchAllDescriptor, catchAllDescriptor2] - }, - { - "input", - ImmutableArray.Create(kvp("class"), kvp("style")), - defaultAvailableDescriptors, - [inputDescriptor, catchAllDescriptor] - }, - { - "input", - ImmutableArray.Create(kvp("nodashprefixA")), - defaultWildcardDescriptors, - [inputWildcardPrefixDescriptor] - }, - { - "input", - ImmutableArray.Create(kvp("nodashprefix-ABC-DEF"), kvp("random")), - defaultWildcardDescriptors, - [inputWildcardPrefixDescriptor] - }, - { - "input", - ImmutableArray.Create(kvp("prefixABCnodashprefix")), - defaultWildcardDescriptors, - default - }, - { - "input", - ImmutableArray.Create(kvp("prefix-")), - defaultWildcardDescriptors, - default - }, - { - "input", - ImmutableArray.Create(kvp("nodashprefix")), - defaultWildcardDescriptors, - default - }, - { - "input", - ImmutableArray.Create(kvp("prefix-A")), - defaultWildcardDescriptors, - [catchAllWildcardPrefixDescriptor] - }, - { - "input", - ImmutableArray.Create(kvp("prefix-ABC-DEF"), kvp("random")), - defaultWildcardDescriptors, - [catchAllWildcardPrefixDescriptor] - }, - { - "input", - ImmutableArray.Create(kvp("prefix-abc"), kvp("nodashprefix-def")), - defaultWildcardDescriptors, - [inputWildcardPrefixDescriptor, catchAllWildcardPrefixDescriptor] - }, - { - "input", - ImmutableArray.Create(kvp("class"), kvp("prefix-abc"), kvp("onclick"), kvp("nodashprefix-def"), kvp("style")), - defaultWildcardDescriptors, - [inputWildcardPrefixDescriptor, catchAllWildcardPrefixDescriptor] - }, - }; + "input", + ImmutableArray.Create(kvp("class"), kvp("style")), + defaultAvailableDescriptors, + [inputDescriptor, catchAllDescriptor] + }, + { + "input", + ImmutableArray.Create(kvp("nodashprefixA")), + defaultWildcardDescriptors, + [inputWildcardPrefixDescriptor] + }, + { + "input", + ImmutableArray.Create(kvp("nodashprefix-ABC-DEF"), kvp("random")), + defaultWildcardDescriptors, + [inputWildcardPrefixDescriptor] + }, + { + "input", + ImmutableArray.Create(kvp("prefixABCnodashprefix")), + defaultWildcardDescriptors, + null + }, + { + "input", + ImmutableArray.Create(kvp("prefix-")), + defaultWildcardDescriptors, + null + }, + { + "input", + ImmutableArray.Create(kvp("nodashprefix")), + defaultWildcardDescriptors, + null + }, + { + "input", + ImmutableArray.Create(kvp("prefix-A")), + defaultWildcardDescriptors, + [catchAllWildcardPrefixDescriptor] + }, + { + "input", + ImmutableArray.Create(kvp("prefix-ABC-DEF"), kvp("random")), + defaultWildcardDescriptors, + [catchAllWildcardPrefixDescriptor] + }, + { + "input", + ImmutableArray.Create(kvp("prefix-abc"), kvp("nodashprefix-def")), + defaultWildcardDescriptors, + [inputWildcardPrefixDescriptor, catchAllWildcardPrefixDescriptor] + }, + { + "input", + ImmutableArray.Create(kvp("class"), kvp("prefix-abc"), kvp("onclick"), kvp("nodashprefix-def"), kvp("style")), + defaultWildcardDescriptors, + [inputWildcardPrefixDescriptor, catchAllWildcardPrefixDescriptor] + }, + }; } } @@ -359,24 +352,24 @@ public static TheoryData RequiredAttributeData public void GetBinding_ReturnsBindingResultDescriptorsWithRequiredAttributes( string tagName, ImmutableArray> providedAttributes, - ImmutableArray availableDescriptors, - ImmutableArray expectedDescriptors) + TagHelperCollection availableTagHelpers, + TagHelperCollection? expectedTagHelpers) { // Arrange - var tagHelperBinder = new TagHelperBinder(null, availableDescriptors); + var binder = new TagHelperBinder(null, availableTagHelpers); // Act - var bindingResult = tagHelperBinder.GetBinding(tagName, providedAttributes, parentTagName: "p", parentIsTagHelper: false); - var descriptors = bindingResult?.Descriptors ?? default; + var binding = binder.GetBinding(tagName, providedAttributes, parentTagName: "p", parentIsTagHelper: false); + var tagHelpers = binding?.TagHelpers; // Assert - if (expectedDescriptors.IsDefault) + if (expectedTagHelpers is null) { - Assert.True(descriptors.IsDefault); + Assert.Null(tagHelpers); } else { - Assert.Equal(expectedDescriptors, descriptors); + Assert.Equal(expectedTagHelpers, tagHelpers); } } @@ -384,72 +377,75 @@ public void GetBinding_ReturnsBindingResultDescriptorsWithRequiredAttributes( public void GetBinding_ReturnsNullBindingResultPrefixAsTagName() { // Arrange - var catchAllDescriptor = TagHelperDescriptorBuilder.CreateTagHelper("foo1", "SomeAssembly") + var catchAllTagHelper = TagHelperDescriptorBuilder.CreateTagHelper("foo1", "SomeAssembly") .TagMatchingRuleDescriptor(rule => rule.RequireTagName(TagHelperMatchingConventions.ElementCatchAllName)) .Build(); - ImmutableArray descriptors = [catchAllDescriptor]; - var tagHelperBinder = new TagHelperBinder("th", descriptors); + TagHelperCollection tagHelpers = [catchAllTagHelper]; + var tagHelperBinder = new TagHelperBinder("th", tagHelpers); // Act - var bindingResult = tagHelperBinder.GetBinding( + var binding = tagHelperBinder.GetBinding( tagName: "th", - attributes: ImmutableArray>.Empty, + attributes: [], parentTagName: "p", parentIsTagHelper: false); // Assert - Assert.Null(bindingResult); + Assert.Null(binding); } [Fact] public void GetBinding_ReturnsBindingResultCatchAllDescriptorsForPrefixedTags() { // Arrange - var catchAllDescriptor = TagHelperDescriptorBuilder.CreateTagHelper("foo1", "SomeAssembly") + var catchAllTagHelper = TagHelperDescriptorBuilder.CreateTagHelper("foo1", "SomeAssembly") .TagMatchingRuleDescriptor(rule => rule.RequireTagName(TagHelperMatchingConventions.ElementCatchAllName)) .Build(); - ImmutableArray descriptors = [catchAllDescriptor]; - var tagHelperBinder = new TagHelperBinder("th:", descriptors); + TagHelperCollection tagHelpers = [catchAllTagHelper]; + var tagHelperBinder = new TagHelperBinder("th:", tagHelpers); // Act - var bindingResultDiv = tagHelperBinder.GetBinding( + var bindingDiv = tagHelperBinder.GetBinding( tagName: "th:div", - attributes: ImmutableArray>.Empty, + attributes: [], parentTagName: "p", parentIsTagHelper: false); - var bindingResultSpan = tagHelperBinder.GetBinding( + var bindingSpan = tagHelperBinder.GetBinding( tagName: "th:span", - attributes: ImmutableArray>.Empty, + attributes: [], parentTagName: "p", parentIsTagHelper: false); // Assert - var descriptor = Assert.Single(bindingResultDiv.Descriptors); - Assert.Same(catchAllDescriptor, descriptor); - descriptor = Assert.Single(bindingResultSpan.Descriptors); - Assert.Same(catchAllDescriptor, descriptor); + Assert.NotNull(bindingDiv); + var tagHelper = Assert.Single(bindingDiv.TagHelpers); + Assert.Same(catchAllTagHelper, tagHelper); + Assert.NotNull(bindingSpan); + tagHelper = Assert.Single(bindingSpan.TagHelpers); + Assert.Same(catchAllTagHelper, tagHelper); } [Fact] public void GetBinding_ReturnsBindingResultDescriptorsForPrefixedTags() { // Arrange - var divDescriptor = TagHelperDescriptorBuilder.CreateTagHelper("foo1", "SomeAssembly") + var divTagHelper = TagHelperDescriptorBuilder.CreateTagHelper("foo1", "SomeAssembly") .TagMatchingRuleDescriptor(rule => rule.RequireTagName("div")) .Build(); - ImmutableArray descriptors = [divDescriptor]; - var tagHelperBinder = new TagHelperBinder("th:", descriptors); + TagHelperCollection tagHelpers = [divTagHelper]; + var tagHelperBinder = new TagHelperBinder("th:", tagHelpers); // Act - var bindingResult = tagHelperBinder.GetBinding( + var binding = tagHelperBinder.GetBinding( tagName: "th:div", - attributes: ImmutableArray>.Empty, + attributes: [], parentTagName: "p", parentIsTagHelper: false); // Assert - var descriptor = Assert.Single(bindingResult.Descriptors); - Assert.Same(divDescriptor, descriptor); + Assert.NotNull(binding); + var tagHelper = Assert.Single(binding.TagHelpers); + Assert.Same(divTagHelper, tagHelper); } [Theory] @@ -458,114 +454,117 @@ public void GetBinding_ReturnsBindingResultDescriptorsForPrefixedTags() public void GetBinding_ReturnsNullForUnprefixedTags(string tagName) { // Arrange - var divDescriptor = TagHelperDescriptorBuilder.CreateTagHelper("foo1", "SomeAssembly") + var divTagHelper = TagHelperDescriptorBuilder.CreateTagHelper("foo1", "SomeAssembly") .TagMatchingRuleDescriptor(rule => rule.RequireTagName(tagName)) .Build(); - ImmutableArray descriptors = [divDescriptor]; - var tagHelperBinder = new TagHelperBinder("th:", descriptors); + TagHelperCollection tagHelpers = [divTagHelper]; + var binder = new TagHelperBinder("th:", tagHelpers); // Act - var bindingResult = tagHelperBinder.GetBinding( + var binding = binder.GetBinding( tagName: "div", - attributes: ImmutableArray>.Empty, + attributes: [], parentTagName: "p", parentIsTagHelper: false); // Assert - Assert.Null(bindingResult); + Assert.Null(binding); } [Fact] public void GetDescriptors_ReturnsNothingForUnregisteredTags() { // Arrange - var divDescriptor = TagHelperDescriptorBuilder.CreateTagHelper("foo1", "SomeAssembly") + var divTagHelper = TagHelperDescriptorBuilder.CreateTagHelper("foo1", "SomeAssembly") .TagMatchingRuleDescriptor(rule => rule.RequireTagName("div")) .Build(); - var spanDescriptor = TagHelperDescriptorBuilder.CreateTagHelper("foo2", "SomeAssembly") + var spanTagHelper = TagHelperDescriptorBuilder.CreateTagHelper("foo2", "SomeAssembly") .TagMatchingRuleDescriptor(rule => rule.RequireTagName("span")) .Build(); - ImmutableArray descriptors = [divDescriptor, spanDescriptor]; - var tagHelperBinder = new TagHelperBinder(null, descriptors); + TagHelperCollection tagHelpers = [divTagHelper, spanTagHelper]; + var binder = new TagHelperBinder(null, tagHelpers); // Act - var tagHelperBinding = tagHelperBinder.GetBinding( + var binding = binder.GetBinding( tagName: "foo", - attributes: ImmutableArray>.Empty, + attributes: [], parentTagName: "p", parentIsTagHelper: false); // Assert - Assert.Null(tagHelperBinding); + Assert.Null(binding); } [Fact] public void GetDescriptors_ReturnsCatchAllsWithEveryTagName() { // Arrange - var divDescriptor = TagHelperDescriptorBuilder.CreateTagHelper("foo1", "SomeAssembly") + var divTagHelper = TagHelperDescriptorBuilder.CreateTagHelper("foo1", "SomeAssembly") .TagMatchingRuleDescriptor(rule => rule.RequireTagName("div")) .Build(); - var spanDescriptor = TagHelperDescriptorBuilder.CreateTagHelper("foo2", "SomeAssembly") + var spanTagHelper = TagHelperDescriptorBuilder.CreateTagHelper("foo2", "SomeAssembly") .TagMatchingRuleDescriptor(rule => rule.RequireTagName("span")) .Build(); - var catchAllDescriptor = TagHelperDescriptorBuilder.CreateTagHelper("foo3", "SomeAssembly") + var catchAllTagHelper = TagHelperDescriptorBuilder.CreateTagHelper("foo3", "SomeAssembly") .TagMatchingRuleDescriptor(rule => rule.RequireTagName(TagHelperMatchingConventions.ElementCatchAllName)) .Build(); - ImmutableArray descriptors = [divDescriptor, spanDescriptor, catchAllDescriptor]; - var tagHelperBinder = new TagHelperBinder(null, descriptors); + TagHelperCollection tagHelpers = [divTagHelper, spanTagHelper, catchAllTagHelper]; + var binder = new TagHelperBinder(null, tagHelpers); // Act - var divBinding = tagHelperBinder.GetBinding( + var divBinding = binder.GetBinding( tagName: "div", - attributes: ImmutableArray>.Empty, + attributes: [], parentTagName: "p", parentIsTagHelper: false); - var spanBinding = tagHelperBinder.GetBinding( + var spanBinding = binder.GetBinding( tagName: "span", - attributes: ImmutableArray>.Empty, + attributes: [], parentTagName: "p", parentIsTagHelper: false); // Assert // For divs - Assert.Equal(2, divBinding.Descriptors.Count()); - Assert.Contains(divDescriptor, divBinding.Descriptors); - Assert.Contains(catchAllDescriptor, divBinding.Descriptors); + Assert.NotNull(divBinding); + Assert.Equal(2, divBinding.TagHelpers.Count); + Assert.Contains(divTagHelper, divBinding.TagHelpers); + Assert.Contains(catchAllTagHelper, divBinding.TagHelpers); // For spans - Assert.Equal(2, spanBinding.Descriptors.Count()); - Assert.Contains(spanDescriptor, spanBinding.Descriptors); - Assert.Contains(catchAllDescriptor, spanBinding.Descriptors); + Assert.NotNull(spanBinding); + Assert.Equal(2, spanBinding.TagHelpers.Count); + Assert.Contains(spanTagHelper, spanBinding.TagHelpers); + Assert.Contains(catchAllTagHelper, spanBinding.TagHelpers); } [Fact] public void GetDescriptors_DuplicateDescriptorsAreNotPartOfTagHelperDescriptorPool() { // Arrange - var divDescriptor = TagHelperDescriptorBuilder.CreateTagHelper("foo1", "SomeAssembly") + var divTagHelper = TagHelperDescriptorBuilder.CreateTagHelper("foo1", "SomeAssembly") .TagMatchingRuleDescriptor(rule => rule.RequireTagName("div")) .Build(); - ImmutableArray descriptors = [divDescriptor, divDescriptor]; - var tagHelperBinder = new TagHelperBinder(null, descriptors); + TagHelperCollection tagHelpers = [divTagHelper, divTagHelper]; + var binder = new TagHelperBinder(null, tagHelpers); // Act - var bindingResult = tagHelperBinder.GetBinding( + var binding = binder.GetBinding( tagName: "div", - attributes: ImmutableArray>.Empty, + attributes: [], parentTagName: "p", parentIsTagHelper: false); // Assert - var descriptor = Assert.Single(bindingResult.Descriptors); - Assert.Same(divDescriptor, descriptor); + Assert.NotNull(binding); + var tagHelper = Assert.Single(binding.TagHelpers); + Assert.Same(divTagHelper, tagHelper); } [Fact] public void GetBinding_DescriptorWithMultipleRules_CorrectlySelectsMatchingRules() { // Arrange - var multiRuleDescriptor = TagHelperDescriptorBuilder.CreateTagHelper("foo", "SomeAssembly") + var multiRuleTagHelper = TagHelperDescriptorBuilder.CreateTagHelper("foo", "SomeAssembly") .TagMatchingRuleDescriptor(rule => rule .RequireTagName(TagHelperMatchingConventions.ElementCatchAllName) .RequireParentTag("body")) @@ -574,20 +573,21 @@ public void GetBinding_DescriptorWithMultipleRules_CorrectlySelectsMatchingRules .TagMatchingRuleDescriptor(rule => rule .RequireTagName("span")) .Build(); - ImmutableArray descriptors = [multiRuleDescriptor]; - var tagHelperBinder = new TagHelperBinder(null, descriptors); + TagHelperCollection tagHelper = [multiRuleTagHelper]; + var binder = new TagHelperBinder(null, tagHelper); // Act - var binding = tagHelperBinder.GetBinding( + var binding = binder.GetBinding( tagName: "div", - attributes: ImmutableArray>.Empty, + attributes: [], parentTagName: "p", parentIsTagHelper: false); // Assert - var boundDescriptor = Assert.Single(binding.Descriptors); - Assert.Same(multiRuleDescriptor, boundDescriptor); - var boundRules = binding.GetBoundRules(boundDescriptor); + Assert.NotNull(binding); + var boundTagHelper = Assert.Single(binding.TagHelpers); + Assert.Same(multiRuleTagHelper, boundTagHelper); + var boundRules = binding.GetBoundRules(boundTagHelper); var boundRule = Assert.Single(boundRules); Assert.Equal("div", boundRule.TagName); } @@ -596,26 +596,27 @@ public void GetBinding_DescriptorWithMultipleRules_CorrectlySelectsMatchingRules public void GetBinding_PrefixedParent_ReturnsBinding() { // Arrange - var divDescriptor = TagHelperDescriptorBuilder.CreateTagHelper("foo1", "SomeAssembly") + var divTagHelper = TagHelperDescriptorBuilder.CreateTagHelper("foo1", "SomeAssembly") .TagMatchingRuleDescriptor(rule => rule.RequireTagName("div").RequireParentTag("p")) .Build(); - var pDescriptor = TagHelperDescriptorBuilder.CreateTagHelper("foo2", "SomeAssembly") + var pTagHelper = TagHelperDescriptorBuilder.CreateTagHelper("foo2", "SomeAssembly") .TagMatchingRuleDescriptor(rule => rule.RequireTagName("p")) .Build(); - ImmutableArray descriptors = [divDescriptor, pDescriptor]; - var tagHelperBinder = new TagHelperBinder("th:", descriptors); + TagHelperCollection tagHelpers = [divTagHelper, pTagHelper]; + var binder = new TagHelperBinder("th:", tagHelpers); // Act - var bindingResult = tagHelperBinder.GetBinding( + var binding = binder.GetBinding( tagName: "th:div", - attributes: ImmutableArray>.Empty, + attributes: [], parentTagName: "th:p", parentIsTagHelper: true); // Assert - var boundDescriptor = Assert.Single(bindingResult.Descriptors); - Assert.Same(divDescriptor, boundDescriptor); - var boundRules = bindingResult.GetBoundRules(boundDescriptor); + Assert.NotNull(binding); + var boundTagHelper = Assert.Single(binding.TagHelpers); + Assert.Same(divTagHelper, boundTagHelper); + var boundRules = binding.GetBoundRules(boundTagHelper); var boundRule = Assert.Single(boundRules); Assert.Equal("div", boundRule.TagName); Assert.Equal("p", boundRule.ParentTag); @@ -625,78 +626,81 @@ public void GetBinding_PrefixedParent_ReturnsBinding() public void GetBinding_IsAttributeMatch_SingleAttributeMatch() { // Arrange - var divDescriptor = TagHelperDescriptorBuilder.CreateTagHelper("foo1", "SomeAssembly") + var divTagHelper = TagHelperDescriptorBuilder.CreateTagHelper("foo1", "SomeAssembly") .ClassifyAttributesOnly(true) .TagMatchingRuleDescriptor(rule => rule.RequireTagName("div")) .Build(); - ImmutableArray descriptors = [divDescriptor]; - var tagHelperBinder = new TagHelperBinder("", descriptors); + TagHelperCollection tagHelpers = [divTagHelper]; + var binder = new TagHelperBinder("", tagHelpers); // Act - var bindingResult = tagHelperBinder.GetBinding( + var binding = binder.GetBinding( tagName: "div", - attributes: ImmutableArray>.Empty, + attributes: [], parentTagName: "p", parentIsTagHelper: false); // Assert - Assert.True(bindingResult.IsAttributeMatch); + Assert.NotNull(binding); + Assert.True(binding.IsAttributeMatch); } [Fact] public void GetBinding_IsAttributeMatch_MultipleAttributeMatches() { // Arrange - var divDescriptor1 = TagHelperDescriptorBuilder.CreateTagHelper("foo1", "SomeAssembly") + var divTagHelper1 = TagHelperDescriptorBuilder.CreateTagHelper("foo1", "SomeAssembly") .ClassifyAttributesOnly(true) .TagMatchingRuleDescriptor(rule => rule.RequireTagName("div")) .Build(); - var divDescriptor2 = TagHelperDescriptorBuilder.CreateTagHelper("foo1", "SomeAssembly") + var divTagHelper2 = TagHelperDescriptorBuilder.CreateTagHelper("foo1", "SomeAssembly") .ClassifyAttributesOnly(true) .TagMatchingRuleDescriptor(rule => rule.RequireTagName("div")) .Build(); - ImmutableArray descriptors = [divDescriptor1, divDescriptor2]; - var tagHelperBinder = new TagHelperBinder("", descriptors); + TagHelperCollection tagHelpers = [divTagHelper1, divTagHelper2]; + var binder = new TagHelperBinder("", tagHelpers); // Act - var bindingResult = tagHelperBinder.GetBinding( + var binding = binder.GetBinding( tagName: "div", - attributes: ImmutableArray>.Empty, + attributes: [], parentTagName: "p", parentIsTagHelper: false); // Assert - Assert.True(bindingResult.IsAttributeMatch); + Assert.NotNull(binding); + Assert.True(binding.IsAttributeMatch); } [Fact] public void GetBinding_IsAttributeMatch_MixedAttributeMatches() { // Arrange - var divDescriptor1 = TagHelperDescriptorBuilder.CreateTagHelper("foo1", "SomeAssembly") + var divTagHelper1 = TagHelperDescriptorBuilder.CreateTagHelper("foo1", "SomeAssembly") .ClassifyAttributesOnly(true) .TagMatchingRuleDescriptor(rule => rule.RequireTagName("div")) .Build(); - var divDescriptor2 = TagHelperDescriptorBuilder.CreateTagHelper("foo1", "SomeAssembly") + var divTagHelper2 = TagHelperDescriptorBuilder.CreateTagHelper("foo1", "SomeAssembly") .TagMatchingRuleDescriptor(rule => rule.RequireTagName("div")) .Build(); - ImmutableArray descriptors = [divDescriptor1, divDescriptor2]; - var tagHelperBinder = new TagHelperBinder("", descriptors); + TagHelperCollection tagHelpers = [divTagHelper1, divTagHelper2]; + var tagHelperBinder = new TagHelperBinder("", tagHelpers); // Act - var bindingResult = tagHelperBinder.GetBinding( + var binding = tagHelperBinder.GetBinding( tagName: "div", - attributes: ImmutableArray>.Empty, + attributes: [], parentTagName: "p", parentIsTagHelper: false); // Assert - Assert.False(bindingResult.IsAttributeMatch); + Assert.NotNull(binding); + Assert.False(binding.IsAttributeMatch); } [Fact] @@ -707,20 +711,20 @@ public void GetBinding_CaseSensitiveRule_CaseMismatch_ReturnsNull() .TagMatchingRuleDescriptor(rule => rule.RequireTagName("div")) .SetCaseSensitive() .Build(); - ImmutableArray expectedDescriptors = [divTagHelper]; + TagHelperCollection expectedTagHelpers = [divTagHelper]; var expectedAttributes = ImmutableArray.Create( new KeyValuePair("class", "something")); - var tagHelperBinder = new TagHelperBinder("th:", expectedDescriptors); + var binder = new TagHelperBinder("th:", expectedTagHelpers); // Act - var bindingResult = tagHelperBinder.GetBinding( + var binding = binder.GetBinding( tagName: "th:Div", attributes: expectedAttributes, parentTagName: "body", parentIsTagHelper: false); // Assert - Assert.Null(bindingResult); + Assert.Null(binding); } [Fact] @@ -733,19 +737,19 @@ public void GetBinding_CaseSensitiveRequiredAttribute_CaseMismatch_ReturnsNull() .RequireAttributeDescriptor(attribute => attribute.Name("class"))) .SetCaseSensitive() .Build(); - ImmutableArray expectedDescriptors = [divTagHelper]; + TagHelperCollection expectedTagHelpers = [divTagHelper]; var expectedAttributes = ImmutableArray.Create( new KeyValuePair("CLASS", "something")); - var tagHelperBinder = new TagHelperBinder(null, expectedDescriptors); + var binder = new TagHelperBinder(null, expectedTagHelpers); // Act - var bindingResult = tagHelperBinder.GetBinding( + var binding = binder.GetBinding( tagName: "div", attributes: expectedAttributes, parentTagName: "body", parentIsTagHelper: false); // Assert - Assert.Null(bindingResult); + Assert.Null(binding); } } diff --git a/src/Compiler/Microsoft.CodeAnalysis.Razor.Compiler/src/CSharp/CompilationTagHelperFeature.cs b/src/Compiler/Microsoft.CodeAnalysis.Razor.Compiler/src/CSharp/CompilationTagHelperFeature.cs index 9e52ee57431..40f8909b4d3 100644 --- a/src/Compiler/Microsoft.CodeAnalysis.Razor.Compiler/src/CSharp/CompilationTagHelperFeature.cs +++ b/src/Compiler/Microsoft.CodeAnalysis.Razor.Compiler/src/CSharp/CompilationTagHelperFeature.cs @@ -15,7 +15,7 @@ public sealed class CompilationTagHelperFeature : RazorEngineFeatureBase, ITagHe private ImmutableArray _providers; private IMetadataReferenceFeature? _referenceFeature; - public IReadOnlyList GetDescriptors(CancellationToken cancellationToken = default) + public TagHelperCollection GetTagHelpers(CancellationToken cancellationToken = default) { var compilation = CSharpCompilation.Create("__TagHelpers", references: _referenceFeature?.References); if (!IsValidCompilation(compilation)) @@ -23,15 +23,15 @@ public IReadOnlyList GetDescriptors(CancellationToken cance return []; } - var results = new List(); - var context = new TagHelperDescriptorProviderContext(compilation, results); + using var builder = new TagHelperCollection.Builder(); + var context = new TagHelperDescriptorProviderContext(compilation, builder); foreach (var provider in _providers) { provider.Execute(context, cancellationToken); } - return results; + return builder.ToCollection(); } protected override void OnInitialized() diff --git a/src/Compiler/Microsoft.CodeAnalysis.Razor.Compiler/src/Language/DefaultRazorIntermediateNodeLoweringPhase.cs b/src/Compiler/Microsoft.CodeAnalysis.Razor.Compiler/src/Language/DefaultRazorIntermediateNodeLoweringPhase.cs index 8f100de820f..24a45e86fd1 100644 --- a/src/Compiler/Microsoft.CodeAnalysis.Razor.Compiler/src/Language/DefaultRazorIntermediateNodeLoweringPhase.cs +++ b/src/Compiler/Microsoft.CodeAnalysis.Razor.Compiler/src/Language/DefaultRazorIntermediateNodeLoweringPhase.cs @@ -1035,7 +1035,7 @@ public override void VisitMarkupTagHelperElement(MarkupTagHelperElementSyntax no TagName = tagName, TagMode = info.TagMode, Source = BuildSourceSpanFromNode(node), - TagHelpers = info.BindingResult.Descriptors + TagHelpers = info.BindingResult.TagHelpers }; _builder.Push(tagHelperNode); @@ -1080,11 +1080,11 @@ public override void VisitMarkupMinimizedTagHelperAttribute(MarkupMinimizedTagHe } var element = node.FirstAncestorOrSelf(); - var descriptors = element.TagHelperInfo.BindingResult.Descriptors; + var tagHelpers = element.TagHelperInfo.BindingResult.TagHelpers; var attributeName = node.Name.GetContent(); using var matches = new PooledArrayBuilder(); - TagHelperMatchingConventions.GetAttributeMatches(descriptors, attributeName, ref matches.AsRef()); + TagHelperMatchingConventions.GetAttributeMatches(tagHelpers, attributeName, ref matches.AsRef()); if (matches.Any() && _renderedBoundAttributeNames.Add(attributeName)) { @@ -1121,12 +1121,12 @@ public override void VisitMarkupMinimizedTagHelperAttribute(MarkupMinimizedTagHe public override void VisitMarkupTagHelperAttribute(MarkupTagHelperAttributeSyntax node) { var element = node.FirstAncestorOrSelf(); - var descriptors = element.TagHelperInfo.BindingResult.Descriptors; + var tagHelpers = element.TagHelperInfo.BindingResult.TagHelpers; var attributeName = node.Name.GetContent(); var attributeValueNode = node.Value; using var matches = new PooledArrayBuilder(); - TagHelperMatchingConventions.GetAttributeMatches(descriptors, attributeName, ref matches.AsRef()); + TagHelperMatchingConventions.GetAttributeMatches(tagHelpers, attributeName, ref matches.AsRef()); if (matches.Any() && _renderedBoundAttributeNames.Add(attributeName)) { @@ -1753,7 +1753,7 @@ public override void VisitMarkupTagHelperElement(MarkupTagHelperElementSyntax no TagName = tagName, TagMode = info.TagMode, Source = BuildSourceSpanFromNode(node), - TagHelpers = info.BindingResult.Descriptors, + TagHelpers = info.BindingResult.TagHelpers, StartTagSpan = node.StartTag.Name.GetSourceSpan(SourceDocument) }; @@ -1828,11 +1828,11 @@ public override void VisitMarkupMinimizedTagHelperAttribute(MarkupMinimizedTagHe } var element = node.FirstAncestorOrSelf(); - var descriptors = element.TagHelperInfo.BindingResult.Descriptors; + var tagHelpers = element.TagHelperInfo.BindingResult.TagHelpers; var attributeName = node.Name.GetContent(); using var matches = new PooledArrayBuilder(); - TagHelperMatchingConventions.GetAttributeMatches(descriptors, attributeName, ref matches.AsRef()); + TagHelperMatchingConventions.GetAttributeMatches(tagHelpers, attributeName, ref matches.AsRef()); if (matches.Any() && _renderedBoundAttributeNames.Add(attributeName)) { @@ -1877,11 +1877,11 @@ public override void VisitMarkupMinimizedTagHelperDirectiveAttribute(MarkupMinim } var element = node.FirstAncestorOrSelf(); - var descriptors = element.TagHelperInfo.BindingResult.Descriptors; + var tagHelpers = element.TagHelperInfo.BindingResult.TagHelpers; var attributeName = node.FullName; using var matches = new PooledArrayBuilder(); - TagHelperMatchingConventions.GetAttributeMatches(descriptors, attributeName, ref matches.AsRef()); + TagHelperMatchingConventions.GetAttributeMatches(tagHelpers, attributeName, ref matches.AsRef()); if (matches.Any() && _renderedBoundAttributeNames.Add(attributeName)) { @@ -1930,12 +1930,12 @@ public override void VisitMarkupMinimizedTagHelperDirectiveAttribute(MarkupMinim public override void VisitMarkupTagHelperAttribute(MarkupTagHelperAttributeSyntax node) { var element = node.FirstAncestorOrSelf(); - var descriptors = element.TagHelperInfo.BindingResult.Descriptors; + var tagHelpers = element.TagHelperInfo.BindingResult.TagHelpers; var attributeName = node.Name.GetContent(); var attributeValueNode = node.Value; using var matches = new PooledArrayBuilder(); - TagHelperMatchingConventions.GetAttributeMatches(descriptors, attributeName, ref matches.AsRef()); + TagHelperMatchingConventions.GetAttributeMatches(tagHelpers, attributeName, ref matches.AsRef()); if (matches.Any() && _renderedBoundAttributeNames.Add(attributeName)) { @@ -1971,12 +1971,12 @@ public override void VisitMarkupTagHelperAttribute(MarkupTagHelperAttributeSynta public override void VisitMarkupTagHelperDirectiveAttribute(MarkupTagHelperDirectiveAttributeSyntax node) { var element = node.FirstAncestorOrSelf(); - var descriptors = element.TagHelperInfo.BindingResult.Descriptors; + var tagHelpers = element.TagHelperInfo.BindingResult.TagHelpers; var attributeName = node.FullName; var attributeValueNode = node.Value; using var matches = new PooledArrayBuilder(); - TagHelperMatchingConventions.GetAttributeMatches(descriptors, attributeName, ref matches.AsRef()); + TagHelperMatchingConventions.GetAttributeMatches(tagHelpers, attributeName, ref matches.AsRef()); if (matches.Any() && _renderedBoundAttributeNames.Add(attributeName)) { diff --git a/src/Compiler/Microsoft.CodeAnalysis.Razor.Compiler/src/Language/DefaultRazorTagHelperContextDiscoveryPhase.cs b/src/Compiler/Microsoft.CodeAnalysis.Razor.Compiler/src/Language/DefaultRazorTagHelperContextDiscoveryPhase.cs index 2e4ad2a7365..7b0ac035e2b 100644 --- a/src/Compiler/Microsoft.CodeAnalysis.Razor.Compiler/src/Language/DefaultRazorTagHelperContextDiscoveryPhase.cs +++ b/src/Compiler/Microsoft.CodeAnalysis.Razor.Compiler/src/Language/DefaultRazorTagHelperContextDiscoveryPhase.cs @@ -3,10 +3,8 @@ using System; using System.Collections.Generic; -using System.Collections.Immutable; using System.Diagnostics; using System.Diagnostics.CodeAnalysis; -using System.Linq; using System.Threading; using Microsoft.AspNetCore.Razor.Language.Components; using Microsoft.AspNetCore.Razor.Language.Legacy; @@ -30,7 +28,7 @@ protected override void ExecuteCore(RazorCodeDocument codeDocument, Cancellation return; } - tagHelpers = tagHelperFeature.GetDescriptors(cancellationToken); + tagHelpers = tagHelperFeature.GetTagHelpers(cancellationToken); } using var _ = GetPooledVisitor(codeDocument, tagHelpers, cancellationToken, out var visitor); @@ -79,7 +77,9 @@ internal abstract class DirectiveVisitor : SyntaxWalker, IPoolableObject private RazorSourceDocument? _source; private CancellationToken _cancellationToken; - private readonly HashSet _matches = []; + private TagHelperCollection.Builder? _matches; + + private TagHelperCollection.Builder Matches => _matches ??= []; protected bool IsInitialized => _isInitialized; protected RazorSourceDocument Source => _source.AssumeNotNull(); @@ -100,7 +100,7 @@ public void Visit(RazorSyntaxTree tree) Visit(tree.Root); } - public ImmutableArray GetResults() => [.. _matches]; + public TagHelperCollection GetResults() => _matches?.ToCollection() ?? []; protected void Initialize(string? filePath, CancellationToken cancellationToken) { @@ -111,7 +111,12 @@ protected void Initialize(string? filePath, CancellationToken cancellationToken) public virtual void Reset() { - _matches.Clear(); + if (_matches is { } matches) + { + matches.Dispose(); + _matches = null; + } + _filePath = null; _source = null; _cancellationToken = default; @@ -121,7 +126,7 @@ public virtual void Reset() protected void AddMatch(TagHelperDescriptor tagHelper) { _cancellationToken.ThrowIfCancellationRequested(); - _matches.Add(tagHelper); + Matches.Add(tagHelper); } protected void AddMatches(List tagHelpers) @@ -130,14 +135,14 @@ protected void AddMatches(List tagHelpers) foreach (var tagHelper in tagHelpers) { - _matches.Add(tagHelper); + Matches.Add(tagHelper); } } protected void RemoveMatch(TagHelperDescriptor tagHelper) { _cancellationToken.ThrowIfCancellationRequested(); - _matches.Remove(tagHelper); + Matches.Remove(tagHelper); } protected void RemoveMatches(List tagHelpers) @@ -146,7 +151,7 @@ protected void RemoveMatches(List tagHelpers) foreach (var tagHelper in tagHelpers) { - _matches.Remove(tagHelper); + Matches.Remove(tagHelper); } } @@ -180,7 +185,7 @@ internal sealed class TagHelperDirectiveVisitor : DirectiveVisitor /// private readonly Dictionary> _tagHelperMap = new(StringComparer.Ordinal); - private IReadOnlyList? _descriptors; + private TagHelperCollection? _tagHelpers; private bool _tagHelperMapComputed; private string? _tagHelperPrefix; @@ -201,13 +206,13 @@ private Dictionary> TagHelperMap void ComputeTagHelperMap() { - var tagHelpers = _descriptors.AssumeNotNull(); + var tagHelpers = _tagHelpers.AssumeNotNull(); string? currentAssemblyName = null; List? currentTagHelpers = null; // We don't want to consider components in a view document. - foreach (var tagHelper in tagHelpers.AsEnumerable()) + foreach (var tagHelper in tagHelpers) { if (!tagHelper.IsAnyComponentDocumentTagHelper()) { @@ -230,13 +235,13 @@ void ComputeTagHelperMap() } public void Initialize( - IReadOnlyList descriptors, + TagHelperCollection tagHelpers, string? filePath, CancellationToken cancellationToken = default) { Debug.Assert(!IsInitialized); - _descriptors = descriptors; + _tagHelpers = tagHelpers; base.Initialize(filePath, cancellationToken); } @@ -250,7 +255,7 @@ public override void Reset() _tagHelperMap.Clear(); _tagHelperMapComputed = false; - _descriptors = null; + _tagHelpers = null; _tagHelperPrefix = null; base.Reset(); @@ -381,14 +386,14 @@ internal sealed class ComponentDirectiveVisitor : DirectiveVisitor private List? _componentsWithoutNamespace; public void Initialize( - IReadOnlyList descriptors, + TagHelperCollection tagHelpers, string? filePath, string? currentNamespace, CancellationToken cancellationToken = default) { Debug.Assert(!IsInitialized); - foreach (var component in descriptors.AsEnumerable()) + foreach (var component in tagHelpers) { cancellationToken.ThrowIfCancellationRequested(); diff --git a/src/Compiler/Microsoft.CodeAnalysis.Razor.Compiler/src/Language/DefaultRazorTagHelperContextDiscoveryPhase_Pooling.cs b/src/Compiler/Microsoft.CodeAnalysis.Razor.Compiler/src/Language/DefaultRazorTagHelperContextDiscoveryPhase_Pooling.cs index 1107139723e..83eff11bdec 100644 --- a/src/Compiler/Microsoft.CodeAnalysis.Razor.Compiler/src/Language/DefaultRazorTagHelperContextDiscoveryPhase_Pooling.cs +++ b/src/Compiler/Microsoft.CodeAnalysis.Razor.Compiler/src/Language/DefaultRazorTagHelperContextDiscoveryPhase_Pooling.cs @@ -30,7 +30,7 @@ public void Dispose() internal static PooledDirectiveVisitor GetPooledVisitor( RazorCodeDocument codeDocument, - IReadOnlyList tagHelpers, + TagHelperCollection tagHelpers, CancellationToken cancellationToken, out DirectiveVisitor visitor) { diff --git a/src/Compiler/Microsoft.CodeAnalysis.Razor.Compiler/src/Language/DefaultRazorTagHelperRewritePhase.cs b/src/Compiler/Microsoft.CodeAnalysis.Razor.Compiler/src/Language/DefaultRazorTagHelperRewritePhase.cs index f0e3b7277a1..0b959abc1c7 100644 --- a/src/Compiler/Microsoft.CodeAnalysis.Razor.Compiler/src/Language/DefaultRazorTagHelperRewritePhase.cs +++ b/src/Compiler/Microsoft.CodeAnalysis.Razor.Compiler/src/Language/DefaultRazorTagHelperRewritePhase.cs @@ -1,8 +1,6 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -using System.Collections.Generic; -using System.Collections.Immutable; using System.Threading; using Microsoft.AspNetCore.Razor.Language.Legacy; @@ -18,15 +16,15 @@ protected override void ExecuteCore(RazorCodeDocument codeDocument, Cancellation { // No descriptors, so no need to see if any are used. Without setting this though, // we trigger an Assert in the ProcessRemaining method in the source generator. - codeDocument.SetReferencedTagHelpers(ImmutableHashSet.Empty); + codeDocument.SetReferencedTagHelpers([]); return; } var binder = context.GetBinder(); - var usedHelpers = new HashSet(); + using var usedHelpers = new TagHelperCollection.Builder(); var rewrittenSyntaxTree = TagHelperParseTreeRewriter.Rewrite(syntaxTree, binder, usedHelpers, cancellationToken); - codeDocument.SetReferencedTagHelpers(usedHelpers); + codeDocument.SetReferencedTagHelpers(usedHelpers.ToCollection()); codeDocument.SetSyntaxTree(rewrittenSyntaxTree); } } diff --git a/src/Compiler/Microsoft.CodeAnalysis.Razor.Compiler/src/Language/ITagHelperFeature.cs b/src/Compiler/Microsoft.CodeAnalysis.Razor.Compiler/src/Language/ITagHelperFeature.cs index d69f3fcf62c..2d4bdc9abc8 100644 --- a/src/Compiler/Microsoft.CodeAnalysis.Razor.Compiler/src/Language/ITagHelperFeature.cs +++ b/src/Compiler/Microsoft.CodeAnalysis.Razor.Compiler/src/Language/ITagHelperFeature.cs @@ -1,12 +1,11 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -using System.Collections.Generic; using System.Threading; namespace Microsoft.AspNetCore.Razor.Language; public interface ITagHelperFeature : IRazorEngineFeature { - IReadOnlyList GetDescriptors(CancellationToken cancellationToken = default); + TagHelperCollection GetTagHelpers(CancellationToken cancellationToken = default); } diff --git a/src/Compiler/Microsoft.CodeAnalysis.Razor.Compiler/src/Language/Intermediate/TagHelperIntermediateNode.cs b/src/Compiler/Microsoft.CodeAnalysis.Razor.Compiler/src/Language/Intermediate/TagHelperIntermediateNode.cs index ce69f80f4ed..393833562b9 100644 --- a/src/Compiler/Microsoft.CodeAnalysis.Razor.Compiler/src/Language/Intermediate/TagHelperIntermediateNode.cs +++ b/src/Compiler/Microsoft.CodeAnalysis.Razor.Compiler/src/Language/Intermediate/TagHelperIntermediateNode.cs @@ -1,7 +1,6 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -using System.Collections.Immutable; using System.Linq; namespace Microsoft.AspNetCore.Razor.Language.Intermediate; @@ -16,7 +15,7 @@ public sealed class TagHelperIntermediateNode : IntermediateNode /// public SourceSpan? StartTagSpan { get; init; } - public ImmutableArray TagHelpers { get; init => field = value.NullToEmpty(); } = []; + public TagHelperCollection TagHelpers { get; init => field = value ?? []; } = []; public override IntermediateNodeCollection Children { get => field ??= []; } diff --git a/src/Compiler/Microsoft.CodeAnalysis.Razor.Compiler/src/Language/Legacy/TagHelperBlockRewriter.cs b/src/Compiler/Microsoft.CodeAnalysis.Razor.Compiler/src/Language/Legacy/TagHelperBlockRewriter.cs index 1b69b0860bc..fde22e52249 100644 --- a/src/Compiler/Microsoft.CodeAnalysis.Razor.Compiler/src/Language/Legacy/TagHelperBlockRewriter.cs +++ b/src/Compiler/Microsoft.CodeAnalysis.Razor.Compiler/src/Language/Legacy/TagHelperBlockRewriter.cs @@ -61,7 +61,7 @@ public static MarkupTagHelperStartTagSyntax Rewrite( string tagName, RazorParserOptions options, MarkupStartTagSyntax startTag, - TagHelperBinding bindingResult, + TagHelperBinding binding, ErrorSink errorSink, RazorSourceDocument source) { @@ -83,7 +83,7 @@ public static MarkupTagHelperStartTagSyntax Rewrite( result = TryParseAttribute( tagName, attributeBlock, - bindingResult.Descriptors, + binding.TagHelpers, errorSink, processedBoundAttributeNames, options); @@ -96,7 +96,7 @@ public static MarkupTagHelperStartTagSyntax Rewrite( result = TryParseMinimizedAttribute( tagName, minimizedAttributeBlock, - bindingResult.Descriptors, + binding.TagHelpers, errorSink, processedBoundAttributeNames); attributeBuilder.Add(result.RewrittenAttribute); @@ -181,7 +181,7 @@ public static MarkupTagHelperStartTagSyntax Rewrite( string.IsNullOrWhiteSpace(GetAttributeValueContent(result.RewrittenAttribute)))) { var errorLocation = new SourceSpan(attributeNameLocation, result.AttributeName.Length); - var propertyTypeName = GetPropertyType(result.AttributeName, bindingResult.Descriptors); + var propertyTypeName = GetPropertyType(result.AttributeName, binding.TagHelpers); var diagnostic = RazorDiagnosticFactory.CreateTagHelper_EmptyBoundAttribute(errorLocation, result.AttributeName, tagName, propertyTypeName); errorSink.OnError(diagnostic); } @@ -216,12 +216,12 @@ public static MarkupTagHelperStartTagSyntax Rewrite( private static TryParseResult TryParseMinimizedAttribute( string tagName, MarkupMinimizedAttributeBlockSyntax attributeBlock, - IEnumerable descriptors, + TagHelperCollection tagHelpers, ErrorSink errorSink, HashSet processedBoundAttributeNames) { // Have a name now. Able to determine correct isBoundNonStringAttribute value. - var result = CreateTryParseResult(attributeBlock.Name.GetContent(), descriptors, processedBoundAttributeNames); + var result = CreateTryParseResult(attributeBlock.Name.GetContent(), tagHelpers, processedBoundAttributeNames); result.AttributeStructure = AttributeStructure.Minimized; @@ -253,13 +253,13 @@ private static TryParseResult TryParseMinimizedAttribute( private static TryParseResult TryParseAttribute( string tagName, MarkupAttributeBlockSyntax attributeBlock, - IEnumerable descriptors, + TagHelperCollection tagHelpers, ErrorSink errorSink, HashSet processedBoundAttributeNames, RazorParserOptions options) { // Have a name now. Able to determine correct isBoundNonStringAttribute value. - var result = CreateTryParseResult(attributeBlock.Name.GetContent(), descriptors, processedBoundAttributeNames); + var result = CreateTryParseResult(attributeBlock.Name.GetContent(), tagHelpers, processedBoundAttributeNames); if (attributeBlock.ValuePrefix == null) { @@ -465,11 +465,11 @@ private static MarkupTagHelperAttributeValueSyntax RewriteAttributeValue(TryPars } // Determines the full name of the Type of the property corresponding to an attribute with the given name. - private static string GetPropertyType(string name, IEnumerable descriptors) + private static string GetPropertyType(string name, TagHelperCollection tagHelpers) { - foreach (var descriptor in descriptors) + foreach (var tagHelper in tagHelpers) { - if (TagHelperMatchingConventions.TryGetFirstBoundAttributeMatch(descriptor, name, out var match)) + if (TagHelperMatchingConventions.TryGetFirstBoundAttributeMatch(tagHelper, name, out var match)) { return match.IsIndexerMatch ? match.Attribute.IndexerTypeName @@ -483,7 +483,7 @@ private static string GetPropertyType(string name, IEnumerable descriptors, + TagHelperCollection tagHelpers, HashSet processedBoundAttributeNames) { var isBoundAttribute = false; @@ -493,9 +493,9 @@ private static TryParseResult CreateTryParseResult( var isDirectiveAttribute = false; var isDuplicateAttribute = false; - foreach (var descriptor in descriptors) + foreach (var tagHelper in tagHelpers) { - if (TagHelperMatchingConventions.TryGetFirstBoundAttributeMatch(descriptor, name, out var match)) + if (TagHelperMatchingConventions.TryGetFirstBoundAttributeMatch(tagHelper, name, out var match)) { isBoundAttribute = true; isBoundNonStringAttribute = !match.ExpectsStringValue; diff --git a/src/Compiler/Microsoft.CodeAnalysis.Razor.Compiler/src/Language/Legacy/TagHelperParseTreeRewriter.cs b/src/Compiler/Microsoft.CodeAnalysis.Razor.Compiler/src/Language/Legacy/TagHelperParseTreeRewriter.cs index 26dc3dae791..7706ba59913 100644 --- a/src/Compiler/Microsoft.CodeAnalysis.Razor.Compiler/src/Language/Legacy/TagHelperParseTreeRewriter.cs +++ b/src/Compiler/Microsoft.CodeAnalysis.Razor.Compiler/src/Language/Legacy/TagHelperParseTreeRewriter.cs @@ -18,7 +18,7 @@ internal static class TagHelperParseTreeRewriter public static RazorSyntaxTree Rewrite( RazorSyntaxTree syntaxTree, TagHelperBinder binder, - ISet? usedDescriptors = null, + TagHelperCollection.Builder? usedDescriptors = null, CancellationToken cancellationToken = default) { using var errorSink = new ErrorSink(); @@ -41,7 +41,7 @@ public static RazorSyntaxTree Rewrite( builder.AddRange(treeDiagnostics); builder.AddRange(sinkDiagnostics); - foreach (var descriptor in binder.Descriptors) + foreach (var descriptor in binder.TagHelpers) { descriptor.AppendAllDiagnostics(ref builder.AsRef()); } @@ -57,7 +57,7 @@ internal sealed class Rewriter( TagHelperBinder binder, RazorParserOptions options, ErrorSink errorSink, - ISet? usedDescriptors, + TagHelperCollection.Builder? usedDescriptors, CancellationToken cancellationToken) : SyntaxRewriter { // Internal for testing. @@ -69,7 +69,7 @@ internal sealed class Rewriter( private readonly Stack _trackerStack = new(); private readonly ErrorSink _errorSink = errorSink; private readonly RazorParserOptions _options = options; - private readonly ISet _usedDescriptors = usedDescriptors ?? new HashSet(); + private readonly TagHelperCollection.Builder? _usedDescriptors = usedDescriptors; private readonly CancellationToken _cancellationToken = cancellationToken; private TagTracker? CurrentTracker => _trackerStack.Count > 0 ? _trackerStack.Peek() : null; @@ -282,10 +282,7 @@ private bool TryRewriteTagHelperStart( return false; } - foreach (var descriptor in tagHelperBinding.Descriptors) - { - _usedDescriptors.Add(descriptor); - } + _usedDescriptors?.AddRange(tagHelperBinding.TagHelpers); ValidateParentAllowsTagHelper(tagName, startTag); ValidateBinding(tagHelperBinding, tagName, startTag); @@ -774,7 +771,7 @@ public bool AllowsChild(string tagName, bool nameIncludesPrefix) using var result = new PooledArrayBuilder(); - foreach (var tagHelper in _binding.Descriptors) + foreach (var tagHelper in _binding.TagHelpers) { foreach (var allowedChildTag in tagHelper.AllowedChildTags) { diff --git a/src/Compiler/Microsoft.CodeAnalysis.Razor.Compiler/src/Language/Legacy/TagHelperSpanInternal.cs b/src/Compiler/Microsoft.CodeAnalysis.Razor.Compiler/src/Language/Legacy/TagHelperSpanInternal.cs index 67737ae0700..df90720bfc8 100644 --- a/src/Compiler/Microsoft.CodeAnalysis.Razor.Compiler/src/Language/Legacy/TagHelperSpanInternal.cs +++ b/src/Compiler/Microsoft.CodeAnalysis.Razor.Compiler/src/Language/Legacy/TagHelperSpanInternal.cs @@ -1,11 +1,9 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -using System.Collections.Immutable; - namespace Microsoft.AspNetCore.Razor.Language.Legacy; internal readonly record struct TagHelperSpanInternal(SourceSpan Span, TagHelperBinding Binding) { - public ImmutableArray TagHelpers => Binding.Descriptors; + public TagHelperCollection TagHelpers => Binding.TagHelpers; } diff --git a/src/Compiler/Microsoft.CodeAnalysis.Razor.Compiler/src/Language/RazorCodeDocument.PropertyTable.cs b/src/Compiler/Microsoft.CodeAnalysis.Razor.Compiler/src/Language/RazorCodeDocument.PropertyTable.cs index c8f829e5f98..f613688d0a3 100644 --- a/src/Compiler/Microsoft.CodeAnalysis.Razor.Compiler/src/Language/RazorCodeDocument.PropertyTable.cs +++ b/src/Compiler/Microsoft.CodeAnalysis.Razor.Compiler/src/Language/RazorCodeDocument.PropertyTable.cs @@ -2,7 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. using System; -using System.Collections.Generic; using System.Collections.Immutable; using System.ComponentModel; using System.Diagnostics.CodeAnalysis; @@ -25,8 +24,8 @@ private readonly struct PropertyTable() private readonly object?[] _values = new object?[Size]; - public Property> TagHelpers => new(_values, 0); - public Property> ReferencedTagHelpers => new(_values, 1); + public Property TagHelpers => new(_values, 0); + public Property ReferencedTagHelpers => new(_values, 1); public Property PreTagHelperSyntaxTree => new(_values, 2); public Property SyntaxTree => new(_values, 3); public BoxedProperty> ImportSyntaxTrees => new(_values, 4); diff --git a/src/Compiler/Microsoft.CodeAnalysis.Razor.Compiler/src/Language/RazorCodeDocument.cs b/src/Compiler/Microsoft.CodeAnalysis.Razor.Compiler/src/Language/RazorCodeDocument.cs index b48baabb2c2..ab668c4d145 100644 --- a/src/Compiler/Microsoft.CodeAnalysis.Razor.Compiler/src/Language/RazorCodeDocument.cs +++ b/src/Compiler/Microsoft.CodeAnalysis.Razor.Compiler/src/Language/RazorCodeDocument.cs @@ -63,28 +63,28 @@ public static RazorCodeDocument Create( return new RazorCodeDocument(source, imports, parserOptions, codeGenerationOptions); } - internal bool TryGetTagHelpers([NotNullWhen(true)] out IReadOnlyList? result) + internal bool TryGetTagHelpers([NotNullWhen(true)] out TagHelperCollection? result) => _properties.TagHelpers.TryGetValue(out result); - internal IReadOnlyList? GetTagHelpers() + internal TagHelperCollection? GetTagHelpers() => _properties.TagHelpers.Value; - internal IReadOnlyList GetRequiredTagHelpers() + internal TagHelperCollection GetRequiredTagHelpers() => _properties.TagHelpers.RequiredValue; - internal void SetTagHelpers(IReadOnlyList? value) + internal void SetTagHelpers(TagHelperCollection? value) => _properties.TagHelpers.SetValue(value); - internal bool TryGetReferencedTagHelpers([NotNullWhen(true)] out ISet? result) + internal bool TryGetReferencedTagHelpers([NotNullWhen(true)] out TagHelperCollection? result) => _properties.ReferencedTagHelpers.TryGetValue(out result); - internal ISet? GetReferencedTagHelpers() + internal TagHelperCollection? GetReferencedTagHelpers() => _properties.ReferencedTagHelpers.Value; - internal ISet GetRequiredReferencedTagHelpers() + internal TagHelperCollection GetRequiredReferencedTagHelpers() => _properties.ReferencedTagHelpers.RequiredValue; - internal void SetReferencedTagHelpers(ISet value) + internal void SetReferencedTagHelpers(TagHelperCollection value) { ArgHelper.ThrowIfNull(value); _properties.ReferencedTagHelpers.SetValue(value); diff --git a/src/Compiler/Microsoft.CodeAnalysis.Razor.Compiler/src/Language/RazorProjectEngine.cs b/src/Compiler/Microsoft.CodeAnalysis.Razor.Compiler/src/Language/RazorProjectEngine.cs index 702782fd46b..e755e4e8317 100644 --- a/src/Compiler/Microsoft.CodeAnalysis.Razor.Compiler/src/Language/RazorProjectEngine.cs +++ b/src/Compiler/Microsoft.CodeAnalysis.Razor.Compiler/src/Language/RazorProjectEngine.cs @@ -71,7 +71,7 @@ public RazorCodeDocument Process( RazorSourceDocument source, RazorFileKind fileKind, ImmutableArray importSources, - IReadOnlyList? tagHelpers, + TagHelperCollection? tagHelpers, CancellationToken cancellationToken = default) { ArgHelper.ThrowIfNull(source); @@ -99,7 +99,7 @@ public RazorCodeDocument ProcessDeclarationOnly( RazorSourceDocument source, RazorFileKind fileKind, ImmutableArray importSources, - IReadOnlyList? tagHelpers, + TagHelperCollection? tagHelpers, CancellationToken cancellationToken = default) { ArgHelper.ThrowIfNull(source); @@ -127,7 +127,7 @@ public RazorCodeDocument ProcessDesignTime( RazorSourceDocument source, RazorFileKind fileKind, ImmutableArray importSources, - IReadOnlyList? tagHelpers, + TagHelperCollection? tagHelpers, CancellationToken cancellationToken = default) { ArgHelper.ThrowIfNull(source); @@ -151,7 +151,7 @@ internal RazorCodeDocument CreateCodeDocument( RazorSourceDocument source, RazorFileKind fileKind, ImmutableArray importSources, - IReadOnlyList? tagHelpers, + TagHelperCollection? tagHelpers, string? cssScope) { ArgHelper.ThrowIfNull(source); @@ -163,7 +163,7 @@ internal RazorCodeDocument CreateDesignTimeCodeDocument( RazorSourceDocument source, RazorFileKind fileKind, ImmutableArray importSources, - IReadOnlyList? tagHelpers) + TagHelperCollection? tagHelpers) { ArgHelper.ThrowIfNull(source); @@ -186,7 +186,7 @@ private RazorCodeDocument CreateCodeDocumentCore( RazorSourceDocument source, RazorFileKind fileKind, ImmutableArray importSources, - IReadOnlyList? tagHelpers, + TagHelperCollection? tagHelpers, string? cssScope, Action? configureParser, Action? configureCodeGeneration) @@ -216,7 +216,7 @@ private RazorCodeDocument CreateCodeDocumentDesignTimeCore( RazorSourceDocument sourceDocument, RazorFileKind fileKind, ImmutableArray importSources, - IReadOnlyList? tagHelpers, + TagHelperCollection? tagHelpers, Action? configureParser, Action? configureCodeGeneration) { diff --git a/src/Compiler/Microsoft.CodeAnalysis.Razor.Compiler/src/Language/RazorProjectEngineExtensions.cs b/src/Compiler/Microsoft.CodeAnalysis.Razor.Compiler/src/Language/RazorProjectEngineExtensions.cs index 8db362d70ab..89c00fac19b 100644 --- a/src/Compiler/Microsoft.CodeAnalysis.Razor.Compiler/src/Language/RazorProjectEngineExtensions.cs +++ b/src/Compiler/Microsoft.CodeAnalysis.Razor.Compiler/src/Language/RazorProjectEngineExtensions.cs @@ -1,7 +1,6 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -using System.Collections.Generic; using System.Collections.Immutable; namespace Microsoft.AspNetCore.Razor.Language; @@ -32,21 +31,21 @@ public static RazorCodeDocument CreateCodeDocument( public static RazorCodeDocument CreateCodeDocument( this RazorProjectEngine projectEngine, RazorSourceDocument source, - IReadOnlyList tagHelpers) + TagHelperCollection tagHelpers) => projectEngine.CreateCodeDocumentCore(source, tagHelpers: tagHelpers); public static RazorCodeDocument CreateCodeDocument( this RazorProjectEngine projectEngine, RazorSourceDocument source, RazorFileKind fileKind, - IReadOnlyList tagHelpers) + TagHelperCollection tagHelpers) => projectEngine.CreateCodeDocumentCore(source, fileKind, tagHelpers: tagHelpers); public static RazorCodeDocument CreateCodeDocument( this RazorProjectEngine projectEngine, RazorSourceDocument source, ImmutableArray importSources, - IReadOnlyList tagHelpers) + TagHelperCollection tagHelpers) => projectEngine.CreateCodeDocumentCore(source, importSources: importSources, tagHelpers: tagHelpers); public static RazorCodeDocument CreateCodeDocument( @@ -54,7 +53,7 @@ public static RazorCodeDocument CreateCodeDocument( RazorSourceDocument source, RazorFileKind fileKind, ImmutableArray importSources, - IReadOnlyList tagHelpers) + TagHelperCollection tagHelpers) => projectEngine.CreateCodeDocumentCore(source, fileKind, importSources, tagHelpers); private static RazorCodeDocument CreateCodeDocumentCore( @@ -62,7 +61,7 @@ private static RazorCodeDocument CreateCodeDocumentCore( RazorSourceDocument source, RazorFileKind? fileKind = null, ImmutableArray importSources = default, - IReadOnlyList? tagHelpers = null) + TagHelperCollection? tagHelpers = null) { var fileKindValue = fileKind ?? (source.FilePath is string filePath ? FileKinds.GetFileKindFromPath(filePath) @@ -93,21 +92,21 @@ public static RazorCodeDocument CreateDesignTimeCodeDocument( public static RazorCodeDocument CreateDesignTimeCodeDocument( this RazorProjectEngine projectEngine, RazorSourceDocument source, - IReadOnlyList tagHelpers) + TagHelperCollection tagHelpers) => projectEngine.CreateDesignTimeCodeDocumentCore(source, tagHelpers: tagHelpers); public static RazorCodeDocument CreateDesignTimeCodeDocument( this RazorProjectEngine projectEngine, RazorSourceDocument source, RazorFileKind fileKind, - IReadOnlyList tagHelpers) + TagHelperCollection tagHelpers) => projectEngine.CreateDesignTimeCodeDocumentCore(source, fileKind, tagHelpers: tagHelpers); public static RazorCodeDocument CreateDesignTimeCodeDocument( this RazorProjectEngine projectEngine, RazorSourceDocument source, ImmutableArray importSources, - IReadOnlyList tagHelpers) + TagHelperCollection tagHelpers) => projectEngine.CreateDesignTimeCodeDocumentCore(source, importSources: importSources, tagHelpers: tagHelpers); public static RazorCodeDocument CreateDesignTimeCodeDocument( @@ -115,7 +114,7 @@ public static RazorCodeDocument CreateDesignTimeCodeDocument( RazorSourceDocument source, RazorFileKind fileKind, ImmutableArray importSources, - IReadOnlyList tagHelpers) + TagHelperCollection tagHelpers) => projectEngine.CreateDesignTimeCodeDocumentCore(source, fileKind, importSources, tagHelpers); private static RazorCodeDocument CreateDesignTimeCodeDocumentCore( @@ -123,7 +122,7 @@ private static RazorCodeDocument CreateDesignTimeCodeDocumentCore( RazorSourceDocument source, RazorFileKind? fileKind = null, ImmutableArray importSources = default, - IReadOnlyList? tagHelpers = null) + TagHelperCollection? tagHelpers = null) { var fileKindValue = fileKind ?? (source.FilePath is string filePath ? FileKinds.GetFileKindFromPath(filePath) diff --git a/src/Compiler/Microsoft.CodeAnalysis.Razor.Compiler/src/Language/Syntax/SyntaxSerializer.cs b/src/Compiler/Microsoft.CodeAnalysis.Razor.Compiler/src/Language/Syntax/SyntaxSerializer.cs index ba11e20c6ee..363f4ebb7f2 100644 --- a/src/Compiler/Microsoft.CodeAnalysis.Razor.Compiler/src/Language/Syntax/SyntaxSerializer.cs +++ b/src/Compiler/Microsoft.CodeAnalysis.Razor.Compiler/src/Language/Syntax/SyntaxSerializer.cs @@ -133,12 +133,12 @@ private void WriteTagHelperElement(MarkupTagHelperElementSyntax node) WriteValue($"{tagHelperInfo.TagName}[{tagHelperInfo.TagMode}]"); // Write descriptors - foreach (var descriptor in tagHelperInfo.BindingResult.Descriptors) + foreach (var tagHelper in tagHelperInfo.BindingResult.TagHelpers) { WriteSeparator(); // Get the type name without the namespace. - var typeName = descriptor.Name[(descriptor.Name.LastIndexOf('.') + 1)..]; + var typeName = tagHelper.Name[(tagHelper.Name.LastIndexOf('.') + 1)..]; WriteValue(typeName); } } diff --git a/src/Compiler/Microsoft.CodeAnalysis.Razor.Compiler/src/Language/TagHelperBinder.cs b/src/Compiler/Microsoft.CodeAnalysis.Razor.Compiler/src/Language/TagHelperBinder.cs index c48b61748f1..90d57d1577b 100644 --- a/src/Compiler/Microsoft.CodeAnalysis.Razor.Compiler/src/Language/TagHelperBinder.cs +++ b/src/Compiler/Microsoft.CodeAnalysis.Razor.Compiler/src/Language/TagHelperBinder.cs @@ -15,28 +15,28 @@ namespace Microsoft.AspNetCore.Razor.Language; /// internal sealed partial class TagHelperBinder { - private readonly TagHelperSet _catchAllDescriptors; - private readonly ReadOnlyDictionary _tagNameToDescriptorsMap; + private readonly TagHelperSet _catchAllTagHelpers; + private readonly ReadOnlyDictionary _tagNameToTagHelpersMap; public string? TagNamePrefix { get; } - public ImmutableArray Descriptors { get; } + public TagHelperCollection TagHelpers { get; } /// /// Instantiates a new instance of the . /// /// The tag helper prefix being used by the document. - /// The s that the + /// The s that the /// will pull from. - public TagHelperBinder(string? tagNamePrefix, ImmutableArray descriptors) + public TagHelperBinder(string? tagNamePrefix, TagHelperCollection tagHelpers) { TagNamePrefix = tagNamePrefix; - Descriptors = descriptors.NullToEmpty(); + TagHelpers = tagHelpers; - ProcessDescriptors(descriptors, tagNamePrefix, out _tagNameToDescriptorsMap, out _catchAllDescriptors); + ProcessDescriptors(tagHelpers, tagNamePrefix, out _tagNameToTagHelpersMap, out _catchAllTagHelpers); } private static void ProcessDescriptors( - ImmutableArray descriptors, + TagHelperCollection descriptors, string? tagNamePrefix, out ReadOnlyDictionary tagNameToDescriptorsMap, out TagHelperSet catchAllDescriptors) @@ -47,29 +47,19 @@ private static void ProcessDescriptors( // Keep track of what needs to be added in the second pass. // There will be an entry for every tag matching rule. // Each entry consists of an index to identify a builder and the TagHelperDescriptor to add to it. - using var toAdd = new MemoryBuilder<(int, TagHelperDescriptor)>(initialCapacity: descriptors.Length * 4, clearArray: true); + using var toAdd = new MemoryBuilder<(int, TagHelperDescriptor)>(initialCapacity: descriptors.Count * 4, clearArray: true); // Use a special TagHelperSet.Builder to track catch-all tag helpers. var catchAllBuilder = new TagHelperSet.Builder(); // At most, there should only be one catch-all tag helper per descriptor. - using var catchAllToAdd = new MemoryBuilder(initialCapacity: descriptors.Length, clearArray: true); + using var catchAllToAdd = new MemoryBuilder(initialCapacity: descriptors.Count, clearArray: true); // The builders are indexed using a map of "tag name" to the index of the builder in the array. using var _1 = SpecializedPools.GetPooledStringDictionary(ignoreCase: true, out var tagNameToBuilderIndexMap); - using var _2 = HashSetPool.GetPooledObject(out var tagHelperSet); - -#if NET - tagHelperSet.EnsureCapacity(descriptors.Length); -#endif foreach (var tagHelper in descriptors) { - if (!tagHelperSet.Add(tagHelper)) - { - // We've already seen this tag helper. Skip. - continue; - } foreach (var rule in tagHelper.TagMatchingRules) { @@ -167,7 +157,7 @@ private static void ProcessDescriptors( using var pooledSet = HashSetPool.GetPooledObject(out var distinctSet); // First, try any tag helpers with this tag name. - if (_tagNameToDescriptorsMap.TryGetValue(tagName, out var matchingDescriptors)) + if (_tagNameToTagHelpersMap.TryGetValue(tagName, out var matchingDescriptors)) { CollectBoundRulesInfo( matchingDescriptors, @@ -177,7 +167,7 @@ private static void ProcessDescriptors( // Next, try any "catch all" descriptors. CollectBoundRulesInfo( - _catchAllDescriptors, + _catchAllTagHelpers, tagNameSpan, parentTagNameSpan, attributes, ref resultsBuilder.AsRef(), ref tempRulesBuilder.AsRef(), distinctSet); diff --git a/src/Compiler/Microsoft.CodeAnalysis.Razor.Compiler/src/Language/TagHelperBinding.cs b/src/Compiler/Microsoft.CodeAnalysis.Razor.Compiler/src/Language/TagHelperBinding.cs index d67122cf217..4d9d796b565 100644 --- a/src/Compiler/Microsoft.CodeAnalysis.Razor.Compiler/src/Language/TagHelperBinding.cs +++ b/src/Compiler/Microsoft.CodeAnalysis.Razor.Compiler/src/Language/TagHelperBinding.cs @@ -1,9 +1,9 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -using System; using System.Collections.Generic; using System.Collections.Immutable; +using Microsoft.AspNetCore.Razor.Threading; namespace Microsoft.AspNetCore.Razor.Language; @@ -15,7 +15,15 @@ internal sealed class TagHelperBinding public string? ParentTagName { get; } public ImmutableArray> Attributes { get; } - private ImmutableArray _descriptors; + private LazyValue, TagHelperCollection> _lazyTagHelpers = new(static allBoundRules => + TagHelperCollection.Build(allBoundRules, initialCapacity: allBoundRules.Length, static (ref builder, allBoundRules) => + { + foreach (var boundRule in allBoundRules) + { + builder.Add(boundRule.Descriptor); + } + })); + private bool? _isAttributeMatch; internal TagHelperBinding( @@ -32,18 +40,7 @@ internal TagHelperBinding( TagNamePrefix = tagNamePrefix; } - public ImmutableArray Descriptors - { - get - { - if (_descriptors.IsDefault) - { - ImmutableInterlocked.InterlockedInitialize(ref _descriptors, AllBoundRules.SelectAsArray(x => x.Descriptor)); - } - - return _descriptors; - } - } + public TagHelperCollection TagHelpers => _lazyTagHelpers.GetValue(AllBoundRules); public ImmutableArray GetBoundRules(TagHelperDescriptor descriptor) => AllBoundRules.First(descriptor, static (info, d) => info.Descriptor.Equals(d)).Rules; @@ -62,13 +59,13 @@ public bool IsAttributeMatch { get { - return _isAttributeMatch ??= ComputeIsAttributeMatch(Descriptors); + return _isAttributeMatch ??= ComputeIsAttributeMatch(TagHelpers); - static bool ComputeIsAttributeMatch(ImmutableArray descriptors) + static bool ComputeIsAttributeMatch(TagHelperCollection tagHelpers) { - foreach (var descriptor in descriptors) + foreach (var tagHelper in tagHelpers) { - if (!descriptor.ClassifyAttributesOnly) + if (!tagHelper.ClassifyAttributesOnly) { return false; } diff --git a/src/Compiler/Microsoft.CodeAnalysis.Razor.Compiler/src/Language/TagHelperDocumentContext.cs b/src/Compiler/Microsoft.CodeAnalysis.Razor.Compiler/src/Language/TagHelperDocumentContext.cs index 0a9409ac177..4311327518f 100644 --- a/src/Compiler/Microsoft.CodeAnalysis.Razor.Compiler/src/Language/TagHelperDocumentContext.cs +++ b/src/Compiler/Microsoft.CodeAnalysis.Razor.Compiler/src/Language/TagHelperDocumentContext.cs @@ -1,9 +1,6 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -using System; -using System.Collections.Immutable; - namespace Microsoft.AspNetCore.Razor.Language; /// @@ -13,22 +10,26 @@ namespace Microsoft.AspNetCore.Razor.Language; internal sealed class TagHelperDocumentContext { public string? Prefix { get; } - public ImmutableArray TagHelpers { get; } + public TagHelperCollection TagHelpers { get; } private TagHelperBinder? _binder; - private TagHelperDocumentContext(string? prefix, ImmutableArray tagHelpers) + private TagHelperDocumentContext(string? prefix, TagHelperCollection tagHelpers) { Prefix = prefix; TagHelpers = tagHelpers; } - public static TagHelperDocumentContext Create(string? prefix, ImmutableArray tagHelpers) + public static TagHelperDocumentContext Create(TagHelperCollection tagHelpers) + { + ArgHelper.ThrowIfNull(tagHelpers); + + return new(prefix: null, tagHelpers); + } + + public static TagHelperDocumentContext Create(string? prefix, TagHelperCollection tagHelpers) { - if (tagHelpers.IsDefault) - { - throw new ArgumentNullException(nameof(tagHelpers)); - } + ArgHelper.ThrowIfNull(tagHelpers); return new(prefix, tagHelpers); } diff --git a/src/Compiler/Microsoft.CodeAnalysis.Razor.Compiler/src/Language/TagHelperMatchingConventions.cs b/src/Compiler/Microsoft.CodeAnalysis.Razor.Compiler/src/Language/TagHelperMatchingConventions.cs index 3d6e23a4b48..4689327fc06 100644 --- a/src/Compiler/Microsoft.CodeAnalysis.Razor.Compiler/src/Language/TagHelperMatchingConventions.cs +++ b/src/Compiler/Microsoft.CodeAnalysis.Razor.Compiler/src/Language/TagHelperMatchingConventions.cs @@ -187,7 +187,7 @@ private static bool TryGetBoundAttributeParameter(string fullAttributeName, out /// for the specified attribute name. Each successful match is added to the provided matches collection. /// public static void GetAttributeMatches( - ImmutableArray tagHelpers, + TagHelperCollection tagHelpers, string name, ref PooledArrayBuilder matches) { diff --git a/src/Compiler/Microsoft.CodeAnalysis.Razor.Compiler/src/SourceGenerators/RazorGeneratorResult.cs b/src/Compiler/Microsoft.CodeAnalysis.Razor.Compiler/src/SourceGenerators/RazorGeneratorResult.cs index 943913aa799..b7aab9a94ab 100644 --- a/src/Compiler/Microsoft.CodeAnalysis.Razor.Compiler/src/SourceGenerators/RazorGeneratorResult.cs +++ b/src/Compiler/Microsoft.CodeAnalysis.Razor.Compiler/src/SourceGenerators/RazorGeneratorResult.cs @@ -1,15 +1,14 @@ // 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.Collections.Generic; -using System.Collections.Immutable; using Microsoft.AspNetCore.Razor.Language; +using System.Collections.Immutable; namespace Microsoft.NET.Sdk.Razor.SourceGenerators { - internal sealed class RazorGeneratorResult(IReadOnlyList tagHelpers, ImmutableDictionary filePathToDocument, ImmutableDictionary hintNameToFilePath) + internal sealed class RazorGeneratorResult(TagHelperCollection tagHelpers, ImmutableDictionary filePathToDocument, ImmutableDictionary hintNameToFilePath) { - public IReadOnlyList TagHelpers => tagHelpers; + public TagHelperCollection TagHelpers => tagHelpers; public RazorCodeDocument? GetCodeDocument(string physicalPath) => filePathToDocument.TryGetValue(physicalPath, out var pair) ? pair.document : null; diff --git a/src/Compiler/Microsoft.CodeAnalysis.Razor.Compiler/src/SourceGenerators/RazorSourceGenerator.AllTagHelpers.cs b/src/Compiler/Microsoft.CodeAnalysis.Razor.Compiler/src/SourceGenerators/RazorSourceGenerator.AllTagHelpers.cs deleted file mode 100644 index 6852d7c9053..00000000000 --- a/src/Compiler/Microsoft.CodeAnalysis.Razor.Compiler/src/SourceGenerators/RazorSourceGenerator.AllTagHelpers.cs +++ /dev/null @@ -1,80 +0,0 @@ -// 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; -using System.Collections.Generic; -using Microsoft.AspNetCore.Razor.Language; - -namespace Microsoft.NET.Sdk.Razor.SourceGenerators -{ - public partial class RazorSourceGenerator - { - /// - /// Helper class that joins together two lists of tag helpers to avoid allocating - /// a new array to copy them to. - /// - private sealed class AllTagHelpers : IReadOnlyList - { - private static readonly List s_emptyList = new(); - - public static readonly AllTagHelpers Empty = new( - tagHelpersFromCompilation: null, - tagHelpersFromReferences: null); - - private readonly List _tagHelpersFromCompilation; - private readonly List _tagHelpersFromReferences; - - private AllTagHelpers( - List? tagHelpersFromCompilation, - List? tagHelpersFromReferences) - { - _tagHelpersFromCompilation = tagHelpersFromCompilation ?? s_emptyList; - _tagHelpersFromReferences = tagHelpersFromReferences ?? s_emptyList; - } - - public static AllTagHelpers Create( - List? tagHelpersFromCompilation, - List? tagHelpersFromReferences) - { - return tagHelpersFromCompilation is null or [] && tagHelpersFromReferences is null or [] - ? Empty - : new(tagHelpersFromCompilation, tagHelpersFromReferences); - } - - public TagHelperDescriptor this[int index] - { - get - { - if (index >= 0) - { - return index < _tagHelpersFromCompilation.Count - ? _tagHelpersFromCompilation[index] - : _tagHelpersFromReferences[index - _tagHelpersFromCompilation.Count]; - } - - throw new IndexOutOfRangeException(); - } - } - - public int Count - => _tagHelpersFromCompilation.Count + _tagHelpersFromReferences.Count; - - public IEnumerator GetEnumerator() - { - foreach (var tagHelper in _tagHelpersFromCompilation) - { - yield return tagHelper; - } - - foreach (var tagHelper in _tagHelpersFromReferences) - { - yield return tagHelper; - } - } - - IEnumerator IEnumerable.GetEnumerator() - => GetEnumerator(); - } - } -} diff --git a/src/Compiler/Microsoft.CodeAnalysis.Razor.Compiler/src/SourceGenerators/RazorSourceGenerator.cs b/src/Compiler/Microsoft.CodeAnalysis.Razor.Compiler/src/SourceGenerators/RazorSourceGenerator.cs index faf72056bfb..66c6ca5d9b5 100644 --- a/src/Compiler/Microsoft.CodeAnalysis.Razor.Compiler/src/SourceGenerators/RazorSourceGenerator.cs +++ b/src/Compiler/Microsoft.CodeAnalysis.Razor.Compiler/src/SourceGenerators/RazorSourceGenerator.cs @@ -125,21 +125,21 @@ public void Initialize(IncrementalGeneratorInitializationContext context) .Select(static (pair, cancellationToken) => { var ((compilation, razorSourceGeneratorOptions), isGeneratorSuppressed) = pair; - var results = new List(); - if (isGeneratorSuppressed) { - return results; + return []; } RazorSourceGeneratorEventSource.Log.DiscoverTagHelpersFromCompilationStart(); var tagHelperFeature = GetStaticTagHelperFeature(compilation); - tagHelperFeature.CollectDescriptors(compilation.Assembly, results, cancellationToken); + using var builder = new TagHelperCollection.Builder(); + + tagHelperFeature.CollectDescriptors(compilation.Assembly, builder, cancellationToken); RazorSourceGeneratorEventSource.Log.DiscoverTagHelpersFromCompilationStop(); - return results; + return builder.ToCollection(); }) .WithLambdaComparer(static (a, b) => a!.SequenceEqual(b!)); @@ -222,7 +222,7 @@ public void Initialize(IncrementalGeneratorInitializationContext context) if (!hasRazorFiles) { // If there's no razor code in this app, don't do anything. - return null; + return []; } RazorSourceGeneratorEventSource.Log.DiscoverTagHelpersFromReferencesStart(); @@ -230,26 +230,26 @@ public void Initialize(IncrementalGeneratorInitializationContext context) // Typically a project with Razor files will have many tag helpers in references. // So, we start with a larger capacity to avoid extra array copies. - var results = new List(capacity: 128); + using var builder = new TagHelperCollection.Builder(); foreach (var reference in compilation.References) { if (compilation.GetAssemblyOrModuleSymbol(reference) is IAssemblySymbol assembly) { - tagHelperFeature.CollectDescriptors(assembly, results, cancellationToken); + tagHelperFeature.CollectDescriptors(assembly, builder, cancellationToken); } } RazorSourceGeneratorEventSource.Log.DiscoverTagHelpersFromReferencesStop(); - return results; + return builder.ToCollection(); }); var allTagHelpers = tagHelpersFromCompilation .Combine(tagHelpersFromReferences) .Select(static (pair, _) => { - return AllTagHelpers.Create(tagHelpersFromCompilation: pair.Left, tagHelpersFromReferences: pair.Right); + return TagHelperCollection.Merge(pair.Left, pair.Right); }); var withOptions = sourceItems diff --git a/src/Compiler/Microsoft.CodeAnalysis.Razor.Compiler/src/SourceGenerators/SourceGeneratorProjectEngine.cs b/src/Compiler/Microsoft.CodeAnalysis.Razor.Compiler/src/SourceGenerators/SourceGeneratorProjectEngine.cs index 120c2d5f666..67b0359dadf 100644 --- a/src/Compiler/Microsoft.CodeAnalysis.Razor.Compiler/src/SourceGenerators/SourceGeneratorProjectEngine.cs +++ b/src/Compiler/Microsoft.CodeAnalysis.Razor.Compiler/src/SourceGenerators/SourceGeneratorProjectEngine.cs @@ -65,7 +65,7 @@ public SourceGeneratorRazorCodeDocument ProcessInitialParse(RazorProjectItem pro return new SourceGeneratorRazorCodeDocument(codeDocument); } - public SourceGeneratorRazorCodeDocument ProcessTagHelpers(SourceGeneratorRazorCodeDocument sgDocument, IReadOnlyList tagHelpers, bool checkForIdempotency, CancellationToken cancellationToken) + public SourceGeneratorRazorCodeDocument ProcessTagHelpers(SourceGeneratorRazorCodeDocument sgDocument, TagHelperCollection tagHelpers, bool checkForIdempotency, CancellationToken cancellationToken) { Debug.Assert(sgDocument.CodeDocument.GetPreTagHelperSyntaxTree() is not null); @@ -75,34 +75,32 @@ public SourceGeneratorRazorCodeDocument ProcessTagHelpers(SourceGeneratorRazorCo if (checkForIdempotency && codeDocument.TryGetTagHelpers(out var previousTagHelpers)) { // compare the tag helpers with the ones the document last used - if (Enumerable.SequenceEqual(tagHelpers, previousTagHelpers)) + if (tagHelpers.Equals(previousTagHelpers)) { // tag helpers are the same, nothing to do! return sgDocument; } - else + + // tag helpers have changed, figure out if we need to re-write + var previousTagHelpersInScope = codeDocument.GetRequiredTagHelperContext().TagHelpers; + var previousUsedTagHelpers = codeDocument.GetRequiredReferencedTagHelpers(); + + // re-run discovery to figure out which tag helpers are now in scope for this document + codeDocument.SetTagHelpers(tagHelpers); + _discoveryPhase.Execute(codeDocument, cancellationToken); + var tagHelpersInScope = codeDocument.GetRequiredTagHelperContext().TagHelpers; + + // Check if any new tag helpers were added or ones we previously used were removed + var newVisibleTagHelpers = tagHelpersInScope.Except(previousTagHelpersInScope); + var newUnusedTagHelpers = previousUsedTagHelpers.Except(tagHelpersInScope); + if (!newVisibleTagHelpers.Any() && !newUnusedTagHelpers.Any()) { - // tag helpers have changed, figure out if we need to re-write - var previousTagHelpersInScope = codeDocument.GetRequiredTagHelperContext().TagHelpers; - var previousUsedTagHelpers = codeDocument.GetRequiredReferencedTagHelpers(); - - // re-run discovery to figure out which tag helpers are now in scope for this document - codeDocument.SetTagHelpers(tagHelpers); - _discoveryPhase.Execute(codeDocument, cancellationToken); - var tagHelpersInScope = codeDocument.GetRequiredTagHelperContext().TagHelpers; - - // Check if any new tag helpers were added or ones we previously used were removed - var newVisibleTagHelpers = tagHelpersInScope.Except(previousTagHelpersInScope); - var newUnusedTagHelpers = previousUsedTagHelpers.Except(tagHelpersInScope); - if (!newVisibleTagHelpers.Any() && !newUnusedTagHelpers.Any()) - { - // No newly visible tag helpers, and any that got removed weren't used by this document anyway - return sgDocument; - } - - // We need to re-write the document, but can skip the scoping as we just performed it - startIndex = _rewritePhaseIndex; + // No newly visible tag helpers, and any that got removed weren't used by this document anyway + return sgDocument; } + + // We need to re-write the document, but can skip the scoping as we just performed it + startIndex = _rewritePhaseIndex; } else { diff --git a/src/Compiler/Microsoft.CodeAnalysis.Razor.Compiler/src/SourceGenerators/StaticCompilationTagHelperFeature.cs b/src/Compiler/Microsoft.CodeAnalysis.Razor.Compiler/src/SourceGenerators/StaticCompilationTagHelperFeature.cs index 5f5a67e224a..fb0bb071f0b 100644 --- a/src/Compiler/Microsoft.CodeAnalysis.Razor.Compiler/src/SourceGenerators/StaticCompilationTagHelperFeature.cs +++ b/src/Compiler/Microsoft.CodeAnalysis.Razor.Compiler/src/SourceGenerators/StaticCompilationTagHelperFeature.cs @@ -16,7 +16,7 @@ internal sealed class StaticCompilationTagHelperFeature(Compilation compilation) public void CollectDescriptors( IAssemblySymbol? targetAssembly, - List results, + TagHelperCollection.Builder results, CancellationToken cancellationToken) { if (_providers.IsDefaultOrEmpty) @@ -32,12 +32,12 @@ public void CollectDescriptors( } } - IReadOnlyList ITagHelperFeature.GetDescriptors(CancellationToken cancellationToken) + TagHelperCollection ITagHelperFeature.GetTagHelpers(CancellationToken cancellationToken) { - var results = new List(); - CollectDescriptors(targetAssembly: null, results, cancellationToken); + using var builder = new TagHelperCollection.Builder(); + CollectDescriptors(targetAssembly: null, builder, cancellationToken); - return results; + return builder.ToCollection(); } protected override void OnInitialized() diff --git a/src/Compiler/Microsoft.CodeAnalysis.Razor/test/CompilationTagHelperFeatureTest.cs b/src/Compiler/Microsoft.CodeAnalysis.Razor/test/CompilationTagHelperFeatureTest.cs index bb4fd061db3..5d9815355aa 100644 --- a/src/Compiler/Microsoft.CodeAnalysis.Razor/test/CompilationTagHelperFeatureTest.cs +++ b/src/Compiler/Microsoft.CodeAnalysis.Razor/test/CompilationTagHelperFeatureTest.cs @@ -90,7 +90,7 @@ public void GetDescriptors_DoesNotSetCompilation_IfCompilationIsInvalid() var feature = engine.Engine.GetFeatures().First(); // Act - var result = feature.GetDescriptors(); + var result = feature.GetTagHelpers(); // Assert Assert.Empty(result); @@ -130,7 +130,7 @@ public void GetDescriptors_SetsCompilation_IfCompilationIsValid() var feature = engine.Engine.GetFeatures().First(); // Act - var result = feature.GetDescriptors(); + var result = feature.GetTagHelpers(); // Assert Assert.Empty(result); diff --git a/src/Compiler/perf/Microbenchmarks/RazorTagHelperParsingBenchmark.cs b/src/Compiler/perf/Microbenchmarks/RazorTagHelperParsingBenchmark.cs index eeec0a1226b..98c1bf61b01 100644 --- a/src/Compiler/perf/Microbenchmarks/RazorTagHelperParsingBenchmark.cs +++ b/src/Compiler/perf/Microbenchmarks/RazorTagHelperParsingBenchmark.cs @@ -2,8 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. using System; -using System.Collections.Generic; -using System.Collections.Immutable; using System.IO; using System.Threading; using BenchmarkDotNet.Attributes; @@ -63,18 +61,18 @@ public void TagHelper_ComponentDirectiveVisitor() ComponentDirectiveVisitor.Visit(SyntaxTree); } - private static ImmutableArray ReadTagHelpers(string filePath) + private static TagHelperCollection ReadTagHelpers(string filePath) { using var reader = new StreamReader(filePath); - return JsonDataConvert.DeserializeTagHelperArray(reader); + var array = JsonDataConvert.DeserializeTagHelperArray(reader); + + return TagHelperCollection.Create(array); } - private sealed class StaticTagHelperFeature(IReadOnlyList descriptors) + private sealed class StaticTagHelperFeature(TagHelperCollection tagHelpers) : RazorEngineFeatureBase, ITagHelperFeature { - public IReadOnlyList Descriptors { get; } = descriptors; - - public IReadOnlyList GetDescriptors(CancellationToken cancellationToken = default) - => Descriptors; + public TagHelperCollection GetTagHelpers(CancellationToken cancellationToken = default) + => tagHelpers; } } diff --git a/src/Compiler/perf/Microbenchmarks/TagHelperBinderBenchmark.cs b/src/Compiler/perf/Microbenchmarks/TagHelperBinderBenchmark.cs index bfa62372895..dc50584e42c 100644 --- a/src/Compiler/perf/Microbenchmarks/TagHelperBinderBenchmark.cs +++ b/src/Compiler/perf/Microbenchmarks/TagHelperBinderBenchmark.cs @@ -42,7 +42,7 @@ public void ConstructTagHelperBinders() { for (var i = 0; i < Count; i++) { - _binders[i] = new TagHelperBinder(tagNamePrefix: null, _tagHelpers); + _binders[i] = new TagHelperBinder(tagNamePrefix: null, [.. _tagHelpers]); } } @@ -51,7 +51,7 @@ public void ConstructTagHelperBinderWithPrefix() { for (var i = 0; i < Count; i++) { - _binders[i] = new TagHelperBinder(tagNamePrefix: "abc", _tagHelpers); + _binders[i] = new TagHelperBinder(tagNamePrefix: "abc", [.. _tagHelpers]); } } } diff --git a/src/Razor/benchmarks/Microsoft.AspNetCore.Razor.Microbenchmarks/LanguageServer/RazorLanguageServerBenchmarkBase.cs b/src/Razor/benchmarks/Microsoft.AspNetCore.Razor.Microbenchmarks/LanguageServer/RazorLanguageServerBenchmarkBase.cs index c964397698c..7ad2bd45e2d 100644 --- a/src/Razor/benchmarks/Microsoft.AspNetCore.Razor.Microbenchmarks/LanguageServer/RazorLanguageServerBenchmarkBase.cs +++ b/src/Razor/benchmarks/Microsoft.AspNetCore.Razor.Microbenchmarks/LanguageServer/RazorLanguageServerBenchmarkBase.cs @@ -71,7 +71,7 @@ await projectManager.UpdateAsync( updater => { updater.AddProject(hostProject); - var projectWorkspaceState = ProjectWorkspaceState.Create(CommonResources.LegacyTagHelpers); + var projectWorkspaceState = ProjectWorkspaceState.Create([.. CommonResources.LegacyTagHelpers]); updater.UpdateProjectWorkspaceState(hostProject.Key, projectWorkspaceState); updater.AddDocument(hostProject.Key, hostDocument, text); }, diff --git a/src/Razor/benchmarks/Microsoft.AspNetCore.Razor.Microbenchmarks/LanguageServer/TagHelperCompletionBenchmark.cs b/src/Razor/benchmarks/Microsoft.AspNetCore.Razor.Microbenchmarks/LanguageServer/TagHelperCompletionBenchmark.cs index 962fd66b8d7..4b6158be6e3 100644 --- a/src/Razor/benchmarks/Microsoft.AspNetCore.Razor.Microbenchmarks/LanguageServer/TagHelperCompletionBenchmark.cs +++ b/src/Razor/benchmarks/Microsoft.AspNetCore.Razor.Microbenchmarks/LanguageServer/TagHelperCompletionBenchmark.cs @@ -31,7 +31,7 @@ public object GetAttributeCompletions() { var tagHelperCompletionService = new TagHelperCompletionService(); var context = new AttributeCompletionContext( - TagHelperDocumentContext.Create(prefix: null, CommonResources.TelerikTagHelpers), + TagHelperDocumentContext.Create([.. CommonResources.TelerikTagHelpers]), existingCompletions: [], currentTagName: "PageTitle", currentAttributeName: null, @@ -48,7 +48,7 @@ public object GetElementCompletions() { var tagHelperCompletionService = new TagHelperCompletionService(); var context = new ElementCompletionContext( - TagHelperDocumentContext.Create(prefix: null, CommonResources.TelerikTagHelpers), + TagHelperDocumentContext.Create([.. CommonResources.TelerikTagHelpers]), existingCompletions: s_existingElementCompletions, containingTagName: null, attributes: [], diff --git a/src/Razor/benchmarks/Microsoft.AspNetCore.Razor.Microbenchmarks/Serialization/CompletionListSerializationBenchmark.cs b/src/Razor/benchmarks/Microsoft.AspNetCore.Razor.Microbenchmarks/Serialization/CompletionListSerializationBenchmark.cs index 07f643b524d..1aee919617f 100644 --- a/src/Razor/benchmarks/Microsoft.AspNetCore.Razor.Microbenchmarks/Serialization/CompletionListSerializationBenchmark.cs +++ b/src/Razor/benchmarks/Microsoft.AspNetCore.Razor.Microbenchmarks/Serialization/CompletionListSerializationBenchmark.cs @@ -6,9 +6,6 @@ using BenchmarkDotNet.Attributes; using Microsoft.AspNetCore.Razor.Language; using Microsoft.AspNetCore.Razor.Language.Syntax; -using Microsoft.AspNetCore.Razor.LanguageServer; -using Microsoft.AspNetCore.Razor.LanguageServer.Completion; -using Microsoft.AspNetCore.Razor.LanguageServer.Hosting; using Microsoft.CodeAnalysis.Razor.Completion; namespace Microsoft.AspNetCore.Razor.Microbenchmarks.Serialization; @@ -69,7 +66,7 @@ private CompletionList GenerateCompletionList(string documentContent, int queryI var sourceDocument = RazorSourceDocument.Create(documentContent, RazorSourceDocumentProperties.Default); var codeDocument = RazorCodeDocument.Create(sourceDocument); var syntaxTree = RazorSyntaxTree.Parse(sourceDocument); - var tagHelperDocumentContext = TagHelperDocumentContext.Create(prefix: string.Empty, CommonResources.LegacyTagHelpers); + var tagHelperDocumentContext = TagHelperDocumentContext.Create([.. CommonResources.LegacyTagHelpers]); var owner = syntaxTree.Root.FindInnermostNode(queryIndex, includeWhitespace: true, walkMarkersBack: true); var context = new RazorCompletionContext(codeDocument, queryIndex, owner, syntaxTree, tagHelperDocumentContext); diff --git a/src/Razor/benchmarks/Microsoft.AspNetCore.Razor.Microbenchmarks/Serialization/RazorProjectInfoSerializationBenchmark.cs b/src/Razor/benchmarks/Microsoft.AspNetCore.Razor.Microbenchmarks/Serialization/RazorProjectInfoSerializationBenchmark.cs index 8db3ea53989..6b4c3dde1dc 100644 --- a/src/Razor/benchmarks/Microsoft.AspNetCore.Razor.Microbenchmarks/Serialization/RazorProjectInfoSerializationBenchmark.cs +++ b/src/Razor/benchmarks/Microsoft.AspNetCore.Razor.Microbenchmarks/Serialization/RazorProjectInfoSerializationBenchmark.cs @@ -67,7 +67,7 @@ public void Deserialize_Json() var projectInfo = DeserializeProjectInfo_Json(reader); if (projectInfo.ProjectWorkspaceState is null || - projectInfo.ProjectWorkspaceState.TagHelpers.Length != ProjectInfo.ProjectWorkspaceState?.TagHelpers.Length) + projectInfo.ProjectWorkspaceState.TagHelpers.Count != ProjectInfo.ProjectWorkspaceState.TagHelpers.Count) { throw new InvalidDataException(); } @@ -89,7 +89,7 @@ public void RoundTrip_Json() var projectInfo = DeserializeProjectInfo_Json(reader); if (projectInfo.ProjectWorkspaceState is null || - projectInfo.ProjectWorkspaceState.TagHelpers.Length != ProjectInfo.ProjectWorkspaceState?.TagHelpers.Length) + projectInfo.ProjectWorkspaceState.TagHelpers.Count != ProjectInfo.ProjectWorkspaceState.TagHelpers.Count) { throw new InvalidDataException(); } @@ -128,7 +128,7 @@ public void Deserialize_MessagePack() var projectInfo = DeserializeProjectInfo_MessagePack(_projectInfoMessagePackBytes); if (projectInfo.ProjectWorkspaceState is null || - projectInfo.ProjectWorkspaceState.TagHelpers.Length != ProjectInfo.ProjectWorkspaceState?.TagHelpers.Length) + projectInfo.ProjectWorkspaceState.TagHelpers.Count != ProjectInfo.ProjectWorkspaceState.TagHelpers.Count) { throw new InvalidDataException(); } @@ -142,7 +142,7 @@ public void RoundTrip_MessagePack() _buffer.Clear(); if (projectInfo.ProjectWorkspaceState is null || - projectInfo.ProjectWorkspaceState.TagHelpers.Length != ProjectInfo.ProjectWorkspaceState?.TagHelpers.Length) + projectInfo.ProjectWorkspaceState.TagHelpers.Count != ProjectInfo.ProjectWorkspaceState.TagHelpers.Count) { throw new InvalidDataException(); } diff --git a/src/Razor/src/Microsoft.AspNetCore.Razor.ExternalAccess.LegacyEditor/RazorWrapperFactory.CodeDocumentWrapper.cs b/src/Razor/src/Microsoft.AspNetCore.Razor.ExternalAccess.LegacyEditor/RazorWrapperFactory.CodeDocumentWrapper.cs index 21f88c0e7b2..5139552f838 100644 --- a/src/Razor/src/Microsoft.AspNetCore.Razor.ExternalAccess.LegacyEditor/RazorWrapperFactory.CodeDocumentWrapper.cs +++ b/src/Razor/src/Microsoft.AspNetCore.Razor.ExternalAccess.LegacyEditor/RazorWrapperFactory.CodeDocumentWrapper.cs @@ -47,7 +47,7 @@ public ImmutableArray GetTagHelperSpans() { builder.Add(new TagHelperSpan( ConvertSourceSpan(item.Span), - WrapAll(item.Binding.Descriptors, Wrap))); + WrapAll(item.Binding.TagHelpers, Wrap))); } return builder.ToImmutableAndClear(); diff --git a/src/Razor/src/Microsoft.AspNetCore.Razor.ExternalAccess.LegacyEditor/RazorWrapperFactory.TagHelperBindingWrapper.cs b/src/Razor/src/Microsoft.AspNetCore.Razor.ExternalAccess.LegacyEditor/RazorWrapperFactory.TagHelperBindingWrapper.cs index f28d39881aa..9ad1f5b3167 100644 --- a/src/Razor/src/Microsoft.AspNetCore.Razor.ExternalAccess.LegacyEditor/RazorWrapperFactory.TagHelperBindingWrapper.cs +++ b/src/Razor/src/Microsoft.AspNetCore.Razor.ExternalAccess.LegacyEditor/RazorWrapperFactory.TagHelperBindingWrapper.cs @@ -10,10 +10,10 @@ internal static partial class RazorWrapperFactory { private class TagHelperBindingWrapper(TagHelperBinding obj) : Wrapper(obj), IRazorTagHelperBinding { - private ImmutableArray _descriptors; + private ImmutableArray _tagHelpers; public ImmutableArray Descriptors - => InitializeArrayWithWrappedItems(ref _descriptors, Object.Descriptors, Wrap); + => InitializeArrayWithWrappedItems(ref _tagHelpers, Object.TagHelpers, Wrap); public ImmutableArray GetBoundRules(IRazorTagHelperDescriptor descriptor) { diff --git a/src/Razor/src/Microsoft.AspNetCore.Razor.ExternalAccess.LegacyEditor/RazorWrapperFactory.cs b/src/Razor/src/Microsoft.AspNetCore.Razor.ExternalAccess.LegacyEditor/RazorWrapperFactory.cs index 13ae732235f..19610b602e6 100644 --- a/src/Razor/src/Microsoft.AspNetCore.Razor.ExternalAccess.LegacyEditor/RazorWrapperFactory.cs +++ b/src/Razor/src/Microsoft.AspNetCore.Razor.ExternalAccess.LegacyEditor/RazorWrapperFactory.cs @@ -87,6 +87,21 @@ private static ImmutableArray InitializeArrayWithWrappedItems InitializeArrayWithWrappedItems( + ref ImmutableArray location, + IEnumerable list, + Func createWrapper) + where TInner : class + where TResult : class + { + if (location.IsDefault) + { + ImmutableInterlocked.InterlockedInitialize(ref location, WrapAll(list, createWrapper)); + } + + return location; + } + private static T Unwrap(object obj) where T : class => ((Wrapper)obj).Object; diff --git a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Diagnostics/MissingTagHelperTelemetryReporter.cs b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Diagnostics/MissingTagHelperTelemetryReporter.cs index e6a3944d3cc..2b4b95ff0da 100644 --- a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Diagnostics/MissingTagHelperTelemetryReporter.cs +++ b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Diagnostics/MissingTagHelperTelemetryReporter.cs @@ -32,7 +32,7 @@ public async ValueTask ReportRZ10012TelemetryAsync(DocumentContext documentConte } var tagHelpers = await documentContext.Project.GetTagHelpersAsync(cancellationToken).ConfigureAwait(false); - var tagHelperCount = tagHelpers.Length; + var tagHelperCount = tagHelpers.Count; var shouldReport = false; ImmutableInterlocked.AddOrUpdate( diff --git a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/ProjectSystem/RazorProjectService.cs b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/ProjectSystem/RazorProjectService.cs index 24891410954..a5aad1a5b0a 100644 --- a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/ProjectSystem/RazorProjectService.cs +++ b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/ProjectSystem/RazorProjectService.cs @@ -400,9 +400,9 @@ private Task AddOrUpdateProjectCoreAsync( UpdateProjectDocuments(updater, documents, project.Key); - if (!projectWorkspaceState.Equals(ProjectWorkspaceState.Default)) + if (!projectWorkspaceState.IsDefault) { - _logger.LogInformation($"Updating project '{project.Key}' TagHelpers ({projectWorkspaceState.TagHelpers.Length})."); + _logger.LogInformation($"Updating project '{project.Key}' TagHelpers ({projectWorkspaceState.TagHelpers.Count})."); } updater.UpdateProjectWorkspaceState(project.Key, projectWorkspaceState); diff --git a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/CodeActions/Razor/GenerateMethodCodeActionProvider.cs b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/CodeActions/Razor/GenerateMethodCodeActionProvider.cs index a0db39d014f..20f840812dc 100644 --- a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/CodeActions/Razor/GenerateMethodCodeActionProvider.cs +++ b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/CodeActions/Razor/GenerateMethodCodeActionProvider.cs @@ -116,20 +116,20 @@ private static bool TryGetEventNameAndMethodName( } var found = false; - foreach (var tagHelperDescriptor in binding.Descriptors) + foreach (var tagHelper in binding.TagHelpers) { - foreach (var attribute in tagHelperDescriptor.BoundAttributes) + foreach (var attribute in tagHelper.BoundAttributes) { if (attribute.Name == attributeName) { // We found the attribute that matches the directive attribute, now we need to check if the // tag helper it's bound to is an event handler. This filters out things like @ref and @rendermode - if (tagHelperDescriptor.Kind == TagHelperKind.EventHandler) + if (tagHelper.Kind == TagHelperKind.EventHandler) { // An event handler like "@onclick" - eventParameterType = tagHelperDescriptor.GetEventArgsType() ?? ""; + eventParameterType = tagHelper.GetEventArgsType() ?? ""; } - else if (tagHelperDescriptor.Kind == TagHelperKind.Bind) + else if (tagHelper.Kind == TagHelperKind.Bind) { // A bind tag helper, so either @bind-XX:after or @bind-XX:set, the latter of which has a parameter if (markupTagHelperDirectiveAttribute.TagHelperAttributeInfo.ParameterName == "set" && @@ -181,9 +181,9 @@ private static bool TryGetEventNameAndMethodName( eventParameterType = null; allowAsync = true; - foreach (var tagHelperDescriptor in binding.Descriptors) + foreach (var tagHelper in binding.TagHelpers) { - foreach (var attribute in tagHelperDescriptor.BoundAttributes) + foreach (var attribute in tagHelper.BoundAttributes) { if (attribute.Name == markupTagHelperDirectiveAttribute.TagHelperAttributeInfo.Name) { @@ -202,7 +202,7 @@ private static bool TryGetEventNameAndMethodName( if (attribute.IsGenericTypedProperty()) { - if (tagHelperDescriptor.TryGetGenericTypeNameFromComponent(binding, out var genericType) && + if (tagHelper.TryGetGenericTypeNameFromComponent(binding, out var genericType) && ComponentAttributeIntermediateNode.TryGetGenericActionArgument(attribute.TypeName.AsMemory(), genericType, out var argument)) { eventParameterType = argument.ToString(); diff --git a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/CodeActions/Razor/SimplifyFullyQualifiedComponentCodeActionProvider.cs b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/CodeActions/Razor/SimplifyFullyQualifiedComponentCodeActionProvider.cs index ae8fdba5709..7aeabc4e1c0 100644 --- a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/CodeActions/Razor/SimplifyFullyQualifiedComponentCodeActionProvider.cs +++ b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/CodeActions/Razor/SimplifyFullyQualifiedComponentCodeActionProvider.cs @@ -123,8 +123,8 @@ private static bool IsFullyQualifiedComponent(MarkupTagHelperElementSyntax eleme @namespace = string.Empty; componentName = string.Empty; - var descriptors = element.TagHelperInfo.BindingResult.Descriptors; - var boundTagHelper = descriptors.FirstOrDefault(static d => d.Kind == TagHelperKind.Component); + var tagHelpers = element.TagHelperInfo.BindingResult.TagHelpers; + var boundTagHelper = tagHelpers.FirstOrDefault(static d => d.Kind == TagHelperKind.Component); if (boundTagHelper is null) { return false; diff --git a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/CodeActions/Razor/SimplifyTagToSelfClosingCodeActionProvider.cs b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/CodeActions/Razor/SimplifyTagToSelfClosingCodeActionProvider.cs index e412ae97b03..5afe590e988 100644 --- a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/CodeActions/Razor/SimplifyTagToSelfClosingCodeActionProvider.cs +++ b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/CodeActions/Razor/SimplifyTagToSelfClosingCodeActionProvider.cs @@ -89,7 +89,7 @@ internal static bool IsApplicableTo(MarkupTagHelperElementSyntax markupElementSy return false; } - if (markupElementSyntax is not { TagHelperInfo.BindingResult.Descriptors: [.. var descriptors] }) + if (markupElementSyntax is not { TagHelperInfo.BindingResult.TagHelpers: { Count: > 0 } tagHelpers }) { return false; } @@ -101,7 +101,7 @@ internal static bool IsApplicableTo(MarkupTagHelperElementSyntax markupElementSy } // Get symbols for the markup element - var boundTagHelper = descriptors.FirstOrDefault(static d => d.Kind == TagHelperKind.Component); + var boundTagHelper = tagHelpers.FirstOrDefault(static d => d.Kind == TagHelperKind.Component); if (boundTagHelper == null) { return false; diff --git a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/Completion/DirectiveAttributeCompletionContext.cs b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/Completion/DirectiveAttributeCompletionContext.cs index 40a2bb2daa7..f55360f696a 100644 --- a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/Completion/DirectiveAttributeCompletionContext.cs +++ b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/Completion/DirectiveAttributeCompletionContext.cs @@ -2,10 +2,11 @@ // The .NET Foundation licenses this file to you under the MIT license. using System.Collections.Immutable; +using Microsoft.AspNetCore.Razor.Language; namespace Microsoft.CodeAnalysis.Razor.Completion; -internal record DirectiveAttributeCompletionContext +internal sealed record DirectiveAttributeCompletionContext { public required string SelectedAttributeName { get; init; } public string? SelectedParameterName { get; init; } @@ -14,4 +15,13 @@ internal record DirectiveAttributeCompletionContext public bool InAttributeName { get; init; } = true; public bool InParameterName { get; init; } public RazorCompletionOptions Options { get; init; } + + public bool AlreadySatisfiesParameter(BoundAttributeParameterDescriptor parameter, BoundAttributeDescriptor attribute) + => ExistingAttributes.Any( + (parameter, attribute), + static (name, arg) => + TagHelperMatchingConventions.SatisfiesBoundAttributeWithParameter(arg.parameter, name, arg.attribute)); + + public bool CanSatisfyAttribute(BoundAttributeDescriptor attribute) + => TagHelperMatchingConventions.CanSatisfyBoundAttribute(SelectedAttributeName, attribute); } diff --git a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/Completion/DirectiveAttributeCompletionItemProvider.AttributeCompletionDetails.cs b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/Completion/DirectiveAttributeCompletionItemProvider.AttributeCompletionDetails.cs new file mode 100644 index 00000000000..564cb17646f --- /dev/null +++ b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/Completion/DirectiveAttributeCompletionItemProvider.AttributeCompletionDetails.cs @@ -0,0 +1,32 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System.Collections.Immutable; +using Microsoft.CodeAnalysis.Razor.Tooltip; + +namespace Microsoft.CodeAnalysis.Razor.Completion; + +internal partial class DirectiveAttributeCompletionItemProvider +{ + private readonly struct AttributeCompletionDetails( + RazorCompletionItemKind kind, + ImmutableArray descriptions = default, + ImmutableArray commitCharacters = default) + { + public RazorCompletionItemKind Kind => kind; + + public ImmutableArray Descriptions => descriptions.NullToEmpty(); + public ImmutableArray CommitCharacters => commitCharacters.NullToEmpty(); + + public void Deconstruct( + out RazorCompletionItemKind kind, + out ImmutableArray descriptions, + out ImmutableArray commitCharacters) + => (kind, descriptions, commitCharacters) = (Kind, Descriptions, CommitCharacters); + + public void Deconstruct( + out ImmutableArray descriptions, + out ImmutableArray commitCharacters) + => (descriptions, commitCharacters) = (Descriptions, CommitCharacters); + } +} diff --git a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/Completion/DirectiveAttributeCompletionItemProvider.DefaultCommitCharacters.cs b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/Completion/DirectiveAttributeCompletionItemProvider.DefaultCommitCharacters.cs new file mode 100644 index 00000000000..72236580200 --- /dev/null +++ b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/Completion/DirectiveAttributeCompletionItemProvider.DefaultCommitCharacters.cs @@ -0,0 +1,37 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System.Collections.Immutable; + +namespace Microsoft.CodeAnalysis.Razor.Completion; + +internal partial class DirectiveAttributeCompletionItemProvider +{ + private static class DefaultCommitCharacters + { + private static readonly ImmutableArray s_equalsCommitCharacters = [EqualsCommit(false)]; + private static readonly ImmutableArray s_equalsSpaceCommitCharacters = [EqualsCommit(false), SpaceCommit]; + private static readonly ImmutableArray s_snippetEqualsCommitCharacters = [EqualsCommit(true)]; + private static readonly ImmutableArray s_snippetEqualsSpaceCommitCharacters = [EqualsCommit(true), SpaceCommit]; + private static readonly ImmutableArray s_spaceCommitCharacters = [SpaceCommit]; + + private static RazorCommitCharacter EqualsCommit(bool snippet) => new("=", Insert: !snippet); + private static RazorCommitCharacter SpaceCommit => new(" "); + + public static ImmutableArray Get(bool useEquals, bool useSpace, bool useSnippets) + => (useEquals, useSpace, useSnippets) switch + { + // Use equals with or without space (no snippets) + (true, false, false) => s_equalsCommitCharacters, + (true, true, false) => s_equalsSpaceCommitCharacters, + + // Use equals with or without space (using snippets) + (true, false, true) => s_snippetEqualsCommitCharacters, + (true, true, true) => s_snippetEqualsSpaceCommitCharacters, + + // No equals and with or without space (snippets not relevant) + (false, true, _) => s_spaceCommitCharacters, + (false, false, _) => [] + }; + } +} diff --git a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/Completion/DirectiveAttributeCompletionItemProvider.cs b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/Completion/DirectiveAttributeCompletionItemProvider.cs index 687a9df8cda..ceeef3f3321 100644 --- a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/Completion/DirectiveAttributeCompletionItemProvider.cs +++ b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/Completion/DirectiveAttributeCompletionItemProvider.cs @@ -6,6 +6,7 @@ using System.Collections.Immutable; using System.Diagnostics; using System.Linq; +using Microsoft.AspNetCore.Razor; using Microsoft.AspNetCore.Razor.Language; using Microsoft.AspNetCore.Razor.Language.Syntax; using Microsoft.AspNetCore.Razor.PooledObjects; @@ -15,13 +16,11 @@ namespace Microsoft.CodeAnalysis.Razor.Completion; -internal class DirectiveAttributeCompletionItemProvider : DirectiveAttributeCompletionItemProviderBase +internal partial class DirectiveAttributeCompletionItemProvider : DirectiveAttributeCompletionItemProviderBase { - private static readonly string s_quotedAttributeValueSnippet = "=\"$0\""; - private static readonly string s_unquotedAttributeValueSnippet = "=$0"; - - private static readonly ImmutableArray s_equalsCommitCharacters = [new("=")]; - private static readonly ImmutableArray s_snippetEqualsCommitCharacters = [new("=", Insert: false)]; + private const string Ellipsis = "..."; + private const string QuotedAttributeValueSnippetSuffix = "=\"$0\""; + private const string UnquotedAttributeValueSnippetSuffix = "=$0"; public override ImmutableArray GetCompletionItems(RazorCompletionContext context) { @@ -67,7 +66,8 @@ public override ImmutableArray GetCompletionItems(RazorComp } var inSnippetContext = InSnippetContext(owner, context.Options); - var directiveAttributeCompletionContext = new DirectiveAttributeCompletionContext() + + var completionContext = new DirectiveAttributeCompletionContext() { SelectedAttributeName = attributeName, SelectedParameterName = parameterName, @@ -78,13 +78,11 @@ public override ImmutableArray GetCompletionItems(RazorComp Options = context.Options }; - return GetAttributeCompletions(containingTagName, directiveAttributeCompletionContext, context.TagHelperDocumentContext); + return GetAttributeCompletions(containingTagName, completionContext, context.TagHelperDocumentContext); - static bool InSnippetContext( - RazorSyntaxNode owner, - RazorCompletionOptions razorCompletionOptions) + static bool InSnippetContext(RazorSyntaxNode owner, RazorCompletionOptions options) { - return razorCompletionOptions.SnippetsSupported + return options.SnippetsSupported // Don't create snippet text when attribute is already in the tag and we are trying to replace it // Otherwise you could have something like @onabort=""="" && owner is not (MarkupTagHelperDirectiveAttributeSyntax or MarkupAttributeBlockSyntax) @@ -95,315 +93,324 @@ static bool InSnippetContext( // Internal for testing internal static ImmutableArray GetAttributeCompletions( string containingTagName, - DirectiveAttributeCompletionContext context, - TagHelperDocumentContext tagHelperDocumentContext) + DirectiveAttributeCompletionContext completionContext, + TagHelperDocumentContext documentContext) { - var descriptorsForTag = TagHelperFacts.GetTagHelpersGivenTag(tagHelperDocumentContext, containingTagName, parentTag: null); - if (descriptorsForTag.Length == 0) + var tagHelpersForTag = TagHelperFacts.GetTagHelpersGivenTag(documentContext, containingTagName, parentTag: null); + if (tagHelpersForTag.IsEmpty) { - // If the current tag has no possible descriptors then we can't have any directive attributes. + // If the current tag has no possible tag helpers then we can't have any directive attributes. return []; } // Use ordinal dictionary because attributes are case sensitive when matching - using var _ = SpecializedPools.GetPooledStringDictionary<(ImmutableArray, ImmutableArray, RazorCompletionItemKind kind)>(out var attributeCompletions); + using var _ = SpecializedPools.GetPooledStringDictionary(out var attributeCompletions); - // Collect indexer descriptors and their parent tag helper type names. Indexer descriptors indicate an attribute prefix - // for which they apply. That can be used in an attribute name context to determine potential parameters. Eg, + // Collect indexer bound attributes and their parent tag helper type names. Indexer attributes indicate an attribute prefix + // for which they apply. That can be used in an attribute name context to determine potential parameters. E.g., // there exists an indexer indicating it applies to attributes that start with "@bind-" and specifies six different // parameters applicable for those attributes (":format", ":event", ":culture", ":get", ":set", ":after") - var indexerDescriptors = CollectIndexerDescriptors(descriptorsForTag, context); - - foreach (var descriptor in descriptorsForTag) + var indexerAttributes = new MemoryBuilder(initialCapacity: 8, clearArray: true); + try { - foreach (var attributeDescriptor in descriptor.BoundAttributes) + CollectIndexerDescriptors(tagHelpersForTag, completionContext, ref indexerAttributes); + + foreach (var tagHelper in tagHelpersForTag) { - if (!attributeDescriptor.IsDirectiveAttribute) + foreach (var attribute in tagHelper.BoundAttributes) { - // We don't care about non-directive attributes - continue; + if (attribute.IsDirectiveAttribute) + { + AddAttributeNameCompletions(attribute, completionContext, attributeCompletions); + AddParameterNameCompletions(attribute, indexerAttributes.AsMemory().Span, completionContext, attributeCompletions); + } } - - AddAttributeNameCompletions(descriptor, attributeDescriptor, context, attributeCompletions); - AddParameterNameCompletions(descriptor, attributeDescriptor, indexerDescriptors, context, attributeCompletions); } - } - // Use the mapping populated above to create completion items - return CreateCompletionItems(context, attributeCompletions); + // Use the mapping populated above to create completion items + return CreateCompletionItems(completionContext, attributeCompletions); + } + finally + { + indexerAttributes.Dispose(); + } } - private static ImmutableArray<(BoundAttributeDescriptor, string)> CollectIndexerDescriptors( - ImmutableArray descriptorsForTag, - DirectiveAttributeCompletionContext context) + private static void CollectIndexerDescriptors( + TagHelperCollection tagHelpersForTag, + DirectiveAttributeCompletionContext completionContext, + ref MemoryBuilder builder) { - if (context.InParameterName) + if (completionContext.InParameterName) { // No need to calculate the indexers When in a parameter name - return []; + return; } - using var allIndexers = new PooledArrayBuilder<(BoundAttributeDescriptor, string)>(); - - foreach (var descriptor in descriptorsForTag) + foreach (var tagHelper in tagHelpersForTag) { - foreach (var attributeDescriptor in descriptor.BoundAttributes) + foreach (var attribute in tagHelper.BoundAttributes) { - if (!attributeDescriptor.IsDirectiveAttribute) + if (attribute.IsDirectiveAttribute && !attribute.IndexerNamePrefix.IsNullOrEmpty()) { - // We don't care about non-directive attributes - continue; - } - - if (!attributeDescriptor.IndexerNamePrefix.IsNullOrEmpty()) - { - allIndexers.Add((attributeDescriptor, descriptor.TypeName)); + builder.Append(attribute); } } } - - return allIndexers.ToImmutableAndClear(); } private static void AddAttributeNameCompletions( - TagHelperDescriptor descriptor, - BoundAttributeDescriptor attributeDescriptor, - DirectiveAttributeCompletionContext context, - Dictionary, ImmutableArray, RazorCompletionItemKind kind)> attributeCompletions) + BoundAttributeDescriptor attribute, + DirectiveAttributeCompletionContext completionContext, + Dictionary attributeCompletions) { - if (!context.InAttributeName) + if (!completionContext.InAttributeName) { // Only add attribute name completions when in an attribute name context return; } - var isIndexer = context.SelectedAttributeName.EndsWith("...", StringComparison.Ordinal); - var descriptionInfo = BoundAttributeDescriptionInfo.From(attributeDescriptor, isIndexer, descriptor.TypeName); + var isIndexer = completionContext.SelectedAttributeName.EndsWith(Ellipsis, StringComparison.Ordinal); + var descriptionInfo = BoundAttributeDescriptionInfo.From(attribute, isIndexer, attribute.Parent.TypeName); - if (!TryAddCompletion(attributeDescriptor.Name, descriptionInfo, descriptor, context, RazorCompletionItemKind.DirectiveAttribute, attributeCompletions) && attributeDescriptor.Parameters.Length > 0) + var tagHelper = attribute.Parent; + + if (!TryAddAttributeCompletion(attribute.Name, descriptionInfo, tagHelper, completionContext, attributeCompletions) && + attribute.Parameters.Length > 0) { // This attribute has parameters and the base attribute name (@bind) is already satisfied. We need to check if there are any valid // parameters left to be provided, if so, we need to still represent the base attribute name in the completion list. - foreach (var parameterDescriptor in attributeDescriptor.Parameters) + foreach (var parameter in attribute.Parameters) { - if (!context.ExistingAttributes.Any(name => TagHelperMatchingConventions.SatisfiesBoundAttributeWithParameter(parameterDescriptor, name, attributeDescriptor))) + if (!completionContext.AlreadySatisfiesParameter(parameter, attribute)) { // This bound attribute parameter has not had a completion entry added for it, re-represent the base attribute name in the completion list - AddCompletion(attributeDescriptor.Name, descriptionInfo, descriptor, context, RazorCompletionItemKind.DirectiveAttribute, attributeCompletions); + AddAttributeCompletion(attribute.Name, descriptionInfo, tagHelper, completionContext, attributeCompletions); break; } } } - if (!attributeDescriptor.IndexerNamePrefix.IsNullOrEmpty()) + if (!attribute.IndexerNamePrefix.IsNullOrEmpty()) { - TryAddCompletion(attributeDescriptor.IndexerNamePrefix + "...", descriptionInfo, descriptor, context, RazorCompletionItemKind.DirectiveAttribute, attributeCompletions); + TryAddAttributeCompletion( + attribute.IndexerNamePrefix + Ellipsis, descriptionInfo, tagHelper, completionContext, attributeCompletions); } } private static void AddParameterNameCompletions( - TagHelperDescriptor descriptor, - BoundAttributeDescriptor attributeDescriptor, - ImmutableArray<(BoundAttributeDescriptor, string)> indexerDescriptors, - DirectiveAttributeCompletionContext context, - Dictionary, ImmutableArray, RazorCompletionItemKind)> attributeCompletions) + BoundAttributeDescriptor attribute, + ReadOnlySpan indexerAttributes, + DirectiveAttributeCompletionContext completionContext, + Dictionary attributeCompletions) { - if (context.InAttributeName && !attributeDescriptor.IndexerNamePrefix.IsNullOrEmpty()) + if (completionContext.InAttributeName && !attribute.IndexerNamePrefix.IsNullOrEmpty()) { // Don't add parameters on indexers in attribute name contexts return; } - else if (context.InParameterName && !TagHelperMatchingConventions.CanSatisfyBoundAttribute(context.SelectedAttributeName, attributeDescriptor)) + + if (completionContext.InParameterName && !completionContext.CanSatisfyAttribute(attribute)) { // Don't add parameters when the selected attribute name can't satisfy the given attribute descriptor in parameter name contexts return; } // Add indexer parameter completions first so they display first in completion descriptions. - foreach (var (indexerDescriptor, parentTagHelperTypeName) in indexerDescriptors) + foreach (var indexerAttribute in indexerAttributes) { - if (!attributeDescriptor.Name.StartsWith(indexerDescriptor.IndexerNamePrefix!)) + var indexerNamePrefix = indexerAttribute.IndexerNamePrefix.AssumeNotNull(); + + if (!attribute.Name.StartsWith(indexerNamePrefix)) { continue; } - AddCompletionsForParameters(indexerDescriptor.Parameters, descriptor, attributeDescriptor, parentTagHelperTypeName, context, attributeCompletions); + AddCompletionsForParameters(attribute, indexerAttribute.Parameters, completionContext, attributeCompletions); } // Then add regular parameter completions - AddCompletionsForParameters(attributeDescriptor.Parameters, descriptor, attributeDescriptor, descriptor.TypeName, context, attributeCompletions); + AddCompletionsForParameters(attribute, attribute.Parameters, completionContext, attributeCompletions); return; static void AddCompletionsForParameters( - ImmutableArray parameterDescriptors, - TagHelperDescriptor descriptor, - BoundAttributeDescriptor attributeDescriptor, - string parentTagHelperTypeName, - DirectiveAttributeCompletionContext context, - Dictionary, ImmutableArray, RazorCompletionItemKind)> attributeCompletions) + BoundAttributeDescriptor attribute, + ImmutableArray parameters, + DirectiveAttributeCompletionContext completionContext, + Dictionary attributeCompletions) { - foreach (var parameterDescriptor in parameterDescriptors) + var tagHelper = attribute.Parent; + + foreach (var parameter in parameters) { - if (context.ExistingAttributes.Any( - (parameterDescriptor, attributeDescriptor), - static (name, arg) => - TagHelperMatchingConventions.SatisfiesBoundAttributeWithParameter(arg.parameterDescriptor, name, arg.attributeDescriptor))) + if (completionContext.AlreadySatisfiesParameter(parameter, attribute)) { // There's already an existing attribute that satisfies this parameter, don't show it in the completion list. continue; } - var descriptionInfo = BoundAttributeDescriptionInfo.From(parameterDescriptor, parentTagHelperTypeName); - var displayName = context.InParameterName - ? parameterDescriptor.Name - : $"{attributeDescriptor.Name}:{parameterDescriptor.Name}"; + var displayName = completionContext.InParameterName + ? parameter.Name + : $"{attribute.Name}:{parameter.Name}"; - AddCompletion(displayName, descriptionInfo, descriptor, context, RazorCompletionItemKind.DirectiveAttributeParameter, attributeCompletions); + AddParameterCompletion( + displayName, + descriptionInfo: BoundAttributeDescriptionInfo.From(parameter), + tagHelper, + completionContext, + attributeCompletions); } } } - private static ImmutableArray CreateCompletionItems(DirectiveAttributeCompletionContext context, Dictionary, ImmutableArray, RazorCompletionItemKind kind)> attributeCompletions) + private static ImmutableArray CreateCompletionItems( + DirectiveAttributeCompletionContext completionContext, + Dictionary attributeCompletions) { using var completionItems = new PooledArrayBuilder(capacity: attributeCompletions.Count); - foreach (var (displayText, (attributeDescriptions, commitCharacters, kind)) in attributeCompletions) + foreach (var (displayText, (kind, descriptions, commitCharacters)) in attributeCompletions) { - var originalInsertTextMemory = displayText.AsMemory(); + var isIndexer = displayText.EndsWith(Ellipsis, StringComparison.Ordinal); + var isSnippet = !isIndexer && completionContext.UseSnippets; + var autoInsertAttributeQuotes = completionContext.Options.AutoInsertAttributeQuotes; - // Strip off the @ from the insertion text. This change is here to align the insertion text with the - // completion hooks into VS and VSCode. Basically, completion triggers when `@` is typed so we don't - // want to insert `@bind` because `@` already exists. - var insertTextMemory = originalInsertTextMemory.Span.StartsWith('@') - ? originalInsertTextMemory[1..] - : originalInsertTextMemory; + var insertText = ComputeInsertText(displayText, isIndexer, isSnippet, autoInsertAttributeQuotes); - var isSnippet = false; - string insertText; + Debug.Assert(kind is RazorCompletionItemKind.DirectiveAttribute or RazorCompletionItemKind.DirectiveAttributeParameter); - // Indexer attribute, we don't want to insert with the triple dot. - if (MemoryExtensions.EndsWith(insertTextMemory.Span, "...".AsSpan())) - { - insertText = insertTextMemory[..^3].ToString(); - } - else if (context.UseSnippets) - { - var suffixText = context.Options.AutoInsertAttributeQuotes ? s_quotedAttributeValueSnippet : s_unquotedAttributeValueSnippet; + var razorCompletionItem = kind == RazorCompletionItemKind.DirectiveAttribute + ? RazorCompletionItem.CreateDirectiveAttribute(displayText, insertText, descriptionInfo: new(descriptions), commitCharacters, isSnippet) + : RazorCompletionItem.CreateDirectiveAttributeParameter(displayText, insertText, descriptionInfo: new(descriptions), commitCharacters, isSnippet); - // We are trying for snippet text only for non-indexer attributes, e.g. *not* something like "@bind-..." - insertText = string.Create( - length: insertTextMemory.Length + suffixText.Length, - state: (insertTextMemory, suffixText), - static (desination, state) => - { - var (baseTextMemory, suffixText) = state; + completionItems.Add(razorCompletionItem); + } - baseTextMemory.Span.CopyTo(desination); - suffixText.AsSpan().CopyTo(desination[baseTextMemory.Length..]); - }); + return completionItems.ToImmutableAndClear(); + } - isSnippet = true; - } - else - { - // Don't create another string unnecessarily, even though ReadOnlySpan.ToString() special-cases the string to avoid allocation - insertText = insertTextMemory.Span == originalInsertTextMemory.Span ? displayText : insertTextMemory.ToString(); - } + private static string ComputeInsertText(string displayText, bool isIndexer, bool isSnippet, bool autoInsertAttributeQuotes) + { + var originalInsertText = displayText.AsMemory(); - Debug.Assert(kind is RazorCompletionItemKind.DirectiveAttribute or RazorCompletionItemKind.DirectiveAttributeParameter); - var razorCompletionItem = (kind == RazorCompletionItemKind.DirectiveAttribute) - ? RazorCompletionItem.CreateDirectiveAttribute(displayText, insertText, descriptionInfo: new(attributeDescriptions), commitCharacters, isSnippet) - : RazorCompletionItem.CreateDirectiveAttributeParameter(displayText, insertText, descriptionInfo: new(attributeDescriptions), commitCharacters, isSnippet); + // Strip off the @ from the insertion text. This change is here to align the insertion text with the + // completion hooks into VS and VSCode. Basically, completion triggers when `@` is typed so we don't + // want to insert `@bind` because `@` already exists. + var insertText = originalInsertText.Span.StartsWith('@') + ? originalInsertText[1..] + : originalInsertText; - completionItems.Add(razorCompletionItem); + // Indexer attribute, we don't want to insert with the triple dot. + if (isIndexer) + { + Debug.Assert(insertText.Span.EndsWith(Ellipsis, StringComparison.Ordinal)); + return insertText[..^3].ToString(); } - return completionItems.ToImmutableAndClear(); + if (isSnippet) + { + var suffixText = autoInsertAttributeQuotes + ? QuotedAttributeValueSnippetSuffix + : UnquotedAttributeValueSnippetSuffix; + + // We are trying for snippet text only for non-indexer attributes, e.g. *not* something like "@bind-..." + return string.Create( + length: insertText.Length + suffixText.Length, + state: (insertText, suffixText), + static (destination, state) => + { + var (insertText, suffixText) = state; + + insertText.Span.CopyTo(destination); + suffixText.AsSpan().CopyTo(destination[insertText.Length..]); + }); + } + + // Don't create another string unnecessarily, even though ReadOnlySpan.ToString() special-cases + // the string to avoid allocation. + return insertText.Span == originalInsertText.Span + ? displayText + : insertText.ToString(); } - private static bool TryAddCompletion( + private static bool TryAddAttributeCompletion( string attributeName, BoundAttributeDescriptionInfo descriptionInfo, - TagHelperDescriptor tagHelperDescriptor, - DirectiveAttributeCompletionContext context, - RazorCompletionItemKind kind, - Dictionary, ImmutableArray, RazorCompletionItemKind kind)> attributeCompletions) + TagHelperDescriptor tagHelper, + DirectiveAttributeCompletionContext completionContext, + Dictionary attributeCompletions) { - if (context.SelectedAttributeName != attributeName && - context.ExistingAttributes.Any(attributeName, static (name, attributeName) => name == attributeName)) + if (completionContext.SelectedAttributeName != attributeName && + completionContext.ExistingAttributes.Contains(attributeName)) { // Attribute is already present on this element and it is not the selected attribute. // It shouldn't exist in the completion list. return false; } - AddCompletion(attributeName, descriptionInfo, tagHelperDescriptor, context, kind, attributeCompletions); + AddAttributeCompletion(attributeName, descriptionInfo, tagHelper, completionContext, attributeCompletions); return true; } - private static void AddCompletion( + private static void AddAttributeCompletion( string attributeName, BoundAttributeDescriptionInfo descriptionInfo, - TagHelperDescriptor tagHelperDescriptor, - DirectiveAttributeCompletionContext context, + TagHelperDescriptor tagHelper, + DirectiveAttributeCompletionContext completionContext, + Dictionary attributeCompletions) + => AddCompletion(RazorCompletionItemKind.DirectiveAttribute, + attributeName, descriptionInfo, tagHelper, completionContext, attributeCompletions); + + private static void AddParameterCompletion( + string attributeName, + BoundAttributeDescriptionInfo descriptionInfo, + TagHelperDescriptor tagHelper, + DirectiveAttributeCompletionContext completionContext, + Dictionary attributeCompletions) + => AddCompletion(RazorCompletionItemKind.DirectiveAttributeParameter, + attributeName, descriptionInfo, tagHelper, completionContext, attributeCompletions); + + private static void AddCompletion( RazorCompletionItemKind kind, - Dictionary, ImmutableArray, RazorCompletionItemKind kind)> attributeCompletions) + string attributeName, + BoundAttributeDescriptionInfo descriptionInfo, + TagHelperDescriptor tagHelper, + DirectiveAttributeCompletionContext completionContext, + Dictionary attributeCompletions) { - if (!attributeCompletions.TryGetValue(attributeName, out var attributeDetails)) - { - attributeDetails = ([], [], RazorCompletionItemKind.Attribute); - } + ImmutableArray descriptions; + ImmutableArray commitCharacters; - (var attributeDescriptions, var commitCharacters, _) = attributeDetails; + if (attributeCompletions.TryGetValue(attributeName, out var existingDetails)) + { + (descriptions, commitCharacters) = existingDetails; - if (!attributeDescriptions.Contains(descriptionInfo)) + if (!descriptions.Contains(descriptionInfo)) + { + descriptions = descriptions.Add(descriptionInfo); + } + } + else { - attributeDescriptions = attributeDescriptions.Add(descriptionInfo); + descriptions = [descriptionInfo]; + commitCharacters = []; } // Verify not an indexer attribute, as those don't commit with standard chars - if (!attributeName.EndsWith("...", StringComparison.Ordinal)) + if (!attributeName.EndsWith(Ellipsis, StringComparison.Ordinal)) { - var isEqualCommitChar = commitCharacters.Any(static c => c.Character == "="); - var isSpaceCommitChar = commitCharacters.Any(static c => c.Character == " "); - - // We don't add "=" as a commit character when using VSCode trigger characters. - isEqualCommitChar |= !context.Options.UseVsCodeCompletionCommitCharacters; - - foreach (var boundAttribute in tagHelperDescriptor.BoundAttributes) - { - isSpaceCommitChar |= boundAttribute.IsBooleanProperty; + // We always add "=" as a commit character in Visual Studio. + var useEqualsCommit = !completionContext.Options.UseVsCodeCompletionCommitCharacters || + commitCharacters.Any(static c => c.Character == "="); - if (isSpaceCommitChar) - { - break; - } - } + var useSpaceCommit = commitCharacters.Any(static c => c.Character == " ") || + tagHelper.BoundAttributes.Any(static a => a.IsBooleanProperty); - // Determine if we have a common commit character set - commitCharacters = (isEqualCommitChar, isSpaceCommitChar, context.UseSnippets) switch - { - (true, false, false) => s_equalsCommitCharacters, - (true, false, true) => s_snippetEqualsCommitCharacters, - _ => [] - }; - - if (commitCharacters.IsEmpty) - { - if (isEqualCommitChar) - { - commitCharacters = commitCharacters.Add(new("=", Insert: !context.UseSnippets)); - } - - if (isSpaceCommitChar) - { - commitCharacters = commitCharacters.Add(new(" ")); - } - } + commitCharacters = DefaultCommitCharacters.Get(useEqualsCommit, useSpaceCommit, completionContext.UseSnippets); } - attributeCompletions[attributeName] = (attributeDescriptions, commitCharacters, kind); + attributeCompletions[attributeName] = new(kind, descriptions, commitCharacters); } } diff --git a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/Completion/TagHelperCompletionProvider.cs b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/Completion/TagHelperCompletionProvider.cs index 11ec80c3498..b3c53185b15 100644 --- a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/Completion/TagHelperCompletionProvider.cs +++ b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/Completion/TagHelperCompletionProvider.cs @@ -114,7 +114,7 @@ private ImmutableArray GetAttributeCompletions( RazorCompletionOptions options) { var ancestors = containingAttribute.Parent.Ancestors(); - var nonDirectiveAttributeTagHelpers = tagHelperDocumentContext.TagHelpers.WhereAsArray( + var nonDirectiveAttributeTagHelpers = tagHelperDocumentContext.TagHelpers.Where( static tagHelper => !tagHelper.BoundAttributes.Any(static attribute => attribute.IsDirectiveAttribute)); var filteredContext = TagHelperDocumentContext.Create(tagHelperDocumentContext.Prefix, nonDirectiveAttributeTagHelpers); var (ancestorTagName, ancestorIsTagHelper) = TagHelperFacts.GetNearestAncestorTagInfo(ancestors); diff --git a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/Completion/TagHelperCompletionService.cs b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/Completion/TagHelperCompletionService.cs index 35688f57f74..45853c1e04a 100644 --- a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/Completion/TagHelperCompletionService.cs +++ b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/Completion/TagHelperCompletionService.cs @@ -6,6 +6,7 @@ using System.Collections.Immutable; using System.Diagnostics; using System.Linq; +using Microsoft.AspNetCore.Razor; using Microsoft.AspNetCore.Razor.Language; using Microsoft.AspNetCore.Razor.PooledObjects; using Microsoft.CodeAnalysis.Razor.Workspaces; @@ -15,6 +16,9 @@ namespace Microsoft.CodeAnalysis.Razor.Completion; internal class TagHelperCompletionService : ITagHelperCompletionService { + private static readonly HashSetPool s_shortNameSetPool = + HashSetPool.Create(ShortNameToFullyQualifiedComparer.Instance); + private static readonly HashSet s_emptyHashSet = new(); // This API attempts to understand a users context as they're typing in a Razor file to provide TagHelper based attribute IntelliSense. @@ -29,10 +33,7 @@ internal class TagHelperCompletionService : ITagHelperCompletionService // BoundAttributeDescriptor. By doing this a user can see what C# type a TagHelper expects for the attribute. public AttributeCompletionResult GetAttributeCompletions(AttributeCompletionContext completionContext) { - if (completionContext is null) - { - throw new ArgumentNullException(nameof(completionContext)); - } + ArgHelper.ThrowIfNull(completionContext); var attributeCompletions = completionContext.ExistingCompletions.ToDictionary( completion => completion, @@ -40,8 +41,8 @@ public AttributeCompletionResult GetAttributeCompletions(AttributeCompletionCont StringComparer.OrdinalIgnoreCase); var documentContext = completionContext.DocumentContext; - var descriptorsForTag = TagHelperFacts.GetTagHelpersGivenTag(documentContext, completionContext.CurrentTagName, completionContext.CurrentParentTagName); - if (descriptorsForTag.Length == 0) + var tagHelpersForTag = TagHelperFacts.GetTagHelpersGivenTag(documentContext, completionContext.CurrentTagName, completionContext.CurrentParentTagName); + if (tagHelpersForTag.IsEmpty) { // If the current tag has no possible descriptors then we can't have any additional attributes. return AttributeCompletionResult.Create(attributeCompletions); @@ -59,9 +60,9 @@ public AttributeCompletionResult GetAttributeCompletions(AttributeCompletionCont using var _ = HashSetPool.GetPooledObject(out var applicableDescriptors); - if (applicableTagHelperBinding is { Descriptors: var descriptors }) + if (applicableTagHelperBinding is { TagHelpers: var tagHelpers }) { - applicableDescriptors.UnionWith(descriptors); + applicableDescriptors.UnionWith(tagHelpers); } var unprefixedTagName = completionContext.CurrentTagName[prefix.Length..]; @@ -73,11 +74,11 @@ public AttributeCompletionResult GetAttributeCompletions(AttributeCompletionCont attributeCompletions.Clear(); } - foreach (var descriptor in descriptorsForTag) + foreach (var tagHelper in tagHelpersForTag) { - if (applicableDescriptors.Contains(descriptor)) + if (applicableDescriptors.Contains(tagHelper)) { - foreach (var attributeDescriptor in descriptor.BoundAttributes) + foreach (var attributeDescriptor in tagHelper.BoundAttributes) { if (!attributeDescriptor.Name.IsNullOrEmpty()) { @@ -93,7 +94,7 @@ public AttributeCompletionResult GetAttributeCompletions(AttributeCompletionCont else { var htmlNameToBoundAttribute = new Dictionary(StringComparer.OrdinalIgnoreCase); - foreach (var attributeDescriptor in descriptor.BoundAttributes) + foreach (var attributeDescriptor in tagHelper.BoundAttributes) { if (attributeDescriptor.Name != null) { @@ -106,7 +107,7 @@ public AttributeCompletionResult GetAttributeCompletions(AttributeCompletionCont } } - foreach (var rule in descriptor.TagMatchingRules) + foreach (var rule in tagHelper.TagMatchingRules) { foreach (var requiredAttribute in rule.Attributes) { @@ -152,10 +153,7 @@ void UpdateCompletions(string attributeName, BoundAttributeDescriptor? possibleD public ElementCompletionResult GetElementCompletions(ElementCompletionContext completionContext) { - if (completionContext is null) - { - throw new ArgumentNullException(nameof(completionContext)); - } + ArgHelper.ThrowIfNull(completionContext); var elementCompletions = new Dictionary>(StringComparer.Ordinal); @@ -170,11 +168,16 @@ public ElementCompletionResult GetElementCompletions(ElementCompletionContext co var tagAttributes = completionContext.Attributes; - var catchAllDescriptors = new HashSet(); + var catchAllTagHelpers = new HashSet(); var prefix = completionContext.DocumentContext.Prefix ?? string.Empty; - var possibleChildDescriptors = TagHelperFacts.GetTagHelpersGivenParent(completionContext.DocumentContext, completionContext.ContainingParentTagName); - possibleChildDescriptors = FilterFullyQualifiedCompletions(possibleChildDescriptors); - foreach (var possibleDescriptor in possibleChildDescriptors) + + var possibleChildTagHelpers = TagHelperFacts.GetTagHelpersGivenParent( + completionContext.DocumentContext, + completionContext.ContainingParentTagName); + + possibleChildTagHelpers = FilterFullyQualifiedTagHelpers(possibleChildTagHelpers); + + foreach (var possibleDescriptor in possibleChildTagHelpers) { var addRuleCompletions = false; var checkAttributeRules = true; @@ -182,14 +185,14 @@ public ElementCompletionResult GetElementCompletions(ElementCompletionContext co foreach (var rule in possibleDescriptor.TagMatchingRules) { - if (!TagHelperMatchingConventions.SatisfiesParentTag(rule, completionContext.ContainingParentTagName.AsSpanOrDefault())) + if (!TagHelperMatchingConventions.SatisfiesParentTag(rule, completionContext.ContainingParentTagName.AsSpan())) { continue; } if (rule.TagName == TagHelperMatchingConventions.ElementCatchAllName) { - catchAllDescriptors.Add(possibleDescriptor); + catchAllTagHelpers.Add(possibleDescriptor); } else if (elementCompletions.ContainsKey(rule.TagName)) { @@ -233,19 +236,16 @@ public ElementCompletionResult GetElementCompletions(ElementCompletionContext co // We needed to track all catch-alls and update their completions after all other completions have been completed. // This way, any TagHelper added completions will also have catch-alls listed under their entries. - foreach (var catchAllDescriptor in catchAllDescriptors) + foreach (var catchAllTagHelper in catchAllTagHelpers) { - foreach (var kvp in elementCompletions) + foreach (var (completionTagName, completionTagHelpers) in elementCompletions) { - var completionTagName = kvp.Key; - var tagHelperDescriptors = kvp.Value; - - if (tagHelperDescriptors.Count > 0 || + if (completionTagHelpers.Count > 0 || (!string.IsNullOrEmpty(prefix) && completionTagName.StartsWith(prefix, StringComparison.OrdinalIgnoreCase))) { // The current completion either has other TagHelper's associated with it or is prefixed with a non-empty // TagHelper prefix. - UpdateCompletions(completionTagName, catchAllDescriptor, elementCompletions, tagHelperDescriptors); + UpdateCompletions(completionTagName, catchAllTagHelper, elementCompletions, completionTagHelpers); } } } @@ -303,17 +303,17 @@ private void AddAllowedChildrenCompletions( return; } - foreach (var descriptor in binding.Descriptors) + foreach (var tagHelper in binding.TagHelpers) { - foreach (var childTag in descriptor.AllowedChildTags) + foreach (var childTag in tagHelper.AllowedChildTags) { var prefixedName = string.Concat(prefix, childTag.Name); - var descriptors = TagHelperFacts.GetTagHelpersGivenTag( + var tagHelpersForTag = TagHelperFacts.GetTagHelpersGivenTag( completionContext.DocumentContext, prefixedName, completionContext.ContainingParentTagName); - if (descriptors.Length == 0) + if (tagHelpersForTag.IsEmpty) { if (!elementCompletions.ContainsKey(prefixedName)) { @@ -329,47 +329,33 @@ private void AddAllowedChildrenCompletions( elementCompletions[prefixedName] = existingRuleDescriptors; } - existingRuleDescriptors.AddRange(descriptors); + existingRuleDescriptors.UnionWith(tagHelpersForTag); } } } - private static ImmutableArray FilterFullyQualifiedCompletions(ImmutableArray possibleChildDescriptors) + private static TagHelperCollection FilterFullyQualifiedTagHelpers(TagHelperCollection tagHelpers) { - // Iterate once through the list to tease apart fully qualified and short name TagHelpers - using var fullyQualifiedTagHelpers = new PooledArrayBuilder(); - var shortNameTagHelpers = new HashSet(ShortNameToFullyQualifiedComparer.Instance); - - foreach (var descriptor in possibleChildDescriptors) - { - if (descriptor.IsFullyQualifiedNameMatch) - { - fullyQualifiedTagHelpers.Add(descriptor); - } - else - { - shortNameTagHelpers.Add(descriptor); - } - } + // We want to filter 'tagHelpers' and remove any tag helpers that require a fully-qualified name match + // but have a short name match present. - // Re-combine the short named & fully qualified TagHelpers but filter out any fully qualified TagHelpers that have a short - // named representation already. - using var filteredList = new PooledArrayBuilder(capacity: shortNameTagHelpers.Count); - filteredList.AddRange(shortNameTagHelpers); + // First, collect all "short name" tag helpers, i.e. those that do not require a fully qualified name match. + using var _ = s_shortNameSetPool.GetPooledObject(out var shortNameSet); - foreach (var fullyQualifiedTagHelper in fullyQualifiedTagHelpers) + foreach (var tagHelper in tagHelpers) { - if (!shortNameTagHelpers.Contains(fullyQualifiedTagHelper)) + if (!tagHelper.IsFullyQualifiedNameMatch) { - // Unimported completion item that isn't represented in a short named form. - filteredList.Add(fullyQualifiedTagHelper); - } - else - { - // There's already a shortname variant of this item, don't include it. + shortNameSet.Add(tagHelper); } } - return filteredList.ToImmutableAndClear(); + return tagHelpers.Where(shortNameSet, static (tagHelper, shortNameSet) => + { + // We want to keep tag helpers that either: + // 1. Do not require a fully qualified name match (i.e., short name tag helpers). + // 2. Are fully qualified tag helpers that do not have a corresponding short name tag helper. + return !tagHelper.IsFullyQualifiedNameMatch || !shortNameSet.Contains(tagHelper); + }); } } diff --git a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/Extensions/ProjectExtensions.cs b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/Extensions/ProjectExtensions.cs index 967f55a17d7..d7319c698d5 100644 --- a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/Extensions/ProjectExtensions.cs +++ b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/Extensions/ProjectExtensions.cs @@ -31,7 +31,7 @@ internal static class ProjectExtensions /// /// A telemetry event will be reported to . /// - public static async ValueTask> GetTagHelpersAsync( + public static async ValueTask GetTagHelpersAsync( this Project project, RazorProjectEngine projectEngine, ITelemetryReporter telemetryReporter, @@ -50,11 +50,11 @@ public static async ValueTask> GetTagHelpers return []; } - using var pooledHashSet = HashSetPool.GetPooledObject(out var results); + using var builder = new TagHelperCollection.Builder(); using var pooledWatch = StopwatchPool.GetPooledObject(out var watch); using var pooledSpan = ArrayPool.Shared.GetPooledArraySpan(minimumLength: providers.Length, out var properties); - var context = new TagHelperDescriptorProviderContext(compilation, results) + var context = new TagHelperDescriptorProviderContext(compilation, builder) { ExcludeHidden = true, IncludeDocumentation = true @@ -74,7 +74,7 @@ public static async ValueTask> GetTagHelpers telemetryReporter.ReportEvent(GetTagHelpersEventName, Severity.Normal, properties); - return [.. results]; + return builder.ToCollection(); } private static ImmutableArray GetTagHelperDescriptorProviders(RazorProjectEngine projectEngine) diff --git a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/Formatting/FormattingVisitor.cs b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/Formatting/FormattingVisitor.cs index c85e1de6aca..8ea75e5a575 100644 --- a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/Formatting/FormattingVisitor.cs +++ b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/Formatting/FormattingVisitor.cs @@ -242,7 +242,7 @@ public override void VisitMarkupTagHelperElement(MarkupTagHelperElementSyntax no static bool IsComponentTagHelperNode(MarkupTagHelperElementSyntax node) { - return node.TagHelperInfo?.BindingResult?.Descriptors is { Length: > 0 } descriptors && + return node.TagHelperInfo.BindingResult.TagHelpers is { Count: > 0 } descriptors && descriptors.Any(static d => d.IsComponentOrChildContentTagHelper()); } @@ -271,7 +271,7 @@ static bool ParentHasProperty(MarkupTagHelperElementSyntax parentComponent, stri // // This code will not count "ChildContent" as causing indentation because its parent // has a property called "ChildContent". - if (parentComponent.TagHelperInfo?.BindingResult.Descriptors.Any(d => d.BoundAttributes.Any(a => a.Name == propertyName)) ?? false) + if (parentComponent.TagHelperInfo.BindingResult.TagHelpers.Any(d => d.BoundAttributes.Any(a => a.Name == propertyName))) { return true; } @@ -281,7 +281,7 @@ static bool ParentHasProperty(MarkupTagHelperElementSyntax parentComponent, stri static bool HasUnspecifiedCascadingTypeParameter(MarkupTagHelperElementSyntax node) { - if (node.TagHelperInfo?.BindingResult?.Descriptors is not { Length: > 0 } descriptors) + if (node.TagHelperInfo.BindingResult.TagHelpers is not { Count: > 0 } descriptors) { return false; } diff --git a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/Formatting/Passes/CSharpFormattingPass.CSharpDocumentGenerator.cs b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/Formatting/Passes/CSharpFormattingPass.CSharpDocumentGenerator.cs index f97f95fb86f..e181ca93095 100644 --- a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/Formatting/Passes/CSharpFormattingPass.CSharpDocumentGenerator.cs +++ b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/Formatting/Passes/CSharpFormattingPass.CSharpDocumentGenerator.cs @@ -261,7 +261,7 @@ private void AddAdditionalLineFormattingContent(StringBuilder additionalLinesBui // what the user expects. if (node is { Parent.Parent: MarkupTagHelperAttributeSyntax attribute } && attribute is { Parent.Parent: MarkupTagHelperElementSyntax element } && - element.TagHelperInfo.BindingResult.Descriptors is [{ } descriptor] && + element.TagHelperInfo.BindingResult.TagHelpers is [{ } descriptor] && descriptor.IsGenericTypedComponent() && descriptor.BoundAttributes.FirstOrDefault(d => d.Name == attribute.TagHelperAttributeInfo.Name) is { } boundAttribute && boundAttribute.IsTypeParameterProperty()) diff --git a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/GoToDefinition/RazorComponentDefinitionHelpers.cs b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/GoToDefinition/RazorComponentDefinitionHelpers.cs index d76a83c5882..c727a4b945f 100644 --- a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/GoToDefinition/RazorComponentDefinitionHelpers.cs +++ b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/GoToDefinition/RazorComponentDefinitionHelpers.cs @@ -71,7 +71,7 @@ public static bool TryGetBoundTagHelpers( using var descriptorsBuilder = new PooledArrayBuilder(); - foreach (var boundTagHelper in binding.Descriptors.Where(d => !d.IsAttributeDescriptor())) + foreach (var boundTagHelper in binding.TagHelpers.Where(d => !d.IsAttributeDescriptor())) { var requireAttributeMatch = false; if ((!ignoreComponentAttributes || boundTagHelper.Kind != TagHelperKind.Component) && diff --git a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/Hover/HoverFactory.cs b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/Hover/HoverFactory.cs index 57d3a5a9a4f..6dc522198e3 100644 --- a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/Hover/HoverFactory.cs +++ b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/Hover/HoverFactory.cs @@ -88,14 +88,14 @@ internal static class HoverFactory return SpecializedTasks.Null(); } - Debug.Assert(binding.Descriptors.Any()); + Debug.Assert(binding.TagHelpers.Any()); var span = containingTagNameToken.GetLinePositionSpan(codeDocument.Source); var filePath = codeDocument.Source.FilePath.AssumeNotNull(); return ElementInfoToHoverAsync( - filePath, binding.Descriptors, span, options, componentAvailabilityService, cancellationToken); + filePath, binding.TagHelpers, span, options, componentAvailabilityService, cancellationToken); } if (HtmlFacts.TryGetAttributeInfo(owner, out containingTagNameToken, out _, out var selectedAttributeName, out var selectedAttributeNameLocation, out attributes) && @@ -123,7 +123,7 @@ internal static class HoverFactory return SpecializedTasks.Null(); } - Debug.Assert(binding.Descriptors.Any()); + Debug.Assert(binding.TagHelpers.Any()); var tagHelperAttributes = TagHelperFacts.GetBoundTagHelperAttributes( tagHelperContext, selectedAttributeName.AssumeNotNull(), @@ -218,7 +218,7 @@ internal static class HoverFactory private static async Task ElementInfoToHoverAsync( string documentFilePath, - ImmutableArray descriptors, + TagHelperCollection tagHelpers, LinePositionSpan span, HoverDisplayOptions options, IComponentAvailabilityService componentAvailabilityService, @@ -226,7 +226,7 @@ internal static class HoverFactory { // Filter out attribute descriptors since we're creating an element hover var keepAttributeInfo = FileKinds.GetFileKindFromPath(documentFilePath) == RazorFileKind.Legacy; - var descriptionInfos = descriptors + var descriptionInfos = tagHelpers .Where(d => keepAttributeInfo || !d.IsAttributeDescriptor()) .SelectAsArray(BoundElementDescriptionInfo.From); var elementDescriptionInfo = new AggregateBoundElementDescription(descriptionInfos); diff --git a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/ITagHelperResolver.cs b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/ITagHelperResolver.cs index 3283d3f64d5..b6692c24fb5 100644 --- a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/ITagHelperResolver.cs +++ b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/ITagHelperResolver.cs @@ -1,7 +1,6 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -using System.Collections.Immutable; using System.Threading; using System.Threading.Tasks; using Microsoft.AspNetCore.Razor.Language; @@ -16,7 +15,7 @@ internal interface ITagHelperResolver /// using the given to provide a /// . /// - ValueTask> GetTagHelpersAsync( + ValueTask GetTagHelpersAsync( Project project, ProjectSnapshot projectSnapshot, CancellationToken cancellationToken); diff --git a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/ProjectSystem/AbstractRazorProjectInfoDriver.cs b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/ProjectSystem/AbstractRazorProjectInfoDriver.cs index 229417d73de..abdf0503063 100644 --- a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/ProjectSystem/AbstractRazorProjectInfoDriver.cs +++ b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/ProjectSystem/AbstractRazorProjectInfoDriver.cs @@ -105,7 +105,7 @@ private async ValueTask ProcessBatchAsync(ImmutableArray items, Cancellati switch (work) { case Update(var projectInfo): - Logger?.LogTrace($"Sending update for {projectInfo.FilePath} with {projectInfo.ProjectWorkspaceState.TagHelpers.Length} TagHelpers"); + Logger?.LogTrace($"Sending update for {projectInfo.FilePath} with {projectInfo.ProjectWorkspaceState.TagHelpers.Count} TagHelpers"); _latestProjectInfoMap[projectInfo.ProjectKey] = projectInfo; break; diff --git a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/ProjectSystem/IProjectSnapshot.cs b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/ProjectSystem/IProjectSnapshot.cs index 7763a9f54b8..310c92e2ea0 100644 --- a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/ProjectSystem/IProjectSnapshot.cs +++ b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/ProjectSystem/IProjectSnapshot.cs @@ -2,7 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. using System.Collections.Generic; -using System.Collections.Immutable; using System.Diagnostics.CodeAnalysis; using System.Threading; using System.Threading.Tasks; @@ -31,7 +30,7 @@ internal interface IProjectSnapshot string DisplayName { get; } LanguageVersion CSharpLanguageVersion { get; } - ValueTask> GetTagHelpersAsync(CancellationToken cancellationToken); + ValueTask GetTagHelpersAsync(CancellationToken cancellationToken); bool ContainsDocument(string filePath); bool TryGetDocument(string filePath, [NotNullWhen(true)] out IDocumentSnapshot? document); diff --git a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/ProjectSystem/Legacy/ILegacyProjectSnapshot.cs b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/ProjectSystem/Legacy/ILegacyProjectSnapshot.cs index 57ee41e1768..b8b657ed984 100644 --- a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/ProjectSystem/Legacy/ILegacyProjectSnapshot.cs +++ b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/ProjectSystem/Legacy/ILegacyProjectSnapshot.cs @@ -1,7 +1,6 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -using System.Collections.Immutable; using Microsoft.AspNetCore.Razor.Language; using Microsoft.CodeAnalysis.CSharp; @@ -21,7 +20,7 @@ internal interface ILegacyProjectSnapshot string? RootNamespace { get; } LanguageVersion CSharpLanguageVersion { get; } - ImmutableArray TagHelpers { get; } + TagHelperCollection TagHelpers { get; } RazorProjectEngine GetProjectEngine(); diff --git a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/ProjectSystem/ProjectSnapshot.cs b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/ProjectSystem/ProjectSnapshot.cs index 6ccc250cb9b..60a681a14c5 100644 --- a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/ProjectSystem/ProjectSnapshot.cs +++ b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/ProjectSystem/ProjectSnapshot.cs @@ -37,7 +37,7 @@ internal sealed class ProjectSnapshot(ProjectState state) : IProjectSnapshot, IL public RazorProjectEngine ProjectEngine => _state.ProjectEngine; - public ValueTask> GetTagHelpersAsync(CancellationToken cancellationToken) + public ValueTask GetTagHelpersAsync(CancellationToken cancellationToken) => new(_state.TagHelpers); public bool ContainsDocument(string filePath) @@ -143,7 +143,7 @@ public ImmutableArray GetRelatedDocumentFilePaths(string documentFilePat string ILegacyProjectSnapshot.FilePath => FilePath; string? ILegacyProjectSnapshot.RootNamespace => RootNamespace; LanguageVersion ILegacyProjectSnapshot.CSharpLanguageVersion => CSharpLanguageVersion; - ImmutableArray ILegacyProjectSnapshot.TagHelpers => ProjectWorkspaceState.TagHelpers; + TagHelperCollection ILegacyProjectSnapshot.TagHelpers => ProjectWorkspaceState.TagHelpers; RazorProjectEngine ILegacyProjectSnapshot.GetProjectEngine() => _state.ProjectEngine; diff --git a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/ProjectSystem/ProjectState.cs b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/ProjectSystem/ProjectState.cs index 22313f45b1d..37c53816b57 100644 --- a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/ProjectSystem/ProjectState.cs +++ b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/ProjectSystem/ProjectState.cs @@ -79,7 +79,7 @@ public static ProjectState Create( IProjectEngineFactoryProvider projectEngineFactoryProvider) => new(hostProject, projectEngineFactoryProvider); - public ImmutableArray TagHelpers => ProjectWorkspaceState.TagHelpers; + public TagHelperCollection TagHelpers => ProjectWorkspaceState.TagHelpers; public LanguageVersion CSharpLanguageVersion => HostProject.Configuration.CSharpLanguageVersion; diff --git a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/ProjectSystem/ProjectWorkspaceState.cs b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/ProjectSystem/ProjectWorkspaceState.cs index 6a550021f72..98eba74d385 100644 --- a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/ProjectSystem/ProjectWorkspaceState.cs +++ b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/ProjectSystem/ProjectWorkspaceState.cs @@ -2,8 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. using System; -using System.Collections.Immutable; -using System.Linq; using Microsoft.AspNetCore.Razor.Language; using Microsoft.Extensions.Internal; @@ -11,18 +9,18 @@ namespace Microsoft.CodeAnalysis.Razor.ProjectSystem; internal sealed class ProjectWorkspaceState : IEquatable { - public static readonly ProjectWorkspaceState Default = new(ImmutableArray.Empty); + public static readonly ProjectWorkspaceState Default = new(TagHelperCollection.Empty); - public ImmutableArray TagHelpers { get; } + public TagHelperCollection TagHelpers { get; } - private ProjectWorkspaceState( - ImmutableArray tagHelpers) + public bool IsDefault => TagHelpers.IsEmpty; + + private ProjectWorkspaceState(TagHelperCollection tagHelpers) { TagHelpers = tagHelpers; } - public static ProjectWorkspaceState Create( - ImmutableArray tagHelpers) + public static ProjectWorkspaceState Create(TagHelperCollection tagHelpers) => tagHelpers.IsEmpty ? Default : new(tagHelpers); @@ -32,7 +30,7 @@ public override bool Equals(object? obj) public bool Equals(ProjectWorkspaceState? other) => other is not null && - TagHelpers.SequenceEqual(other.TagHelpers); + TagHelpers.Equals(other.TagHelpers); public override int GetHashCode() { diff --git a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/Rename/RenameService.cs b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/Rename/RenameService.cs index 95d6b3d0db8..4e817a3494a 100644 --- a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/Rename/RenameService.cs +++ b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/Rename/RenameService.cs @@ -17,7 +17,6 @@ using Microsoft.CodeAnalysis.Razor.DocumentMapping; using Microsoft.CodeAnalysis.Razor.ProjectSystem; using Microsoft.CodeAnalysis.Razor.Workspaces; -using RazorSyntaxKind = Microsoft.AspNetCore.Razor.Language.SyntaxKind; using RazorSyntaxNode = Microsoft.AspNetCore.Razor.Language.Syntax.SyntaxNode; namespace Microsoft.CodeAnalysis.Razor.Rename; @@ -46,14 +45,13 @@ public async Task TryGetRazorRenameEditsAsync( var codeDocument = await documentContext.GetCodeDocumentAsync(cancellationToken).ConfigureAwait(false); - var originTagHelpers = await GetOriginTagHelpersAsync(documentContext, positionInfo.HostDocumentIndex, cancellationToken).ConfigureAwait(false); - if (originTagHelpers.IsDefaultOrEmpty) + if (!TryGetOriginTagHelpers(codeDocument, positionInfo.HostDocumentIndex, out var originTagHelpers)) { return new(Edit: null); } var originComponentDocumentSnapshot = await _componentSearchEngine - .TryLocateComponentAsync(originTagHelpers.First(), solutionQueryOperations, cancellationToken) + .TryLocateComponentAsync(originTagHelpers.Primary, solutionQueryOperations, cancellationToken) .ConfigureAwait(false); if (originComponentDocumentSnapshot is null) { @@ -69,17 +67,28 @@ public async Task TryGetRazorRenameEditsAsync( return new(Edit: null, FallbackToCSharp: false); } - using var _ = ListPool>.GetPooledObject(out var documentChanges); + using var documentChanges = new PooledArrayBuilder>(); + var fileRename = GetRenameFileEdit(originComponentDocumentFilePath, newPath); documentChanges.Add(fileRename); - AddEditsForCodeDocument(documentChanges, originTagHelpers, newName, new(documentContext.Uri), codeDocument); - AddAdditionalFileRenames(documentChanges, originComponentDocumentFilePath, newPath); + + AddEditsForCodeDocument(ref documentChanges.AsRef(), originTagHelpers, newName, new(documentContext.Uri), codeDocument); + AddAdditionalFileRenames(ref documentChanges.AsRef(), originComponentDocumentFilePath, newPath); var documentSnapshots = GetAllDocumentSnapshots(documentContext.FilePath, solutionQueryOperations); foreach (var documentSnapshot in documentSnapshots) { - await AddEditsForCodeDocumentAsync(documentChanges, originTagHelpers, newName, documentSnapshot, cancellationToken).ConfigureAwait(false); + if (!documentSnapshot.FileKind.IsComponent()) + { + continue; + } + + // VS Code in Windows expects path to start with '/' + var uri = new DocumentUri(LspFactory.CreateFilePathUri(documentSnapshot.FilePath, _languageServerFeatureOptions)); + var generatedOutput = await documentSnapshot.GetGeneratedOutputAsync(cancellationToken).ConfigureAwait(false); + + AddEditsForCodeDocument(ref documentChanges.AsRef(), originTagHelpers, newName, uri, generatedOutput); } foreach (var documentChange in documentChanges) @@ -91,9 +100,9 @@ public async Task TryGetRazorRenameEditsAsync( } } - return new(new WorkspaceEdit + return new(Edit: new() { - DocumentChanges = documentChanges.ToArray(), + DocumentChanges = documentChanges.ToArrayAndClear() }); } @@ -131,14 +140,19 @@ private static ImmutableArray GetAllDocumentSnapshots(string return documentSnapshots.ToImmutableAndClear(); } - private void AddAdditionalFileRenames(List> documentChanges, string oldFilePath, string newFilePath) + private void AddAdditionalFileRenames( + ref PooledArrayBuilder> documentChanges, + string oldFilePath, string newFilePath) { - TryAdd(".cs"); - TryAdd(".css"); + TryAdd(".cs", ref documentChanges); + TryAdd(".css", ref documentChanges); - void TryAdd(string extension) + void TryAdd( + string extension, + ref PooledArrayBuilder> documentChanges) { var changedPath = oldFilePath + extension; + if (_fileSystem.FileExists(changedPath)) { documentChanges.Add(GetRenameFileEdit(changedPath, newFilePath + extension)); @@ -147,7 +161,7 @@ void TryAdd(string extension) } private RenameFile GetRenameFileEdit(string oldFilePath, string newFilePath) - => new RenameFile + => new() { OldDocumentUri = new(LspFactory.CreateFilePathUri(oldFilePath, _languageServerFeatureOptions)), NewDocumentUri = new(LspFactory.CreateFilePathUri(newFilePath, _languageServerFeatureOptions)), @@ -160,115 +174,161 @@ private static string MakeNewPath(string originalPath, string newName) return Path.Combine(directoryName, newFileName); } - private async Task AddEditsForCodeDocumentAsync( - List> documentChanges, - ImmutableArray originTagHelpers, + private static void AddEditsForCodeDocument( + ref PooledArrayBuilder> documentChanges, + OriginTagHelpers originTagHelpers, string newName, - IDocumentSnapshot documentSnapshot, - CancellationToken cancellationToken) + DocumentUri uri, + RazorCodeDocument codeDocument) { - if (!documentSnapshot.FileKind.IsComponent()) + var documentIdentifier = new OptionalVersionedTextDocumentIdentifier { DocumentUri = uri }; + + using var elements = new PooledArrayBuilder(); + + foreach (var node in codeDocument.GetRequiredSyntaxRoot().DescendantNodes()) { - return; + if (node is MarkupTagHelperElementSyntax element) + { + elements.Add(element); + } } - var codeDocument = await documentSnapshot.GetGeneratedOutputAsync(cancellationToken).ConfigureAwait(false); + // Collect all edits first, then de-duplicate them by range. + using var allEdits = new PooledArrayBuilder>(); - // VS Code in Windows expects path to start with '/' - var uri = new DocumentUri(LspFactory.CreateFilePathUri(documentSnapshot.FilePath, _languageServerFeatureOptions)); + if (TryCollectEdits(originTagHelpers.Primary, newName, codeDocument.Source, in elements, ref allEdits.AsRef()) && + TryCollectEdits(originTagHelpers.Associated, newName, codeDocument.Source, in elements, ref allEdits.AsRef())) + { + var uniqueEdits = GetUniqueEdits(ref allEdits.AsRef()); - AddEditsForCodeDocument(documentChanges, originTagHelpers, newName, uri, codeDocument); - } + if (uniqueEdits.Length > 0) + { + documentChanges.Add(new TextDocumentEdit + { + TextDocument = documentIdentifier, + Edits = uniqueEdits, + }); + } + } - private static void AddEditsForCodeDocument( - List> documentChanges, - ImmutableArray originTagHelpers, - string newName, - DocumentUri uri, - RazorCodeDocument codeDocument) - { - var documentIdentifier = new OptionalVersionedTextDocumentIdentifier { DocumentUri = uri }; - var tagHelperElements = codeDocument.GetRequiredSyntaxRoot() - .DescendantNodes() - .OfType(); + return; - foreach (var originTagHelper in originTagHelpers) + static bool TryCollectEdits( + TagHelperDescriptor tagHelper, + string newName, + RazorSourceDocument sourceDocument, + ref readonly PooledArrayBuilder elements, + ref PooledArrayBuilder> edits) { var editedName = newName; - if (originTagHelper.IsFullyQualifiedNameMatch) + + if (tagHelper.IsFullyQualifiedNameMatch) { // Fully qualified binding, our "new name" needs to be fully qualified. - var @namespace = originTagHelper.TypeNamespace; + var @namespace = tagHelper.TypeNamespace; if (@namespace == null) { - return; + return false; } - // The origin TagHelper was fully qualified so any fully qualified rename locations we find will need a fully qualified renamed edit. + // The origin TagHelper was fully qualified so any fully qualified rename locations + // we find will need a fully qualified renamed edit. editedName = $"{@namespace}.{newName}"; } - foreach (var node in tagHelperElements) + foreach (var element in elements) { - if (node is MarkupTagHelperElementSyntax { TagHelperInfo.BindingResult: var binding } tagHelperElement && - BindingContainsTagHelper(originTagHelper, binding)) + if (element.TagHelperInfo.BindingResult.TagHelpers.Contains(tagHelper)) { - documentChanges.Add(new TextDocumentEdit + var startTagEdit = LspFactory.CreateTextEdit(element.StartTag.Name.GetRange(sourceDocument), editedName); + + edits.Add(startTagEdit); + + if (element.EndTag is MarkupTagHelperEndTagSyntax endTag) { - TextDocument = documentIdentifier, - Edits = CreateEditsForMarkupTagHelperElement(tagHelperElement, codeDocument, editedName), - }); + var endTagEdit = LspFactory.CreateTextEdit(endTag.Name.GetRange(sourceDocument), editedName); + + edits.Add(endTagEdit); + } } } - } - } - private static SumType[] CreateEditsForMarkupTagHelperElement(MarkupTagHelperElementSyntax element, RazorCodeDocument codeDocument, string newName) - { - var startTagEdit = LspFactory.CreateTextEdit(element.StartTag.Name.GetRange(codeDocument.Source), newName); + return true; + } - if (element.EndTag is MarkupTagHelperEndTagSyntax endTag) + static SumType[] GetUniqueEdits( + ref PooledArrayBuilder> edits) { - var endTagEdit = LspFactory.CreateTextEdit(endTag.Name.GetRange(codeDocument.Source), newName); + if (edits.Count == 0) + { + return []; + } - return [startTagEdit, endTagEdit]; - } + // De-duplicate edits by range. + using var uniqueEdits = new PooledArrayBuilder>(edits.Count); + using var _ = HashSetPool.GetPooledObject(out var seenRanges); + +#if NET + seenRanges.EnsureCapacity(edits.Count); +#endif + + foreach (var edit in edits) + { + if (edit.TryGetFirst(out var textEdit)) + { + if (seenRanges.Add(textEdit.Range)) + { + uniqueEdits.Add(edit); + } + } + else if (edit.TryGetSecond(out var annotatedEdit)) + { + if (seenRanges.Add(annotatedEdit.Range)) + { + uniqueEdits.Add(edit); + } + } + } - return [startTagEdit]; + return uniqueEdits.ToArrayAndClear(); + } } - private static bool BindingContainsTagHelper(TagHelperDescriptor tagHelper, TagHelperBinding potentialBinding) - => potentialBinding.Descriptors.Any(descriptor => descriptor.Equals(tagHelper)); + private readonly record struct OriginTagHelpers(TagHelperDescriptor Primary, TagHelperDescriptor Associated); - private static async Task> GetOriginTagHelpersAsync(DocumentContext documentContext, int absoluteIndex, CancellationToken cancellationToken) + private static bool TryGetOriginTagHelpers(RazorCodeDocument codeDocument, int absoluteIndex, out OriginTagHelpers originTagHelpers) { - var owner = await documentContext.GetSyntaxNodeAsync(absoluteIndex, cancellationToken).ConfigureAwait(false); + var owner = codeDocument.GetRequiredSyntaxRoot().FindInnermostNode(absoluteIndex); if (owner is null) { Debug.Fail("Owner should never be null."); - return default; + originTagHelpers = default; + return false; } if (!TryGetTagHelperBinding(owner, absoluteIndex, out var binding)) { - return default; + originTagHelpers = default; + return false; } // Can only have 1 component TagHelper belonging to an element at a time - var primaryTagHelper = binding.Descriptors.FirstOrDefault(static d => d.Kind == TagHelperKind.Component); + var primaryTagHelper = binding.TagHelpers.FirstOrDefault(static d => d.Kind == TagHelperKind.Component); if (primaryTagHelper is null) { - return default; + originTagHelpers = default; + return false; } - var tagHelpers = await documentContext.Snapshot.Project.GetTagHelpersAsync(cancellationToken).ConfigureAwait(false); - var associatedTagHelper = FindAssociatedTagHelper(primaryTagHelper, tagHelpers); - if (associatedTagHelper is null) + var tagHelpers = codeDocument.GetRequiredTagHelpers(); + if (!TryFindAssociatedTagHelper(primaryTagHelper, tagHelpers, out var associatedTagHelper)) { - return default; + originTagHelpers = default; + return false; } - return [primaryTagHelper, associatedTagHelper]; + originTagHelpers = new(primaryTagHelper, associatedTagHelper); + return true; } private static bool TryGetTagHelperBinding(RazorSyntaxNode owner, int absoluteIndex, [NotNullWhen(true)] out TagHelperBinding? binding) @@ -282,8 +342,7 @@ private static bool TryGetTagHelperBinding(RazorSyntaxNode owner, int absoluteIn // A rename of a start tag could have an "owner" of one of its attributes, so we do a bit more checking // to support this case - var node = owner.FirstAncestorOrSelf(n => n.Kind == RazorSyntaxKind.MarkupTagHelperStartTag); - if (node is not MarkupTagHelperStartTagSyntax tagHelperStartTag) + if (owner.FirstAncestorOrSelf() is not { } tagHelperStartTag) { binding = null; return false; @@ -308,33 +367,29 @@ private static bool TryGetTagHelperBinding(RazorSyntaxNode owner, int absoluteIn return false; } - private static TagHelperDescriptor? FindAssociatedTagHelper(TagHelperDescriptor tagHelper, ImmutableArray tagHelpers) + private static bool TryFindAssociatedTagHelper( + TagHelperDescriptor primary, + TagHelperCollection tagHelpers, + [NotNullWhen(true)] out TagHelperDescriptor? associated) { - var typeName = tagHelper.TypeName; - var assemblyName = tagHelper.AssemblyName; - foreach (var currentTagHelper in tagHelpers) - { - if (tagHelper == currentTagHelper) - { - // Same as the primary, we're looking for our other pair. - continue; - } + var typeName = primary.TypeName; + var assemblyName = primary.AssemblyName; - if (typeName != currentTagHelper.TypeName) - { - continue; - } - - if (assemblyName != currentTagHelper.AssemblyName) + foreach (var tagHelper in tagHelpers) + { + if (typeName == tagHelper.TypeName && + assemblyName == tagHelper.AssemblyName && + !tagHelper.Equals(primary)) { - continue; + // Found our associated TagHelper, there should only ever be + // one other associated TagHelper (fully qualified and non-fully qualified). + associated = tagHelper; + return true; } - - // Found our associated TagHelper, there should only ever be 1 other associated TagHelper (fully qualified and non-fully qualified). - return currentTagHelper; } Debug.Fail("Components should always have an associated TagHelper."); - return null; + associated = null; + return false; } } diff --git a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/SemanticTokens/SemanticTokensVisitor.cs b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/SemanticTokens/SemanticTokensVisitor.cs index ab8f682eb3b..2d5ff0eeed3 100644 --- a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/SemanticTokens/SemanticTokensVisitor.cs +++ b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/SemanticTokens/SemanticTokensVisitor.cs @@ -490,7 +490,7 @@ private static bool IsComponent(SyntaxNode node) { if (node is MarkupTagHelperElementSyntax { TagHelperInfo.BindingResult: var binding }) { - var componentDescriptor = binding.Descriptors.FirstOrDefault(static d => d.Kind == TagHelperKind.Component); + var componentDescriptor = binding.TagHelpers.FirstOrDefault(static d => d.Kind == TagHelperKind.Component); return componentDescriptor is not null; } else if (node is MarkupTagHelperStartTagSyntax startTag) diff --git a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/Serialization/FetchTagHelpersResult.cs b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/Serialization/FetchTagHelpersResult.cs index 9a9c95ada4a..64f2ab367c8 100644 --- a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/Serialization/FetchTagHelpersResult.cs +++ b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/Serialization/FetchTagHelpersResult.cs @@ -1,12 +1,11 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -using System.Collections.Immutable; using Microsoft.AspNetCore.Razor.Language; namespace Microsoft.CodeAnalysis.Razor.Serialization; -internal sealed record FetchTagHelpersResult(ImmutableArray TagHelpers) +internal sealed record FetchTagHelpersResult(TagHelperCollection TagHelpers) { - public static readonly FetchTagHelpersResult Empty = new(ImmutableArray.Empty); + public static readonly FetchTagHelpersResult Empty = new(TagHelperCollection.Empty); } diff --git a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/Serialization/MessagePack/Formatters/FetchTagHelpersResultFormatter.cs b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/Serialization/MessagePack/Formatters/FetchTagHelpersResultFormatter.cs index 351bb25397d..96b4f4008f1 100644 --- a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/Serialization/MessagePack/Formatters/FetchTagHelpersResultFormatter.cs +++ b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/Serialization/MessagePack/Formatters/FetchTagHelpersResultFormatter.cs @@ -1,7 +1,6 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -using System.Collections.Immutable; using MessagePack; using Microsoft.AspNetCore.Razor.Language; @@ -17,7 +16,7 @@ private FetchTagHelpersResultFormatter() public override FetchTagHelpersResult Deserialize(ref MessagePackReader reader, SerializerCachingOptions options) { - var tagHelpers = reader.Deserialize>(options); + var tagHelpers = reader.Deserialize(options); return new(tagHelpers); } diff --git a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/Serialization/MessagePack/Formatters/ProjectWorkspaceStateFormatter.cs b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/Serialization/MessagePack/Formatters/ProjectWorkspaceStateFormatter.cs index 9da11b26804..b9fb89b3eea 100644 --- a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/Serialization/MessagePack/Formatters/ProjectWorkspaceStateFormatter.cs +++ b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/Serialization/MessagePack/Formatters/ProjectWorkspaceStateFormatter.cs @@ -1,14 +1,10 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -using System.Collections.Immutable; using MessagePack; +using Microsoft.AspNetCore.Razor; using Microsoft.AspNetCore.Razor.Language; -using Microsoft.AspNetCore.Razor.PooledObjects; -using Microsoft.AspNetCore.Razor.Utilities; using Microsoft.CodeAnalysis.Razor.ProjectSystem; -using Microsoft.CodeAnalysis.Razor.Serialization.MessagePack.Formatters.TagHelpers; -using Microsoft.CodeAnalysis.Razor.Utilities; namespace Microsoft.CodeAnalysis.Razor.Serialization.MessagePack.Formatters; @@ -22,42 +18,13 @@ private ProjectWorkspaceStateFormatter() public override ProjectWorkspaceState Deserialize(ref MessagePackReader reader, SerializerCachingOptions options) { - reader.ReadArrayHeaderAndVerify(2); - - var checksums = reader.Deserialize>(options); - - reader.ReadArrayHeaderAndVerify(checksums.Length); - - using var builder = new PooledArrayBuilder(capacity: checksums.Length); - var cache = TagHelperCache.Default; - - foreach (var checksum in checksums) - { - if (!cache.TryGet(checksum, out var tagHelper)) - { - tagHelper = TagHelperFormatter.Instance.Deserialize(ref reader, options); - cache.TryAdd(checksum, tagHelper); - } - else - { - TagHelperFormatter.Instance.Skim(ref reader, options); - } - - builder.Add(tagHelper); - } - - var tagHelpers = builder.ToImmutableAndClear(); + var tagHelpers = reader.Deserialize(options).AssumeNotNull(); return ProjectWorkspaceState.Create(tagHelpers); } public override void Serialize(ref MessagePackWriter writer, ProjectWorkspaceState value, SerializerCachingOptions options) { - writer.WriteArrayHeader(2); - - var checksums = value.TagHelpers.SelectAsArray(x => x.Checksum); - - writer.Serialize(checksums, options); writer.Serialize(value.TagHelpers, options); } } diff --git a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/Serialization/MessagePack/Resolvers/FetchTagHelpersResultResolver.cs b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/Serialization/MessagePack/Resolvers/FetchTagHelpersResultResolver.cs index 0761038f1ee..c9c1491915f 100644 --- a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/Serialization/MessagePack/Resolvers/FetchTagHelpersResultResolver.cs +++ b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/Serialization/MessagePack/Resolvers/FetchTagHelpersResultResolver.cs @@ -48,6 +48,7 @@ private static class TypeToFormatterMap RazorDiagnosticFormatter.Instance, RequiredAttributeFormatter.Instance, TagHelperFormatter.Instance, + TagHelperCollectionFormatter.Instance, TagMatchingRuleFormatter.Instance, TypeNameObjectFormatter.Instance }; diff --git a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/Serialization/MessagePack/SerializationFormat.cs b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/Serialization/MessagePack/SerializationFormat.cs index e2ff382a39d..e5b0ca9684c 100644 --- a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/Serialization/MessagePack/SerializationFormat.cs +++ b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/Serialization/MessagePack/SerializationFormat.cs @@ -9,5 +9,5 @@ internal static class SerializationFormat // or any of the types that compose it changes. This includes: RazorConfiguration, // ProjectWorkspaceState, TagHelperDescriptor, and DocumentSnapshotHandle. // NOTE: If this version is changed, a coordinated insertion is required between Roslyn and Razor for the C# extension. - public const int Version = 15; + public const int Version = 16; } diff --git a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/TagHelperFacts.cs b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/TagHelperFacts.cs index 199c856d359..1c3b53a4363 100644 --- a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/TagHelperFacts.cs +++ b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/TagHelperFacts.cs @@ -4,6 +4,7 @@ using System; using System.Collections.Generic; using System.Collections.Immutable; +using Microsoft.AspNetCore.Razor; using Microsoft.AspNetCore.Razor.Language; using Microsoft.AspNetCore.Razor.Language.Syntax; using Microsoft.AspNetCore.Razor.PooledObjects; @@ -19,10 +20,7 @@ internal static class TagHelperFacts string? parentTag, bool parentIsTagHelper) { - if (documentContext is null) - { - throw new ArgumentNullException(nameof(documentContext)); - } + ArgHelper.ThrowIfNull(documentContext); if (attributes.IsDefault) { @@ -34,7 +32,7 @@ internal static class TagHelperFacts return null; } - if (documentContext.TagHelpers.Length == 0) + if (documentContext.TagHelpers.Count == 0) { return null; } @@ -49,24 +47,13 @@ public static ImmutableArray GetBoundTagHelperAttribut string attributeName, TagHelperBinding binding) { - if (documentContext is null) - { - throw new ArgumentNullException(nameof(documentContext)); - } - - if (attributeName is null) - { - throw new ArgumentNullException(nameof(attributeName)); - } - - if (binding is null) - { - throw new ArgumentNullException(nameof(binding)); - } + ArgHelper.ThrowIfNull(documentContext); + ArgHelper.ThrowIfNull(attributeName); + ArgHelper.ThrowIfNull(binding); using var matchingBoundAttributes = new PooledArrayBuilder(); - foreach (var tagHelper in binding.Descriptors) + foreach (var tagHelper in binding.TagHelpers) { foreach (var boundAttribute in tagHelper.BoundAttributes) { @@ -83,85 +70,73 @@ public static ImmutableArray GetBoundTagHelperAttribut return matchingBoundAttributes.ToImmutableAndClear(); } - public static ImmutableArray GetTagHelpersGivenTag( + public static TagHelperCollection GetTagHelpersGivenTag( TagHelperDocumentContext documentContext, string tagName, string? parentTag) { - if (documentContext is null) - { - throw new ArgumentNullException(nameof(documentContext)); - } + ArgHelper.ThrowIfNull(documentContext); + ArgHelper.ThrowIfNull(tagName); - if (tagName is null) + if (documentContext.TagHelpers.IsEmpty) { - throw new ArgumentNullException(nameof(tagName)); + return []; } - if (documentContext?.TagHelpers is not { Length: > 0 } tagHelpers) - { - return ImmutableArray.Empty; - } + var tagNameWithoutPrefix = tagName.AsMemory(); - var prefix = documentContext?.Prefix ?? string.Empty; - if (!tagName.StartsWith(prefix, StringComparison.OrdinalIgnoreCase)) + if (documentContext.Prefix is { Length: > 0 } prefix) { - // Can't possibly match TagHelpers, it doesn't start with the TagHelperPrefix. - return ImmutableArray.Empty; - } - - using var matchingDescriptors = new PooledArrayBuilder(); + if (!tagNameWithoutPrefix.Span.StartsWith(prefix.AsSpan(), StringComparison.OrdinalIgnoreCase)) + { + // 'tagName' can't possibly match TagHelpers if it doesn't start with the provided prefix. + return []; + } - var tagNameWithoutPrefix = tagName.AsSpan()[prefix.Length..]; + tagNameWithoutPrefix = tagNameWithoutPrefix[prefix.Length..]; + } - foreach (var tagHelper in tagHelpers) + return documentContext.TagHelpers.Where(state: (tagNameWithoutPrefix, parentTag), static (tagHelper, state) => { foreach (var rule in tagHelper.TagMatchingRules) { - if (TagHelperMatchingConventions.SatisfiesTagName(rule, tagNameWithoutPrefix) && - TagHelperMatchingConventions.SatisfiesParentTag(rule, parentTag.AsSpanOrDefault())) + if (TagHelperMatchingConventions.SatisfiesTagName(rule, state.tagNameWithoutPrefix.Span) && + TagHelperMatchingConventions.SatisfiesParentTag(rule, state.parentTag.AsSpan())) { - matchingDescriptors.Add(tagHelper); - break; + return true; } } - } - return matchingDescriptors.ToImmutableAndClear(); + return false; + }); } - public static ImmutableArray GetTagHelpersGivenParent(TagHelperDocumentContext documentContext, string? parentTag) + public static TagHelperCollection GetTagHelpersGivenParent(TagHelperDocumentContext documentContext, string? parentTag) { - if (documentContext is null) - { - throw new ArgumentNullException(nameof(documentContext)); - } + ArgHelper.ThrowIfNull(documentContext); - if (documentContext?.TagHelpers is not { Length: > 0 } tagHelpers) + if (documentContext.TagHelpers.IsEmpty) { - return ImmutableArray.Empty; + return []; } - using var matchingDescriptors = new PooledArrayBuilder(); - - foreach (var descriptor in tagHelpers) + return documentContext.TagHelpers.Where(parentTag, static (tagHelper, parentTag) => { - foreach (var rule in descriptor.TagMatchingRules) + foreach (var rule in tagHelper.TagMatchingRules) { - if (TagHelperMatchingConventions.SatisfiesParentTag(rule, parentTag.AsSpanOrDefault())) + if (TagHelperMatchingConventions.SatisfiesParentTag(rule, parentTag.AsSpan())) { - matchingDescriptors.Add(descriptor); - break; + return true; } } - } - return matchingDescriptors.ToImmutableAndClear(); + return false; + }); } public static ImmutableArray> StringifyAttributes(SyntaxList attributes) { - using var stringifiedAttributes = new PooledArrayBuilder>(); + using var builder = new PooledArrayBuilder>(); foreach (var attribute in attributes) { @@ -171,14 +146,14 @@ public static ImmutableArray> StringifyAttributes(S { var name = tagHelperAttribute.Name.GetContent(); var value = tagHelperAttribute.Value?.GetContent() ?? string.Empty; - stringifiedAttributes.Add(new KeyValuePair(name, value)); + builder.Add(KeyValuePair.Create(name, value)); break; } case MarkupMinimizedTagHelperAttributeSyntax minimizedTagHelperAttribute: { var name = minimizedTagHelperAttribute.Name.GetContent(); - stringifiedAttributes.Add(new KeyValuePair(name, string.Empty)); + builder.Add(KeyValuePair.Create(name, string.Empty)); break; } @@ -186,14 +161,14 @@ public static ImmutableArray> StringifyAttributes(S { var name = markupAttribute.Name.GetContent(); var value = markupAttribute.Value?.GetContent() ?? string.Empty; - stringifiedAttributes.Add(new KeyValuePair(name, value)); + builder.Add(KeyValuePair.Create(name, value)); break; } case MarkupMinimizedAttributeBlockSyntax minimizedMarkupAttribute: { var name = minimizedMarkupAttribute.Name.GetContent(); - stringifiedAttributes.Add(new KeyValuePair(name, string.Empty)); + builder.Add(KeyValuePair.Create(name, string.Empty)); break; } @@ -201,20 +176,20 @@ public static ImmutableArray> StringifyAttributes(S { var name = directiveAttribute.FullName; var value = directiveAttribute.Value?.GetContent() ?? string.Empty; - stringifiedAttributes.Add(new KeyValuePair(name, value)); + builder.Add(KeyValuePair.Create(name, value)); break; } case MarkupMinimizedTagHelperDirectiveAttributeSyntax minimizedDirectiveAttribute: { var name = minimizedDirectiveAttribute.FullName; - stringifiedAttributes.Add(new KeyValuePair(name, string.Empty)); + builder.Add(KeyValuePair.Create(name, string.Empty)); break; } } } - return stringifiedAttributes.ToImmutableAndClear(); + return builder.ToImmutableAndClear(); } public static (string? ancestorTagName, bool ancestorIsTagHelper) GetNearestAncestorTagInfo(IEnumerable ancestors) diff --git a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/Tooltip/BoundAttributeDescriptionInfo.cs b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/Tooltip/BoundAttributeDescriptionInfo.cs index fc14ca25ebb..1a2c3d57396 100644 --- a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/Tooltip/BoundAttributeDescriptionInfo.cs +++ b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/Tooltip/BoundAttributeDescriptionInfo.cs @@ -9,25 +9,18 @@ namespace Microsoft.CodeAnalysis.Razor.Tooltip; internal record BoundAttributeDescriptionInfo(string ReturnTypeName, string TypeName, string PropertyName, string? Documentation = null) { - public static BoundAttributeDescriptionInfo From(BoundAttributeParameterDescriptor parameterAttribute, string parentTagHelperTypeName) + public static BoundAttributeDescriptionInfo From(BoundAttributeParameterDescriptor parameter) { - if (parameterAttribute is null) - { - throw new ArgumentNullException(nameof(parameterAttribute)); - } - - if (parentTagHelperTypeName is null) - { - throw new ArgumentNullException(nameof(parentTagHelperTypeName)); - } + ArgHelper.ThrowIfNull(parameter); - var propertyName = parameterAttribute.PropertyName; + var parentTagHelperTypeName = parameter.Parent.Parent.TypeName; + var propertyName = parameter.PropertyName; return new BoundAttributeDescriptionInfo( - parameterAttribute.TypeName, + parameter.TypeName, parentTagHelperTypeName, propertyName, - parameterAttribute.Documentation); + parameter.Documentation); } public static BoundAttributeDescriptionInfo From(BoundAttributeDescriptor boundAttribute, bool isIndexer) diff --git a/src/Razor/src/Microsoft.CodeAnalysis.Remote.Razor/DevTools/RemoteDevToolsService.cs b/src/Razor/src/Microsoft.CodeAnalysis.Remote.Razor/DevTools/RemoteDevToolsService.cs index b4353f1f95a..602c6185ea9 100644 --- a/src/Razor/src/Microsoft.CodeAnalysis.Remote.Razor/DevTools/RemoteDevToolsService.cs +++ b/src/Razor/src/Microsoft.CodeAnalysis.Remote.Razor/DevTools/RemoteDevToolsService.cs @@ -1,8 +1,6 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -using System.Collections.Generic; -using System.Collections.Immutable; using System.Linq; using System.Threading; using System.Threading.Tasks; @@ -88,12 +86,12 @@ private static async ValueTask GetTagHelpersJsonAsync(Rem { TagHelpersKind.All => codeDocument.GetTagHelpers(), TagHelpersKind.InScope => codeDocument.GetRequiredTagHelperContext().TagHelpers, - TagHelpersKind.Referenced => (IEnumerable?)codeDocument.GetReferencedTagHelpers(), + TagHelpersKind.Referenced => codeDocument.GetReferencedTagHelpers(), _ => [] }; tagHelpers ??= []; - return new FetchTagHelpersResult(tagHelpers.ToImmutableArray()); + return new FetchTagHelpersResult(tagHelpers); } public ValueTask GetRazorSyntaxTreeAsync( diff --git a/src/Razor/src/Microsoft.CodeAnalysis.Remote.Razor/ProjectSystem/GeneratorRunResult.cs b/src/Razor/src/Microsoft.CodeAnalysis.Remote.Razor/ProjectSystem/GeneratorRunResult.cs index 0ba9b367fe2..299ec3e86a6 100644 --- a/src/Razor/src/Microsoft.CodeAnalysis.Remote.Razor/ProjectSystem/GeneratorRunResult.cs +++ b/src/Razor/src/Microsoft.CodeAnalysis.Remote.Razor/ProjectSystem/GeneratorRunResult.cs @@ -20,7 +20,7 @@ internal readonly record struct GeneratorRunResult(RazorGeneratorResult Generato { public bool IsDefault => GeneratorResult is null && Project is null; - public IReadOnlyList TagHelpers => GeneratorResult.TagHelpers; + public TagHelperCollection TagHelpers => GeneratorResult.TagHelpers; public RazorCodeDocument? GetCodeDocument(string filePath) => GeneratorResult.GetCodeDocument(filePath); diff --git a/src/Razor/src/Microsoft.CodeAnalysis.Remote.Razor/ProjectSystem/RemoteProjectSnapshot.cs b/src/Razor/src/Microsoft.CodeAnalysis.Remote.Razor/ProjectSystem/RemoteProjectSnapshot.cs index ad1a7558fba..c603e416dfc 100644 --- a/src/Razor/src/Microsoft.CodeAnalysis.Remote.Razor/ProjectSystem/RemoteProjectSnapshot.cs +++ b/src/Razor/src/Microsoft.CodeAnalysis.Remote.Razor/ProjectSystem/RemoteProjectSnapshot.cs @@ -56,13 +56,13 @@ public IEnumerable DocumentFilePaths public LanguageVersion CSharpLanguageVersion => ((CSharpParseOptions)_project.ParseOptions.AssumeNotNull()).LanguageVersion; - public async ValueTask> GetTagHelpersAsync(CancellationToken cancellationToken) + public async ValueTask GetTagHelpersAsync(CancellationToken cancellationToken) { var generatorResult = await GeneratorRunResult.CreateAsync(throwIfNotFound: false, _project, SolutionSnapshot.SnapshotManager, cancellationToken).ConfigureAwait(false); - if (generatorResult.IsDefault) - return []; - return [.. generatorResult.TagHelpers]; + return !generatorResult.IsDefault + ? generatorResult.TagHelpers + : []; } public RemoteDocumentSnapshot GetDocument(TextDocument document) diff --git a/src/Razor/src/Microsoft.CodeAnalysis.Remote.Razor/TagHelpers/RemoteTagHelperProviderService.cs b/src/Razor/src/Microsoft.CodeAnalysis.Remote.Razor/TagHelpers/RemoteTagHelperProviderService.cs index dd49aa5d08b..1f46757b624 100644 --- a/src/Razor/src/Microsoft.CodeAnalysis.Remote.Razor/TagHelpers/RemoteTagHelperProviderService.cs +++ b/src/Razor/src/Microsoft.CodeAnalysis.Remote.Razor/TagHelpers/RemoteTagHelperProviderService.cs @@ -2,10 +2,10 @@ // The .NET Foundation licenses this file to you under the MIT license. using System.Collections.Immutable; +using System.Runtime.InteropServices; using System.Threading; using System.Threading.Tasks; using Microsoft.AspNetCore.Razor.Language; -using Microsoft.AspNetCore.Razor.PooledObjects; using Microsoft.AspNetCore.Razor.Utilities; using Microsoft.CodeAnalysis.ExternalAccess.Razor; using Microsoft.CodeAnalysis.Razor.Remote; @@ -76,23 +76,23 @@ private async ValueTask FetchTagHelpersCoreAsync( return new FetchTagHelpersResult(tagHelpers); - static bool TryGetCachedTagHelpers(ImmutableArray checksums, out ImmutableArray tagHelpers) + static bool TryGetCachedTagHelpers(ImmutableArray checksums, out TagHelperCollection tagHelpers) { - using var builder = new PooledArrayBuilder(capacity: checksums.Length); + using var builder = new TagHelperCollection.RefBuilder(initialCapacity: checksums.Length); var cache = TagHelperCache.Default; foreach (var checksum in checksums) { if (!cache.TryGet(checksum, out var tagHelper)) { - tagHelpers = ImmutableArray.Empty; + tagHelpers = []; return false; } builder.Add(tagHelper); } - tagHelpers = builder.ToImmutableAndClear(); + tagHelpers = builder.ToCollection(); return true; } } @@ -117,7 +117,7 @@ private async ValueTask GetTagHelpersDeltaCoreAsync( if (solution.GetProject(projectHandle.ProjectId) is not Project workspaceProject) { - checksums = ImmutableArray.Empty; + checksums = []; } else { @@ -130,21 +130,22 @@ private async ValueTask GetTagHelpersDeltaCoreAsync( return _tagHelperDeltaProvider.GetTagHelpersDelta(projectHandle.ProjectId, lastResultId, checksums); - static ImmutableArray GetChecksums(ImmutableArray tagHelpers) + static ImmutableArray GetChecksums(TagHelperCollection tagHelpers) { - using var builder = new PooledArrayBuilder(capacity: tagHelpers.Length); + var array = new Checksum[tagHelpers.Count]; // Add each tag helpers to the cache so that we can retrieve them later if needed. var cache = TagHelperCache.Default; + var index = 0; foreach (var tagHelper in tagHelpers) { var checksum = tagHelper.Checksum; - builder.Add(checksum); + array[index++] = checksum; cache.TryAdd(checksum, tagHelper); } - return builder.ToImmutableAndClear(); + return ImmutableCollectionsMarshal.AsImmutableArray(array); } } } diff --git a/src/Razor/src/Microsoft.CodeAnalysis.Remote.Razor/TagHelpers/RemoteTagHelperResolver.cs b/src/Razor/src/Microsoft.CodeAnalysis.Remote.Razor/TagHelpers/RemoteTagHelperResolver.cs index 3e4707bc552..e3fdcd34971 100644 --- a/src/Razor/src/Microsoft.CodeAnalysis.Remote.Razor/TagHelpers/RemoteTagHelperResolver.cs +++ b/src/Razor/src/Microsoft.CodeAnalysis.Remote.Razor/TagHelpers/RemoteTagHelperResolver.cs @@ -3,7 +3,6 @@ using System; using System.Collections.Generic; -using System.Collections.Immutable; using System.Composition; using System.Threading; using System.Threading.Tasks; @@ -36,7 +35,7 @@ private static Dictionary CreateConfigurationName return map; } - public ValueTask> GetTagHelpersAsync( + public ValueTask GetTagHelpersAsync( Project workspaceProject, RazorConfiguration? configuration, CancellationToken cancellationToken) @@ -44,7 +43,7 @@ public ValueTask> GetTagHelpersAsync( ? workspaceProject.GetTagHelpersAsync(CreateProjectEngine(configuration), _telemetryReporter, cancellationToken) : new([]); - private RazorProjectEngine CreateProjectEngine(RazorConfiguration configuration) + private static RazorProjectEngine CreateProjectEngine(RazorConfiguration configuration) { // If there's no factory to handle the configuration then fall back to a very basic configuration. // diff --git a/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/Discovery/OutOfProcTagHelperResolver.cs b/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/Discovery/OutOfProcTagHelperResolver.cs index bebcdbc5f97..2e890e6fdda 100644 --- a/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/Discovery/OutOfProcTagHelperResolver.cs +++ b/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/Discovery/OutOfProcTagHelperResolver.cs @@ -40,7 +40,7 @@ internal class OutOfProcTagHelperResolver( private readonly ITelemetryReporter _telemetryReporter = telemetryReporter; private readonly TagHelperResultCache _resultCache = new(); - public async ValueTask> GetTagHelpersAsync( + public async ValueTask GetTagHelpersAsync( Project project, ProjectSnapshot projectSnapshot, CancellationToken cancellationToken) @@ -52,7 +52,7 @@ public async ValueTask> GetTagHelpersAsync( var result = await ResolveTagHelpersOutOfProcessAsync(project, projectSnapshot, cancellationToken).ConfigureAwait(false); // We received tag helpers, so we're done. - if (!result.IsDefault) + if (result is not null) { return result; } @@ -70,11 +70,11 @@ public async ValueTask> GetTagHelpersAsync( catch (Exception ex) when (ex is not OperationCanceledException) { _logger.LogError(ex, $"Error encountered from project '{projectSnapshot.FilePath}':{Environment.NewLine}{ex}"); - return default; + return null; } } - protected virtual async ValueTask> ResolveTagHelpersOutOfProcessAsync(Project project, ProjectSnapshot projectSnapshot, CancellationToken cancellationToken) + protected virtual async ValueTask ResolveTagHelpersOutOfProcessAsync(Project project, ProjectSnapshot projectSnapshot, CancellationToken cancellationToken) { if (!_resultCache.TryGetId(project.Id, out var lastResultId)) { @@ -92,7 +92,7 @@ protected virtual async ValueTask> ResolveTa if (deltaResult is null) { // For some reason, TryInvokeAsync can return null if it is cancelled while fetching the client. - return default; + return null; } // Apply the delta we received to any cached checksums for the current project. @@ -137,7 +137,7 @@ protected virtual async ValueTask> ResolveTa if (fetchResult is null) { // For some reason, TryInvokeAsync can return null if it is cancelled while fetching the client. - return default; + return null; } var fetchedTagHelpers = fetchResult.TagHelpers; @@ -149,7 +149,7 @@ protected virtual async ValueTask> ResolveTa } Debug.Assert( - checksumsToFetch.Length == fetchedTagHelpers.Length, + checksumsToFetch.Length == fetchedTagHelpers.Count, $"{nameof(FetchTagHelpersResult)} should return the same number of tag helpers as checksums requested."); Debug.Assert( @@ -159,7 +159,7 @@ protected virtual async ValueTask> ResolveTa // Be sure to add the tag helpers we just fetched to the cache. var cache = TagHelperCache.Default; - for (var i = 0; i < fetchedTagHelpers.Length; i++) + for (var i = 0; i < fetchedTagHelpers.Count; i++) { var index = checksumIndicesBuilder[i]; Debug.Assert(result[index] is null); @@ -169,14 +169,14 @@ protected virtual async ValueTask> ResolveTa cache.TryAdd(fetchedTagHelper.Checksum, fetchedTagHelper); } - if (checksumsToFetch.Length != fetchedTagHelpers.Length) + if (checksumsToFetch.Length != fetchedTagHelpers.Count) { _logger.LogWarning($"Expected to receive {checksumsToFetch.Length} tag helpers from Roslyn OOP, " + - $"but received {fetchedTagHelpers.Length} instead. Returning a partial set of tag helpers."); + $"but received {fetchedTagHelpers.Count} instead. Returning a partial set of tag helpers."); // We didn't receive all the tag helpers we requested. This is bad. However, instead of failing, // we'll just return the tag helpers we were able to retrieve. - using var resultBuilder = new PooledArrayBuilder(capacity: result.Length); + using var resultBuilder = new TagHelperCollection.RefBuilder(initialCapacity: result.Length); foreach (var tagHelper in result) { @@ -186,11 +186,17 @@ protected virtual async ValueTask> ResolveTa } } - return resultBuilder.ToImmutableAndClear(); + return resultBuilder.ToCollection(); } } - return ImmutableCollectionsMarshal.AsImmutableArray(result); + // If we pass 'result' to TagHelperCollection.Create(...) the overload that takes + // a ReadOnlySpan will be called, resulting in 'result' being + // copied to a new array. By first wrapping 'result' in an ImmutableArray we ensure + // that TagHelperCollection.Create(...) slices 'result' into segments. + var resultArray = ImmutableCollectionsMarshal.AsImmutableArray(result); + + return TagHelperCollection.Create(resultArray); } // Protected virtual for testing @@ -224,7 +230,7 @@ protected ImmutableArray ProduceChecksumsFromDelta(ProjectId projectId return checksums; } - protected virtual ValueTask> ResolveTagHelpersInProcessAsync( + protected virtual ValueTask ResolveTagHelpersInProcessAsync( Project project, ProjectSnapshot projectSnapshot, CancellationToken cancellationToken) diff --git a/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/Discovery/ProjectStateUpdater.cs b/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/Discovery/ProjectStateUpdater.cs index 2d9bbca820f..80ad12ed5a1 100644 --- a/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/Discovery/ProjectStateUpdater.cs +++ b/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/Discovery/ProjectStateUpdater.cs @@ -159,7 +159,7 @@ private async Task UpdateWorkspaceStateAsync(ProjectKey key, ProjectId? id, Canc return; } - _logger.LogTrace($"Received {nameof(ProjectWorkspaceState)} with {workspaceState.TagHelpers.Length} tag helper(s) for '{key}'"); + _logger.LogTrace($"Received {nameof(ProjectWorkspaceState)} with {workspaceState.TagHelpers.Count} tag helper(s) for '{key}'"); await _projectManager .UpdateAsync( @@ -172,7 +172,7 @@ await _projectManager return; } - logger.LogTrace($"Updating project with {workspaceState.TagHelpers.Length} tag helper(s) for '{projectKey}'"); + logger.LogTrace($"Updating project with {workspaceState.TagHelpers.Count} tag helper(s) for '{projectKey}'"); var projectSnapshot = updater.GetRequiredProject(projectKey); var hostProject = projectSnapshot.HostProject with { Configuration = configuration }; @@ -290,7 +290,7 @@ private void ReleaseSemaphore(ProjectKey projectKey) _telemetryReporter.ReportEvent("taghelperresolve/begin", Severity.Normal, new("id", telemetryId), - new("tagHelperCount", projectSnapshot.ProjectWorkspaceState.TagHelpers.Length)); + new("tagHelperCount", projectSnapshot.ProjectWorkspaceState.TagHelpers.Count)); try { @@ -317,7 +317,7 @@ private void ReleaseSemaphore(ProjectKey projectKey) // Don't report success if the call failed. // If the ImmutableArray that was returned is default, then the call failed. - if (tagHelpers.IsDefault) + if (tagHelpers is null) { _telemetryReporter.ReportEvent("taghelperresolve/end", Severity.Normal, new("id", telemetryId), @@ -335,14 +335,14 @@ Tag helper discovery failed. new("id", telemetryId), new("ellapsedms", watch.ElapsedMilliseconds), new("result", "success"), - new("tagHelperCount", tagHelpers.Length)); + new("tagHelperCount", tagHelpers.Count)); _logger.LogInformation($""" Resolved tag helpers for project in {watch.ElapsedMilliseconds} ms. Project: {projectSnapshot.FilePath} """); - return (ProjectWorkspaceState.Create(tagHelpers), configuration); + return (ProjectWorkspaceState.Create([.. tagHelpers]), configuration); } catch (OperationCanceledException) { diff --git a/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/Documents/EditorDocumentManagerListener.cs b/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/Documents/EditorDocumentManagerListener.cs index 0a22e87400e..2b5a2ae5f96 100644 --- a/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/Documents/EditorDocumentManagerListener.cs +++ b/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/Documents/EditorDocumentManagerListener.cs @@ -256,7 +256,7 @@ private Task Document_OpenedAsync(object sender, CancellationToken cancellationT "fallbackproject/documentopen", Severity.Normal, new Property("document.count", project.DocumentCount), - new Property("taghelper.count", project.ProjectWorkspaceState.TagHelpers.Length)); + new Property("taghelper.count", project.ProjectWorkspaceState.TagHelpers.Count)); } updater.OpenDocument(document.ProjectKey, document.DocumentFilePath, document.EditorTextContainer!.CurrentText); diff --git a/src/Razor/src/Microsoft.VisualStudio.LegacyEditor.Razor/Completion/LegacyTagHelperCompletionService.cs b/src/Razor/src/Microsoft.VisualStudio.LegacyEditor.Razor/Completion/LegacyTagHelperCompletionService.cs index 41f502d3196..f35d52cd32e 100644 --- a/src/Razor/src/Microsoft.VisualStudio.LegacyEditor.Razor/Completion/LegacyTagHelperCompletionService.cs +++ b/src/Razor/src/Microsoft.VisualStudio.LegacyEditor.Razor/Completion/LegacyTagHelperCompletionService.cs @@ -20,6 +20,9 @@ namespace Microsoft.VisualStudio.LegacyEditor.Razor.Completion; [Export(typeof(ITagHelperCompletionService))] internal sealed class LegacyTagHelperCompletionService : ITagHelperCompletionService { + private static readonly HashSetPool s_shortNameSetPool = + HashSetPool.Create(ShortNameToFullyQualifiedComparer.Instance); + private static readonly HashSet s_emptyHashSet = new(); // This API attempts to understand a users context as they're typing in a Razor file to provide TagHelper based attribute IntelliSense. @@ -45,8 +48,13 @@ public AttributeCompletionResult GetAttributeCompletions(AttributeCompletionCont StringComparer.OrdinalIgnoreCase); var documentContext = completionContext.DocumentContext; - var descriptorsForTag = TagHelperFacts.GetTagHelpersGivenTag(documentContext, completionContext.CurrentTagName, completionContext.CurrentParentTagName); - if (descriptorsForTag.Length == 0) + + var tagHelpersForTag = TagHelperFacts.GetTagHelpersGivenTag( + documentContext, + completionContext.CurrentTagName, + completionContext.CurrentParentTagName); + + if (tagHelpersForTag.IsEmpty) { // If the current tag has no possible descriptors then we can't have any additional attributes. return AttributeCompletionResult.Create(attributeCompletions); @@ -64,9 +72,9 @@ public AttributeCompletionResult GetAttributeCompletions(AttributeCompletionCont using var _ = HashSetPool.GetPooledObject(out var applicableDescriptors); - if (applicableTagHelperBinding is { Descriptors: var descriptors }) + if (applicableTagHelperBinding is { TagHelpers: var tagHelpers }) { - applicableDescriptors.UnionWith(descriptors); + applicableDescriptors.UnionWith(tagHelpers); } var unprefixedTagName = completionContext.CurrentTagName[prefix.Length..]; @@ -78,11 +86,11 @@ public AttributeCompletionResult GetAttributeCompletions(AttributeCompletionCont attributeCompletions.Clear(); } - foreach (var descriptor in descriptorsForTag) + foreach (var tagHelper in tagHelpersForTag) { - if (applicableDescriptors.Contains(descriptor)) + if (applicableDescriptors.Contains(tagHelper)) { - foreach (var attributeDescriptor in descriptor.BoundAttributes) + foreach (var attributeDescriptor in tagHelper.BoundAttributes) { if (!attributeDescriptor.Name.IsNullOrEmpty()) { @@ -98,7 +106,7 @@ public AttributeCompletionResult GetAttributeCompletions(AttributeCompletionCont else { var htmlNameToBoundAttribute = new Dictionary(StringComparer.OrdinalIgnoreCase); - foreach (var attributeDescriptor in descriptor.BoundAttributes) + foreach (var attributeDescriptor in tagHelper.BoundAttributes) { if (attributeDescriptor.Name != null) { @@ -111,7 +119,7 @@ public AttributeCompletionResult GetAttributeCompletions(AttributeCompletionCont } } - foreach (var rule in descriptor.TagMatchingRules) + foreach (var rule in tagHelper.TagMatchingRules) { foreach (var requiredAttribute in rule.Attributes) { @@ -178,16 +186,21 @@ public ElementCompletionResult GetElementCompletions(ElementCompletionContext co _ => new HashSet(), StringComparer.Ordinal); - var catchAllDescriptors = new HashSet(); + var catchAllTagHelpers = new HashSet(); var prefix = completionContext.DocumentContext.Prefix ?? string.Empty; - var possibleChildDescriptors = TagHelperFacts.GetTagHelpersGivenParent(completionContext.DocumentContext, completionContext.ContainingTagName); - possibleChildDescriptors = FilterFullyQualifiedCompletions(possibleChildDescriptors); - foreach (var possibleDescriptor in possibleChildDescriptors) + + var possibleChildTagHelpers = TagHelperFacts.GetTagHelpersGivenParent( + completionContext.DocumentContext, + completionContext.ContainingTagName); + + possibleChildTagHelpers = FilterFullyQualifiedTagHelpers(possibleChildTagHelpers); + + foreach (var possibleChildTagHelper in possibleChildTagHelpers) { var addRuleCompletions = false; - var outputHint = possibleDescriptor.TagOutputHint; + var outputHint = possibleChildTagHelper.TagOutputHint; - foreach (var rule in possibleDescriptor.TagMatchingRules) + foreach (var rule in possibleChildTagHelper.TagMatchingRules) { if (!TagHelperMatchingConventions.SatisfiesParentTag(rule, completionContext.ContainingTagName.AsSpanOrDefault())) { @@ -196,7 +209,7 @@ public ElementCompletionResult GetElementCompletions(ElementCompletionContext co if (rule.TagName == TagHelperMatchingConventions.ElementCatchAllName) { - catchAllDescriptors.Add(possibleDescriptor); + catchAllTagHelpers.Add(possibleChildTagHelper); } else if (elementCompletions.ContainsKey(rule.TagName)) { @@ -221,14 +234,14 @@ public ElementCompletionResult GetElementCompletions(ElementCompletionContext co if (addRuleCompletions) { - UpdateCompletions(prefix + rule.TagName, possibleDescriptor); + UpdateCompletions(prefix + rule.TagName, possibleChildTagHelper); } } } // We needed to track all catch-alls and update their completions after all other completions have been completed. // This way, any TagHelper added completions will also have catch-alls listed under their entries. - foreach (var catchAllDescriptor in catchAllDescriptors) + foreach (var catchAllDescriptor in catchAllTagHelpers) { foreach (var completionTagName in elementCompletions.Keys) { @@ -290,17 +303,17 @@ private void AddAllowedChildrenCompletions( return; } - foreach (var descriptor in binding.Descriptors) + foreach (var tagHelper in binding.TagHelpers) { - foreach (var childTag in descriptor.AllowedChildTags) + foreach (var childTag in tagHelper.AllowedChildTags) { var prefixedName = string.Concat(prefix, childTag.Name); - var descriptors = TagHelperFacts.GetTagHelpersGivenTag( + var tagHelpersForTag = TagHelperFacts.GetTagHelpersGivenTag( completionContext.DocumentContext, prefixedName, completionContext.ContainingTagName); - if (descriptors.Length == 0) + if (tagHelpersForTag.IsEmpty) { if (!elementCompletions.ContainsKey(prefixedName)) { @@ -316,47 +329,33 @@ private void AddAllowedChildrenCompletions( elementCompletions[prefixedName] = existingRuleDescriptors; } - existingRuleDescriptors.AddRange(descriptors); + existingRuleDescriptors.UnionWith(tagHelpersForTag); } } } - private static ImmutableArray FilterFullyQualifiedCompletions(ImmutableArray possibleChildDescriptors) + private static TagHelperCollection FilterFullyQualifiedTagHelpers(TagHelperCollection tagHelpers) { - // Iterate once through the list to tease apart fully qualified and short name TagHelpers - using var fullyQualifiedTagHelpers = new PooledArrayBuilder(); - var shortNameTagHelpers = new HashSet(ShortNameToFullyQualifiedComparer.Instance); + // We want to filter 'tagHelpers' and remove any tag helpers that require a fully-qualified name match + // but have a short name match present. - foreach (var descriptor in possibleChildDescriptors) - { - if (descriptor.IsFullyQualifiedNameMatch) - { - fullyQualifiedTagHelpers.Add(descriptor); - } - else - { - shortNameTagHelpers.Add(descriptor); - } - } + // First, collect all "short name" tag helpers, i.e. those that do not require a fully qualified name match. + using var _ = s_shortNameSetPool.GetPooledObject(out var shortNameSet); - // Re-combine the short named & fully qualified TagHelpers but filter out any fully qualified TagHelpers that have a short - // named representation already. - using var filteredList = new PooledArrayBuilder(capacity: shortNameTagHelpers.Count); - filteredList.AddRange(shortNameTagHelpers); - - foreach (var fullyQualifiedTagHelper in fullyQualifiedTagHelpers) + foreach (var tagHelper in tagHelpers) { - if (!shortNameTagHelpers.Contains(fullyQualifiedTagHelper)) + if (!tagHelper.IsFullyQualifiedNameMatch) { - // Unimported completion item that isn't represented in a short named form. - filteredList.Add(fullyQualifiedTagHelper); - } - else - { - // There's already a shortname variant of this item, don't include it. + shortNameSet.Add(tagHelper); } } - return filteredList.ToImmutableAndClear(); + return tagHelpers.Where(shortNameSet, static (tagHelper, shortNameSet) => + { + // We want to keep tag helpers that either: + // 1. Do not require a fully qualified name match (i.e., short name tag helpers). + // 2. Are fully qualified tag helpers that do not have a corresponding short name tag helper. + return !tagHelper.IsFullyQualifiedNameMatch || !shortNameSet.Contains(tagHelper); + }); } } diff --git a/src/Razor/src/Microsoft.VisualStudio.LegacyEditor.Razor/EphemeralProjectSnapshot.cs b/src/Razor/src/Microsoft.VisualStudio.LegacyEditor.Razor/EphemeralProjectSnapshot.cs index 4a51b790441..32d6d65f18f 100644 --- a/src/Razor/src/Microsoft.VisualStudio.LegacyEditor.Razor/EphemeralProjectSnapshot.cs +++ b/src/Razor/src/Microsoft.VisualStudio.LegacyEditor.Razor/EphemeralProjectSnapshot.cs @@ -2,7 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. using System; -using System.Collections.Immutable; using System.IO; using Microsoft.AspNetCore.Razor; using Microsoft.AspNetCore.Razor.Language; @@ -26,7 +25,7 @@ internal sealed class EphemeralProjectSnapshot(IProjectEngineFactoryProvider pro public RazorConfiguration Configuration => FallbackRazorConfiguration.Latest; public string? RootNamespace => null; public LanguageVersion CSharpLanguageVersion => LanguageVersion.Default; - public ImmutableArray TagHelpers => []; + public TagHelperCollection TagHelpers => []; public RazorProjectEngine GetProjectEngine() => _projectEngine.Value; diff --git a/src/Razor/src/Microsoft.VisualStudio.LegacyEditor.Razor/IVisualStudioDocumentTracker.cs b/src/Razor/src/Microsoft.VisualStudio.LegacyEditor.Razor/IVisualStudioDocumentTracker.cs index 7f936343cf8..ae3226ac284 100644 --- a/src/Razor/src/Microsoft.VisualStudio.LegacyEditor.Razor/IVisualStudioDocumentTracker.cs +++ b/src/Razor/src/Microsoft.VisualStudio.LegacyEditor.Razor/IVisualStudioDocumentTracker.cs @@ -3,7 +3,6 @@ using System; using System.Collections.Generic; -using System.Collections.Immutable; using Microsoft.AspNetCore.Razor.Language; using Microsoft.CodeAnalysis.Razor.ProjectSystem.Legacy; using Microsoft.CodeAnalysis.Razor.Settings; @@ -16,7 +15,7 @@ internal interface IVisualStudioDocumentTracker { RazorConfiguration? Configuration { get; } ClientSpaceSettings EditorSettings { get; } - ImmutableArray TagHelpers { get; } + TagHelperCollection TagHelpers { get; } bool IsSupportedProject { get; } string FilePath { get; } string ProjectPath { get; } diff --git a/src/Razor/src/Microsoft.VisualStudio.LegacyEditor.Razor/Parsing/VisualStudioRazorParser.cs b/src/Razor/src/Microsoft.VisualStudio.LegacyEditor.Razor/Parsing/VisualStudioRazorParser.cs index 8945148d6de..6cd75e68db6 100644 --- a/src/Razor/src/Microsoft.VisualStudio.LegacyEditor.Razor/Parsing/VisualStudioRazorParser.cs +++ b/src/Razor/src/Microsoft.VisualStudio.LegacyEditor.Razor/Parsing/VisualStudioRazorParser.cs @@ -581,18 +581,11 @@ private void CompleteCodeDocumentRequestsForSnapshot(RazorCodeDocument codeDocum } } - private class VisualStudioTagHelperFeature : RazorEngineFeatureBase, ITagHelperFeature + private class VisualStudioTagHelperFeature(TagHelperCollection tagHelpers) : RazorEngineFeatureBase, ITagHelperFeature { - private readonly IReadOnlyList? _tagHelpers; - - public VisualStudioTagHelperFeature(IReadOnlyList? tagHelpers) - { - _tagHelpers = tagHelpers; - } - - public IReadOnlyList GetDescriptors(CancellationToken cancellationToken = default) + public TagHelperCollection GetTagHelpers(CancellationToken cancellationToken = default) { - return _tagHelpers ?? []; + return tagHelpers; } } diff --git a/src/Razor/src/Microsoft.VisualStudio.LegacyEditor.Razor/VisualStudioDocumentTracker.cs b/src/Razor/src/Microsoft.VisualStudio.LegacyEditor.Razor/VisualStudioDocumentTracker.cs index 0569e316961..d7d828da149 100644 --- a/src/Razor/src/Microsoft.VisualStudio.LegacyEditor.Razor/VisualStudioDocumentTracker.cs +++ b/src/Razor/src/Microsoft.VisualStudio.LegacyEditor.Razor/VisualStudioDocumentTracker.cs @@ -3,8 +3,6 @@ using System; using System.Collections.Generic; -using System.Collections.Immutable; -using System.Linq; using System.Threading; using System.Threading.Tasks; using Microsoft.AspNetCore.Razor; @@ -70,7 +68,7 @@ public VisualStudioDocumentTracker( public ClientSpaceSettings EditorSettings => _workspaceEditorSettings.Current.ClientSpaceSettings; - public ImmutableArray TagHelpers + public TagHelperCollection TagHelpers => _projectSnapshot is { TagHelpers: var tagHelpers } ? tagHelpers : []; @@ -218,7 +216,7 @@ internal void ProjectManager_Changed(object sender, ProjectChangeEventArgs e) OnContextChangedAsync(ContextChangeKind.ProjectChanged).Forget(); if (e.Older is not ILegacyProjectSnapshot older || - !older.TagHelpers.SequenceEqual(newer.TagHelpers)) + !older.TagHelpers.Equals(newer.TagHelpers)) { OnContextChangedAsync(ContextChangeKind.TagHelpersChanged).Forget(); } diff --git a/src/Razor/test/Microsoft.AspNetCore.Razor.ExternalAccess.LegacyEditor.Test/RazorSyntaxFactsServiceTest.cs b/src/Razor/test/Microsoft.AspNetCore.Razor.ExternalAccess.LegacyEditor.Test/RazorSyntaxFactsServiceTest.cs index 522bc96bcc0..b455ba332b3 100644 --- a/src/Razor/test/Microsoft.AspNetCore.Razor.ExternalAccess.LegacyEditor.Test/RazorSyntaxFactsServiceTest.cs +++ b/src/Razor/test/Microsoft.AspNetCore.Razor.ExternalAccess.LegacyEditor.Test/RazorSyntaxFactsServiceTest.cs @@ -1,7 +1,6 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -using System.Collections.Immutable; using Microsoft.AspNetCore.Razor.Language; using Xunit; using Xunit.Abstractions; @@ -98,7 +97,7 @@ private IRazorCodeDocument GetCodeDocument(string source) var sourceDocument = TestRazorSourceDocument.Create(source, normalizeNewLines: true); var importDocument = TestRazorSourceDocument.Create("@addTagHelper *, TestAssembly", filePath: "import.cshtml", relativePath: "import.cshtml"); - var codeDocument = engine.ProcessDesignTime(sourceDocument, RazorFileKind.Legacy, importSources: ImmutableArray.Create(importDocument), new[] { taghelper }); + var codeDocument = engine.ProcessDesignTime(sourceDocument, RazorFileKind.Legacy, importSources: [importDocument], [taghelper]); return RazorWrapperFactory.WrapCodeDocument(codeDocument); } diff --git a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/AutoInsert/RazorOnAutoInsertProviderTestBase.cs b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/AutoInsert/RazorOnAutoInsertProviderTestBase.cs index c10d481c6fc..f591a868349 100644 --- a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/AutoInsert/RazorOnAutoInsertProviderTestBase.cs +++ b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/AutoInsert/RazorOnAutoInsertProviderTestBase.cs @@ -2,7 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. using System; -using System.Collections.Immutable; using Microsoft.AspNetCore.Razor.Language; using Microsoft.AspNetCore.Razor.Test.Common.LanguageServer; using Microsoft.CodeAnalysis.Razor.AutoInsert; @@ -22,7 +21,7 @@ protected void RunAutoInsertTest( string expected, bool enableAutoClosingTags = true, RazorFileKind? fileKind = null, - ImmutableArray tagHelpers = default) + TagHelperCollection? tagHelpers = null) { // Arrange TestFileMarkupParser.GetPosition(input, out input, out var location); @@ -54,11 +53,11 @@ private static SourceText ApplyEdit(SourceText source, TextEdit edit) private static RazorCodeDocument CreateCodeDocument( SourceText text, string path, - ImmutableArray tagHelpers, + TagHelperCollection? tagHelpers, RazorFileKind? fileKind = null) { var fileKindValue = fileKind ?? RazorFileKind.Component; - tagHelpers = tagHelpers.NullToEmpty(); + tagHelpers ??= []; var sourceDocument = RazorSourceDocument.Create(text, RazorSourceDocumentProperties.Create(path, path)); var projectEngine = RazorProjectEngine.Create(builder => diff --git a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/CodeActions/CSharp/CSharpCodeActionProviderTest.cs b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/CodeActions/CSharp/CSharpCodeActionProviderTest.cs index 169222c6cb7..ffae1703b2f 100644 --- a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/CodeActions/CSharp/CSharpCodeActionProviderTest.cs +++ b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/CodeActions/CSharp/CSharpCodeActionProviderTest.cs @@ -307,11 +307,11 @@ private static RazorCodeActionContext CreateRazorCodeActionContext( bool supportsFileCreation = true, bool supportsCodeActionResolve = true) { - var tagHelpers = ImmutableArray.Empty; + var tagHelpers = TagHelperCollection.Empty; var sourceDocument = TestRazorSourceDocument.Create(text, filePath: filePath, relativePath: filePath); var projectEngine = RazorProjectEngine.Create(builder => { - builder.AddTagHelpers(tagHelpers); + builder.SetTagHelpers(tagHelpers); builder.ConfigureParserOptions(builder => { diff --git a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/CodeActions/CSharp/TypeAccessibilityCodeActionProviderTest.cs b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/CodeActions/CSharp/TypeAccessibilityCodeActionProviderTest.cs index b21cce5223a..a1524cbafe0 100644 --- a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/CodeActions/CSharp/TypeAccessibilityCodeActionProviderTest.cs +++ b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/CodeActions/CSharp/TypeAccessibilityCodeActionProviderTest.cs @@ -431,12 +431,12 @@ private static RazorCodeActionContext CreateRazorCodeActionContext( var fullyQualifiedComponent = TagHelperDescriptorBuilder.CreateComponent("Fully.Qualified.Component", "TestAssembly"); fullyQualifiedComponent.TagMatchingRule(rule => rule.TagName = "Fully.Qualified.Component"); - var tagHelpers = ImmutableArray.Create(shortComponent.Build(), fullyQualifiedComponent.Build()); + TagHelperCollection tagHelpers = [shortComponent.Build(), fullyQualifiedComponent.Build()]; var sourceDocument = TestRazorSourceDocument.Create(text, filePath: filePath, relativePath: filePath); var projectEngine = RazorProjectEngine.Create(builder => { - builder.AddTagHelpers(tagHelpers); + builder.SetTagHelpers(tagHelpers); builder.AddDirective(InjectDirective.Directive); builder.ConfigureParserOptions(builder => diff --git a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/CodeActions/CodeActionEndToEndTest.NetFx.cs b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/CodeActions/CodeActionEndToEndTest.NetFx.cs index b4fa852f71d..da59332bea5 100644 --- a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/CodeActions/CodeActionEndToEndTest.NetFx.cs +++ b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/CodeActions/CodeActionEndToEndTest.NetFx.cs @@ -11,8 +11,6 @@ using Microsoft.CodeAnalysis.Razor.Formatting; using Microsoft.CodeAnalysis.Razor.Protocol; using Microsoft.CodeAnalysis.Testing; -using Microsoft.CodeAnalysis.Text; -using Roslyn.Test.Utilities; using Xunit; using Xunit.Abstractions; diff --git a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/CodeActions/CodeActionEndToEndTestBase.NetFx.cs b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/CodeActions/CodeActionEndToEndTestBase.NetFx.cs index 02ab7f1c1f6..7b8569c7da5 100644 --- a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/CodeActions/CodeActionEndToEndTestBase.NetFx.cs +++ b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/CodeActions/CodeActionEndToEndTestBase.NetFx.cs @@ -288,7 +288,7 @@ internal async Task GetEditsAsync( return documentEdits; } - internal static ImmutableArray CreateTagHelperDescriptors() + internal static TagHelperCollection CreateTagHelperDescriptors() { return [.. BuildTagHelpers()]; diff --git a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/CodeActions/Html/HtmlCodeActionProviderTest.cs b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/CodeActions/Html/HtmlCodeActionProviderTest.cs index def2a9572d3..9d91f6bdd84 100644 --- a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/CodeActions/Html/HtmlCodeActionProviderTest.cs +++ b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/CodeActions/Html/HtmlCodeActionProviderTest.cs @@ -139,11 +139,11 @@ private static RazorCodeActionContext CreateRazorCodeActionContext( bool supportsFileCreation = true, bool supportsCodeActionResolve = true) { - var tagHelpers = ImmutableArray.Empty; + var tagHelpers = TagHelperCollection.Empty; var sourceDocument = TestRazorSourceDocument.Create(text, filePath: filePath, relativePath: filePath); var projectEngine = RazorProjectEngine.Create(builder => { - builder.AddTagHelpers(tagHelpers); + builder.SetTagHelpers(tagHelpers); builder.ConfigureParserOptions(builder => { diff --git a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/CodeActions/Razor/ComponentAccessibilityCodeActionProviderTest.cs b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/CodeActions/Razor/ComponentAccessibilityCodeActionProviderTest.cs index ead20806c3e..f55f98b44e9 100644 --- a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/CodeActions/Razor/ComponentAccessibilityCodeActionProviderTest.cs +++ b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/CodeActions/Razor/ComponentAccessibilityCodeActionProviderTest.cs @@ -466,12 +466,12 @@ private static RazorCodeActionContext CreateRazorCodeActionContext( fullyQualifiedGenericComponent.CaseSensitive = true; fullyQualifiedGenericComponent.TagMatchingRule(rule => rule.TagName = "Fully.Qualified.GenericComponent"); - var tagHelpers = ImmutableArray.Create(shortComponent.Build(), fullyQualifiedComponent.Build(), shortGenericComponent.Build(), fullyQualifiedGenericComponent.Build()); + TagHelperCollection tagHelpers = [shortComponent.Build(), fullyQualifiedComponent.Build(), shortGenericComponent.Build(), fullyQualifiedGenericComponent.Build()]; var sourceDocument = TestRazorSourceDocument.Create(text, filePath: filePath, relativePath: filePath); var projectEngine = RazorProjectEngine.Create(builder => { - builder.AddTagHelpers(tagHelpers); + builder.SetTagHelpers(tagHelpers); builder.ConfigureParserOptions(builder => { diff --git a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Completion/TagHelperCompletionProviderTest.cs b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Completion/TagHelperCompletionProviderTest.cs index 29cc3fc059b..e0e4ccefff1 100644 --- a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Completion/TagHelperCompletionProviderTest.cs +++ b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Completion/TagHelperCompletionProviderTest.cs @@ -4,7 +4,6 @@ #nullable disable using System.Collections.Generic; -using System.Collections.Immutable; using Microsoft.AspNetCore.Razor.Language; using Microsoft.AspNetCore.Razor.Language.Syntax; using Microsoft.AspNetCore.Razor.Test.Common; @@ -561,7 +560,7 @@ public void GetCompletionAt_AtAttributeEdge_IndexerBoolAttribute_ReturnsCompleti """, isRazorFile: false, - tagHelpers: ImmutableArray.Create(tagHelper.Build())); + tagHelpers: [tagHelper.Build()]); // Act var completions = service.GetCompletionItems(context); @@ -604,7 +603,7 @@ public void GetCompletionAt_AtAttributeEdge_IndexerAttribute_ReturnsCompletions( """, isRazorFile: false, - tagHelpers: ImmutableArray.Create(tagHelper.Build())); + tagHelpers: [tagHelper.Build()]); // Act var completions = service.GetCompletionItems(context); @@ -971,17 +970,17 @@ public void GetCompletionAt_ComponentWithEditorRequiredAttributes_SnippetsSuppor """, isRazorFile: true, options, - tagHelpers: ImmutableArray.Create(componentBuilder.Build())); + tagHelpers: [componentBuilder.Build()]); // Act var completions = service.GetCompletionItems(context); // Assert - should have two completions: regular and snippet Assert.Equal(2, completions.Length); - + RazorCompletionItem regularCompletion = null; RazorCompletionItem snippetCompletion = null; - + foreach (var completion in completions) { if (completion.DisplayText == "ComponentWithRequiredParams") @@ -993,11 +992,11 @@ public void GetCompletionAt_ComponentWithEditorRequiredAttributes_SnippetsSuppor snippetCompletion = completion; } } - + Assert.NotNull(regularCompletion); Assert.False(regularCompletion.IsSnippet); Assert.Equal("ComponentWithRequiredParams", regularCompletion.InsertText); - + Assert.NotNull(snippetCompletion); Assert.True(snippetCompletion.IsSnippet); Assert.Contains("RequiredParam1", snippetCompletion.InsertText); @@ -1036,7 +1035,7 @@ public void GetCompletionAt_ComponentWithEditorRequiredAttributes_SnippetsNotSup """, isRazorFile: true, options, - tagHelpers: ImmutableArray.Create(componentBuilder.Build())); + tagHelpers: [componentBuilder.Build()]); // Act var completions = service.GetCompletionItems(context); @@ -1074,7 +1073,7 @@ public void GetCompletionAt_ComponentWithNoEditorRequiredAttributes_SnippetsSupp """, isRazorFile: true, options, - tagHelpers: ImmutableArray.Create(componentBuilder.Build())); + tagHelpers: [componentBuilder.Build()]); // Act var completions = service.GetCompletionItems(context); @@ -1086,9 +1085,13 @@ public void GetCompletionAt_ComponentWithNoEditorRequiredAttributes_SnippetsSupp Assert.Equal("ComponentWithoutRequired", completion.InsertText); } - private static RazorCompletionContext CreateRazorCompletionContext(string markup, bool isRazorFile, RazorCompletionOptions options = default, ImmutableArray tagHelpers = default) + private static RazorCompletionContext CreateRazorCompletionContext( + string markup, + bool isRazorFile, + RazorCompletionOptions options = default, + TagHelperCollection tagHelpers = null) { - tagHelpers = tagHelpers.NullToEmpty(); + tagHelpers ??= []; TestFileMarkupParser.GetPosition(markup, out var documentContent, out var position); var codeDocument = CreateCodeDocument(documentContent, isRazorFile, tagHelpers); diff --git a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Completion/TagHelperServiceTestBase.cs b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Completion/TagHelperServiceTestBase.cs index 778cfcf1672..14eb54161f9 100644 --- a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Completion/TagHelperServiceTestBase.cs +++ b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Completion/TagHelperServiceTestBase.cs @@ -1,7 +1,6 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -using System.Collections.Immutable; using Microsoft.AspNetCore.Razor.Language; using Microsoft.AspNetCore.Razor.Test.Common; using Microsoft.AspNetCore.Razor.Test.Common.LanguageServer; @@ -11,14 +10,14 @@ namespace Microsoft.AspNetCore.Razor.LanguageServer.Completion; public abstract class TagHelperServiceTestBase(ITestOutputHelper testOutput) : LanguageServerTestBase(testOutput) { - protected static ImmutableArray DefaultTagHelpers => SimpleTagHelpers.Default; + protected static TagHelperCollection DefaultTagHelpers => SimpleTagHelpers.Default; protected static string GetFileName(bool isRazorFile) => RazorCodeDocumentFactory.GetFileName(isRazorFile); - protected static RazorCodeDocument CreateCodeDocument(string text, bool isRazorFile, params ImmutableArray tagHelpers) + protected static RazorCodeDocument CreateCodeDocument(string text, bool isRazorFile, params TagHelperCollection tagHelpers) => RazorCodeDocumentFactory.CreateCodeDocument(text, isRazorFile, tagHelpers); - protected static RazorCodeDocument CreateCodeDocument(string text, string filePath, params ImmutableArray tagHelpers) + protected static RazorCodeDocument CreateCodeDocument(string text, string filePath, params TagHelperCollection tagHelpers) => RazorCodeDocumentFactory.CreateCodeDocument(text, filePath, tagHelpers); } diff --git a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Formatting_NetFx/CodeDirectiveFormattingTest.cs b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Formatting_NetFx/CodeDirectiveFormattingTest.cs index 1aadee43d1e..389732eca72 100644 --- a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Formatting_NetFx/CodeDirectiveFormattingTest.cs +++ b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Formatting_NetFx/CodeDirectiveFormattingTest.cs @@ -1,7 +1,6 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -using System.Collections.Immutable; using System.Threading.Tasks; using Microsoft.AspNetCore.Razor.Language; using Microsoft.AspNetCore.Razor.Test.Common; @@ -70,7 +69,7 @@ await RunFormattingTestAsync( private IEnumerable _items = new[] { 1, 2, 3, 4, 5 }; } """, - tagHelpers: GetComponentWithCascadingTypeParameter()); + tagHelpers: [.. GetComponentWithCascadingTypeParameter()]); } [FormattingTestFact] @@ -120,7 +119,7 @@ await RunFormattingTestAsync( private IEnumerable _items = new[] { 1, 2, 3, 4, 5 }; } """, - tagHelpers: GetComponentWithCascadingTypeParameter()); + tagHelpers: [.. GetComponentWithCascadingTypeParameter()]); } [FormattingTestFact] @@ -160,10 +159,10 @@ await RunFormattingTestAsync( private IEnumerable _items2 = new long[] { 1, 2, 3, 4, 5 }; } """, - tagHelpers: GetComponentWithTwoCascadingTypeParameter()); + tagHelpers: [.. GetComponentWithTwoCascadingTypeParameter()]); } - private ImmutableArray GetComponentWithCascadingTypeParameter() + private TagHelperCollection GetComponentWithCascadingTypeParameter() { var input = """ @using System.Collections.Generic @@ -185,7 +184,7 @@ @attribute [CascadingTypeParameter(nameof(TItem))] return generated.CodeDocument.GetRequiredTagHelperContext().TagHelpers; } - private ImmutableArray GetComponentWithTwoCascadingTypeParameter() + private TagHelperCollection GetComponentWithTwoCascadingTypeParameter() { var input = """ @using System.Collections.Generic diff --git a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Formatting_NetFx/FormattingContentValidationPassTest.cs b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Formatting_NetFx/FormattingContentValidationPassTest.cs index a9121c3d38e..86947910032 100644 --- a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Formatting_NetFx/FormattingContentValidationPassTest.cs +++ b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Formatting_NetFx/FormattingContentValidationPassTest.cs @@ -97,11 +97,11 @@ private static FormattingContext CreateFormattingContext private static (RazorCodeDocument, IDocumentSnapshot) CreateCodeDocumentAndSnapshot( SourceText text, string path, - ImmutableArray tagHelpers = default, + TagHelperCollection? tagHelpers = null, RazorFileKind? fileKind = null) { var fileKindValue = fileKind ?? RazorFileKind.Component; - tagHelpers = tagHelpers.NullToEmpty(); + tagHelpers ??= []; var sourceDocument = RazorSourceDocument.Create(text, RazorSourceDocumentProperties.Create(path, path)); var projectEngine = RazorProjectEngine.Create(builder => diff --git a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Formatting_NetFx/FormattingDiagnosticValidationPassTest.cs b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Formatting_NetFx/FormattingDiagnosticValidationPassTest.cs index ad52c5cbd3f..6cb25b593c2 100644 --- a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Formatting_NetFx/FormattingDiagnosticValidationPassTest.cs +++ b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Formatting_NetFx/FormattingDiagnosticValidationPassTest.cs @@ -95,11 +95,11 @@ private static FormattingContext CreateFormattingContext( private static (RazorCodeDocument, IDocumentSnapshot) CreateCodeDocumentAndSnapshot( SourceText text, string path, - ImmutableArray tagHelpers = default, + TagHelperCollection? tagHelpers = null, RazorFileKind? fileKind = null) { var fileKindValue = fileKind ?? RazorFileKind.Component; - tagHelpers = tagHelpers.NullToEmpty(); + tagHelpers ??= []; var sourceDocument = RazorSourceDocument.Create(text, RazorSourceDocumentProperties.Create(path, path)); var projectEngine = RazorProjectEngine.Create(builder => diff --git a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Formatting_NetFx/FormattingTestBase.cs b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Formatting_NetFx/FormattingTestBase.cs index be252e20a17..c0a706c7b37 100644 --- a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Formatting_NetFx/FormattingTestBase.cs +++ b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Formatting_NetFx/FormattingTestBase.cs @@ -36,7 +36,7 @@ namespace Microsoft.AspNetCore.Razor.LanguageServer.Formatting; public abstract class FormattingTestBase : RazorToolingIntegrationTestBase { - private static readonly AsyncLazy> s_standardTagHelpers = AsyncLazy.Create(GetStandardTagHelpersAsync); + private static readonly AsyncLazy s_standardTagHelpers = AsyncLazy.Create(GetStandardTagHelpersAsync); private readonly HtmlFormattingService _htmlFormattingService; private readonly FormattingTestContext _context; @@ -56,7 +56,7 @@ private protected async Task RunFormattingTestAsync( int tabSize = 4, bool insertSpaces = true, RazorFileKind? fileKind = null, - ImmutableArray tagHelpers = default, + TagHelperCollection? tagHelpers = null, bool allowDiagnostics = false, bool codeBlockBraceOnNextLine = false, bool inGlobalNamespace = false, @@ -78,7 +78,7 @@ private async Task RunFormattingTestInternalAsync( int tabSize, bool insertSpaces, RazorFileKind? fileKind, - ImmutableArray tagHelpers, + TagHelperCollection? tagHelpers, bool allowDiagnostics, RazorLSPOptions? razorLSPOptions, bool inGlobalNamespace, @@ -87,7 +87,7 @@ private async Task RunFormattingTestInternalAsync( { // Arrange var fileKindValue = fileKind ?? RazorFileKind.Component; - tagHelpers = tagHelpers.NullToEmpty(); + tagHelpers ??= []; TestFileMarkupParser.GetSpans(input, out input, out ImmutableArray spans); @@ -96,7 +96,7 @@ private async Task RunFormattingTestInternalAsync( ? null : source.GetLinePositionSpan(spans.Single()); - tagHelpers = tagHelpers.AddRange(await s_standardTagHelpers.GetValueAsync(DisposalToken)); + tagHelpers = TagHelperCollection.Merge(tagHelpers, await s_standardTagHelpers.GetValueAsync(DisposalToken)); var path = "file:///path/to/Document." + fileKindValue.ToString(); var uri = new Uri(path); @@ -229,7 +229,7 @@ private protected async Task RunOnTypeFormattingTestAsync( private (RazorCodeDocument, IDocumentSnapshot) CreateCodeDocumentAndSnapshot( SourceText text, string path, - ImmutableArray tagHelpers, + TagHelperCollection tagHelpers, RazorFileKind? fileKind = null, bool allowDiagnostics = false, bool inGlobalNamespace = false) @@ -303,7 +303,7 @@ internal static IDocumentSnapshot CreateDocumentSnapshot( RazorProjectEngine projectEngine, ImmutableArray imports, ImmutableArray importDocuments, - ImmutableArray tagHelpers, + TagHelperCollection tagHelpers, bool inGlobalNamespace) { var projectKey = new ProjectKey(Path.Combine(path, "obj")); @@ -354,7 +354,7 @@ internal static IDocumentSnapshot CreateDocumentSnapshot( return snapshotMock.Object; } - private static async Task> GetStandardTagHelpersAsync(CancellationToken cancellationToken) + private static async Task GetStandardTagHelpersAsync(CancellationToken cancellationToken) { var projectId = ProjectId.CreateNewId(); var projectInfo = ProjectInfo diff --git a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Formatting_NetFx/HtmlFormattingTest.cs b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Formatting_NetFx/HtmlFormattingTest.cs index 2a7fa0de08f..23f85daf973 100644 --- a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Formatting_NetFx/HtmlFormattingTest.cs +++ b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Formatting_NetFx/HtmlFormattingTest.cs @@ -56,7 +56,7 @@ await RunFormattingTestAsync( } """, - tagHelpers: tagHelpers); + tagHelpers: [.. tagHelpers]); } [FormattingTestFact] @@ -80,7 +80,7 @@ await RunFormattingTestAsync( """, - tagHelpers: tagHelpers); + tagHelpers: [.. tagHelpers]); } [FormattingTestFact] @@ -102,7 +102,7 @@ await RunFormattingTestAsync( """, - tagHelpers: tagHelpers); + tagHelpers: [.. tagHelpers]); } [FormattingTestFact] @@ -124,7 +124,7 @@ await RunFormattingTestAsync( """, - tagHelpers: tagHelpers); + tagHelpers: [.. tagHelpers]); } [FormattingTestFact] @@ -150,7 +150,7 @@ await RunFormattingTestAsync( """, - tagHelpers: tagHelpers); + tagHelpers: [.. tagHelpers]); } [FormattingTestFact] @@ -198,7 +198,7 @@ await RunFormattingTestAsync( """, - tagHelpers: GetComponents()); + tagHelpers: [.. GetComponents()]); } [FormattingTestFact] @@ -260,7 +260,7 @@ await RunFormattingTestAsync( } """, - tagHelpers: GetComponents()); + tagHelpers: [.. GetComponents()]); } [FormattingTestFact(Skip = "Requires fix")] @@ -284,7 +284,7 @@ await RunFormattingTestAsync( ; } """, - tagHelpers: GetComponents()); + tagHelpers: [.. GetComponents()]); } [FormattingTestFact] @@ -312,7 +312,7 @@ await RunFormattingTestAsync( } """, - tagHelpers: GetComponents()); + tagHelpers: [.. GetComponents()]); } [FormattingTestFact] @@ -360,7 +360,7 @@ await RunFormattingTestAsync( """, - tagHelpers: GetComponents()); + tagHelpers: [.. GetComponents()]); } [FormattingTestFact] @@ -398,7 +398,7 @@ await RunFormattingTestAsync( } """, - tagHelpers: CreateTagHelpers()); + tagHelpers: [.. CreateTagHelpers()]); ImmutableArray CreateTagHelpers() { @@ -480,7 +480,7 @@ await RunFormattingTestAsync( allowDiagnostics: true); } - private ImmutableArray GetComponents() + private TagHelperCollection GetComponents() { AdditionalSyntaxTrees.Add(Parse(""" using Microsoft.AspNetCore.Components; diff --git a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Refactoring/RenameEndpointTest.cs b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Refactoring/RenameEndpointTest.cs index 5145ce72968..f31c736913b 100644 --- a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Refactoring/RenameEndpointTest.cs +++ b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Refactoring/RenameEndpointTest.cs @@ -327,7 +327,7 @@ public async Task Handle_Rename_ComponentInSameFile() // Assert Assert.NotNull(result); var documentChanges = result.DocumentChanges.AssumeNotNull(); - Assert.Equal(5, documentChanges.Count()); + Assert.Equal(4, documentChanges.Count()); // We renamed Component3 to Component5, so we should expect file rename. var renameChange = documentChanges.ElementAt(0); @@ -335,20 +335,14 @@ public async Task Handle_Rename_ComponentInSameFile() Assert.Equal(TestPathUtilities.GetUri(s_componentFilePath3), renameFile.OldDocumentUri.GetRequiredParsedUri()); Assert.Equal(TestPathUtilities.GetUri(s_componentFilePath5), renameFile.NewDocumentUri.GetRequiredParsedUri()); - Assert.Collection(GetTextDocumentEdits(result, startIndex: 1, endIndex: 4), + Assert.Collection(GetTextDocumentEdits(result, startIndex: 1, endIndex: 3), textDocumentEdit => { Assert.Equal(TestPathUtilities.GetUri(s_componentFilePath4), textDocumentEdit.TextDocument.DocumentUri.GetRequiredParsedUri()); Assert.Collection( textDocumentEdit.Edits, AssertTextEdit("Component5", startLine: 1, startCharacter: 1, endLine: 1, endCharacter: 11), - AssertTextEdit("Component5", startLine: 1, startCharacter: 14, endLine: 1, endCharacter: 24)); - }, - textDocumentEdit => - { - Assert.Equal(TestPathUtilities.GetUri(s_componentFilePath4), textDocumentEdit.TextDocument.DocumentUri.GetRequiredParsedUri()); - Assert.Collection( - textDocumentEdit.Edits, + AssertTextEdit("Component5", startLine: 1, startCharacter: 14, endLine: 1, endCharacter: 24), AssertTextEdit("Component5", startLine: 2, startCharacter: 1, endLine: 2, endCharacter: 11), AssertTextEdit("Component5", startLine: 2, startCharacter: 14, endLine: 2, endCharacter: 24)); }, @@ -413,7 +407,7 @@ public async Task Handle_Rename_FullyQualifiedAndNot() // Assert Assert.NotNull(result); var documentChanges = result.DocumentChanges.AssumeNotNull(); - Assert.Equal(3, documentChanges.Count()); + Assert.Equal(2, documentChanges.Count()); var renameChange = documentChanges.ElementAt(0); Assert.True(renameChange.TryGetThird(out var renameFile)); @@ -426,13 +420,7 @@ public async Task Handle_Rename_FullyQualifiedAndNot() Assert.Collection( textDocumentEdit.Edits, AssertTextEdit("Component5", startLine: 2, startCharacter: 1, endLine: 2, endCharacter: 14), - AssertTextEdit("Component5", startLine: 2, startCharacter: 17, endLine: 2, endCharacter: 30)); - - var editChange2 = result.DocumentChanges.Value.ElementAt(2); - Assert.True(editChange2.TryGetFirst(out var textDocumentEdit2)); - Assert.Equal(TestPathUtilities.GetUri(s_indexFilePath1), textDocumentEdit2.TextDocument.DocumentUri.GetRequiredParsedUri()); - Assert.Collection( - textDocumentEdit2.Edits, + AssertTextEdit("Component5", startLine: 2, startCharacter: 17, endLine: 2, endCharacter: 30), AssertTextEdit("Test.Component5", startLine: 3, startCharacter: 1, endLine: 3, endCharacter: 19), AssertTextEdit("Test.Component5", startLine: 3, startCharacter: 22, endLine: 3, endCharacter: 40)); } @@ -459,7 +447,7 @@ public async Task Handle_Rename_MultipleFileUsages() // Assert Assert.NotNull(result); var documentChanges = result.DocumentChanges.AssumeNotNull(); - Assert.Equal(5, documentChanges.Count()); + Assert.Equal(4, documentChanges.Count()); var renameChange = documentChanges.ElementAt(0); Assert.True(renameChange.TryGetThird(out var renameFile)); @@ -477,17 +465,18 @@ public async Task Handle_Rename_MultipleFileUsages() var editChange2 = documentChanges.ElementAt(2); Assert.True(editChange2.TryGetFirst(out var textDocumentEdit2)); Assert.Equal(TestPathUtilities.GetUri(s_componentFilePath4), textDocumentEdit2.TextDocument.DocumentUri.GetRequiredParsedUri()); - Assert.Equal(2, textDocumentEdit2.Edits.Length); + Assert.Collection( + textDocumentEdit.Edits, + AssertTextEdit("Component5", 1, 1, 1, 11), + AssertTextEdit("Component5", 1, 14, 1, 24)); var editChange3 = documentChanges.ElementAt(3); Assert.True(editChange3.TryGetFirst(out var textDocumentEdit3)); - Assert.Equal(TestPathUtilities.GetUri(s_componentFilePath4), textDocumentEdit3.TextDocument.DocumentUri.GetRequiredParsedUri()); - Assert.Equal(2, textDocumentEdit3.Edits.Length); - - var editChange4 = documentChanges.ElementAt(4); - Assert.True(editChange4.TryGetFirst(out var textDocumentEdit4)); - Assert.Equal(TestPathUtilities.GetUri(s_componentWithParamFilePath), textDocumentEdit4.TextDocument.DocumentUri.GetRequiredParsedUri()); - Assert.Equal(2, textDocumentEdit4.Edits.Length); + Assert.Equal(TestPathUtilities.GetUri(s_componentWithParamFilePath), textDocumentEdit3.TextDocument.DocumentUri.GetRequiredParsedUri()); + Assert.Collection( + textDocumentEdit.Edits, + AssertTextEdit("Component5", 1, 1, 1, 11), + AssertTextEdit("Component5", 1, 14, 1, 24)); } [Fact] @@ -617,16 +606,7 @@ public async Task Handle_Rename_SingleServer_DoesNotDelegateForRazor() IEditMappingService? editMappingService = null, IClientConnection? clientConnection = null) { - using PooledArrayBuilder builder = []; - builder.AddRange(CreateRazorComponentTagHelperDescriptors("First", RootNamespace1, "Component1")); - builder.AddRange(CreateRazorComponentTagHelperDescriptors("First", "Test", "Component2")); - builder.AddRange(CreateRazorComponentTagHelperDescriptors("Second", RootNamespace2, "Component3")); - builder.AddRange(CreateRazorComponentTagHelperDescriptors("Second", RootNamespace2, "Component4")); - builder.AddRange(CreateRazorComponentTagHelperDescriptors("First", "Test", "Component1337")); - builder.AddRange(CreateRazorComponentTagHelperDescriptors("First", "Test.Components", "Directory1")); - builder.AddRange(CreateRazorComponentTagHelperDescriptors("First", "Test.Components", "Directory2")); - var tagHelpers = builder.ToImmutable(); - + var tagHelpers = CreateRazorComponentTagHelpers(); var projectManager = CreateProjectSnapshotManager(); var documentContextFactory = new DocumentContextFactory(projectManager, LoggerFactory); @@ -723,21 +703,36 @@ await projectManager.UpdateAsync(updater => return (endpoint, documentContextFactory); } - private static IEnumerable CreateRazorComponentTagHelperDescriptors(string assemblyName, string namespaceName, string tagName) + private static TagHelperCollection CreateRazorComponentTagHelpers() { - var fullyQualifiedName = $"{namespaceName}.{tagName}"; - var builder = TagHelperDescriptorBuilder.CreateComponent(fullyQualifiedName, assemblyName); - builder.SetTypeName(fullyQualifiedName, namespaceName, tagName); - builder.TagMatchingRule(rule => rule.TagName = tagName); + using var builder = new TagHelperCollection.RefBuilder(); + builder.AddRange(CreateRazorComponentTagHelpersCore("First", RootNamespace1, "Component1")); + builder.AddRange(CreateRazorComponentTagHelpersCore("First", "Test", "Component2")); + builder.AddRange(CreateRazorComponentTagHelpersCore("Second", RootNamespace2, "Component3")); + builder.AddRange(CreateRazorComponentTagHelpersCore("Second", RootNamespace2, "Component4")); + builder.AddRange(CreateRazorComponentTagHelpersCore("First", "Test", "Component1337")); + builder.AddRange(CreateRazorComponentTagHelpersCore("First", "Test.Components", "Directory1")); + builder.AddRange(CreateRazorComponentTagHelpersCore("First", "Test.Components", "Directory2")); + + return builder.ToCollection(); + + static IEnumerable CreateRazorComponentTagHelpersCore( + string assemblyName, string namespaceName, string tagName) + { + var fullyQualifiedName = $"{namespaceName}.{tagName}"; + var builder = TagHelperDescriptorBuilder.CreateComponent(fullyQualifiedName, assemblyName); + builder.SetTypeName(fullyQualifiedName, namespaceName, tagName); + builder.TagMatchingRule(rule => rule.TagName = tagName); - yield return builder.Build(); + yield return builder.Build(); - var fullyQualifiedBuilder = TagHelperDescriptorBuilder.CreateComponent(fullyQualifiedName, assemblyName); - fullyQualifiedBuilder.SetTypeName(fullyQualifiedName, namespaceName, tagName); - fullyQualifiedBuilder.TagMatchingRule(rule => rule.TagName = fullyQualifiedName); - fullyQualifiedBuilder.IsFullyQualifiedNameMatch = true; + var fullyQualifiedBuilder = TagHelperDescriptorBuilder.CreateComponent(fullyQualifiedName, assemblyName); + fullyQualifiedBuilder.SetTypeName(fullyQualifiedName, namespaceName, tagName); + fullyQualifiedBuilder.TagMatchingRule(rule => rule.TagName = fullyQualifiedName); + fullyQualifiedBuilder.IsFullyQualifiedNameMatch = true; - yield return fullyQualifiedBuilder.Build(); + yield return fullyQualifiedBuilder.Build(); + } } private static Action> AssertTextEdit(string fileName, int startLine, int startCharacter, int endLine, int endCharacter) diff --git a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Semantic/SemanticTokensTest.cs b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Semantic/SemanticTokensTest.cs index f5764b61ca7..a28fa8c6117 100644 --- a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Semantic/SemanticTokensTest.cs +++ b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Semantic/SemanticTokensTest.cs @@ -930,7 +930,7 @@ private async Task AssertSemanticTokensAsync( private static DocumentContext CreateDocumentContext( string documentText, bool isRazorFile, - ImmutableArray tagHelpers, + TagHelperCollection tagHelpers, int version) { var document = CreateCodeDocument(documentText, isRazorFile, tagHelpers); diff --git a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/TagHelperFactsServiceTest.cs b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/TagHelperFactsServiceTest.cs index 1c181387342..dfd9cded377 100644 --- a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/TagHelperFactsServiceTest.cs +++ b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/TagHelperFactsServiceTest.cs @@ -4,7 +4,6 @@ #nullable disable using System; -using System.Collections.Immutable; using Microsoft.AspNetCore.Razor.Language; using Microsoft.AspNetCore.Razor.Language.Syntax; using Microsoft.AspNetCore.Razor.LanguageServer.Completion; @@ -20,7 +19,7 @@ public class TagHelperFactsServiceTest(ITestOutputHelper testOutput) : TagHelper public void StringifyAttributes_DirectiveAttribute() { // Arrange - var codeDocument = CreateComponentDocument($"", DefaultTagHelpers); + var codeDocument = CreateComponentDocument($"", [.. DefaultTagHelpers]); var root = codeDocument.GetRequiredSyntaxRoot(); var startTag = (MarkupTagHelperStartTagSyntax)root.FindInnermostNode(3); @@ -41,7 +40,7 @@ public void StringifyAttributes_DirectiveAttribute() public void StringifyAttributes_DirectiveAttributeWithParameter() { // Arrange - var codeDocument = CreateComponentDocument($"", DefaultTagHelpers); + var codeDocument = CreateComponentDocument($"", [.. DefaultTagHelpers]); var root = codeDocument.GetRequiredSyntaxRoot(); var startTag = (MarkupTagHelperStartTagSyntax)root.FindInnermostNode(3); @@ -62,7 +61,7 @@ public void StringifyAttributes_DirectiveAttributeWithParameter() public void StringifyAttributes_MinimizedDirectiveAttribute() { // Arrange - var codeDocument = CreateComponentDocument($"", DefaultTagHelpers); + var codeDocument = CreateComponentDocument($"", [.. DefaultTagHelpers]); var root = codeDocument.GetRequiredSyntaxRoot(); var startTag = (MarkupTagHelperStartTagSyntax)root.FindInnermostNode(3); @@ -83,7 +82,7 @@ public void StringifyAttributes_MinimizedDirectiveAttribute() public void StringifyAttributes_MinimizedDirectiveAttributeWithParameter() { // Arrange - var codeDocument = CreateComponentDocument($"", DefaultTagHelpers); + var codeDocument = CreateComponentDocument($"", [.. DefaultTagHelpers]); var root = codeDocument.GetRequiredSyntaxRoot(); var startTag = (MarkupTagHelperStartTagSyntax)root.FindInnermostNode(3); @@ -238,9 +237,9 @@ public void StringifyAttributes_IgnoresMiscContent() }); } - private static RazorCodeDocument CreateComponentDocument(string text, ImmutableArray tagHelpers) + private static RazorCodeDocument CreateComponentDocument(string text, TagHelperCollection tagHelpers) { - tagHelpers = tagHelpers.NullToEmpty(); + tagHelpers ??= []; var sourceDocument = TestRazorSourceDocument.Create(text); var projectEngine = RazorProjectEngine.Create(builder => { diff --git a/src/Razor/test/Microsoft.AspNetCore.Razor.Test.Common.Tooling/LanguageServer/LanguageServerTestBase.cs b/src/Razor/test/Microsoft.AspNetCore.Razor.Test.Common.Tooling/LanguageServer/LanguageServerTestBase.cs index 2a8a13f2530..ec292c917e5 100644 --- a/src/Razor/test/Microsoft.AspNetCore.Razor.Test.Common.Tooling/LanguageServer/LanguageServerTestBase.cs +++ b/src/Razor/test/Microsoft.AspNetCore.Razor.Test.Common.Tooling/LanguageServer/LanguageServerTestBase.cs @@ -47,16 +47,20 @@ private protected static RazorRequestContext CreateRazorRequestContext( LspServices? lspServices = null) => new(documentContext, lspServices ?? LspServices.Empty, "lsp/method", uri: null); - protected static RazorCodeDocument CreateCodeDocument(string text, ImmutableArray tagHelpers = default, string? filePath = null, string? rootNamespace = null) + protected static RazorCodeDocument CreateCodeDocument( + string text, + TagHelperCollection? tagHelpers = null, + string? filePath = null, + string? rootNamespace = null) { filePath ??= "test.cshtml"; var fileKind = FileKinds.GetFileKindFromPath(filePath); - tagHelpers = tagHelpers.NullToEmpty(); + tagHelpers ??= []; if (fileKind == RazorFileKind.Component) { - tagHelpers = tagHelpers.AddRange(RazorTestResources.BlazorServerAppTagHelpers); + tagHelpers = TagHelperCollection.Merge(tagHelpers, [.. RazorTestResources.BlazorServerAppTagHelpers]); } var sourceDocument = TestRazorSourceDocument.Create(text, filePath: filePath, relativePath: filePath); diff --git a/src/Razor/test/Microsoft.AspNetCore.Razor.Test.Common.Tooling/ProjectSystem/TestDocumentSnapshot.cs b/src/Razor/test/Microsoft.AspNetCore.Razor.Test.Common.Tooling/ProjectSystem/TestDocumentSnapshot.cs index 94dbbff64f7..7ad696ba4e4 100644 --- a/src/Razor/test/Microsoft.AspNetCore.Razor.Test.Common.Tooling/ProjectSystem/TestDocumentSnapshot.cs +++ b/src/Razor/test/Microsoft.AspNetCore.Razor.Test.Common.Tooling/ProjectSystem/TestDocumentSnapshot.cs @@ -42,7 +42,7 @@ public static TestDocumentSnapshot Create(string filePath, string text, ProjectW } public static TestDocumentSnapshot Create(string filePath, RazorCodeDocument codeDocument) - => Create(filePath, codeDocument, ProjectWorkspaceState.Create([.. codeDocument.GetTagHelpers() ?? []])); + => Create(filePath, codeDocument, ProjectWorkspaceState.Create(codeDocument.GetTagHelpers() ?? [])); public static TestDocumentSnapshot Create(string filePath, RazorCodeDocument codeDocument, ProjectWorkspaceState projectWorkspaceState) { diff --git a/src/Razor/test/Microsoft.AspNetCore.Razor.Test.Common.Tooling/ProjectSystem/TestProjectSnapshot.cs b/src/Razor/test/Microsoft.AspNetCore.Razor.Test.Common.Tooling/ProjectSystem/TestProjectSnapshot.cs index d7500551b6c..875cd612fb4 100644 --- a/src/Razor/test/Microsoft.AspNetCore.Razor.Test.Common.Tooling/ProjectSystem/TestProjectSnapshot.cs +++ b/src/Razor/test/Microsoft.AspNetCore.Razor.Test.Common.Tooling/ProjectSystem/TestProjectSnapshot.cs @@ -2,7 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. using System.Collections.Generic; -using System.Collections.Immutable; using System.Diagnostics.CodeAnalysis; using System.Threading; using System.Threading.Tasks; @@ -45,7 +44,7 @@ public static TestProjectSnapshot Create(string filePath, ProjectWorkspaceState? public string DisplayName => RealSnapshot.DisplayName; public LanguageVersion CSharpLanguageVersion => RealSnapshot.CSharpLanguageVersion; - public ValueTask> GetTagHelpersAsync(CancellationToken cancellationToken) + public ValueTask GetTagHelpersAsync(CancellationToken cancellationToken) => RealSnapshot.GetTagHelpersAsync(cancellationToken); public bool ContainsDocument(string filePath) diff --git a/src/Razor/test/Microsoft.AspNetCore.Razor.Test.Common.Tooling/RazorCodeDocumentFactory.cs b/src/Razor/test/Microsoft.AspNetCore.Razor.Test.Common.Tooling/RazorCodeDocumentFactory.cs index 55d7498f907..7d1e3a71bd3 100644 --- a/src/Razor/test/Microsoft.AspNetCore.Razor.Test.Common.Tooling/RazorCodeDocumentFactory.cs +++ b/src/Razor/test/Microsoft.AspNetCore.Razor.Test.Common.Tooling/RazorCodeDocumentFactory.cs @@ -1,7 +1,6 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -using System.Collections.Immutable; using Microsoft.AspNetCore.Mvc.Razor.Extensions; using Microsoft.AspNetCore.Razor.Language; @@ -15,14 +14,14 @@ internal static class RazorCodeDocumentFactory public static string GetFileName(bool isRazorFile) => isRazorFile ? RazorFile : CSHtmlFile; - public static RazorCodeDocument CreateCodeDocument(string text, bool isRazorFile, params ImmutableArray tagHelpers) + public static RazorCodeDocument CreateCodeDocument(string text, bool isRazorFile, params TagHelperCollection tagHelpers) { return CreateCodeDocument(text, GetFileName(isRazorFile), tagHelpers); } - public static RazorCodeDocument CreateCodeDocument(string text, string filePath, params ImmutableArray tagHelpers) + public static RazorCodeDocument CreateCodeDocument(string text, string filePath, params TagHelperCollection tagHelpers) { - tagHelpers = tagHelpers.NullToEmpty(); + tagHelpers ??= []; var sourceDocument = TestRazorSourceDocument.Create(text, filePath: filePath, relativePath: filePath); var projectEngine = RazorProjectEngine.Create(builder => diff --git a/src/Razor/test/Microsoft.AspNetCore.Razor.Test.Common.Tooling/SimpleTagHelpers.cs b/src/Razor/test/Microsoft.AspNetCore.Razor.Test.Common.Tooling/SimpleTagHelpers.cs index 7cf30d8897d..03255601eb5 100644 --- a/src/Razor/test/Microsoft.AspNetCore.Razor.Test.Common.Tooling/SimpleTagHelpers.cs +++ b/src/Razor/test/Microsoft.AspNetCore.Razor.Test.Common.Tooling/SimpleTagHelpers.cs @@ -9,7 +9,7 @@ namespace Microsoft.AspNetCore.Razor.Test.Common; internal static class SimpleTagHelpers { - public static ImmutableArray Default { get; } + public static TagHelperCollection Default { get; } static SimpleTagHelpers() { diff --git a/src/Razor/test/Microsoft.AspNetCore.Razor.Test.Common.Tooling/TestTagHelperResolver.cs b/src/Razor/test/Microsoft.AspNetCore.Razor.Test.Common.Tooling/TestTagHelperResolver.cs index 938aa1e50b8..a53e0ccefdc 100644 --- a/src/Razor/test/Microsoft.AspNetCore.Razor.Test.Common.Tooling/TestTagHelperResolver.cs +++ b/src/Razor/test/Microsoft.AspNetCore.Razor.Test.Common.Tooling/TestTagHelperResolver.cs @@ -1,7 +1,6 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -using System.Collections.Immutable; using System.Threading; using System.Threading.Tasks; using Microsoft.AspNetCore.Razor.Language; @@ -11,11 +10,11 @@ namespace Microsoft.AspNetCore.Razor.Test.Common; -internal class TestTagHelperResolver(ImmutableArray tagHelpers) : ITagHelperResolver +internal class TestTagHelperResolver(TagHelperCollection tagHelpers) : ITagHelperResolver { - public ImmutableArray TagHelpers { get; } = tagHelpers; + public TagHelperCollection TagHelpers { get; } = tagHelpers; - public ValueTask> GetTagHelpersAsync( + public ValueTask GetTagHelpersAsync( Project workspaceProject, ProjectSnapshot projectSnapshot, CancellationToken cancellationToken) diff --git a/src/Razor/test/Microsoft.CodeAnalysis.Razor.Workspaces.Test/Completion/DefaultRazorCompletionFactsServiceTest.cs b/src/Razor/test/Microsoft.CodeAnalysis.Razor.Workspaces.Test/Completion/DefaultRazorCompletionFactsServiceTest.cs index 883f42a2227..a15a17460c2 100644 --- a/src/Razor/test/Microsoft.CodeAnalysis.Razor.Workspaces.Test/Completion/DefaultRazorCompletionFactsServiceTest.cs +++ b/src/Razor/test/Microsoft.CodeAnalysis.Razor.Workspaces.Test/Completion/DefaultRazorCompletionFactsServiceTest.cs @@ -18,7 +18,7 @@ public void GetDirectiveCompletionItems_AllProvidersCompletionItems() var sourceDocument = RazorSourceDocument.Create("", RazorSourceDocumentProperties.Default); var codeDocument = RazorCodeDocument.Create(sourceDocument); var syntaxTree = RazorSyntaxTree.Parse(TestRazorSourceDocument.Create()); - var tagHelperDocumentContext = TagHelperDocumentContext.Create(prefix: null, tagHelpers: []); + var tagHelperDocumentContext = TagHelperDocumentContext.Create(tagHelpers: []); var completionItem1 = RazorCompletionItem.CreateDirective( displayText: "displayText1", diff --git a/src/Razor/test/Microsoft.CodeAnalysis.Razor.Workspaces.Test/Completion/DirectiveAttributeCompletionItemProviderTest.AttributeNames.cs b/src/Razor/test/Microsoft.CodeAnalysis.Razor.Workspaces.Test/Completion/DirectiveAttributeCompletionItemProviderTest.AttributeNames.cs index 43879cbf064..c9c19ab7f63 100644 --- a/src/Razor/test/Microsoft.CodeAnalysis.Razor.Workspaces.Test/Completion/DirectiveAttributeCompletionItemProviderTest.AttributeNames.cs +++ b/src/Razor/test/Microsoft.CodeAnalysis.Razor.Workspaces.Test/Completion/DirectiveAttributeCompletionItemProviderTest.AttributeNames.cs @@ -180,7 +180,7 @@ public void GetCompletionItems_ExistingAttribute_Partial_ReturnsEmptyCollection( public void GetAttributeCompletions_NoDescriptorsForTag_ReturnsEmptyCollection() { // Arrange - var documentContext = TagHelperDocumentContext.Create(string.Empty, tagHelpers: []); + var documentContext = TagHelperDocumentContext.Create(tagHelpers: []); var context = GetDefaultDirectivateAttributeCompletionContext("@bin"); // Act @@ -197,7 +197,7 @@ public void GetAttributeCompletions_NoDirectiveAttributesForTag_ReturnsEmptyColl var descriptor = TagHelperDescriptorBuilder.CreateTagHelper("CatchAll", "TestAssembly"); descriptor.BoundAttributeDescriptor(boundAttribute => boundAttribute.Name = "Test"); descriptor.TagMatchingRule(rule => rule.RequireTagName("*")); - var documentContext = TagHelperDocumentContext.Create(string.Empty, [descriptor.Build()]); + var documentContext = TagHelperDocumentContext.Create([descriptor.Build()]); var context = GetDefaultDirectivateAttributeCompletionContext("@bin"); diff --git a/src/Razor/test/Microsoft.CodeAnalysis.Razor.Workspaces.Test/Completion/DirectiveAttributeCompletionItemProviderTest.ParameterNames.cs b/src/Razor/test/Microsoft.CodeAnalysis.Razor.Workspaces.Test/Completion/DirectiveAttributeCompletionItemProviderTest.ParameterNames.cs index 2fb2929d4a2..2b33d2197a8 100644 --- a/src/Razor/test/Microsoft.CodeAnalysis.Razor.Workspaces.Test/Completion/DirectiveAttributeCompletionItemProviderTest.ParameterNames.cs +++ b/src/Razor/test/Microsoft.CodeAnalysis.Razor.Workspaces.Test/Completion/DirectiveAttributeCompletionItemProviderTest.ParameterNames.cs @@ -35,7 +35,7 @@ public void GetCompletionItems_OnDirectiveAttributeParameter_ReturnsCompletions( public void GetAttributeParameterCompletions_NoDescriptorsForTag_ReturnsEmptyCollection() { // Arrange - var documentContext = TagHelperDocumentContext.Create(string.Empty, tagHelpers: []); + var documentContext = TagHelperDocumentContext.Create(tagHelpers: []); var context = GetDefaultDirectiveAttributeCompletionContext("@bin"); // Act @@ -52,7 +52,7 @@ public void GetAttributeParameterCompletions_NoDirectiveAttributesForTag_Returns var descriptor = TagHelperDescriptorBuilder.CreateTagHelper("CatchAll", "TestAssembly"); descriptor.BoundAttributeDescriptor(boundAttribute => boundAttribute.Name = "Test"); descriptor.TagMatchingRule(rule => rule.RequireTagName("*")); - var documentContext = TagHelperDocumentContext.Create(string.Empty, [descriptor.Build()]); + var documentContext = TagHelperDocumentContext.Create([descriptor.Build()]); var context = GetDefaultDirectiveAttributeCompletionContext("@bin"); diff --git a/src/Razor/test/Microsoft.CodeAnalysis.Razor.Workspaces.Test/Completion/DirectiveAttributeTransitionCompletionItemProviderTest.cs b/src/Razor/test/Microsoft.CodeAnalysis.Razor.Workspaces.Test/Completion/DirectiveAttributeTransitionCompletionItemProviderTest.cs index e0359be2311..d2f8a1e50fd 100644 --- a/src/Razor/test/Microsoft.CodeAnalysis.Razor.Workspaces.Test/Completion/DirectiveAttributeTransitionCompletionItemProviderTest.cs +++ b/src/Razor/test/Microsoft.CodeAnalysis.Razor.Workspaces.Test/Completion/DirectiveAttributeTransitionCompletionItemProviderTest.cs @@ -13,8 +13,8 @@ namespace Microsoft.CodeAnalysis.Razor.Completion; public class DirectiveAttributeTransitionCompletionItemProviderTest(ITestOutputHelper testOutput) : ToolingTestBase(testOutput) { - private readonly TagHelperDocumentContext _tagHelperDocumentContext = TagHelperDocumentContext.Create(prefix: string.Empty, tagHelpers: []); - private readonly DirectiveAttributeTransitionCompletionItemProvider _provider = new DirectiveAttributeTransitionCompletionItemProvider(TestLanguageServerFeatureOptions.Instance); + private readonly TagHelperDocumentContext _tagHelperDocumentContext = TagHelperDocumentContext.Create(tagHelpers: []); + private readonly DirectiveAttributeTransitionCompletionItemProvider _provider = new(TestLanguageServerFeatureOptions.Instance); [Fact] public void IsValidCompletionPoint_AtPrefixLeadingEdge_ReturnsFalse() diff --git a/src/Razor/test/Microsoft.CodeAnalysis.Razor.Workspaces.Test/Completion/DirectiveCompletionItemProviderTest.cs b/src/Razor/test/Microsoft.CodeAnalysis.Razor.Workspaces.Test/Completion/DirectiveCompletionItemProviderTest.cs index f2d885e2254..95d143fae44 100644 --- a/src/Razor/test/Microsoft.CodeAnalysis.Razor.Workspaces.Test/Completion/DirectiveCompletionItemProviderTest.cs +++ b/src/Razor/test/Microsoft.CodeAnalysis.Razor.Workspaces.Test/Completion/DirectiveCompletionItemProviderTest.cs @@ -425,7 +425,7 @@ private static RazorCompletionContext CreateRazorCompletionContext(TestCode text var sourceDocument = RazorSourceDocument.Create("", RazorSourceDocumentProperties.Default); var codeDocument = RazorCodeDocument.Create(sourceDocument); - var tagHelperDocumentContext = TagHelperDocumentContext.Create(prefix: string.Empty, tagHelpers: []); + var tagHelperDocumentContext = TagHelperDocumentContext.Create(tagHelpers: []); var owner = syntaxTree.Root.FindInnermostNode(absoluteIndex); owner = AbstractRazorCompletionFactsService.AdjustSyntaxNodeForWordBoundary(owner, absoluteIndex); return new RazorCompletionContext(codeDocument, absoluteIndex, owner, syntaxTree, tagHelperDocumentContext, reason); diff --git a/src/Razor/test/Microsoft.CodeAnalysis.Razor.Workspaces.Test/Completion/LanguageServerTagHelperCompletionServiceTest.cs b/src/Razor/test/Microsoft.CodeAnalysis.Razor.Workspaces.Test/Completion/LanguageServerTagHelperCompletionServiceTest.cs index 7eb8040c709..f9cb0a48de3 100644 --- a/src/Razor/test/Microsoft.CodeAnalysis.Razor.Workspaces.Test/Completion/LanguageServerTagHelperCompletionServiceTest.cs +++ b/src/Razor/test/Microsoft.CodeAnalysis.Razor.Workspaces.Test/Completion/LanguageServerTagHelperCompletionServiceTest.cs @@ -3,7 +3,6 @@ using System.Collections.Generic; using System.Collections.Immutable; -using System.Linq; using Microsoft.AspNetCore.Razor.Language; using Microsoft.AspNetCore.Razor.Test.Common; using Xunit; @@ -17,12 +16,10 @@ public class LanguageServerTagHelperCompletionServiceTest(ITestOutputHelper test [WorkItem("https://devdiv.visualstudio.com/DevDiv/_workitems/edit/1452432")] public void GetAttributeCompletions_OnlyIndexerNamePrefix() { - // Arrange - ImmutableArray documentDescriptors = + TagHelperCollection tagHelpers = [ TagHelperDescriptorBuilder.CreateTagHelper("FormTagHelper", "TestAssembly") - .TagMatchingRuleDescriptor(rule => rule - .RequireTagName("form")) + .TagMatchingRule(tagName: "form") .BoundAttributeDescriptor(attribute => attribute .TypeName("System.Collections.Generic.IDictionary") .PropertyName("RouteValues") @@ -32,32 +29,29 @@ public void GetAttributeCompletions_OnlyIndexerNamePrefix() var expectedCompletions = AttributeCompletionResult.Create(new() { - ["asp-route-..."] = [documentDescriptors[0].BoundAttributes.Last()] + ["asp-route-..."] = [tagHelpers[0].BoundAttributes[^1]] }); var completionContext = BuildAttributeCompletionContext( - documentDescriptors, + tagHelpers, existingCompletions: [], attributes: [], currentTagName: "form"); + var service = CreateTagHelperCompletionFactsService(); - // Act var completions = service.GetAttributeCompletions(completionContext); - // Assert AssertCompletionsAreEquivalent(expectedCompletions, completions); } [Fact] public void GetAttributeCompletions_BoundDictionaryAttribute_ReturnsPrefixIndexerAndFullSetter() { - // Arrange - ImmutableArray documentDescriptors = + TagHelperCollection tagHelpers = [ TagHelperDescriptorBuilder.CreateTagHelper("FormTagHelper", "TestAssembly") - .TagMatchingRuleDescriptor(rule => rule - .RequireTagName("form")) + .TagMatchingRule(tagName: "form") .BoundAttributeDescriptor(attribute => attribute .Name("asp-all-route-data") .TypeName("System.Collections.Generic.IDictionary") @@ -68,41 +62,33 @@ public void GetAttributeCompletions_BoundDictionaryAttribute_ReturnsPrefixIndexe var expectedCompletions = AttributeCompletionResult.Create(new() { - ["asp-all-route-data"] = [documentDescriptors[0].BoundAttributes.Last()], - ["asp-route-..."] = [documentDescriptors[0].BoundAttributes.Last()] + ["asp-all-route-data"] = [tagHelpers[0].BoundAttributes[^1]], + ["asp-route-..."] = [tagHelpers[0].BoundAttributes[^1]] }); var completionContext = BuildAttributeCompletionContext( - documentDescriptors, + tagHelpers, existingCompletions: [], attributes: [], currentTagName: "form"); + var service = CreateTagHelperCompletionFactsService(); - // Act var completions = service.GetAttributeCompletions(completionContext); - // Assert AssertCompletionsAreEquivalent(expectedCompletions, completions); } [Fact] public void GetAttributeCompletions_RequiredBoundDictionaryAttribute_ReturnsPrefixIndexerAndFullSetter() { - // Arrange - ImmutableArray documentDescriptors = + TagHelperCollection tagHelpers = [ TagHelperDescriptorBuilder.CreateTagHelper("FormTagHelper", "TestAssembly") - .TagMatchingRuleDescriptor(rule => rule - .RequireTagName("form") - .RequireAttributeDescriptor(builder => - { - builder.Name = "asp-route-"; - builder.NameComparison = RequiredAttributeNameComparison.PrefixMatch; - })) - .TagMatchingRuleDescriptor(rule => rule - .RequireTagName("form") - .RequireAttributeDescriptor(builder => builder.Name = "asp-all-route-data")) + .TagMatchingRule(tagName: "form", static b => b + .RequiredAttribute(name: "asp-route-", nameComparison: RequiredAttributeNameComparison.PrefixMatch)) + .TagMatchingRule(tagName: "form", static b => b + .RequiredAttribute(name: "asp-all-route-data")) .BoundAttributeDescriptor(attribute => attribute .Name("asp-all-route-data") .TypeName("System.Collections.Generic.IDictionary") @@ -113,102 +99,84 @@ public void GetAttributeCompletions_RequiredBoundDictionaryAttribute_ReturnsPref var expectedCompletions = AttributeCompletionResult.Create(new() { - ["asp-all-route-data"] = [documentDescriptors[0].BoundAttributes.Last()], - ["asp-route-..."] = [documentDescriptors[0].BoundAttributes.Last()] + ["asp-all-route-data"] = [tagHelpers[0].BoundAttributes[^1]], + ["asp-route-..."] = [tagHelpers[0].BoundAttributes[^1]] }); var completionContext = BuildAttributeCompletionContext( - documentDescriptors, + tagHelpers, existingCompletions: [], attributes: [], currentTagName: "form"); + var service = CreateTagHelperCompletionFactsService(); - // Act var completions = service.GetAttributeCompletions(completionContext); - // Assert AssertCompletionsAreEquivalent(expectedCompletions, completions); } [Fact] public void GetAttributeCompletions_DoesNotReturnCompletionsForAlreadySuppliedAttributes() { - // Arrange - ImmutableArray documentDescriptors = + TagHelperCollection tagHelpers = [ TagHelperDescriptorBuilder.CreateTagHelper("DivTagHelper", "TestAssembly") - .TagMatchingRuleDescriptor(rule => rule - .RequireTagName("div") - .RequireAttributeDescriptor(attribute => attribute.Name("repeat"))) - .BoundAttributeDescriptor(attribute => attribute - .Name("visible") - .TypeName(typeof(bool).FullName) - .PropertyName("Visible")) + .TagMatchingRule(tagName: "div", static b => b + .RequiredAttribute(name: "repeat")) + .BoundAttribute(name: "visible", propertyName: "Visible") .Build(), TagHelperDescriptorBuilder.CreateTagHelper("StyleTagHelper", "TestAssembly") - .TagMatchingRuleDescriptor(rule => rule.RequireTagName("*")) - .BoundAttributeDescriptor(attribute => attribute - .Name("class") - .TypeName(typeof(string).FullName) - .PropertyName("Class")) + .TagMatchingRule(tagName: "*") + .BoundAttribute(name: "class", propertyName: "Class") .Build(), ]; var expectedCompletions = AttributeCompletionResult.Create(new() { ["onclick"] = [], - ["visible"] = [documentDescriptors[0].BoundAttributes.Last()] + ["visible"] = [tagHelpers[0].BoundAttributes[^1]] }); var completionContext = BuildAttributeCompletionContext( - documentDescriptors, + tagHelpers, existingCompletions: ["onclick"], attributes: [ KeyValuePair.Create("class", "something"), KeyValuePair.Create("repeat", "4")], currentTagName: "div"); + var service = CreateTagHelperCompletionFactsService(); - // Act var completions = service.GetAttributeCompletions(completionContext); - // Assert AssertCompletionsAreEquivalent(expectedCompletions, completions); } [Fact] public void GetAttributeCompletions_ReturnsCompletionForAlreadySuppliedAttribute_IfCurrentAttributeMatches() { - // Arrange - ImmutableArray documentDescriptors = + TagHelperCollection tagHelpers = [ TagHelperDescriptorBuilder.CreateTagHelper("DivTagHelper", "TestAssembly") - .TagMatchingRuleDescriptor(rule => rule - .RequireTagName("div") - .RequireAttributeDescriptor(attribute => attribute.Name("repeat"))) - .BoundAttributeDescriptor(attribute => attribute - .Name("visible") - .TypeName(typeof(bool).FullName) - .PropertyName("Visible")) + .TagMatchingRule(tagName: "div", static b => b + .RequiredAttribute(name: "repeat")) + .BoundAttribute(name: "visible", propertyName: "Visible") .Build(), TagHelperDescriptorBuilder.CreateTagHelper("StyleTagHelper", "TestAssembly") - .TagMatchingRuleDescriptor(rule => rule.RequireTagName("*")) - .BoundAttributeDescriptor(attribute => attribute - .Name("class") - .TypeName(typeof(string).FullName) - .PropertyName("Class")) + .TagMatchingRule(tagName: "*") + .BoundAttribute(name: "class", propertyName: "Class") .Build(), ]; var expectedCompletions = AttributeCompletionResult.Create(new() { ["onclick"] = [], - ["visible"] = [documentDescriptors[0].BoundAttributes.Last()] + ["visible"] = [tagHelpers[0].BoundAttributes[^1]] }); var completionContext = BuildAttributeCompletionContext( - documentDescriptors, + tagHelpers, existingCompletions: ["onclick"], attributes: [ KeyValuePair.Create("class", "something"), @@ -216,36 +184,27 @@ public void GetAttributeCompletions_ReturnsCompletionForAlreadySuppliedAttribute KeyValuePair.Create("visible", "false")], currentTagName: "div", currentAttributeName: "visible"); + var service = CreateTagHelperCompletionFactsService(); - // Act var completions = service.GetAttributeCompletions(completionContext); - // Assert AssertCompletionsAreEquivalent(expectedCompletions, completions); } [Fact] public void GetAttributeCompletions_DoesNotReturnAlreadySuppliedAttribute_IfCurrentAttributeDoesNotMatch() { - // Arrange - ImmutableArray documentDescriptors = + TagHelperCollection tagHelpers = [ TagHelperDescriptorBuilder.CreateTagHelper("DivTagHelper", "TestAssembly") - .TagMatchingRuleDescriptor(rule => rule - .RequireTagName("div") - .RequireAttributeDescriptor(attribute => attribute.Name("repeat"))) - .BoundAttributeDescriptor(attribute => attribute - .Name("visible") - .TypeName(typeof(bool).FullName) - .PropertyName("Visible")) + .TagMatchingRule(tagName: "div", static b => b + .RequiredAttribute(name: "repeat")) + .BoundAttribute(name: "visible", propertyName: "Visible") .Build(), TagHelperDescriptorBuilder.CreateTagHelper("StyleTagHelper", "TestAssembly") - .TagMatchingRuleDescriptor(rule => rule.RequireTagName("*")) - .BoundAttributeDescriptor(attribute => attribute - .Name("class") - .TypeName(typeof(string).FullName) - .PropertyName("Class")) + .TagMatchingRule(tagName: "*") + .BoundAttribute(name: "class", propertyName: "Class") .Build(), ]; @@ -255,7 +214,7 @@ public void GetAttributeCompletions_DoesNotReturnAlreadySuppliedAttribute_IfCurr }); var completionContext = BuildAttributeCompletionContext( - documentDescriptors, + tagHelpers, existingCompletions: ["onclick"], attributes: [ KeyValuePair.Create("class", "something"), @@ -263,30 +222,26 @@ public void GetAttributeCompletions_DoesNotReturnAlreadySuppliedAttribute_IfCurr KeyValuePair.Create("visible", "false")], currentTagName: "div", currentAttributeName: "repeat"); + var service = CreateTagHelperCompletionFactsService(); - // Act var completions = service.GetAttributeCompletions(completionContext); - // Assert AssertCompletionsAreEquivalent(expectedCompletions, completions); } [Fact] public void GetAttributeCompletions_PossibleDescriptorsReturnUnboundRequiredAttributesWithExistingCompletions() { - // Arrange - ImmutableArray documentDescriptors = + TagHelperCollection tagHelpers = [ TagHelperDescriptorBuilder.CreateTagHelper("DivTagHelper", "TestAssembly") - .TagMatchingRuleDescriptor(rule => rule - .RequireTagName("div") - .RequireAttributeDescriptor(attribute => attribute.Name("repeat"))) + .TagMatchingRule(tagName: "div", static b => b + .RequiredAttribute(name: "repeat")) .Build(), TagHelperDescriptorBuilder.CreateTagHelper("StyleTagHelper", "TestAssembly") - .TagMatchingRuleDescriptor(rule => rule - .RequireTagName("*") - .RequireAttributeDescriptor(attribute => attribute.Name("class"))) + .TagMatchingRule(tagName: "*", static b => b + .RequiredAttribute(name: "class")) .Build(), ]; @@ -298,136 +253,104 @@ public void GetAttributeCompletions_PossibleDescriptorsReturnUnboundRequiredAttr }); var completionContext = BuildAttributeCompletionContext( - documentDescriptors, + tagHelpers, existingCompletions: ["onclick", "class"], currentTagName: "div"); + var service = CreateTagHelperCompletionFactsService(); - // Act var completions = service.GetAttributeCompletions(completionContext); - // Assert AssertCompletionsAreEquivalent(expectedCompletions, completions); } [Fact] public void GetAttributeCompletions_PossibleDescriptorsReturnBoundRequiredAttributesWithExistingCompletions() { - // Arrange - ImmutableArray documentDescriptors = + TagHelperCollection tagHelpers = [ TagHelperDescriptorBuilder.CreateTagHelper("DivTagHelper", "TestAssembly") - .TagMatchingRuleDescriptor(rule => rule - .RequireTagName("div") - .RequireAttributeDescriptor(attribute => attribute.Name("repeat"))) - .BoundAttributeDescriptor(attribute => attribute - .Name("repeat") - .TypeName(typeof(bool).FullName) - .PropertyName("Repeat")) - .BoundAttributeDescriptor(attribute => attribute - .Name("visible") - .TypeName(typeof(bool).FullName) - .PropertyName("Visible")) + .TagMatchingRule(tagName: "div", static b => b + .RequiredAttribute(name: "repeat")) + .BoundAttribute(name: "repeat", propertyName: "Repeat") + .BoundAttribute(name: "visible", propertyName: "Visible") .Build(), TagHelperDescriptorBuilder.CreateTagHelper("StyleTagHelper", "TestAssembly") - .TagMatchingRuleDescriptor(rule => rule - .RequireTagName("*") - .RequireAttributeDescriptor(attribute => attribute.Name("class"))) - .BoundAttributeDescriptor(attribute => attribute - .Name("class") - .TypeName(typeof(string).FullName) - .PropertyName("Class")) + .TagMatchingRule(tagName: "*", static b => b + .RequiredAttribute(name: "class")) + .BoundAttribute(name: "class", propertyName: "Class") .Build(), ]; var expectedCompletions = AttributeCompletionResult.Create(new() { - ["class"] = [.. documentDescriptors[1].BoundAttributes], + ["class"] = [.. tagHelpers[1].BoundAttributes], ["onclick"] = [], - ["repeat"] = [documentDescriptors[0].BoundAttributes.First()] + ["repeat"] = [tagHelpers[0].BoundAttributes[0]] }); var completionContext = BuildAttributeCompletionContext( - documentDescriptors, + tagHelpers, existingCompletions: ["onclick"], currentTagName: "div"); + var service = CreateTagHelperCompletionFactsService(); - // Act var completions = service.GetAttributeCompletions(completionContext); - // Assert AssertCompletionsAreEquivalent(expectedCompletions, completions); } [Fact] public void GetAttributeCompletions_AppliedDescriptorsReturnAllBoundAttributesWithExistingCompletionsForSchemaTags() { - // Arrange - ImmutableArray documentDescriptors = + TagHelperCollection tagHelpers = [ TagHelperDescriptorBuilder.CreateTagHelper("DivTagHelper", "TestAssembly") - .TagMatchingRuleDescriptor(rule => rule.RequireTagName("div")) - .BoundAttributeDescriptor(attribute => attribute - .Name("repeat") - .TypeName(typeof(bool).FullName) - .PropertyName("Repeat")) - .BoundAttributeDescriptor(attribute => attribute - .Name("visible") - .TypeName(typeof(bool).FullName) - .PropertyName("Visible")) + .TagMatchingRule(tagName: "div", static b => b + .RequiredAttribute(name: "repeat")) + .BoundAttribute(name: "repeat", propertyName: "Repeat") + .BoundAttribute(name: "visible", propertyName: "Visible") .Build(), TagHelperDescriptorBuilder.CreateTagHelper("StyleTagHelper", "TestAssembly") - .TagMatchingRuleDescriptor(rule => rule - .RequireTagName("*") - .RequireAttributeDescriptor(attribute => attribute.Name("class"))) - .BoundAttributeDescriptor(attribute => attribute - .Name("class") - .TypeName(typeof(string).FullName) - .PropertyName("Class")) + .TagMatchingRule(tagName: "*", static b => b + .RequiredAttribute(name: "class")) + .BoundAttribute(name: "class", propertyName: "Class") .Build(), TagHelperDescriptorBuilder.CreateTagHelper("StyleTagHelper", "TestAssembly") - .TagMatchingRuleDescriptor(rule => rule.RequireTagName("*")) - .BoundAttributeDescriptor(attribute => attribute - .Name("visible") - .TypeName(typeof(bool).FullName) - .PropertyName("Visible")) + .TagMatchingRule(tagName: "*") + .BoundAttribute(name: "visible", propertyName: "Visible") .Build(), ]; var expectedCompletions = AttributeCompletionResult.Create(new() { ["onclick"] = [], - ["class"] = [.. documentDescriptors[1].BoundAttributes], - ["repeat"] = [documentDescriptors[0].BoundAttributes.First()], - ["visible"] = [documentDescriptors[0].BoundAttributes.Last(), documentDescriptors[2].BoundAttributes.First()] + ["class"] = [.. tagHelpers[1].BoundAttributes], + ["repeat"] = [tagHelpers[0].BoundAttributes[0]], + ["visible"] = [tagHelpers[0].BoundAttributes[^1], tagHelpers[2].BoundAttributes[0]] }); var completionContext = BuildAttributeCompletionContext( - documentDescriptors, + tagHelpers, existingCompletions: ["class", "onclick"], currentTagName: "div"); + var service = CreateTagHelperCompletionFactsService(); - // Act var completions = service.GetAttributeCompletions(completionContext); - // Assert AssertCompletionsAreEquivalent(expectedCompletions, completions); } [Fact] public void GetAttributeCompletions_AppliedTagOutputHintDescriptorsReturnBoundAttributesWithExistingCompletionsForNonSchemaTags() { - // Arrange - ImmutableArray documentDescriptors = + TagHelperCollection tagHelpers = [ TagHelperDescriptorBuilder.CreateTagHelper("CustomTagHelper", "TestAssembly") - .TagMatchingRuleDescriptor(rule => rule.RequireTagName("custom")) - .BoundAttributeDescriptor(attribute => attribute - .Name("repeat") - .TypeName(typeof(bool).FullName) - .PropertyName("Repeat")) + .TagMatchingRule(tagName: "custom") + .BoundAttribute(name: "repeat", propertyName: "Repeat") .TagOutputHint("div") .Build(), ]; @@ -435,52 +358,46 @@ public void GetAttributeCompletions_AppliedTagOutputHintDescriptorsReturnBoundAt var expectedCompletions = AttributeCompletionResult.Create(new() { ["class"] = [], - ["repeat"] = [.. documentDescriptors[0].BoundAttributes] + ["repeat"] = [.. tagHelpers[0].BoundAttributes] }); var completionContext = BuildAttributeCompletionContext( - documentDescriptors, + tagHelpers, existingCompletions: ["class"], currentTagName: "custom"); + var service = CreateTagHelperCompletionFactsService(); - // Act var completions = service.GetAttributeCompletions(completionContext); - // Assert AssertCompletionsAreEquivalent(expectedCompletions, completions); } [Fact] public void GetAttributeCompletions_AppliedDescriptorsReturnBoundAttributesCompletionsForNonSchemaTags() { - // Arrange - ImmutableArray documentDescriptors = + TagHelperCollection tagHelpers = [ TagHelperDescriptorBuilder.CreateTagHelper("CustomTagHelper", "TestAssembly") - .TagMatchingRuleDescriptor(rule => rule.RequireTagName("custom")) - .BoundAttributeDescriptor(attribute => attribute - .Name("repeat") - .TypeName(typeof(bool).FullName) - .PropertyName("Repeat")) + .TagMatchingRule(tagName: "custom") + .BoundAttribute(name: "repeat", propertyName: "Repeat") .Build(), ]; var expectedCompletions = AttributeCompletionResult.Create(new() { - ["repeat"] = [.. documentDescriptors[0].BoundAttributes] + ["repeat"] = [.. tagHelpers[0].BoundAttributes] }); var completionContext = BuildAttributeCompletionContext( - documentDescriptors, + tagHelpers, existingCompletions: ["class"], currentTagName: "custom"); + var service = CreateTagHelperCompletionFactsService(); - // Act var completions = service.GetAttributeCompletions(completionContext); - // Assert AssertCompletionsAreEquivalent(expectedCompletions, completions); } @@ -488,129 +405,116 @@ public void GetAttributeCompletions_AppliedDescriptorsReturnBoundAttributesCompl public void GetAttributeCompletions_AppliedDescriptorsReturnBoundAttributesWithExistingCompletionsForSchemaTags() { // Arrange - ImmutableArray documentDescriptors = + TagHelperCollection tagHelpers = [ TagHelperDescriptorBuilder.CreateTagHelper("DivTagHelper", "TestAssembly") - .TagMatchingRuleDescriptor(rule => rule.RequireTagName("div")) - .BoundAttributeDescriptor(attribute => attribute - .Name("repeat") - .TypeName(typeof(bool).FullName) - .PropertyName("Repeat")) + .TagMatchingRule(tagName: "div") + .BoundAttribute(name: "repeat", propertyName: "Repeat") .Build(), ]; var expectedCompletions = AttributeCompletionResult.Create(new() { ["class"] = [], - ["repeat"] = [.. documentDescriptors[0].BoundAttributes] + ["repeat"] = [.. tagHelpers[0].BoundAttributes] }); var completionContext = BuildAttributeCompletionContext( - documentDescriptors, + tagHelpers, existingCompletions: ["class"], currentTagName: "div"); + var service = CreateTagHelperCompletionFactsService(); - // Act var completions = service.GetAttributeCompletions(completionContext); - // Assert AssertCompletionsAreEquivalent(expectedCompletions, completions); } [Fact] public void GetAttributeCompletions_NoDescriptorsReturnsExistingCompletions() { - // Arrange var expectedCompletions = AttributeCompletionResult.Create(new() { - ["class"] = [], + ["class"] = [] }); var completionContext = BuildAttributeCompletionContext( - descriptors: [], + tagHelpers: [], existingCompletions: ["class"], currentTagName: "div"); + var service = CreateTagHelperCompletionFactsService(); - // Act var completions = service.GetAttributeCompletions(completionContext); - // Assert AssertCompletionsAreEquivalent(expectedCompletions, completions); } [Fact] public void GetAttributeCompletions_NoDescriptorsForUnprefixedTagReturnsExistingCompletions() { - // Arrange - ImmutableArray documentDescriptors = + TagHelperCollection tagHelpers = [ TagHelperDescriptorBuilder.CreateTagHelper("DivTagHelper", "TestAssembly") - .TagMatchingRuleDescriptor(rule => rule - .RequireTagName("div") - .RequireAttributeDescriptor(attribute => attribute.Name("special"))) + .TagMatchingRule(tagName: "div", static b => b + .RequiredAttribute("special")) .Build(), ]; var expectedCompletions = AttributeCompletionResult.Create(new() { - ["class"] = [], + ["class"] = [] }); var completionContext = BuildAttributeCompletionContext( - documentDescriptors, + tagHelpers, existingCompletions: ["class"], currentTagName: "div", tagHelperPrefix: "th:"); + var service = CreateTagHelperCompletionFactsService(); - // Act var completions = service.GetAttributeCompletions(completionContext); - // Assert AssertCompletionsAreEquivalent(expectedCompletions, completions); } [Fact] public void GetAttributeCompletions_NoDescriptorsForTagReturnsExistingCompletions() { - // Arrange - ImmutableArray documentDescriptors = + TagHelperCollection tagHelpers = [ TagHelperDescriptorBuilder.CreateTagHelper("MyTableTagHelper", "TestAssembly") - .TagMatchingRuleDescriptor(rule => rule - .RequireTagName("table") - .RequireAttributeDescriptor(attribute => attribute.Name("special"))) + .TagMatchingRule(tagName: "table", static b => b + .RequiredAttribute("special")) .Build(), ]; var expectedCompletions = AttributeCompletionResult.Create(new() { - ["class"] = [], + ["class"] = [] }); var completionContext = BuildAttributeCompletionContext( - documentDescriptors, + tagHelpers, existingCompletions: ["class"], currentTagName: "div"); + var service = CreateTagHelperCompletionFactsService(); - // Act var completions = service.GetAttributeCompletions(completionContext); - // Assert AssertCompletionsAreEquivalent(expectedCompletions, completions); } [Fact] public void GetElementCompletions_IgnoresDirectiveAttributes() { - // Arrange - ImmutableArray documentDescriptors = + TagHelperCollection tagHelpers = [ TagHelperDescriptorBuilder.CreateTagHelper("BindAttribute", "TestAssembly") - .TagMatchingRuleDescriptor(rule => rule.RequireTagName("input")) + .TagMatchingRule(tagName: "input") .BoundAttributeDescriptor(builder => { builder.Name = "@bind"; @@ -623,536 +527,514 @@ public void GetElementCompletions_IgnoresDirectiveAttributes() var expectedCompletions = ElementCompletionResult.Create([]); var completionContext = BuildElementCompletionContext( - documentDescriptors, + tagHelpers, existingCompletions: ["table"], containingTagName: "body", - containingParentTagName: null!); + containingParentTagName: null); + var service = CreateTagHelperCompletionFactsService(); - // Act var completions = service.GetElementCompletions(completionContext); - // Assert AssertCompletionsAreEquivalent(expectedCompletions, completions); } [Fact] public void GetElementCompletions_FiltersFullyQualifiedElementsIfShortNameExists() { - // Arrange - ImmutableArray documentDescriptors = + TagHelperCollection tagHelpers = [ TagHelperDescriptorBuilder.CreateTagHelper("TestTagHelper", "TestAssembly") - .TagMatchingRuleDescriptor(rule => rule.RequireTagName("Test")) + .TagMatchingRule(tagName: "Test") .Build(), TagHelperDescriptorBuilder.CreateTagHelper("TestTagHelper", "TestAssembly") - .TagMatchingRuleDescriptor(rule => rule.RequireTagName("TestAssembly.Test")) + .TagMatchingRule(tagName: "TestAssembly.Test") .IsFullyQualifiedNameMatch(true) .Build(), TagHelperDescriptorBuilder.CreateTagHelper("Test2TagHelper", "TestAssembly") - .TagMatchingRuleDescriptor(rule => rule.RequireTagName("Test2Assembly.Test")) + .TagMatchingRule(tagName: "Test2Assembly.Test") .IsFullyQualifiedNameMatch(true) .Build(), ]; var expectedCompletions = ElementCompletionResult.Create(new() { - ["Test"] = [documentDescriptors[0]], - ["Test2Assembly.Test"] = [documentDescriptors[2]], + ["Test"] = [tagHelpers[0]], + ["Test2Assembly.Test"] = [tagHelpers[2]] }); var completionContext = BuildElementCompletionContext( - documentDescriptors, + tagHelpers, existingCompletions: [], containingTagName: "body", - containingParentTagName: null!); + containingParentTagName: null); + var service = CreateTagHelperCompletionFactsService(); - // Act var completions = service.GetElementCompletions(completionContext); - // Assert AssertCompletionsAreEquivalent(expectedCompletions, completions); } [Fact] public void GetElementCompletions_TagOutputHintDoesNotFallThroughToSchemaCheck() { - // Arrange - ImmutableArray documentDescriptors = + TagHelperCollection tagHelpers = [ TagHelperDescriptorBuilder.CreateTagHelper("MyTableTagHelper", "TestAssembly") - .TagMatchingRuleDescriptor(rule => rule.RequireTagName("my-table")) + .TagMatchingRule(tagName: "my-table") .TagOutputHint("table") .Build(), TagHelperDescriptorBuilder.CreateTagHelper("MyTrTagHelper", "TestAssembly") - .TagMatchingRuleDescriptor(rule => rule.RequireTagName("my-tr")) + .TagMatchingRule(tagName: "my-tr") .TagOutputHint("tr") .Build(), ]; var expectedCompletions = ElementCompletionResult.Create(new() { - ["my-table"] = [documentDescriptors[0]] + ["my-table"] = [tagHelpers[0]] }); var completionContext = BuildElementCompletionContext( - documentDescriptors, + tagHelpers, existingCompletions: ["table", "div"], containingTagName: "body", - containingParentTagName: null!); + containingParentTagName: null); + var service = CreateTagHelperCompletionFactsService(); - // Act var completions = service.GetElementCompletions(completionContext); - // Assert AssertCompletionsAreEquivalent(expectedCompletions, completions); } [Fact] public void GetElementCompletions_CatchAllsOnlyApplyToCompletionsStartingWithPrefix() { - // Arrange - ImmutableArray documentDescriptors = + TagHelperCollection tagHelpers = [ TagHelperDescriptorBuilder.CreateTagHelper("CatchAllTagHelper", "TestAssembly") - .TagMatchingRuleDescriptor(rule => rule.RequireTagName("*")) + .TagMatchingRule(tagName: "*") .Build(), TagHelperDescriptorBuilder.CreateTagHelper("LiTagHelper", "TestAssembly") - .TagMatchingRuleDescriptor(rule => rule.RequireTagName("li")) + .TagMatchingRule(tagName: "li") .Build(), ]; var expectedCompletions = ElementCompletionResult.Create(new() { - ["th:li"] = [documentDescriptors[1], documentDescriptors[0]], + ["th:li"] = [tagHelpers[1], tagHelpers[0]] }); var completionContext = BuildElementCompletionContext( - documentDescriptors, + tagHelpers, existingCompletions: ["li"], containingTagName: "ul", tagHelperPrefix: "th:"); + var service = CreateTagHelperCompletionFactsService(); - // Act var completions = service.GetElementCompletions(completionContext); - // Assert AssertCompletionsAreEquivalent(expectedCompletions, completions); } [Fact] public void GetElementCompletions_TagHelperPrefixIsPrependedToTagHelperCompletions() { - // Arrange - ImmutableArray documentDescriptors = + TagHelperCollection tagHelpers = [ TagHelperDescriptorBuilder.CreateTagHelper("SuperLiTagHelper", "TestAssembly") - .TagMatchingRuleDescriptor(rule => rule.RequireTagName("superli")) + .TagMatchingRule(tagName: "superli") .Build(), TagHelperDescriptorBuilder.CreateTagHelper("LiTagHelper", "TestAssembly") - .TagMatchingRuleDescriptor(rule => rule.RequireTagName("li")) + .TagMatchingRule(tagName: "li") .Build(), ]; var expectedCompletions = ElementCompletionResult.Create(new() { - ["th:superli"] = [documentDescriptors[0]], - ["th:li"] = [documentDescriptors[1]], + ["th:superli"] = [tagHelpers[0]], + ["th:li"] = [tagHelpers[1]] }); var completionContext = BuildElementCompletionContext( - documentDescriptors, + tagHelpers, existingCompletions: ["li"], containingTagName: "ul", tagHelperPrefix: "th:"); + var service = CreateTagHelperCompletionFactsService(); - // Act var completions = service.GetElementCompletions(completionContext); - // Assert AssertCompletionsAreEquivalent(expectedCompletions, completions); } [Fact] public void GetElementCompletions_IsCaseSensitive() { - // Arrange - ImmutableArray documentDescriptors = + TagHelperCollection tagHelpers = [ TagHelperDescriptorBuilder.CreateTagHelper("MyliTagHelper", "TestAssembly") - .TagMatchingRuleDescriptor(rule => rule.RequireTagName("myli")) + .TagMatchingRule(tagName: "myli") .SetCaseSensitive() .Build(), TagHelperDescriptorBuilder.CreateTagHelper("MYLITagHelper", "TestAssembly") - .TagMatchingRuleDescriptor(rule => rule.RequireTagName("MYLI")) + .TagMatchingRule(tagName: "MYLI") .SetCaseSensitive() .Build(), ]; var expectedCompletions = ElementCompletionResult.Create(new() { - ["myli"] = [documentDescriptors[0]], - ["MYLI"] = [documentDescriptors[1]], + ["myli"] = [tagHelpers[0]], + ["MYLI"] = [tagHelpers[1]] }); var completionContext = BuildElementCompletionContext( - documentDescriptors, + tagHelpers, existingCompletions: ["li"], - containingTagName: "ul", - tagHelperPrefix: null!); + containingTagName: "ul"); + var service = CreateTagHelperCompletionFactsService(); - // Act var completions = service.GetElementCompletions(completionContext); - // Assert AssertCompletionsAreEquivalent(expectedCompletions, completions); } [Fact] public void GetElementCompletions_HTMLSchemaTagName_IsCaseSensitive() { - // Arrange - ImmutableArray documentDescriptors = + TagHelperCollection tagHelpers = [ TagHelperDescriptorBuilder.CreateTagHelper("LITagHelper", "TestAssembly") - .TagMatchingRuleDescriptor(rule => rule.RequireTagName("LI")) + .TagMatchingRule(tagName: "LI") .SetCaseSensitive() .Build(), TagHelperDescriptorBuilder.CreateTagHelper("LiTagHelper", "TestAssembly") - .TagMatchingRuleDescriptor(rule => rule.RequireTagName("li")) + .TagMatchingRule(tagName: "li") .SetCaseSensitive() .Build(), ]; var expectedCompletions = ElementCompletionResult.Create(new() { - ["LI"] = [documentDescriptors[0]], - ["li"] = [documentDescriptors[1]], + ["LI"] = [tagHelpers[0]], + ["li"] = [tagHelpers[1]] }); var completionContext = BuildElementCompletionContext( - documentDescriptors, + tagHelpers, existingCompletions: ["li"], - containingTagName: "ul", - tagHelperPrefix: null!); + containingTagName: "ul"); + var service = CreateTagHelperCompletionFactsService(); - // Act var completions = service.GetElementCompletions(completionContext); - // Assert AssertCompletionsAreEquivalent(expectedCompletions, completions); } [Fact] public void GetElementCompletions_CatchAllsApplyToOnlyTagHelperCompletions() { - // Arrange - ImmutableArray documentDescriptors = + TagHelperCollection tagHelpers = [ TagHelperDescriptorBuilder.CreateTagHelper("SuperLiTagHelper", "TestAssembly") - .TagMatchingRuleDescriptor(rule => rule.RequireTagName("superli")) + .TagMatchingRule(tagName: "superli") .Build(), TagHelperDescriptorBuilder.CreateTagHelper("CatchAll", "TestAssembly") - .TagMatchingRuleDescriptor(rule => rule.RequireTagName("*")) - .Build(), + .TagMatchingRule(tagName: "*") + .Build() ]; var expectedCompletions = ElementCompletionResult.Create(new() { - ["superli"] = [documentDescriptors[0], documentDescriptors[1]], + ["superli"] = [tagHelpers[0], tagHelpers[1]] }); var completionContext = BuildElementCompletionContext( - documentDescriptors, + tagHelpers, existingCompletions: ["li"], containingTagName: "ul"); + var service = CreateTagHelperCompletionFactsService(); - // Act var completions = service.GetElementCompletions(completionContext); - // Assert AssertCompletionsAreEquivalent(expectedCompletions, completions); } [Fact] public void GetElementCompletions_CatchAllsApplyToNonTagHelperCompletionsIfStartsWithTagHelperPrefix() { - // Arrange - ImmutableArray documentDescriptors = + TagHelperCollection tagHelpers = [ TagHelperDescriptorBuilder.CreateTagHelper("SuperLiTagHelper", "TestAssembly") - .TagMatchingRuleDescriptor(rule => rule.RequireTagName("superli")) + .TagMatchingRule(tagName: "superli") .Build(), TagHelperDescriptorBuilder.CreateTagHelper("CatchAll", "TestAssembly") - .TagMatchingRuleDescriptor(rule => rule.RequireTagName("*")) + .TagMatchingRule(tagName: "*") .Build(), ]; var expectedCompletions = ElementCompletionResult.Create(new() { - ["th:superli"] = [documentDescriptors[0], documentDescriptors[1]], + ["th:superli"] = [tagHelpers[0], tagHelpers[1]] }); var completionContext = BuildElementCompletionContext( - documentDescriptors, + tagHelpers, existingCompletions: ["th:li"], containingTagName: "ul", tagHelperPrefix: "th:"); + var service = CreateTagHelperCompletionFactsService(); - // Act var completions = service.GetElementCompletions(completionContext); - // Assert AssertCompletionsAreEquivalent(expectedCompletions, completions); } [Fact] public void GetElementCompletions_AllowsMultiTargetingTagHelpers() { - // Arrange - ImmutableArray documentDescriptors = + TagHelperCollection tagHelpers = [ TagHelperDescriptorBuilder.CreateTagHelper("BoldTagHelper1", "TestAssembly") - .TagMatchingRuleDescriptor(rule => rule.RequireTagName("strong")) - .TagMatchingRuleDescriptor(rule => rule.RequireTagName("b")) - .TagMatchingRuleDescriptor(rule => rule.RequireTagName("bold")) + .TagMatchingRule(tagName: "strong") + .TagMatchingRule(tagName: "b") + .TagMatchingRule(tagName: "bold") .Build(), TagHelperDescriptorBuilder.CreateTagHelper("BoldTagHelper2", "TestAssembly") - .TagMatchingRuleDescriptor(rule => rule.RequireTagName("strong")) + .TagMatchingRule(tagName: "strong") .Build(), ]; var expectedCompletions = ElementCompletionResult.Create(new() { - ["strong"] = [documentDescriptors[0], documentDescriptors[1]], - ["b"] = [documentDescriptors[0]], - ["bold"] = [documentDescriptors[0]], + ["strong"] = [tagHelpers[0], tagHelpers[1]], + ["b"] = [tagHelpers[0]], + ["bold"] = [tagHelpers[0]] }); var completionContext = BuildElementCompletionContext( - documentDescriptors, + tagHelpers, existingCompletions: ["strong", "b", "bold"], containingTagName: "ul"); + var service = CreateTagHelperCompletionFactsService(); - // Act var completions = service.GetElementCompletions(completionContext); - // Assert AssertCompletionsAreEquivalent(expectedCompletions, completions); } [Fact] public void GetElementCompletions_CombinesDescriptorsOnExistingCompletions() { - // Arrange - ImmutableArray documentDescriptors = + TagHelperCollection tagHelpers = [ TagHelperDescriptorBuilder.CreateTagHelper("LiTagHelper1", "TestAssembly") - .TagMatchingRuleDescriptor(rule => rule.RequireTagName("li")) + .TagMatchingRule(tagName: "li") .Build(), TagHelperDescriptorBuilder.CreateTagHelper("LiTagHelper2", "TestAssembly") - .TagMatchingRuleDescriptor(rule => rule.RequireTagName("li")) + .TagMatchingRule(tagName: "li") .Build(), ]; var expectedCompletions = ElementCompletionResult.Create(new() { - ["li"] = [documentDescriptors[0], documentDescriptors[1]], + ["li"] = [tagHelpers[0], tagHelpers[1]] }); - var completionContext = BuildElementCompletionContext(documentDescriptors, existingCompletions: ["li"], containingTagName: "ul"); + var completionContext = BuildElementCompletionContext( + tagHelpers, + existingCompletions: ["li"], + containingTagName: "ul"); + var service = CreateTagHelperCompletionFactsService(); - // Act var completions = service.GetElementCompletions(completionContext); - // Assert AssertCompletionsAreEquivalent(expectedCompletions, completions); } [Fact] public void GetElementCompletions_NewCompletionsForSchemaTagsNotInExistingCompletionsAreIgnored() { - // Arrange - ImmutableArray documentDescriptors = + TagHelperCollection tagHelpers = [ TagHelperDescriptorBuilder.CreateTagHelper("SuperLiTagHelper", "TestAssembly") - .TagMatchingRuleDescriptor(rule => rule.RequireTagName("superli")) + .TagMatchingRule(tagName: "superli") .Build(), TagHelperDescriptorBuilder.CreateTagHelper("LiTagHelper", "TestAssembly") - .TagMatchingRuleDescriptor(rule => rule.RequireTagName("li")) + .TagMatchingRule(tagName: "li") .TagOutputHint("strong") .Build(), TagHelperDescriptorBuilder.CreateTagHelper("DivTagHelper", "TestAssembly") - .TagMatchingRuleDescriptor(rule => rule.RequireTagName("div")) + .TagMatchingRule(tagName: "div") .Build(), ]; var expectedCompletions = ElementCompletionResult.Create(new() { - ["li"] = [documentDescriptors[1]], - ["superli"] = [documentDescriptors[0]], + ["li"] = [tagHelpers[1]], + ["superli"] = [tagHelpers[0]] }); - var completionContext = BuildElementCompletionContext(documentDescriptors, existingCompletions: ["li"], containingTagName: "ul"); + var completionContext = BuildElementCompletionContext( + tagHelpers, + existingCompletions: ["li"], + containingTagName: "ul"); + var service = CreateTagHelperCompletionFactsService(); - // Act var completions = service.GetElementCompletions(completionContext); - // Assert AssertCompletionsAreEquivalent(expectedCompletions, completions); } [Fact] public void GetElementCompletions_OutputHintIsCrossReferencedWithExistingCompletions() { - // Arrange - ImmutableArray documentDescriptors = + TagHelperCollection tagHelpers = [ TagHelperDescriptorBuilder.CreateTagHelper("DivTagHelper", "TestAssembly") - .TagMatchingRuleDescriptor(rule => rule.RequireTagName("div")) + .TagMatchingRule(tagName: "div") .TagOutputHint("li") .Build(), TagHelperDescriptorBuilder.CreateTagHelper("LiTagHelper", "TestAssembly") - .TagMatchingRuleDescriptor(rule => rule.RequireTagName("li")) + .TagMatchingRule(tagName: "li") .TagOutputHint("strong") .Build(), ]; var expectedCompletions = ElementCompletionResult.Create(new() { - ["div"] = [documentDescriptors[0]], - ["li"] = [documentDescriptors[1]], + ["div"] = [tagHelpers[0]], + ["li"] = [tagHelpers[1]] }); - var completionContext = BuildElementCompletionContext(documentDescriptors, existingCompletions: ["li"], containingTagName: "ul"); + var completionContext = BuildElementCompletionContext( + tagHelpers, + existingCompletions: ["li"], + containingTagName: "ul"); + var service = CreateTagHelperCompletionFactsService(); - // Act var completions = service.GetElementCompletions(completionContext); - // Assert AssertCompletionsAreEquivalent(expectedCompletions, completions); } [Fact] public void GetElementCompletions_EnsuresDescriptorsHaveSatisfiedParent() { - // Arrange - ImmutableArray documentDescriptors = + TagHelperCollection tagHelpers = [ TagHelperDescriptorBuilder.CreateTagHelper("LiTagHelper1", "TestAssembly") - .TagMatchingRuleDescriptor(rule => rule.RequireTagName("li")) + .TagMatchingRule(tagName: "li") .Build(), TagHelperDescriptorBuilder.CreateTagHelper("LiTagHelper2", "TestAssembly") - .TagMatchingRuleDescriptor(rule => rule.RequireTagName("li").RequireParentTag("ol")) + .TagMatchingRule(tagName: "li", parentTagName: "ol") .Build(), ]; var expectedCompletions = ElementCompletionResult.Create(new() { - ["li"] = [documentDescriptors[0]], + ["li"] = [tagHelpers[0]] }); - var completionContext = BuildElementCompletionContext(documentDescriptors, existingCompletions: ["li"], containingTagName: "ul"); + var completionContext = BuildElementCompletionContext( + tagHelpers, + existingCompletions: ["li"], + containingTagName: "ul"); + var service = CreateTagHelperCompletionFactsService(); - // Act var completions = service.GetElementCompletions(completionContext); - // Assert AssertCompletionsAreEquivalent(expectedCompletions, completions); } [Fact] public void GetElementCompletions_NoContainingParentTag_DoesNotGetCompletionForRuleWithParentTag() { - // Arrange - ImmutableArray documentDescriptors = + TagHelperCollection tagHelpers = [ TagHelperDescriptorBuilder.CreateTagHelper("Tag1", "TestAssembly") - .TagMatchingRuleDescriptor(rule => rule.RequireTagName("outer-child-tag")) - .TagMatchingRuleDescriptor(rule => rule.RequireTagName("child-tag").RequireParentTag("parent-tag")) + .TagMatchingRule(tagName: "outer-child-tag") + .TagMatchingRule(tagName: "child-tag", parentTagName: "parent-tag") .Build(), TagHelperDescriptorBuilder.CreateTagHelper("Tag2", "TestAssembly") - .TagMatchingRuleDescriptor(rule => rule.RequireTagName("parent-tag")) + .TagMatchingRule(tagName: "parent-tag") .AllowChildTag("child-tag") .Build(), ]; var expectedCompletions = ElementCompletionResult.Create(new() { - ["outer-child-tag"] = [documentDescriptors[0]], - ["parent-tag"] = [documentDescriptors[1]], + ["outer-child-tag"] = [tagHelpers[0]], + ["parent-tag"] = [tagHelpers[1]] }); var completionContext = BuildElementCompletionContext( - documentDescriptors, + tagHelpers, existingCompletions: [], - containingTagName: null!, - containingParentTagName: null!); + containingTagName: null, + containingParentTagName: null); + var service = CreateTagHelperCompletionFactsService(); - // Act var completions = service.GetElementCompletions(completionContext); - // Assert AssertCompletionsAreEquivalent(expectedCompletions, completions); } [Fact] public void GetElementCompletions_WithContainingParentTag_GetsCompletionForRuleWithParentTag() { - // Arrange - ImmutableArray documentDescriptors = + TagHelperCollection tagHelpers = [ TagHelperDescriptorBuilder.CreateTagHelper("Tag1", "TestAssembly") - .TagMatchingRuleDescriptor(rule => rule.RequireTagName("outer-child-tag")) - .TagMatchingRuleDescriptor(rule => rule.RequireTagName("child-tag").RequireParentTag("parent-tag")) + .TagMatchingRule(tagName: "outer-child-tag") + .TagMatchingRule(tagName: "child-tag", parentTagName: "parent-tag") .Build(), TagHelperDescriptorBuilder.CreateTagHelper("Tag2", "TestAssembly") - .TagMatchingRuleDescriptor(rule => rule.RequireTagName("parent-tag")) + .TagMatchingRule(tagName: "parent-tag") .AllowChildTag("child-tag") .Build(), ]; var expectedCompletions = ElementCompletionResult.Create(new() { - ["child-tag"] = [documentDescriptors[0]], + ["child-tag"] = [tagHelpers[0]] }); var completionContext = BuildElementCompletionContext( - documentDescriptors, + tagHelpers, existingCompletions: [], containingTagName: "child-tag", containingParentTagName: "parent-tag"); + var service = CreateTagHelperCompletionFactsService(); - // Act var completions = service.GetElementCompletions(completionContext); - // Assert AssertCompletionsAreEquivalent(expectedCompletions, completions); } [Fact] public void GetElementCompletions_AllowedChildrenAreIgnoredWhenAtRoot() { - // Arrange - ImmutableArray documentDescriptors = + TagHelperCollection tagHelpers = [ TagHelperDescriptorBuilder.CreateTagHelper("CatchAll", "TestAssembly") - .TagMatchingRuleDescriptor(rule => rule.RequireTagName("*")) + .TagMatchingRule(tagName: "*") .AllowChildTag("b") .AllowChildTag("bold") .AllowChildTag("div") @@ -1162,27 +1044,25 @@ public void GetElementCompletions_AllowedChildrenAreIgnoredWhenAtRoot() var expectedCompletions = ElementCompletionResult.Create([]); var completionContext = BuildElementCompletionContext( - documentDescriptors, + tagHelpers, existingCompletions: [], - containingTagName: null!, - containingParentTagName: null!); + containingTagName: null, + containingParentTagName: null); + var service = CreateTagHelperCompletionFactsService(); - // Act var completions = service.GetElementCompletions(completionContext); - // Assert AssertCompletionsAreEquivalent(expectedCompletions, completions); } [Fact] public void GetElementCompletions_DoesNotReturnExistingCompletionsWhenAllowedChildren() { - // Arrange - ImmutableArray documentDescriptors = + TagHelperCollection tagHelpers = [ TagHelperDescriptorBuilder.CreateTagHelper("BoldParent", "TestAssembly") - .TagMatchingRuleDescriptor(rule => rule.RequireTagName("div")) + .TagMatchingRule(tagName: "div") .AllowChildTag("b") .AllowChildTag("bold") .AllowChildTag("div") @@ -1193,31 +1073,29 @@ public void GetElementCompletions_DoesNotReturnExistingCompletionsWhenAllowedChi { ["b"] = [], ["bold"] = [], - ["div"] = [documentDescriptors[0]] + ["div"] = [tagHelpers[0]] }); var completionContext = BuildElementCompletionContext( - documentDescriptors, + tagHelpers, existingCompletions: ["p", "em"], containingTagName: "thing", containingParentTagName: "div"); + var service = CreateTagHelperCompletionFactsService(); - // Act var completions = service.GetElementCompletions(completionContext); - // Assert AssertCompletionsAreEquivalent(expectedCompletions, completions); } [Fact] public void GetElementCompletions_CapturesAllAllowedChildTagsFromParentTagHelpers_NoneTagHelpers() { - // Arrange - ImmutableArray documentDescriptors = + TagHelperCollection tagHelpers = [ TagHelperDescriptorBuilder.CreateTagHelper("BoldParent", "TestAssembly") - .TagMatchingRuleDescriptor(rule => rule.RequireTagName("div")) + .TagMatchingRule(tagName: "div") .AllowChildTag("b") .AllowChildTag("bold") .Build(), @@ -1226,31 +1104,29 @@ public void GetElementCompletions_CapturesAllAllowedChildTagsFromParentTagHelper var expectedCompletions = ElementCompletionResult.Create(new() { ["b"] = [], - ["bold"] = [], + ["bold"] = [] }); var completionContext = BuildElementCompletionContext( - documentDescriptors, + tagHelpers, existingCompletions: [], containingTagName: "", containingParentTagName: "div"); + var service = CreateTagHelperCompletionFactsService(); - // Act var completions = service.GetElementCompletions(completionContext); - // Assert AssertCompletionsAreEquivalent(expectedCompletions, completions); } [Fact] public void GetElementCompletions_CapturesAllAllowedChildTagsFromParentTagHelpers_SomeTagHelpers() { - // Arrange - ImmutableArray documentDescriptors = + TagHelperCollection tagHelpers = [ TagHelperDescriptorBuilder.CreateTagHelper("BoldParent", "TestAssembly") - .TagMatchingRuleDescriptor(rule => rule.RequireTagName("div")) + .TagMatchingRule(tagName: "div") .AllowChildTag("b") .AllowChildTag("bold") .AllowChildTag("div") @@ -1261,37 +1137,35 @@ public void GetElementCompletions_CapturesAllAllowedChildTagsFromParentTagHelper { ["b"] = [], ["bold"] = [], - ["div"] = [documentDescriptors[0]] + ["div"] = [tagHelpers[0]] }); var completionContext = BuildElementCompletionContext( - documentDescriptors, + tagHelpers, existingCompletions: [], containingTagName: "", containingParentTagName: "div"); + var service = CreateTagHelperCompletionFactsService(); - // Act var completions = service.GetElementCompletions(completionContext); - // Assert AssertCompletionsAreEquivalent(expectedCompletions, completions); } [Fact] public void GetElementCompletions_CapturesAllAllowedChildTagsFromParentTagHelpers_AllTagHelpers() { - // Arrange - ImmutableArray documentDescriptors = + TagHelperCollection tagHelpers = [ TagHelperDescriptorBuilder.CreateTagHelper("BoldParentCatchAll", "TestAssembly") - .TagMatchingRuleDescriptor(rule => rule.RequireTagName("*")) + .TagMatchingRule(tagName: "*") .AllowChildTag("strong") .AllowChildTag("div") .AllowChildTag("b") .Build(), TagHelperDescriptorBuilder.CreateTagHelper("BoldParent", "TestAssembly") - .TagMatchingRuleDescriptor(rule => rule.RequireTagName("div")) + .TagMatchingRule(tagName: "div") .AllowChildTag("b") .AllowChildTag("bold") .Build(), @@ -1299,132 +1173,107 @@ public void GetElementCompletions_CapturesAllAllowedChildTagsFromParentTagHelper var expectedCompletions = ElementCompletionResult.Create(new() { - ["strong"] = [documentDescriptors[0]], - ["b"] = [documentDescriptors[0]], - ["bold"] = [documentDescriptors[0]], - ["div"] = [documentDescriptors[0], documentDescriptors[1]], + ["strong"] = [tagHelpers[0]], + ["b"] = [tagHelpers[0]], + ["bold"] = [tagHelpers[0]], + ["div"] = [tagHelpers[0], tagHelpers[1]] }); var completionContext = BuildElementCompletionContext( - documentDescriptors, + tagHelpers, existingCompletions: [], containingTagName: "", containingParentTagName: "div"); + var service = CreateTagHelperCompletionFactsService(); - // Act var completions = service.GetElementCompletions(completionContext); - // Assert AssertCompletionsAreEquivalent(expectedCompletions, completions); } [Fact] public void GetElementCompletions_MustSatisfyAttributeRules_WithAttributes() { - // Arrange - ImmutableArray documentDescriptors = + TagHelperCollection tagHelpers = [ TagHelperDescriptorBuilder.CreateTagHelper("FormTagHelper", "TestAssembly") - .TagMatchingRuleDescriptor(rule => rule - .RequireTagName("form") - .RequireAttributeDescriptor(builder => - { - builder.Name = "asp-route-"; - builder.NameComparison = RequiredAttributeNameComparison.PrefixMatch; - })) - .Build(), + .TagMatchingRule(tagName: "form", static b => b + .RequiredAttribute(name: "asp-route-", nameComparison: RequiredAttributeNameComparison.PrefixMatch)) + .Build() ]; var expectedCompletions = ElementCompletionResult.Create(new() { - ["form"] = [documentDescriptors[0]] + ["form"] = [tagHelpers[0]] }); - var attributes = ImmutableArray.Create( - KeyValuePair.Create("asp-route-id", "123")); - var completionContext = BuildElementCompletionContext( - documentDescriptors, + tagHelpers, existingCompletions: ["form"], containingTagName: "", containingParentTagName: "div", - attributes: attributes); + attributes: [KeyValuePair.Create("asp-route-id", "123")]); + var service = CreateTagHelperCompletionFactsService(); - // Act var completions = service.GetElementCompletions(completionContext); - // Assert AssertCompletionsAreEquivalent(expectedCompletions, completions); } [Fact] public void GetElementCompletions_MustSatisfyAttributeRules_NoAttributes() { - // Arrange - ImmutableArray documentDescriptors = + TagHelperCollection tagHelpers = [ TagHelperDescriptorBuilder.CreateTagHelper("FormTagHelper", "TestAssembly") - .TagMatchingRuleDescriptor(rule => rule - .RequireTagName("form") - .RequireAttributeDescriptor(builder => - { - builder.Name = "asp-route-"; - builder.NameComparison = RequiredAttributeNameComparison.PrefixMatch; - })) + .TagMatchingRule(tagName: "form", static b => b + .RequiredAttribute(name: "asp-route-", nameComparison: RequiredAttributeNameComparison.PrefixMatch)) .Build(), ]; var expectedCompletions = ElementCompletionResult.Create([]); var completionContext = BuildElementCompletionContext( - documentDescriptors, + tagHelpers, existingCompletions: ["form"], containingTagName: "", containingParentTagName: "div"); + var service = CreateTagHelperCompletionFactsService(); - // Act var completions = service.GetElementCompletions(completionContext); - // Assert AssertCompletionsAreEquivalent(expectedCompletions, completions); } [Fact] public void GetElementCompletions_MustSatisfyAttributeRules_NoAttributes_AllowedIfNotHtml() { - // Arrange - ImmutableArray documentDescriptors = + TagHelperCollection tagHelpers = [ TagHelperDescriptorBuilder.CreateTagHelper("ComponentTagHelper", "TestAssembly") - .TagMatchingRuleDescriptor(rule => rule - .RequireTagName("component") - .RequireAttributeDescriptor(builder => - { - builder.Name = "type"; - builder.NameComparison = RequiredAttributeNameComparison.PrefixMatch; - })) + .TagMatchingRule(tagName: "component", static b => b + .RequiredAttribute(name: "type", nameComparison: RequiredAttributeNameComparison.PrefixMatch)) .Build(), ]; var expectedCompletions = ElementCompletionResult.Create(new() { - ["component"] = [documentDescriptors[0]], + ["component"] = [tagHelpers[0]] }); var completionContext = BuildElementCompletionContext( - documentDescriptors, + tagHelpers, existingCompletions: [], containingTagName: "", containingParentTagName: "div"); + var service = CreateTagHelperCompletionFactsService(); - // Act var completions = service.GetElementCompletions(completionContext); - // Assert AssertCompletionsAreEquivalent(expectedCompletions, completions); } @@ -1455,40 +1304,40 @@ private static void AssertCompletionsAreEquivalent(AttributeCompletionResult exp } private static ElementCompletionContext BuildElementCompletionContext( - ImmutableArray descriptors, + TagHelperCollection tagHelpers, ImmutableArray existingCompletions, - string containingTagName, - string containingParentTagName = "body", + string? containingTagName, + string? containingParentTagName = "body", bool containingParentIsTagHelper = false, - string tagHelperPrefix = "", + string? tagHelperPrefix = null, ImmutableArray> attributes = default) { attributes = attributes.NullToEmpty(); - var documentContext = TagHelperDocumentContext.Create(tagHelperPrefix, descriptors); + var documentContext = TagHelperDocumentContext.Create(tagHelperPrefix, tagHelpers); var completionContext = new ElementCompletionContext( documentContext, existingCompletions, containingTagName, attributes, - containingParentTagName: containingParentTagName, - containingParentIsTagHelper: containingParentIsTagHelper, - inHTMLSchema: (tag) => tag == "strong" || tag == "b" || tag == "bold" || tag == "li" || tag == "div" || tag == "form"); + containingParentTagName, + containingParentIsTagHelper, + inHTMLSchema: static tag => tag is "strong" or "b" or "bold" or "li" or "div" or "form"); return completionContext; } private static AttributeCompletionContext BuildAttributeCompletionContext( - ImmutableArray descriptors, + TagHelperCollection tagHelpers, ImmutableArray existingCompletions, string currentTagName, - string? currentAttributeName = null!, + string? currentAttributeName = null, ImmutableArray> attributes = default, string tagHelperPrefix = "") { attributes = attributes.NullToEmpty(); - var documentContext = TagHelperDocumentContext.Create(tagHelperPrefix, descriptors); + var documentContext = TagHelperDocumentContext.Create(tagHelperPrefix, tagHelpers); var completionContext = new AttributeCompletionContext( documentContext, existingCompletions, @@ -1497,7 +1346,7 @@ private static AttributeCompletionContext BuildAttributeCompletionContext( attributes, currentParentTagName: "body", currentParentIsTagHelper: false, - inHTMLSchema: (tag) => tag == "strong" || tag == "b" || tag == "bold" || tag == "li" || tag == "div"); + inHTMLSchema: static tag => tag is "strong" or "b" or "bold" or "li" or "div" or "form"); return completionContext; } diff --git a/src/Razor/test/Microsoft.CodeAnalysis.Razor.Workspaces.Test/Completion/MarkupTransitionCompletionItemProviderTest.cs b/src/Razor/test/Microsoft.CodeAnalysis.Razor.Workspaces.Test/Completion/MarkupTransitionCompletionItemProviderTest.cs index 9a2d954e17b..57467c263a0 100644 --- a/src/Razor/test/Microsoft.CodeAnalysis.Razor.Workspaces.Test/Completion/MarkupTransitionCompletionItemProviderTest.cs +++ b/src/Razor/test/Microsoft.CodeAnalysis.Razor.Workspaces.Test/Completion/MarkupTransitionCompletionItemProviderTest.cs @@ -299,7 +299,7 @@ private static RazorCompletionContext CreateRazorCompletionContext(TestCode text var sourceDocument = RazorSourceDocument.Create("", RazorSourceDocumentProperties.Default); var codeDocument = RazorCodeDocument.Create(sourceDocument); - var tagHelperDocumentContext = TagHelperDocumentContext.Create(prefix: string.Empty, tagHelpers: []); + var tagHelperDocumentContext = TagHelperDocumentContext.Create(tagHelpers: []); var owner = syntaxTree.Root.FindInnermostNode(absoluteIndex, includeWhitespace: true, walkMarkersBack: true); owner = AbstractRazorCompletionFactsService.AdjustSyntaxNodeForWordBoundary(owner, absoluteIndex); diff --git a/src/Razor/test/Microsoft.CodeAnalysis.Razor.Workspaces.Test/Completion/RazorCompletionListProviderTest.cs b/src/Razor/test/Microsoft.CodeAnalysis.Razor.Workspaces.Test/Completion/RazorCompletionListProviderTest.cs index 97f37a144df..43bc2995f52 100644 --- a/src/Razor/test/Microsoft.CodeAnalysis.Razor.Workspaces.Test/Completion/RazorCompletionListProviderTest.cs +++ b/src/Razor/test/Microsoft.CodeAnalysis.Razor.Workspaces.Test/Completion/RazorCompletionListProviderTest.cs @@ -1,7 +1,6 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -using System.Collections.Immutable; using System.Linq; using System.Text.Json; using Microsoft.AspNetCore.Razor.Language; @@ -531,13 +530,13 @@ public void GetCompletionList_ProvidesTagHelperAttributeItems_AttributeQuotesOff Assert.Contains(completionList.Items, item => item.InsertText == "testAttribute=$0"); } - private static RazorCodeDocument CreateCodeDocument(string text, string documentFilePath, ImmutableArray tagHelpers = default) + private static RazorCodeDocument CreateCodeDocument(string text, string documentFilePath, TagHelperCollection? tagHelpers = null) { var codeDocument = TestRazorCodeDocument.CreateEmpty(); var sourceDocument = TestRazorSourceDocument.Create(text, filePath: documentFilePath); var syntaxTree = RazorSyntaxTree.Parse(sourceDocument); codeDocument.SetSyntaxTree(syntaxTree); - var tagHelperDocumentContext = TagHelperDocumentContext.Create(prefix: null, tagHelpers.NullToEmpty()); + var tagHelperDocumentContext = TagHelperDocumentContext.Create(tagHelpers ?? []); codeDocument.SetTagHelperContext(tagHelperDocumentContext); return codeDocument; } diff --git a/src/Razor/test/Microsoft.CodeAnalysis.Razor.Workspaces.Test/Extensions/RazorCodeDocumentExtensionsTest.cs b/src/Razor/test/Microsoft.CodeAnalysis.Razor.Workspaces.Test/Extensions/RazorCodeDocumentExtensionsTest.cs index 4182c01b517..b1db2fb6de1 100644 --- a/src/Razor/test/Microsoft.CodeAnalysis.Razor.Workspaces.Test/Extensions/RazorCodeDocumentExtensionsTest.cs +++ b/src/Razor/test/Microsoft.CodeAnalysis.Razor.Workspaces.Test/Extensions/RazorCodeDocumentExtensionsTest.cs @@ -1,7 +1,6 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -using System.Collections.Immutable; using Microsoft.AspNetCore.Razor.Language; using Microsoft.AspNetCore.Razor.Test.Common; using Microsoft.CodeAnalysis.Razor.Protocol; @@ -350,9 +349,9 @@ public void GetLanguageKind_TagHelperInCSharpRightAssociative() Assert.Equal(RazorLanguageKind.Html, languageKind); } - private static RazorCodeDocument CreateCodeDocument(TestCode code, params ImmutableArray tagHelpers) + private static RazorCodeDocument CreateCodeDocument(TestCode code, params TagHelperCollection tagHelpers) { - tagHelpers = tagHelpers.NullToEmpty(); + tagHelpers ??= []; var sourceDocument = TestRazorSourceDocument.Create(code.Text); var projectEngine = RazorProjectEngine.Create(builder => diff --git a/src/Razor/test/Microsoft.CodeAnalysis.Razor.Workspaces.Test/ProjectSystem/ProjectStateTest.cs b/src/Razor/test/Microsoft.CodeAnalysis.Razor.Workspaces.Test/ProjectSystem/ProjectStateTest.cs index df7f9b27e09..42f3e053f5d 100644 --- a/src/Razor/test/Microsoft.CodeAnalysis.Razor.Workspaces.Test/ProjectSystem/ProjectStateTest.cs +++ b/src/Razor/test/Microsoft.CodeAnalysis.Razor.Workspaces.Test/ProjectSystem/ProjectStateTest.cs @@ -603,7 +603,7 @@ public void ProjectState_WithProjectWorkspaceState_Changed_TagHelpersChanged() // The configuration didn't change, but the tag helpers did Assert.Same(state.ProjectEngine, newState.ProjectEngine); - Assert.NotEqual(state.TagHelpers, newState.TagHelpers); + Assert.NotEqual(state.TagHelpers, newState.TagHelpers); Assert.NotSame(state.Documents[SomeProjectFile2.FilePath], newState.Documents[SomeProjectFile2.FilePath]); Assert.NotSame(state.Documents[AnotherProjectNestedFile3.FilePath], newState.Documents[AnotherProjectNestedFile3.FilePath]); } @@ -856,11 +856,11 @@ public void ProjectState_RemoveImportDocument_UpdatesRelatedDocuments() Assert.Empty(documentPathSet); } - private static void AssertSameTagHelpers(ImmutableArray expected, ImmutableArray actual) + private static void AssertSameTagHelpers(TagHelperCollection expected, TagHelperCollection actual) { - Assert.Equal(expected.Length, actual.Length); + Assert.Equal(expected.Count, actual.Count); - for (var i = 0; i < expected.Length; i++) + for (var i = 0; i < expected.Count; i++) { Assert.Same(expected[i], actual[i]); } diff --git a/src/Razor/test/Microsoft.CodeAnalysis.Razor.Workspaces.Test/TagHelperFactsTest.cs b/src/Razor/test/Microsoft.CodeAnalysis.Razor.Workspaces.Test/TagHelperFactsTest.cs index 6459e590f32..b120bd78265 100644 --- a/src/Razor/test/Microsoft.CodeAnalysis.Razor.Workspaces.Test/TagHelperFactsTest.cs +++ b/src/Razor/test/Microsoft.CodeAnalysis.Razor.Workspaces.Test/TagHelperFactsTest.cs @@ -1,8 +1,6 @@ // 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 System.Collections.Generic; using System.Collections.Immutable; using System.Linq; @@ -18,357 +16,317 @@ public class TagHelperFactsTest(ITestOutputHelper testOutput) : ToolingTestBase( [Fact] public void GetTagHelperBinding_DoesNotAllowOptOutCharacterPrefix() { - // Arrange - ImmutableArray documentDescriptors = + TagHelperCollection tagHelpers = [ TagHelperDescriptorBuilder.CreateTagHelper("TestType", "TestAssembly") - .TagMatchingRuleDescriptor(rule => rule.RequireTagName("*")) + .TagMatchingRule(tagName: "*") .Build() ]; - var documentContext = TagHelperDocumentContext.Create(string.Empty, documentDescriptors); - // Act - var binding = TagHelperFacts.GetTagHelperBinding(documentContext, "!a", ImmutableArray>.Empty, parentTag: null, parentIsTagHelper: false); + var documentContext = TagHelperDocumentContext.Create(tagHelpers); + + var binding = TagHelperFacts.GetTagHelperBinding( + documentContext, + tagName: "!a", + attributes: [], + parentTag: null, + parentIsTagHelper: false); - // Assert Assert.Null(binding); } [Fact] public void GetTagHelperBinding_WorksAsExpected() { - // Arrange - ImmutableArray documentDescriptors = + TagHelperCollection tagHelpers = [ TagHelperDescriptorBuilder.CreateTagHelper("TestType", "TestAssembly") - .TagMatchingRuleDescriptor(rule => - rule - .RequireTagName("a") - .RequireAttributeDescriptor(attribute => attribute.Name("asp-for"))) - .BoundAttributeDescriptor(attribute => - attribute - .Name("asp-for") - .TypeName(typeof(string).FullName) - .PropertyName("AspFor")) - .BoundAttributeDescriptor(attribute => - attribute - .Name("asp-route") - .TypeName(typeof(IDictionary).Namespace + "IDictionary") - .PropertyName("AspRoute") - .AsDictionaryAttribute("asp-route-", typeof(string).FullName)) + .TagMatchingRule(tagName: "a", static b => b + .RequiredAttribute(name: "asp-for")) + .BoundAttribute(name: "asp-for", propertyName: "AspFor") + .BoundAttribute(name: "asp-route", propertyName: "AspRoute", typeName: typeof(IDictionary<,>).Namespace + "IDictionary", static b => b + .AsDictionaryAttribute("asp-route-")) .Build(), TagHelperDescriptorBuilder.CreateTagHelper("TestType", "TestAssembly") .TagMatchingRuleDescriptor(rule => rule.RequireTagName("input")) - .BoundAttributeDescriptor(attribute => - attribute - .Name("asp-for") - .TypeName(typeof(string).FullName) - .PropertyName("AspFor")) + .BoundAttributeDescriptor(attribute => attribute + .Name("asp-for") + .TypeName(typeof(string).FullName) + .PropertyName("AspFor")) .Build(), ]; - var documentContext = TagHelperDocumentContext.Create(string.Empty, documentDescriptors); - var attributes = ImmutableArray.Create( - new KeyValuePair("asp-for", "Name")); - - // Act - var binding = TagHelperFacts.GetTagHelperBinding(documentContext, "a", attributes, parentTag: "p", parentIsTagHelper: false); - - // Assert - var descriptor = Assert.Single(binding.Descriptors); - Assert.Equal(documentDescriptors[0], descriptor); - var boundRule = Assert.Single(binding.GetBoundRules(descriptor)); - Assert.Equal(documentDescriptors[0].TagMatchingRules.First(), boundRule); + + var documentContext = TagHelperDocumentContext.Create(tagHelpers); + + var binding = TagHelperFacts.GetTagHelperBinding( + documentContext, + tagName: "a", + attributes: [KeyValuePair.Create("asp-for", "Name")], + parentTag: "p", + parentIsTagHelper: false); + + Assert.NotNull(binding); + var tagHelper = Assert.Single(binding.TagHelpers); + Assert.Same(tagHelpers[0], tagHelper); + var boundRule = Assert.Single(binding.GetBoundRules(tagHelper)); + Assert.Same(tagHelpers[0].TagMatchingRules[0], boundRule); } [Fact] public void GetBoundTagHelperAttributes_MatchesPrefixedAttributeName() { - // Arrange - ImmutableArray documentDescriptors = + TagHelperCollection tagHelpers = [ TagHelperDescriptorBuilder.CreateTagHelper("TestType", "TestAssembly") - .TagMatchingRuleDescriptor(rule => rule.RequireTagName("a")) - .BoundAttributeDescriptor(attribute => - attribute - .Name("asp-for") - .TypeName(typeof(string).FullName) - .PropertyName("AspFor")) - .BoundAttributeDescriptor(attribute => - attribute - .Name("asp-route") - .TypeName(typeof(IDictionary).Namespace + "IDictionary") - .PropertyName("AspRoute") - .AsDictionaryAttribute("asp-route-", typeof(string).FullName)) + .TagMatchingRule(tagName: "a") + .BoundAttribute(name: "asp-for", propertyName: "AspFor") + .BoundAttribute(name: "asp-route", propertyName: "AspRoute", typeName: typeof(IDictionary<,>).Namespace + "IDictionary", static b => b + .AsDictionaryAttribute("asp-route-")) .Build() ]; - var expectedAttributeDescriptors = new[] - { - documentDescriptors[0].BoundAttributes.Last() - }; - var documentContext = TagHelperDocumentContext.Create(string.Empty, documentDescriptors); - var binding = TagHelperFacts.GetTagHelperBinding(documentContext, "a", ImmutableArray>.Empty, parentTag: null, parentIsTagHelper: false); - // Act - var tagHelperAttributes = TagHelperFacts.GetBoundTagHelperAttributes(documentContext, "asp-route-something", binding); + var documentContext = TagHelperDocumentContext.Create(tagHelpers); + var binding = TagHelperFacts.GetTagHelperBinding( + documentContext, + tagName: "a", + attributes: [], + parentTag: null, + parentIsTagHelper: false); + + Assert.NotNull(binding); - // Assert - Assert.Equal(expectedAttributeDescriptors, tagHelperAttributes); + var result = TagHelperFacts.GetBoundTagHelperAttributes( + documentContext, + attributeName: "asp-route-something", + binding); + + Assert.Same(tagHelpers[0].BoundAttributes[^1], Assert.Single(result)); } [Fact] public void GetBoundTagHelperAttributes_MatchesAttributeName() { - // Arrange - ImmutableArray documentDescriptors = + TagHelperCollection tagHelpers = [ TagHelperDescriptorBuilder.CreateTagHelper("TestType", "TestAssembly") - .TagMatchingRuleDescriptor(rule => rule.RequireTagName("input")) - .BoundAttributeDescriptor(attribute => - attribute - .Name("asp-for") - .TypeName(typeof(string).FullName) - .PropertyName("AspFor")) - .BoundAttributeDescriptor(attribute => - attribute - .Name("asp-extra") - .TypeName(typeof(string).FullName) - .PropertyName("AspExtra")) + .TagMatchingRule(tagName: "input") + .BoundAttribute(name: "asp-for", propertyName: "AspFor") + .BoundAttribute(name: "asp-extra", propertyName: "AspExtra") .Build() ]; - var expectedAttributeDescriptors = new[] + + var expectedBoundAttributes = new[] { - documentDescriptors[0].BoundAttributes.First() + tagHelpers[0].BoundAttributes.First() }; - var documentContext = TagHelperDocumentContext.Create(string.Empty, documentDescriptors); - var binding = TagHelperFacts.GetTagHelperBinding(documentContext, "input", ImmutableArray>.Empty, parentTag: null, parentIsTagHelper: false); - // Act - var tagHelperAttributes = TagHelperFacts.GetBoundTagHelperAttributes(documentContext, "asp-for", binding); + var documentContext = TagHelperDocumentContext.Create(tagHelpers); + + var binding = TagHelperFacts.GetTagHelperBinding( + documentContext, + tagName: "input", + attributes: [], + parentTag: null, + parentIsTagHelper: false); + + Assert.NotNull(binding); - // Assert - Assert.Equal(expectedAttributeDescriptors, tagHelperAttributes); + var result = TagHelperFacts.GetBoundTagHelperAttributes( + documentContext, + attributeName: "asp-for", + binding); + + Assert.Equal(expectedBoundAttributes, result); } [Fact] public void GetTagHelpersGivenTag_DoesNotAllowOptOutCharacterPrefix() { - // Arrange - ImmutableArray documentDescriptors = + TagHelperCollection tagHelpers = [ TagHelperDescriptorBuilder.CreateTagHelper("TestType", "TestAssembly") - .TagMatchingRuleDescriptor(rule => rule.RequireTagName("*")) + .TagMatchingRule(tagName: "*") .Build() ]; - var documentContext = TagHelperDocumentContext.Create(string.Empty, documentDescriptors); - // Act - var descriptors = TagHelperFacts.GetTagHelpersGivenTag(documentContext, "!strong", parentTag: null); + var documentContext = TagHelperDocumentContext.Create(tagHelpers); + + var result = TagHelperFacts.GetTagHelpersGivenTag( + documentContext, + tagName: "!strong", + parentTag: null); - // Assert - Assert.Empty(descriptors); + Assert.Empty(result); } [Fact] public void GetTagHelpersGivenTag_RequiresTagName() { - // Arrange - ImmutableArray documentDescriptors = + TagHelperCollection tagHelpers = [ TagHelperDescriptorBuilder.CreateTagHelper("TestType", "TestAssembly") - .TagMatchingRuleDescriptor(rule => rule.RequireTagName("strong")) + .TagMatchingRule(tagName: "strong") .Build() ]; - var documentContext = TagHelperDocumentContext.Create(string.Empty, documentDescriptors); - // Act - var descriptors = TagHelperFacts.GetTagHelpersGivenTag(documentContext, "strong", "p"); + var documentContext = TagHelperDocumentContext.Create(tagHelpers); - // Assert - Assert.Equal(documentDescriptors, descriptors); + var result = TagHelperFacts.GetTagHelpersGivenTag( + documentContext, + tagName: "strong", + parentTag: "p"); + + Assert.Equal(tagHelpers, result); } [Fact] public void GetTagHelpersGivenTag_RestrictsTagHelpersBasedOnTagName() { - // Arrange - ImmutableArray expectedDescriptors = + TagHelperCollection tagHelpers = [ TagHelperDescriptorBuilder.CreateTagHelper("TestType", "TestAssembly") - .TagMatchingRuleDescriptor( - rule => rule - .RequireTagName("a") - .RequireParentTag("div")) - .Build() - ]; - ImmutableArray documentDescriptors = - [ - expectedDescriptors[0], + .TagMatchingRule(tagName: "a", parentTagName: "div") + .Build(), TagHelperDescriptorBuilder.CreateTagHelper("TestType2", "TestAssembly") - .TagMatchingRuleDescriptor( - rule => rule - .RequireTagName("strong") - .RequireParentTag("div")) + .TagMatchingRule(tagName: "strong", parentTagName: "div") .Build() ]; - var documentContext = TagHelperDocumentContext.Create(string.Empty, documentDescriptors); - // Act - var descriptors = TagHelperFacts.GetTagHelpersGivenTag(documentContext, "a", "div"); + var documentContext = TagHelperDocumentContext.Create(tagHelpers); - // Assert - Assert.Equal(expectedDescriptors, descriptors); + var result = TagHelperFacts.GetTagHelpersGivenTag( + documentContext, + tagName: "a", + parentTag: "div"); + + Assert.Same(tagHelpers[0], Assert.Single(result)); } [Fact] public void GetTagHelpersGivenTag_RestrictsTagHelpersBasedOnTagHelperPrefix() { - // Arrange - ImmutableArray expectedDescriptors = + TagHelperCollection tagHelpers = [ TagHelperDescriptorBuilder.CreateTagHelper("TestType", "TestAssembly") - .TagMatchingRuleDescriptor(rule => rule.RequireTagName("strong")) - .Build() - ]; - ImmutableArray documentDescriptors = - [ - expectedDescriptors[0], + .TagMatchingRule(tagName: "strong") + .Build(), TagHelperDescriptorBuilder.CreateTagHelper("TestType2", "TestAssembly") - .TagMatchingRuleDescriptor(rule => rule.RequireTagName("thstrong")) + .TagMatchingRule(tagName: "thstrong") .Build() ]; - var documentContext = TagHelperDocumentContext.Create("th", documentDescriptors); - // Act - var descriptors = TagHelperFacts.GetTagHelpersGivenTag(documentContext, "thstrong", "div"); + var documentContext = TagHelperDocumentContext.Create(prefix: "th", tagHelpers); - // Assert - Assert.Equal(expectedDescriptors, descriptors); + var result = TagHelperFacts.GetTagHelpersGivenTag( + documentContext, + tagName: "thstrong", + parentTag: "div"); + + Assert.Same(tagHelpers[0], Assert.Single(result)); } [Fact] public void GetTagHelpersGivenTag_RestrictsTagHelpersBasedOnParent() { - // Arrange - ImmutableArray expectedDescriptors = + TagHelperCollection tagHelpers = [ TagHelperDescriptorBuilder.CreateTagHelper("TestType", "TestAssembly") - .TagMatchingRuleDescriptor( - rule => rule - .RequireTagName("strong") - .RequireParentTag("div")) - .Build() - ]; - ImmutableArray documentDescriptors = - [ - expectedDescriptors[0], + .TagMatchingRule(tagName: "strong", parentTagName: "div") + .Build(), TagHelperDescriptorBuilder.CreateTagHelper("TestType2", "TestAssembly") - .TagMatchingRuleDescriptor( - rule => rule - .RequireTagName("strong") - .RequireParentTag("p")) + .TagMatchingRule(tagName: "strong", parentTagName: "p") .Build() ]; - var documentContext = TagHelperDocumentContext.Create(string.Empty, documentDescriptors); - // Act - var descriptors = TagHelperFacts.GetTagHelpersGivenTag(documentContext, "strong", "div"); + var documentContext = TagHelperDocumentContext.Create(tagHelpers); - // Assert - Assert.Equal(expectedDescriptors, descriptors); + var result = TagHelperFacts.GetTagHelpersGivenTag( + documentContext, + tagName: "strong", + parentTag: "div"); + + Assert.Same(tagHelpers[0], Assert.Single(result)); } [Fact] public void GetTagHelpersGivenParent_AllowsRootParentTag() { - // Arrange - ImmutableArray documentDescriptors = + TagHelperCollection tagHelpers = [ TagHelperDescriptorBuilder.CreateTagHelper("TestType", "TestAssembly") - .TagMatchingRuleDescriptor(rule => rule.RequireTagName("div")) + .TagMatchingRule(tagName: "div") .Build() ]; - var documentContext = TagHelperDocumentContext.Create(string.Empty, documentDescriptors); - // Act - var descriptors = TagHelperFacts.GetTagHelpersGivenParent(documentContext, parentTag: null /* root */); + var documentContext = TagHelperDocumentContext.Create(tagHelpers); + + var result = TagHelperFacts.GetTagHelpersGivenParent( + documentContext, + parentTag: null /* root */); - // Assert - Assert.Equal(documentDescriptors, descriptors); + Assert.Equal(tagHelpers, result); } [Fact] public void GetTagHelpersGivenParent_AllowsRootParentTagForParentRestrictedTagHelperDescriptors() { - // Arrange - ImmutableArray documentDescriptors = + TagHelperCollection tagHelpers = [ TagHelperDescriptorBuilder.CreateTagHelper("DivTagHelper", "TestAssembly") - .TagMatchingRuleDescriptor(rule => rule.RequireTagName("div")) + .TagMatchingRule(tagName: "div") .Build(), TagHelperDescriptorBuilder.CreateTagHelper("PTagHelper", "TestAssembly") - .TagMatchingRuleDescriptor(rule => rule - .RequireTagName("p") - .RequireParentTag("body")) + .TagMatchingRule(tagName: "p", parentTagName: "body") .Build() ]; - var documentContext = TagHelperDocumentContext.Create(string.Empty, documentDescriptors); - // Act - var descriptors = TagHelperFacts.GetTagHelpersGivenParent(documentContext, parentTag: null /* root */); + var documentContext = TagHelperDocumentContext.Create(tagHelpers); + + var result = TagHelperFacts.GetTagHelpersGivenParent( + documentContext, + parentTag: null /* root */); - // Assert - var descriptor = Assert.Single(descriptors); - Assert.Equal(documentDescriptors[0], descriptor); + Assert.Same(tagHelpers[0], Assert.Single(result)); } [Fact] public void GetTagHelpersGivenParent_AllowsUnspecifiedParentTagHelpers() { - // Arrange - ImmutableArray documentDescriptors = + TagHelperCollection tagHelpers = [ TagHelperDescriptorBuilder.CreateTagHelper("TestType", "TestAssembly") - .TagMatchingRuleDescriptor(rule => rule.RequireTagName("div")) + .TagMatchingRule(tagName: "div") .Build() ]; - var documentContext = TagHelperDocumentContext.Create(string.Empty, documentDescriptors); - // Act - var descriptors = TagHelperFacts.GetTagHelpersGivenParent(documentContext, "p"); + var documentContext = TagHelperDocumentContext.Create(tagHelpers); - // Assert - Assert.Equal(documentDescriptors, descriptors); + var result = TagHelperFacts.GetTagHelpersGivenParent( + documentContext, + parentTag: "p"); + + Assert.Equal(tagHelpers, result); } [Fact] public void GetTagHelpersGivenParent_RestrictsTagHelpersBasedOnParent() { - // Arrange - ImmutableArray expectedDescriptors = + TagHelperCollection tagHelpers = [ TagHelperDescriptorBuilder.CreateTagHelper("TestType", "TestAssembly") - .TagMatchingRuleDescriptor( - rule => rule - .RequireTagName("p") - .RequireParentTag("div")) - .Build() - ]; - ImmutableArray documentDescriptors = - [ - expectedDescriptors[0], + .TagMatchingRule(tagName: "p", parentTagName: "div") + .Build(), TagHelperDescriptorBuilder.CreateTagHelper("TestType2", "TestAssembly") - .TagMatchingRuleDescriptor( - rule => rule - .RequireTagName("strong") - .RequireParentTag("p")) + .TagMatchingRule(tagName: "strong", parentTagName: "p") .Build() ]; - var documentContext = TagHelperDocumentContext.Create(string.Empty, documentDescriptors); - // Act - var descriptors = TagHelperFacts.GetTagHelpersGivenParent(documentContext, "div"); + var documentContext = TagHelperDocumentContext.Create(tagHelpers); + + var result = TagHelperFacts.GetTagHelpersGivenParent( + documentContext, + parentTag: "div"); - // Assert - Assert.Equal(expectedDescriptors, descriptors); + Assert.Same(tagHelpers[0], Assert.Single(result)); } } diff --git a/src/Razor/test/Microsoft.CodeAnalysis.Razor.Workspaces.Test/Tooltip/ProjectAvailabilityTests.cs b/src/Razor/test/Microsoft.CodeAnalysis.Razor.Workspaces.Test/Tooltip/ProjectAvailabilityTests.cs index d5aa947c690..760d2c9f28f 100644 --- a/src/Razor/test/Microsoft.CodeAnalysis.Razor.Workspaces.Test/Tooltip/ProjectAvailabilityTests.cs +++ b/src/Razor/test/Microsoft.CodeAnalysis.Razor.Workspaces.Test/Tooltip/ProjectAvailabilityTests.cs @@ -1,7 +1,6 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -using System.Collections.Immutable; using System.Threading.Tasks; using Microsoft.AspNetCore.Razor.Language; using Microsoft.AspNetCore.Razor.Test.Common; @@ -32,8 +31,7 @@ public async Task GetProjectAvailabilityText_OneProject_ReturnsNull() builder.TagMatchingRule(rule => rule.TagName = "Test"); var tagHelperTypeName = "TestNamespace.TestTagHelper"; builder.TypeName = tagHelperTypeName; - var tagHelpers = ImmutableArray.Create(builder.Build()); - var projectWorkspaceState = ProjectWorkspaceState.Create(tagHelpers); + var projectWorkspaceState = ProjectWorkspaceState.Create([builder.Build()]); var hostProject = new HostProject( "C:/path/to/project.csproj", @@ -70,8 +68,7 @@ public async Task GetProjectAvailabilityText_AvailableInAllProjects_ReturnsNull( builder.TagMatchingRule(rule => rule.TagName = "Test"); var tagHelperTypeName = "TestNamespace.TestTagHelper"; builder.TypeName = tagHelperTypeName; - var tagHelpers = ImmutableArray.Create(builder.Build()); - var projectWorkspaceState = ProjectWorkspaceState.Create(tagHelpers); + var projectWorkspaceState = ProjectWorkspaceState.Create([builder.Build()]); var hostProject1 = new HostProject( "C:/path/to/project.csproj", @@ -119,8 +116,7 @@ public async Task GetProjectAvailabilityText_NotAvailableInAllProjects_ReturnsTe builder.TagMatchingRule(rule => rule.TagName = "Test"); var tagHelperTypeName = "TestNamespace.TestTagHelper"; builder.TypeName = tagHelperTypeName; - var tagHelpers = ImmutableArray.Create(builder.Build()); - var projectWorkspaceState = ProjectWorkspaceState.Create(tagHelpers); + var projectWorkspaceState = ProjectWorkspaceState.Create([builder.Build()]); var hostProject1 = new HostProject( "C:/path/to/project.csproj", diff --git a/src/Razor/test/Microsoft.VisualStudio.LanguageServices.Razor.Test/Discovery/OutOfProcTagHelperResolverTest.TestResolver.cs b/src/Razor/test/Microsoft.VisualStudio.LanguageServices.Razor.Test/Discovery/OutOfProcTagHelperResolverTest.TestResolver.cs index 7a985e2aa79..d319b8b9cb4 100644 --- a/src/Razor/test/Microsoft.VisualStudio.LanguageServices.Razor.Test/Discovery/OutOfProcTagHelperResolverTest.TestResolver.cs +++ b/src/Razor/test/Microsoft.VisualStudio.LanguageServices.Razor.Test/Discovery/OutOfProcTagHelperResolverTest.TestResolver.cs @@ -24,15 +24,31 @@ private class TestResolver( ITelemetryReporter telemetryReporter) : OutOfProcTagHelperResolver(remoteServiceInvoker, loggerFactory, telemetryReporter) { - public Func>>? OnResolveOutOfProcess { get; init; } + public Func? OnResolveOutOfProcess { get; init; } - public Func>>? OnResolveInProcess { get; init; } + public Func? OnResolveInProcess { get; init; } - protected override ValueTask> ResolveTagHelpersOutOfProcessAsync(Project project, ProjectSnapshot projectSnapshot, CancellationToken cancellationToken) - => OnResolveOutOfProcess?.Invoke(projectSnapshot) ?? default; + protected override ValueTask ResolveTagHelpersOutOfProcessAsync(Project project, ProjectSnapshot projectSnapshot, CancellationToken cancellationToken) + { + var handler = OnResolveOutOfProcess; + if (handler is not null) + { + return new(handler.Invoke(projectSnapshot)); + } - protected override ValueTask> ResolveTagHelpersInProcessAsync(Project project, ProjectSnapshot projectSnapshot, CancellationToken cancellationToken) - => OnResolveInProcess?.Invoke(projectSnapshot) ?? default; + return default; + } + + protected override ValueTask ResolveTagHelpersInProcessAsync(Project project, ProjectSnapshot projectSnapshot, CancellationToken cancellationToken) + { + var handler = OnResolveInProcess; + if (handler is not null) + { + return new(handler.Invoke(projectSnapshot)); + } + + return default; + } public ImmutableArray PublicProduceChecksumsFromDelta(ProjectId projectId, int lastResultId, TagHelperDeltaResult deltaResult) => ProduceChecksumsFromDelta(projectId, lastResultId, deltaResult); diff --git a/src/Razor/test/Microsoft.VisualStudio.LanguageServices.Razor.Test/Discovery/OutOfProcTagHelperResolverTest.cs b/src/Razor/test/Microsoft.VisualStudio.LanguageServices.Razor.Test/Discovery/OutOfProcTagHelperResolverTest.cs index 150e9af6804..2ace1071c4f 100644 --- a/src/Razor/test/Microsoft.VisualStudio.LanguageServices.Razor.Test/Discovery/OutOfProcTagHelperResolverTest.cs +++ b/src/Razor/test/Microsoft.VisualStudio.LanguageServices.Razor.Test/Discovery/OutOfProcTagHelperResolverTest.cs @@ -93,7 +93,7 @@ await _projectManager.UpdateAsync(updater => Assert.Same(projectSnapshot, p); - return new([]); + return []; }, }; @@ -101,6 +101,7 @@ await _projectManager.UpdateAsync(updater => // Assert Assert.True(calledOutOfProcess); + Assert.NotNull(result); Assert.Empty(result); } @@ -125,14 +126,14 @@ await _projectManager.UpdateAsync(updater => calledOutOfProcess = true; Assert.Same(projectSnapshot, p); - return new([]); + return []; }, OnResolveInProcess = (p) => { calledInProcess = true; Assert.Same(projectSnapshot, p); - return new([]); + return []; }, }; @@ -141,6 +142,7 @@ await _projectManager.UpdateAsync(updater => // Assert Assert.True(calledOutOfProcess); Assert.False(calledInProcess); + Assert.NotNull(result); Assert.Empty(result); } @@ -172,7 +174,7 @@ await _projectManager.UpdateAsync(updater => calledInProcess = true; Assert.Same(projectSnapshot, p); - return new([]); + return []; }, }; @@ -181,6 +183,7 @@ await _projectManager.UpdateAsync(updater => // Assert Assert.True(calledOutOfProcess); Assert.True(calledInProcess); + Assert.NotNull(result); Assert.Empty(result); } @@ -205,7 +208,7 @@ await _projectManager.UpdateAsync(updater => Assert.Same(projectSnapshot, p); - return new([]); + return []; }, }; @@ -213,6 +216,7 @@ await _projectManager.UpdateAsync(updater => // Assert Assert.True(calledInProcess); + Assert.NotNull(result); Assert.Empty(result); } @@ -238,7 +242,7 @@ await _projectManager.UpdateAsync(updater => calledInProcess = true; Assert.Same(projectSnapshot, p); - return new([]); + return []; }, OnResolveOutOfProcess = (p) => { diff --git a/src/Razor/test/Microsoft.VisualStudio.LanguageServices.Razor.Test/Discovery/ProjectStateUpdaterTest.cs b/src/Razor/test/Microsoft.VisualStudio.LanguageServices.Razor.Test/Discovery/ProjectStateUpdaterTest.cs index e9cc8f0e517..e3c399afb17 100644 --- a/src/Razor/test/Microsoft.VisualStudio.LanguageServices.Razor.Test/Discovery/ProjectStateUpdaterTest.cs +++ b/src/Razor/test/Microsoft.VisualStudio.LanguageServices.Razor.Test/Discovery/ProjectStateUpdaterTest.cs @@ -2,7 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. using System; -using System.Collections.Immutable; using System.Threading; using System.Threading.Tasks; using Microsoft.AspNetCore.Razor.Language; @@ -36,7 +35,7 @@ protected override Task InitializeAsync() var solution = Workspace.CurrentSolution.AddProject(projectInfo); Workspace.TryApplyChanges(solution); - ImmutableArray tagHelpers = [ + TagHelperCollection tagHelpers = [ TagHelperDescriptorBuilder.CreateTagHelper("ResolvableTagHelper", "TestAssembly").Build()]; _projectWorkspaceState = ProjectWorkspaceState.Create(tagHelpers); _tagHelperResolver = new TestTagHelperResolver(tagHelpers); @@ -164,6 +163,6 @@ await _projectManager.UpdateAsync(updater => // Assert var newProjectSnapshot = _projectManager.GetRequiredProject(s_hostProject.Key); - Assert.Equal(_tagHelperResolver.TagHelpers, await newProjectSnapshot.GetTagHelpersAsync(DisposalToken)); + Assert.Equal(_tagHelperResolver.TagHelpers, await newProjectSnapshot.GetTagHelpersAsync(DisposalToken)); } } diff --git a/src/Razor/test/Microsoft.VisualStudio.LanguageServices.Razor.Test/LiveShare/Guest/ProjectSnapshotSynchronizationServiceTest.cs b/src/Razor/test/Microsoft.VisualStudio.LanguageServices.Razor.Test/LiveShare/Guest/ProjectSnapshotSynchronizationServiceTest.cs index 2191fd2128a..db1537fc0f3 100644 --- a/src/Razor/test/Microsoft.VisualStudio.LanguageServices.Razor.Test/LiveShare/Guest/ProjectSnapshotSynchronizationServiceTest.cs +++ b/src/Razor/test/Microsoft.VisualStudio.LanguageServices.Razor.Test/LiveShare/Guest/ProjectSnapshotSynchronizationServiceTest.cs @@ -66,11 +66,7 @@ public async Task InitializeAsync_RetrievesHostProjectManagerStateAndInitializes Assert.Same(RazorConfiguration.Default, project.Configuration); var tagHelpers = await project.GetTagHelpersAsync(DisposalToken); - Assert.Equal(_projectWorkspaceStateWithTagHelpers.TagHelpers.Length, tagHelpers.Length); - for (var i = 0; i < _projectWorkspaceStateWithTagHelpers.TagHelpers.Length; i++) - { - Assert.Same(_projectWorkspaceStateWithTagHelpers.TagHelpers[i], tagHelpers[i]); - } + Assert.SameItems(_projectWorkspaceStateWithTagHelpers.TagHelpers, tagHelpers); } [UIFact] @@ -101,11 +97,7 @@ public async Task UpdateGuestProjectManager_ProjectAdded() Assert.Same(RazorConfiguration.Default, project.Configuration); var tagHelpers = await project.GetTagHelpersAsync(DisposalToken); - Assert.Equal(_projectWorkspaceStateWithTagHelpers.TagHelpers.Length, tagHelpers.Length); - for (var i = 0; i < _projectWorkspaceStateWithTagHelpers.TagHelpers.Length; i++) - { - Assert.Same(_projectWorkspaceStateWithTagHelpers.TagHelpers[i], tagHelpers[i]); - } + Assert.SameItems(_projectWorkspaceStateWithTagHelpers.TagHelpers, tagHelpers); } [UIFact] @@ -228,10 +220,6 @@ await _projectManager.UpdateAsync(updater => Assert.Same(RazorConfiguration.Default, project.Configuration); var tagHelpers = await project.GetTagHelpersAsync(DisposalToken); - Assert.Equal(_projectWorkspaceStateWithTagHelpers.TagHelpers.Length, tagHelpers.Length); - for (var i = 0; i < _projectWorkspaceStateWithTagHelpers.TagHelpers.Length; i++) - { - Assert.Same(_projectWorkspaceStateWithTagHelpers.TagHelpers[i], tagHelpers[i]); - } + Assert.SameItems(_projectWorkspaceStateWithTagHelpers.TagHelpers, tagHelpers); } } diff --git a/src/Razor/test/Microsoft.VisualStudio.LanguageServices.Razor.Test/LiveShare/Host/ProjectSnapshotManagerProxyTest.cs b/src/Razor/test/Microsoft.VisualStudio.LanguageServices.Razor.Test/LiveShare/Host/ProjectSnapshotManagerProxyTest.cs index 97dc44e30b3..f4df85a3959 100644 --- a/src/Razor/test/Microsoft.VisualStudio.LanguageServices.Razor.Test/LiveShare/Host/ProjectSnapshotManagerProxyTest.cs +++ b/src/Razor/test/Microsoft.VisualStudio.LanguageServices.Razor.Test/LiveShare/Host/ProjectSnapshotManagerProxyTest.cs @@ -2,7 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. using System; -using System.Collections.Immutable; using System.Threading.Tasks; using Microsoft.AspNetCore.Razor; using Microsoft.AspNetCore.Razor.Language; @@ -244,10 +243,10 @@ await projectManager.UpdateAsync(updater => private static Action AssertProjectSnapshotHandle( string expectedFilePath, - ImmutableArray expectedTagHelpers) + TagHelperCollection expectedTagHelpers) => handle => { Assert.Equal(expectedFilePath, handle.FilePath.ToString()); - Assert.Equal(expectedTagHelpers, handle.ProjectWorkspaceState.TagHelpers); + Assert.Equal(expectedTagHelpers, handle.ProjectWorkspaceState.TagHelpers); }; } diff --git a/src/Razor/test/Microsoft.VisualStudio.LanguageServices.Razor.Test/LiveShare/SerializationTest.cs b/src/Razor/test/Microsoft.VisualStudio.LanguageServices.Razor.Test/LiveShare/SerializationTest.cs index ce58c110c25..d621aa9d9b6 100644 --- a/src/Razor/test/Microsoft.VisualStudio.LanguageServices.Razor.Test/LiveShare/SerializationTest.cs +++ b/src/Razor/test/Microsoft.VisualStudio.LanguageServices.Razor.Test/LiveShare/SerializationTest.cs @@ -2,7 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. using System; -using System.Collections.Immutable; using Microsoft.AspNetCore.Razor.Language; using Microsoft.AspNetCore.Razor.Test.Common; using Microsoft.CodeAnalysis.Razor.ProjectSystem; @@ -19,9 +18,9 @@ public class SerializationTest(ITestOutputHelper testOutput) : ToolingTestBase(t public void ProjectSnapshotHandleProxy_RoundTripsProperly() { // Arrange - var tagHelpers = ImmutableArray.Create( + TagHelperCollection tagHelpers = [ TagHelperDescriptorBuilder.CreateTagHelper("TestTagHelper", "TestAssembly").Build(), - TagHelperDescriptorBuilder.CreateTagHelper("TestTagHelper2", "TestAssembly2").Build()); + TagHelperDescriptorBuilder.CreateTagHelper("TestTagHelper2", "TestAssembly2").Build()]; var projectWorkspaceState = ProjectWorkspaceState.Create(tagHelpers); var expectedConfiguration = RazorConfiguration.Default; diff --git a/src/Razor/test/Microsoft.VisualStudio.LanguageServices.Razor.Test/ProjectSystem/ProjectSnapshotManagerTest.cs b/src/Razor/test/Microsoft.VisualStudio.LanguageServices.Razor.Test/ProjectSystem/ProjectSnapshotManagerTest.cs index eb78d7b7185..4b8422cddb8 100644 --- a/src/Razor/test/Microsoft.VisualStudio.LanguageServices.Razor.Test/ProjectSystem/ProjectSnapshotManagerTest.cs +++ b/src/Razor/test/Microsoft.VisualStudio.LanguageServices.Razor.Test/ProjectSystem/ProjectSnapshotManagerTest.cs @@ -2,7 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. using System.Collections.Generic; -using System.Collections.Immutable; using System.Linq; using System.Threading; using System.Threading.Tasks; @@ -51,12 +50,10 @@ public class ProjectSnapshotManagerTest : VisualStudioWorkspaceTestBase public ProjectSnapshotManagerTest(ITestOutputHelper testOutput) : base(testOutput) { - var someTagHelpers = ImmutableArray.Create( - TagHelperDescriptorBuilder.CreateTagHelper("Test1", "TestAssembly").Build()); - _projectManager = CreateProjectSnapshotManager(); - _projectWorkspaceStateWithTagHelpers = ProjectWorkspaceState.Create(someTagHelpers); + _projectWorkspaceStateWithTagHelpers = ProjectWorkspaceState.Create([ + TagHelperDescriptorBuilder.CreateTagHelper("Test1", "TestAssembly").Build()]); _sourceText = SourceText.From("Hello world"); } @@ -282,11 +279,7 @@ await _projectManager.UpdateAsync(updater => .GetRequiredProject(s_hostProject.Key) .GetTagHelpersAsync(DisposalToken); - Assert.Equal(originalTagHelpers.Length, newTagHelpers.Length); - for (var i = 0; i < originalTagHelpers.Length; i++) - { - Assert.Same(originalTagHelpers[i], newTagHelpers[i]); - } + Assert.SameItems(originalTagHelpers, newTagHelpers); } [UIFact] @@ -412,11 +405,7 @@ await _projectManager.UpdateAsync(updater => .GetRequiredProject(s_hostProject.Key) .GetTagHelpersAsync(DisposalToken); - Assert.Equal(originalTagHelpers.Length, newTagHelpers.Length); - for (var i = 0; i < originalTagHelpers.Length; i++) - { - Assert.Same(originalTagHelpers[i], newTagHelpers[i]); - } + Assert.SameItems(originalTagHelpers, newTagHelpers); } [UIFact] diff --git a/src/Razor/test/Microsoft.VisualStudio.LegacyEditor.Razor.Test/Completion/LegacyTagHelperCompletionServiceTest.cs b/src/Razor/test/Microsoft.VisualStudio.LegacyEditor.Razor.Test/Completion/LegacyTagHelperCompletionServiceTest.cs index 0bc031aac44..623a43df8fe 100644 --- a/src/Razor/test/Microsoft.VisualStudio.LegacyEditor.Razor.Test/Completion/LegacyTagHelperCompletionServiceTest.cs +++ b/src/Razor/test/Microsoft.VisualStudio.LegacyEditor.Razor.Test/Completion/LegacyTagHelperCompletionServiceTest.cs @@ -3,7 +3,6 @@ using System.Collections.Generic; using System.Collections.Immutable; -using System.Linq; using Microsoft.AspNetCore.Razor.Language; using Microsoft.AspNetCore.Razor.Test.Common; using Microsoft.CodeAnalysis.Razor.Completion; @@ -18,12 +17,10 @@ public class LegacyTagHelperCompletionServiceTest(ITestOutputHelper testOutput) [WorkItem("https://devdiv.visualstudio.com/DevDiv/_workitems/edit/1452432")] public void GetAttributeCompletions_OnlyIndexerNamePrefix() { - // Arrange - ImmutableArray documentDescriptors = + TagHelperCollection tagHelpers = [ TagHelperDescriptorBuilder.CreateTagHelper("FormTagHelper", "TestAssembly") - .TagMatchingRuleDescriptor(rule => rule - .RequireTagName("form")) + .TagMatchingRule(tagName: "form") .BoundAttributeDescriptor(attribute => attribute .TypeName("System.Collections.Generic.IDictionary") .PropertyName("RouteValues") @@ -33,32 +30,29 @@ public void GetAttributeCompletions_OnlyIndexerNamePrefix() var expectedCompletions = AttributeCompletionResult.Create(new() { - ["asp-route-..."] = [documentDescriptors[0].BoundAttributes.Last()] + ["asp-route-..."] = [tagHelpers[0].BoundAttributes[^1]] }); var completionContext = BuildAttributeCompletionContext( - documentDescriptors, + tagHelpers, existingCompletions: [], attributes: [], currentTagName: "form"); + var service = CreateTagHelperCompletionFactsService(); - // Act var completions = service.GetAttributeCompletions(completionContext); - // Assert AssertCompletionsAreEquivalent(expectedCompletions, completions); } [Fact] public void GetAttributeCompletions_BoundDictionaryAttribute_ReturnsPrefixIndexerAndFullSetter() { - // Arrange - ImmutableArray documentDescriptors = + TagHelperCollection tagHelpers = [ TagHelperDescriptorBuilder.CreateTagHelper("FormTagHelper", "TestAssembly") - .TagMatchingRuleDescriptor(rule => rule - .RequireTagName("form")) + .TagMatchingRule(tagName: "form") .BoundAttributeDescriptor(attribute => attribute .Name("asp-all-route-data") .TypeName("System.Collections.Generic.IDictionary") @@ -69,41 +63,33 @@ public void GetAttributeCompletions_BoundDictionaryAttribute_ReturnsPrefixIndexe var expectedCompletions = AttributeCompletionResult.Create(new() { - ["asp-all-route-data"] = [documentDescriptors[0].BoundAttributes.Last()], - ["asp-route-..."] = [documentDescriptors[0].BoundAttributes.Last()] + ["asp-all-route-data"] = [tagHelpers[0].BoundAttributes[^1]], + ["asp-route-..."] = [tagHelpers[0].BoundAttributes[^1]] }); var completionContext = BuildAttributeCompletionContext( - documentDescriptors, + tagHelpers, existingCompletions: [], attributes: [], currentTagName: "form"); + var service = CreateTagHelperCompletionFactsService(); - // Act var completions = service.GetAttributeCompletions(completionContext); - // Assert AssertCompletionsAreEquivalent(expectedCompletions, completions); } [Fact] public void GetAttributeCompletions_RequiredBoundDictionaryAttribute_ReturnsPrefixIndexerAndFullSetter() { - // Arrange - ImmutableArray documentDescriptors = + TagHelperCollection tagHelpers = [ TagHelperDescriptorBuilder.CreateTagHelper("FormTagHelper", "TestAssembly") - .TagMatchingRuleDescriptor(rule => rule - .RequireTagName("form") - .RequireAttributeDescriptor(builder => - { - builder.Name = "asp-route-"; - builder.NameComparison = RequiredAttributeNameComparison.PrefixMatch; - })) - .TagMatchingRuleDescriptor(rule => rule - .RequireTagName("form") - .RequireAttributeDescriptor(builder => builder.Name = "asp-all-route-data")) + .TagMatchingRule(tagName: "form", static b => b + .RequiredAttribute(name: "asp-route-", nameComparison: RequiredAttributeNameComparison.PrefixMatch)) + .TagMatchingRule(tagName: "form", static b => b + .RequiredAttribute(name: "asp-all-route-data")) .BoundAttributeDescriptor(attribute => attribute .Name("asp-all-route-data") .TypeName("System.Collections.Generic.IDictionary") @@ -114,41 +100,38 @@ public void GetAttributeCompletions_RequiredBoundDictionaryAttribute_ReturnsPref var expectedCompletions = AttributeCompletionResult.Create(new() { - ["asp-all-route-data"] = [documentDescriptors[0].BoundAttributes.Last()], - ["asp-route-..."] = [documentDescriptors[0].BoundAttributes.Last()] + ["asp-all-route-data"] = [tagHelpers[0].BoundAttributes[^1]], + ["asp-route-..."] = [tagHelpers[0].BoundAttributes[^1]] }); var completionContext = BuildAttributeCompletionContext( - documentDescriptors, + tagHelpers, existingCompletions: [], attributes: [], currentTagName: "form"); + var service = CreateTagHelperCompletionFactsService(); - // Act var completions = service.GetAttributeCompletions(completionContext); - // Assert AssertCompletionsAreEquivalent(expectedCompletions, completions); } [Fact] public void GetAttributeCompletions_DoesNotReturnCompletionsForAlreadySuppliedAttributes() { - // Arrange - ImmutableArray documentDescriptors = + TagHelperCollection tagHelpers = [ TagHelperDescriptorBuilder.CreateTagHelper("DivTagHelper", "TestAssembly") - .TagMatchingRuleDescriptor(rule => rule - .RequireTagName("div") - .RequireAttributeDescriptor(attribute => attribute.Name("repeat"))) + .TagMatchingRule(tagName: "div", static b => b + .RequiredAttribute(name: "repeat")) .BoundAttributeDescriptor(attribute => attribute .Name("visible") .TypeName(typeof(bool).FullName) .PropertyName("Visible")) .Build(), TagHelperDescriptorBuilder.CreateTagHelper("StyleTagHelper", "TestAssembly") - .TagMatchingRuleDescriptor(rule => rule.RequireTagName("*")) + .TagMatchingRule(tagName: "*") .BoundAttributeDescriptor(attribute => attribute .Name("class") .TypeName(typeof(string).FullName) @@ -159,43 +142,39 @@ public void GetAttributeCompletions_DoesNotReturnCompletionsForAlreadySuppliedAt var expectedCompletions = AttributeCompletionResult.Create(new() { ["onclick"] = [], - ["visible"] = [documentDescriptors[0].BoundAttributes.Last()] + ["visible"] = [tagHelpers[0].BoundAttributes[^1]] }); - var existingCompletions = new[] { "onclick" }; var completionContext = BuildAttributeCompletionContext( - documentDescriptors, - existingCompletions, + tagHelpers, + existingCompletions: ["onclick"], attributes: [ KeyValuePair.Create("class", "something"), KeyValuePair.Create("repeat", "4")], currentTagName: "div"); + var service = CreateTagHelperCompletionFactsService(); - // Act var completions = service.GetAttributeCompletions(completionContext); - // Assert AssertCompletionsAreEquivalent(expectedCompletions, completions); } [Fact] public void GetAttributeCompletions_ReturnsCompletionForAlreadySuppliedAttribute_IfCurrentAttributeMatches() { - // Arrange - ImmutableArray documentDescriptors = + TagHelperCollection tagHelpers = [ TagHelperDescriptorBuilder.CreateTagHelper("DivTagHelper", "TestAssembly") - .TagMatchingRuleDescriptor(rule => rule - .RequireTagName("div") - .RequireAttributeDescriptor(attribute => attribute.Name("repeat"))) + .TagMatchingRule(tagName: "div", static b => b + .RequiredAttribute(name: "repeat")) .BoundAttributeDescriptor(attribute => attribute .Name("visible") .TypeName(typeof(bool).FullName) .PropertyName("Visible")) .Build(), TagHelperDescriptorBuilder.CreateTagHelper("StyleTagHelper", "TestAssembly") - .TagMatchingRuleDescriptor(rule => rule.RequireTagName("*")) + .TagMatchingRule("*") .BoundAttributeDescriptor(attribute => attribute .Name("class") .TypeName(typeof(string).FullName) @@ -206,45 +185,41 @@ public void GetAttributeCompletions_ReturnsCompletionForAlreadySuppliedAttribute var expectedCompletions = AttributeCompletionResult.Create(new() { ["onclick"] = [], - ["visible"] = [documentDescriptors[0].BoundAttributes.Last()] + ["visible"] = [tagHelpers[0].BoundAttributes[^1]] }); - var existingCompletions = new[] { "onclick" }; var completionContext = BuildAttributeCompletionContext( - documentDescriptors, - existingCompletions, + tagHelpers, + existingCompletions: ["onclick"], attributes: [ KeyValuePair.Create("class", "something"), KeyValuePair.Create("repeat", "4"), KeyValuePair.Create("visible", "false")], currentTagName: "div", currentAttributeName: "visible"); + var service = CreateTagHelperCompletionFactsService(); - // Act var completions = service.GetAttributeCompletions(completionContext); - // Assert AssertCompletionsAreEquivalent(expectedCompletions, completions); } [Fact] public void GetAttributeCompletions_DoesNotReturnAlreadySuppliedAttribute_IfCurrentAttributeDoesNotMatch() { - // Arrange - ImmutableArray documentDescriptors = + TagHelperCollection tagHelpers = [ TagHelperDescriptorBuilder.CreateTagHelper("DivTagHelper", "TestAssembly") - .TagMatchingRuleDescriptor(rule => rule - .RequireTagName("div") - .RequireAttributeDescriptor(attribute => attribute.Name("repeat"))) + .TagMatchingRule(tagName: "div", static b => b + .RequiredAttribute(name: "repeat")) .BoundAttributeDescriptor(attribute => attribute .Name("visible") .TypeName(typeof(bool).FullName) .PropertyName("Visible")) .Build(), TagHelperDescriptorBuilder.CreateTagHelper("StyleTagHelper", "TestAssembly") - .TagMatchingRuleDescriptor(rule => rule.RequireTagName("*")) + .TagMatchingRule("*") .BoundAttributeDescriptor(attribute => attribute .Name("class") .TypeName(typeof(string).FullName) @@ -257,40 +232,35 @@ public void GetAttributeCompletions_DoesNotReturnAlreadySuppliedAttribute_IfCurr ["onclick"] = [] }); - var existingCompletions = new[] { "onclick" }; var completionContext = BuildAttributeCompletionContext( - documentDescriptors, - existingCompletions, + tagHelpers, + existingCompletions: ["onclick"], attributes: [ KeyValuePair.Create("class", "something"), KeyValuePair.Create("repeat", "4"), KeyValuePair.Create("visible", "false")], currentTagName: "div", currentAttributeName: "repeat"); + var service = CreateTagHelperCompletionFactsService(); - // Act var completions = service.GetAttributeCompletions(completionContext); - // Assert AssertCompletionsAreEquivalent(expectedCompletions, completions); } [Fact] public void GetAttributeCompletions_PossibleDescriptorsReturnUnboundRequiredAttributesWithExistingCompletions() { - // Arrange - ImmutableArray documentDescriptors = + TagHelperCollection tagHelpers = [ TagHelperDescriptorBuilder.CreateTagHelper("DivTagHelper", "TestAssembly") - .TagMatchingRuleDescriptor(rule => rule - .RequireTagName("div") - .RequireAttributeDescriptor(attribute => attribute.Name("repeat"))) + .TagMatchingRule(tagName: "div", static b => b + .RequiredAttribute(name: "repeat")) .Build(), TagHelperDescriptorBuilder.CreateTagHelper("StyleTagHelper", "TestAssembly") - .TagMatchingRuleDescriptor(rule => rule - .RequireTagName("*") - .RequireAttributeDescriptor(attribute => attribute.Name("class"))) + .TagMatchingRule(tagName: "*", static b => b + .RequiredAttribute(name: "class")) .Build(), ]; @@ -301,30 +271,26 @@ public void GetAttributeCompletions_PossibleDescriptorsReturnUnboundRequiredAttr ["repeat"] = [] }); - var existingCompletions = new[] { "onclick", "class" }; var completionContext = BuildAttributeCompletionContext( - documentDescriptors, - existingCompletions, + tagHelpers, + existingCompletions: ["onclick", "class"], currentTagName: "div"); + var service = CreateTagHelperCompletionFactsService(); - // Act var completions = service.GetAttributeCompletions(completionContext); - // Assert AssertCompletionsAreEquivalent(expectedCompletions, completions); } [Fact] public void GetAttributeCompletions_PossibleDescriptorsReturnBoundRequiredAttributesWithExistingCompletions() { - // Arrange - ImmutableArray documentDescriptors = + TagHelperCollection tagHelpers = [ TagHelperDescriptorBuilder.CreateTagHelper("DivTagHelper", "TestAssembly") - .TagMatchingRuleDescriptor(rule => rule - .RequireTagName("div") - .RequireAttributeDescriptor(attribute => attribute.Name("repeat"))) + .TagMatchingRule(tagName: "div", static b => b + .RequiredAttribute(name: "repeat")) .BoundAttributeDescriptor(attribute => attribute .Name("repeat") .TypeName(typeof(bool).FullName) @@ -335,9 +301,8 @@ public void GetAttributeCompletions_PossibleDescriptorsReturnBoundRequiredAttrib .PropertyName("Visible")) .Build(), TagHelperDescriptorBuilder.CreateTagHelper("StyleTagHelper", "TestAssembly") - .TagMatchingRuleDescriptor(rule => rule - .RequireTagName("*") - .RequireAttributeDescriptor(attribute => attribute.Name("class"))) + .TagMatchingRule(tagName: "*", static b => b + .RequiredAttribute(name: "class")) .BoundAttributeDescriptor(attribute => attribute .Name("class") .TypeName(typeof(string).FullName) @@ -347,33 +312,30 @@ public void GetAttributeCompletions_PossibleDescriptorsReturnBoundRequiredAttrib var expectedCompletions = AttributeCompletionResult.Create(new() { - ["class"] = [.. documentDescriptors[1].BoundAttributes], + ["class"] = [.. tagHelpers[1].BoundAttributes], ["onclick"] = [], - ["repeat"] = [documentDescriptors[0].BoundAttributes.First()] + ["repeat"] = [tagHelpers[0].BoundAttributes[0]] }); - var existingCompletions = new[] { "onclick" }; var completionContext = BuildAttributeCompletionContext( - documentDescriptors, - existingCompletions, + tagHelpers, + existingCompletions: ["onclick"], currentTagName: "div"); + var service = CreateTagHelperCompletionFactsService(); - // Act var completions = service.GetAttributeCompletions(completionContext); - // Assert AssertCompletionsAreEquivalent(expectedCompletions, completions); } [Fact] public void GetAttributeCompletions_AppliedDescriptorsReturnAllBoundAttributesWithExistingCompletionsForSchemaTags() { - // Arrange - ImmutableArray documentDescriptors = + TagHelperCollection tagHelpers = [ TagHelperDescriptorBuilder.CreateTagHelper("DivTagHelper", "TestAssembly") - .TagMatchingRuleDescriptor(rule => rule.RequireTagName("div")) + .TagMatchingRule("div") .BoundAttributeDescriptor(attribute => attribute .Name("repeat") .TypeName(typeof(bool).FullName) @@ -384,52 +346,49 @@ public void GetAttributeCompletions_AppliedDescriptorsReturnAllBoundAttributesWi .PropertyName("Visible")) .Build(), TagHelperDescriptorBuilder.CreateTagHelper("StyleTagHelper", "TestAssembly") - .TagMatchingRuleDescriptor(rule => rule - .RequireTagName("*") - .RequireAttributeDescriptor(attribute => attribute.Name("class"))) + .TagMatchingRule(tagName: "*", static b => b + .RequiredAttribute(name: "class")) .BoundAttributeDescriptor(attribute => attribute .Name("class") .TypeName(typeof(string).FullName) .PropertyName("Class")) .Build(), TagHelperDescriptorBuilder.CreateTagHelper("StyleTagHelper", "TestAssembly") - .TagMatchingRuleDescriptor(rule => rule.RequireTagName("*")) + .TagMatchingRule(tagName: "*") .BoundAttributeDescriptor(attribute => attribute .Name("visible") .TypeName(typeof(bool).FullName) .PropertyName("Visible")) .Build(), ]; + var expectedCompletions = AttributeCompletionResult.Create(new() { ["onclick"] = [], - ["class"] = [.. documentDescriptors[1].BoundAttributes], - ["repeat"] = [documentDescriptors[0].BoundAttributes.First()], - ["visible"] = [documentDescriptors[0].BoundAttributes.Last(), documentDescriptors[2].BoundAttributes.First()] + ["class"] = [.. tagHelpers[1].BoundAttributes], + ["repeat"] = [tagHelpers[0].BoundAttributes[0]], + ["visible"] = [tagHelpers[0].BoundAttributes[^1], tagHelpers[2].BoundAttributes[0]] }); - var existingCompletions = new[] { "class", "onclick" }; var completionContext = BuildAttributeCompletionContext( - documentDescriptors, - existingCompletions, + tagHelpers, + existingCompletions: ["class", "onclick"], currentTagName: "div"); + var service = CreateTagHelperCompletionFactsService(); - // Act var completions = service.GetAttributeCompletions(completionContext); - // Assert AssertCompletionsAreEquivalent(expectedCompletions, completions); } [Fact] public void GetAttributeCompletions_AppliedTagOutputHintDescriptorsReturnBoundAttributesWithExistingCompletionsForNonSchemaTags() { - // Arrange - ImmutableArray documentDescriptors = + TagHelperCollection tagHelpers = [ TagHelperDescriptorBuilder.CreateTagHelper("CustomTagHelper", "TestAssembly") - .TagMatchingRuleDescriptor(rule => rule.RequireTagName("custom")) + .TagMatchingRule(tagName: "custom") .BoundAttributeDescriptor(attribute => attribute .Name("repeat") .TypeName(typeof(bool).FullName) @@ -441,31 +400,28 @@ public void GetAttributeCompletions_AppliedTagOutputHintDescriptorsReturnBoundAt var expectedCompletions = AttributeCompletionResult.Create(new() { ["class"] = [], - ["repeat"] = [.. documentDescriptors[0].BoundAttributes] + ["repeat"] = [.. tagHelpers[0].BoundAttributes] }); - var existingCompletions = new[] { "class" }; var completionContext = BuildAttributeCompletionContext( - documentDescriptors, - existingCompletions, + tagHelpers, + existingCompletions: ["class"], currentTagName: "custom"); + var service = CreateTagHelperCompletionFactsService(); - // Act var completions = service.GetAttributeCompletions(completionContext); - // Assert AssertCompletionsAreEquivalent(expectedCompletions, completions); } [Fact] public void GetAttributeCompletions_AppliedDescriptorsReturnBoundAttributesCompletionsForNonSchemaTags() { - // Arrange - ImmutableArray documentDescriptors = + TagHelperCollection tagHelpers = [ TagHelperDescriptorBuilder.CreateTagHelper("CustomTagHelper", "TestAssembly") - .TagMatchingRuleDescriptor(rule => rule.RequireTagName("custom")) + .TagMatchingRule(tagName: "custom") .BoundAttributeDescriptor(attribute => attribute .Name("repeat") .TypeName(typeof(bool).FullName) @@ -475,31 +431,28 @@ public void GetAttributeCompletions_AppliedDescriptorsReturnBoundAttributesCompl var expectedCompletions = AttributeCompletionResult.Create(new() { - ["repeat"] = [.. documentDescriptors[0].BoundAttributes] + ["repeat"] = [.. tagHelpers[0].BoundAttributes] }); - var existingCompletions = new[] { "class" }; var completionContext = BuildAttributeCompletionContext( - documentDescriptors, - existingCompletions, + tagHelpers, + existingCompletions: ["class"], currentTagName: "custom"); + var service = CreateTagHelperCompletionFactsService(); - // Act var completions = service.GetAttributeCompletions(completionContext); - // Assert AssertCompletionsAreEquivalent(expectedCompletions, completions); } [Fact] public void GetAttributeCompletions_AppliedDescriptorsReturnBoundAttributesWithExistingCompletionsForSchemaTags() { - // Arrange - ImmutableArray documentDescriptors = + TagHelperCollection tagHelpers = [ TagHelperDescriptorBuilder.CreateTagHelper("DivTagHelper", "TestAssembly") - .TagMatchingRuleDescriptor(rule => rule.RequireTagName("div")) + .TagMatchingRule(tagName: "div") .BoundAttributeDescriptor(attribute => attribute .Name("repeat") .TypeName(typeof(bool).FullName) @@ -510,119 +463,105 @@ public void GetAttributeCompletions_AppliedDescriptorsReturnBoundAttributesWithE var expectedCompletions = AttributeCompletionResult.Create(new() { ["class"] = [], - ["repeat"] = [.. documentDescriptors[0].BoundAttributes] + ["repeat"] = [.. tagHelpers[0].BoundAttributes] }); - var existingCompletions = new[] { "class" }; var completionContext = BuildAttributeCompletionContext( - documentDescriptors, - existingCompletions, + tagHelpers, + existingCompletions: ["class"], currentTagName: "div"); + var service = CreateTagHelperCompletionFactsService(); - // Act var completions = service.GetAttributeCompletions(completionContext); - // Assert AssertCompletionsAreEquivalent(expectedCompletions, completions); } [Fact] public void GetAttributeCompletions_NoDescriptorsReturnsExistingCompletions() { - // Arrange var expectedCompletions = AttributeCompletionResult.Create(new() { - ["class"] = [], + ["class"] = [] }); - var existingCompletions = new[] { "class" }; var completionContext = BuildAttributeCompletionContext( - descriptors: [], - existingCompletions, + tagHelpers: [], + existingCompletions: ["class"], currentTagName: "div"); + var service = CreateTagHelperCompletionFactsService(); - // Act var completions = service.GetAttributeCompletions(completionContext); - // Assert AssertCompletionsAreEquivalent(expectedCompletions, completions); } [Fact] public void GetAttributeCompletions_NoDescriptorsForUnprefixedTagReturnsExistingCompletions() { - // Arrange - ImmutableArray documentDescriptors = + TagHelperCollection tagHelpers = [ TagHelperDescriptorBuilder.CreateTagHelper("DivTagHelper", "TestAssembly") - .TagMatchingRuleDescriptor(rule => rule - .RequireTagName("div") - .RequireAttributeDescriptor(attribute => attribute.Name("special"))) + .TagMatchingRule(tagName: "div", static b => b + .RequiredAttribute(name: "special")) .Build(), ]; var expectedCompletions = AttributeCompletionResult.Create(new() { - ["class"] = [], + ["class"] = [] }); - var existingCompletions = new[] { "class" }; var completionContext = BuildAttributeCompletionContext( - documentDescriptors, - existingCompletions, + tagHelpers, + existingCompletions: ["class"], currentTagName: "div", tagHelperPrefix: "th:"); + var service = CreateTagHelperCompletionFactsService(); - // Act var completions = service.GetAttributeCompletions(completionContext); - // Assert AssertCompletionsAreEquivalent(expectedCompletions, completions); } [Fact] public void GetAttributeCompletions_NoDescriptorsForTagReturnsExistingCompletions() { - // Arrange - ImmutableArray documentDescriptors = + TagHelperCollection tagHelpers = [ TagHelperDescriptorBuilder.CreateTagHelper("MyTableTagHelper", "TestAssembly") - .TagMatchingRuleDescriptor(rule => rule - .RequireTagName("table") - .RequireAttributeDescriptor(attribute => attribute.Name("special"))) + .TagMatchingRule(tagName: "table", static b => b + .RequiredAttribute(name: "special")) .Build(), ]; var expectedCompletions = AttributeCompletionResult.Create(new() { - ["class"] = [], + ["class"] = [] }); - var existingCompletions = new[] { "class" }; var completionContext = BuildAttributeCompletionContext( - documentDescriptors, - existingCompletions, + tagHelpers, + existingCompletions: ["class"], currentTagName: "div"); + var service = CreateTagHelperCompletionFactsService(); - // Act var completions = service.GetAttributeCompletions(completionContext); - // Assert AssertCompletionsAreEquivalent(expectedCompletions, completions); } [Fact] public void GetElementCompletions_IgnoresDirectiveAttributes() { - // Arrange - ImmutableArray documentDescriptors = + TagHelperCollection tagHelpers = [ TagHelperDescriptorBuilder.CreateTagHelper("BindAttribute", "TestAssembly") - .TagMatchingRuleDescriptor(rule => rule.RequireTagName("input")) + .TagMatchingRule(tagName: "input") .BoundAttributeDescriptor(builder => { builder.Name = "@bind"; @@ -634,559 +573,524 @@ public void GetElementCompletions_IgnoresDirectiveAttributes() var expectedCompletions = ElementCompletionResult.Create(new() { - ["table"] = [], + ["table"] = [] }); - var existingCompletions = new[] { "table" }; var completionContext = BuildElementCompletionContext( - documentDescriptors, - existingCompletions, + tagHelpers, + existingCompletions: ["table"], containingTagName: "body", containingParentTagName: null); + var service = CreateTagHelperCompletionFactsService(); - // Act var completions = service.GetElementCompletions(completionContext); - // Assert AssertCompletionsAreEquivalent(expectedCompletions, completions); } [Fact] public void GetElementCompletions_FiltersFullyQualifiedElementsIfShortNameExists() { - // Arrange - ImmutableArray documentDescriptors = + TagHelperCollection tagHelpers = [ TagHelperDescriptorBuilder.CreateTagHelper("TestTagHelper", "TestAssembly") - .TagMatchingRuleDescriptor(rule => rule.RequireTagName("Test")) + .TagMatchingRule("Test") .Build(), TagHelperDescriptorBuilder.CreateTagHelper("TestTagHelper", "TestAssembly") - .TagMatchingRuleDescriptor(rule => rule.RequireTagName("TestAssembly.Test")) + .TagMatchingRule("TestAssembly.Test") .IsFullyQualifiedNameMatch(true) .Build(), TagHelperDescriptorBuilder.CreateTagHelper("Test2TagHelper", "TestAssembly") - .TagMatchingRuleDescriptor(rule => rule.RequireTagName("Test2Assembly.Test")) + .TagMatchingRule("Test2Assembly.Test") .IsFullyQualifiedNameMatch(true) .Build(), ]; var expectedCompletions = ElementCompletionResult.Create(new() { - ["Test"] = [documentDescriptors[0]], - ["Test2Assembly.Test"] = [documentDescriptors[2]], + ["Test"] = [tagHelpers[0]], + ["Test2Assembly.Test"] = [tagHelpers[2]] }); var completionContext = BuildElementCompletionContext( - documentDescriptors, + tagHelpers, existingCompletions: [], containingTagName: "body", containingParentTagName: null); + var service = CreateTagHelperCompletionFactsService(); - // Act var completions = service.GetElementCompletions(completionContext); - // Assert AssertCompletionsAreEquivalent(expectedCompletions, completions); } [Fact] public void GetElementCompletions_TagOutputHintDoesNotFallThroughToSchemaCheck() { - // Arrange - ImmutableArray documentDescriptors = + TagHelperCollection tagHelpers = [ TagHelperDescriptorBuilder.CreateTagHelper("MyTableTagHelper", "TestAssembly") - .TagMatchingRuleDescriptor(rule => rule.RequireTagName("my-table")) + .TagMatchingRule("my-table") .TagOutputHint("table") .Build(), TagHelperDescriptorBuilder.CreateTagHelper("MyTrTagHelper", "TestAssembly") - .TagMatchingRuleDescriptor(rule => rule.RequireTagName("my-tr")) + .TagMatchingRule("my-tr") .TagOutputHint("tr") .Build(), ]; var expectedCompletions = ElementCompletionResult.Create(new() { - ["my-table"] = [documentDescriptors[0]], - ["table"] = [], + ["my-table"] = [tagHelpers[0]], + ["table"] = [] }); - var existingCompletions = new[] { "table" }; var completionContext = BuildElementCompletionContext( - documentDescriptors, - existingCompletions, + tagHelpers, + existingCompletions: ["table"], containingTagName: "body", containingParentTagName: null); + var service = CreateTagHelperCompletionFactsService(); - // Act var completions = service.GetElementCompletions(completionContext); - // Assert AssertCompletionsAreEquivalent(expectedCompletions, completions); } [Fact] public void GetElementCompletions_CatchAllsOnlyApplyToCompletionsStartingWithPrefix() { - // Arrange - ImmutableArray documentDescriptors = + TagHelperCollection tagHelpers = [ TagHelperDescriptorBuilder.CreateTagHelper("CatchAllTagHelper", "TestAssembly") - .TagMatchingRuleDescriptor(rule => rule.RequireTagName("*")) + .TagMatchingRule("*") .Build(), TagHelperDescriptorBuilder.CreateTagHelper("LiTagHelper", "TestAssembly") - .TagMatchingRuleDescriptor(rule => rule.RequireTagName("li")) + .TagMatchingRule("li") .Build(), ]; var expectedCompletions = ElementCompletionResult.Create(new() { - ["th:li"] = [documentDescriptors[1], documentDescriptors[0]], - ["li"] = [], + ["th:li"] = [tagHelpers[1], tagHelpers[0]], + ["li"] = [] }); - var existingCompletions = new[] { "li" }; var completionContext = BuildElementCompletionContext( - documentDescriptors, - existingCompletions, + tagHelpers, + existingCompletions: ["li"], containingTagName: "ul", tagHelperPrefix: "th:"); + var service = CreateTagHelperCompletionFactsService(); - // Act var completions = service.GetElementCompletions(completionContext); - // Assert AssertCompletionsAreEquivalent(expectedCompletions, completions); } [Fact] public void GetElementCompletions_TagHelperPrefixIsPrependedToTagHelperCompletions() { - // Arrange - ImmutableArray documentDescriptors = + TagHelperCollection tagHelpers = [ TagHelperDescriptorBuilder.CreateTagHelper("SuperLiTagHelper", "TestAssembly") - .TagMatchingRuleDescriptor(rule => rule.RequireTagName("superli")) + .TagMatchingRule("superli") .Build(), TagHelperDescriptorBuilder.CreateTagHelper("LiTagHelper", "TestAssembly") - .TagMatchingRuleDescriptor(rule => rule.RequireTagName("li")) + .TagMatchingRule("li") .Build(), ]; var expectedCompletions = ElementCompletionResult.Create(new() { - ["th:superli"] = [documentDescriptors[0]], - ["th:li"] = [documentDescriptors[1]], - ["li"] = [], + ["th:superli"] = [tagHelpers[0]], + ["th:li"] = [tagHelpers[1]], + ["li"] = [] }); - var existingCompletions = new[] { "li" }; var completionContext = BuildElementCompletionContext( - documentDescriptors, - existingCompletions, + tagHelpers, + existingCompletions: ["li"], containingTagName: "ul", tagHelperPrefix: "th:"); + var service = CreateTagHelperCompletionFactsService(); - // Act var completions = service.GetElementCompletions(completionContext); - // Assert AssertCompletionsAreEquivalent(expectedCompletions, completions); } [Fact] public void GetElementCompletions_IsCaseSensitive() { - // Arrange - ImmutableArray documentDescriptors = + TagHelperCollection tagHelpers = [ TagHelperDescriptorBuilder.CreateTagHelper("MyliTagHelper", "TestAssembly") - .TagMatchingRuleDescriptor(rule => rule.RequireTagName("myli")) + .TagMatchingRule("myli") .SetCaseSensitive() .Build(), TagHelperDescriptorBuilder.CreateTagHelper("MYLITagHelper", "TestAssembly") - .TagMatchingRuleDescriptor(rule => rule.RequireTagName("MYLI")) + .TagMatchingRule("MYLI") .SetCaseSensitive() .Build(), ]; var expectedCompletions = ElementCompletionResult.Create(new() { - ["myli"] = [documentDescriptors[0]], - ["MYLI"] = [documentDescriptors[1]], - ["li"] = [], + ["myli"] = [tagHelpers[0]], + ["MYLI"] = [tagHelpers[1]], + ["li"] = [] }); - var existingCompletions = new[] { "li" }; var completionContext = BuildElementCompletionContext( - documentDescriptors, - existingCompletions, - containingTagName: "ul", - tagHelperPrefix: null); + tagHelpers, + existingCompletions: ["li"], + containingTagName: "ul"); + var service = CreateTagHelperCompletionFactsService(); - // Act var completions = service.GetElementCompletions(completionContext); - // Assert AssertCompletionsAreEquivalent(expectedCompletions, completions); } [Fact] public void GetElementCompletions_HTMLSchemaTagName_IsCaseSensitive() { - // Arrange - ImmutableArray documentDescriptors = + TagHelperCollection tagHelpers = [ TagHelperDescriptorBuilder.CreateTagHelper("LITagHelper", "TestAssembly") - .TagMatchingRuleDescriptor(rule => rule.RequireTagName("LI")) + .TagMatchingRule("LI") .SetCaseSensitive() .Build(), TagHelperDescriptorBuilder.CreateTagHelper("LiTagHelper", "TestAssembly") - .TagMatchingRuleDescriptor(rule => rule.RequireTagName("li")) + .TagMatchingRule("li") .SetCaseSensitive() .Build(), ]; var expectedCompletions = ElementCompletionResult.Create(new() { - ["LI"] = [documentDescriptors[0]], - ["li"] = [documentDescriptors[1]], + ["LI"] = [tagHelpers[0]], + ["li"] = [tagHelpers[1]] }); - var existingCompletions = new[] { "li" }; var completionContext = BuildElementCompletionContext( - documentDescriptors, - existingCompletions, - containingTagName: "ul", - tagHelperPrefix: null); + tagHelpers, + existingCompletions: ["li"], + containingTagName: "ul"); + var service = CreateTagHelperCompletionFactsService(); - // Act var completions = service.GetElementCompletions(completionContext); - // Assert AssertCompletionsAreEquivalent(expectedCompletions, completions); } [Fact] public void GetElementCompletions_CatchAllsApplyToOnlyTagHelperCompletions() { - // Arrange - ImmutableArray documentDescriptors = + TagHelperCollection tagHelpers = [ TagHelperDescriptorBuilder.CreateTagHelper("SuperLiTagHelper", "TestAssembly") - .TagMatchingRuleDescriptor(rule => rule.RequireTagName("superli")) + .TagMatchingRule(tagName: "superli") .Build(), TagHelperDescriptorBuilder.CreateTagHelper("CatchAll", "TestAssembly") - .TagMatchingRuleDescriptor(rule => rule.RequireTagName("*")) + .TagMatchingRule(tagName: "*") .Build(), ]; var expectedCompletions = ElementCompletionResult.Create(new() { - ["superli"] = [documentDescriptors[0], documentDescriptors[1]], - ["li"] = [], + ["superli"] = [tagHelpers[0], tagHelpers[1]], + ["li"] = [] }); - var existingCompletions = new[] { "li" }; var completionContext = BuildElementCompletionContext( - documentDescriptors, - existingCompletions, + tagHelpers, + existingCompletions: ["li"], containingTagName: "ul"); + var service = CreateTagHelperCompletionFactsService(); - // Act var completions = service.GetElementCompletions(completionContext); - // Assert AssertCompletionsAreEquivalent(expectedCompletions, completions); } [Fact] public void GetElementCompletions_CatchAllsApplyToNonTagHelperCompletionsIfStartsWithTagHelperPrefix() { - // Arrange - ImmutableArray documentDescriptors = + TagHelperCollection tagHelpers = [ TagHelperDescriptorBuilder.CreateTagHelper("SuperLiTagHelper", "TestAssembly") - .TagMatchingRuleDescriptor(rule => rule.RequireTagName("superli")) + .TagMatchingRule(tagName: "superli") .Build(), TagHelperDescriptorBuilder.CreateTagHelper("CatchAll", "TestAssembly") - .TagMatchingRuleDescriptor(rule => rule.RequireTagName("*")) + .TagMatchingRule(tagName: "*") .Build(), ]; var expectedCompletions = ElementCompletionResult.Create(new() { - ["th:superli"] = [documentDescriptors[0], documentDescriptors[1]], - ["th:li"] = [documentDescriptors[1]], + ["th:superli"] = [tagHelpers[0], tagHelpers[1]], + ["th:li"] = [tagHelpers[1]] }); - var existingCompletions = new[] { "th:li" }; var completionContext = BuildElementCompletionContext( - documentDescriptors, - existingCompletions, + tagHelpers, + existingCompletions: ["th:li"], containingTagName: "ul", tagHelperPrefix: "th:"); + var service = CreateTagHelperCompletionFactsService(); - // Act var completions = service.GetElementCompletions(completionContext); - // Assert AssertCompletionsAreEquivalent(expectedCompletions, completions); } [Fact] public void GetElementCompletions_AllowsMultiTargetingTagHelpers() { - // Arrange - ImmutableArray documentDescriptors = + TagHelperCollection tagHelpers = [ TagHelperDescriptorBuilder.CreateTagHelper("BoldTagHelper1", "TestAssembly") - .TagMatchingRuleDescriptor(rule => rule.RequireTagName("strong")) - .TagMatchingRuleDescriptor(rule => rule.RequireTagName("b")) - .TagMatchingRuleDescriptor(rule => rule.RequireTagName("bold")) + .TagMatchingRule(tagName: "strong") + .TagMatchingRule(tagName: "b") + .TagMatchingRule(tagName: "bold") .Build(), TagHelperDescriptorBuilder.CreateTagHelper("BoldTagHelper2", "TestAssembly") - .TagMatchingRuleDescriptor(rule => rule.RequireTagName("strong")) + .TagMatchingRule(tagName: "strong") .Build(), ]; var expectedCompletions = ElementCompletionResult.Create(new() { - ["strong"] = [documentDescriptors[0], documentDescriptors[1]], - ["b"] = [documentDescriptors[0]], - ["bold"] = [documentDescriptors[0]], + ["strong"] = [tagHelpers[0], tagHelpers[1]], + ["b"] = [tagHelpers[0]], + ["bold"] = [tagHelpers[0]] }); - var existingCompletions = new[] { "strong", "b", "bold" }; var completionContext = BuildElementCompletionContext( - documentDescriptors, - existingCompletions, + tagHelpers, + existingCompletions: ["strong", "b", "bold"], containingTagName: "ul"); + var service = CreateTagHelperCompletionFactsService(); - // Act var completions = service.GetElementCompletions(completionContext); - // Assert AssertCompletionsAreEquivalent(expectedCompletions, completions); } [Fact] public void GetElementCompletions_CombinesDescriptorsOnExistingCompletions() { - // Arrange - ImmutableArray documentDescriptors = + TagHelperCollection tagHelpers = [ TagHelperDescriptorBuilder.CreateTagHelper("LiTagHelper1", "TestAssembly") - .TagMatchingRuleDescriptor(rule => rule.RequireTagName("li")) + .TagMatchingRule(tagName: "li") .Build(), TagHelperDescriptorBuilder.CreateTagHelper("LiTagHelper2", "TestAssembly") - .TagMatchingRuleDescriptor(rule => rule.RequireTagName("li")) + .TagMatchingRule(tagName: "li") .Build(), ]; var expectedCompletions = ElementCompletionResult.Create(new() { - ["li"] = [documentDescriptors[0], documentDescriptors[1]], + ["li"] = [tagHelpers[0], tagHelpers[1]] }); - var existingCompletions = new[] { "li" }; - var completionContext = BuildElementCompletionContext(documentDescriptors, existingCompletions, containingTagName: "ul"); + var completionContext = BuildElementCompletionContext( + tagHelpers, + existingCompletions: ["li"], + containingTagName: "ul"); + var service = CreateTagHelperCompletionFactsService(); - // Act var completions = service.GetElementCompletions(completionContext); - // Assert AssertCompletionsAreEquivalent(expectedCompletions, completions); } [Fact] public void GetElementCompletions_NewCompletionsForSchemaTagsNotInExistingCompletionsAreIgnored() { - // Arrange - ImmutableArray documentDescriptors = + TagHelperCollection tagHelpers = [ TagHelperDescriptorBuilder.CreateTagHelper("SuperLiTagHelper", "TestAssembly") - .TagMatchingRuleDescriptor(rule => rule.RequireTagName("superli")) + .TagMatchingRule(tagName: "superli") .Build(), TagHelperDescriptorBuilder.CreateTagHelper("LiTagHelper", "TestAssembly") - .TagMatchingRuleDescriptor(rule => rule.RequireTagName("li")) + .TagMatchingRule(tagName: "li") .TagOutputHint("strong") .Build(), TagHelperDescriptorBuilder.CreateTagHelper("DivTagHelper", "TestAssembly") - .TagMatchingRuleDescriptor(rule => rule.RequireTagName("div")) + .TagMatchingRule(tagName: "div") .Build(), ]; var expectedCompletions = ElementCompletionResult.Create(new() { - ["li"] = [documentDescriptors[1]], - ["superli"] = [documentDescriptors[0]], + ["li"] = [tagHelpers[1]], + ["superli"] = [tagHelpers[0]] }); - var existingCompletions = new[] { "li" }; - var completionContext = BuildElementCompletionContext(documentDescriptors, existingCompletions, containingTagName: "ul"); + var completionContext = BuildElementCompletionContext( + tagHelpers, + existingCompletions: ["li"], + containingTagName: "ul"); + var service = CreateTagHelperCompletionFactsService(); - // Act var completions = service.GetElementCompletions(completionContext); - // Assert AssertCompletionsAreEquivalent(expectedCompletions, completions); } [Fact] public void GetElementCompletions_OutputHintIsCrossReferencedWithExistingCompletions() { - // Arrange - ImmutableArray documentDescriptors = + TagHelperCollection tagHelpers = [ TagHelperDescriptorBuilder.CreateTagHelper("DivTagHelper", "TestAssembly") - .TagMatchingRuleDescriptor(rule => rule.RequireTagName("div")) + .TagMatchingRule(tagName: "div") .TagOutputHint("li") .Build(), TagHelperDescriptorBuilder.CreateTagHelper("LiTagHelper", "TestAssembly") - .TagMatchingRuleDescriptor(rule => rule.RequireTagName("li")) + .TagMatchingRule(tagName: "li") .TagOutputHint("strong") .Build(), ]; var expectedCompletions = ElementCompletionResult.Create(new() { - ["div"] = [documentDescriptors[0]], - ["li"] = [documentDescriptors[1]], + ["div"] = [tagHelpers[0]], + ["li"] = [tagHelpers[1]] }); - var existingCompletions = new[] { "li" }; - var completionContext = BuildElementCompletionContext(documentDescriptors, existingCompletions, containingTagName: "ul"); + var completionContext = BuildElementCompletionContext( + tagHelpers, + existingCompletions: ["li"], + containingTagName: "ul"); + var service = CreateTagHelperCompletionFactsService(); - // Act var completions = service.GetElementCompletions(completionContext); - // Assert AssertCompletionsAreEquivalent(expectedCompletions, completions); } [Fact] public void GetElementCompletions_EnsuresDescriptorsHaveSatisfiedParent() { - // Arrange - ImmutableArray documentDescriptors = + TagHelperCollection tagHelpers = [ TagHelperDescriptorBuilder.CreateTagHelper("LiTagHelper1", "TestAssembly") - .TagMatchingRuleDescriptor(rule => rule.RequireTagName("li")) + .TagMatchingRule(tagName: "li") .Build(), TagHelperDescriptorBuilder.CreateTagHelper("LiTagHelper2", "TestAssembly") - .TagMatchingRuleDescriptor(rule => rule.RequireTagName("li").RequireParentTag("ol")) + .TagMatchingRule(tagName: "li", parentTagName: "ol") .Build(), ]; var expectedCompletions = ElementCompletionResult.Create(new() { - ["li"] = [documentDescriptors[0]], + ["li"] = [tagHelpers[0]] }); - var existingCompletions = new[] { "li" }; - var completionContext = BuildElementCompletionContext(documentDescriptors, existingCompletions, containingTagName: "ul"); + var completionContext = BuildElementCompletionContext( + tagHelpers, + existingCompletions: ["li"], + containingTagName: "ul"); + var service = CreateTagHelperCompletionFactsService(); - // Act var completions = service.GetElementCompletions(completionContext); - // Assert AssertCompletionsAreEquivalent(expectedCompletions, completions); } [Fact] public void GetElementCompletions_NoContainingParentTag_DoesNotGetCompletionForRuleWithParentTag() { - // Arrange - ImmutableArray documentDescriptors = + TagHelperCollection tagHelpers = [ TagHelperDescriptorBuilder.CreateTagHelper("Tag1", "TestAssembly") - .TagMatchingRuleDescriptor(rule => rule.RequireTagName("outer-child-tag")) - .TagMatchingRuleDescriptor(rule => rule.RequireTagName("child-tag").RequireParentTag("parent-tag")) + .TagMatchingRule(tagName: "outer-child-tag") + .TagMatchingRule(tagName: "child-tag", parentTagName: "parent-tag") .Build(), TagHelperDescriptorBuilder.CreateTagHelper("Tag2", "TestAssembly") - .TagMatchingRuleDescriptor(rule => rule.RequireTagName("parent-tag")) + .TagMatchingRule(tagName: "parent-tag") .AllowChildTag("child-tag") .Build(), ]; var expectedCompletions = ElementCompletionResult.Create(new() { - ["outer-child-tag"] = [documentDescriptors[0]], - ["parent-tag"] = [documentDescriptors[1]], + ["outer-child-tag"] = [tagHelpers[0]], + ["parent-tag"] = [tagHelpers[1]] }); var completionContext = BuildElementCompletionContext( - documentDescriptors, + tagHelpers, existingCompletions: [], containingTagName: null, containingParentTagName: null); + var service = CreateTagHelperCompletionFactsService(); - // Act var completions = service.GetElementCompletions(completionContext); - // Assert AssertCompletionsAreEquivalent(expectedCompletions, completions); } [Fact] public void GetElementCompletions_WithContainingParentTag_GetsCompletionForRuleWithParentTag() { - // Arrange - ImmutableArray documentDescriptors = + TagHelperCollection tagHelpers = [ TagHelperDescriptorBuilder.CreateTagHelper("Tag1", "TestAssembly") - .TagMatchingRuleDescriptor(rule => rule.RequireTagName("outer-child-tag")) - .TagMatchingRuleDescriptor(rule => rule.RequireTagName("child-tag").RequireParentTag("parent-tag")) + .TagMatchingRule(tagName: "outer-child-tag") + .TagMatchingRule(tagName: "child-tag", parentTagName: "parent-tag") .Build(), TagHelperDescriptorBuilder.CreateTagHelper("Tag2", "TestAssembly") - .TagMatchingRuleDescriptor(rule => rule.RequireTagName("parent-tag")) + .TagMatchingRule(tagName: "parent-tag") .AllowChildTag("child-tag") .Build(), ]; var expectedCompletions = ElementCompletionResult.Create(new() { - ["child-tag"] = [documentDescriptors[0]], + ["child-tag"] = [tagHelpers[0]] }); var completionContext = BuildElementCompletionContext( - documentDescriptors, + tagHelpers, existingCompletions: [], containingTagName: "parent-tag", containingParentTagName: null); + var service = CreateTagHelperCompletionFactsService(); - // Act var completions = service.GetElementCompletions(completionContext); - // Assert AssertCompletionsAreEquivalent(expectedCompletions, completions); } [Fact] public void GetElementCompletions_AllowedChildrenAreIgnoredWhenAtRoot() { - // Arrange - ImmutableArray documentDescriptors = + TagHelperCollection tagHelpers = [ TagHelperDescriptorBuilder.CreateTagHelper("CatchAll", "TestAssembly") - .TagMatchingRuleDescriptor(rule => rule.RequireTagName("*")) + .TagMatchingRule("*") .AllowChildTag("b") .AllowChildTag("bold") .AllowChildTag("div") @@ -1196,27 +1100,25 @@ public void GetElementCompletions_AllowedChildrenAreIgnoredWhenAtRoot() var expectedCompletions = ElementCompletionResult.Create([]); var completionContext = BuildElementCompletionContext( - documentDescriptors, + tagHelpers, existingCompletions: [], containingTagName: null, containingParentTagName: null); + var service = CreateTagHelperCompletionFactsService(); - // Act var completions = service.GetElementCompletions(completionContext); - // Assert AssertCompletionsAreEquivalent(expectedCompletions, completions); } [Fact] public void GetElementCompletions_DoesNotReturnExistingCompletionsWhenAllowedChildren() { - // Arrange - ImmutableArray documentDescriptors = + TagHelperCollection tagHelpers = [ TagHelperDescriptorBuilder.CreateTagHelper("BoldParent", "TestAssembly") - .TagMatchingRuleDescriptor(rule => rule.RequireTagName("div")) + .TagMatchingRule("div") .AllowChildTag("b") .AllowChildTag("bold") .AllowChildTag("div") @@ -1227,28 +1129,29 @@ public void GetElementCompletions_DoesNotReturnExistingCompletionsWhenAllowedChi { ["b"] = [], ["bold"] = [], - ["div"] = [documentDescriptors[0]] + ["div"] = [tagHelpers[0]] }); - var existingCompletions = new[] { "p", "em" }; - var completionContext = BuildElementCompletionContext(documentDescriptors, existingCompletions, containingTagName: "div", containingParentTagName: "thing"); + var completionContext = BuildElementCompletionContext( + tagHelpers, + existingCompletions: ["p", "em"], + containingTagName: "div", + containingParentTagName: "thing"); + var service = CreateTagHelperCompletionFactsService(); - // Act var completions = service.GetElementCompletions(completionContext); - // Assert AssertCompletionsAreEquivalent(expectedCompletions, completions); } [Fact] public void GetElementCompletions_CapturesAllAllowedChildTagsFromParentTagHelpers_NoneTagHelpers() { - // Arrange - ImmutableArray documentDescriptors = + TagHelperCollection tagHelpers = [ TagHelperDescriptorBuilder.CreateTagHelper("BoldParent", "TestAssembly") - .TagMatchingRuleDescriptor(rule => rule.RequireTagName("div")) + .TagMatchingRule("div") .AllowChildTag("b") .AllowChildTag("bold") .Build(), @@ -1257,31 +1160,29 @@ public void GetElementCompletions_CapturesAllAllowedChildTagsFromParentTagHelper var expectedCompletions = ElementCompletionResult.Create(new() { ["b"] = [], - ["bold"] = [], + ["bold"] = [] }); var completionContext = BuildElementCompletionContext( - documentDescriptors, + tagHelpers, existingCompletions: [], containingTagName: "div", containingParentTagName: ""); + var service = CreateTagHelperCompletionFactsService(); - // Act var completions = service.GetElementCompletions(completionContext); - // Assert AssertCompletionsAreEquivalent(expectedCompletions, completions); } [Fact] public void GetElementCompletions_CapturesAllAllowedChildTagsFromParentTagHelpers_SomeTagHelpers() { - // Arrange - ImmutableArray documentDescriptors = + TagHelperCollection tagHelpers = [ TagHelperDescriptorBuilder.CreateTagHelper("BoldParent", "TestAssembly") - .TagMatchingRuleDescriptor(rule => rule.RequireTagName("div")) + .TagMatchingRule("div") .AllowChildTag("b") .AllowChildTag("bold") .AllowChildTag("div") @@ -1292,37 +1193,35 @@ public void GetElementCompletions_CapturesAllAllowedChildTagsFromParentTagHelper { ["b"] = [], ["bold"] = [], - ["div"] = [documentDescriptors[0]] + ["div"] = [tagHelpers[0]] }); var completionContext = BuildElementCompletionContext( - documentDescriptors, + tagHelpers, existingCompletions: [], containingTagName: "div", - containingParentTagName: ""); + containingParentTagName: null); + var service = CreateTagHelperCompletionFactsService(); - // Act var completions = service.GetElementCompletions(completionContext); - // Assert AssertCompletionsAreEquivalent(expectedCompletions, completions); } [Fact] public void GetElementCompletions_CapturesAllAllowedChildTagsFromParentTagHelpers_AllTagHelpers() { - // Arrange - ImmutableArray documentDescriptors = + TagHelperCollection tagHelpers = [ TagHelperDescriptorBuilder.CreateTagHelper("BoldParentCatchAll", "TestAssembly") - .TagMatchingRuleDescriptor(rule => rule.RequireTagName("*")) + .TagMatchingRule("*") .AllowChildTag("strong") .AllowChildTag("div") .AllowChildTag("b") .Build(), TagHelperDescriptorBuilder.CreateTagHelper("BoldParent", "TestAssembly") - .TagMatchingRuleDescriptor(rule => rule.RequireTagName("div")) + .TagMatchingRule("div") .AllowChildTag("b") .AllowChildTag("bold") .Build(), @@ -1330,23 +1229,22 @@ public void GetElementCompletions_CapturesAllAllowedChildTagsFromParentTagHelper var expectedCompletions = ElementCompletionResult.Create(new() { - ["strong"] = [documentDescriptors[0]], - ["b"] = [documentDescriptors[0]], - ["bold"] = [documentDescriptors[0]], - ["div"] = [documentDescriptors[0], documentDescriptors[1]], + ["strong"] = [tagHelpers[0]], + ["b"] = [tagHelpers[0]], + ["bold"] = [tagHelpers[0]], + ["div"] = [tagHelpers[0], tagHelpers[1]] }); var completionContext = BuildElementCompletionContext( - documentDescriptors, + tagHelpers, existingCompletions: [], containingTagName: "div", - containingParentTagName: ""); + containingParentTagName: null); + var service = CreateTagHelperCompletionFactsService(); - // Act var completions = service.GetElementCompletions(completionContext); - // Assert AssertCompletionsAreEquivalent(expectedCompletions, completions); } @@ -1377,37 +1275,37 @@ private static void AssertCompletionsAreEquivalent(AttributeCompletionResult exp } private static ElementCompletionContext BuildElementCompletionContext( - ImmutableArray descriptors, + TagHelperCollection tagHelpers, IEnumerable existingCompletions, string? containingTagName, string? containingParentTagName = "body", bool containingParentIsTagHelper = false, - string? tagHelperPrefix = "") + string? tagHelperPrefix = null) { - var documentContext = TagHelperDocumentContext.Create(tagHelperPrefix, descriptors); + var documentContext = TagHelperDocumentContext.Create(tagHelperPrefix, tagHelpers); var completionContext = new ElementCompletionContext( documentContext, existingCompletions, containingTagName, attributes: [], - containingParentTagName: containingParentTagName, - containingParentIsTagHelper: containingParentIsTagHelper, - inHTMLSchema: (tag) => tag == "strong" || tag == "b" || tag == "bold" || tag == "li" || tag == "div"); + containingParentTagName, + containingParentIsTagHelper, + inHTMLSchema: static tag => tag is "strong" or "b" or "bold" or "li" or "div"); return completionContext; } private static AttributeCompletionContext BuildAttributeCompletionContext( - ImmutableArray descriptors, + TagHelperCollection tagHelpers, IEnumerable existingCompletions, string currentTagName, string? currentAttributeName = null, ImmutableArray> attributes = default, - string tagHelperPrefix = "") + string? tagHelperPrefix = null) { attributes = attributes.NullToEmpty(); - var documentContext = TagHelperDocumentContext.Create(tagHelperPrefix, descriptors); + var documentContext = TagHelperDocumentContext.Create(tagHelperPrefix, tagHelpers); var completionContext = new AttributeCompletionContext( documentContext, existingCompletions, @@ -1416,7 +1314,7 @@ private static AttributeCompletionContext BuildAttributeCompletionContext( attributes, currentParentTagName: "body", currentParentIsTagHelper: false, - inHTMLSchema: (tag) => tag == "strong" || tag == "b" || tag == "bold" || tag == "li" || tag == "div"); + inHTMLSchema: static tag => tag is "strong" or "b" or "bold" or "li" or "div"); return completionContext; } diff --git a/src/Razor/test/Microsoft.VisualStudio.LegacyEditor.Razor.Test/Completion/RazorDirectiveCompletionSourceTest.cs b/src/Razor/test/Microsoft.VisualStudio.LegacyEditor.Razor.Test/Completion/RazorDirectiveCompletionSourceTest.cs index 8d24812aa5e..d60b646c253 100644 --- a/src/Razor/test/Microsoft.VisualStudio.LegacyEditor.Razor.Test/Completion/RazorDirectiveCompletionSourceTest.cs +++ b/src/Razor/test/Microsoft.VisualStudio.LegacyEditor.Razor.Test/Completion/RazorDirectiveCompletionSourceTest.cs @@ -211,7 +211,7 @@ private static IVisualStudioRazorParser CreateParser(string text, params Directi var syntaxTree = RazorSyntaxTree.Parse(source, codeDocument.ParserOptions); codeDocument.SetSyntaxTree(syntaxTree); - codeDocument.SetTagHelperContext(TagHelperDocumentContext.Create(prefix: null, tagHelpers: [])); + codeDocument.SetTagHelperContext(TagHelperDocumentContext.Create(tagHelpers: [])); var parserMock = new StrictMock(); parserMock diff --git a/src/Razor/test/Microsoft.VisualStudio.LegacyEditor.Razor.Test/Parsing/RazorSyntaxTreePartialParserTest.cs b/src/Razor/test/Microsoft.VisualStudio.LegacyEditor.Razor.Test/Parsing/RazorSyntaxTreePartialParserTest.cs index cd58b74d648..7cd634cdf2f 100644 --- a/src/Razor/test/Microsoft.VisualStudio.LegacyEditor.Razor.Test/Parsing/RazorSyntaxTreePartialParserTest.cs +++ b/src/Razor/test/Microsoft.VisualStudio.LegacyEditor.Razor.Test/Parsing/RazorSyntaxTreePartialParserTest.cs @@ -3,7 +3,6 @@ #nullable disable -using System.Collections.Generic; using Microsoft.AspNetCore.Mvc.Razor.Extensions; using Microsoft.AspNetCore.Razor.Language; using Microsoft.AspNetCore.Razor.Language.Legacy; @@ -43,11 +42,8 @@ public void TagHelperTagBodiesRejectPartialChanges(object objectEdit) var builder = TagHelperDescriptorBuilder.CreateTagHelper("PTagHelper", "TestAssembly"); builder.TypeName = "PTagHelper"; builder.TagMatchingRule(rule => rule.TagName = "p"); - var descriptors = new[] - { - builder.Build() - }; - var projectEngine = CreateProjectEngine(tagHelpers: descriptors); + TagHelperCollection tagHelpers = [builder.Build()]; + var projectEngine = CreateProjectEngine(tagHelpers); var projectItem = new TestRazorProjectItem("Index.cshtml") { Content = edit.OldSnapshot.GetText() @@ -116,8 +112,8 @@ public void TagHelperAttributesAreLocatedAndAcceptChangesCorrectly(object editOb attribute.TypeName = typeof(string).FullName; attribute.PropertyName = "StringAttribute"; }); - var descriptors = new[] { builder.Build() }; - var projectEngine = CreateProjectEngine(tagHelpers: descriptors); + TagHelperCollection tagHelpers = [builder.Build()]; + var projectEngine = CreateProjectEngine(tagHelpers); var sourceDocument = new TestRazorProjectItem("Index.cshtml") { Content = edit.OldSnapshot.GetText() @@ -390,8 +386,7 @@ private static TestEdit CreateInsertionChange(string initialText, int insertionL return new TestEdit(sourceChange, oldSnapshot, changedSnapshot); } - private static RazorProjectEngine CreateProjectEngine( - IEnumerable tagHelpers = null) + private static RazorProjectEngine CreateProjectEngine(TagHelperCollection tagHelpers = null) { var fileSystem = new TestRazorProjectFileSystem(); var projectEngine = RazorProjectEngine.Create(RazorConfiguration.Default, fileSystem, builder => @@ -402,7 +397,7 @@ private static RazorProjectEngine CreateProjectEngine( if (tagHelpers != null) { - builder.AddTagHelpers(tagHelpers); + builder.SetTagHelpers(tagHelpers); } builder.ConfigureParserOptions(VisualStudioRazorParser.ConfigureParserOptions); diff --git a/src/Shared/Microsoft.AspNetCore.Razor.Serialization.Json/ObjectReaders_ProjectSystem.cs b/src/Shared/Microsoft.AspNetCore.Razor.Serialization.Json/ObjectReaders_ProjectSystem.cs index 840a796aa4c..c226bb85a2f 100644 --- a/src/Shared/Microsoft.AspNetCore.Razor.Serialization.Json/ObjectReaders_ProjectSystem.cs +++ b/src/Shared/Microsoft.AspNetCore.Razor.Serialization.Json/ObjectReaders_ProjectSystem.cs @@ -36,13 +36,15 @@ public static DocumentSnapshotHandle ReadDocumentSnapshotHandleFromProperties(Js public static ProjectWorkspaceState ReadProjectWorkspaceStateFromProperties(JsonDataReader reader) { - var tagHelpers = reader.ReadImmutableArrayOrEmpty(nameof(ProjectWorkspaceState.TagHelpers), + var array = reader.ReadImmutableArrayOrEmpty(nameof(ProjectWorkspaceState.TagHelpers), static r => ReadTagHelper(r #if JSONSERIALIZATION_ENABLETAGHELPERCACHE , useCache: true #endif )); + var tagHelpers = TagHelperCollection.Create(array); + return ProjectWorkspaceState.Create(tagHelpers); } diff --git a/src/Shared/Microsoft.AspNetCore.Razor.Serialization.Json/ObjectWriters_ProjectSystem.cs b/src/Shared/Microsoft.AspNetCore.Razor.Serialization.Json/ObjectWriters_ProjectSystem.cs index c70979cf9f3..532374ff235 100644 --- a/src/Shared/Microsoft.AspNetCore.Razor.Serialization.Json/ObjectWriters_ProjectSystem.cs +++ b/src/Shared/Microsoft.AspNetCore.Razor.Serialization.Json/ObjectWriters_ProjectSystem.cs @@ -35,7 +35,7 @@ public static void Write(JsonDataWriter writer, ProjectWorkspaceState? value) public static void WriteProperties(JsonDataWriter writer, ProjectWorkspaceState value) { - writer.WriteArrayIfNotDefaultOrEmpty(nameof(value.TagHelpers), value.TagHelpers, Write); + writer.WriteArrayIfNotNullOrEmpty(nameof(value.TagHelpers), value.TagHelpers, Write); } public static void Write(JsonDataWriter writer, RazorProjectInfo value) diff --git a/src/Shared/Microsoft.AspNetCore.Razor.Serialization.Json/SerializationFormat.cs b/src/Shared/Microsoft.AspNetCore.Razor.Serialization.Json/SerializationFormat.cs index 807fc8c3729..9dee6f06b45 100644 --- a/src/Shared/Microsoft.AspNetCore.Razor.Serialization.Json/SerializationFormat.cs +++ b/src/Shared/Microsoft.AspNetCore.Razor.Serialization.Json/SerializationFormat.cs @@ -9,5 +9,5 @@ internal static class SerializationFormat // or any of the types that compose it changes. This includes: RazorConfiguration, // ProjectWorkspaceState, TagHelperDescriptor, and DocumentSnapshotHandle. // NOTE: If this version is changed, a coordinated insertion is required between Roslyn and Razor for the C# extension. - public const int Version = 15; + public const int Version = 16; } diff --git a/src/Shared/Microsoft.AspNetCore.Razor.Test.Common/Language/Intermediate/IntermediateNodeAssert.cs b/src/Shared/Microsoft.AspNetCore.Razor.Test.Common/Language/Intermediate/IntermediateNodeAssert.cs index 174bf215658..a1675327ef4 100644 --- a/src/Shared/Microsoft.AspNetCore.Razor.Test.Common/Language/Intermediate/IntermediateNodeAssert.cs +++ b/src/Shared/Microsoft.AspNetCore.Razor.Test.Common/Language/Intermediate/IntermediateNodeAssert.cs @@ -307,7 +307,12 @@ internal static void PreallocatedTagHelperPropertyValue( } } - internal static void TagHelper(string tagName, TagMode tagMode, IEnumerable tagHelpers, IntermediateNode node, params Action[] childValidators) + internal static void TagHelper( + string tagName, + TagMode tagMode, + TagHelperCollection tagHelpers, + IntermediateNode node, + params Action[] childValidators) { var tagHelperNode = Assert.IsType(node); diff --git a/src/Shared/Microsoft.AspNetCore.Razor.Test.Common/Language/RazorProjectEngineBuilderExtensions.cs b/src/Shared/Microsoft.AspNetCore.Razor.Test.Common/Language/RazorProjectEngineBuilderExtensions.cs index 09d0fc9b180..10761e45eb8 100644 --- a/src/Shared/Microsoft.AspNetCore.Razor.Test.Common/Language/RazorProjectEngineBuilderExtensions.cs +++ b/src/Shared/Microsoft.AspNetCore.Razor.Test.Common/Language/RazorProjectEngineBuilderExtensions.cs @@ -30,12 +30,7 @@ public static RazorProjectEngineBuilder AddDefaultImports(this RazorProjectEngin return builder; } - public static RazorProjectEngineBuilder AddTagHelpers(this RazorProjectEngineBuilder builder, params TagHelperDescriptor[] tagHelpers) - { - return AddTagHelpers(builder, (IEnumerable)tagHelpers); - } - - public static RazorProjectEngineBuilder AddTagHelpers(this RazorProjectEngineBuilder builder, IEnumerable tagHelpers) + public static RazorProjectEngineBuilder SetTagHelpers(this RazorProjectEngineBuilder builder, params TagHelperCollection tagHelpers) { var feature = (TestTagHelperFeature)builder.Features.OfType().FirstOrDefault(); if (feature == null) @@ -44,7 +39,7 @@ public static RazorProjectEngineBuilder AddTagHelpers(this RazorProjectEngineBui builder.Features.Add(feature); } - feature.TagHelpers.AddRange(tagHelpers); + feature.SetTagHelpers(tagHelpers); return builder; } diff --git a/src/Shared/Microsoft.AspNetCore.Razor.Test.Common/Language/RazorProjectEngineExtensions.cs b/src/Shared/Microsoft.AspNetCore.Razor.Test.Common/Language/RazorProjectEngineExtensions.cs index 3113d6ab4ed..02e624b04ac 100644 --- a/src/Shared/Microsoft.AspNetCore.Razor.Test.Common/Language/RazorProjectEngineExtensions.cs +++ b/src/Shared/Microsoft.AspNetCore.Razor.Test.Common/Language/RazorProjectEngineExtensions.cs @@ -2,7 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. using System; -using System.Collections.Generic; using System.Collections.Immutable; using Microsoft.AspNetCore.Razor.Language.Intermediate; using Xunit; @@ -32,33 +31,33 @@ public static RazorCodeDocument CreateEmptyCodeDocument( public static RazorCodeDocument CreateEmptyCodeDocument( this RazorProjectEngine projectEngine, - IReadOnlyList tagHelpers) + TagHelperCollection tagHelpers) => projectEngine.CreateEmptyCodeDocumentCore(tagHelpers: tagHelpers); public static RazorCodeDocument CreateEmptyCodeDocument( this RazorProjectEngine projectEngine, RazorFileKind fileKind, - IReadOnlyList tagHelpers) + TagHelperCollection tagHelpers) => projectEngine.CreateEmptyCodeDocumentCore(fileKind, tagHelpers: tagHelpers); public static RazorCodeDocument CreateEmptyCodeDocument( this RazorProjectEngine projectEngine, ImmutableArray importSources, - IReadOnlyList tagHelpers) + TagHelperCollection tagHelpers) => projectEngine.CreateEmptyCodeDocumentCore(importSources: importSources, tagHelpers: tagHelpers); public static RazorCodeDocument CreateEmptyCodeDocument( this RazorProjectEngine projectEngine, RazorFileKind fileKind, ImmutableArray importSources, - IReadOnlyList tagHelpers) + TagHelperCollection tagHelpers) => projectEngine.CreateEmptyCodeDocumentCore(fileKind, importSources, tagHelpers); private static RazorCodeDocument CreateEmptyCodeDocumentCore( this RazorProjectEngine projectEngine, RazorFileKind? fileKind = null, ImmutableArray importSources = default, - IReadOnlyList? tagHelpers = null) + TagHelperCollection? tagHelpers = null) => projectEngine.CreateCodeDocumentCore(string.Empty, fileKind, importSources, tagHelpers); public static RazorCodeDocument CreateEmptyDesignTimeCodeDocument(this RazorProjectEngine projectEngine) @@ -80,33 +79,33 @@ public static RazorCodeDocument CreateEmptyDesignTimeCodeDocument( public static RazorCodeDocument CreateEmptyDesignTimeCodeDocument( this RazorProjectEngine projectEngine, - IReadOnlyList tagHelpers) + TagHelperCollection tagHelpers) => projectEngine.CreateEmptyDesignTimeCodeDocumentCore(tagHelpers: tagHelpers); public static RazorCodeDocument CreateEmptyDesignTimeCodeDocument( this RazorProjectEngine projectEngine, RazorFileKind fileKind, - IReadOnlyList tagHelpers) + TagHelperCollection tagHelpers) => projectEngine.CreateEmptyDesignTimeCodeDocumentCore(fileKind, tagHelpers: tagHelpers); public static RazorCodeDocument CreateEmptyDesignTimeCodeDocument( this RazorProjectEngine projectEngine, ImmutableArray importSources, - IReadOnlyList tagHelpers) + TagHelperCollection tagHelpers) => projectEngine.CreateEmptyDesignTimeCodeDocumentCore(importSources: importSources, tagHelpers: tagHelpers); public static RazorCodeDocument CreateEmptyDesignTimeCodeDocument( this RazorProjectEngine projectEngine, RazorFileKind fileKind, ImmutableArray importSources, - IReadOnlyList tagHelpers) + TagHelperCollection tagHelpers) => projectEngine.CreateEmptyDesignTimeCodeDocumentCore(fileKind, importSources, tagHelpers); private static RazorCodeDocument CreateEmptyDesignTimeCodeDocumentCore( this RazorProjectEngine projectEngine, RazorFileKind? fileKind = null, ImmutableArray importSources = default, - IReadOnlyList? tagHelpers = null) + TagHelperCollection? tagHelpers = null) => projectEngine.CreateDesignTimeCodeDocumentCore(string.Empty, fileKind, importSources, tagHelpers); public static RazorCodeDocument CreateCodeDocument(this RazorProjectEngine projectEngine, string content) @@ -131,21 +130,21 @@ public static RazorCodeDocument CreateCodeDocument( public static RazorCodeDocument CreateCodeDocument( this RazorProjectEngine projectEngine, string content, - IReadOnlyList tagHelpers) + TagHelperCollection tagHelpers) => projectEngine.CreateCodeDocumentCore(content, tagHelpers: tagHelpers); public static RazorCodeDocument CreateCodeDocument( this RazorProjectEngine projectEngine, string content, RazorFileKind fileKind, - IReadOnlyList tagHelpers) + TagHelperCollection tagHelpers) => projectEngine.CreateCodeDocumentCore(content, fileKind, tagHelpers: tagHelpers); public static RazorCodeDocument CreateCodeDocument( this RazorProjectEngine projectEngine, string content, ImmutableArray importSources, - IReadOnlyList tagHelpers) + TagHelperCollection tagHelpers) => projectEngine.CreateCodeDocumentCore(content, importSources: importSources, tagHelpers: tagHelpers); public static RazorCodeDocument CreateCodeDocument( @@ -153,7 +152,7 @@ public static RazorCodeDocument CreateCodeDocument( string content, RazorFileKind fileKind, ImmutableArray importSources, - IReadOnlyList tagHelpers) + TagHelperCollection tagHelpers) => projectEngine.CreateCodeDocumentCore(content, fileKind, importSources, tagHelpers); private static RazorCodeDocument CreateCodeDocumentCore( @@ -161,7 +160,7 @@ private static RazorCodeDocument CreateCodeDocumentCore( string content, RazorFileKind? fileKind = null, ImmutableArray importSources = default, - IReadOnlyList? tagHelpers = null) + TagHelperCollection? tagHelpers = null) { var source = TestRazorSourceDocument.Create(content); @@ -174,7 +173,7 @@ public static RazorCodeDocument CreateDesignTimeCodeDocument(this RazorProjectEn public static RazorCodeDocument CreateDesignTimeCodeDocument( this RazorProjectEngine projectEngine, string content, - IReadOnlyList? tagHelpers) + TagHelperCollection? tagHelpers) => projectEngine.CreateDesignTimeCodeDocumentCore(content, tagHelpers: tagHelpers); public static RazorCodeDocument CreateDesignTimeCodeDocument(this RazorProjectEngine projectEngine, string content, RazorFileKind fileKind) @@ -184,7 +183,7 @@ public static RazorCodeDocument CreateDesignTimeCodeDocument( this RazorProjectEngine projectEngine, string content, RazorFileKind fileKind, - IReadOnlyList? tagHelpers) + TagHelperCollection? tagHelpers) => projectEngine.CreateDesignTimeCodeDocumentCore(content, fileKind, tagHelpers: tagHelpers); public static RazorCodeDocument CreateDesignTimeCodeDocument( @@ -197,7 +196,7 @@ public static RazorCodeDocument CreateDesignTimeCodeDocument( this RazorProjectEngine projectEngine, string content, ImmutableArray importSources, - IReadOnlyList tagHelpers) + TagHelperCollection tagHelpers) => projectEngine.CreateDesignTimeCodeDocumentCore(content, importSources: importSources, tagHelpers: tagHelpers); public static RazorCodeDocument CreateDesignTimeCodeDocument( @@ -212,7 +211,7 @@ public static RazorCodeDocument CreateDesignTimeCodeDocument( string content, RazorFileKind fileKind, ImmutableArray importSources, - IReadOnlyList tagHelpers) + TagHelperCollection tagHelpers) => projectEngine.CreateDesignTimeCodeDocumentCore(content, fileKind, importSources, tagHelpers); private static RazorCodeDocument CreateDesignTimeCodeDocumentCore( @@ -220,7 +219,7 @@ private static RazorCodeDocument CreateDesignTimeCodeDocumentCore( string content, RazorFileKind? fileKind = null, ImmutableArray importSources = default, - IReadOnlyList? tagHelpers = null) + TagHelperCollection? tagHelpers = null) { var source = TestRazorSourceDocument.Create(content); diff --git a/src/Shared/Microsoft.AspNetCore.Razor.Test.Common/Language/TestTagHelperFeature.cs b/src/Shared/Microsoft.AspNetCore.Razor.Test.Common/Language/TestTagHelperFeature.cs index 1c025f604ae..f573bdc1774 100644 --- a/src/Shared/Microsoft.AspNetCore.Razor.Test.Common/Language/TestTagHelperFeature.cs +++ b/src/Shared/Microsoft.AspNetCore.Razor.Test.Common/Language/TestTagHelperFeature.cs @@ -1,25 +1,19 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -using System.Collections.Generic; using System.Threading; namespace Microsoft.AspNetCore.Razor.Language; public class TestTagHelperFeature : RazorEngineFeatureBase, ITagHelperFeature { - public TestTagHelperFeature() - { - TagHelpers = []; - } + private TagHelperCollection? _tagHelpers; - public TestTagHelperFeature(IEnumerable tagHelpers) + public void SetTagHelpers(TagHelperCollection tagHelpers) { - TagHelpers = [.. tagHelpers]; + _tagHelpers = tagHelpers; } - public List TagHelpers { get; } - - public IReadOnlyList GetDescriptors(CancellationToken cancellationToken = default) - => [.. TagHelpers]; + public TagHelperCollection GetTagHelpers(CancellationToken cancellationToken = default) + => _tagHelpers ?? []; } diff --git a/src/Shared/files/Tooling/Telerik/Kendo.Mvc.Examples.project.razor.json b/src/Shared/files/Tooling/Telerik/Kendo.Mvc.Examples.project.razor.json index 73dd551958b..c6f0bf87ffb 100644 --- a/src/Shared/files/Tooling/Telerik/Kendo.Mvc.Examples.project.razor.json +++ b/src/Shared/files/Tooling/Telerik/Kendo.Mvc.Examples.project.razor.json @@ -1,5 +1,5 @@ { - "__Version": 15, + "__Version": 16, "ProjectKey": "C:/Users/admin/location/Kendo.Mvc.Examples/obj/Debug/net7.0/", "FilePath": "C:\\Users\\admin\\location\\Kendo.Mvc.Examples\\Kendo.Mvc.Examples.csproj", "Configuration": { diff --git a/src/Shared/files/Tooling/project.razor.json b/src/Shared/files/Tooling/project.razor.json index 40d69a1bb61..a89e35c9d80 100644 --- a/src/Shared/files/Tooling/project.razor.json +++ b/src/Shared/files/Tooling/project.razor.json @@ -1,5 +1,5 @@ { - "__Version": 15, + "__Version": 16, "ProjectKey": "C:/Users/admin/location/blazorserver/obj/Debug/net7.0/", "FilePath": "C:\\Users\\admin\\location\\blazorserver\\blazorserver.csproj", "Configuration": {