public abstract void EndWriterScope(CodeRenderingContext context);
Beispiel #2
0
 public abstract void WriteTemplate(CodeRenderingContext context, TemplateIntermediateNode node);
Beispiel #3
0
 public sealed override void EndWriterScope(CodeRenderingContext context)
 {
     throw new NotImplementedException(nameof(EndWriterScope));
 }
Beispiel #4
0
 public abstract void WriteComponentChildContent(CodeRenderingContext context, ComponentChildContentIntermediateNode node);
Beispiel #5
0
 public abstract void WriteHtmlBlock(CodeRenderingContext context, HtmlBlockIntermediateNode node);
        public void WriteTagHelperHtmlAttribute(CodeRenderingContext context, DefaultTagHelperHtmlAttributeIntermediateNode node)
        {
            if (context.Parent as TagHelperIntermediateNode == null)
            {
                var message = Resources.FormatIntermediateNodes_InvalidParentNode(node.GetType(), typeof(TagHelperIntermediateNode));
                throw new InvalidOperationException(message);
            }

            if (context.Options.DesignTime)
            {
                context.RenderChildren(node);
            }
            else
            {
                var attributeValueStyleParameter = $"{HtmlAttributeValueStyleTypeName}.{node.AttributeStructure}";
                var isConditionalAttributeValue  = node.Children.Any(
                    child => child is CSharpExpressionAttributeValueIntermediateNode || child is CSharpCodeAttributeValueIntermediateNode);

                // All simple text and minimized attributes will be pre-allocated.
                if (isConditionalAttributeValue)
                {
                    // Dynamic attribute value should be run through the conditional attribute removal system. It's
                    // unbound and contains C#.

                    // TagHelper attribute rendering is buffered by default. We do not want to write to the current
                    // writer.
                    var valuePieceCount = node.Children.Count(
                        child =>
                        child is HtmlAttributeValueIntermediateNode ||
                        child is CSharpExpressionAttributeValueIntermediateNode ||
                        child is CSharpCodeAttributeValueIntermediateNode ||
                        child is ExtensionIntermediateNode);

                    context.CodeWriter
                    .WriteStartMethodInvocation(BeginAddHtmlAttributeValuesMethodName)
                    .Write(ExecutionContextVariableName)
                    .WriteParameterSeparator()
                    .WriteStringLiteral(node.AttributeName)
                    .WriteParameterSeparator()
                    .Write(valuePieceCount.ToString(CultureInfo.InvariantCulture))
                    .WriteParameterSeparator()
                    .Write(attributeValueStyleParameter)
                    .WriteEndMethodInvocation();

                    context.RenderChildren(node, new TagHelperHtmlAttributeRuntimeNodeWriter());

                    context.CodeWriter
                    .WriteMethodInvocation(
                        EndAddHtmlAttributeValuesMethodName,
                        ExecutionContextVariableName);
                }
                else
                {
                    // This is a data-* attribute which includes C#. Do not perform the conditional attribute removal or
                    // other special cases used when IsDynamicAttributeValue(). But the attribute must still be buffered to
                    // determine its final value.

                    // Attribute value is not plain text, must be buffered to determine its final value.
                    context.CodeWriter.WriteMethodInvocation(BeginWriteTagHelperAttributeMethodName);

                    // We're building a writing scope around the provided chunks which captures everything written from the
                    // page. Therefore, we do not want to write to any other buffer since we're using the pages buffer to
                    // ensure we capture all content that's written, directly or indirectly.
                    context.RenderChildren(node, new RuntimeNodeWriter());

                    context.CodeWriter
                    .WriteStartAssignment(StringValueBufferVariableName)
                    .WriteMethodInvocation(EndWriteTagHelperAttributeMethodName)
                    .WriteStartInstanceMethodInvocation(
                        ExecutionContextVariableName,
                        ExecutionContextAddHtmlAttributeMethodName)
                    .WriteStringLiteral(node.AttributeName)
                    .WriteParameterSeparator()
                    .WriteStartMethodInvocation(MarkAsHtmlEncodedMethodName)
                    .Write(StringValueBufferVariableName)
                    .WriteEndMethodInvocation(endLine: false)
                    .WriteParameterSeparator()
                    .Write(attributeValueStyleParameter)
                    .WriteEndMethodInvocation();
                }
            }
        }
 private static void Push(CodeRenderingContext context, TagHelperIntermediateNode node)
 {
     ((DefaultCodeRenderingContext)context).AncestorsInternal.Push(node);
 }
