public void VisitExtension(ComponentChildContentIntermediateNode node)
            {
                // Check that each child content has a unique parameter name within its scope. This is important
                // because the parameter name can be implicit, and it doesn't work well when nested.
                if (node.IsParameterized)
                {
                    for (var i = 0; i < Ancestors.Count - 1; i++)
                    {
                        var ancestor = Ancestors[i] as ComponentChildContentIntermediateNode;
                        if (ancestor != null &&
                            ancestor.IsParameterized &&
                            string.Equals(node.ParameterName, ancestor.ParameterName, StringComparison.Ordinal))
                        {
                            // Duplicate name. We report an error because this will almost certainly also lead to an error
                            // from the C# compiler that's way less clear.
                            node.Diagnostics.Add(BlazorDiagnosticFactory.Create_ChildContentRepeatedParameterName(
                                                     node.Source,
                                                     node,
                                                     (ComponentExtensionNode)Ancestors[0],       // Enclosing component
                                                     ancestor,                                   // conflicting child content node
                                                     (ComponentExtensionNode)Ancestors[i + 1])); // Enclosing component of conflicting child content node
                        }
                    }
                }

                base.VisitDefault(node);
            }
Example #2
0
            private ComponentChildContentIntermediateNode RewriteChildContent(BoundAttributeDescriptor attribute, SourceSpan?source, IntermediateNodeCollection children)
            {
                var childContent = new ComponentChildContentIntermediateNode()
                {
                    BoundAttribute = attribute,
                    Source         = source,
                    TypeName       = attribute?.TypeName ?? ComponentsApi.RenderFragment.FullTypeName,
                };

                // There are two cases here:
                // 1. Implicit child content - the children will be non-taghelper nodes, just accept them
                // 2. Explicit child content - the children will be various tag helper nodes, that need special processing.
                for (var i = 0; i < children.Count; i++)
                {
                    var child = children[i];
                    if (child is TagHelperBodyIntermediateNode body)
                    {
                        // The body is all of the content we want to render, the rest of the children will
                        // be the attributes.
                        for (var j = 0; j < body.Children.Count; j++)
                        {
                            childContent.Children.Add(body.Children[j]);
                        }
                    }
                    else if (child is TagHelperPropertyIntermediateNode property)
                    {
                        if (property.BoundAttribute.IsChildContentParameterNameProperty())
                        {
                            // Check for each child content with a parameter name, that the parameter name is specified
                            // with literal text. For instance, the following is not allowed and should generate a diagnostic.
                            //
                            // <MyComponent><ChildContent Context="@Foo()">...</ChildContent></MyComponent>
                            if (TryGetAttributeStringContent(property, out var parameterName))
                            {
                                childContent.ParameterName = parameterName;
                                continue;
                            }

                            // The parameter name is invalid.
                            childContent.Diagnostics.Add(BlazorDiagnosticFactory.Create_ChildContentHasInvalidParameter(property.Source, property.AttributeName, attribute.Name));
                            continue;
                        }

                        // This is an unrecognized attribute, this is possible if you try to do something like put 'ref' on a child content.
                        childContent.Diagnostics.Add(BlazorDiagnosticFactory.Create_ChildContentHasInvalidAttribute(property.Source, property.AttributeName, attribute.Name));
                    }
                    else if (child is TagHelperHtmlAttributeIntermediateNode a)
                    {
                        // This is an HTML attribute on a child content.
                        childContent.Diagnostics.Add(BlazorDiagnosticFactory.Create_ChildContentHasInvalidAttribute(a.Source, a.AttributeName, attribute.Name));
                    }
                    else
                    {
                        // This is some other kind of node (likely an implicit child content)
                        childContent.Children.Add(child);
                    }
                }

                return(childContent);
            }
        public static RazorDiagnostic Create_ChildContentRepeatedParameterName(
            SourceSpan?source,
            ComponentChildContentIntermediateNode childContent1,
            ComponentExtensionNode component1,
            ComponentChildContentIntermediateNode childContent2,
            ComponentExtensionNode component2)
        {
            Debug.Assert(childContent1.ParameterName == childContent2.ParameterName);
            Debug.Assert(childContent1.IsParameterized);
            Debug.Assert(childContent2.IsParameterized);

            return(RazorDiagnostic.Create(
                       ChildContentRepeatedParameterName,
                       source ?? SourceSpan.Undefined,
                       childContent1.AttributeName,
                       component1.TagName,
                       childContent1.ParameterName,
                       childContent2.AttributeName,
                       component2.TagName));
        }
Example #4
0
 public abstract void WriteComponentChildContent(CodeRenderingContext context, ComponentChildContentIntermediateNode node);