Skip to content

Commit 9c83a09

Browse files
authored
Prefer child content over a matching component (#1180)
* Prefer child content over a matching component * feedback
1 parent 8108f50 commit 9c83a09

File tree

8 files changed

+186
-6
lines changed

8 files changed

+186
-6
lines changed

src/Razor/src/Microsoft.AspNetCore.Razor.Language/Components/ComponentLoweringPass.cs

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -34,15 +34,21 @@ protected override void ExecuteCore(RazorCodeDocument codeDocument, DocumentInte
3434
{
3535
var reference = references[i];
3636
var node = (TagHelperIntermediateNode)reference.Node;
37+
if (node.TagHelpers.Any(t => t.IsChildContentTagHelper()))
38+
{
39+
// This is a child content tag helper. This will be rewritten when we visit its parent.
40+
continue;
41+
}
3742

43+
// The element didn't match any child content descriptors. Look for any matching component descriptors.
3844
var count = 0;
3945
for (var j = 0; j < node.TagHelpers.Count; j++)
4046
{
4147
if (node.TagHelpers[j].IsComponentTagHelper())
4248
{
4349
// Only allow a single component tag helper per element. If there are multiple, we'll just consider
4450
// the first one and ignore the others.
45-
if (count++ > 1)
51+
if (++count > 1)
4652
{
4753
node.Diagnostics.Add(ComponentDiagnosticFactory.Create_MultipleComponents(node.Source, node.TagName, node.TagHelpers));
4854
break;
@@ -54,10 +60,6 @@ protected override void ExecuteCore(RazorCodeDocument codeDocument, DocumentInte
5460
{
5561
reference.Replace(RewriteAsComponent(node, node.TagHelpers.First(t => t.IsComponentTagHelper())));
5662
}
57-
else if (node.TagHelpers.Any(t => t.IsChildContentTagHelper()))
58-
{
59-
// Ignore, this will be handled when we rewrite the parent.
60-
}
6163
else
6264
{
6365
reference.Replace(RewriteAsElement(node));

src/Razor/test/RazorLanguage.Test/IntegrationTests/ComponentCodeGenerationTestBase.cs

Lines changed: 39 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1698,6 +1698,44 @@ public class MyComponent : ComponentBase
16981698
CompileToAssembly(generated);
16991699
}
17001700

1701+
[Fact]
1702+
public void MultipleChildContentMatchingComponentName()
1703+
{
1704+
// Arrange
1705+
AdditionalSyntaxTrees.Add(Parse(@"
1706+
using Microsoft.AspNetCore.Components;
1707+
1708+
namespace Test
1709+
{
1710+
public class MyComponent : ComponentBase
1711+
{
1712+
[Parameter]
1713+
public RenderFragment Header { get; set; }
1714+
1715+
[Parameter]
1716+
public RenderFragment Footer { get; set; }
1717+
}
1718+
1719+
public class Header : ComponentBase
1720+
{
1721+
}
1722+
}
1723+
"));
1724+
1725+
// Act
1726+
var generated = CompileToCSharp(@"
1727+
<MyComponent>
1728+
<Header>Hi!</Header>
1729+
<Footer>Bye!</Footer>
1730+
</MyComponent>
1731+
<Header>Hello!</Header>");
1732+
1733+
// Assert
1734+
AssertDocumentNodeMatchesBaseline(generated.CodeDocument);
1735+
AssertCSharpDocumentMatchesBaseline(generated.CodeDocument);
1736+
CompileToAssembly(generated);
1737+
}
1738+
17011739
#endregion
17021740

17031741
#region Directives
@@ -1804,7 +1842,7 @@ @using Test3
18041842
// Assert
18051843
AssertDocumentNodeMatchesBaseline(generated.CodeDocument);
18061844
AssertCSharpDocumentMatchesBaseline(generated.CodeDocument);
1807-
var result = CompileToAssembly(generated, throwOnFailure: !DesignTime);
1845+
var result = CompileToAssembly(generated, throwOnFailure: false);
18081846

18091847
if (DesignTime)
18101848
{
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
x:\dir\subdir\Test\TestComponent.cshtml(4,1): Error RZ9985: Multiple components use the tag 'SomeComponent'. Components: Test2.SomeComponent, Test3.SomeComponent
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
// <auto-generated/>
2+
#pragma warning disable 1591
3+
namespace Test
4+
{
5+
#line hidden
6+
using System;
7+
using System.Collections.Generic;
8+
using System.Linq;
9+
using System.Threading.Tasks;
10+
using Microsoft.AspNetCore.Components;
11+
public class TestComponent : Microsoft.AspNetCore.Components.ComponentBase
12+
{
13+
#pragma warning disable 219
14+
private void __RazorDirectiveTokenHelpers__() {
15+
}
16+
#pragma warning restore 219
17+
#pragma warning disable 0414
18+
private static System.Object __o = null;
19+
#pragma warning restore 0414
20+
#pragma warning disable 1998
21+
protected override void BuildRenderTree(Microsoft.AspNetCore.Components.Rendering.RenderTreeBuilder __builder)
22+
{
23+
__builder.AddAttribute(-1, "Header", (Microsoft.AspNetCore.Components.RenderFragment)((__builder2) => {
24+
}
25+
));
26+
__builder.AddAttribute(-1, "Footer", (Microsoft.AspNetCore.Components.RenderFragment)((__builder2) => {
27+
}
28+
));
29+
#nullable restore
30+
#line 1 "x:\dir\subdir\Test\TestComponent.cshtml"
31+
__o = typeof(MyComponent);
32+
33+
#line default
34+
#line hidden
35+
#nullable disable
36+
__builder.AddAttribute(-1, "ChildContent", (Microsoft.AspNetCore.Components.RenderFragment)((__builder2) => {
37+
}
38+
));
39+
#nullable restore
40+
#line 5 "x:\dir\subdir\Test\TestComponent.cshtml"
41+
__o = typeof(Header);
42+
43+
#line default
44+
#line hidden
45+
#nullable disable
46+
}
47+
#pragma warning restore 1998
48+
}
49+
}
50+
#pragma warning restore 1591
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
Document -
2+
NamespaceDeclaration - - Test
3+
UsingDirective - (3:1,1 [12] ) - System
4+
UsingDirective - (18:2,1 [32] ) - System.Collections.Generic
5+
UsingDirective - (53:3,1 [17] ) - System.Linq
6+
UsingDirective - (73:4,1 [28] ) - System.Threading.Tasks
7+
UsingDirective - (104:5,1 [37] ) - Microsoft.AspNetCore.Components
8+
ClassDeclaration - - public - TestComponent - Microsoft.AspNetCore.Components.ComponentBase -
9+
DesignTimeDirective -
10+
CSharpCode -
11+
IntermediateToken - - CSharp - #pragma warning disable 0414
12+
CSharpCode -
13+
IntermediateToken - - CSharp - private static System.Object __o = null;
14+
CSharpCode -
15+
IntermediateToken - - CSharp - #pragma warning restore 0414
16+
MethodDeclaration - - protected override - void - BuildRenderTree
17+
Component - (0:0,0 [78] x:\dir\subdir\Test\TestComponent.cshtml) - MyComponent
18+
ComponentChildContent - (17:1,2 [20] x:\dir\subdir\Test\TestComponent.cshtml) - Header - context
19+
HtmlContent - (25:1,10 [3] x:\dir\subdir\Test\TestComponent.cshtml)
20+
IntermediateToken - (25:1,10 [3] x:\dir\subdir\Test\TestComponent.cshtml) - Html - Hi!
21+
ComponentChildContent - (41:2,2 [21] x:\dir\subdir\Test\TestComponent.cshtml) - Footer - context
22+
HtmlContent - (49:2,10 [4] x:\dir\subdir\Test\TestComponent.cshtml)
23+
IntermediateToken - (49:2,10 [4] x:\dir\subdir\Test\TestComponent.cshtml) - Html - Bye!
24+
HtmlContent - (78:3,14 [2] x:\dir\subdir\Test\TestComponent.cshtml)
25+
IntermediateToken - (78:3,14 [2] x:\dir\subdir\Test\TestComponent.cshtml) - Html - \n
26+
Component - (80:4,0 [23] x:\dir\subdir\Test\TestComponent.cshtml) - Header
27+
ComponentChildContent - - ChildContent - context
28+
HtmlContent - (88:4,8 [6] x:\dir\subdir\Test\TestComponent.cshtml)
29+
IntermediateToken - (88:4,8 [6] x:\dir\subdir\Test\TestComponent.cshtml) - Html - Hello!
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
x:\dir\subdir\Test\TestComponent.cshtml(4,1): Error RZ9985: Multiple components use the tag 'SomeComponent'. Components: Test2.SomeComponent, Test3.SomeComponent
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
// <auto-generated/>
2+
#pragma warning disable 1591
3+
namespace Test
4+
{
5+
#line hidden
6+
using System;
7+
using System.Collections.Generic;
8+
using System.Linq;
9+
using System.Threading.Tasks;
10+
using Microsoft.AspNetCore.Components;
11+
public class TestComponent : Microsoft.AspNetCore.Components.ComponentBase
12+
{
13+
#pragma warning disable 1998
14+
protected override void BuildRenderTree(Microsoft.AspNetCore.Components.Rendering.RenderTreeBuilder __builder)
15+
{
16+
__builder.OpenComponent<Test.MyComponent>(0);
17+
__builder.AddAttribute(1, "Header", (Microsoft.AspNetCore.Components.RenderFragment)((__builder2) => {
18+
__builder2.AddContent(2, "Hi!");
19+
}
20+
));
21+
__builder.AddAttribute(3, "Footer", (Microsoft.AspNetCore.Components.RenderFragment)((__builder2) => {
22+
__builder2.AddContent(4, "Bye!");
23+
}
24+
));
25+
__builder.CloseComponent();
26+
__builder.AddMarkupContent(5, "\r\n");
27+
__builder.OpenComponent<Test.Header>(6);
28+
__builder.AddAttribute(7, "ChildContent", (Microsoft.AspNetCore.Components.RenderFragment)((__builder2) => {
29+
__builder2.AddContent(8, "Hello!");
30+
}
31+
));
32+
__builder.CloseComponent();
33+
}
34+
#pragma warning restore 1998
35+
}
36+
}
37+
#pragma warning restore 1591
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
Document -
2+
NamespaceDeclaration - - Test
3+
UsingDirective - (3:1,1 [14] ) - System
4+
UsingDirective - (18:2,1 [34] ) - System.Collections.Generic
5+
UsingDirective - (53:3,1 [19] ) - System.Linq
6+
UsingDirective - (73:4,1 [30] ) - System.Threading.Tasks
7+
UsingDirective - (104:5,1 [39] ) - Microsoft.AspNetCore.Components
8+
ClassDeclaration - - public - TestComponent - Microsoft.AspNetCore.Components.ComponentBase -
9+
MethodDeclaration - - protected override - void - BuildRenderTree
10+
Component - (0:0,0 [78] x:\dir\subdir\Test\TestComponent.cshtml) - MyComponent
11+
ComponentChildContent - (17:1,2 [20] x:\dir\subdir\Test\TestComponent.cshtml) - Header - context
12+
HtmlContent - (25:1,10 [3] x:\dir\subdir\Test\TestComponent.cshtml)
13+
IntermediateToken - (25:1,10 [3] x:\dir\subdir\Test\TestComponent.cshtml) - Html - Hi!
14+
ComponentChildContent - (41:2,2 [21] x:\dir\subdir\Test\TestComponent.cshtml) - Footer - context
15+
HtmlContent - (49:2,10 [4] x:\dir\subdir\Test\TestComponent.cshtml)
16+
IntermediateToken - (49:2,10 [4] x:\dir\subdir\Test\TestComponent.cshtml) - Html - Bye!
17+
HtmlContent - (78:3,14 [2] x:\dir\subdir\Test\TestComponent.cshtml)
18+
IntermediateToken - (78:3,14 [2] x:\dir\subdir\Test\TestComponent.cshtml) - Html - \n
19+
Component - (80:4,0 [23] x:\dir\subdir\Test\TestComponent.cshtml) - Header
20+
ComponentChildContent - - ChildContent - context
21+
HtmlContent - (88:4,8 [6] x:\dir\subdir\Test\TestComponent.cshtml)
22+
IntermediateToken - (88:4,8 [6] x:\dir\subdir\Test\TestComponent.cshtml) - Html - Hello!

0 commit comments

Comments
 (0)