Beispiel #8
0
        private void WriteDesignTimeDirectiveToken(CodeRenderingContext context, DirectiveTokenIntermediateNode node)
        {
            var tokenKind = node.DirectiveToken.Kind;

            if (!node.Source.HasValue ||
                !string.Equals(
                    context.SourceDocument?.FilePath,
                    node.Source.Value.FilePath,
                    StringComparison.OrdinalIgnoreCase))
            {
                // We don't want to handle directives from imports.
                return;
            }

            if (tokenKind == DirectiveTokenKind.Attribute)
            {
                // We don't need to do anything special here.
                // We let the Roslyn take care of providing syntax errors for C# attributes.
                return;
            }

            // Wrap the directive token in a lambda to isolate variable names.
            context.CodeWriter
            .Write("((")
            .Write(typeof(Action).FullName)
            .Write(")(");
            using (context.CodeWriter.BuildLambda())
            {
                var originalIndent = context.CodeWriter.CurrentIndent;
                context.CodeWriter.CurrentIndent = 0;
                switch (tokenKind)
                {
                case DirectiveTokenKind.Type:

                    if (string.IsNullOrEmpty(node.Content))
                    {
                        // This is most likely a marker token.
                        WriteMarkerToken(context, node);
                        break;
                    }

                    // {node.Content} __typeHelper = default({node.Content});
                    using (context.CodeWriter.BuildLinePragma(node.Source, context))
                    {
                        context.AddSourceMappingFor(node);
                        context.CodeWriter
                        .Write(node.Content)
                        .Write(" ")
                        .WriteStartAssignment(TypeHelper)
                        .Write("default");

                        if (!context.Options.SuppressNullabilityEnforcement)
                        {
                            context.CodeWriter.Write("!");
                        }

                        context.CodeWriter.WriteLine(";");
                    }
                    break;

                case DirectiveTokenKind.Member:

                    if (string.IsNullOrEmpty(node.Content))
                    {
                        // This is most likely a marker token.
                        WriteMarkerToken(context, node);
                        break;
                    }

                    // global::System.Object {node.content} = null;
                    using (context.CodeWriter.BuildLinePragma(node.Source, context))
                    {
                        context.CodeWriter
                        .Write("global::")
                        .Write(typeof(object).FullName)
                        .Write(" ");

                        context.AddSourceMappingFor(node);
                        context.CodeWriter
                        .Write(node.Content)
                        .Write(" = null");

                        if (!context.Options.SuppressNullabilityEnforcement)
                        {
                            context.CodeWriter.Write("!");
                        }

                        context.CodeWriter.WriteLine(";");
                    }
                    break;

                case DirectiveTokenKind.Namespace:

                    if (string.IsNullOrEmpty(node.Content))
                    {
                        // This is most likely a marker token.
                        WriteMarkerToken(context, node);
                        break;
                    }

                    // global::System.Object __typeHelper = nameof({node.Content});
                    using (context.CodeWriter.BuildLinePragma(node.Source, context))
                    {
                        context.CodeWriter
                        .Write("global::")
                        .Write(typeof(object).FullName)
                        .Write(" ")
                        .WriteStartAssignment(TypeHelper);

                        context.CodeWriter.Write("nameof(");

                        context.AddSourceMappingFor(node);
                        context.CodeWriter
                        .Write(node.Content)
                        .WriteLine(");");
                    }
                    break;

                case DirectiveTokenKind.String:

                    // global::System.Object __typeHelper = "{node.Content}";
                    using (context.CodeWriter.BuildLinePragma(node.Source, context))
                    {
                        context.CodeWriter
                        .Write("global::")
                        .Write(typeof(object).FullName)
                        .Write(" ")
                        .WriteStartAssignment(TypeHelper);

                        if (node.Content.StartsWith("\"", StringComparison.Ordinal))
                        {
                            context.AddSourceMappingFor(node);
                            context.CodeWriter.Write(node.Content);
                        }
                        else
                        {
                            context.CodeWriter.Write("\"");
                            context.AddSourceMappingFor(node);
                            context.CodeWriter
                            .Write(node.Content)
                            .Write("\"");
                        }

                        context.CodeWriter.WriteLine(";");
                    }
                    break;

                case DirectiveTokenKind.Boolean:
                    // global::System.Boolean __typeHelper = {node.Content};
                    using (context.CodeWriter.BuildLinePragma(node.Source, context))
                    {
                        context.CodeWriter
                        .Write("global::")
                        .Write(typeof(bool).FullName)
                        .Write(" ")
                        .WriteStartAssignment(TypeHelper);

                        context.AddSourceMappingFor(node);
                        context.CodeWriter.Write(node.Content);
                        context.CodeWriter.WriteLine(";");
                    }
                    break;
                }
                context.CodeWriter.CurrentIndent = originalIndent;
            }
            context.CodeWriter.WriteLine("))();");
        }
