696 lines
33 KiB
C#
696 lines
33 KiB
C#
// 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.Globalization;
|
|
using System.Linq;
|
|
using System.Diagnostics;
|
|
using Microsoft.AspNetCore.Razor.Evolution.Intermediate;
|
|
using Microsoft.AspNetCore.Razor.Evolution.Legacy;
|
|
|
|
namespace Microsoft.AspNetCore.Razor.Evolution.CodeGeneration
|
|
{
|
|
internal class RuntimeCSharpRenderer : PageStructureCSharpRenderer
|
|
{
|
|
public RuntimeCSharpRenderer(CSharpRenderingContext context)
|
|
: base(context)
|
|
{
|
|
}
|
|
|
|
public override void VisitChecksum(ChecksumIRNode node)
|
|
{
|
|
if (!string.IsNullOrEmpty(node.Bytes))
|
|
{
|
|
Context.Writer
|
|
.Write("#pragma checksum \"")
|
|
.Write(node.Filename)
|
|
.Write("\" \"")
|
|
.Write(node.Guid)
|
|
.Write("\" \"")
|
|
.Write(node.Bytes)
|
|
.WriteLine("\"");
|
|
}
|
|
}
|
|
|
|
public override void VisitCSharpToken(CSharpTokenIRNode node)
|
|
{
|
|
Context.Writer.Write(node.Content);
|
|
}
|
|
|
|
public override void VisitHtml(HtmlContentIRNode node)
|
|
{
|
|
const int MaxStringLiteralLength = 1024;
|
|
|
|
var charactersConsumed = 0;
|
|
|
|
// Render the string in pieces to avoid Roslyn OOM exceptions at compile time: https://github.com/aspnet/External/issues/54
|
|
while (charactersConsumed < node.Content.Length)
|
|
{
|
|
string textToRender;
|
|
if (node.Content.Length <= MaxStringLiteralLength)
|
|
{
|
|
textToRender = node.Content;
|
|
}
|
|
else
|
|
{
|
|
var charactersToSubstring = Math.Min(MaxStringLiteralLength, node.Content.Length - charactersConsumed);
|
|
textToRender = node.Content.Substring(charactersConsumed, charactersToSubstring);
|
|
}
|
|
|
|
Context.Writer
|
|
.Write(Context.RenderingConventions.StartWriteLiteralMethod)
|
|
.WriteStringLiteral(textToRender)
|
|
.WriteEndMethodInvocation();
|
|
|
|
charactersConsumed += textToRender.Length;
|
|
}
|
|
}
|
|
|
|
public override void VisitCSharpExpression(CSharpExpressionIRNode node)
|
|
{
|
|
IDisposable linePragmaScope = null;
|
|
if (node.Source != null)
|
|
{
|
|
linePragmaScope = new LinePragmaWriter(Context.Writer, node.Source.Value);
|
|
var padding = BuildOffsetPadding(Context.RenderingConventions.StartWriteMethod.Length, node.Source.Value, Context);
|
|
Context.Writer.Write(padding);
|
|
}
|
|
|
|
Context.Writer.Write(Context.RenderingConventions.StartWriteMethod);
|
|
|
|
VisitDefault(node);
|
|
|
|
Context.Writer.WriteEndMethodInvocation();
|
|
|
|
linePragmaScope?.Dispose();
|
|
}
|
|
|
|
public override void VisitUsingStatement(UsingStatementIRNode node)
|
|
{
|
|
Context.Writer.WriteUsing(node.Content);
|
|
}
|
|
|
|
public override void VisitHtmlAttribute(HtmlAttributeIRNode node)
|
|
{
|
|
var valuePieceCount = node
|
|
.Children
|
|
.Count(child => child is HtmlAttributeValueIRNode || child is CSharpAttributeValueIRNode);
|
|
var prefixLocation = node.Source.Value.AbsoluteIndex;
|
|
var suffixLocation = node.Source.Value.AbsoluteIndex + node.Source.Value.Length - node.Suffix.Length;
|
|
Context.Writer
|
|
.Write(Context.RenderingConventions.StartBeginWriteAttributeMethod)
|
|
.WriteStringLiteral(node.Name)
|
|
.WriteParameterSeparator()
|
|
.WriteStringLiteral(node.Prefix)
|
|
.WriteParameterSeparator()
|
|
.Write(prefixLocation.ToString(CultureInfo.InvariantCulture))
|
|
.WriteParameterSeparator()
|
|
.WriteStringLiteral(node.Suffix)
|
|
.WriteParameterSeparator()
|
|
.Write(suffixLocation.ToString(CultureInfo.InvariantCulture))
|
|
.WriteParameterSeparator()
|
|
.Write(valuePieceCount.ToString(CultureInfo.InvariantCulture))
|
|
.WriteEndMethodInvocation();
|
|
|
|
VisitDefault(node);
|
|
|
|
Context.Writer
|
|
.Write(Context.RenderingConventions.StartEndWriteAttributeMethod)
|
|
.WriteEndMethodInvocation();
|
|
}
|
|
|
|
public override void VisitHtmlAttributeValue(HtmlAttributeValueIRNode node)
|
|
{
|
|
var prefixLocation = node.Source.Value.AbsoluteIndex;
|
|
var valueLocation = node.Source.Value.AbsoluteIndex + node.Prefix.Length;
|
|
var valueLength = node.Source.Value.Length;
|
|
Context.Writer
|
|
.Write(Context.RenderingConventions.StartWriteAttributeValueMethod)
|
|
.WriteStringLiteral(node.Prefix)
|
|
.WriteParameterSeparator()
|
|
.Write(prefixLocation.ToString(CultureInfo.InvariantCulture))
|
|
.WriteParameterSeparator()
|
|
.WriteStringLiteral(node.Content)
|
|
.WriteParameterSeparator()
|
|
.Write(valueLocation.ToString(CultureInfo.InvariantCulture))
|
|
.WriteParameterSeparator()
|
|
.Write(valueLength.ToString(CultureInfo.InvariantCulture))
|
|
.WriteParameterSeparator()
|
|
.WriteBooleanLiteral(true)
|
|
.WriteEndMethodInvocation();
|
|
}
|
|
|
|
public override void VisitCSharpAttributeValue(CSharpAttributeValueIRNode node)
|
|
{
|
|
const string ValueWriterName = "__razor_attribute_value_writer";
|
|
|
|
var expressionValue = node.Children.FirstOrDefault() as CSharpExpressionIRNode;
|
|
var linePragma = expressionValue != null ? new LinePragmaWriter(Context.Writer, node.Source.Value) : null;
|
|
var prefixLocation = node.Source.Value.AbsoluteIndex;
|
|
var valueLocation = node.Source.Value.AbsoluteIndex + node.Prefix.Length;
|
|
var valueLength = node.Source.Value.Length - node.Prefix.Length;
|
|
Context.Writer
|
|
.Write(Context.RenderingConventions.StartWriteAttributeValueMethod)
|
|
.WriteStringLiteral(node.Prefix)
|
|
.WriteParameterSeparator()
|
|
.Write(prefixLocation.ToString(CultureInfo.InvariantCulture))
|
|
.WriteParameterSeparator();
|
|
|
|
if (expressionValue != null)
|
|
{
|
|
Debug.Assert(node.Children.Count == 1);
|
|
|
|
RenderExpressionInline(expressionValue, Context);
|
|
}
|
|
else
|
|
{
|
|
// Not an expression; need to buffer the result.
|
|
Context.Writer.WriteStartNewObject("Microsoft.AspNetCore.Mvc.Razor.HelperResult" /* ORIGINAL: TemplateTypeName */);
|
|
|
|
var initialRenderingConventions = Context.RenderingConventions;
|
|
Context.RenderingConventions = new CSharpRedirectRenderingConventions(ValueWriterName, Context.Writer);
|
|
using (Context.Writer.BuildAsyncLambda(endLine: false, parameterNames: ValueWriterName))
|
|
{
|
|
VisitDefault(node);
|
|
}
|
|
Context.RenderingConventions = initialRenderingConventions;
|
|
|
|
Context.Writer.WriteEndMethodInvocation(false);
|
|
}
|
|
|
|
Context.Writer
|
|
.WriteParameterSeparator()
|
|
.Write(valueLocation.ToString(CultureInfo.InvariantCulture))
|
|
.WriteParameterSeparator()
|
|
.Write(valueLength.ToString(CultureInfo.InvariantCulture))
|
|
.WriteParameterSeparator()
|
|
.WriteBooleanLiteral(false)
|
|
.WriteEndMethodInvocation();
|
|
|
|
linePragma?.Dispose();
|
|
}
|
|
|
|
public override void VisitCSharpStatement(CSharpStatementIRNode node)
|
|
{
|
|
if (string.IsNullOrWhiteSpace(node.Content))
|
|
{
|
|
return;
|
|
}
|
|
|
|
if (node.Source != null)
|
|
{
|
|
using (new LinePragmaWriter(Context.Writer, node.Source.Value))
|
|
{
|
|
var padding = BuildOffsetPadding(0, node.Source.Value, Context);
|
|
Context.Writer
|
|
.Write(padding)
|
|
.WriteLine(node.Content);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
Context.Writer.WriteLine(node.Content);
|
|
}
|
|
}
|
|
|
|
public override void VisitTemplate(TemplateIRNode node)
|
|
{
|
|
const string ItemParameterName = "item";
|
|
const string TemplateWriterName = "__razor_template_writer";
|
|
|
|
Context.Writer
|
|
.Write(ItemParameterName).Write(" => ")
|
|
.WriteStartNewObject("Microsoft.AspNetCore.Mvc.Razor.HelperResult" /* ORIGINAL: TemplateTypeName */);
|
|
|
|
var initialRenderingConventions = Context.RenderingConventions;
|
|
Context.RenderingConventions = new CSharpRedirectRenderingConventions(TemplateWriterName, Context.Writer);
|
|
using (Context.Writer.BuildAsyncLambda(endLine: false, parameterNames: TemplateWriterName))
|
|
{
|
|
VisitDefault(node);
|
|
}
|
|
Context.RenderingConventions = initialRenderingConventions;
|
|
|
|
Context.Writer.WriteEndMethodInvocation(endLine: false);
|
|
}
|
|
|
|
public override void VisitTagHelper(TagHelperIRNode node)
|
|
{
|
|
var initialTagHelperRenderingContext = Context.TagHelperRenderingContext;
|
|
Context.TagHelperRenderingContext = new TagHelperRenderingContext();
|
|
VisitDefault(node);
|
|
Context.TagHelperRenderingContext = initialTagHelperRenderingContext;
|
|
}
|
|
|
|
public override void VisitInitializeTagHelperStructure(InitializeTagHelperStructureIRNode node)
|
|
{
|
|
// Call into the tag helper scope manager to start a new tag helper scope.
|
|
// Also capture the value as the current execution context.
|
|
Context.Writer
|
|
.WriteStartAssignment("__tagHelperExecutionContext" /* ORIGINAL: ExecutionContextVariableName */)
|
|
.WriteStartInstanceMethodInvocation(
|
|
"__tagHelperScopeManager" /* ORIGINAL: ScopeManagerVariableName */,
|
|
"Begin" /* ORIGINAL: ScopeManagerBeginMethodName */);
|
|
|
|
// Assign a unique ID for this instance of the source HTML tag. This must be unique
|
|
// per call site, e.g. if the tag is on the view twice, there should be two IDs.
|
|
Context.Writer.WriteStringLiteral(node.TagName)
|
|
.WriteParameterSeparator()
|
|
.Write("global::")
|
|
.Write("Microsoft.AspNetCore.Razor.TagHelpers.TagMode")
|
|
.Write(".")
|
|
.Write(node.TagMode.ToString())
|
|
.WriteParameterSeparator()
|
|
.WriteStringLiteral(Context.IdGenerator())
|
|
.WriteParameterSeparator();
|
|
|
|
// We remove and redirect writers so TagHelper authors can retrieve content.
|
|
var initialRenderingConventions = Context.RenderingConventions;
|
|
Context.RenderingConventions = new CSharpRenderingConventions(Context.Writer);
|
|
using (Context.Writer.BuildAsyncLambda(endLine: false))
|
|
{
|
|
VisitDefault(node);
|
|
}
|
|
Context.RenderingConventions = initialRenderingConventions;
|
|
|
|
Context.Writer.WriteEndMethodInvocation();
|
|
}
|
|
|
|
public override void VisitCreateTagHelper(CreateTagHelperIRNode node)
|
|
{
|
|
var tagHelperVariableName = GetTagHelperVariableName(node.TagHelperTypeName);
|
|
|
|
Context.Writer
|
|
.WriteStartAssignment(tagHelperVariableName)
|
|
.WriteStartMethodInvocation(
|
|
"CreateTagHelper" /* ORIGINAL: CreateTagHelperMethodName */,
|
|
"global::" + node.TagHelperTypeName)
|
|
.WriteEndMethodInvocation();
|
|
|
|
Context.Writer.WriteInstanceMethodInvocation(
|
|
"__tagHelperExecutionContext" /* ORIGINAL: ExecutionContextVariableName */,
|
|
"Add" /* ORIGINAL: ExecutionContextAddMethodName */,
|
|
tagHelperVariableName);
|
|
}
|
|
|
|
public override void VisitAddPreallocatedTagHelperHtmlAttribute(AddPreallocatedTagHelperHtmlAttributeIRNode node)
|
|
{
|
|
Context.Writer
|
|
.WriteStartInstanceMethodInvocation(
|
|
"__tagHelperExecutionContext" /* ORIGINAL: ExecutionContextVariableName */,
|
|
"AddHtmlAttribute" /* ORIGINAL: ExecutionContextAddHtmlAttributeMethodName */)
|
|
.Write(node.VariableName)
|
|
.WriteEndMethodInvocation();
|
|
}
|
|
|
|
public override void VisitAddTagHelperHtmlAttribute(AddTagHelperHtmlAttributeIRNode node)
|
|
{
|
|
var attributeValueStyleParameter = $"global::Microsoft.AspNetCore.Razor.TagHelpers.HtmlAttributeValueStyle.{node.ValueStyle}";
|
|
var isConditionalAttributeValue = node.Children.Any(child => child is CSharpAttributeValueIRNode);
|
|
|
|
// 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 HtmlAttributeValueIRNode || child is CSharpAttributeValueIRNode);
|
|
|
|
Context.Writer
|
|
.WriteStartMethodInvocation("BeginAddHtmlAttributeValues" /* ORIGINAL: BeginAddHtmlAttributeValuesMethodName */)
|
|
.Write("__tagHelperExecutionContext" /* ORIGINAL: ExecutionContextVariableName */)
|
|
.WriteParameterSeparator()
|
|
.WriteStringLiteral(node.Name)
|
|
.WriteParameterSeparator()
|
|
.Write(valuePieceCount.ToString(CultureInfo.InvariantCulture))
|
|
.WriteParameterSeparator()
|
|
.Write(attributeValueStyleParameter)
|
|
.WriteEndMethodInvocation();
|
|
|
|
var initialRenderingConventions = Context.RenderingConventions;
|
|
Context.RenderingConventions = new TagHelperHtmlAttributeRenderingConventions(Context.Writer);
|
|
VisitDefault(node);
|
|
Context.RenderingConventions = initialRenderingConventions;
|
|
|
|
Context.Writer
|
|
.WriteMethodInvocation(
|
|
"EndAddHtmlAttributeValues" /* ORIGINAL: EndAddHtmlAttributeValuesMethodName */,
|
|
"__tagHelperExecutionContext" /* ORIGINAL: 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.Writer.WriteMethodInvocation("BeginWriteTagHelperAttribute" /* ORIGINAL: 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.
|
|
var initialRenderingConventions = Context.RenderingConventions;
|
|
Context.RenderingConventions = new CSharpRenderingConventions(Context.Writer);
|
|
VisitDefault(node);
|
|
Context.RenderingConventions = initialRenderingConventions;
|
|
|
|
Context.Writer
|
|
.WriteStartAssignment("__tagHelperStringValueBuffer" /* ORIGINAL: StringValueBufferVariableName */)
|
|
.WriteMethodInvocation("EndWriteTagHelperAttribute" /* ORIGINAL: EndWriteTagHelperAttributeMethodName */)
|
|
.WriteStartInstanceMethodInvocation(
|
|
"__tagHelperExecutionContext" /* ORIGINAL: ExecutionContextVariableName */,
|
|
"AddHtmlAttribute" /* ORIGINAL: ExecutionContextAddHtmlAttributeMethodName */)
|
|
.WriteStringLiteral(node.Name)
|
|
.WriteParameterSeparator()
|
|
.WriteStartMethodInvocation("Html.Raw" /* ORIGINAL: MarkAsHtmlEncodedMethodName */)
|
|
.Write("__tagHelperStringValueBuffer" /* ORIGINAL: StringValueBufferVariableName */)
|
|
.WriteEndMethodInvocation(endLine: false)
|
|
.WriteParameterSeparator()
|
|
.Write(attributeValueStyleParameter)
|
|
.WriteEndMethodInvocation();
|
|
}
|
|
}
|
|
|
|
public override void VisitSetPreallocatedTagHelperProperty(SetPreallocatedTagHelperPropertyIRNode node)
|
|
{
|
|
var tagHelperVariableName = GetTagHelperVariableName(node.TagHelperTypeName);
|
|
var propertyValueAccessor = GetTagHelperPropertyAccessor(tagHelperVariableName, node.AttributeName, node.Descriptor);
|
|
var attributeValueAccessor = $"{node.VariableName}.Value" /* ORIGINAL: TagHelperAttributeValuePropertyName */;
|
|
Context.Writer
|
|
.WriteStartAssignment(propertyValueAccessor)
|
|
.Write("(string)")
|
|
.Write(attributeValueAccessor)
|
|
.WriteLine(";")
|
|
.WriteStartInstanceMethodInvocation(
|
|
"__tagHelperExecutionContext" /* ORIGINAL: ExecutionContextVariableName */,
|
|
"AddTagHelperAttribute" /* ORIGINAL: ExecutionContextAddTagHelperAttributeMethodName */)
|
|
.Write(node.VariableName)
|
|
.WriteEndMethodInvocation();
|
|
}
|
|
|
|
public override void VisitSetTagHelperProperty(SetTagHelperPropertyIRNode node)
|
|
{
|
|
var tagHelperVariableName = GetTagHelperVariableName(node.TagHelperTypeName);
|
|
var tagHelperRenderingContext = Context.TagHelperRenderingContext;
|
|
|
|
// Ensure that the property we're trying to set has initialized its dictionary bound properties.
|
|
if (node.Descriptor.IsIndexer &&
|
|
tagHelperRenderingContext.VerifiedPropertyDictionaries.Add(node.Descriptor.PropertyName))
|
|
{
|
|
// Throw a reasonable Exception at runtime if the dictionary property is null.
|
|
Context.Writer
|
|
.Write("if (")
|
|
.Write(tagHelperVariableName)
|
|
.Write(".")
|
|
.Write(node.Descriptor.PropertyName)
|
|
.WriteLine(" == null)");
|
|
using (Context.Writer.BuildScope())
|
|
{
|
|
// System is in Host.NamespaceImports for all MVC scenarios. No need to generate FullName
|
|
// of InvalidOperationException type.
|
|
Context.Writer
|
|
.Write("throw ")
|
|
.WriteStartNewObject(nameof(InvalidOperationException))
|
|
.WriteStartMethodInvocation("InvalidTagHelperIndexerAssignment" /* ORIGINAL: FormatInvalidIndexerAssignmentMethodName */)
|
|
.WriteStringLiteral(node.AttributeName)
|
|
.WriteParameterSeparator()
|
|
.WriteStringLiteral(node.TagHelperTypeName)
|
|
.WriteParameterSeparator()
|
|
.WriteStringLiteral(node.Descriptor.PropertyName)
|
|
.WriteEndMethodInvocation(endLine: false) // End of method call
|
|
.WriteEndMethodInvocation(); // End of new expression / throw statement
|
|
}
|
|
}
|
|
|
|
var propertyValueAccessor = GetTagHelperPropertyAccessor(tagHelperVariableName, node.AttributeName, node.Descriptor);
|
|
|
|
string previousValueAccessor;
|
|
if (tagHelperRenderingContext.RenderedBoundAttributes.TryGetValue(node.AttributeName, out previousValueAccessor))
|
|
{
|
|
Context.Writer
|
|
.WriteStartAssignment(propertyValueAccessor)
|
|
.Write(previousValueAccessor)
|
|
.WriteLine(";");
|
|
|
|
return;
|
|
}
|
|
else
|
|
{
|
|
tagHelperRenderingContext.RenderedBoundAttributes[node.AttributeName] = propertyValueAccessor;
|
|
}
|
|
|
|
if (node.Descriptor.IsStringProperty)
|
|
{
|
|
Context.Writer.WriteMethodInvocation("BeginWriteTagHelperAttribute" /* ORIGINAL: BeginWriteTagHelperAttributeMethodName */);
|
|
|
|
var initialRenderingConventions = Context.RenderingConventions;
|
|
Context.RenderingConventions = new CSharpLiteralCodeConventions(Context.Writer);
|
|
VisitDefault(node);
|
|
Context.RenderingConventions = initialRenderingConventions;
|
|
|
|
Context.Writer
|
|
.WriteStartAssignment("__tagHelperStringValueBuffer" /* ORIGINAL: StringValueBufferVariableName */)
|
|
.WriteMethodInvocation("EndWriteTagHelperAttribute" /* ORIGINAL: EndWriteTagHelperAttributeMethodName */)
|
|
.WriteStartAssignment(propertyValueAccessor)
|
|
.Write("__tagHelperStringValueBuffer" /* ORIGINAL: StringValueBufferVariableName */)
|
|
.WriteLine(";");
|
|
}
|
|
else
|
|
{
|
|
using (new LinePragmaWriter(Context.Writer, node.Source.Value))
|
|
{
|
|
Context.Writer.WriteStartAssignment(propertyValueAccessor);
|
|
|
|
if (node.Descriptor.IsEnum &&
|
|
node.Children.Count == 1 &&
|
|
node.Children.First() is HtmlContentIRNode)
|
|
{
|
|
Context.Writer
|
|
.Write("global::")
|
|
.Write(node.Descriptor.TypeName)
|
|
.Write(".");
|
|
}
|
|
|
|
RenderTagHelperAttributeInline(node, node.Source.Value);
|
|
|
|
Context.Writer.WriteLine(";");
|
|
}
|
|
}
|
|
|
|
// We need to inform the context of the attribute value.
|
|
Context.Writer
|
|
.WriteStartInstanceMethodInvocation(
|
|
"__tagHelperExecutionContext" /* ORIGINAL: ExecutionContextVariableName */,
|
|
"AddTagHelperAttribute" /* ORIGINAL: ExecutionContextAddTagHelperAttributeMethodName */)
|
|
.WriteStringLiteral(node.AttributeName)
|
|
.WriteParameterSeparator()
|
|
.Write(propertyValueAccessor)
|
|
.WriteParameterSeparator()
|
|
.Write($"global::Microsoft.AspNetCore.Razor.TagHelpers.HtmlAttributeValueStyle.{node.ValueStyle}")
|
|
.WriteEndMethodInvocation();
|
|
}
|
|
|
|
public override void VisitExecuteTagHelpers(ExecuteTagHelpersIRNode node)
|
|
{
|
|
Context.Writer
|
|
.Write("await ")
|
|
.WriteStartInstanceMethodInvocation(
|
|
"__tagHelperRunner" /* ORIGINAL: RunnerVariableName */,
|
|
"RunAsync" /* ORIGINAL: RunnerRunAsyncMethodName */)
|
|
.Write("__tagHelperExecutionContext" /* ORIGINAL: ExecutionContextVariableName */)
|
|
.WriteEndMethodInvocation();
|
|
|
|
var executionContextVariableName = "__tagHelperExecutionContext" /* ORIGINAL: ExecutionContextVariableName */;
|
|
var executionContextOutputPropertyName = "Output" /* ORIGINAL: ExecutionContextOutputPropertyName */;
|
|
var tagHelperOutputAccessor = $"{executionContextVariableName}.{executionContextOutputPropertyName}";
|
|
|
|
Context.Writer
|
|
.Write("if (!")
|
|
.Write(tagHelperOutputAccessor)
|
|
.Write(".")
|
|
.Write("IsContentModified" /* ORIGINAL: TagHelperOutputIsContentModifiedPropertyName */)
|
|
.WriteLine(")");
|
|
|
|
using (Context.Writer.BuildScope())
|
|
{
|
|
Context.Writer
|
|
.Write("await ")
|
|
.WriteInstanceMethodInvocation(
|
|
executionContextVariableName,
|
|
"SetOutputContentAsync" /* ORIGINAL: ExecutionContextSetOutputContentAsyncMethodName */);
|
|
}
|
|
|
|
Context.Writer
|
|
.Write(Context.RenderingConventions.StartWriteMethod)
|
|
.Write(tagHelperOutputAccessor)
|
|
.WriteEndMethodInvocation()
|
|
.WriteStartAssignment(executionContextVariableName)
|
|
.WriteInstanceMethodInvocation(
|
|
"__tagHelperScopeManager" /* ORIGINAL: ScopeManagerVariableName */,
|
|
"End" /* ORIGINAL: ScopeManagerEndMethodName */);
|
|
}
|
|
|
|
public override void VisitDeclarePreallocatedTagHelperHtmlAttribute(DeclarePreallocatedTagHelperHtmlAttributeIRNode node)
|
|
{
|
|
Context.Writer
|
|
.Write("private static readonly global::")
|
|
.Write("Microsoft.AspNetCore.Razor.TagHelpers.TagHelperAttribute" /* ORIGINAL: TagHelperAttributeTypeName */)
|
|
.Write(" ")
|
|
.Write(node.VariableName)
|
|
.Write(" = ")
|
|
.WriteStartNewObject("global::" + "Microsoft.AspNetCore.Razor.TagHelpers.TagHelperAttribute" /* ORIGINAL: TagHelperAttributeTypeName */)
|
|
.WriteStringLiteral(node.Name);
|
|
|
|
if (node.ValueStyle == HtmlAttributeValueStyle.Minimized)
|
|
{
|
|
Context.Writer.WriteEndMethodInvocation();
|
|
}
|
|
else
|
|
{
|
|
Context.Writer
|
|
.WriteParameterSeparator()
|
|
.WriteStartNewObject("global::" + "Microsoft.AspNetCore.Html.HtmlString" /* ORIGINAL: EncodedHtmlStringTypeName */)
|
|
.WriteStringLiteral(node.Value)
|
|
.WriteEndMethodInvocation(endLine: false)
|
|
.WriteParameterSeparator()
|
|
.Write($"global::Microsoft.AspNetCore.Razor.TagHelpers.HtmlAttributeValueStyle.{node.ValueStyle}")
|
|
.WriteEndMethodInvocation();
|
|
}
|
|
}
|
|
|
|
public override void VisitDeclarePreallocatedTagHelperAttribute(DeclarePreallocatedTagHelperAttributeIRNode node)
|
|
{
|
|
Context.Writer
|
|
.Write("private static readonly global::")
|
|
.Write("Microsoft.AspNetCore.Razor.TagHelpers.TagHelperAttribute" /* ORIGINAL: TagHelperAttributeTypeName */)
|
|
.Write(" ")
|
|
.Write(node.VariableName)
|
|
.Write(" = ")
|
|
.WriteStartNewObject("global::" + "Microsoft.AspNetCore.Razor.TagHelpers.TagHelperAttribute" /* ORIGINAL: TagHelperAttributeTypeName */)
|
|
.WriteStringLiteral(node.Name)
|
|
.WriteParameterSeparator()
|
|
.WriteStringLiteral(node.Value)
|
|
.WriteParameterSeparator()
|
|
.Write($"global::Microsoft.AspNetCore.Razor.TagHelpers.HtmlAttributeValueStyle.{node.ValueStyle}")
|
|
.WriteEndMethodInvocation();
|
|
}
|
|
|
|
public override void VisitDeclareTagHelperFields(DeclareTagHelperFieldsIRNode node)
|
|
{
|
|
Context.Writer.WriteLineHiddenDirective();
|
|
|
|
// Need to disable the warning "X is assigned to but never used." for the value buffer since
|
|
// whether it's used depends on how a TagHelper is used.
|
|
Context.Writer
|
|
.WritePragma("warning disable 0414")
|
|
.Write("private ")
|
|
.WriteVariableDeclaration("string", "__tagHelperStringValueBuffer" /* ORIGINAL: StringValueBufferVariableName */, value: null)
|
|
.WritePragma("warning restore 0414");
|
|
|
|
Context.Writer
|
|
.Write("private global::")
|
|
.WriteVariableDeclaration(
|
|
"Microsoft.AspNetCore.Razor.Runtime.TagHelpers.TagHelperExecutionContext" /* ORIGINAL: ExecutionContextTypeName */,
|
|
"__tagHelperExecutionContext" /* ORIGINAL: ExecutionContextVariableName */,
|
|
value: null);
|
|
|
|
Context.Writer
|
|
.Write("private global::")
|
|
.Write("Microsoft.AspNetCore.Razor.Runtime.TagHelpers.TagHelperRunner" /* ORIGINAL: RunnerTypeName */)
|
|
.Write(" ")
|
|
.Write("__tagHelperRunner" /* ORIGINAL: RunnerVariableName */)
|
|
.Write(" = new global::")
|
|
.Write("Microsoft.AspNetCore.Razor.Runtime.TagHelpers.TagHelperRunner" /* ORIGINAL: RunnerTypeName */)
|
|
.WriteLine("();");
|
|
|
|
const string backedScopeManageVariableName = "__backed" + "__tagHelperScopeManager" /* ORIGINAL: ScopeManagerVariableName */;
|
|
Context.Writer
|
|
.Write("private global::")
|
|
.WriteVariableDeclaration(
|
|
"Microsoft.AspNetCore.Razor.Runtime.TagHelpers.TagHelperScopeManager",
|
|
backedScopeManageVariableName,
|
|
value: null);
|
|
|
|
Context.Writer
|
|
.Write("private global::")
|
|
.Write("Microsoft.AspNetCore.Razor.Runtime.TagHelpers.TagHelperScopeManager" /* ORIGINAL: ScopeManagerTypeName */)
|
|
.Write(" ")
|
|
.WriteLine("__tagHelperScopeManager" /* ORIGINAL: ScopeManagerVariableName */);
|
|
|
|
using (Context.Writer.BuildScope())
|
|
{
|
|
Context.Writer.WriteLine("get");
|
|
using (Context.Writer.BuildScope())
|
|
{
|
|
Context.Writer
|
|
.Write("if (")
|
|
.Write(backedScopeManageVariableName)
|
|
.WriteLine(" == null)");
|
|
|
|
using (Context.Writer.BuildScope())
|
|
{
|
|
Context.Writer
|
|
.WriteStartAssignment(backedScopeManageVariableName)
|
|
.WriteStartNewObject("Microsoft.AspNetCore.Razor.Runtime.TagHelpers.TagHelperScopeManager" /* ORIGINAL: ScopeManagerTypeName */)
|
|
.Write("StartTagHelperWritingScope" /* ORIGINAL: StartTagHelperWritingScopeMethodName */)
|
|
.WriteParameterSeparator()
|
|
.Write("EndTagHelperWritingScope" /* ORIGINAL: EndTagHelperWritingScopeMethodName */)
|
|
.WriteEndMethodInvocation();
|
|
}
|
|
|
|
Context.Writer.WriteReturn(backedScopeManageVariableName);
|
|
}
|
|
}
|
|
|
|
foreach (var tagHelperTypeName in node.UsedTagHelperTypeNames)
|
|
{
|
|
var tagHelperVariableName = GetTagHelperVariableName(tagHelperTypeName);
|
|
Context.Writer
|
|
.Write("private global::")
|
|
.WriteVariableDeclaration(
|
|
tagHelperTypeName,
|
|
tagHelperVariableName,
|
|
value: null);
|
|
}
|
|
}
|
|
|
|
private void RenderTagHelperAttributeInline(
|
|
RazorIRNode node,
|
|
SourceSpan documentLocation)
|
|
{
|
|
if (node is SetTagHelperPropertyIRNode || node is CSharpExpressionIRNode)
|
|
{
|
|
for (var i = 0; i < node.Children.Count; i++)
|
|
{
|
|
RenderTagHelperAttributeInline(node.Children[i], documentLocation);
|
|
}
|
|
}
|
|
else if (node is HtmlContentIRNode)
|
|
{
|
|
Context.Writer.Write(((HtmlContentIRNode)node).Content);
|
|
}
|
|
else if (node is CSharpTokenIRNode)
|
|
{
|
|
Context.Writer.Write(((CSharpTokenIRNode)node).Content);
|
|
}
|
|
else if (node is CSharpStatementIRNode)
|
|
{
|
|
Context.ErrorSink.OnError(
|
|
new SourceLocation(documentLocation.AbsoluteIndex, documentLocation.CharacterIndex, documentLocation.Length),
|
|
LegacyResources.TagHelpers_CodeBlocks_NotSupported_InAttributes,
|
|
documentLocation.Length);
|
|
}
|
|
else if (node is TemplateIRNode)
|
|
{
|
|
var attributeValueNode = (SetTagHelperPropertyIRNode)node.Parent;
|
|
Context.ErrorSink.OnError(
|
|
new SourceLocation(documentLocation.AbsoluteIndex, documentLocation.CharacterIndex, documentLocation.Length),
|
|
LegacyResources.FormatTagHelpers_InlineMarkupBlocks_NotSupported_InAttributes(attributeValueNode.Descriptor.TypeName),
|
|
documentLocation.Length);
|
|
}
|
|
}
|
|
}
|
|
}
|