Beispiel #9
0
        public void SetUp()
        {
            TestingCodeBox box = new TestingCodeBox();

            _context = box.RenderingContext;
        }
        private void WriteDesignTimeDirectiveToken(CodeRenderingContext context, DirectiveTokenIntermediateNode node)
        {
            var tokenKind = node.DirectiveToken.Kind;

            if (!node.Source.HasValue ||
                !string.Equals(
                    context.SourceDocument?.FilePath,
                    node.Source.Value.FilePath,
                    StringComparison.OrdinalIgnoreCase))
            {
                // We don't want to handle directives from imports.
                return;
            }

            // Wrap the directive token in a lambda to isolate variable names.
            context.CodeWriter
            .Write("((")
            .Write(typeof(Action).FullName)
            .Write(")(");
            using (context.CodeWriter.BuildLambda())
            {
                var originalIndent = context.CodeWriter.CurrentIndent;
                context.CodeWriter.CurrentIndent = 0;
                switch (tokenKind)
                {
                case DirectiveTokenKind.Type:

                    if (string.IsNullOrEmpty(node.Content))
                    {
                        // This is most likely a marker token.
                        WriteMarkerToken(context, node);
                        break;
                    }

                    // {node.Content} __typeHelper = default({node.Content});

                    context.AddSourceMappingFor(node);
                    context.CodeWriter
                    .Write(node.Content)
                    .Write(" ")
                    .WriteStartAssignment(TypeHelper)
                    .Write("default(")
                    .Write(node.Content)
                    .WriteLine(");");
                    break;

                case DirectiveTokenKind.Member:

                    if (string.IsNullOrEmpty(node.Content))
                    {
                        // This is most likely a marker token.
                        WriteMarkerToken(context, node);
                        break;
                    }

                    // global::System.Object {node.content} = null;

                    context.CodeWriter
                    .Write("global::")
                    .Write(typeof(object).FullName)
                    .Write(" ");

                    context.AddSourceMappingFor(node);
                    context.CodeWriter
                    .Write(node.Content)
                    .WriteLine(" = null;");
                    break;

                case DirectiveTokenKind.Namespace:

                    if (string.IsNullOrEmpty(node.Content))
                    {
                        // This is most likely a marker token.
                        WriteMarkerToken(context, node);
                        break;
                    }

                    // global::System.Object __typeHelper = nameof({node.Content});

                    context.CodeWriter
                    .Write("global::")
                    .Write(typeof(object).FullName)
                    .Write(" ")
                    .WriteStartAssignment(TypeHelper);

                    context.CodeWriter.Write("nameof(");

                    context.AddSourceMappingFor(node);
                    context.CodeWriter
                    .Write(node.Content)
                    .WriteLine(");");
                    break;

                case DirectiveTokenKind.String:

                    // global::System.Object __typeHelper = "{node.Content}";

                    context.CodeWriter
                    .Write("global::")
                    .Write(typeof(object).FullName)
                    .Write(" ")
                    .WriteStartAssignment(TypeHelper);

                    if (node.Content.StartsWith("\"", StringComparison.Ordinal))
                    {
                        context.AddSourceMappingFor(node);
                        context.CodeWriter.Write(node.Content);
                    }
                    else
                    {
                        context.CodeWriter.Write("\"");
                        context.AddSourceMappingFor(node);
                        context.CodeWriter
                        .Write(node.Content)
                        .Write("\"");
                    }

                    context.CodeWriter.WriteLine(";");
                    break;
                }
                context.CodeWriter.CurrentIndent = originalIndent;
            }
            context.CodeWriter.WriteLine("))();");
        }
 public void WriteTemplate(CodeRenderingContext context, TemplateIntermediateNode node)
 {
     // This is OK because this will only be plugged in by the component code target
     // not globally.
     ((ComponentNodeWriter)context.NodeWriter).WriteTemplate(context, node);
 }
 public override void WriteNode(CodeTarget target, CodeRenderingContext context)
 {
     throw new NotImplementedException();
 }
 public void WriteTemplate(CodeRenderingContext context, TemplateIntermediateNode node)
 {
     ((BlazorNodeWriter)context.NodeWriter).WriteTemplate(context, node);
 }
Beispiel #14
0
 public override void WriteNode(CodeTarget target, CodeRenderingContext context)
 {
     context.CodeWriter.WriteLine("MyExtensionNode");
 }
Beispiel #15
0
        // Currently the same for design time and runtime
        public override void WriteComponentTypeInferenceMethod(CodeRenderingContext context, ComponentTypeInferenceMethodIntermediateNode node)
        {
            if (context == null)
            {
                throw new ArgumentNullException(nameof(context));
            }

            if (node == null)
            {
                throw new ArgumentNullException(nameof(node));
            }

            var parameters = GetTypeInferenceMethodParameters(node);

            // This is really similar to the code in WriteComponentAttribute and WriteComponentChildContent - except simpler because
            // attributes and child contents look like variables.
            //
            // Looks like:
            //
            //  public static void CreateFoo_0<T1, T2>(RenderTreeBuilder __builder, int seq, int __seq0, T1 __arg0, int __seq1, global::System.Collections.Generic.List<T2> __arg1, int __seq2, string __arg2)
            //  {
            //      builder.OpenComponent<Foo<T1, T2>>();
            //      builder.AddAttribute(__seq0, "Attr0", __arg0);
            //      builder.AddAttribute(__seq1, "Attr1", __arg1);
            //      builder.AddAttribute(__seq2, "Attr2", __arg2);
            //      builder.CloseComponent();
            //  }
            //
            // As a special case, we need to generate a thunk for captures in this block instead of using
            // them verbatim.
            //
            // The problem is that RenderTreeBuilder wants an Action<object>. The caller can't write the type
            // name if it contains generics, and we can't write the variable they want to assign to.
            var writer = context.CodeWriter;

            writer.Write("public static void ");
            writer.Write(node.MethodName);
            writer.Write("<");
            writer.Write(string.Join(", ", node.Component.Component.GetTypeParameters().Select(a => a.Name)));
            writer.Write(">");

            writer.Write("(");
            writer.Write("global::");
            writer.Write(ComponentsApi.RenderTreeBuilder.FullTypeName);
            writer.Write(" ");
            writer.Write(ComponentsApi.RenderTreeBuilder.BuilderParameter);
            writer.Write(", ");
            writer.Write("int seq");

            if (parameters.Count > 0)
            {
                writer.Write(", ");
            }

            for (var i = 0; i < parameters.Count; i++)
            {
                if (!string.IsNullOrEmpty(parameters[i].SeqName))
                {
                    writer.Write("int ");
                    writer.Write(parameters[i].SeqName);
                    writer.Write(", ");
                }

                writer.Write(parameters[i].TypeName);
                writer.Write(" ");
                writer.Write(parameters[i].ParameterName);

                if (i < parameters.Count - 1)
                {
                    writer.Write(", ");
                }
            }

            writer.Write(")");
            writer.WriteLine();

            writer.WriteLine("{");

            // _builder.OpenComponent<TComponent>(42);
            context.CodeWriter.Write(ComponentsApi.RenderTreeBuilder.BuilderParameter);
            context.CodeWriter.Write(".");
            context.CodeWriter.Write(ComponentsApi.RenderTreeBuilder.OpenComponent);
            context.CodeWriter.Write("<");
            context.CodeWriter.Write(node.Component.TypeName);
            context.CodeWriter.Write(">(");
            context.CodeWriter.Write("seq");
            context.CodeWriter.Write(");");
            context.CodeWriter.WriteLine();

            foreach (var parameter in parameters)
            {
                switch (parameter.Source)
                {
                case ComponentAttributeIntermediateNode attribute:
                    context.CodeWriter.WriteStartInstanceMethodInvocation(ComponentsApi.RenderTreeBuilder.BuilderParameter, ComponentsApi.RenderTreeBuilder.AddAttribute);
                    context.CodeWriter.Write(parameter.SeqName);
                    context.CodeWriter.Write(", ");

                    context.CodeWriter.Write($"\"{attribute.AttributeName}\"");
                    context.CodeWriter.Write(", ");

                    context.CodeWriter.Write(parameter.ParameterName);
                    context.CodeWriter.WriteEndMethodInvocation();
                    break;

                case SplatIntermediateNode:
                    context.CodeWriter.WriteStartInstanceMethodInvocation(ComponentsApi.RenderTreeBuilder.BuilderParameter, ComponentsApi.RenderTreeBuilder.AddMultipleAttributes);
                    context.CodeWriter.Write(parameter.SeqName);
                    context.CodeWriter.Write(", ");

                    context.CodeWriter.Write(parameter.ParameterName);
                    context.CodeWriter.WriteEndMethodInvocation();
                    break;

                case ComponentChildContentIntermediateNode childContent:
                    context.CodeWriter.WriteStartInstanceMethodInvocation(ComponentsApi.RenderTreeBuilder.BuilderParameter, ComponentsApi.RenderTreeBuilder.AddAttribute);
                    context.CodeWriter.Write(parameter.SeqName);
                    context.CodeWriter.Write(", ");

                    context.CodeWriter.Write($"\"{childContent.AttributeName}\"");
                    context.CodeWriter.Write(", ");

                    context.CodeWriter.Write(parameter.ParameterName);
                    context.CodeWriter.WriteEndMethodInvocation();
                    break;

                case SetKeyIntermediateNode:
                    context.CodeWriter.WriteStartInstanceMethodInvocation(ComponentsApi.RenderTreeBuilder.BuilderParameter, ComponentsApi.RenderTreeBuilder.SetKey);
                    context.CodeWriter.Write(parameter.ParameterName);
                    context.CodeWriter.WriteEndMethodInvocation();
                    break;

                case ReferenceCaptureIntermediateNode capture:
                    context.CodeWriter.WriteStartInstanceMethodInvocation(ComponentsApi.RenderTreeBuilder.BuilderParameter, capture.IsComponentCapture ? ComponentsApi.RenderTreeBuilder.AddComponentReferenceCapture : ComponentsApi.RenderTreeBuilder.AddElementReferenceCapture);
                    context.CodeWriter.Write(parameter.SeqName);
                    context.CodeWriter.Write(", ");

                    var cast = capture.IsComponentCapture ? $"({capture.ComponentCaptureTypeName})" : string.Empty;
                    context.CodeWriter.Write($"(__value) => {{ {parameter.ParameterName}({cast}__value); }}");
                    context.CodeWriter.WriteEndMethodInvocation();
                    break;

                case CascadingGenericTypeParameter:
                    // We only use the synthetic cascading parameters for type inference
                    break;

                default:
                    throw new InvalidOperationException($"Not implemented: type inference method parameter from source {parameter.Source}");
                }
            }

            context.CodeWriter.WriteInstanceMethodInvocation(ComponentsApi.RenderTreeBuilder.BuilderParameter, ComponentsApi.RenderTreeBuilder.CloseComponent);

            writer.WriteLine("}");

            if (node.Component.Component.SuppliesCascadingGenericParameters())
            {
                // If this component cascades any generic parameters, we'll need to be able to capture its type inference
                // args at the call site. The point of this is to ensure that:
                //
                // [1] We only evaluate each expression once
                // [2] We evaluate them in the correct order matching the developer's source
                // [3] We can even make variables for lambdas or other expressions that can't just be assigned to implicitly-typed vars.
                //
                // We do that by emitting a method like the following. It has exactly the same generic type inference
                // characteristics as the regular CreateFoo_0 method emitted earlier
                //
                //  public static void CreateFoo_0_CaptureParameters<T1, T2>(T1 __arg0, out T1 __arg0_out, global::System.Collections.Generic.List<T2> __arg1, out global::System.Collections.Generic.List<T2> __arg1_out, int __seq2, string __arg2, out string __arg2_out)
                //  {
                //      __arg0_out = __arg0;
                //      __arg1_out = __arg1;
                //      __arg2_out = __arg2;
                //  }
                //
                writer.WriteLine();
                writer.Write("public static void ");
                writer.Write(node.MethodName);
                writer.Write("_CaptureParameters<");
                writer.Write(string.Join(", ", node.Component.Component.GetTypeParameters().Select(a => a.Name)));
                writer.Write(">");

                writer.Write("(");
                var isFirst = true;
                foreach (var parameter in parameters.Where(p => p.UsedForTypeInference))
                {
                    if (isFirst)
                    {
                        isFirst = false;
                    }
                    else
                    {
                        writer.Write(", ");
                    }

                    writer.Write(parameter.TypeName);
                    writer.Write(" ");
                    writer.Write(parameter.ParameterName);
                    writer.Write(", out ");
                    writer.Write(parameter.TypeName);
                    writer.Write(" ");
                    writer.Write(parameter.ParameterName);
                    writer.Write("_out");
                }

                writer.WriteLine(")");
                writer.WriteLine("{");
                foreach (var parameter in parameters.Where(p => p.UsedForTypeInference))
                {
                    writer.Write("    ");
                    writer.Write(parameter.ParameterName);
                    writer.Write("_out = ");
                    writer.Write(parameter.ParameterName);
                    writer.WriteLine(";");
                }
                writer.WriteLine("}");
            }
        }
Beispiel #16
0
 public override void WriteNode(CodeTarget target, CodeRenderingContext context)
 => context.CodeWriter.WriteAutoPropertyDeclaration(
     _injectedPropertyModifiers,
     TypeName,
     MemberName);
Beispiel #17
0
        public static CodeWriter WritePadding(this CodeWriter writer, int offset, SourceSpan?span, CodeRenderingContext context)
        {
            if (span == null)
            {
                return(writer);
            }

            var basePadding     = CalculatePadding();
            var resolvedPadding = Math.Max(basePadding - offset, 0);

            if (context.Options.IndentWithTabs)
            {
                // Avoid writing directly to the StringBuilder here, that will throw off the manual indexing
                // done by the base class.
                var tabs = resolvedPadding / context.Options.IndentSize;
                for (var i = 0; i < tabs; i++)
                {
                    writer.Write("\t");
                }

                var spaces = resolvedPadding % context.Options.IndentSize;
                for (var i = 0; i < spaces; i++)
                {
                    writer.Write(" ");
                }
            }
            else
            {
                for (var i = 0; i < resolvedPadding; i++)
                {
                    writer.Write(" ");
                }
            }

            return(writer);

            int CalculatePadding()
            {
                var spaceCount = 0;

                for (var i = span.Value.AbsoluteIndex - 1; i >= 0; i--)
                {
                    var @char = context.SourceDocument[i];
                    if (@char == '\n' || @char == '\r')
                    {
                        break;
                    }
                    else if (@char == '\t')
                    {
                        spaceCount += context.Options.IndentSize;
                    }
                    else
                    {
                        spaceCount++;
                    }
                }

                return(spaceCount);
            }
        }
Beispiel #18
0
 public abstract void WriteComponentTypeArgument(CodeRenderingContext context, ComponentTypeArgumentExtensionNode node);
        public void WriteTagHelperProperty(CodeRenderingContext context, DefaultTagHelperPropertyIntermediateNode node)
        {
            var tagHelperNode = context.Parent as TagHelperIntermediateNode;

            if (context.Parent == null)
            {
                var message = Resources.FormatIntermediateNodes_InvalidParentNode(node.GetType(), typeof(TagHelperIntermediateNode));
                throw new InvalidOperationException(message);
            }

            if (!context.Options.DesignTime)
            {
                // Ensure that the property we're trying to set has initialized its dictionary bound properties.
                if (node.IsIndexerNameMatch &&
                    object.ReferenceEquals(FindFirstUseOfIndexer(tagHelperNode, node), node))
                {
                    // Throw a reasonable Exception at runtime if the dictionary property is null.
                    context.CodeWriter
                    .Write("if (")
                    .Write(node.FieldName)
                    .Write(".")
                    .Write(node.PropertyName)
                    .WriteLine(" == null)");
                    using (context.CodeWriter.BuildScope())
                    {
                        // System is in Host.NamespaceImports for all MVC scenarios. No need to generate FullName
                        // of InvalidOperationException type.
                        context.CodeWriter
                        .Write("throw ")
                        .WriteStartNewObject(nameof(InvalidOperationException))
                        .WriteStartMethodInvocation(FormatInvalidIndexerAssignmentMethodName)
                        .WriteStringLiteral(node.AttributeName)
                        .WriteParameterSeparator()
                        .WriteStringLiteral(node.TagHelper.GetTypeName())
                        .WriteParameterSeparator()
                        .WriteStringLiteral(node.PropertyName)
                        .WriteEndMethodInvocation(endLine: false) // End of method call
                        .WriteEndMethodInvocation();              // End of new expression / throw statement
                    }
                }
            }

            // If this is not the first use of the attribute value, we need to evaluate the expression and assign it to
            // the tag helper property.
            //
            // Otherwise, the value has already been computed and assigned to another tag helper. We just need to
            // copy from that tag helper to this one.
            //
            // This is important because we can't evaluate the expression twice due to side-effects.
            var firstUseOfAttribute = FindFirstUseOfAttribute(tagHelperNode, node);

            if (!object.ReferenceEquals(firstUseOfAttribute, node))
            {
                // If we get here, this value has already been used. We just need to copy the value.
                context.CodeWriter
                .WriteStartAssignment(GetPropertyAccessor(node))
                .Write(GetPropertyAccessor(firstUseOfAttribute))
                .WriteLine(";");

                return;
            }

            // If we get there, this is the first time seeing this property so we need to evaluate the expression.
            if (node.BoundAttribute.ExpectsStringValue(node.AttributeName))
            {
                if (context.Options.DesignTime)
                {
                    context.RenderChildren(node);

                    context.CodeWriter.WriteStartAssignment(GetPropertyAccessor(node));
                    if (node.Children.Count == 1 && node.Children.First() is HtmlContentIntermediateNode htmlNode)
                    {
                        var content = GetContent(htmlNode);
                        context.CodeWriter.WriteStringLiteral(content);
                    }
                    else
                    {
                        context.CodeWriter.Write("string.Empty");
                    }
                    context.CodeWriter.WriteLine(";");
                }
                else
                {
                    context.CodeWriter.WriteMethodInvocation(BeginWriteTagHelperAttributeMethodName);

                    context.RenderChildren(node, new LiteralRuntimeNodeWriter());

                    context.CodeWriter
                    .WriteStartAssignment(StringValueBufferVariableName)
                    .WriteMethodInvocation(EndWriteTagHelperAttributeMethodName)
                    .WriteStartAssignment(GetPropertyAccessor(node))
                    .Write(StringValueBufferVariableName)
                    .WriteLine(";");
                }
            }
            else
            {
                if (context.Options.DesignTime)
                {
                    var firstMappedChild = node.Children.FirstOrDefault(child => child.Source != null) as IntermediateNode;
                    var valueStart       = firstMappedChild?.Source;

                    using (context.CodeWriter.BuildLinePragma(node.Source, context))
                    {
                        var accessor = GetPropertyAccessor(node);
                        var assignmentPrefixLength = accessor.Length + " = ".Length;
                        if (node.BoundAttribute.IsEnum &&
                            node.Children.Count == 1 &&
                            node.Children.First() is IntermediateToken token &&
                            token.IsCSharp)
                        {
                            assignmentPrefixLength += $"global::{node.BoundAttribute.TypeName}.".Length;

                            if (valueStart != null)
                            {
                                context.CodeWriter.WritePadding(assignmentPrefixLength, node.Source, context);
                            }

                            context.CodeWriter
                            .WriteStartAssignment(accessor)
                            .Write("global::")
                            .Write(node.BoundAttribute.TypeName)
                            .Write(".");
                        }
                        else
                        {
                            if (valueStart != null)
                            {
                                context.CodeWriter.WritePadding(assignmentPrefixLength, node.Source, context);
                            }

                            context.CodeWriter.WriteStartAssignment(GetPropertyAccessor(node));
                        }

                        if (node.Children.Count == 0 &&
                            node.AttributeStructure == AttributeStructure.Minimized &&
                            node.BoundAttribute.ExpectsBooleanValue(node.AttributeName))
                        {
                            // If this is a minimized boolean attribute, set the value to true.
                            context.CodeWriter.Write("true");
                        }
                        else
                        {
                            RenderTagHelperAttributeInline(context, node, node.Source);
                        }

                        context.CodeWriter.WriteLine(";");
                    }
                }
Beispiel #20
0
        // Currently the same for design time and runtime
        public void WriteComponentTypeInferenceMethod(CodeRenderingContext context, ComponentTypeInferenceMethodIntermediateNode node)
        {
            if (context == null)
            {
                throw new ArgumentNullException(nameof(context));
            }

            if (node == null)
            {
                throw new ArgumentNullException(nameof(node));
            }

            // This is ugly because CodeWriter doesn't allow us to erase, but we need to comma-delimit. So we have to
            // materizalize something can iterate, or use string.Join. We'll need this multiple times, so materializing
            // it.
            var parameters = GetParameterDeclarations();

            // This is really similar to the code in WriteComponentAttribute and WriteComponentChildContent - except simpler because
            // attributes and child contents look like variables.
            //
            // Looks like:
            //
            //  public static void CreateFoo_0<T1, T2>(RenderTreeBuilder builder, int seq, int __seq0, T1 __arg0, int __seq1, global::System.Collections.Generic.List<T2> __arg1, int __seq2, string __arg2)
            //  {
            //      builder.OpenComponent<Foo<T1, T2>>();
            //      builder.AddAttribute(__seq0, "Attr0", __arg0);
            //      builder.AddAttribute(__seq1, "Attr1", __arg1);
            //      builder.AddAttribute(__seq2, "Attr2", __arg2);
            //      builder.CloseComponent();
            //  }
            //
            // As a special case, we need to generate a thunk for captures in this block instead of using
            // them verbatim.
            //
            // The problem is that RenderTreeBuilder wants an Action<object>. The caller can't write the type
            // name if it contains generics, and we can't write the variable they want to assign to.
            var writer = context.CodeWriter;

            writer.Write("public static void ");
            writer.Write(node.MethodName);

            writer.Write("<");
            writer.Write(string.Join(", ", node.Component.Component.GetTypeParameters().Select(a => a.Name)));
            writer.Write(">");

            writer.Write("(");
            writer.Write("global::");
            writer.Write(ComponentsApi.RenderTreeBuilder.FullTypeName);
            writer.Write(" builder");
            writer.Write(", ");
            writer.Write("int seq");

            if (parameters.Count > 0)
            {
                writer.Write(", ");
            }

            for (var i = 0; i < parameters.Count; i++)
            {
                writer.Write("int ");
                writer.Write(parameters[i].seqName);

                writer.Write(", ");
                writer.Write(parameters[i].typeName);
                writer.Write(" ");
                writer.Write(parameters[i].parameterName);

                if (i < parameters.Count - 1)
                {
                    writer.Write(", ");
                }
            }

            writer.Write(")");
            writer.WriteLine();

            writer.WriteLine("{");

            // builder.OpenComponent<TComponent>(42);
            context.CodeWriter.Write("builder");
            context.CodeWriter.Write(".");
            context.CodeWriter.Write(ComponentsApi.RenderTreeBuilder.OpenComponent);
            context.CodeWriter.Write("<");
            context.CodeWriter.Write(node.Component.TypeName);
            context.CodeWriter.Write(">(");
            context.CodeWriter.Write("seq");
            context.CodeWriter.Write(");");
            context.CodeWriter.WriteLine();

            var index = 0;

            foreach (var attribute in node.Component.Attributes)
            {
                context.CodeWriter.WriteStartInstanceMethodInvocation("builder", ComponentsApi.RenderTreeBuilder.AddAttribute);
                context.CodeWriter.Write(parameters[index].seqName);
                context.CodeWriter.Write(", ");

                context.CodeWriter.Write($"\"{attribute.AttributeName}\"");
                context.CodeWriter.Write(", ");

                context.CodeWriter.Write(parameters[index].parameterName);
                context.CodeWriter.WriteEndMethodInvocation();

                index++;
            }

            foreach (var childContent in node.Component.ChildContents)
            {
                context.CodeWriter.WriteStartInstanceMethodInvocation("builder", ComponentsApi.RenderTreeBuilder.AddAttribute);
                context.CodeWriter.Write(parameters[index].seqName);
                context.CodeWriter.Write(", ");

                context.CodeWriter.Write($"\"{childContent.AttributeName}\"");
                context.CodeWriter.Write(", ");

                context.CodeWriter.Write(parameters[index].parameterName);
                context.CodeWriter.WriteEndMethodInvocation();

                index++;
            }

            foreach (var capture in node.Component.Captures)
            {
                context.CodeWriter.WriteStartInstanceMethodInvocation("builder", capture.IsComponentCapture ? ComponentsApi.RenderTreeBuilder.AddComponentReferenceCapture : ComponentsApi.RenderTreeBuilder.AddElementReferenceCapture);
                context.CodeWriter.Write(parameters[index].seqName);
                context.CodeWriter.Write(", ");

                var cast = capture.IsComponentCapture ? $"({capture.ComponentCaptureTypeName})" : string.Empty;
                context.CodeWriter.Write($"(__value) => {{ {parameters[index].parameterName}({cast}__value); }}");
                context.CodeWriter.WriteEndMethodInvocation();

                index++;
            }

            context.CodeWriter.WriteInstanceMethodInvocation("builder", ComponentsApi.RenderTreeBuilder.CloseComponent);

            writer.WriteLine("}");

            List <(string seqName, string typeName, string parameterName)> GetParameterDeclarations()
            {
                var p = new List <(string seqName, string typeName, string parameterName)>();

                foreach (var attribute in node.Component.Attributes)
                {
                    p.Add(($"__seq{p.Count}", attribute.TypeName, $"__arg{p.Count}"));
                }

                foreach (var childContent in node.Component.ChildContents)
                {
                    p.Add(($"__seq{p.Count}", childContent.TypeName, $"__arg{p.Count}"));
                }

                foreach (var capture in node.Component.Captures)
                {
                    p.Add(($"__seq{p.Count}", capture.TypeName, $"__arg{p.Count}"));
                }

                return(p);
            }
        }
Beispiel #21
0
 public abstract void WriteComponentAttribute(CodeRenderingContext context, ComponentAttributeExtensionNode node);
Beispiel #22
0
 public void DrawToGraphics(FormattedCode code, CodeRenderingContext args, Rectangle viewport)
 {
     CURRENTLINE_INDEX = args.CurrentLine;
 }
Beispiel #23
0
 public abstract void WriteHtmlElement(CodeRenderingContext context, HtmlElementIntermediateNode node);
Beispiel #24
0
 protected abstract void BeginWriteAttribute(CodeRenderingContext context, string key);
Beispiel #25
0
 public abstract void WriteReferenceCapture(CodeRenderingContext context, RefExtensionNode node);
Beispiel #26
0
 protected abstract void BeginWriteAttribute(CodeRenderingContext context, IntermediateNode expression);
Beispiel #27
0
 public sealed override void BeginWriterScope(CodeRenderingContext context, string writer)
 {
     throw new NotImplementedException(nameof(BeginWriterScope));
 }
Beispiel #28
0
 protected abstract void WriteReferenceCaptureInnards(CodeRenderingContext context, ReferenceCaptureIntermediateNode node, bool shouldTypeCheck);
 public abstract void WriteNode(CodeTarget target, CodeRenderingContext context);
 public abstract void BeginWriterScope(CodeRenderingContext context, string writer);