Rewrite of HTML handling for Blazor

This change replaces the parsing of HTML that we perform during the code
generation phase, which parsing of HTML during the IR lowering phase.
The main benefit of this change is that the structure of the HTML is
reflected in the IR tree, allowing us to do more more advance
transformations.

As an example, see how the the handling of `<script>` tags is now a
separate pass.

As an aside from this I also redesigned the structure of component IR
nodes to match the new HTML element nodes. Passes are now more easily
aware of the nodes they are expected to handle and are more easily aware
of the difference between a component and element. This still isn't as
clean as I would like, but I think it's a reasonable improvement.

Another benefit of this is that the code generation is much simpler and
requires much less bookkeeping and statefulness.
This commit is contained in:
Ryan Nowak 2018-04-18 13:06:21 -04:00
parent b4e70e72a0
commit b390ae0c1c
99 changed files with 2554 additions and 1853 deletions

View File

@ -1,6 +1,7 @@
// 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.Linq;
using Microsoft.AspNetCore.Blazor.Shared;
using Microsoft.AspNetCore.Razor.Language;
@ -11,7 +12,7 @@ namespace Microsoft.AspNetCore.Blazor.Razor
internal class BindLoweringPass : IntermediateNodePassBase, IRazorOptimizationPass
{
// Run after event handler pass
public override int Order => base.Order + 50;
public override int Order => 100;
protected override void ExecuteCore(RazorCodeDocument codeDocument, DocumentIntermediateNode documentNode)
{
@ -24,28 +25,45 @@ namespace Microsoft.AspNetCore.Blazor.Razor
}
// For each bind *usage* we need to rewrite the tag helper node to map to basic constructs.
var nodes = documentNode.FindDescendantNodes<TagHelperIntermediateNode>();
for (var i = 0; i < nodes.Count; i++)
var references = documentNode.FindDescendantReferences<TagHelperPropertyIntermediateNode>();
var parents = new HashSet<IntermediateNode>();
for (var i = 0; i < references.Count; i++)
{
var node = nodes[i];
parents.Add(references[i].Parent);
}
ProcessDuplicates(node);
foreach (var parent in parents)
{
ProcessDuplicates(parent);
}
for (var j = node.Children.Count - 1; j >= 0; j--)
for (var i = 0; i < references.Count; i++)
{
var reference = references[i];
var node = (TagHelperPropertyIntermediateNode)reference.Node;
if (!reference.Parent.Children.Contains(node))
{
var attributeNode = node.Children[j] as ComponentAttributeExtensionNode;
if (attributeNode != null &&
attributeNode.TagHelper != null &&
attributeNode.TagHelper.IsBindTagHelper() &&
attributeNode.AttributeName.StartsWith("bind"))
// This node was removed as a duplicate, skip it.
continue;
}
if (node.TagHelper.IsBindTagHelper() && node.AttributeName.StartsWith("bind"))
{
// Workaround for https://github.com/aspnet/Blazor/issues/703
var rewritten = RewriteUsage(reference.Parent, node);
reference.Remove();
for (var j = 0; j < rewritten.Length; j++)
{
RewriteUsage(node, j, attributeNode);
reference.Parent.Children.Add(rewritten[j]);
}
}
}
}
private void ProcessDuplicates(TagHelperIntermediateNode node)
private void ProcessDuplicates(IntermediateNode node)
{
// Reverse order because we will remove nodes.
//
@ -56,24 +74,23 @@ namespace Microsoft.AspNetCore.Blazor.Razor
{
// For each usage of the general 'fallback' bind tag helper, it could duplicate
// the usage of a more specific one. Look for duplicates and remove the fallback.
var attributeNode = node.Children[i] as ComponentAttributeExtensionNode;
if (attributeNode != null &&
attributeNode.TagHelper != null &&
attributeNode.TagHelper.IsFallbackBindTagHelper())
var attribute = node.Children[i] as TagHelperPropertyIntermediateNode;
if (attribute != null &&
attribute.TagHelper != null &&
attribute.TagHelper.IsFallbackBindTagHelper())
{
for (var j = 0; j < node.Children.Count; j++)
{
var duplicate = node.Children[j] as ComponentAttributeExtensionNode;
var duplicate = node.Children[j] as TagHelperPropertyIntermediateNode;
if (duplicate != null &&
duplicate.TagHelper != null &&
duplicate.TagHelper.IsBindTagHelper() &&
duplicate.AttributeName == attributeNode.AttributeName &&
!object.ReferenceEquals(attributeNode, duplicate))
duplicate.AttributeName == attribute.AttributeName &&
!object.ReferenceEquals(attribute, duplicate))
{
// Found a duplicate - remove the 'fallback' in favor of the
// more specific tag helper.
node.Children.RemoveAt(i);
node.TagHelpers.Remove(attributeNode.TagHelper);
break;
}
}
@ -82,23 +99,22 @@ namespace Microsoft.AspNetCore.Blazor.Razor
// Also treat the general <input bind="..." /> as a 'fallback' for that case and remove it.
// This is a workaround for a limitation where you can't write a tag helper that binds only
// when a specific attribute is **not** present.
if (attributeNode != null &&
attributeNode.TagHelper != null &&
attributeNode.TagHelper.IsInputElementFallbackBindTagHelper())
if (attribute != null &&
attribute.TagHelper != null &&
attribute.TagHelper.IsInputElementFallbackBindTagHelper())
{
for (var j = 0; j < node.Children.Count; j++)
{
var duplicate = node.Children[j] as ComponentAttributeExtensionNode;
var duplicate = node.Children[j] as TagHelperPropertyIntermediateNode;
if (duplicate != null &&
duplicate.TagHelper != null &&
duplicate.TagHelper.IsInputElementBindTagHelper() &&
duplicate.AttributeName == attributeNode.AttributeName &&
!object.ReferenceEquals(attributeNode, duplicate))
duplicate.AttributeName == attribute.AttributeName &&
!object.ReferenceEquals(attribute, duplicate))
{
// Found a duplicate - remove the 'fallback' input tag helper in favor of the
// more specific tag helper.
node.Children.RemoveAt(i);
node.TagHelpers.Remove(attributeNode.TagHelper);
break;
}
}
@ -107,7 +123,7 @@ namespace Microsoft.AspNetCore.Blazor.Razor
// If we still have duplicates at this point then they are genuine conflicts.
var duplicates = node.Children
.OfType<ComponentAttributeExtensionNode>()
.OfType<TagHelperPropertyIntermediateNode>()
.GroupBy(p => p.AttributeName)
.Where(g => g.Count() > 1);
@ -124,7 +140,7 @@ namespace Microsoft.AspNetCore.Blazor.Razor
}
}
private void RewriteUsage(TagHelperIntermediateNode node, int index, ComponentAttributeExtensionNode attributeNode)
private IntermediateNode[] RewriteUsage(IntermediateNode parent, TagHelperPropertyIntermediateNode node)
{
// Bind works similarly to a macro, it always expands to code that the user could have written.
//
@ -146,8 +162,9 @@ namespace Microsoft.AspNetCore.Blazor.Razor
// multiple passes handle 'special' tag helpers. We have another pass that translates
// a tag helper node back into 'regular' element when it doesn't have an associated component
if (!TryComputeAttributeNames(
parent,
node,
attributeNode.AttributeName,
node.AttributeName,
out var valueAttributeName,
out var changeAttributeName,
out var valueAttribute,
@ -156,83 +173,60 @@ namespace Microsoft.AspNetCore.Blazor.Razor
// Skip anything we can't understand. It's important that we don't crash, that will bring down
// the build.
node.Diagnostics.Add(BlazorDiagnosticFactory.CreateBindAttribute_InvalidSyntax(
attributeNode.Source,
attributeNode.AttributeName));
return;
node.Source,
node.AttributeName));
return new[] { node };
}
var original = GetAttributeContent(attributeNode);
var original = GetAttributeContent(node);
if (string.IsNullOrEmpty(original.Content))
{
// This can happen in error cases, the parser will already have flagged this
// as an error, so ignore it.
return;
return new[] { node };
}
// Look for a matching format node. If we find one then we need to pass the format into the
// two nodes we generate.
IntermediateToken format = null;
if (TryGetFormatNode(node,
attributeNode,
if (TryGetFormatNode(
parent,
node,
valueAttributeName,
out var formatNode))
{
// Don't write the format out as its own attribute, just capture it as a string
// or expression.
node.Children.Remove(formatNode);
parent.Children.Remove(formatNode);
format = GetAttributeContent(formatNode);
}
var valueAttributeNode = new ComponentAttributeExtensionNode(attributeNode)
{
AttributeName = valueAttributeName,
BoundAttribute = valueAttribute, // Might be null if it doesn't match a component attribute
PropertyName = valueAttribute?.GetPropertyName(),
TagHelper = valueAttribute == null ? null : attributeNode.TagHelper,
};
node.Children.Insert(index, valueAttributeNode);
// Now rewrite the content of the value node to look like:
//
// BindMethods.GetValue(<code>) OR
// BindMethods.GetValue(<code>, <format>)
valueAttributeNode.Children.Clear();
var expression = new CSharpExpressionIntermediateNode();
valueAttributeNode.Children.Add(expression);
expression.Children.Add(new IntermediateToken()
var valueExpressionTokens = new List<IntermediateToken>();
valueExpressionTokens.Add(new IntermediateToken()
{
Content = $"{BlazorApi.BindMethods.GetValue}(",
Kind = TokenKind.CSharp
});
expression.Children.Add(original);
valueExpressionTokens.Add(original);
if (!string.IsNullOrEmpty(format?.Content))
{
expression.Children.Add(new IntermediateToken()
valueExpressionTokens.Add(new IntermediateToken()
{
Content = ", ",
Kind = TokenKind.CSharp,
});
expression.Children.Add(format);
valueExpressionTokens.Add(format);
}
expression.Children.Add(new IntermediateToken()
valueExpressionTokens.Add(new IntermediateToken()
{
Content = ")",
Kind = TokenKind.CSharp,
});
var changeAttributeNode = new ComponentAttributeExtensionNode(attributeNode)
{
AttributeName = changeAttributeName,
BoundAttribute = changeAttribute, // Might be null if it doesn't match a component attribute
PropertyName = changeAttribute?.GetPropertyName(),
TagHelper = changeAttribute == null ? null : attributeNode.TagHelper,
};
node.Children[index + 1] = changeAttributeNode;
// Now rewrite the content of the change-handler node. There are two cases we care about
// here. If it's a component attribute, then don't use the 'BindMethods wrapper. We expect
// component attributes to always 'match' on type.
@ -246,32 +240,102 @@ namespace Microsoft.AspNetCore.Blazor.Razor
// BindMethods.SetValueHandler(__value => <code> = __value, <code>, <format>)
//
// Note that the linemappings here are applied to the value attribute, not the change attribute.
string changeAttributeContent = null;
if (changeAttributeNode.BoundAttribute == null && format == null)
string changeExpressionContent = null;
if (changeAttribute == null && format == null)
{
changeAttributeContent = $"{BlazorApi.BindMethods.SetValueHandler}(__value => {original.Content} = __value, {original.Content})";
changeExpressionContent = $"{BlazorApi.BindMethods.SetValueHandler}(__value => {original.Content} = __value, {original.Content})";
}
else if (changeAttributeNode.BoundAttribute == null && format != null)
else if (changeAttribute == null && format != null)
{
changeAttributeContent = $"{BlazorApi.BindMethods.SetValueHandler}(__value => {original.Content} = __value, {original.Content}, {format.Content})";
changeExpressionContent = $"{BlazorApi.BindMethods.SetValueHandler}(__value => {original.Content} = __value, {original.Content}, {format.Content})";
}
else
{
changeAttributeContent = $"__value => {original.Content} = __value";
changeExpressionContent = $"__value => {original.Content} = __value";
}
changeAttributeNode.Children.Clear();
changeAttributeNode.Children.Add(new CSharpExpressionIntermediateNode()
var changeExpressionTokens = new List<IntermediateToken>()
{
Children =
new IntermediateToken()
{
new IntermediateToken()
{
Content = changeAttributeContent,
Kind = TokenKind.CSharp
},
},
});
Content = changeExpressionContent,
Kind = TokenKind.CSharp
}
};
if (parent is HtmlElementIntermediateNode)
{
var valueNode = new HtmlAttributeIntermediateNode()
{
AttributeName = valueAttributeName,
Source = node.Source,
Prefix = valueAttributeName + "=\"",
Suffix = "\"",
};
for (var i = 0; i < node.Diagnostics.Count; i++)
{
valueNode.Diagnostics.Add(node.Diagnostics[i]);
}
valueNode.Children.Add(new CSharpExpressionAttributeValueIntermediateNode());
for (var i = 0; i < valueExpressionTokens.Count; i++)
{
valueNode.Children[0].Children.Add(valueExpressionTokens[i]);
}
var changeNode = new HtmlAttributeIntermediateNode()
{
AttributeName = changeAttributeName,
Source = node.Source,
Prefix = changeAttributeName + "=\"",
Suffix = "\"",
};
changeNode.Children.Add(new CSharpExpressionAttributeValueIntermediateNode());
for (var i = 0; i < changeExpressionTokens.Count; i++)
{
changeNode.Children[0].Children.Add(changeExpressionTokens[i]);
}
return new[] { valueNode, changeNode };
}
else
{
var valueNode = new ComponentAttributeExtensionNode(node)
{
AttributeName = valueAttributeName,
BoundAttribute = valueAttribute, // Might be null if it doesn't match a component attribute
PropertyName = valueAttribute?.GetPropertyName(),
TagHelper = valueAttribute == null ? null : node.TagHelper,
};
valueNode.Children.Clear();
valueNode.Children.Add(new CSharpExpressionIntermediateNode());
for (var i = 0; i < valueExpressionTokens.Count; i++)
{
valueNode.Children[0].Children.Add(valueExpressionTokens[i]);
}
var changeNode = new ComponentAttributeExtensionNode(node)
{
AttributeName = changeAttributeName,
BoundAttribute = changeAttribute, // Might be null if it doesn't match a component attribute
PropertyName = changeAttribute?.GetPropertyName(),
TagHelper = changeAttribute == null ? null : node.TagHelper,
};
changeNode.Children.Clear();
changeNode.Children.Add(new CSharpExpressionIntermediateNode());
for (var i = 0; i < changeExpressionTokens.Count; i++)
{
changeNode.Children[0].Children.Add(changeExpressionTokens[i]);
}
return new[] { valueNode, changeNode };
}
}
private bool TryParseBindAttribute(
@ -319,7 +383,8 @@ namespace Microsoft.AspNetCore.Blazor.Razor
// Attempts to compute the attribute names that should be used for an instance of 'bind'.
private bool TryComputeAttributeNames(
TagHelperIntermediateNode node,
IntermediateNode parent,
TagHelperPropertyIntermediateNode node,
string attributeName,
out string valueAttributeName,
out string changeAttributeName,
@ -342,12 +407,11 @@ namespace Microsoft.AspNetCore.Blazor.Razor
// generated to match a specific tag and has metadata that identify the attributes.
//
// We expect 1 bind tag helper per-node.
var bindTagHelper = node.TagHelpers.Single(t => t.IsBindTagHelper());
valueAttributeName = bindTagHelper.GetValueAttributeName() ?? valueAttributeName;
changeAttributeName = bindTagHelper.GetChangeAttributeName() ?? changeAttributeName;
valueAttributeName = node.TagHelper.GetValueAttributeName() ?? valueAttributeName;
changeAttributeName = node.TagHelper.GetChangeAttributeName() ?? changeAttributeName;
// We expect 0-1 components per-node.
var componentTagHelper = node.TagHelpers.FirstOrDefault(t => t.IsComponentTagHelper());
var componentTagHelper = (parent as ComponentExtensionNode)?.Component;
if (componentTagHelper == null)
{
// If it's not a component node then there isn't too much else to figure out.
@ -386,14 +450,14 @@ namespace Microsoft.AspNetCore.Blazor.Razor
}
private bool TryGetFormatNode(
TagHelperIntermediateNode node,
ComponentAttributeExtensionNode attributeNode,
IntermediateNode node,
TagHelperPropertyIntermediateNode attributeNode,
string valueAttributeName,
out ComponentAttributeExtensionNode formatNode)
out TagHelperPropertyIntermediateNode formatNode)
{
for (var i = 0; i < node.Children.Count; i++)
{
var child = node.Children[i] as ComponentAttributeExtensionNode;
var child = node.Children[i] as TagHelperPropertyIntermediateNode;
if (child != null &&
child.TagHelper != null &&
child.TagHelper == attributeNode.TagHelper &&
@ -408,7 +472,7 @@ namespace Microsoft.AspNetCore.Blazor.Razor
return false;
}
private static IntermediateToken GetAttributeContent(ComponentAttributeExtensionNode node)
private static IntermediateToken GetAttributeContent(TagHelperPropertyIntermediateNode node)
{
if (node.Children[0] is HtmlContentIntermediateNode htmlContentNode)
{

View File

@ -17,6 +17,21 @@ namespace Microsoft.AspNetCore.Blazor.Razor
private readonly static string DesignTimeVariable = "__o";
public override void WriteHtmlElement(CodeRenderingContext context, HtmlElementIntermediateNode node)
{
if (context == null)
{
throw new ArgumentNullException(nameof(context));
}
if (node == null)
{
throw new ArgumentNullException(nameof(node));
}
context.RenderChildren(node);
}
public override void WriteUsingDirective(CodeRenderingContext context, UsingDirectiveIntermediateNode node)
{
if (context == null)
@ -194,7 +209,7 @@ namespace Microsoft.AspNetCore.Blazor.Razor
throw new ArgumentNullException(nameof(node));
}
context.RenderChildren(node);
// Do nothing, this can't contain code.
}
public override void WriteCSharpExpressionAttributeValue(CodeRenderingContext context, CSharpExpressionAttributeValueIntermediateNode node)
@ -264,60 +279,6 @@ namespace Microsoft.AspNetCore.Blazor.Razor
}
}
public override void WriteCSharpCodeAttributeValue(CodeRenderingContext context, CSharpCodeAttributeValueIntermediateNode node)
{
if (context == null)
{
throw new ArgumentNullException(nameof(context));
}
if (node == null)
{
throw new ArgumentNullException(nameof(node));
}
for (var i = 0; i < node.Children.Count; i++)
{
if (node.Children[i] is IntermediateToken token && token.IsCSharp)
{
IDisposable linePragmaScope = null;
var isWhitespaceStatement = string.IsNullOrWhiteSpace(token.Content);
if (token.Source != null)
{
if (!isWhitespaceStatement)
{
linePragmaScope = context.CodeWriter.BuildLinePragma(token.Source.Value);
}
context.CodeWriter.WritePadding(0, token.Source.Value, context);
}
else if (isWhitespaceStatement)
{
// Don't write whitespace if there is no line mapping for it.
continue;
}
context.AddSourceMappingFor(token);
context.CodeWriter.Write(token.Content);
if (linePragmaScope != null)
{
linePragmaScope.Dispose();
}
else
{
context.CodeWriter.WriteLine();
}
}
else
{
// There may be something else inside the statement like an extension node.
context.RenderNode(node.Children[i]);
}
}
}
public override void WriteHtmlContent(CodeRenderingContext context, HtmlContentIntermediateNode node)
{
if (context == null)
@ -335,6 +296,16 @@ namespace Microsoft.AspNetCore.Blazor.Razor
public override void BeginWriteAttribute(CodeWriter codeWriter, string key)
{
if (codeWriter == null)
{
throw new ArgumentNullException(nameof(codeWriter));
}
if (key == null)
{
throw new ArgumentNullException(nameof(key));
}
codeWriter
.WriteStartMethodInvocation($"{_scopeStack.BuilderVarName}.{nameof(BlazorApi.RenderTreeBuilder.AddAttribute)}")
.Write("-1")
@ -343,7 +314,7 @@ namespace Microsoft.AspNetCore.Blazor.Razor
.WriteParameterSeparator();
}
public override void WriteComponentOpen(CodeRenderingContext context, ComponentOpenExtensionNode node)
public override void WriteComponent(CodeRenderingContext context, ComponentExtensionNode node)
{
if (context == null)
{
@ -355,34 +326,9 @@ namespace Microsoft.AspNetCore.Blazor.Razor
throw new ArgumentNullException(nameof(node));
}
// Do nothing
}
public override void WriteComponentClose(CodeRenderingContext context, ComponentCloseExtensionNode node)
{
if (context == null)
foreach (var attribute in node.Attributes)
{
throw new ArgumentNullException(nameof(context));
}
if (node == null)
{
throw new ArgumentNullException(nameof(node));
}
// Do nothing
}
public override void WriteComponentBody(CodeRenderingContext context, ComponentBodyExtensionNode node)
{
if (context == null)
{
throw new ArgumentNullException(nameof(context));
}
if (node == null)
{
throw new ArgumentNullException(nameof(node));
context.RenderNode(attribute);
}
// We need to be aware of the blazor scope-tracking concept in design-time code generation
@ -391,8 +337,17 @@ namespace Microsoft.AspNetCore.Blazor.Razor
// We're hacking it a bit here by just forcing every component to have an empty lambda
_scopeStack.OpenScope(node.TagName, isComponent: true);
_scopeStack.IncrementCurrentScopeChildCount(context);
context.RenderChildren(node);
_scopeStack.CloseScope(context, node.TagName, isComponent: true, source: node.Source);
foreach (var child in node.Body)
{
context.RenderNode(child);
}
_scopeStack.CloseScope(context);
foreach (var capture in node.Captures)
{
context.RenderNode(capture);
}
}
public override void WriteComponentAttribute(CodeRenderingContext context, ComponentAttributeExtensionNode node)
@ -440,7 +395,7 @@ namespace Microsoft.AspNetCore.Blazor.Razor
context.CodeWriter.Write(node.BoundAttribute.TypeName);
context.CodeWriter.Write("(");
context.CodeWriter.WriteLine();
for (var i = 0; i < tokens.Count; i++)
{
WriteCSharpToken(context, (IntermediateToken)tokens[i]);

View File

@ -30,23 +30,14 @@ namespace Microsoft.AspNetCore.Blazor.Razor
return diagnostic;
}
public static readonly RazorDiagnosticDescriptor ExpressionInAttributeList =
new RazorDiagnosticDescriptor(
public static readonly RazorDiagnosticDescriptor UnclosedTag = new RazorDiagnosticDescriptor(
"BL9980",
() =>
"Expressions like '{0}' inside of a tag must be part of an attribute. " +
"Previous releases of Blazor supported constructs like '@onclick(...)' or '@bind(...)'." +
"These features have been changed to use attribute syntax. " +
"Use 'onclick=\"@...\"' or 'bind=\"...\" respectively.",
() => "Unclosed tag '{0}' with no matching end tag.",
RazorDiagnosticSeverity.Error);
public static RazorDiagnostic Create_ExpressionInAttributeList(SourceSpan? source, string expression)
public static RazorDiagnostic Create_UnclosedTag(SourceSpan? span, string tagName)
{
var diagnostic = RazorDiagnostic.Create(
ExpressionInAttributeList,
source ?? SourceSpan.Undefined,
expression);
return diagnostic;
return RazorDiagnostic.Create(UnclosedTag, span ?? SourceSpan.Undefined, tagName);
}
public static readonly RazorDiagnosticDescriptor UnexpectedClosingTag = new RazorDiagnosticDescriptor(
@ -69,14 +60,14 @@ namespace Microsoft.AspNetCore.Blazor.Razor
return RazorDiagnostic.Create(MismatchedClosingTag, span ?? SourceSpan.Undefined, expectedTagName, tagName);
}
public static readonly RazorDiagnosticDescriptor MismatchedClosingTagKind = new RazorDiagnosticDescriptor(
public static readonly RazorDiagnosticDescriptor InvalidHtmlContent = new RazorDiagnosticDescriptor(
"BL9984",
() => "Mismatching closing tag. Found '{0}' of type '{1}' but expected type '{2}'.",
() => "Found invalid HTML content. Text '{0}'",
RazorDiagnosticSeverity.Error);
public static RazorDiagnostic Create_MismatchedClosingTagKind(SourceSpan? span, string tagName, string kind, string expectedKind)
public static RazorDiagnostic Create_InvalidHtmlContent(SourceSpan? span, string text)
{
return RazorDiagnostic.Create(MismatchedClosingTagKind, span ?? SourceSpan.Undefined, tagName, kind, expectedKind);
return RazorDiagnostic.Create(InvalidHtmlContent, span ?? SourceSpan.Undefined, text);
}
public static readonly RazorDiagnosticDescriptor MultipleComponents = new RazorDiagnosticDescriptor(
@ -132,7 +123,7 @@ namespace Microsoft.AspNetCore.Blazor.Razor
() => "The attribute '{0}' was matched by multiple bind attributes. Duplicates:{1}",
RazorDiagnosticSeverity.Error);
public static RazorDiagnostic CreateBindAttribute_Duplicates(SourceSpan? source, string attribute, ComponentAttributeExtensionNode[] attributes)
public static RazorDiagnostic CreateBindAttribute_Duplicates(SourceSpan? source, string attribute, TagHelperPropertyIntermediateNode[] attributes)
{
var diagnostic = RazorDiagnostic.Create(
BindAttribute_Duplicates,
@ -148,7 +139,7 @@ namespace Microsoft.AspNetCore.Blazor.Razor
() => "The attribute '{0}' was matched by multiple event handlers attributes. Duplicates:{1}",
RazorDiagnosticSeverity.Error);
public static RazorDiagnostic CreateEventHandler_Duplicates(SourceSpan? source, string attribute, ComponentAttributeExtensionNode[] attributes)
public static RazorDiagnostic CreateEventHandler_Duplicates(SourceSpan? source, string attribute, TagHelperPropertyIntermediateNode[] attributes)
{
var diagnostic = RazorDiagnostic.Create(
EventHandler_Duplicates,

View File

@ -72,12 +72,13 @@ namespace Microsoft.AspNetCore.Blazor.Razor
builder.Features.Add(new TrimWhitespacePass());
}
builder.Features.Add(new ComponentDocumentClassifierPass());
builder.Features.Add(new ComponentDocumentRewritePass());
builder.Features.Add(new ScriptTagPass());
builder.Features.Add(new ComplexAttributeContentPass());
builder.Features.Add(new BindLoweringPass());
builder.Features.Add(new EventHandlerLoweringPass());
builder.Features.Add(new ComponentLoweringPass());
builder.Features.Add(new EventHandlerLoweringPass());
builder.Features.Add(new RefLoweringPass());
builder.Features.Add(new OrphanTagHelperLoweringPass());
builder.Features.Add(new BindLoweringPass());
builder.Features.Add(new ComponentTagHelperDescriptorProvider());
builder.Features.Add(new BindTagHelperDescriptorProvider());

View File

@ -2,12 +2,24 @@
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using System.Linq;
using Microsoft.AspNetCore.Razor.Language.CodeGeneration;
using Microsoft.AspNetCore.Razor.Language.Intermediate;
namespace Microsoft.AspNetCore.Blazor.Razor
{
internal abstract class BlazorNodeWriter : IntermediateNodeWriter
{
public abstract void BeginWriteAttribute(CodeWriter codeWriter, string key);
public abstract void WriteComponent(CodeRenderingContext context, ComponentExtensionNode node);
public abstract void WriteComponentAttribute(CodeRenderingContext context, ComponentAttributeExtensionNode node);
public abstract void WriteHtmlElement(CodeRenderingContext context, HtmlElementIntermediateNode node);
public abstract void WriteReferenceCapture(CodeRenderingContext context, RefExtensionNode node);
public sealed override void BeginWriterScope(CodeRenderingContext context, string writer)
{
throw new NotImplementedException(nameof(BeginWriterScope));
@ -18,16 +30,15 @@ namespace Microsoft.AspNetCore.Blazor.Razor
throw new NotImplementedException(nameof(EndWriterScope));
}
public abstract void BeginWriteAttribute(CodeWriter codeWriter, string key);
public abstract void WriteComponentOpen(CodeRenderingContext context, ComponentOpenExtensionNode node);
public abstract void WriteComponentClose(CodeRenderingContext context, ComponentCloseExtensionNode node);
public abstract void WriteComponentBody(CodeRenderingContext context, ComponentBodyExtensionNode node);
public abstract void WriteComponentAttribute(CodeRenderingContext context, ComponentAttributeExtensionNode node);
public abstract void WriteReferenceCapture(CodeRenderingContext context, RefExtensionNode node);
public sealed override void WriteCSharpCodeAttributeValue(CodeRenderingContext context, CSharpCodeAttributeValueIntermediateNode node)
{
// We used to support syntaxes like <elem onsomeevent=@{ /* some C# code */ } /> but this is no longer the
// case.
//
// We provide an error for this case just to be friendly.
var content = string.Join("", node.Children.OfType<IntermediateToken>().Select(t => t.Content));
context.Diagnostics.Add(BlazorDiagnosticFactory.Create_CodeBlockInAttribute(node.Source, content));
return;
}
}
}

View File

@ -3,11 +3,9 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;
using AngleSharp;
using AngleSharp.Html;
using AngleSharp.Parser.Html;
using Microsoft.AspNetCore.Blazor.Shared;
using Microsoft.AspNetCore.Razor.Language;
using Microsoft.AspNetCore.Razor.Language.CodeGeneration;
@ -20,25 +18,10 @@ namespace Microsoft.AspNetCore.Blazor.Razor
/// </summary>
internal class BlazorRuntimeNodeWriter : BlazorNodeWriter
{
// Per the HTML spec, the following elements are inherently self-closing
// For example, <img> is the same as <img /> (and therefore it cannot contain descendants)
private readonly static HashSet<string> htmlVoidElementsLookup
= new HashSet<string>(
new[] { "area", "base", "br", "col", "embed", "hr", "img", "input", "link", "meta", "param", "source", "track", "wbr" },
StringComparer.OrdinalIgnoreCase);
private readonly List<IntermediateToken> _currentAttributeValues = new List<IntermediateToken>();
private readonly ScopeStack _scopeStack = new ScopeStack();
private string _unconsumedHtml;
private List<IntermediateToken> _currentAttributeValues;
private IDictionary<string, PendingAttribute> _currentElementAttributes = new Dictionary<string, PendingAttribute>();
private List<RefExtensionNode> _currentElementRefCaptures = new List<RefExtensionNode>();
private int _sourceSequence = 0;
private struct PendingAttribute
{
public List<IntermediateToken> Values { get; set; }
}
public override void WriteCSharpCode(CodeRenderingContext context, CSharpCodeIntermediateNode node)
{
if (context == null)
@ -102,34 +85,16 @@ namespace Microsoft.AspNetCore.Blazor.Razor
}
}
public override void WriteCSharpCodeAttributeValue(CodeRenderingContext context, CSharpCodeAttributeValueIntermediateNode node)
{
if (_currentAttributeValues == null)
{
throw new InvalidOperationException($"Invoked {nameof(WriteCSharpCodeAttributeValue)} while {nameof(_currentAttributeValues)} was null.");
}
// We used to support syntaxes like <elem onsomeevent=@{ /* some C# code */ } /> but this is no longer the
// case.
//
// We provide an error for this case just to be friendly.
var content = string.Join("", node.Children.OfType<IntermediateToken>().Select(t => t.Content));
context.Diagnostics.Add(BlazorDiagnosticFactory.Create_CodeBlockInAttribute(node.Source, content));
return;
}
public override void WriteCSharpExpression(CodeRenderingContext context, CSharpExpressionIntermediateNode node)
{
// We used to support syntaxes like <elem @completeAttributePair /> but this is no longer the case.
// The APIs that a user would need to do this correctly aren't accessible outside of Blazor's core
// anyway.
//
// We provide an error for this case just to be friendly.
if (_unconsumedHtml != null)
if (context == null)
{
var content = string.Join("", node.Children.OfType<IntermediateToken>().Select(t => t.Content));
context.Diagnostics.Add(BlazorDiagnosticFactory.Create_ExpressionInAttributeList(node.Source, content));
return;
throw new ArgumentNullException(nameof(context));
}
if (node == null)
{
throw new ArgumentNullException(nameof(node));
}
// Since we're not in the middle of writing an element, this must evaluate as some
@ -153,15 +118,19 @@ namespace Microsoft.AspNetCore.Blazor.Razor
}
}
context.CodeWriter
.WriteEndMethodInvocation();
context.CodeWriter.WriteEndMethodInvocation();
}
public override void WriteCSharpExpressionAttributeValue(CodeRenderingContext context, CSharpExpressionAttributeValueIntermediateNode node)
{
if (_currentAttributeValues == null)
if (context == null)
{
throw new InvalidOperationException($"Invoked {nameof(WriteCSharpCodeAttributeValue)} while {nameof(_currentAttributeValues)} was null.");
throw new ArgumentNullException(nameof(context));
}
if (node == null)
{
throw new ArgumentNullException(nameof(node));
}
// In cases like "somestring @variable", Razor tokenizes it as:
@ -179,22 +148,80 @@ namespace Microsoft.AspNetCore.Blazor.Razor
}
}
public override void WriteHtmlElement(CodeRenderingContext context, HtmlElementIntermediateNode node)
{
if (context == null)
{
throw new ArgumentNullException(nameof(context));
}
if (node == null)
{
throw new ArgumentNullException(nameof(node));
}
context.CodeWriter
.WriteStartMethodInvocation($"{_scopeStack.BuilderVarName}.{nameof(BlazorApi.RenderTreeBuilder.OpenElement)}")
.Write((_sourceSequence++).ToString())
.WriteParameterSeparator()
.WriteStringLiteral(node.TagName)
.WriteEndMethodInvocation();
// Render Attributes before creating the scope.
foreach (var attribute in node.Attributes)
{
context.RenderNode(attribute);
}
foreach (var capture in node.Captures)
{
context.RenderNode(capture);
}
_scopeStack.OpenScope(tagName: node.TagName, isComponent: false);
// Render body of the tag inside the scope
foreach (var child in node.Body)
{
context.RenderNode(child);
}
_scopeStack.CloseScope(context);
context.CodeWriter
.WriteStartMethodInvocation($"{_scopeStack.BuilderVarName}.{BlazorApi.RenderTreeBuilder.CloseElement}")
.WriteEndMethodInvocation();
}
public override void WriteHtmlAttribute(CodeRenderingContext context, HtmlAttributeIntermediateNode node)
{
_currentAttributeValues = new List<IntermediateToken>();
context.RenderChildren(node);
_currentElementAttributes[node.AttributeName] = new PendingAttribute
if (context == null)
{
Values = _currentAttributeValues,
};
_currentAttributeValues = null;
throw new ArgumentNullException(nameof(context));
}
if (node == null)
{
throw new ArgumentNullException(nameof(node));
}
Debug.Assert(_currentAttributeValues.Count == 0);
context.RenderChildren(node);
WriteAttribute(context.CodeWriter, node.AttributeName, _currentAttributeValues);
_currentAttributeValues.Clear();
}
public override void WriteHtmlAttributeValue(CodeRenderingContext context, HtmlAttributeValueIntermediateNode node)
{
if (_currentAttributeValues == null)
if (context == null)
{
throw new InvalidOperationException($"Invoked {nameof(WriteHtmlAttributeValue)} while {nameof(_currentAttributeValues)} was null.");
throw new ArgumentNullException(nameof(context));
}
if (node == null)
{
throw new ArgumentNullException(nameof(node));
}
var stringContent = ((IntermediateToken)node.Children.Single()).Content;
@ -203,179 +230,43 @@ namespace Microsoft.AspNetCore.Blazor.Razor
public override void WriteHtmlContent(CodeRenderingContext context, HtmlContentIntermediateNode node)
{
var originalHtmlContent = GetContent(node);
if (_unconsumedHtml != null)
if (context == null)
{
originalHtmlContent = _unconsumedHtml + originalHtmlContent;
_unconsumedHtml = null;
throw new ArgumentNullException(nameof(context));
}
var tokenizer = new HtmlTokenizer(
new TextSource(originalHtmlContent),
HtmlEntityService.Resolver);
var codeWriter = context.CodeWriter;
// TODO: As an optimization, identify static subtrees (i.e., HTML elements in the Razor source
// that contain no C#) and represent them as a new RenderTreeFrameType called StaticElement or
// similar. This means you can have arbitrarily deep static subtrees without paying any per-
// node cost during rendering or diffing.
HtmlToken nextToken;
while ((nextToken = tokenizer.Get()).Type != HtmlTokenType.EndOfFile)
if (node == null)
{
switch (nextToken.Type)
{
case HtmlTokenType.Character:
{
// Text node
_scopeStack.IncrementCurrentScopeChildCount(context);
codeWriter
.WriteStartMethodInvocation($"{_scopeStack.BuilderVarName}.{nameof(BlazorApi.RenderTreeBuilder.AddContent)}")
.Write((_sourceSequence++).ToString())
.WriteParameterSeparator()
.WriteStringLiteral(nextToken.Data)
.WriteEndMethodInvocation();
break;
}
case HtmlTokenType.StartTag:
case HtmlTokenType.EndTag:
{
var nextTag = nextToken.AsTag();
var tagNameOriginalCase = GetTagNameWithOriginalCase(originalHtmlContent, nextTag);
if (nextToken.Type == HtmlTokenType.StartTag)
{
RejectDisallowedHtmlTags(node, nextTag);
_scopeStack.IncrementCurrentScopeChildCount(context);
codeWriter
.WriteStartMethodInvocation($"{_scopeStack.BuilderVarName}.{nameof(BlazorApi.RenderTreeBuilder.OpenElement)}")
.Write((_sourceSequence++).ToString())
.WriteParameterSeparator()
.WriteStringLiteral(nextTag.Data)
.WriteEndMethodInvocation();
foreach (var attribute in nextTag.Attributes)
{
var token = new IntermediateToken() { Kind = TokenKind.Html, Content = attribute.Value };
WriteAttribute(codeWriter, attribute.Key, new[] { token });
}
if (_currentElementAttributes.Count > 0)
{
foreach (var pair in _currentElementAttributes)
{
WriteAttribute(codeWriter, pair.Key, pair.Value.Values);
}
_currentElementAttributes.Clear();
}
if (_currentElementRefCaptures.Count > 0)
{
foreach (var refNode in _currentElementRefCaptures)
{
WriteAddReferenceCaptureCall(context, refNode);
}
_currentElementRefCaptures.Clear();
}
_scopeStack.OpenScope( tagName: nextTag.Data, isComponent: false);
}
if (nextToken.Type == HtmlTokenType.EndTag
|| nextTag.IsSelfClosing
|| htmlVoidElementsLookup.Contains(nextTag.Data))
{
_scopeStack.CloseScope(
context: context,
tagName: nextTag.Data,
isComponent: false,
source: CalculateSourcePosition(node.Source, nextToken.Position));
codeWriter
.WriteStartMethodInvocation($"{_scopeStack.BuilderVarName}.{BlazorApi.RenderTreeBuilder.CloseElement}")
.WriteEndMethodInvocation();
}
break;
}
case HtmlTokenType.Comment:
break;
default:
throw new InvalidCastException($"Unsupported token type: {nextToken.Type.ToString()}");
}
throw new ArgumentNullException(nameof(node));
}
// If we got an EOF in the middle of an HTML element, it's probably because we're
// about to receive some attribute name/value pairs. Store the unused HTML content
// so we can prepend it to the part that comes after the attributes to make
// complete valid markup.
if (originalHtmlContent.Length > nextToken.Position.Position)
{
_unconsumedHtml = originalHtmlContent.Substring(nextToken.Position.Position - 1);
}
}
private void WriteAddReferenceCaptureCall(CodeRenderingContext context, RefExtensionNode refNode)
{
var codeWriter = context.CodeWriter;
var methodName = refNode.IsComponentCapture
? nameof(BlazorApi.RenderTreeBuilder.AddComponentReferenceCapture)
: nameof(BlazorApi.RenderTreeBuilder.AddElementReferenceCapture);
codeWriter
.WriteStartMethodInvocation($"{_scopeStack.BuilderVarName}.{methodName}")
// Text node
var content = GetHtmlContent(node);
_scopeStack.IncrementCurrentScopeChildCount(context);
context.CodeWriter
.WriteStartMethodInvocation($"{_scopeStack.BuilderVarName}.{nameof(BlazorApi.RenderTreeBuilder.AddContent)}")
.Write((_sourceSequence++).ToString())
.WriteParameterSeparator();
const string refCaptureParamName = "__value";
using (var lambdaScope = codeWriter.BuildLambda(refCaptureParamName))
{
var typecastIfNeeded = refNode.IsComponentCapture ? $"({refNode.ComponentCaptureTypeName})" : string.Empty;
WriteCSharpCode(context, new CSharpCodeIntermediateNode
{
Source = refNode.Source,
Children =
{
refNode.IdentifierToken,
new IntermediateToken {
Kind = TokenKind.CSharp,
Content = $" = {typecastIfNeeded}{refCaptureParamName};"
}
}
});
}
codeWriter.WriteEndMethodInvocation();
}
private void RejectDisallowedHtmlTags(IntermediateNode node, HtmlTagToken tagToken)
{
// Disallow <script> in components as per #552
// Case-sensitive comparison is fine because AngleSharp always lowercases tag names
if (tagToken.Name.Equals("script", StringComparison.Ordinal))
{
const string suppressErrorAttributeName = "suppress-error";
if (string.Equals(tagToken.GetAttribute(suppressErrorAttributeName), "BL9992", StringComparison.Ordinal))
{
tagToken.Attributes.RemoveAll(kvp => kvp.Key.Equals(suppressErrorAttributeName, StringComparison.Ordinal));
}
else
{
var adjustedSpan = CalculateSourcePosition(node.Source, tagToken.Position);
var diagnostic = BlazorDiagnosticFactory.Create_DisallowedScriptTag(adjustedSpan);
throw new RazorCompilerException(diagnostic);
}
}
.WriteParameterSeparator()
.WriteStringLiteral(content)
.WriteEndMethodInvocation();
}
public override void WriteUsingDirective(CodeRenderingContext context, UsingDirectiveIntermediateNode node)
{
if (context == null)
{
throw new ArgumentNullException(nameof(context));
}
if (node == null)
{
throw new ArgumentNullException(nameof(node));
}
context.CodeWriter.WriteUsing(node.Content, endLine: true);
}
public override void WriteComponentOpen(CodeRenderingContext context, ComponentOpenExtensionNode node)
public override void WriteComponent(CodeRenderingContext context, ComponentExtensionNode node)
{
if (context == null)
{
@ -400,18 +291,22 @@ namespace Microsoft.AspNetCore.Blazor.Razor
context.CodeWriter.Write((_sourceSequence++).ToString());
context.CodeWriter.Write(");");
context.CodeWriter.WriteLine();
}
public override void WriteComponentClose(CodeRenderingContext context, ComponentCloseExtensionNode node)
{
if (context == null)
foreach (var attribute in node.Attributes)
{
throw new ArgumentNullException(nameof(context));
context.RenderNode(attribute);
}
if (node == null)
_scopeStack.OpenScope(node.TagName, isComponent: true);
foreach (var child in node.Body)
{
throw new ArgumentNullException(nameof(node));
context.RenderNode(child);
}
_scopeStack.CloseScope(context);
foreach (var capture in node.Captures)
{
context.RenderNode(capture);
}
// The close tag counts as a child from a markup point of view.
@ -425,23 +320,6 @@ namespace Microsoft.AspNetCore.Blazor.Razor
context.CodeWriter.WriteLine();
}
public override void WriteComponentBody(CodeRenderingContext context, ComponentBodyExtensionNode node)
{
if (context == null)
{
throw new ArgumentNullException(nameof(context));
}
if (node == null)
{
throw new ArgumentNullException(nameof(node));
}
_scopeStack.OpenScope(node.TagName, isComponent: true);
context.RenderChildren(node);
_scopeStack.CloseScope(context, node.TagName, isComponent: true, source: node.Source);
}
public override void WriteComponentAttribute(CodeRenderingContext context, ComponentAttributeExtensionNode node)
{
if (context == null)
@ -523,57 +401,42 @@ namespace Microsoft.AspNetCore.Blazor.Razor
{
throw new InvalidOperationException("Unexpected node type " + node.Children[0].GetType().FullName);
}
context.CodeWriter.Write(");");
context.CodeWriter.WriteLine();
}
public override void WriteReferenceCapture(CodeRenderingContext context, RefExtensionNode node)
{
if (node.IsComponentCapture)
{
// AddComponentReferenceCapture calls can be inserted directly because they are
// already in the desired place in the IR
WriteAddReferenceCaptureCall(context, node);
}
else
{
// AddElementReferenceCapture calls must appear in the RenderTree as children of the element
// being captured, so store the RefCapture until we're ready to write its children.
// We could instead modify RefLoweringPass to insert the RefExtensionNode at the right
// place, but this is harder because it would involve understanding which HtmlContent
// node represents the end of the tag. It's simpler to do it here because here we are
// already doing HTML parsing to understand the structure.
_currentElementRefCaptures.Add(node);
}
}
var codeWriter = context.CodeWriter;
private SourceSpan? CalculateSourcePosition(
SourceSpan? razorTokenPosition,
TextPosition htmlNodePosition)
{
if (razorTokenPosition.HasValue)
{
var razorPos = razorTokenPosition.Value;
return new SourceSpan(
razorPos.FilePath,
razorPos.AbsoluteIndex + htmlNodePosition.Position,
razorPos.LineIndex + htmlNodePosition.Line - 1,
htmlNodePosition.Line == 1
? razorPos.CharacterIndex + htmlNodePosition.Column - 1
: htmlNodePosition.Column - 1,
length: 1);
}
else
{
return null;
}
}
var methodName = node.IsComponentCapture
? nameof(BlazorApi.RenderTreeBuilder.AddComponentReferenceCapture)
: nameof(BlazorApi.RenderTreeBuilder.AddElementReferenceCapture);
codeWriter
.WriteStartMethodInvocation($"{_scopeStack.BuilderVarName}.{methodName}")
.Write((_sourceSequence++).ToString())
.WriteParameterSeparator();
private static string GetTagNameWithOriginalCase(string document, HtmlTagToken tagToken)
{
var offset = tagToken.Type == HtmlTokenType.EndTag ? 1 : 0; // For end tags, skip the '/'
return document.Substring(tagToken.Position.Position + offset, tagToken.Name.Length);
const string refCaptureParamName = "__value";
using (var lambdaScope = codeWriter.BuildLambda(refCaptureParamName))
{
var typecastIfNeeded = node.IsComponentCapture ? $"({node.ComponentCaptureTypeName})" : string.Empty;
WriteCSharpCode(context, new CSharpCodeIntermediateNode
{
Source = node.Source,
Children =
{
node.IdentifierToken,
new IntermediateToken {
Kind = TokenKind.CSharp,
Content = $" = {typecastIfNeeded}{refCaptureParamName};"
}
}
});
}
codeWriter.WriteEndMethodInvocation();
}
private void WriteAttribute(CodeWriter codeWriter, string key, IList<IntermediateToken> value)
@ -602,7 +465,7 @@ namespace Microsoft.AspNetCore.Blazor.Razor
.WriteParameterSeparator();
}
private static string GetContent(HtmlContentIntermediateNode node)
private static string GetHtmlContent(HtmlContentIntermediateNode node)
{
var builder = new StringBuilder();
var htmlTokens = node.Children.OfType<IntermediateToken>().Where(t => t.IsHtml);
@ -697,6 +560,11 @@ namespace Microsoft.AspNetCore.Blazor.Razor
{
writer.WriteStringLiteral(string.Join("", tokens.Select(t => t.Content)));
}
else
{
// Minimized attributes always map to 'true'
writer.Write("true");
}
}
}
}

View File

@ -39,8 +39,6 @@ namespace Microsoft.AspNetCore.Blazor.Razor
node.Children.RemoveAt(i);
continue;
}
node.Children[i] = new ComponentAttributeExtensionNode(propertyNode);
}
else if (node.Children[i] is TagHelperHtmlAttributeIntermediateNode htmlNode)
{

View File

@ -1,69 +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 Microsoft.AspNetCore.Razor.Language;
using Microsoft.AspNetCore.Razor.Language.CodeGeneration;
using Microsoft.AspNetCore.Razor.Language.Intermediate;
namespace Microsoft.AspNetCore.Blazor.Razor
{
internal sealed class ComponentBodyExtensionNode : ExtensionIntermediateNode
{
public ComponentBodyExtensionNode()
{
}
public ComponentBodyExtensionNode(TagHelperBodyIntermediateNode bodyNode)
{
if (bodyNode == null)
{
throw new ArgumentNullException(nameof(bodyNode));
}
Source = bodyNode.Source;
for (var i = 0; i < bodyNode.Children.Count; i++)
{
Children.Add(bodyNode.Children[i]);
}
for (var i = 0; i < bodyNode.Diagnostics.Count; i++)
{
Diagnostics.Add(bodyNode.Diagnostics[i]);
}
}
public override IntermediateNodeCollection Children { get; } = new IntermediateNodeCollection();
public TagMode TagMode { get; set; }
public string TagName { get; set; }
public override void Accept(IntermediateNodeVisitor visitor)
{
if (visitor == null)
{
throw new ArgumentNullException(nameof(visitor));
}
AcceptExtensionNode<ComponentBodyExtensionNode>(this, visitor);
}
public override void WriteNode(CodeTarget target, CodeRenderingContext context)
{
if (target == null)
{
throw new ArgumentNullException(nameof(target));
}
if (context == null)
{
throw new ArgumentNullException(nameof(context));
}
var writer = (BlazorNodeWriter)context.NodeWriter;
writer.WriteComponentBody(context, this);
}
}
}

View File

@ -1,40 +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 Microsoft.AspNetCore.Razor.Language.CodeGeneration;
using Microsoft.AspNetCore.Razor.Language.Intermediate;
namespace Microsoft.AspNetCore.Blazor.Razor
{
internal class ComponentCloseExtensionNode : ExtensionIntermediateNode
{
public override IntermediateNodeCollection Children => IntermediateNodeCollection.ReadOnly;
public override void Accept(IntermediateNodeVisitor visitor)
{
if (visitor == null)
{
throw new ArgumentNullException(nameof(visitor));
}
AcceptExtensionNode<ComponentCloseExtensionNode>(this, visitor);
}
public override void WriteNode(CodeTarget target, CodeRenderingContext context)
{
if (target == null)
{
throw new ArgumentNullException(nameof(target));
}
if (context == null)
{
throw new ArgumentNullException(nameof(context));
}
var writer = (BlazorNodeWriter)context.NodeWriter;
writer.WriteComponentClose(context, this);
}
}
}

View File

@ -0,0 +1,487 @@
// 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.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;
using AngleSharp;
using AngleSharp.Html;
using AngleSharp.Parser.Html;
using Microsoft.AspNetCore.Razor.Language;
using Microsoft.AspNetCore.Razor.Language.Intermediate;
namespace Microsoft.AspNetCore.Blazor.Razor
{
// Rewrites the standard IR to a format more suitable for Blazor
//
// HTML nodes are rewritten to contain more structure, instead of treating HTML as opaque content
// it is structured into element/component nodes, and attribute nodes.
internal class ComponentDocumentRewritePass : IntermediateNodePassBase, IRazorDocumentClassifierPass
{
// Per the HTML spec, the following elements are inherently self-closing
// For example, <img> is the same as <img /> (and therefore it cannot contain descendants)
private readonly static HashSet<string> VoidElements = new HashSet<string>(StringComparer.OrdinalIgnoreCase)
{
"area", "base", "br", "col", "embed", "hr", "img", "input", "link", "meta", "param", "source", "track", "wbr",
};
// Run as soon as possible after the Component document classifier
public override int Order => ComponentDocumentClassifierPass.DefaultFeatureOrder + 1;
protected override void ExecuteCore(RazorCodeDocument codeDocument, DocumentIntermediateNode documentNode)
{
if (documentNode.DocumentKind != ComponentDocumentClassifierPass.ComponentDocumentKind)
{
return;
}
var visitor = new RewriteWalker(codeDocument.Source);
visitor.Visit(documentNode);
}
// Visits nodes then rewrites them using a post-order traversal. The result is that the tree
// is rewritten bottom up.
//
// This relies on a few invariants Razor already provides for correctness.
// - Tag Helpers are the only real nesting construct
// - Tag Helpers require properly nested HTML inside their body
//
// This means that when we find a 'container' for HTML content, we have the guarantee
// that the content is properly nested, except at the top level of scope. And since the top
// level isn't nested inside anything, we can't introduce any errors due to misunderstanding
// the structure.
private class RewriteWalker : IntermediateNodeWalker
{
private readonly RazorSourceDocument _source;
public RewriteWalker(RazorSourceDocument source)
{
_source = source;
}
public override void VisitDefault(IntermediateNode node)
{
var foundHtml = false;
for (var i = 0; i < node.Children.Count; i++)
{
var child = node.Children[i];
Visit(child);
if (child is HtmlContentIntermediateNode)
{
foundHtml = true;
}
}
if (foundHtml)
{
RewriteChildren(_source, node);
}
}
private void RewriteChildren(RazorSourceDocument source, IntermediateNode node)
{
// We expect all of the immediate children of a node (together) to comprise
// a well-formed tree of elements and components.
var stack = new Stack<IntermediateNode>();
stack.Push(node);
// Make a copy, we will clear and rebuild the child collection of this node.
var children = node.Children.ToArray();
node.Children.Clear();
// Due to the way Anglesharp parses HTML (tags at a time) we need to keep track of some state.
// This handles cases like:
//
// <foo bar="17" baz="@baz" />
//
// This will lower like:
//
// HtmlContent <foo bar="17"
// HtmlAttribute baz=" - "
// CSharpAttributeValue baz
// HtmlContent />
//
// We need to consume HTML until we see the 'end tag' for <foo /> and then we can
// the attributes from the parsed HTML and the CSharpAttribute value.
var parser = new HtmlParser(source);
var attributes = new List<HtmlAttributeIntermediateNode>();
for (var i = 0; i < children.Length; i++)
{
if (children[i] is HtmlContentIntermediateNode htmlNode)
{
parser.Push(htmlNode);
while (true)
{
// We have to call this before get. Anglesharp doesn't return the start position
// of tokens.
var start = parser.GetCurrentLocation();
var token = parser.Get();
var end = parser.GetCurrentLocation();
if (token.Type == HtmlTokenType.EndOfFile)
{
break;
}
switch (token.Type)
{
case HtmlTokenType.Character:
{
// Text content
var span = new SourceSpan(start, end.AbsoluteIndex - start.AbsoluteIndex);
stack.Peek().Children.Add(new HtmlContentIntermediateNode()
{
Children =
{
new IntermediateToken()
{
Content = token.Data,
Kind = TokenKind.Html,
Source = span,
}
},
Source = span,
});
break;
}
case HtmlTokenType.StartTag:
case HtmlTokenType.EndTag:
{
var tag = token.AsTag();
if (token.Type == HtmlTokenType.StartTag)
{
var elementNode = new HtmlElementIntermediateNode()
{
TagName = parser.GetTagNameOriginalCasing(tag),
Source = new SourceSpan(start, end.AbsoluteIndex - start.AbsoluteIndex),
};
stack.Peek().Children.Add(elementNode);
stack.Push(elementNode);
for (var j = 0; j < tag.Attributes.Count; j++)
{
// Unfortunately Anglesharp doesn't provide positions for attributes
// so we can't record the spans here.
var attribute = tag.Attributes[j];
stack.Peek().Children.Add(CreateAttributeNode(attribute));
}
for (var j = 0; j < attributes.Count; j++)
{
stack.Peek().Children.Add(attributes[j]);
}
attributes.Clear();
}
if (tag.IsSelfClosing || VoidElements.Contains(tag.Data))
{
// We can't possibly hit an error here since we just added an element node.
stack.Pop();
}
if (token.Type == HtmlTokenType.EndTag)
{
var popped = stack.Pop();
if (stack.Count == 0)
{
// If we managed to 'bottom out' the stack then we have an unbalanced end tag.
// Put back the current node so we don't crash.
stack.Push(popped);
var tagName = parser.GetTagNameOriginalCasing(token.AsTag());
var span = new SourceSpan(start, end.AbsoluteIndex - start.AbsoluteIndex);
var diagnostic = BlazorDiagnosticFactory.Create_UnexpectedClosingTag(span, tagName);
popped.Children.Add(new HtmlElementIntermediateNode()
{
Diagnostics =
{
diagnostic,
},
TagName = tagName,
Source = span,
});
}
else if (!string.Equals(tag.Name, ((HtmlElementIntermediateNode)popped).TagName, StringComparison.OrdinalIgnoreCase))
{
var span = new SourceSpan(start, end.AbsoluteIndex - start.AbsoluteIndex);
var diagnostic = BlazorDiagnosticFactory.Create_MismatchedClosingTag(span, ((HtmlElementIntermediateNode)popped).TagName, token.Data);
popped.Diagnostics.Add(diagnostic);
}
else
{
// Happy path.
//
// We need to compute a new source span because when we found the start tag before we knew
// the end poosition of the tag.
var length = end.AbsoluteIndex - popped.Source.Value.AbsoluteIndex;
popped.Source = new SourceSpan(
popped.Source.Value.FilePath,
popped.Source.Value.AbsoluteIndex,
popped.Source.Value.LineIndex,
popped.Source.Value.CharacterIndex,
length);
}
}
break;
}
case HtmlTokenType.Comment:
break;
default:
throw new InvalidCastException($"Unsupported token type: {token.Type.ToString()}");
}
}
}
else if (children[i] is HtmlAttributeIntermediateNode htmlAttribute)
{
// Buffer the attribute for now, it will get written out as part of a tag.
attributes.Add(htmlAttribute);
}
else
{
// not HTML, or already rewritten.
stack.Peek().Children.Add(children[i]);
}
}
var extraContent = parser.GetUnparsedContent();
if (!string.IsNullOrEmpty(extraContent))
{
// extra HTML - almost certainly invalid because it couldn't be parsed.
var start = parser.GetCurrentLocation();
var end = parser.GetCurrentLocation(extraContent.Length);
var span = new SourceSpan(start, end.AbsoluteIndex - start.AbsoluteIndex);
stack.Peek().Children.Add(new HtmlContentIntermediateNode()
{
Children =
{
new IntermediateToken()
{
Content = extraContent,
Kind = TokenKind.Html,
Source = span,
}
},
Diagnostics =
{
BlazorDiagnosticFactory.Create_InvalidHtmlContent(span, extraContent),
},
Source = span,
});
}
while (stack.Count > 1)
{
// not balanced
var popped = (HtmlElementIntermediateNode)stack.Pop();
var diagnostic = BlazorDiagnosticFactory.Create_UnclosedTag(popped.Source, popped.TagName);
popped.Diagnostics.Add(diagnostic);
}
}
}
private static HtmlAttributeIntermediateNode CreateAttributeNode(KeyValuePair<string, string> attribute)
{
return new HtmlAttributeIntermediateNode()
{
AttributeName = attribute.Key,
Children =
{
new HtmlAttributeValueIntermediateNode()
{
Children =
{
new IntermediateToken()
{
Kind = TokenKind.Html,
Content = attribute.Value,
},
}
},
}
};
}
private static string GetHtmlContent(HtmlContentIntermediateNode node)
{
var builder = new StringBuilder();
for (var i = 0; i < node.Children.Count; i++)
{
var token = node.Children[i] as IntermediateToken;
if (token != null && token.IsHtml)
{
builder.Append(token.Content);
}
}
return builder.ToString();
}
[DebuggerDisplay("{DebuggerDisplay,nq}")]
private class HtmlParser
{
private readonly RazorSourceDocument _source;
// Tracks the offsets between the start of _content and then original source document.
private List<(int offset, int sourceOffset)> _offsets;
private HtmlTokenizer _tokenizer;
private int _position;
private string _content;
public HtmlParser(RazorSourceDocument source)
{
_source = source;
}
public void Push(HtmlContentIntermediateNode node)
{
var builder = new StringBuilder();
var offsets = new List<(int offset, int sourceOffset)>();
if (_content != null && _position < _content.Length)
{
offsets.Add((0, _offsets[0].sourceOffset + _position));
builder.Append(_content, _position, _content.Length - _position);
}
for (var i = 0; i < node.Children.Count; i++)
{
var token = node.Children[i] as IntermediateToken;
if (token != null && token.IsHtml)
{
offsets.Add((builder.Length, token.Source.Value.AbsoluteIndex));
builder.Append(token.Content);
}
}
_content = builder.ToString();
_offsets = offsets;
_tokenizer = new HtmlTokenizer(new TextSource(_content), HtmlEntityService.Resolver);
_position = 0;
}
public string GetUnparsedContent()
{
return _position >= _content.Length ? string.Empty : _content.Substring(_position);
}
public HtmlToken Get()
{
if (_tokenizer == null)
{
throw new InvalidOperationException("You need to call Push first.");
}
var token = _tokenizer.Get();
// The tokenizer will advance to the end when you have an unclosed tag.
// We don't want this, we want to resume before the unclosed tag.
if (token.Type != HtmlTokenType.EndOfFile)
{
_position = _tokenizer.Position;
}
return token;
}
public SourceLocation GetCurrentLocation(int offset = 0)
{
var absoluteIndex = GetAbsoluteIndex(_position + offset);
int lineIndex = -1;
int columnIndex = -1;
var remaining = absoluteIndex;
for (var i = 0; i < _source.Lines.Count; i++)
{
var lineLength = _source.Lines.GetLineLength(i);
if (lineLength > remaining)
{
lineIndex = i;
columnIndex = remaining;
break;
}
remaining -= lineLength;
}
return new SourceLocation(_source.FilePath, absoluteIndex, lineIndex, columnIndex);
}
public SourceSpan GetSpan(HtmlToken token)
{
var absoluteIndex = GetAbsoluteIndex(token.Position.Position);
int lineIndex = -1;
int columnIndex = -1;
var remaining = absoluteIndex;
for (var i = 0; i < _source.Lines.Count; i++)
{
var lineLength = _source.Lines.GetLineLength(i);
if (lineLength > remaining)
{
lineIndex = i;
columnIndex = remaining;
break;
}
remaining -= lineLength;
}
var length = GetAbsoluteIndex(_position) - absoluteIndex;
return new SourceSpan(_source.FilePath, absoluteIndex, lineIndex, columnIndex, length);
}
private int GetAbsoluteIndex(int contentIndex)
{
for (var i = _offsets.Count - 1; i >= 0; i--)
{
if (_offsets[i].offset <= contentIndex)
{
return _offsets[i].sourceOffset + (contentIndex - _offsets[i].offset);
}
}
throw new InvalidOperationException("Unexpected index value.");
}
// Anglesharp canonicalizes the case of tags, we want what the user typed.
public string GetTagNameOriginalCasing(HtmlTagToken tag)
{
var offset = tag.Type == HtmlTokenType.EndTag ? 1 : 0; // For end tags, skip the '/'
return tag.Name;
}
private string DebuggerDisplay
{
get
{
if (_content == null)
{
return "Content={}";
}
var builder = new StringBuilder();
builder.Append("Content=");
builder.Append("{");
builder.Append(_content.Substring(0, Math.Min(_position, _content.Length)));
builder.Append("|");
builder.Append(_content.Substring(Math.Min(_position, _content.Length)));
builder.Append("}");
return builder.ToString();
}
}
}
}
}

View File

@ -0,0 +1,94 @@
// 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.Generic;
using System.Linq;
using System.Text;
using Microsoft.AspNetCore.Razor.Language;
using Microsoft.AspNetCore.Razor.Language.CodeGeneration;
using Microsoft.AspNetCore.Razor.Language.Intermediate;
namespace Microsoft.AspNetCore.Blazor.Razor
{
internal class ComponentExtensionNode : ExtensionIntermediateNode
{
public IEnumerable<ComponentAttributeExtensionNode> Attributes => Children.OfType<ComponentAttributeExtensionNode>();
public IEnumerable<RefExtensionNode> Captures => Children.OfType<RefExtensionNode>();
public IEnumerable<IntermediateNode> Body => Children.Where(c =>
{
return
c as ComponentAttributeExtensionNode == null &&
c as RefExtensionNode == null;
});
public override IntermediateNodeCollection Children { get; } = new IntermediateNodeCollection();
public TagHelperDescriptor Component { get; set; }
public string TagName { get; set; }
public string TypeName => Component?.GetTypeName();
public override void Accept(IntermediateNodeVisitor visitor)
{
if (visitor == null)
{
throw new ArgumentNullException(nameof(visitor));
}
AcceptExtensionNode<ComponentExtensionNode>(this, visitor);
}
public override void WriteNode(CodeTarget target, CodeRenderingContext context)
{
if (target == null)
{
throw new ArgumentNullException(nameof(target));
}
if (context == null)
{
throw new ArgumentNullException(nameof(context));
}
var writer = (BlazorNodeWriter)context.NodeWriter;
writer.WriteComponent(context, this);
}
private string DebuggerDisplay
{
get
{
var builder = new StringBuilder();
builder.Append("Component: ");
builder.Append("<");
builder.Append(TagName);
foreach (var attribute in Attributes)
{
builder.Append(" ");
builder.Append(attribute.AttributeName);
builder.Append("=\"...\"");
}
foreach (var capture in Captures)
{
builder.Append(" ");
builder.Append("ref");
builder.Append("=\"...\"");
}
builder.Append(">");
builder.Append(Body.Any() ? "..." : string.Empty);
builder.Append("</");
builder.Append(TagName);
builder.Append(">");
return builder.ToString();
}
}
}
}

View File

@ -9,8 +9,8 @@ namespace Microsoft.AspNetCore.Blazor.Razor
{
internal class ComponentLoweringPass : IntermediateNodePassBase, IRazorOptimizationPass
{
// Run after our *special* tag helpers get lowered.
public override int Order => 1000;
// This pass runs earlier than our other passes that 'lower' specific kinds of attributes.
public override int Order => 0;
protected override void ExecuteCore(RazorCodeDocument codeDocument, DocumentIntermediateNode documentNode)
{
@ -24,112 +24,265 @@ namespace Microsoft.AspNetCore.Blazor.Razor
// For each component *usage* we need to rewrite the tag helper node to map to the relevant component
// APIs.
var nodes = documentNode.FindDescendantNodes<TagHelperIntermediateNode>();
for (var i = 0; i < nodes.Count; i++)
var references = documentNode.FindDescendantReferences<TagHelperIntermediateNode>();
for (var i = 0; i < references.Count; i++)
{
var reference = references[i];
var node = (TagHelperIntermediateNode)reference.Node;
var count = 0;
var node = nodes[i];
for (var j = 0; j < node.TagHelpers.Count; j++)
{
if (node.TagHelpers[j].IsComponentTagHelper())
{
// Only allow a single component tag helper per element. We also have some *special* tag helpers
// and they should have already been processed by now.
// Only allow a single component tag helper per element. If there are multiple, we'll just consider
// the first one and ignore the others.
if (count++ > 1)
{
node.Diagnostics.Add(BlazorDiagnosticFactory.Create_MultipleComponents(node.Source, node.TagName, node.TagHelpers));
break;
}
RewriteUsage(node, node.TagHelpers[j]);
}
}
if (count >= 1)
{
reference.Replace(RewriteAsComponent(node, node.TagHelpers.First(t => t.IsComponentTagHelper())));
}
else
{
reference.Replace(RewriteAsElement(node));
}
}
}
private void RewriteUsage(TagHelperIntermediateNode node, TagHelperDescriptor tagHelper)
private ComponentExtensionNode RewriteAsComponent(TagHelperIntermediateNode node, TagHelperDescriptor tagHelper)
{
// We need to surround the contents of the node with open and close nodes to ensure the component
// is scoped correctly.
node.Children.Insert(0, new ComponentOpenExtensionNode()
var result = new ComponentExtensionNode()
{
TypeName = tagHelper.GetTypeName(),
});
Component = tagHelper,
Source = node.Source,
TagName = node.TagName,
};
for (var i = node.Children.Count - 1; i >= 0; i--)
for (var i = 0; i < node.Diagnostics.Count; i++)
{
if (node.Children[i] is TagHelperBodyIntermediateNode bodyNode)
result.Diagnostics.Add(node.Diagnostics[i]);
}
var visitor = new ComponentRewriteVisitor(result.Children);
visitor.Visit(node);
return result;
}
private HtmlElementIntermediateNode RewriteAsElement(TagHelperIntermediateNode node)
{
var result = new HtmlElementIntermediateNode()
{
Source = node.Source,
TagName = node.TagName,
};
for (var i = 0; i < node.Diagnostics.Count; i++)
{
result.Diagnostics.Add(node.Diagnostics[i]);
}
var visitor = new ElementRewriteVisitor(result.Children);
visitor.Visit(node);
return result;
}
private class ComponentRewriteVisitor : IntermediateNodeWalker
{
private readonly IntermediateNodeCollection _children;
public ComponentRewriteVisitor(IntermediateNodeCollection children)
{
_children = children;
}
public override void VisitTagHelper(TagHelperIntermediateNode node)
{
// Visit children, we're replacing this node.
for (var i = 0; i < node.Children.Count; i++)
{
// Replace with a node that we recognize so that it we can do proper scope tracking.
//
// Note that we force the body node to be last, this is done to push it after the
// attribute nodes. This gives us the ordering we want for the render tree.
node.Children.RemoveAt(i);
node.Children.Add(new ComponentBodyExtensionNode(bodyNode)
{
TagMode = node.TagMode,
TagName = node.TagName,
});
Visit(node.Children[i]);
}
}
node.Children.Add(new ComponentCloseExtensionNode());
// Now we need to rewrite any set property or HTML nodes to call the appropriate AddAttribute api.
for (var i = node.Children.Count - 1; i >= 0; i--)
public override void VisitTagHelperBody(TagHelperBodyIntermediateNode node)
{
if (node.Children[i] is TagHelperPropertyIntermediateNode propertyNode &&
propertyNode.TagHelper == tagHelper)
for (var i = 0; i < node.Children.Count; i++)
{
node.Children[i] = new ComponentAttributeExtensionNode(propertyNode);
_children.Add(node.Children[i]);
}
else if (node.Children[i] is TagHelperHtmlAttributeIntermediateNode htmlNode)
{
// For any nodes that don't map to a component property we won't have type information
// but these should follow the same path through the runtime.
var attributeNode = new ComponentAttributeExtensionNode(htmlNode);
node.Children[i] = attributeNode;
}
// Since we don't support complex content, we can rewrite the inside of this
// node to the rather simpler form that property nodes usually have.
for (var j = 0; j < attributeNode.Children.Count; j++)
public override void VisitTagHelperHtmlAttribute(TagHelperHtmlAttributeIntermediateNode node)
{
var attribute = new ComponentAttributeExtensionNode(node);
_children.Add(attribute);
// Since we don't support complex content, we can rewrite the inside of this
// node to the rather simpler form that property nodes usually have.
for (var i = 0; i < attribute.Children.Count; i++)
{
if (attribute.Children[i] is HtmlAttributeValueIntermediateNode htmlValue)
{
if (attributeNode.Children[j] is HtmlAttributeValueIntermediateNode htmlValue)
attribute.Children[i] = new HtmlContentIntermediateNode()
{
attributeNode.Children[j] = new HtmlContentIntermediateNode()
Children =
{
Children =
{
htmlValue.Children.Single(),
},
Source = htmlValue.Source,
};
}
else if (attributeNode.Children[j] is CSharpExpressionAttributeValueIntermediateNode expressionValue)
htmlValue.Children.Single(),
},
Source = htmlValue.Source,
};
}
else if (attribute.Children[i] is CSharpExpressionAttributeValueIntermediateNode expressionValue)
{
attribute.Children[i] = new CSharpExpressionIntermediateNode()
{
attributeNode.Children[j] = new CSharpExpressionIntermediateNode()
Children =
{
Children =
{
expressionValue.Children.Single(),
},
Source = expressionValue.Source,
};
}
else if (attributeNode.Children[j] is CSharpCodeAttributeValueIntermediateNode codeValue)
expressionValue.Children.Single(),
},
Source = expressionValue.Source,
};
}
else if (attribute.Children[i] is CSharpCodeAttributeValueIntermediateNode codeValue)
{
attribute.Children[i] = new CSharpExpressionIntermediateNode()
{
attributeNode.Children[j] = new CSharpExpressionIntermediateNode()
Children =
{
Children =
{
codeValue.Children.Single(),
},
Source = codeValue.Source,
};
}
codeValue.Children.Single(),
},
Source = codeValue.Source,
};
}
}
}
public override void VisitTagHelperProperty(TagHelperPropertyIntermediateNode node)
{
// Each 'tag helper property' belongs to a specific tag helper. We want to handle
// the cases for components, but leave others alone. This allows our other passes
// to handle those cases.
_children.Add(node.TagHelper.IsComponentTagHelper() ? (IntermediateNode)new ComponentAttributeExtensionNode(node) : node);
}
public override void VisitDefault(IntermediateNode node)
{
_children.Add(node);
}
}
private class ElementRewriteVisitor : IntermediateNodeWalker
{
private readonly IntermediateNodeCollection _children;
public ElementRewriteVisitor(IntermediateNodeCollection children)
{
_children = children;
}
public override void VisitTagHelper(TagHelperIntermediateNode node)
{
// Visit children, we're replacing this node.
for (var i = 0; i < node.Children.Count; i++)
{
Visit(node.Children[i]);
}
}
public override void VisitTagHelperBody(TagHelperBodyIntermediateNode node)
{
for (var i = 0; i < node.Children.Count; i++)
{
_children.Add(node.Children[i]);
}
}
public override void VisitTagHelperHtmlAttribute(TagHelperHtmlAttributeIntermediateNode node)
{
var attribute = new HtmlAttributeIntermediateNode()
{
AttributeName = node.AttributeName,
Source = node.Source,
};
_children.Add(attribute);
for (var i = 0; i < node.Diagnostics.Count; i++)
{
attribute.Diagnostics.Add(node.Diagnostics[i]);
}
switch (node.AttributeStructure)
{
case AttributeStructure.Minimized:
attribute.Prefix = node.AttributeName;
attribute.Suffix = string.Empty;
break;
case AttributeStructure.NoQuotes:
case AttributeStructure.SingleQuotes:
case AttributeStructure.DoubleQuotes:
// We're ignoring attribute structure here for simplicity, it doesn't effect us.
attribute.Prefix = node.AttributeName + "=\"";
attribute.Suffix = "\"";
for (var i = 0; i < node.Children.Count; i++)
{
attribute.Children.Add(RewriteAttributeContent(node.Children[i]));
}
break;
}
IntermediateNode RewriteAttributeContent(IntermediateNode content)
{
if (content is HtmlContentIntermediateNode html)
{
var value = new HtmlAttributeValueIntermediateNode()
{
Source = content.Source,
};
for (var i = 0; i < html.Children.Count; i++)
{
value.Children.Add(html.Children[i]);
}
for (var i = 0; i < html.Diagnostics.Count; i++)
{
value.Diagnostics.Add(html.Diagnostics[i]);
}
return value;
}
return content;
}
}
public override void VisitTagHelperProperty(TagHelperPropertyIntermediateNode node)
{
// Each 'tag helper property' belongs to a specific tag helper. We want to handle
// the cases for components, but leave others alone. This allows our other passes
// to handle those cases.
_children.Add(node.TagHelper.IsComponentTagHelper() ? (IntermediateNode)new ComponentAttributeExtensionNode(node) : node);
}
public override void VisitDefault(IntermediateNode node)
{
_children.Add(node);
}
}
}
}

View File

@ -1,42 +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 Microsoft.AspNetCore.Razor.Language.CodeGeneration;
using Microsoft.AspNetCore.Razor.Language.Intermediate;
namespace Microsoft.AspNetCore.Blazor.Razor
{
internal class ComponentOpenExtensionNode : ExtensionIntermediateNode
{
public override IntermediateNodeCollection Children => IntermediateNodeCollection.ReadOnly;
public string TypeName { get; set; }
public override void Accept(IntermediateNodeVisitor visitor)
{
if (visitor == null)
{
throw new ArgumentNullException(nameof(visitor));
}
AcceptExtensionNode<ComponentOpenExtensionNode>(this, visitor);
}
public override void WriteNode(CodeTarget target, CodeRenderingContext context)
{
if (target == null)
{
throw new ArgumentNullException(nameof(target));
}
if (context == null)
{
throw new ArgumentNullException(nameof(context));
}
var writer = (BlazorNodeWriter)context.NodeWriter;
writer.WriteComponentOpen(context, this);
}
}
}

View File

@ -0,0 +1,44 @@
// 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.Generic;
namespace Microsoft.AspNetCore.Razor.Language.Intermediate
{
internal static class DocumentIntermediateNodeExtensions
{
public static IReadOnlyList<IntermediateNodeReference> FindDescendantReferences<TNode>(this DocumentIntermediateNode document)
where TNode : IntermediateNode
{
if (document == null)
{
throw new ArgumentNullException(nameof(document));
}
var visitor = new ReferenceVisitor<TNode>();
visitor.Visit(document);
return visitor.References;
}
private class ReferenceVisitor<TNode> : IntermediateNodeWalker
where TNode : IntermediateNode
{
public List<IntermediateNodeReference> References = new List<IntermediateNodeReference>();
public override void VisitDefault(IntermediateNode node)
{
base.VisitDefault(node);
// Use a post-order traversal because references are used to replace nodes, and thus
// change the parent nodes.
//
// This ensures that we always operate on the leaf nodes first.
if (node is TNode)
{
References.Add(new IntermediateNodeReference(Parent, node));
}
}
}
}
}

View File

@ -1,6 +1,7 @@
// 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.Linq;
using Microsoft.AspNetCore.Blazor.Shared;
using Microsoft.AspNetCore.Razor.Language;
@ -10,6 +11,8 @@ namespace Microsoft.AspNetCore.Blazor.Razor
{
internal class EventHandlerLoweringPass : IntermediateNodePassBase, IRazorOptimizationPass
{
public override int Order => 50;
protected override void ExecuteCore(RazorCodeDocument codeDocument, DocumentIntermediateNode documentNode)
{
var @namespace = documentNode.FindPrimaryNamespace();
@ -21,52 +24,63 @@ namespace Microsoft.AspNetCore.Blazor.Razor
}
// For each event handler *usage* we need to rewrite the tag helper node to map to basic constructs.
var nodes = documentNode.FindDescendantNodes<TagHelperIntermediateNode>();
for (var i = 0; i < nodes.Count; i++)
// Each usage will be represented by a tag helper property that is a descendant of either
// a component or element.
var references = documentNode.FindDescendantReferences<TagHelperPropertyIntermediateNode>();
var parents = new HashSet<IntermediateNode>();
for (var i = 0; i < references.Count; i++)
{
var node = nodes[i];
parents.Add(references[i].Parent);
}
ProcessDuplicates(node);
foreach (var parent in parents)
{
ProcessDuplicates(parent);
}
for (var j = node.Children.Count - 1; j >= 0; j--)
for (var i = 0; i < references.Count; i++)
{
var reference = references[i];
var node = (TagHelperPropertyIntermediateNode)reference.Node;
if (!reference.Parent.Children.Contains(node))
{
var attributeNode = node.Children[j] as ComponentAttributeExtensionNode;
if (attributeNode != null &&
attributeNode.TagHelper != null &&
attributeNode.TagHelper.IsEventHandlerTagHelper())
{
RewriteUsage(node, j, attributeNode);
}
// This node was removed as a duplicate, skip it.
continue;
}
if (node.TagHelper.IsEventHandlerTagHelper())
{
reference.Replace(RewriteUsage(reference.Parent, node));
}
}
}
private void ProcessDuplicates(TagHelperIntermediateNode node)
private void ProcessDuplicates(IntermediateNode parent)
{
// Reverse order because we will remove nodes.
//
// Each 'property' node could be duplicated if there are multiple tag helpers that match that
// particular attribute. This is likely to happen when a component also defines something like
// OnClick. We want to remove the 'onclick' and let it fall back to be handled by the component.
for (var i = node.Children.Count - 1; i >= 0; i--)
for (var i = parent.Children.Count - 1; i >= 0; i--)
{
var attributeNode = node.Children[i] as ComponentAttributeExtensionNode;
if (attributeNode != null &&
attributeNode.TagHelper != null &&
attributeNode.TagHelper.IsEventHandlerTagHelper())
var eventHandler = parent.Children[i] as TagHelperPropertyIntermediateNode;
if (eventHandler != null &&
eventHandler.TagHelper != null &&
eventHandler.TagHelper.IsEventHandlerTagHelper())
{
for (var j = 0; j < node.Children.Count; j++)
for (var j = 0; j < parent.Children.Count; j++)
{
var duplicate = node.Children[j] as ComponentAttributeExtensionNode;
if (duplicate != null &&
duplicate.TagHelper != null &&
duplicate.TagHelper.IsComponentTagHelper() &&
duplicate.AttributeName == attributeNode.AttributeName)
var componentAttribute = parent.Children[j] as ComponentAttributeExtensionNode;
if (componentAttribute != null &&
componentAttribute.TagHelper != null &&
componentAttribute.TagHelper.IsComponentTagHelper() &&
componentAttribute.AttributeName == eventHandler.AttributeName)
{
// Found a duplicate - remove the 'fallback' in favor of the
// more specific tag helper.
node.Children.RemoveAt(i);
node.TagHelpers.Remove(attributeNode.TagHelper);
// Found a duplicate - remove the 'fallback' in favor of the component's own handling.
parent.Children.RemoveAt(i);
break;
}
}
@ -74,37 +88,28 @@ namespace Microsoft.AspNetCore.Blazor.Razor
}
// If we still have duplicates at this point then they are genuine conflicts.
var duplicates = node.Children
.OfType<ComponentAttributeExtensionNode>()
var duplicates = parent.Children
.OfType<TagHelperPropertyIntermediateNode>()
.Where(p => p.TagHelper?.IsEventHandlerTagHelper() ?? false)
.GroupBy(p => p.AttributeName)
.Where(g => g.Count() > 1);
foreach (var duplicate in duplicates)
{
node.Diagnostics.Add(BlazorDiagnosticFactory.CreateEventHandler_Duplicates(
node.Source,
parent.Diagnostics.Add(BlazorDiagnosticFactory.CreateEventHandler_Duplicates(
parent.Source,
duplicate.Key,
duplicate.ToArray()));
foreach (var property in duplicate)
{
node.Children.Remove(property);
parent.Children.Remove(property);
}
}
}
private void RewriteUsage(TagHelperIntermediateNode node, int index, ComponentAttributeExtensionNode attributeNode)
private IntermediateNode RewriteUsage(IntermediateNode parent, TagHelperPropertyIntermediateNode node)
{
var original = GetAttributeContent(attributeNode);
if (string.IsNullOrEmpty(original.Content))
{
// This can happen in error cases, the parser will already have flagged this
// as an error, so ignore it.
return;
}
var rewrittenNode = new ComponentAttributeExtensionNode(attributeNode);
node.Children[index] = rewrittenNode;
var original = GetAttributeContent(node);
// Now rewrite the content of the value node to look like:
//
@ -112,29 +117,62 @@ namespace Microsoft.AspNetCore.Blazor.Razor
//
// This method is overloaded on string and TDelegate, which means that it will put the code in the
// correct context for intellisense when typing in the attribute.
var eventArgsType = attributeNode.TagHelper.GetEventArgsType();
rewrittenNode.Children.Clear();
rewrittenNode.Children.Add(new CSharpExpressionIntermediateNode()
var eventArgsType = node.TagHelper.GetEventArgsType();
var tokens = new List<IntermediateToken>()
{
Children =
new IntermediateToken()
{
new IntermediateToken()
{
Content = $"{BlazorApi.BindMethods.GetEventHandlerValue}<{eventArgsType}>(",
Kind = TokenKind.CSharp
},
original,
new IntermediateToken()
{
Content = $")",
Kind = TokenKind.CSharp
}
Content = $"{BlazorApi.BindMethods.GetEventHandlerValue}<{eventArgsType}>(",
Kind = TokenKind.CSharp
},
});
original,
new IntermediateToken()
{
Content = $")",
Kind = TokenKind.CSharp
}
};
if (parent is HtmlElementIntermediateNode)
{
var result = new HtmlAttributeIntermediateNode()
{
AttributeName = node.AttributeName,
Source = node.Source,
Prefix = node.AttributeName + "=\"",
Suffix = "\"",
};
for (var i = 0; i < node.Diagnostics.Count; i++)
{
result.Diagnostics.Add(node.Diagnostics[i]);
}
result.Children.Add(new CSharpExpressionAttributeValueIntermediateNode());
for (var i = 0; i < tokens.Count; i++)
{
result.Children[0].Children.Add(tokens[i]);
}
return result;
}
else
{
var result = new ComponentAttributeExtensionNode(node);
result.Children.Clear();
result.Children.Add(new CSharpExpressionIntermediateNode());
for (var i = 0; i < tokens.Count; i++)
{
result.Children[0].Children.Add(tokens[i]);
}
return result;
}
}
private static IntermediateToken GetAttributeContent(ComponentAttributeExtensionNode node)
private static IntermediateToken GetAttributeContent(TagHelperPropertyIntermediateNode node)
{
if (node.Children[0] is HtmlContentIntermediateNode htmlContentNode)
{

View File

@ -0,0 +1,91 @@
// 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.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;
using Microsoft.AspNetCore.Razor.Language.CodeGeneration;
using Microsoft.AspNetCore.Razor.Language.Intermediate;
namespace Microsoft.AspNetCore.Blazor.Razor
{
[DebuggerDisplay("{DebuggerDisplay,nq}")]
internal class HtmlElementIntermediateNode : ExtensionIntermediateNode
{
public IEnumerable<HtmlAttributeIntermediateNode> Attributes => Children.OfType<HtmlAttributeIntermediateNode>();
public IEnumerable<RefExtensionNode> Captures => Children.OfType<RefExtensionNode>();
public IEnumerable<IntermediateNode> Body => Children.Where(c =>
{
return
c as HtmlAttributeIntermediateNode == null &&
c as RefExtensionNode == null;
});
public override IntermediateNodeCollection Children { get; } = new IntermediateNodeCollection();
public string TagName { get; set; }
public override void Accept(IntermediateNodeVisitor visitor)
{
if (visitor == null)
{
throw new ArgumentNullException(nameof(visitor));
}
AcceptExtensionNode<HtmlElementIntermediateNode>(this, visitor);
}
public override void WriteNode(CodeTarget target, CodeRenderingContext context)
{
if (target == null)
{
throw new ArgumentNullException(nameof(target));
}
if (context == null)
{
throw new ArgumentNullException(nameof(context));
}
var writer = (BlazorNodeWriter)context.NodeWriter;
writer.WriteHtmlElement(context, this);
}
private string DebuggerDisplay
{
get
{
var builder = new StringBuilder();
builder.Append("Element: ");
builder.Append("<");
builder.Append(TagName);
foreach (var attribute in Attributes)
{
builder.Append(" ");
builder.Append(attribute.AttributeName);
builder.Append("=\"...\"");
}
foreach (var capture in Captures)
{
builder.Append(" ");
builder.Append("ref");
builder.Append("=\"...\"");
}
builder.Append(">");
builder.Append(Body.Any() ? "..." : string.Empty);
builder.Append("</");
builder.Append(TagName);
builder.Append(">");
return builder.ToString();
}
}
}
}

View File

@ -1,283 +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.Generic;
using System.Linq;
using Microsoft.AspNetCore.Razor.Language;
using Microsoft.AspNetCore.Razor.Language.Intermediate;
namespace Microsoft.AspNetCore.Blazor.Razor
{
// We use some tag helpers that can be applied directly to HTML elements. When
// that happens, the default lowering pass will map the whole element as a tag helper.
//
// This phase exists to turn these 'orphan' tag helpers back into HTML elements so that
// go down the proper path for rendering.
internal class OrphanTagHelperLoweringPass : IntermediateNodePassBase, IRazorOptimizationPass
{
// Run after our other passes
public override int Order => 1000;
protected override void ExecuteCore(RazorCodeDocument codeDocument, DocumentIntermediateNode documentNode)
{
if (codeDocument == null)
{
throw new ArgumentNullException(nameof(codeDocument));
}
if (documentNode == null)
{
throw new ArgumentNullException(nameof(documentNode));
}
var visitor = new Visitor();
visitor.Visit(documentNode);
for (var i = 0; i < visitor.References.Count; i++)
{
var reference = visitor.References[i];
var tagHelperNode = (TagHelperIntermediateNode)reference.Node;
// Since this is converted from a tag helper to a regular old HTMl element, we need to
// flatten out the structure
var insert = new List<IntermediateNode>();
insert.Add(new HtmlContentIntermediateNode()
{
Children =
{
new IntermediateToken()
{
Content = "<" + tagHelperNode.TagName + " ",
Kind = TokenKind.Html,
}
},
});
for (var j = 0; j < tagHelperNode.Diagnostics.Count; j++)
{
insert[0].Diagnostics.Add(tagHelperNode.Diagnostics[j]);
}
// We expect to see a body node, followed by a series of property/attribute nodes
// This isn't really the order we want, so skip over the body for now, and we'll do another
// pass that merges it in.
for (var j = 0; j < tagHelperNode.Children.Count; j++)
{
if (tagHelperNode.Children[j] is TagHelperBodyIntermediateNode)
{
continue;
}
else if (tagHelperNode.Children[j] is TagHelperHtmlAttributeIntermediateNode htmlAttribute)
{
if (htmlAttribute.Children.Count == 0)
{
RewriteEmptyAttributeContent(insert, htmlAttribute);
}
else if (htmlAttribute.Children[0] is HtmlContentIntermediateNode)
{
RewriteHtmlAttributeContent(insert, htmlAttribute);
}
else if (htmlAttribute.Children[0] is CSharpExpressionAttributeValueIntermediateNode csharpContent)
{
RewriteCSharpAttributeContent(insert, htmlAttribute);
}
}
else if (tagHelperNode.Children[j] is ComponentAttributeExtensionNode attributeNode)
{
RewriteComponentAttributeContent(insert, attributeNode);
}
else
{
// We shouldn't see anything else here, but just in case, add the content as-is.
insert.Add(tagHelperNode.Children[j]);
}
}
if (tagHelperNode.TagMode == TagMode.SelfClosing)
{
insert.Add(new HtmlContentIntermediateNode()
{
Children =
{
new IntermediateToken()
{
Content = "/>",
Kind = TokenKind.Html,
}
}
});
}
else if (tagHelperNode.TagMode == TagMode.StartTagOnly)
{
insert.Add(new HtmlContentIntermediateNode()
{
Children =
{
new IntermediateToken()
{
Content = ">",
Kind = TokenKind.Html,
}
}
});
}
else
{
insert.Add(new HtmlContentIntermediateNode()
{
Children =
{
new IntermediateToken()
{
Content = ">",
Kind = TokenKind.Html,
}
}
});
for (var j = 0; j < tagHelperNode.Children.Count; j++)
{
if (tagHelperNode.Children[j] is TagHelperBodyIntermediateNode bodyNode)
{
insert.AddRange(bodyNode.Children);
}
}
insert.Add(new HtmlContentIntermediateNode()
{
Children =
{
new IntermediateToken()
{
Content = "</" + tagHelperNode.TagName + ">",
Kind = TokenKind.Html,
}
}
});
}
reference.InsertAfter(insert);
reference.Remove();
}
}
private static void RewriteEmptyAttributeContent(List<IntermediateNode> nodes, TagHelperHtmlAttributeIntermediateNode node)
{
nodes.Add(new HtmlContentIntermediateNode()
{
Children =
{
new IntermediateToken()
{
Content = node.AttributeName + " ",
Kind = TokenKind.Html,
}
}
});
}
private static void RewriteHtmlAttributeContent(List<IntermediateNode> nodes, TagHelperHtmlAttributeIntermediateNode node)
{
switch (node.AttributeStructure)
{
case AttributeStructure.Minimized:
nodes.Add(new HtmlContentIntermediateNode()
{
Children =
{
new IntermediateToken()
{
Content = node.AttributeName + " ",
Kind = TokenKind.Html,
}
}
});
break;
// Blazor doesn't really care about preserving the fidelity of the attributes.
case AttributeStructure.NoQuotes:
case AttributeStructure.SingleQuotes:
case AttributeStructure.DoubleQuotes:
var htmlNode = new HtmlContentIntermediateNode();
nodes.Add(htmlNode);
htmlNode.Children.Add(new IntermediateToken()
{
Content = node.AttributeName + "=\"",
Kind = TokenKind.Html,
});
for (var i = 0; i < node.Children[0].Children.Count; i++)
{
htmlNode.Children.Add(node.Children[0].Children[i]);
}
htmlNode.Children.Add(new IntermediateToken()
{
Content = "\" ",
Kind = TokenKind.Html,
});
break;
}
}
private static void RewriteCSharpAttributeContent(List<IntermediateNode> nodes, TagHelperHtmlAttributeIntermediateNode node)
{
var attributeNode = new HtmlAttributeIntermediateNode()
{
AttributeName = node.AttributeName,
Prefix = "=\"",
Suffix = "\"",
};
nodes.Add(attributeNode);
var valueNode = new CSharpExpressionAttributeValueIntermediateNode();
attributeNode.Children.Add(valueNode);
for (var i = 0; i < node.Children[0].Children.Count; i++)
{
valueNode.Children.Add(node.Children[0].Children[i]);
}
}
private void RewriteComponentAttributeContent(List<IntermediateNode> nodes, ComponentAttributeExtensionNode node)
{
var attributeNode = new HtmlAttributeIntermediateNode()
{
AttributeName = node.AttributeName,
Prefix = "=\"",
Suffix = "\"",
};
nodes.Add(attributeNode);
var valueNode = new CSharpExpressionAttributeValueIntermediateNode();
attributeNode.Children.Add(valueNode);
for (var i = 0; i < node.Children[0].Children.Count; i++)
{
valueNode.Children.Add(node.Children[0].Children[i]);
}
}
private class Visitor : IntermediateNodeWalker
{
public List<IntermediateNodeReference> References = new List<IntermediateNodeReference>();
public override void VisitTagHelper(TagHelperIntermediateNode node)
{
base.VisitTagHelper(node);
// Use a post-order traversal because we're going to rewrite tag helper nodes, and thus
// change the parent nodes.
//
// This ensures that we operate the leaf nodes first.
if (!node.TagHelpers.Any(t => t.IsComponentTagHelper()))
{
References.Add(new IntermediateNodeReference(Parent, node));
}
}
}
}
}

View File

@ -3,16 +3,13 @@
using Microsoft.AspNetCore.Razor.Language;
using Microsoft.AspNetCore.Razor.Language.Intermediate;
using System;
using System.Collections.Generic;
using System.Linq;
namespace Microsoft.AspNetCore.Blazor.Razor
{
internal class RefLoweringPass : IntermediateNodePassBase, IRazorOptimizationPass
{
// Run after our other passes
public override int Order => 1000;
// Run after component lowering pass
public override int Order => 50;
protected override void ExecuteCore(RazorCodeDocument codeDocument, DocumentIntermediateNode documentNode)
{
@ -24,62 +21,43 @@ namespace Microsoft.AspNetCore.Blazor.Razor
return;
}
var nodes = documentNode.FindDescendantNodes<TagHelperIntermediateNode>();
for (var i = 0; i < nodes.Count; i++)
var references = documentNode.FindDescendantReferences<TagHelperPropertyIntermediateNode>();
for (var i = 0; i < references.Count; i++)
{
var node = nodes[i];
var reference = references[i];
var node = (TagHelperPropertyIntermediateNode)reference.Node;
for (var j = node.Children.Count - 1; j >= 0; j--)
if (node.TagHelper.IsRefTagHelper())
{
var attributeNode = node.Children[j] as ComponentAttributeExtensionNode;
if (attributeNode != null &&
attributeNode.TagHelper != null &&
attributeNode.TagHelper.IsRefTagHelper())
{
RewriteUsage(@class, node, j, attributeNode);
}
reference.Replace(RewriteUsage(@class, reference.Parent, node));
}
}
}
private void RewriteUsage(ClassDeclarationIntermediateNode classNode, TagHelperIntermediateNode node, int index, ComponentAttributeExtensionNode attributeNode)
private IntermediateNode RewriteUsage(ClassDeclarationIntermediateNode classNode, IntermediateNode parent, TagHelperPropertyIntermediateNode node)
{
// If we can't get a nonempty attribute name, do nothing because there will
// already be a diagnostic for empty values
var identifierToken = DetermineIdentifierToken(attributeNode);
if (identifierToken != null)
var identifierToken = DetermineIdentifierToken(node);
if (identifierToken == null)
{
node.Children.Remove(attributeNode);
return node;
}
// Determine whether this is an element capture or a component capture, and
// if applicable the type name that will appear in the resulting capture code
var componentTagHelper = node.TagHelpers.FirstOrDefault(x => x.IsComponentTagHelper());
if (componentTagHelper != null)
{
// For components, the RefExtensionNode must go after all ComponentAttributeExtensionNode
// and ComponentBodyExtensionNode siblings because they translate to AddAttribute calls.
// We can therefore put it immediately before the ComponentCloseExtensionNode.
var componentCloseNodePosition = LastIndexOf(node.Children, n => n is ComponentCloseExtensionNode);
if (componentCloseNodePosition < 0)
{
// Should never happen - would imply we're running the lowering passes in the wrong order
throw new InvalidOperationException($"Cannot find {nameof(ComponentCloseExtensionNode)} among ref node siblings.");
}
var refExtensionNode = new RefExtensionNode(identifierToken, componentTagHelper.GetTypeName());
node.Children.Insert(componentCloseNodePosition, refExtensionNode);
}
else
{
// For elements, it doesn't matter how the RefExtensionNode is positioned
// among the children, as the node writer takes care of emitting the
// code at the right point after the AddAttribute calls
node.Children.Add(new RefExtensionNode(identifierToken));
}
// Determine whether this is an element capture or a component capture, and
// if applicable the type name that will appear in the resulting capture code
var componentTagHelper = (parent as ComponentExtensionNode)?.Component;
if (componentTagHelper != null)
{
return new RefExtensionNode(identifierToken, componentTagHelper.GetTypeName());
}
else
{
return new RefExtensionNode(identifierToken);
}
}
private IntermediateToken DetermineIdentifierToken(ComponentAttributeExtensionNode attributeNode)
private IntermediateToken DetermineIdentifierToken(TagHelperPropertyIntermediateNode attributeNode)
{
IntermediateToken foundToken = null;
@ -100,18 +78,5 @@ namespace Microsoft.AspNetCore.Blazor.Razor
return !string.IsNullOrWhiteSpace(foundToken?.Content) ? foundToken : null;
}
private static int LastIndexOf<T>(IList<T> items, Predicate<T> predicate)
{
for (var index = items.Count - 1; index >= 0; index--)
{
if (predicate(items[index]))
{
return index;
}
}
return -1;
}
}
}

View File

@ -26,31 +26,9 @@ namespace Microsoft.AspNetCore.Blazor.Razor
_stack.Push(new ScopeEntry(tagName, isComponent));
}
public void CloseScope(CodeRenderingContext context, string tagName, bool isComponent, SourceSpan? source)
public void CloseScope(CodeRenderingContext context)
{
if (_stack.Count == 0)
{
var diagnostic = BlazorDiagnosticFactory.Create_UnexpectedClosingTag(source ?? SourceSpan.Undefined, tagName);
throw new RazorCompilerException(diagnostic);
}
var currentScope = _stack.Pop();
if (!tagName.Equals(currentScope.TagName, StringComparison.Ordinal))
{
var diagnostic = BlazorDiagnosticFactory.Create_MismatchedClosingTag(source, currentScope.TagName, tagName);
throw new RazorCompilerException(diagnostic);
}
// Note: there's no unit test to cover the following, because there's no known way of
// triggering it from user code (i.e., Razor source code). But the check is here anyway
// just in case one day it turns out there is some way of causing this error.
if (isComponent != currentScope.IsComponent)
{
var kind = isComponent ? "component" : "element";
var expectedKind = currentScope.IsComponent ? "component" : "element";
var diagnostic = BlazorDiagnosticFactory.Create_MismatchedClosingTagKind(source, tagName, kind, expectedKind);
throw new RazorCompilerException(diagnostic);
}
// When closing the scope for a component with children, it's time to close the lambda
if (currentScope.LambdaScope != null)

View File

@ -0,0 +1,67 @@
// 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.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;
using AngleSharp;
using AngleSharp.Html;
using AngleSharp.Parser.Html;
using Microsoft.AspNetCore.Razor.Language;
using Microsoft.AspNetCore.Razor.Language.Intermediate;
namespace Microsoft.AspNetCore.Blazor.Razor
{
internal class ScriptTagPass : IntermediateNodePassBase, IRazorDocumentClassifierPass
{
// Run as soon as possible after the Component rewrite pass
public override int Order => ComponentDocumentClassifierPass.DefaultFeatureOrder + 2;
protected override void ExecuteCore(RazorCodeDocument codeDocument, DocumentIntermediateNode documentNode)
{
if (documentNode.DocumentKind != ComponentDocumentClassifierPass.ComponentDocumentKind)
{
return;
}
var visitor = new Visitor();
visitor.Visit(documentNode);
}
private class Visitor : IntermediateNodeWalker, IExtensionIntermediateNodeVisitor<HtmlElementIntermediateNode>
{
public void VisitExtension(HtmlElementIntermediateNode node)
{
// Disallow <script> in components as per #552
if (string.Equals(node.TagName, "script", StringComparison.OrdinalIgnoreCase))
{
for (var i = 0; i < node.Children.Count; i++)
{
// We allow you to supress this error like:
// <script suppress-error="BL9992" />
var attribute = node.Children[i] as HtmlAttributeIntermediateNode;
if (attribute != null &&
attribute.AttributeName == "suppress-error" &&
attribute.Children.Count == 1 &&
attribute.Children[0] is HtmlAttributeValueIntermediateNode value &&
value.Children.Count == 1 &&
value.Children[0] is IntermediateToken token &&
token.IsHtml &&
string.Equals(token.Content, "BL9992", StringComparison.Ordinal))
{
node.Children.RemoveAt(i);
return;
}
}
var diagnostic = BlazorDiagnosticFactory.Create_DisallowedScriptTag(node.Source);
node.Diagnostics.Add(diagnostic);
}
base.VisitDefault(node);
}
}
}
}

View File

@ -55,6 +55,7 @@ namespace Microsoft.AspNetCore.Blazor.Razor
shouldContinueIteration = shouldRemoveNode;
break;
case HtmlElementIntermediateNode _:
case CSharpExpressionIntermediateNode _:
case TagHelperIntermediateNode _:
// These node types may produce non-whitespace output at runtime

View File

@ -442,8 +442,35 @@ namespace Test
Assert.Collection(
frames,
frame => AssertFrame.Element(frame, "input", 5, 0),
frame => AssertFrame.Attribute(frame, "visible", 1), // This gets reordered in the node writer
frame => AssertFrame.Attribute(frame, "type", "text", 2),
frame => AssertFrame.Attribute(frame, "type", "text", 1),
frame => AssertFrame.Attribute(frame, "visible", 2),
frame => AssertFrame.Attribute(frame, "value", "42", 3),
frame => AssertFrame.Attribute(frame, "onchange", typeof(Action<UIEventArgs>), 4));
}
[Fact] // See https://github.com/aspnet/Blazor/issues/703
public void Workaround_703()
{
// Arrange
var component = CompileToComponent(@"
@addTagHelper *, TestAssembly
<input bind-value-onchange=""@ParentValue"" type=""text"" visible />
@functions {
public int ParentValue { get; set; } = 42;
}");
// Act
var frames = GetRenderTree(component);
// Assert
//
// The workaround for 703 is that the value attribute MUST be after the type
// attribute.
Assert.Collection(
frames,
frame => AssertFrame.Element(frame, "input", 5, 0),
frame => AssertFrame.Attribute(frame, "type", "text", 1),
frame => AssertFrame.Attribute(frame, "visible", 2),
frame => AssertFrame.Attribute(frame, "value", "42", 3),
frame => AssertFrame.Attribute(frame, "onchange", typeof(Action<UIEventArgs>), 4));
}

View File

@ -23,55 +23,6 @@ namespace Microsoft.AspNetCore.Blazor.Build.Test
});
}
[Fact]
public void RejectsEndTagWithDifferentNameToStartTag()
{
// Arrange/Act
var result = CompileToCSharp(
$"@{{\n" +
$" var abc = 123;\n" +
$"}}\n" +
$"<root>\n" +
$" <other />\n" +
$" text\n" +
$" <child>more text</root>\n" +
$"</child>\n");
// Assert
Assert.Collection(result.Diagnostics,
item =>
{
Assert.Equal("BL9982", item.Id);
Assert.Equal("Mismatching closing tag. Found 'child' but expected 'root'.", item.GetMessage());
Assert.Equal(6, item.Span.LineIndex);
Assert.Equal(20, item.Span.CharacterIndex);
});
}
// This is the old syntax used by @bind and @onclick, it's explicitly unsupported
// and has its own diagnostic.
[Fact]
public void OldEventHandlerSyntax_ReportsError()
{
// Arrange/Act
var generated = CompileToCSharp(@"
<elem @foo(MyHandler) />
@functions {
void MyHandler()
{
}
string foo(Action action)
{
return action.ToString();
}
}");
// Assert
var diagnostic = Assert.Single(generated.Diagnostics);
Assert.Equal("BL9980", diagnostic.Id);
}
// This used to be a sugar syntax for lambdas, but we don't support that anymore
[Fact]
public void OldCodeBlockAttributeSyntax_ReportsError()

View File

@ -14,10 +14,9 @@ namespace Microsoft.AspNetCore.Razor.Language.IntegrationTests
// Serializes single IR nodes (shallow).
public class IntermediateNodeWriter :
IntermediateNodeVisitor,
IExtensionIntermediateNodeVisitor<HtmlElementIntermediateNode>,
IExtensionIntermediateNodeVisitor<ComponentExtensionNode>,
IExtensionIntermediateNodeVisitor<ComponentAttributeExtensionNode>,
IExtensionIntermediateNodeVisitor<ComponentBodyExtensionNode>,
IExtensionIntermediateNodeVisitor<ComponentCloseExtensionNode>,
IExtensionIntermediateNodeVisitor<ComponentOpenExtensionNode>,
IExtensionIntermediateNodeVisitor<RouteAttributeExtensionNode>,
IExtensionIntermediateNodeVisitor<RefExtensionNode>
{
@ -265,9 +264,14 @@ namespace Microsoft.AspNetCore.Razor.Language.IntegrationTests
_writer.Write(content.Replace("\r", string.Empty).Replace("\n", "\\n").Replace(" - ", "\\-"));
}
void IExtensionIntermediateNodeVisitor<ComponentOpenExtensionNode>.VisitExtension(ComponentOpenExtensionNode node)
void IExtensionIntermediateNodeVisitor<HtmlElementIntermediateNode>.VisitExtension(HtmlElementIntermediateNode node)
{
WriteContentNode(node, node.TypeName);
WriteContentNode(node, node.TagName);
}
void IExtensionIntermediateNodeVisitor<ComponentExtensionNode>.VisitExtension(ComponentExtensionNode node)
{
WriteContentNode(node, node.TagName, node.TypeName);
}
void IExtensionIntermediateNodeVisitor<ComponentAttributeExtensionNode>.VisitExtension(ComponentAttributeExtensionNode node)
@ -275,16 +279,6 @@ namespace Microsoft.AspNetCore.Razor.Language.IntegrationTests
WriteContentNode(node, node.AttributeName, node.PropertyName);
}
void IExtensionIntermediateNodeVisitor<ComponentBodyExtensionNode>.VisitExtension(ComponentBodyExtensionNode node)
{
WriteBasicNode(node);
}
void IExtensionIntermediateNodeVisitor<ComponentCloseExtensionNode>.VisitExtension(ComponentCloseExtensionNode node)
{
WriteBasicNode(node);
}
void IExtensionIntermediateNodeVisitor<RouteAttributeExtensionNode>.VisitExtension(RouteAttributeExtensionNode node)
{
WriteContentNode(node, node.Template);

View File

@ -1,7 +1,6 @@
// 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 Microsoft.CodeAnalysis.CSharp;
using Xunit;
namespace Microsoft.AspNetCore.Blazor.Build.Test

View File

@ -22,14 +22,11 @@ Document -
IntermediateToken - (29:0,29 [2] x:\dir\subdir\Test\TestComponent.cshtml) - Html - \n
HtmlContent - (65:1,34 [2] x:\dir\subdir\Test\TestComponent.cshtml)
IntermediateToken - (65:1,34 [2] x:\dir\subdir\Test\TestComponent.cshtml) - Html - \n
HtmlContent -
IntermediateToken - - Html - <input
HtmlAttribute - - =" - "
CSharpExpressionAttributeValue - -
IntermediateToken - - CSharp - Microsoft.AspNetCore.Blazor.Components.BindMethods.GetEventHandlerValue<Microsoft.AspNetCore.Blazor.UIMouseEventArgs>(
IntermediateToken - - CSharp - "async (e) => await Task.Delay(10)"
IntermediateToken - - CSharp - )
HtmlContent -
IntermediateToken - - Html - />
HtmlElement - (67:2,0 [53] x:\dir\subdir\Test\TestComponent.cshtml) - input
HtmlAttribute - (83:2,16 [33] x:\dir\subdir\Test\TestComponent.cshtml) - onclick=" - "
CSharpExpressionAttributeValue - -
IntermediateToken - - CSharp - Microsoft.AspNetCore.Blazor.Components.BindMethods.GetEventHandlerValue<Microsoft.AspNetCore.Blazor.UIMouseEventArgs>(
IntermediateToken - - CSharp - "async (e) => await Task.Delay(10)"
IntermediateToken - - CSharp - )
HtmlContent - (120:2,53 [2] x:\dir\subdir\Test\TestComponent.cshtml)
IntermediateToken - (120:2,53 [2] x:\dir\subdir\Test\TestComponent.cshtml) - Html - \n

View File

@ -22,15 +22,12 @@ Document -
IntermediateToken - (29:0,29 [2] x:\dir\subdir\Test\TestComponent.cshtml) - Html - \n
HtmlContent - (65:1,34 [2] x:\dir\subdir\Test\TestComponent.cshtml)
IntermediateToken - (65:1,34 [2] x:\dir\subdir\Test\TestComponent.cshtml) - Html - \n
HtmlContent -
IntermediateToken - - Html - <input
HtmlAttribute - - =" - "
CSharpExpressionAttributeValue - -
IntermediateToken - - CSharp - Microsoft.AspNetCore.Blazor.Components.BindMethods.GetEventHandlerValue<Microsoft.AspNetCore.Blazor.UIMouseEventArgs>(
IntermediateToken - (84:2,17 [7] x:\dir\subdir\Test\TestComponent.cshtml) - CSharp - OnClick
IntermediateToken - - CSharp - )
HtmlContent -
IntermediateToken - - Html - />
HtmlElement - (67:2,0 [28] x:\dir\subdir\Test\TestComponent.cshtml) - input
HtmlAttribute - (83:2,16 [8] x:\dir\subdir\Test\TestComponent.cshtml) - onclick=" - "
CSharpExpressionAttributeValue - -
IntermediateToken - - CSharp - Microsoft.AspNetCore.Blazor.Components.BindMethods.GetEventHandlerValue<Microsoft.AspNetCore.Blazor.UIMouseEventArgs>(
IntermediateToken - (84:2,17 [7] x:\dir\subdir\Test\TestComponent.cshtml) - CSharp - OnClick
IntermediateToken - - CSharp - )
HtmlContent - (95:2,28 [2] x:\dir\subdir\Test\TestComponent.cshtml)
IntermediateToken - (95:2,28 [2] x:\dir\subdir\Test\TestComponent.cshtml) - Html - \n
CSharpCode - (109:3,12 [91] x:\dir\subdir\Test\TestComponent.cshtml)

View File

@ -22,14 +22,11 @@ Document -
IntermediateToken - (29:0,29 [2] x:\dir\subdir\Test\TestComponent.cshtml) - Html - \n
HtmlContent - (65:1,34 [2] x:\dir\subdir\Test\TestComponent.cshtml)
IntermediateToken - (65:1,34 [2] x:\dir\subdir\Test\TestComponent.cshtml) - Html - \n
HtmlContent -
IntermediateToken - - Html - <input
HtmlAttribute - - =" - "
CSharpExpressionAttributeValue - -
IntermediateToken - - CSharp - Microsoft.AspNetCore.Blazor.Components.BindMethods.GetEventHandlerValue<Microsoft.AspNetCore.Blazor.UIMouseEventArgs>(
IntermediateToken - - CSharp - "async (e) => await Task.Delay(10)"
IntermediateToken - - CSharp - )
HtmlContent -
IntermediateToken - - Html - />
HtmlElement - (67:2,0 [53] x:\dir\subdir\Test\TestComponent.cshtml) - input
HtmlAttribute - (83:2,16 [33] x:\dir\subdir\Test\TestComponent.cshtml) - onclick=" - "
CSharpExpressionAttributeValue - -
IntermediateToken - - CSharp - Microsoft.AspNetCore.Blazor.Components.BindMethods.GetEventHandlerValue<Microsoft.AspNetCore.Blazor.UIMouseEventArgs>(
IntermediateToken - - CSharp - "async (e) => await Task.Delay(10)"
IntermediateToken - - CSharp - )
HtmlContent - (120:2,53 [2] x:\dir\subdir\Test\TestComponent.cshtml)
IntermediateToken - (120:2,53 [2] x:\dir\subdir\Test\TestComponent.cshtml) - Html - \n

View File

@ -22,15 +22,12 @@ Document -
IntermediateToken - (29:0,29 [2] x:\dir\subdir\Test\TestComponent.cshtml) - Html - \n
HtmlContent - (65:1,34 [2] x:\dir\subdir\Test\TestComponent.cshtml)
IntermediateToken - (65:1,34 [2] x:\dir\subdir\Test\TestComponent.cshtml) - Html - \n
HtmlContent -
IntermediateToken - - Html - <input
HtmlAttribute - - =" - "
CSharpExpressionAttributeValue - -
IntermediateToken - - CSharp - Microsoft.AspNetCore.Blazor.Components.BindMethods.GetEventHandlerValue<Microsoft.AspNetCore.Blazor.UIMouseEventArgs>(
IntermediateToken - (84:2,17 [7] x:\dir\subdir\Test\TestComponent.cshtml) - CSharp - OnClick
IntermediateToken - - CSharp - )
HtmlContent -
IntermediateToken - - Html - />
HtmlElement - (67:2,0 [28] x:\dir\subdir\Test\TestComponent.cshtml) - input
HtmlAttribute - (83:2,16 [8] x:\dir\subdir\Test\TestComponent.cshtml) - onclick=" - "
CSharpExpressionAttributeValue - -
IntermediateToken - - CSharp - Microsoft.AspNetCore.Blazor.Components.BindMethods.GetEventHandlerValue<Microsoft.AspNetCore.Blazor.UIMouseEventArgs>(
IntermediateToken - (84:2,17 [7] x:\dir\subdir\Test\TestComponent.cshtml) - CSharp - OnClick
IntermediateToken - - CSharp - )
HtmlContent - (95:2,28 [2] x:\dir\subdir\Test\TestComponent.cshtml)
IntermediateToken - (95:2,28 [2] x:\dir\subdir\Test\TestComponent.cshtml) - Html - \n
CSharpCode - (109:3,12 [73] x:\dir\subdir\Test\TestComponent.cshtml)

View File

@ -20,8 +20,7 @@ Document -
IntermediateToken - - CSharp - base.BuildRenderTree(builder);
HtmlContent - (29:0,29 [2] x:\dir\subdir\Test\TestComponent.cshtml)
IntermediateToken - (29:0,29 [2] x:\dir\subdir\Test\TestComponent.cshtml) - Html - \n
TagHelper - (31:1,0 [50] x:\dir\subdir\Test\TestComponent.cshtml) - MyComponent - TagMode.SelfClosing
ComponentOpenExtensionNode - - Test.MyComponent
ComponentExtensionNode - (31:1,0 [50] x:\dir\subdir\Test\TestComponent.cshtml) - MyComponent - Test.MyComponent
ComponentAttributeExtensionNode - (66:1,35 [11] x:\dir\subdir\Test\TestComponent.cshtml) - Value - Value
CSharpExpression -
IntermediateToken - - CSharp - Microsoft.AspNetCore.Blazor.Components.BindMethods.GetValue(
@ -30,8 +29,6 @@ Document -
ComponentAttributeExtensionNode - (66:1,35 [11] x:\dir\subdir\Test\TestComponent.cshtml) - OnChanged - OnChanged
CSharpExpression -
IntermediateToken - - CSharp - __value => ParentValue = __value
ComponentBodyExtensionNode -
ComponentCloseExtensionNode -
HtmlContent - (81:1,50 [2] x:\dir\subdir\Test\TestComponent.cshtml)
IntermediateToken - (81:1,50 [2] x:\dir\subdir\Test\TestComponent.cshtml) - Html - \n
CSharpCode - (95:2,12 [50] x:\dir\subdir\Test\TestComponent.cshtml)

View File

@ -20,8 +20,7 @@ Document -
IntermediateToken - - CSharp - base.BuildRenderTree(builder);
HtmlContent - (29:0,29 [2] x:\dir\subdir\Test\TestComponent.cshtml)
IntermediateToken - (29:0,29 [2] x:\dir\subdir\Test\TestComponent.cshtml) - Html - \n
TagHelper - (31:1,0 [50] x:\dir\subdir\Test\TestComponent.cshtml) - MyComponent - TagMode.SelfClosing
ComponentOpenExtensionNode - - Test.MyComponent
ComponentExtensionNode - (31:1,0 [50] x:\dir\subdir\Test\TestComponent.cshtml) - MyComponent - Test.MyComponent
ComponentAttributeExtensionNode - (66:1,35 [11] x:\dir\subdir\Test\TestComponent.cshtml) - Value -
CSharpExpression -
IntermediateToken - - CSharp - Microsoft.AspNetCore.Blazor.Components.BindMethods.GetValue(
@ -30,8 +29,6 @@ Document -
ComponentAttributeExtensionNode - (66:1,35 [11] x:\dir\subdir\Test\TestComponent.cshtml) - OnChanged -
CSharpExpression -
IntermediateToken - - CSharp - Microsoft.AspNetCore.Blazor.Components.BindMethods.SetValueHandler(__value => ParentValue = __value, ParentValue)
ComponentBodyExtensionNode -
ComponentCloseExtensionNode -
HtmlContent - (81:1,50 [2] x:\dir\subdir\Test\TestComponent.cshtml)
IntermediateToken - (81:1,50 [2] x:\dir\subdir\Test\TestComponent.cshtml) - Html - \n
CSharpCode - (95:2,12 [50] x:\dir\subdir\Test\TestComponent.cshtml)

View File

@ -20,8 +20,7 @@ Document -
IntermediateToken - - CSharp - base.BuildRenderTree(builder);
HtmlContent - (29:0,29 [2] x:\dir\subdir\Test\TestComponent.cshtml)
IntermediateToken - (29:0,29 [2] x:\dir\subdir\Test\TestComponent.cshtml) - Html - \n
TagHelper - (31:1,0 [40] x:\dir\subdir\Test\TestComponent.cshtml) - MyComponent - TagMode.SelfClosing
ComponentOpenExtensionNode - - Test.MyComponent
ComponentExtensionNode - (31:1,0 [40] x:\dir\subdir\Test\TestComponent.cshtml) - MyComponent - Test.MyComponent
ComponentAttributeExtensionNode - (56:1,25 [11] x:\dir\subdir\Test\TestComponent.cshtml) - Value - Value
CSharpExpression -
IntermediateToken - - CSharp - Microsoft.AspNetCore.Blazor.Components.BindMethods.GetValue(
@ -30,8 +29,6 @@ Document -
ComponentAttributeExtensionNode - (56:1,25 [11] x:\dir\subdir\Test\TestComponent.cshtml) - ValueChanged - ValueChanged
CSharpExpression -
IntermediateToken - - CSharp - __value => ParentValue = __value
ComponentBodyExtensionNode -
ComponentCloseExtensionNode -
HtmlContent - (71:1,40 [2] x:\dir\subdir\Test\TestComponent.cshtml)
IntermediateToken - (71:1,40 [2] x:\dir\subdir\Test\TestComponent.cshtml) - Html - \n
CSharpCode - (85:2,12 [50] x:\dir\subdir\Test\TestComponent.cshtml)

View File

@ -20,8 +20,7 @@ Document -
IntermediateToken - - CSharp - base.BuildRenderTree(builder);
HtmlContent - (29:0,29 [2] x:\dir\subdir\Test\TestComponent.cshtml)
IntermediateToken - (29:0,29 [2] x:\dir\subdir\Test\TestComponent.cshtml) - Html - \n
TagHelper - (31:1,0 [40] x:\dir\subdir\Test\TestComponent.cshtml) - MyComponent - TagMode.SelfClosing
ComponentOpenExtensionNode - - Test.MyComponent
ComponentExtensionNode - (31:1,0 [40] x:\dir\subdir\Test\TestComponent.cshtml) - MyComponent - Test.MyComponent
ComponentAttributeExtensionNode - (56:1,25 [11] x:\dir\subdir\Test\TestComponent.cshtml) - Value -
CSharpExpression -
IntermediateToken - - CSharp - Microsoft.AspNetCore.Blazor.Components.BindMethods.GetValue(
@ -30,8 +29,6 @@ Document -
ComponentAttributeExtensionNode - (56:1,25 [11] x:\dir\subdir\Test\TestComponent.cshtml) - ValueChanged -
CSharpExpression -
IntermediateToken - - CSharp - Microsoft.AspNetCore.Blazor.Components.BindMethods.SetValueHandler(__value => ParentValue = __value, ParentValue)
ComponentBodyExtensionNode -
ComponentCloseExtensionNode -
HtmlContent - (71:1,40 [2] x:\dir\subdir\Test\TestComponent.cshtml)
IntermediateToken - (71:1,40 [2] x:\dir\subdir\Test\TestComponent.cshtml) - Html - \n
CSharpCode - (85:2,12 [50] x:\dir\subdir\Test\TestComponent.cshtml)

View File

@ -20,24 +20,20 @@ Document -
IntermediateToken - - CSharp - base.BuildRenderTree(builder);
HtmlContent - (29:0,29 [2] x:\dir\subdir\Test\TestComponent.cshtml)
IntermediateToken - (29:0,29 [2] x:\dir\subdir\Test\TestComponent.cshtml) - Html - \n
HtmlContent -
IntermediateToken - - Html - <input
HtmlContent -
IntermediateToken - - Html - type="
IntermediateToken - (44:1,13 [4] x:\dir\subdir\Test\TestComponent.cshtml) - Html - text
IntermediateToken - - Html - "
HtmlAttribute - - =" - "
CSharpExpressionAttributeValue - -
IntermediateToken - - CSharp - Microsoft.AspNetCore.Blazor.Components.BindMethods.GetValue(
IntermediateToken - (72:1,41 [11] x:\dir\subdir\Test\TestComponent.cshtml) - CSharp - CurrentDate
IntermediateToken - - CSharp - ,
IntermediateToken - - CSharp - "MM/dd"
IntermediateToken - - CSharp - )
HtmlAttribute - - =" - "
CSharpExpressionAttributeValue - -
IntermediateToken - - CSharp - Microsoft.AspNetCore.Blazor.Components.BindMethods.SetValueHandler(__value => CurrentDate = __value, CurrentDate, "MM/dd")
HtmlContent -
IntermediateToken - - Html - />
HtmlElement - (31:1,0 [77] x:\dir\subdir\Test\TestComponent.cshtml) - input
HtmlAttribute - - type=" - "
HtmlAttributeValue - (44:1,13 [4] x:\dir\subdir\Test\TestComponent.cshtml) -
IntermediateToken - (44:1,13 [4] x:\dir\subdir\Test\TestComponent.cshtml) - Html - text
HtmlAttribute - (71:1,40 [12] x:\dir\subdir\Test\TestComponent.cshtml) - value=" - "
CSharpExpressionAttributeValue - -
IntermediateToken - - CSharp - Microsoft.AspNetCore.Blazor.Components.BindMethods.GetValue(
IntermediateToken - (72:1,41 [11] x:\dir\subdir\Test\TestComponent.cshtml) - CSharp - CurrentDate
IntermediateToken - - CSharp - ,
IntermediateToken - - CSharp - "MM/dd"
IntermediateToken - - CSharp - )
HtmlAttribute - (71:1,40 [12] x:\dir\subdir\Test\TestComponent.cshtml) - onchange=" - "
CSharpExpressionAttributeValue - -
IntermediateToken - - CSharp - Microsoft.AspNetCore.Blazor.Components.BindMethods.SetValueHandler(__value => CurrentDate = __value, CurrentDate, "MM/dd")
HtmlContent - (108:1,77 [2] x:\dir\subdir\Test\TestComponent.cshtml)
IntermediateToken - (108:1,77 [2] x:\dir\subdir\Test\TestComponent.cshtml) - Html - \n
CSharpCode - (122:2,12 [77] x:\dir\subdir\Test\TestComponent.cshtml)

View File

@ -20,22 +20,18 @@ Document -
IntermediateToken - - CSharp - base.BuildRenderTree(builder);
HtmlContent - (29:0,29 [2] x:\dir\subdir\Test\TestComponent.cshtml)
IntermediateToken - (29:0,29 [2] x:\dir\subdir\Test\TestComponent.cshtml) - Html - \n
HtmlContent -
IntermediateToken - - Html - <input
HtmlContent -
IntermediateToken - - Html - type="
IntermediateToken - (44:1,13 [4] x:\dir\subdir\Test\TestComponent.cshtml) - Html - text
IntermediateToken - - Html - "
HtmlAttribute - - =" - "
CSharpExpressionAttributeValue - -
IntermediateToken - - CSharp - Microsoft.AspNetCore.Blazor.Components.BindMethods.GetValue(
IntermediateToken - (72:1,41 [11] x:\dir\subdir\Test\TestComponent.cshtml) - CSharp - ParentValue
IntermediateToken - - CSharp - )
HtmlAttribute - - =" - "
CSharpExpressionAttributeValue - -
IntermediateToken - - CSharp - Microsoft.AspNetCore.Blazor.Components.BindMethods.SetValueHandler(__value => ParentValue = __value, ParentValue)
HtmlContent -
IntermediateToken - - Html - />
HtmlElement - (31:1,0 [56] x:\dir\subdir\Test\TestComponent.cshtml) - input
HtmlAttribute - - type=" - "
HtmlAttributeValue - (44:1,13 [4] x:\dir\subdir\Test\TestComponent.cshtml) -
IntermediateToken - (44:1,13 [4] x:\dir\subdir\Test\TestComponent.cshtml) - Html - text
HtmlAttribute - (71:1,40 [12] x:\dir\subdir\Test\TestComponent.cshtml) - value=" - "
CSharpExpressionAttributeValue - -
IntermediateToken - - CSharp - Microsoft.AspNetCore.Blazor.Components.BindMethods.GetValue(
IntermediateToken - (72:1,41 [11] x:\dir\subdir\Test\TestComponent.cshtml) - CSharp - ParentValue
IntermediateToken - - CSharp - )
HtmlAttribute - (71:1,40 [12] x:\dir\subdir\Test\TestComponent.cshtml) - onchange=" - "
CSharpExpressionAttributeValue - -
IntermediateToken - - CSharp - Microsoft.AspNetCore.Blazor.Components.BindMethods.SetValueHandler(__value => ParentValue = __value, ParentValue)
HtmlContent - (87:1,56 [2] x:\dir\subdir\Test\TestComponent.cshtml)
IntermediateToken - (87:1,56 [2] x:\dir\subdir\Test\TestComponent.cshtml) - Html - \n
CSharpCode - (101:2,12 [50] x:\dir\subdir\Test\TestComponent.cshtml)

View File

@ -20,18 +20,15 @@ Document -
IntermediateToken - - CSharp - base.BuildRenderTree(builder);
HtmlContent - (29:0,29 [2] x:\dir\subdir\Test\TestComponent.cshtml)
IntermediateToken - (29:0,29 [2] x:\dir\subdir\Test\TestComponent.cshtml) - Html - \n
HtmlContent -
IntermediateToken - - Html - <div
HtmlAttribute - - =" - "
CSharpExpressionAttributeValue - -
IntermediateToken - - CSharp - Microsoft.AspNetCore.Blazor.Components.BindMethods.GetValue(
IntermediateToken - (49:1,18 [11] x:\dir\subdir\Test\TestComponent.cshtml) - CSharp - ParentValue
IntermediateToken - - CSharp - )
HtmlAttribute - - =" - "
CSharpExpressionAttributeValue - -
IntermediateToken - - CSharp - Microsoft.AspNetCore.Blazor.Components.BindMethods.SetValueHandler(__value => ParentValue = __value, ParentValue)
HtmlContent -
IntermediateToken - - Html - />
HtmlElement - (31:1,0 [33] x:\dir\subdir\Test\TestComponent.cshtml) - div
HtmlAttribute - (48:1,17 [12] x:\dir\subdir\Test\TestComponent.cshtml) - myvalue=" - "
CSharpExpressionAttributeValue - -
IntermediateToken - - CSharp - Microsoft.AspNetCore.Blazor.Components.BindMethods.GetValue(
IntermediateToken - (49:1,18 [11] x:\dir\subdir\Test\TestComponent.cshtml) - CSharp - ParentValue
IntermediateToken - - CSharp - )
HtmlAttribute - (48:1,17 [12] x:\dir\subdir\Test\TestComponent.cshtml) - myevent=" - "
CSharpExpressionAttributeValue - -
IntermediateToken - - CSharp - Microsoft.AspNetCore.Blazor.Components.BindMethods.SetValueHandler(__value => ParentValue = __value, ParentValue)
HtmlContent - (64:1,33 [2] x:\dir\subdir\Test\TestComponent.cshtml)
IntermediateToken - (64:1,33 [2] x:\dir\subdir\Test\TestComponent.cshtml) - Html - \n
CSharpCode - (78:2,12 [55] x:\dir\subdir\Test\TestComponent.cshtml)

View File

@ -20,18 +20,15 @@ Document -
IntermediateToken - - CSharp - base.BuildRenderTree(builder);
HtmlContent - (29:0,29 [2] x:\dir\subdir\Test\TestComponent.cshtml)
IntermediateToken - (29:0,29 [2] x:\dir\subdir\Test\TestComponent.cshtml) - Html - \n
HtmlContent -
IntermediateToken - - Html - <div
HtmlAttribute - - =" - "
CSharpExpressionAttributeValue - -
IntermediateToken - - CSharp - Microsoft.AspNetCore.Blazor.Components.BindMethods.GetValue(
IntermediateToken - (43:1,12 [11] x:\dir\subdir\Test\TestComponent.cshtml) - CSharp - ParentValue
IntermediateToken - - CSharp - )
HtmlAttribute - - =" - "
CSharpExpressionAttributeValue - -
IntermediateToken - - CSharp - Microsoft.AspNetCore.Blazor.Components.BindMethods.SetValueHandler(__value => ParentValue = __value, ParentValue)
HtmlContent -
IntermediateToken - - Html - />
HtmlElement - (31:1,0 [27] x:\dir\subdir\Test\TestComponent.cshtml) - div
HtmlAttribute - (42:1,11 [12] x:\dir\subdir\Test\TestComponent.cshtml) - myvalue=" - "
CSharpExpressionAttributeValue - -
IntermediateToken - - CSharp - Microsoft.AspNetCore.Blazor.Components.BindMethods.GetValue(
IntermediateToken - (43:1,12 [11] x:\dir\subdir\Test\TestComponent.cshtml) - CSharp - ParentValue
IntermediateToken - - CSharp - )
HtmlAttribute - (42:1,11 [12] x:\dir\subdir\Test\TestComponent.cshtml) - myevent=" - "
CSharpExpressionAttributeValue - -
IntermediateToken - - CSharp - Microsoft.AspNetCore.Blazor.Components.BindMethods.SetValueHandler(__value => ParentValue = __value, ParentValue)
HtmlContent - (58:1,27 [2] x:\dir\subdir\Test\TestComponent.cshtml)
IntermediateToken - (58:1,27 [2] x:\dir\subdir\Test\TestComponent.cshtml) - Html - \n
CSharpCode - (72:2,12 [55] x:\dir\subdir\Test\TestComponent.cshtml)

View File

@ -20,22 +20,18 @@ Document -
IntermediateToken - - CSharp - base.BuildRenderTree(builder);
HtmlContent - (29:0,29 [2] x:\dir\subdir\Test\TestComponent.cshtml)
IntermediateToken - (29:0,29 [2] x:\dir\subdir\Test\TestComponent.cshtml) - Html - \n
HtmlContent -
IntermediateToken - - Html - <input
HtmlContent -
IntermediateToken - - Html - type="
IntermediateToken - (44:1,13 [8] x:\dir\subdir\Test\TestComponent.cshtml) - Html - checkbox
IntermediateToken - - Html - "
HtmlAttribute - - =" - "
CSharpExpressionAttributeValue - -
IntermediateToken - - CSharp - Microsoft.AspNetCore.Blazor.Components.BindMethods.GetValue(
IntermediateToken - (61:1,30 [7] x:\dir\subdir\Test\TestComponent.cshtml) - CSharp - Enabled
IntermediateToken - - CSharp - )
HtmlAttribute - - =" - "
CSharpExpressionAttributeValue - -
IntermediateToken - - CSharp - Microsoft.AspNetCore.Blazor.Components.BindMethods.SetValueHandler(__value => Enabled = __value, Enabled)
HtmlContent -
IntermediateToken - - Html - />
HtmlElement - (31:1,0 [41] x:\dir\subdir\Test\TestComponent.cshtml) - input
HtmlAttribute - - type=" - "
HtmlAttributeValue - (44:1,13 [8] x:\dir\subdir\Test\TestComponent.cshtml) -
IntermediateToken - (44:1,13 [8] x:\dir\subdir\Test\TestComponent.cshtml) - Html - checkbox
HtmlAttribute - (60:1,29 [8] x:\dir\subdir\Test\TestComponent.cshtml) - checked=" - "
CSharpExpressionAttributeValue - -
IntermediateToken - - CSharp - Microsoft.AspNetCore.Blazor.Components.BindMethods.GetValue(
IntermediateToken - (61:1,30 [7] x:\dir\subdir\Test\TestComponent.cshtml) - CSharp - Enabled
IntermediateToken - - CSharp - )
HtmlAttribute - (60:1,29 [8] x:\dir\subdir\Test\TestComponent.cshtml) - onchange=" - "
CSharpExpressionAttributeValue - -
IntermediateToken - - CSharp - Microsoft.AspNetCore.Blazor.Components.BindMethods.SetValueHandler(__value => Enabled = __value, Enabled)
HtmlContent - (72:1,41 [2] x:\dir\subdir\Test\TestComponent.cshtml)
IntermediateToken - (72:1,41 [2] x:\dir\subdir\Test\TestComponent.cshtml) - Html - \n
CSharpCode - (86:2,12 [41] x:\dir\subdir\Test\TestComponent.cshtml)

View File

@ -20,24 +20,20 @@ Document -
IntermediateToken - - CSharp - base.BuildRenderTree(builder);
HtmlContent - (29:0,29 [2] x:\dir\subdir\Test\TestComponent.cshtml)
IntermediateToken - (29:0,29 [2] x:\dir\subdir\Test\TestComponent.cshtml) - Html - \n
HtmlContent -
IntermediateToken - - Html - <input
HtmlContent -
IntermediateToken - - Html - type="
IntermediateToken - (44:1,13 [4] x:\dir\subdir\Test\TestComponent.cshtml) - Html - text
IntermediateToken - - Html - "
HtmlAttribute - - =" - "
CSharpExpressionAttributeValue - -
IntermediateToken - - CSharp - Microsoft.AspNetCore.Blazor.Components.BindMethods.GetValue(
IntermediateToken - (57:1,26 [11] x:\dir\subdir\Test\TestComponent.cshtml) - CSharp - CurrentDate
IntermediateToken - - CSharp - ,
IntermediateToken - (85:1,54 [6] x:\dir\subdir\Test\TestComponent.cshtml) - CSharp - Format
IntermediateToken - - CSharp - )
HtmlAttribute - - =" - "
CSharpExpressionAttributeValue - -
IntermediateToken - - CSharp - Microsoft.AspNetCore.Blazor.Components.BindMethods.SetValueHandler(__value => CurrentDate = __value, CurrentDate, Format)
HtmlContent -
IntermediateToken - - Html - />
HtmlElement - (31:1,0 [63] x:\dir\subdir\Test\TestComponent.cshtml) - input
HtmlAttribute - - type=" - "
HtmlAttributeValue - (44:1,13 [4] x:\dir\subdir\Test\TestComponent.cshtml) -
IntermediateToken - (44:1,13 [4] x:\dir\subdir\Test\TestComponent.cshtml) - Html - text
HtmlAttribute - (56:1,25 [12] x:\dir\subdir\Test\TestComponent.cshtml) - value=" - "
CSharpExpressionAttributeValue - -
IntermediateToken - - CSharp - Microsoft.AspNetCore.Blazor.Components.BindMethods.GetValue(
IntermediateToken - (57:1,26 [11] x:\dir\subdir\Test\TestComponent.cshtml) - CSharp - CurrentDate
IntermediateToken - - CSharp - ,
IntermediateToken - (85:1,54 [6] x:\dir\subdir\Test\TestComponent.cshtml) - CSharp - Format
IntermediateToken - - CSharp - )
HtmlAttribute - (56:1,25 [12] x:\dir\subdir\Test\TestComponent.cshtml) - onchange=" - "
CSharpExpressionAttributeValue - -
IntermediateToken - - CSharp - Microsoft.AspNetCore.Blazor.Components.BindMethods.SetValueHandler(__value => CurrentDate = __value, CurrentDate, Format)
HtmlContent - (94:1,63 [2] x:\dir\subdir\Test\TestComponent.cshtml)
IntermediateToken - (94:1,63 [2] x:\dir\subdir\Test\TestComponent.cshtml) - Html - \n
CSharpCode - (108:2,12 [135] x:\dir\subdir\Test\TestComponent.cshtml)

View File

@ -20,24 +20,20 @@ Document -
IntermediateToken - - CSharp - base.BuildRenderTree(builder);
HtmlContent - (29:0,29 [2] x:\dir\subdir\Test\TestComponent.cshtml)
IntermediateToken - (29:0,29 [2] x:\dir\subdir\Test\TestComponent.cshtml) - Html - \n
HtmlContent -
IntermediateToken - - Html - <input
HtmlContent -
IntermediateToken - - Html - type="
IntermediateToken - (44:1,13 [4] x:\dir\subdir\Test\TestComponent.cshtml) - Html - text
IntermediateToken - - Html - "
HtmlAttribute - - =" - "
CSharpExpressionAttributeValue - -
IntermediateToken - - CSharp - Microsoft.AspNetCore.Blazor.Components.BindMethods.GetValue(
IntermediateToken - (57:1,26 [11] x:\dir\subdir\Test\TestComponent.cshtml) - CSharp - CurrentDate
IntermediateToken - - CSharp - ,
IntermediateToken - - CSharp - "MM/dd/yyyy"
IntermediateToken - - CSharp - )
HtmlAttribute - - =" - "
CSharpExpressionAttributeValue - -
IntermediateToken - - CSharp - Microsoft.AspNetCore.Blazor.Components.BindMethods.SetValueHandler(__value => CurrentDate = __value, CurrentDate, "MM/dd/yyyy")
HtmlContent -
IntermediateToken - - Html - />
HtmlElement - (31:1,0 [66] x:\dir\subdir\Test\TestComponent.cshtml) - input
HtmlAttribute - - type=" - "
HtmlAttributeValue - (44:1,13 [4] x:\dir\subdir\Test\TestComponent.cshtml) -
IntermediateToken - (44:1,13 [4] x:\dir\subdir\Test\TestComponent.cshtml) - Html - text
HtmlAttribute - (56:1,25 [12] x:\dir\subdir\Test\TestComponent.cshtml) - value=" - "
CSharpExpressionAttributeValue - -
IntermediateToken - - CSharp - Microsoft.AspNetCore.Blazor.Components.BindMethods.GetValue(
IntermediateToken - (57:1,26 [11] x:\dir\subdir\Test\TestComponent.cshtml) - CSharp - CurrentDate
IntermediateToken - - CSharp - ,
IntermediateToken - - CSharp - "MM/dd/yyyy"
IntermediateToken - - CSharp - )
HtmlAttribute - (56:1,25 [12] x:\dir\subdir\Test\TestComponent.cshtml) - onchange=" - "
CSharpExpressionAttributeValue - -
IntermediateToken - - CSharp - Microsoft.AspNetCore.Blazor.Components.BindMethods.SetValueHandler(__value => CurrentDate = __value, CurrentDate, "MM/dd/yyyy")
HtmlContent - (97:1,66 [2] x:\dir\subdir\Test\TestComponent.cshtml)
IntermediateToken - (97:1,66 [2] x:\dir\subdir\Test\TestComponent.cshtml) - Html - \n
CSharpCode - (111:2,12 [77] x:\dir\subdir\Test\TestComponent.cshtml)

View File

@ -20,22 +20,18 @@ Document -
IntermediateToken - - CSharp - base.BuildRenderTree(builder);
HtmlContent - (29:0,29 [2] x:\dir\subdir\Test\TestComponent.cshtml)
IntermediateToken - (29:0,29 [2] x:\dir\subdir\Test\TestComponent.cshtml) - Html - \n
HtmlContent -
IntermediateToken - - Html - <input
HtmlContent -
IntermediateToken - - Html - type="
IntermediateToken - (44:1,13 [4] x:\dir\subdir\Test\TestComponent.cshtml) - Html - text
IntermediateToken - - Html - "
HtmlAttribute - - =" - "
CSharpExpressionAttributeValue - -
IntermediateToken - - CSharp - Microsoft.AspNetCore.Blazor.Components.BindMethods.GetValue(
IntermediateToken - (57:1,26 [11] x:\dir\subdir\Test\TestComponent.cshtml) - CSharp - ParentValue
IntermediateToken - - CSharp - )
HtmlAttribute - - =" - "
CSharpExpressionAttributeValue - -
IntermediateToken - - CSharp - Microsoft.AspNetCore.Blazor.Components.BindMethods.SetValueHandler(__value => ParentValue = __value, ParentValue)
HtmlContent -
IntermediateToken - - Html - />
HtmlElement - (31:1,0 [41] x:\dir\subdir\Test\TestComponent.cshtml) - input
HtmlAttribute - - type=" - "
HtmlAttributeValue - (44:1,13 [4] x:\dir\subdir\Test\TestComponent.cshtml) -
IntermediateToken - (44:1,13 [4] x:\dir\subdir\Test\TestComponent.cshtml) - Html - text
HtmlAttribute - (56:1,25 [12] x:\dir\subdir\Test\TestComponent.cshtml) - value=" - "
CSharpExpressionAttributeValue - -
IntermediateToken - - CSharp - Microsoft.AspNetCore.Blazor.Components.BindMethods.GetValue(
IntermediateToken - (57:1,26 [11] x:\dir\subdir\Test\TestComponent.cshtml) - CSharp - ParentValue
IntermediateToken - - CSharp - )
HtmlAttribute - (56:1,25 [12] x:\dir\subdir\Test\TestComponent.cshtml) - onchange=" - "
CSharpExpressionAttributeValue - -
IntermediateToken - - CSharp - Microsoft.AspNetCore.Blazor.Components.BindMethods.SetValueHandler(__value => ParentValue = __value, ParentValue)
HtmlContent - (72:1,41 [2] x:\dir\subdir\Test\TestComponent.cshtml)
IntermediateToken - (72:1,41 [2] x:\dir\subdir\Test\TestComponent.cshtml) - Html - \n
CSharpCode - (86:2,12 [50] x:\dir\subdir\Test\TestComponent.cshtml)

View File

@ -20,18 +20,15 @@ Document -
IntermediateToken - - CSharp - base.BuildRenderTree(builder);
HtmlContent - (29:0,29 [2] x:\dir\subdir\Test\TestComponent.cshtml)
IntermediateToken - (29:0,29 [2] x:\dir\subdir\Test\TestComponent.cshtml) - Html - \n
HtmlContent -
IntermediateToken - - Html - <input
HtmlAttribute - - =" - "
CSharpExpressionAttributeValue - -
IntermediateToken - - CSharp - Microsoft.AspNetCore.Blazor.Components.BindMethods.GetValue(
IntermediateToken - (45:1,14 [11] x:\dir\subdir\Test\TestComponent.cshtml) - CSharp - ParentValue
IntermediateToken - - CSharp - )
HtmlAttribute - - =" - "
CSharpExpressionAttributeValue - -
IntermediateToken - - CSharp - Microsoft.AspNetCore.Blazor.Components.BindMethods.SetValueHandler(__value => ParentValue = __value, ParentValue)
HtmlContent -
IntermediateToken - - Html - />
HtmlElement - (31:1,0 [29] x:\dir\subdir\Test\TestComponent.cshtml) - input
HtmlAttribute - (44:1,13 [12] x:\dir\subdir\Test\TestComponent.cshtml) - value=" - "
CSharpExpressionAttributeValue - -
IntermediateToken - - CSharp - Microsoft.AspNetCore.Blazor.Components.BindMethods.GetValue(
IntermediateToken - (45:1,14 [11] x:\dir\subdir\Test\TestComponent.cshtml) - CSharp - ParentValue
IntermediateToken - - CSharp - )
HtmlAttribute - (44:1,13 [12] x:\dir\subdir\Test\TestComponent.cshtml) - onchange=" - "
CSharpExpressionAttributeValue - -
IntermediateToken - - CSharp - Microsoft.AspNetCore.Blazor.Components.BindMethods.SetValueHandler(__value => ParentValue = __value, ParentValue)
HtmlContent - (60:1,29 [2] x:\dir\subdir\Test\TestComponent.cshtml)
IntermediateToken - (60:1,29 [2] x:\dir\subdir\Test\TestComponent.cshtml) - Html - \n
CSharpCode - (74:2,12 [50] x:\dir\subdir\Test\TestComponent.cshtml)

View File

@ -20,17 +20,15 @@ Document -
IntermediateToken - - CSharp - base.BuildRenderTree(builder);
HtmlContent - (29:0,29 [2] x:\dir\subdir\Test\TestComponent.cshtml)
IntermediateToken - (29:0,29 [2] x:\dir\subdir\Test\TestComponent.cshtml) - Html - \n
TagHelper - (31:1,0 [91] x:\dir\subdir\Test\TestComponent.cshtml) - MyComponent - TagMode.StartTagAndEndTag
ComponentOpenExtensionNode - - Test.MyComponent
ComponentExtensionNode - (31:1,0 [91] x:\dir\subdir\Test\TestComponent.cshtml) - MyComponent - Test.MyComponent
HtmlContent - (57:1,26 [9] x:\dir\subdir\Test\TestComponent.cshtml)
IntermediateToken - (57:1,26 [9] x:\dir\subdir\Test\TestComponent.cshtml) - Html - Some text
HtmlElement - (66:1,35 [42] x:\dir\subdir\Test\TestComponent.cshtml) - some-child
HtmlAttribute - - -
HtmlAttributeValue - -
IntermediateToken - - Html - 1
HtmlContent - (84:1,53 [11] x:\dir\subdir\Test\TestComponent.cshtml)
IntermediateToken - (84:1,53 [11] x:\dir\subdir\Test\TestComponent.cshtml) - Html - Nested text
ComponentAttributeExtensionNode - (52:1,21 [3] x:\dir\subdir\Test\TestComponent.cshtml) - MyAttr - MyAttr
HtmlContent - (52:1,21 [3] x:\dir\subdir\Test\TestComponent.cshtml)
IntermediateToken - (52:1,21 [3] x:\dir\subdir\Test\TestComponent.cshtml) - Html - abc
ComponentBodyExtensionNode -
HtmlContent - (57:1,26 [51] x:\dir\subdir\Test\TestComponent.cshtml)
IntermediateToken - (57:1,26 [9] x:\dir\subdir\Test\TestComponent.cshtml) - Html - Some text
IntermediateToken - (66:1,35 [11] x:\dir\subdir\Test\TestComponent.cshtml) - Html - <some-child
IntermediateToken - (77:1,46 [6] x:\dir\subdir\Test\TestComponent.cshtml) - Html - a='1'
IntermediateToken - (83:1,52 [1] x:\dir\subdir\Test\TestComponent.cshtml) - Html - >
IntermediateToken - (84:1,53 [11] x:\dir\subdir\Test\TestComponent.cshtml) - Html - Nested text
IntermediateToken - (95:1,64 [13] x:\dir\subdir\Test\TestComponent.cshtml) - Html - </some-child>
ComponentCloseExtensionNode -

View File

@ -23,13 +23,10 @@ Document -
IntermediateToken - (29:0,29 [2] x:\dir\subdir\Test\TestComponent.cshtml) - Html - \n
HtmlContent - (65:1,34 [2] x:\dir\subdir\Test\TestComponent.cshtml)
IntermediateToken - (65:1,34 [2] x:\dir\subdir\Test\TestComponent.cshtml) - Html - \n
TagHelper - (67:2,0 [35] x:\dir\subdir\Test\TestComponent.cshtml) - MyComponent - TagMode.SelfClosing
ComponentOpenExtensionNode - - Test.MyComponent
ComponentExtensionNode - (67:2,0 [35] x:\dir\subdir\Test\TestComponent.cshtml) - MyComponent - Test.MyComponent
ComponentAttributeExtensionNode - (89:2,22 [10] x:\dir\subdir\Test\TestComponent.cshtml) - OnClick - OnClick
CSharpExpression - (90:2,23 [9] x:\dir\subdir\Test\TestComponent.cshtml)
IntermediateToken - (90:2,23 [9] x:\dir\subdir\Test\TestComponent.cshtml) - CSharp - Increment
ComponentBodyExtensionNode -
ComponentCloseExtensionNode -
HtmlContent - (102:2,35 [4] x:\dir\subdir\Test\TestComponent.cshtml)
IntermediateToken - (102:2,35 [4] x:\dir\subdir\Test\TestComponent.cshtml) - Html - \n\n
CSharpCode - (118:4,12 [100] x:\dir\subdir\Test\TestComponent.cshtml)

View File

@ -20,10 +20,7 @@ Document -
IntermediateToken - - CSharp - base.BuildRenderTree(builder);
HtmlContent - (29:0,29 [2] x:\dir\subdir\Test\TestComponent.cshtml)
IntermediateToken - (29:0,29 [2] x:\dir\subdir\Test\TestComponent.cshtml) - Html - \n
TagHelper - (31:1,0 [49] x:\dir\subdir\Test\TestComponent.cshtml) - MyComponent - TagMode.SelfClosing
ComponentOpenExtensionNode - - Test.MyComponent
ComponentExtensionNode - (31:1,0 [49] x:\dir\subdir\Test\TestComponent.cshtml) - MyComponent - Test.MyComponent
ComponentAttributeExtensionNode - (60:1,29 [16] x:\dir\subdir\Test\TestComponent.cshtml) - StringProperty - StringProperty
CSharpExpression - (62:1,31 [13] x:\dir\subdir\Test\TestComponent.cshtml)
IntermediateToken - (62:1,31 [13] x:\dir\subdir\Test\TestComponent.cshtml) - CSharp - 42.ToString()
ComponentBodyExtensionNode -
ComponentCloseExtensionNode -

View File

@ -20,13 +20,10 @@ Document -
IntermediateToken - - CSharp - base.BuildRenderTree(builder);
HtmlContent - (29:0,29 [2] x:\dir\subdir\Test\TestComponent.cshtml)
IntermediateToken - (29:0,29 [2] x:\dir\subdir\Test\TestComponent.cshtml) - Html - \n
TagHelper - (31:1,0 [51] x:\dir\subdir\Test\TestComponent.cshtml) - MyComponent - TagMode.SelfClosing
ComponentOpenExtensionNode - - Test.MyComponent
ComponentExtensionNode - (31:1,0 [51] x:\dir\subdir\Test\TestComponent.cshtml) - MyComponent - Test.MyComponent
ComponentAttributeExtensionNode - (53:1,22 [26] x:\dir\subdir\Test\TestComponent.cshtml) - OnClick - OnClick
CSharpExpression - (54:1,23 [25] x:\dir\subdir\Test\TestComponent.cshtml)
IntermediateToken - (55:1,24 [23] x:\dir\subdir\Test\TestComponent.cshtml) - CSharp - (e) => { Increment(); }
ComponentBodyExtensionNode -
ComponentCloseExtensionNode -
HtmlContent - (82:1,51 [4] x:\dir\subdir\Test\TestComponent.cshtml)
IntermediateToken - (82:1,51 [4] x:\dir\subdir\Test\TestComponent.cshtml) - Html - \n\n
CSharpCode - (98:3,12 [87] x:\dir\subdir\Test\TestComponent.cshtml)

View File

@ -20,13 +20,10 @@ Document -
IntermediateToken - - CSharp - base.BuildRenderTree(builder);
HtmlContent - (29:0,29 [2] x:\dir\subdir\Test\TestComponent.cshtml)
IntermediateToken - (29:0,29 [2] x:\dir\subdir\Test\TestComponent.cshtml) - Html - \n
TagHelper - (31:1,0 [72] x:\dir\subdir\Test\TestComponent.cshtml) - MyComponent - TagMode.SelfClosing
ComponentOpenExtensionNode - - Test.MyComponent
ComponentExtensionNode - (31:1,0 [72] x:\dir\subdir\Test\TestComponent.cshtml) - MyComponent - Test.MyComponent
ComponentAttributeExtensionNode - - some-attribute -
HtmlContent - (60:1,29 [3] x:\dir\subdir\Test\TestComponent.cshtml)
IntermediateToken - (60:1,29 [3] x:\dir\subdir\Test\TestComponent.cshtml) - Html - foo
ComponentAttributeExtensionNode - - another-attribute -
CSharpExpression - (84:1,53 [16] x:\dir\subdir\Test\TestComponent.cshtml)
IntermediateToken - (86:1,55 [13] x:\dir\subdir\Test\TestComponent.cshtml) - CSharp - 43.ToString()
ComponentBodyExtensionNode -
ComponentCloseExtensionNode -

View File

@ -20,8 +20,7 @@ Document -
IntermediateToken - - CSharp - base.BuildRenderTree(builder);
HtmlContent - (29:0,29 [2] x:\dir\subdir\Test\TestComponent.cshtml)
IntermediateToken - (29:0,29 [2] x:\dir\subdir\Test\TestComponent.cshtml) - Html - \n
TagHelper - (31:1,0 [132] x:\dir\subdir\Test\TestComponent.cshtml) - MyComponent - TagMode.SelfClosing
ComponentOpenExtensionNode - - Test.MyComponent
ComponentExtensionNode - (31:1,0 [132] x:\dir\subdir\Test\TestComponent.cshtml) - MyComponent - Test.MyComponent
ComponentAttributeExtensionNode - (63:2,17 [3] x:\dir\subdir\Test\TestComponent.cshtml) - IntProperty - IntProperty
IntermediateToken - (63:2,17 [3] x:\dir\subdir\Test\TestComponent.cshtml) - CSharp - 123
ComponentAttributeExtensionNode - (87:3,18 [4] x:\dir\subdir\Test\TestComponent.cshtml) - BoolProperty - BoolProperty
@ -31,5 +30,3 @@ Document -
IntermediateToken - (114:4,20 [9] x:\dir\subdir\Test\TestComponent.cshtml) - Html - My string
ComponentAttributeExtensionNode - (146:5,20 [14] x:\dir\subdir\Test\TestComponent.cshtml) - ObjectProperty - ObjectProperty
IntermediateToken - (146:5,20 [14] x:\dir\subdir\Test\TestComponent.cshtml) - CSharp - new SomeType()
ComponentBodyExtensionNode -
ComponentCloseExtensionNode -

View File

@ -20,17 +20,14 @@ Document -
IntermediateToken - - CSharp - base.BuildRenderTree(builder);
HtmlContent - (29:0,29 [2] x:\dir\subdir\Test\TestComponent.cshtml)
IntermediateToken - (29:0,29 [2] x:\dir\subdir\Test\TestComponent.cshtml) - Html - \n
TagHelper - (31:1,0 [72] x:\dir\subdir\Test\TestComponent.cshtml) - MyComponent - TagMode.SelfClosing
ComponentOpenExtensionNode - - Test.MyComponent
ComponentExtensionNode - (31:1,0 [72] x:\dir\subdir\Test\TestComponent.cshtml) - MyComponent - Test.MyComponent
ComponentAttributeExtensionNode - - ParamBefore -
HtmlContent - (57:1,26 [6] x:\dir\subdir\Test\TestComponent.cshtml)
IntermediateToken - (57:1,26 [6] x:\dir\subdir\Test\TestComponent.cshtml) - Html - before
RefExtensionNode - (70:1,39 [10] x:\dir\subdir\Test\TestComponent.cshtml) - myInstance - Test.MyComponent
ComponentAttributeExtensionNode - - ParamAfter -
HtmlContent - (94:1,63 [5] x:\dir\subdir\Test\TestComponent.cshtml)
IntermediateToken - (94:1,63 [5] x:\dir\subdir\Test\TestComponent.cshtml) - Html - after
ComponentBodyExtensionNode -
RefExtensionNode - (70:1,39 [10] x:\dir\subdir\Test\TestComponent.cshtml) - myInstance - Test.MyComponent
ComponentCloseExtensionNode -
HtmlContent - (103:1,72 [4] x:\dir\subdir\Test\TestComponent.cshtml)
IntermediateToken - (103:1,72 [4] x:\dir\subdir\Test\TestComponent.cshtml) - Html - \n\n
HtmlContent - (253:7,1 [2] x:\dir\subdir\Test\TestComponent.cshtml)

View File

@ -17,23 +17,16 @@ Document -
MethodDeclaration - - protected override - void - BuildRenderTree
CSharpCode -
IntermediateToken - - CSharp - base.BuildRenderTree(builder);
HtmlContent -
IntermediateToken - - Html - <elem
HtmlContent -
IntermediateToken - - Html - attributebefore="
IntermediateToken - (23:0,23 [6] x:\dir\subdir\Test\TestComponent.cshtml) - Html - before
IntermediateToken - - Html - "
HtmlContent -
IntermediateToken - - Html - attributeafter="
IntermediateToken - (60:0,60 [5] x:\dir\subdir\Test\TestComponent.cshtml) - Html - after
IntermediateToken - - Html - "
RefExtensionNode - (36:0,36 [6] x:\dir\subdir\Test\TestComponent.cshtml) - myElem - Element
HtmlContent -
IntermediateToken - - Html - >
HtmlContent - (67:0,67 [5] x:\dir\subdir\Test\TestComponent.cshtml)
IntermediateToken - (67:0,67 [5] x:\dir\subdir\Test\TestComponent.cshtml) - Html - Hello
HtmlContent -
IntermediateToken - - Html - </elem>
HtmlElement - (0:0,0 [79] x:\dir\subdir\Test\TestComponent.cshtml) - elem
HtmlContent - (67:0,67 [5] x:\dir\subdir\Test\TestComponent.cshtml)
IntermediateToken - (67:0,67 [5] x:\dir\subdir\Test\TestComponent.cshtml) - Html - Hello
HtmlAttribute - - attributebefore=" - "
HtmlAttributeValue - (23:0,23 [6] x:\dir\subdir\Test\TestComponent.cshtml) -
IntermediateToken - (23:0,23 [6] x:\dir\subdir\Test\TestComponent.cshtml) - Html - before
RefExtensionNode - (36:0,36 [6] x:\dir\subdir\Test\TestComponent.cshtml) - myElem - Element
HtmlAttribute - - attributeafter=" - "
HtmlAttributeValue - (60:0,60 [5] x:\dir\subdir\Test\TestComponent.cshtml) -
IntermediateToken - (60:0,60 [5] x:\dir\subdir\Test\TestComponent.cshtml) - Html - after
HtmlContent - (79:0,79 [4] x:\dir\subdir\Test\TestComponent.cshtml)
IntermediateToken - (79:0,79 [4] x:\dir\subdir\Test\TestComponent.cshtml) - Html - \n\n
HtmlContent - (243:6,1 [2] x:\dir\subdir\Test\TestComponent.cshtml)

View File

@ -20,15 +20,12 @@ Document -
IntermediateToken - - CSharp - base.BuildRenderTree(builder);
HtmlContent - (34:0,34 [2] x:\dir\subdir\Test\TestComponent.cshtml)
IntermediateToken - (34:0,34 [2] x:\dir\subdir\Test\TestComponent.cshtml) - Html - \n
HtmlContent -
IntermediateToken - - Html - <input
HtmlAttribute - - =" - "
CSharpExpressionAttributeValue - -
IntermediateToken - - CSharp - Microsoft.AspNetCore.Blazor.Components.BindMethods.GetEventHandlerValue<Microsoft.AspNetCore.Blazor.UIMouseEventArgs>(
IntermediateToken - (53:1,17 [7] x:\dir\subdir\Test\TestComponent.cshtml) - CSharp - OnClick
IntermediateToken - - CSharp - )
HtmlContent -
IntermediateToken - - Html - />
HtmlElement - (36:1,0 [28] x:\dir\subdir\Test\TestComponent.cshtml) - input
HtmlAttribute - (52:1,16 [8] x:\dir\subdir\Test\TestComponent.cshtml) - onclick=" - "
CSharpExpressionAttributeValue - -
IntermediateToken - - CSharp - Microsoft.AspNetCore.Blazor.Components.BindMethods.GetEventHandlerValue<Microsoft.AspNetCore.Blazor.UIMouseEventArgs>(
IntermediateToken - (53:1,17 [7] x:\dir\subdir\Test\TestComponent.cshtml) - CSharp - OnClick
IntermediateToken - - CSharp - )
HtmlContent - (64:1,28 [2] x:\dir\subdir\Test\TestComponent.cshtml)
IntermediateToken - (64:1,28 [2] x:\dir\subdir\Test\TestComponent.cshtml) - Html - \n
CSharpCode - (78:2,12 [49] x:\dir\subdir\Test\TestComponent.cshtml)

View File

@ -20,12 +20,9 @@ Document -
IntermediateToken - - CSharp - base.BuildRenderTree(builder);
HtmlContent - (34:0,34 [2] x:\dir\subdir\Test\TestComponent.cshtml)
IntermediateToken - (34:0,34 [2] x:\dir\subdir\Test\TestComponent.cshtml) - Html - \n
HtmlContent -
IntermediateToken - - Html - <input
HtmlAttribute - - =" - "
CSharpExpressionAttributeValue - -
IntermediateToken - - CSharp - Microsoft.AspNetCore.Blazor.Components.BindMethods.GetEventHandlerValue<Microsoft.AspNetCore.Blazor.UIMouseEventArgs>(
IntermediateToken - (54:1,18 [8] x:\dir\subdir\Test\TestComponent.cshtml) - CSharp - x => { }
IntermediateToken - - CSharp - )
HtmlContent -
IntermediateToken - - Html - />
HtmlElement - (36:1,0 [31] x:\dir\subdir\Test\TestComponent.cshtml) - input
HtmlAttribute - (52:1,16 [11] x:\dir\subdir\Test\TestComponent.cshtml) - onclick=" - "
CSharpExpressionAttributeValue - -
IntermediateToken - - CSharp - Microsoft.AspNetCore.Blazor.Components.BindMethods.GetEventHandlerValue<Microsoft.AspNetCore.Blazor.UIMouseEventArgs>(
IntermediateToken - (54:1,18 [8] x:\dir\subdir\Test\TestComponent.cshtml) - CSharp - x => { }
IntermediateToken - - CSharp - )

View File

@ -17,12 +17,9 @@ Document -
MethodDeclaration - - protected override - void - BuildRenderTree
CSharpCode -
IntermediateToken - - CSharp - base.BuildRenderTree(builder);
HtmlContent -
IntermediateToken - - Html - <input
HtmlAttribute - - =" - "
CSharpExpressionAttributeValue - -
IntermediateToken - - CSharp - Microsoft.AspNetCore.Blazor.Components.BindMethods.GetEventHandlerValue<Microsoft.AspNetCore.Blazor.UIMouseEventArgs>(
IntermediateToken - - CSharp - "foo"
IntermediateToken - - CSharp - )
HtmlContent -
IntermediateToken - - Html - />
HtmlElement - (0:0,0 [23] x:\dir\subdir\Test\TestComponent.cshtml) - input
HtmlAttribute - (16:0,16 [3] x:\dir\subdir\Test\TestComponent.cshtml) - onclick=" - "
CSharpExpressionAttributeValue - -
IntermediateToken - - CSharp - Microsoft.AspNetCore.Blazor.Components.BindMethods.GetEventHandlerValue<Microsoft.AspNetCore.Blazor.UIMouseEventArgs>(
IntermediateToken - - CSharp - "foo"
IntermediateToken - - CSharp - )

View File

@ -20,8 +20,7 @@ Document -
IntermediateToken - - CSharp - base.BuildRenderTree(builder);
HtmlContent - (29:0,29 [2] x:\dir\subdir\Test\TestComponent.cshtml)
IntermediateToken - (29:0,29 [2] x:\dir\subdir\Test\TestComponent.cshtml) - Html - \n
TagHelper - (31:1,0 [22] x:\dir\subdir\Test\TestComponent.cshtml) - Counter - TagMode.SelfClosing
ComponentOpenExtensionNode - - Test.Counter
ComponentExtensionNode - (31:1,0 [22] x:\dir\subdir\Test\TestComponent.cshtml) - Counter - Test.Counter
ComponentAttributeExtensionNode - (48:1,17 [1] x:\dir\subdir\Test\TestComponent.cshtml) - v -
CSharpExpression -
IntermediateToken - - CSharp - Microsoft.AspNetCore.Blazor.Components.BindMethods.GetValue(
@ -30,8 +29,6 @@ Document -
ComponentAttributeExtensionNode - (48:1,17 [1] x:\dir\subdir\Test\TestComponent.cshtml) - vChanged -
CSharpExpression -
IntermediateToken - - CSharp - Microsoft.AspNetCore.Blazor.Components.BindMethods.SetValueHandler(__value => y = __value, y)
ComponentBodyExtensionNode -
ComponentCloseExtensionNode -
HtmlContent - (53:1,22 [2] x:\dir\subdir\Test\TestComponent.cshtml)
IntermediateToken - (53:1,22 [2] x:\dir\subdir\Test\TestComponent.cshtml) - Html - \n
HtmlContent - (92:4,1 [2] x:\dir\subdir\Test\TestComponent.cshtml)

View File

@ -9,12 +9,9 @@ Document -
MethodDeclaration - - protected override - void - BuildRenderTree
CSharpCode -
IntermediateToken - - CSharp - base.BuildRenderTree(builder);
HtmlContent -
IntermediateToken - - Html - <input
HtmlAttribute - - =" - "
CSharpExpressionAttributeValue - -
IntermediateToken - - CSharp - Microsoft.AspNetCore.Blazor.Components.BindMethods.GetEventHandlerValue<Microsoft.AspNetCore.Blazor.UIMouseEventArgs>(
IntermediateToken - - CSharp - "async (e) => await Task.Delay(10)"
IntermediateToken - - CSharp - )
HtmlContent -
IntermediateToken - - Html - />
HtmlElement - (67:2,0 [53] x:\dir\subdir\Test\TestComponent.cshtml) - input
HtmlAttribute - (83:2,16 [33] x:\dir\subdir\Test\TestComponent.cshtml) - onclick=" - "
CSharpExpressionAttributeValue - -
IntermediateToken - - CSharp - Microsoft.AspNetCore.Blazor.Components.BindMethods.GetEventHandlerValue<Microsoft.AspNetCore.Blazor.UIMouseEventArgs>(
IntermediateToken - - CSharp - "async (e) => await Task.Delay(10)"
IntermediateToken - - CSharp - )

View File

@ -9,14 +9,11 @@ Document -
MethodDeclaration - - protected override - void - BuildRenderTree
CSharpCode -
IntermediateToken - - CSharp - base.BuildRenderTree(builder);
HtmlContent -
IntermediateToken - - Html - <input
HtmlAttribute - - =" - "
CSharpExpressionAttributeValue - -
IntermediateToken - - CSharp - Microsoft.AspNetCore.Blazor.Components.BindMethods.GetEventHandlerValue<Microsoft.AspNetCore.Blazor.UIMouseEventArgs>(
IntermediateToken - (84:2,17 [7] x:\dir\subdir\Test\TestComponent.cshtml) - CSharp - OnClick
IntermediateToken - - CSharp - )
HtmlContent -
IntermediateToken - - Html - />
HtmlElement - (67:2,0 [28] x:\dir\subdir\Test\TestComponent.cshtml) - input
HtmlAttribute - (83:2,16 [8] x:\dir\subdir\Test\TestComponent.cshtml) - onclick=" - "
CSharpExpressionAttributeValue - -
IntermediateToken - - CSharp - Microsoft.AspNetCore.Blazor.Components.BindMethods.GetEventHandlerValue<Microsoft.AspNetCore.Blazor.UIMouseEventArgs>(
IntermediateToken - (84:2,17 [7] x:\dir\subdir\Test\TestComponent.cshtml) - CSharp - OnClick
IntermediateToken - - CSharp - )
CSharpCode - (109:3,12 [91] x:\dir\subdir\Test\TestComponent.cshtml)
IntermediateToken - (109:3,12 [91] x:\dir\subdir\Test\TestComponent.cshtml) - CSharp - \n Task OnClick(UIMouseEventArgs e) \n {\n return Task.CompletedTask;\n }\n

View File

@ -9,12 +9,9 @@ Document -
MethodDeclaration - - protected override - void - BuildRenderTree
CSharpCode -
IntermediateToken - - CSharp - base.BuildRenderTree(builder);
HtmlContent -
IntermediateToken - - Html - <input
HtmlAttribute - - =" - "
CSharpExpressionAttributeValue - -
IntermediateToken - - CSharp - Microsoft.AspNetCore.Blazor.Components.BindMethods.GetEventHandlerValue<Microsoft.AspNetCore.Blazor.UIMouseEventArgs>(
IntermediateToken - - CSharp - "async (e) => await Task.Delay(10)"
IntermediateToken - - CSharp - )
HtmlContent -
IntermediateToken - - Html - />
HtmlElement - (67:2,0 [53] x:\dir\subdir\Test\TestComponent.cshtml) - input
HtmlAttribute - (83:2,16 [33] x:\dir\subdir\Test\TestComponent.cshtml) - onclick=" - "
CSharpExpressionAttributeValue - -
IntermediateToken - - CSharp - Microsoft.AspNetCore.Blazor.Components.BindMethods.GetEventHandlerValue<Microsoft.AspNetCore.Blazor.UIMouseEventArgs>(
IntermediateToken - - CSharp - "async (e) => await Task.Delay(10)"
IntermediateToken - - CSharp - )

View File

@ -9,14 +9,11 @@ Document -
MethodDeclaration - - protected override - void - BuildRenderTree
CSharpCode -
IntermediateToken - - CSharp - base.BuildRenderTree(builder);
HtmlContent -
IntermediateToken - - Html - <input
HtmlAttribute - - =" - "
CSharpExpressionAttributeValue - -
IntermediateToken - - CSharp - Microsoft.AspNetCore.Blazor.Components.BindMethods.GetEventHandlerValue<Microsoft.AspNetCore.Blazor.UIMouseEventArgs>(
IntermediateToken - (84:2,17 [7] x:\dir\subdir\Test\TestComponent.cshtml) - CSharp - OnClick
IntermediateToken - - CSharp - )
HtmlContent -
IntermediateToken - - Html - />
HtmlElement - (67:2,0 [28] x:\dir\subdir\Test\TestComponent.cshtml) - input
HtmlAttribute - (83:2,16 [8] x:\dir\subdir\Test\TestComponent.cshtml) - onclick=" - "
CSharpExpressionAttributeValue - -
IntermediateToken - - CSharp - Microsoft.AspNetCore.Blazor.Components.BindMethods.GetEventHandlerValue<Microsoft.AspNetCore.Blazor.UIMouseEventArgs>(
IntermediateToken - (84:2,17 [7] x:\dir\subdir\Test\TestComponent.cshtml) - CSharp - OnClick
IntermediateToken - - CSharp - )
CSharpCode - (109:3,12 [73] x:\dir\subdir\Test\TestComponent.cshtml)
IntermediateToken - (109:3,12 [73] x:\dir\subdir\Test\TestComponent.cshtml) - CSharp - \n Task OnClick() \n {\n return Task.CompletedTask;\n }\n

View File

@ -8,8 +8,7 @@ Document -
MethodDeclaration - - protected override - void - BuildRenderTree
CSharpCode -
IntermediateToken - - CSharp - base.BuildRenderTree(builder);
TagHelper - (31:1,0 [50] x:\dir\subdir\Test\TestComponent.cshtml) - MyComponent - TagMode.SelfClosing
ComponentOpenExtensionNode - - Test.MyComponent
ComponentExtensionNode - (31:1,0 [50] x:\dir\subdir\Test\TestComponent.cshtml) - MyComponent - Test.MyComponent
ComponentAttributeExtensionNode - (66:1,35 [11] x:\dir\subdir\Test\TestComponent.cshtml) - Value - Value
CSharpExpression -
IntermediateToken - - CSharp - Microsoft.AspNetCore.Blazor.Components.BindMethods.GetValue(
@ -18,7 +17,5 @@ Document -
ComponentAttributeExtensionNode - (66:1,35 [11] x:\dir\subdir\Test\TestComponent.cshtml) - OnChanged - OnChanged
CSharpExpression -
IntermediateToken - - CSharp - __value => ParentValue = __value
ComponentBodyExtensionNode -
ComponentCloseExtensionNode -
CSharpCode - (95:2,12 [50] x:\dir\subdir\Test\TestComponent.cshtml)
IntermediateToken - (95:2,12 [50] x:\dir\subdir\Test\TestComponent.cshtml) - CSharp - \n public int ParentValue { get; set; } = 42;\n

View File

@ -8,8 +8,7 @@ Document -
MethodDeclaration - - protected override - void - BuildRenderTree
CSharpCode -
IntermediateToken - - CSharp - base.BuildRenderTree(builder);
TagHelper - (31:1,0 [50] x:\dir\subdir\Test\TestComponent.cshtml) - MyComponent - TagMode.SelfClosing
ComponentOpenExtensionNode - - Test.MyComponent
ComponentExtensionNode - (31:1,0 [50] x:\dir\subdir\Test\TestComponent.cshtml) - MyComponent - Test.MyComponent
ComponentAttributeExtensionNode - (66:1,35 [11] x:\dir\subdir\Test\TestComponent.cshtml) - Value -
CSharpExpression -
IntermediateToken - - CSharp - Microsoft.AspNetCore.Blazor.Components.BindMethods.GetValue(
@ -18,7 +17,5 @@ Document -
ComponentAttributeExtensionNode - (66:1,35 [11] x:\dir\subdir\Test\TestComponent.cshtml) - OnChanged -
CSharpExpression -
IntermediateToken - - CSharp - Microsoft.AspNetCore.Blazor.Components.BindMethods.SetValueHandler(__value => ParentValue = __value, ParentValue)
ComponentBodyExtensionNode -
ComponentCloseExtensionNode -
CSharpCode - (95:2,12 [50] x:\dir\subdir\Test\TestComponent.cshtml)
IntermediateToken - (95:2,12 [50] x:\dir\subdir\Test\TestComponent.cshtml) - CSharp - \n public int ParentValue { get; set; } = 42;\n

View File

@ -8,8 +8,7 @@ Document -
MethodDeclaration - - protected override - void - BuildRenderTree
CSharpCode -
IntermediateToken - - CSharp - base.BuildRenderTree(builder);
TagHelper - (31:1,0 [40] x:\dir\subdir\Test\TestComponent.cshtml) - MyComponent - TagMode.SelfClosing
ComponentOpenExtensionNode - - Test.MyComponent
ComponentExtensionNode - (31:1,0 [40] x:\dir\subdir\Test\TestComponent.cshtml) - MyComponent - Test.MyComponent
ComponentAttributeExtensionNode - (56:1,25 [11] x:\dir\subdir\Test\TestComponent.cshtml) - Value - Value
CSharpExpression -
IntermediateToken - - CSharp - Microsoft.AspNetCore.Blazor.Components.BindMethods.GetValue(
@ -18,7 +17,5 @@ Document -
ComponentAttributeExtensionNode - (56:1,25 [11] x:\dir\subdir\Test\TestComponent.cshtml) - ValueChanged - ValueChanged
CSharpExpression -
IntermediateToken - - CSharp - __value => ParentValue = __value
ComponentBodyExtensionNode -
ComponentCloseExtensionNode -
CSharpCode - (85:2,12 [50] x:\dir\subdir\Test\TestComponent.cshtml)
IntermediateToken - (85:2,12 [50] x:\dir\subdir\Test\TestComponent.cshtml) - CSharp - \n public int ParentValue { get; set; } = 42;\n

View File

@ -8,8 +8,7 @@ Document -
MethodDeclaration - - protected override - void - BuildRenderTree
CSharpCode -
IntermediateToken - - CSharp - base.BuildRenderTree(builder);
TagHelper - (31:1,0 [40] x:\dir\subdir\Test\TestComponent.cshtml) - MyComponent - TagMode.SelfClosing
ComponentOpenExtensionNode - - Test.MyComponent
ComponentExtensionNode - (31:1,0 [40] x:\dir\subdir\Test\TestComponent.cshtml) - MyComponent - Test.MyComponent
ComponentAttributeExtensionNode - (56:1,25 [11] x:\dir\subdir\Test\TestComponent.cshtml) - Value -
CSharpExpression -
IntermediateToken - - CSharp - Microsoft.AspNetCore.Blazor.Components.BindMethods.GetValue(
@ -18,7 +17,5 @@ Document -
ComponentAttributeExtensionNode - (56:1,25 [11] x:\dir\subdir\Test\TestComponent.cshtml) - ValueChanged -
CSharpExpression -
IntermediateToken - - CSharp - Microsoft.AspNetCore.Blazor.Components.BindMethods.SetValueHandler(__value => ParentValue = __value, ParentValue)
ComponentBodyExtensionNode -
ComponentCloseExtensionNode -
CSharpCode - (85:2,12 [50] x:\dir\subdir\Test\TestComponent.cshtml)
IntermediateToken - (85:2,12 [50] x:\dir\subdir\Test\TestComponent.cshtml) - CSharp - \n public int ParentValue { get; set; } = 42;\n

View File

@ -8,23 +8,19 @@ Document -
MethodDeclaration - - protected override - void - BuildRenderTree
CSharpCode -
IntermediateToken - - CSharp - base.BuildRenderTree(builder);
HtmlContent -
IntermediateToken - - Html - <input
HtmlContent -
IntermediateToken - - Html - type="
IntermediateToken - (44:1,13 [4] x:\dir\subdir\Test\TestComponent.cshtml) - Html - text
IntermediateToken - - Html - "
HtmlAttribute - - =" - "
CSharpExpressionAttributeValue - -
IntermediateToken - - CSharp - Microsoft.AspNetCore.Blazor.Components.BindMethods.GetValue(
IntermediateToken - (72:1,41 [11] x:\dir\subdir\Test\TestComponent.cshtml) - CSharp - CurrentDate
IntermediateToken - - CSharp - ,
IntermediateToken - - CSharp - "MM/dd"
IntermediateToken - - CSharp - )
HtmlAttribute - - =" - "
CSharpExpressionAttributeValue - -
IntermediateToken - - CSharp - Microsoft.AspNetCore.Blazor.Components.BindMethods.SetValueHandler(__value => CurrentDate = __value, CurrentDate, "MM/dd")
HtmlContent -
IntermediateToken - - Html - />
HtmlElement - (31:1,0 [77] x:\dir\subdir\Test\TestComponent.cshtml) - input
HtmlAttribute - - type=" - "
HtmlAttributeValue - (44:1,13 [4] x:\dir\subdir\Test\TestComponent.cshtml) -
IntermediateToken - (44:1,13 [4] x:\dir\subdir\Test\TestComponent.cshtml) - Html - text
HtmlAttribute - (71:1,40 [12] x:\dir\subdir\Test\TestComponent.cshtml) - value=" - "
CSharpExpressionAttributeValue - -
IntermediateToken - - CSharp - Microsoft.AspNetCore.Blazor.Components.BindMethods.GetValue(
IntermediateToken - (72:1,41 [11] x:\dir\subdir\Test\TestComponent.cshtml) - CSharp - CurrentDate
IntermediateToken - - CSharp - ,
IntermediateToken - - CSharp - "MM/dd"
IntermediateToken - - CSharp - )
HtmlAttribute - (71:1,40 [12] x:\dir\subdir\Test\TestComponent.cshtml) - onchange=" - "
CSharpExpressionAttributeValue - -
IntermediateToken - - CSharp - Microsoft.AspNetCore.Blazor.Components.BindMethods.SetValueHandler(__value => CurrentDate = __value, CurrentDate, "MM/dd")
CSharpCode - (122:2,12 [77] x:\dir\subdir\Test\TestComponent.cshtml)
IntermediateToken - (122:2,12 [77] x:\dir\subdir\Test\TestComponent.cshtml) - CSharp - \n public DateTime CurrentDate { get; set; } = new DateTime(2018, 1, 1);\n

View File

@ -8,21 +8,17 @@ Document -
MethodDeclaration - - protected override - void - BuildRenderTree
CSharpCode -
IntermediateToken - - CSharp - base.BuildRenderTree(builder);
HtmlContent -
IntermediateToken - - Html - <input
HtmlContent -
IntermediateToken - - Html - type="
IntermediateToken - (44:1,13 [4] x:\dir\subdir\Test\TestComponent.cshtml) - Html - text
IntermediateToken - - Html - "
HtmlAttribute - - =" - "
CSharpExpressionAttributeValue - -
IntermediateToken - - CSharp - Microsoft.AspNetCore.Blazor.Components.BindMethods.GetValue(
IntermediateToken - (72:1,41 [11] x:\dir\subdir\Test\TestComponent.cshtml) - CSharp - ParentValue
IntermediateToken - - CSharp - )
HtmlAttribute - - =" - "
CSharpExpressionAttributeValue - -
IntermediateToken - - CSharp - Microsoft.AspNetCore.Blazor.Components.BindMethods.SetValueHandler(__value => ParentValue = __value, ParentValue)
HtmlContent -
IntermediateToken - - Html - />
HtmlElement - (31:1,0 [56] x:\dir\subdir\Test\TestComponent.cshtml) - input
HtmlAttribute - - type=" - "
HtmlAttributeValue - (44:1,13 [4] x:\dir\subdir\Test\TestComponent.cshtml) -
IntermediateToken - (44:1,13 [4] x:\dir\subdir\Test\TestComponent.cshtml) - Html - text
HtmlAttribute - (71:1,40 [12] x:\dir\subdir\Test\TestComponent.cshtml) - value=" - "
CSharpExpressionAttributeValue - -
IntermediateToken - - CSharp - Microsoft.AspNetCore.Blazor.Components.BindMethods.GetValue(
IntermediateToken - (72:1,41 [11] x:\dir\subdir\Test\TestComponent.cshtml) - CSharp - ParentValue
IntermediateToken - - CSharp - )
HtmlAttribute - (71:1,40 [12] x:\dir\subdir\Test\TestComponent.cshtml) - onchange=" - "
CSharpExpressionAttributeValue - -
IntermediateToken - - CSharp - Microsoft.AspNetCore.Blazor.Components.BindMethods.SetValueHandler(__value => ParentValue = __value, ParentValue)
CSharpCode - (101:2,12 [50] x:\dir\subdir\Test\TestComponent.cshtml)
IntermediateToken - (101:2,12 [50] x:\dir\subdir\Test\TestComponent.cshtml) - CSharp - \n public int ParentValue { get; set; } = 42;\n

View File

@ -8,17 +8,14 @@ Document -
MethodDeclaration - - protected override - void - BuildRenderTree
CSharpCode -
IntermediateToken - - CSharp - base.BuildRenderTree(builder);
HtmlContent -
IntermediateToken - - Html - <div
HtmlAttribute - - =" - "
CSharpExpressionAttributeValue - -
IntermediateToken - - CSharp - Microsoft.AspNetCore.Blazor.Components.BindMethods.GetValue(
IntermediateToken - (49:1,18 [11] x:\dir\subdir\Test\TestComponent.cshtml) - CSharp - ParentValue
IntermediateToken - - CSharp - )
HtmlAttribute - - =" - "
CSharpExpressionAttributeValue - -
IntermediateToken - - CSharp - Microsoft.AspNetCore.Blazor.Components.BindMethods.SetValueHandler(__value => ParentValue = __value, ParentValue)
HtmlContent -
IntermediateToken - - Html - />
HtmlElement - (31:1,0 [33] x:\dir\subdir\Test\TestComponent.cshtml) - div
HtmlAttribute - (48:1,17 [12] x:\dir\subdir\Test\TestComponent.cshtml) - myvalue=" - "
CSharpExpressionAttributeValue - -
IntermediateToken - - CSharp - Microsoft.AspNetCore.Blazor.Components.BindMethods.GetValue(
IntermediateToken - (49:1,18 [11] x:\dir\subdir\Test\TestComponent.cshtml) - CSharp - ParentValue
IntermediateToken - - CSharp - )
HtmlAttribute - (48:1,17 [12] x:\dir\subdir\Test\TestComponent.cshtml) - myevent=" - "
CSharpExpressionAttributeValue - -
IntermediateToken - - CSharp - Microsoft.AspNetCore.Blazor.Components.BindMethods.SetValueHandler(__value => ParentValue = __value, ParentValue)
CSharpCode - (78:2,12 [55] x:\dir\subdir\Test\TestComponent.cshtml)
IntermediateToken - (78:2,12 [55] x:\dir\subdir\Test\TestComponent.cshtml) - CSharp - \n public string ParentValue { get; set; } = "hi";\n

View File

@ -8,17 +8,14 @@ Document -
MethodDeclaration - - protected override - void - BuildRenderTree
CSharpCode -
IntermediateToken - - CSharp - base.BuildRenderTree(builder);
HtmlContent -
IntermediateToken - - Html - <div
HtmlAttribute - - =" - "
CSharpExpressionAttributeValue - -
IntermediateToken - - CSharp - Microsoft.AspNetCore.Blazor.Components.BindMethods.GetValue(
IntermediateToken - (43:1,12 [11] x:\dir\subdir\Test\TestComponent.cshtml) - CSharp - ParentValue
IntermediateToken - - CSharp - )
HtmlAttribute - - =" - "
CSharpExpressionAttributeValue - -
IntermediateToken - - CSharp - Microsoft.AspNetCore.Blazor.Components.BindMethods.SetValueHandler(__value => ParentValue = __value, ParentValue)
HtmlContent -
IntermediateToken - - Html - />
HtmlElement - (31:1,0 [27] x:\dir\subdir\Test\TestComponent.cshtml) - div
HtmlAttribute - (42:1,11 [12] x:\dir\subdir\Test\TestComponent.cshtml) - myvalue=" - "
CSharpExpressionAttributeValue - -
IntermediateToken - - CSharp - Microsoft.AspNetCore.Blazor.Components.BindMethods.GetValue(
IntermediateToken - (43:1,12 [11] x:\dir\subdir\Test\TestComponent.cshtml) - CSharp - ParentValue
IntermediateToken - - CSharp - )
HtmlAttribute - (42:1,11 [12] x:\dir\subdir\Test\TestComponent.cshtml) - myevent=" - "
CSharpExpressionAttributeValue - -
IntermediateToken - - CSharp - Microsoft.AspNetCore.Blazor.Components.BindMethods.SetValueHandler(__value => ParentValue = __value, ParentValue)
CSharpCode - (72:2,12 [55] x:\dir\subdir\Test\TestComponent.cshtml)
IntermediateToken - (72:2,12 [55] x:\dir\subdir\Test\TestComponent.cshtml) - CSharp - \n public string ParentValue { get; set; } = "hi";\n

View File

@ -8,21 +8,17 @@ Document -
MethodDeclaration - - protected override - void - BuildRenderTree
CSharpCode -
IntermediateToken - - CSharp - base.BuildRenderTree(builder);
HtmlContent -
IntermediateToken - - Html - <input
HtmlContent -
IntermediateToken - - Html - type="
IntermediateToken - (44:1,13 [8] x:\dir\subdir\Test\TestComponent.cshtml) - Html - checkbox
IntermediateToken - - Html - "
HtmlAttribute - - =" - "
CSharpExpressionAttributeValue - -
IntermediateToken - - CSharp - Microsoft.AspNetCore.Blazor.Components.BindMethods.GetValue(
IntermediateToken - (61:1,30 [7] x:\dir\subdir\Test\TestComponent.cshtml) - CSharp - Enabled
IntermediateToken - - CSharp - )
HtmlAttribute - - =" - "
CSharpExpressionAttributeValue - -
IntermediateToken - - CSharp - Microsoft.AspNetCore.Blazor.Components.BindMethods.SetValueHandler(__value => Enabled = __value, Enabled)
HtmlContent -
IntermediateToken - - Html - />
HtmlElement - (31:1,0 [41] x:\dir\subdir\Test\TestComponent.cshtml) - input
HtmlAttribute - - type=" - "
HtmlAttributeValue - (44:1,13 [8] x:\dir\subdir\Test\TestComponent.cshtml) -
IntermediateToken - (44:1,13 [8] x:\dir\subdir\Test\TestComponent.cshtml) - Html - checkbox
HtmlAttribute - (60:1,29 [8] x:\dir\subdir\Test\TestComponent.cshtml) - checked=" - "
CSharpExpressionAttributeValue - -
IntermediateToken - - CSharp - Microsoft.AspNetCore.Blazor.Components.BindMethods.GetValue(
IntermediateToken - (61:1,30 [7] x:\dir\subdir\Test\TestComponent.cshtml) - CSharp - Enabled
IntermediateToken - - CSharp - )
HtmlAttribute - (60:1,29 [8] x:\dir\subdir\Test\TestComponent.cshtml) - onchange=" - "
CSharpExpressionAttributeValue - -
IntermediateToken - - CSharp - Microsoft.AspNetCore.Blazor.Components.BindMethods.SetValueHandler(__value => Enabled = __value, Enabled)
CSharpCode - (86:2,12 [41] x:\dir\subdir\Test\TestComponent.cshtml)
IntermediateToken - (86:2,12 [41] x:\dir\subdir\Test\TestComponent.cshtml) - CSharp - \n public bool Enabled { get; set; }\n

View File

@ -8,23 +8,19 @@ Document -
MethodDeclaration - - protected override - void - BuildRenderTree
CSharpCode -
IntermediateToken - - CSharp - base.BuildRenderTree(builder);
HtmlContent -
IntermediateToken - - Html - <input
HtmlContent -
IntermediateToken - - Html - type="
IntermediateToken - (44:1,13 [4] x:\dir\subdir\Test\TestComponent.cshtml) - Html - text
IntermediateToken - - Html - "
HtmlAttribute - - =" - "
CSharpExpressionAttributeValue - -
IntermediateToken - - CSharp - Microsoft.AspNetCore.Blazor.Components.BindMethods.GetValue(
IntermediateToken - (57:1,26 [11] x:\dir\subdir\Test\TestComponent.cshtml) - CSharp - CurrentDate
IntermediateToken - - CSharp - ,
IntermediateToken - (85:1,54 [6] x:\dir\subdir\Test\TestComponent.cshtml) - CSharp - Format
IntermediateToken - - CSharp - )
HtmlAttribute - - =" - "
CSharpExpressionAttributeValue - -
IntermediateToken - - CSharp - Microsoft.AspNetCore.Blazor.Components.BindMethods.SetValueHandler(__value => CurrentDate = __value, CurrentDate, Format)
HtmlContent -
IntermediateToken - - Html - />
HtmlElement - (31:1,0 [63] x:\dir\subdir\Test\TestComponent.cshtml) - input
HtmlAttribute - - type=" - "
HtmlAttributeValue - (44:1,13 [4] x:\dir\subdir\Test\TestComponent.cshtml) -
IntermediateToken - (44:1,13 [4] x:\dir\subdir\Test\TestComponent.cshtml) - Html - text
HtmlAttribute - (56:1,25 [12] x:\dir\subdir\Test\TestComponent.cshtml) - value=" - "
CSharpExpressionAttributeValue - -
IntermediateToken - - CSharp - Microsoft.AspNetCore.Blazor.Components.BindMethods.GetValue(
IntermediateToken - (57:1,26 [11] x:\dir\subdir\Test\TestComponent.cshtml) - CSharp - CurrentDate
IntermediateToken - - CSharp - ,
IntermediateToken - (85:1,54 [6] x:\dir\subdir\Test\TestComponent.cshtml) - CSharp - Format
IntermediateToken - - CSharp - )
HtmlAttribute - (56:1,25 [12] x:\dir\subdir\Test\TestComponent.cshtml) - onchange=" - "
CSharpExpressionAttributeValue - -
IntermediateToken - - CSharp - Microsoft.AspNetCore.Blazor.Components.BindMethods.SetValueHandler(__value => CurrentDate = __value, CurrentDate, Format)
CSharpCode - (108:2,12 [135] x:\dir\subdir\Test\TestComponent.cshtml)
IntermediateToken - (108:2,12 [135] x:\dir\subdir\Test\TestComponent.cshtml) - CSharp - \n public DateTime CurrentDate { get; set; } = new DateTime(2018, 1, 1);\n\n public string Format { get; set; } = "MM/dd/yyyy";\n

View File

@ -8,23 +8,19 @@ Document -
MethodDeclaration - - protected override - void - BuildRenderTree
CSharpCode -
IntermediateToken - - CSharp - base.BuildRenderTree(builder);
HtmlContent -
IntermediateToken - - Html - <input
HtmlContent -
IntermediateToken - - Html - type="
IntermediateToken - (44:1,13 [4] x:\dir\subdir\Test\TestComponent.cshtml) - Html - text
IntermediateToken - - Html - "
HtmlAttribute - - =" - "
CSharpExpressionAttributeValue - -
IntermediateToken - - CSharp - Microsoft.AspNetCore.Blazor.Components.BindMethods.GetValue(
IntermediateToken - (57:1,26 [11] x:\dir\subdir\Test\TestComponent.cshtml) - CSharp - CurrentDate
IntermediateToken - - CSharp - ,
IntermediateToken - - CSharp - "MM/dd/yyyy"
IntermediateToken - - CSharp - )
HtmlAttribute - - =" - "
CSharpExpressionAttributeValue - -
IntermediateToken - - CSharp - Microsoft.AspNetCore.Blazor.Components.BindMethods.SetValueHandler(__value => CurrentDate = __value, CurrentDate, "MM/dd/yyyy")
HtmlContent -
IntermediateToken - - Html - />
HtmlElement - (31:1,0 [66] x:\dir\subdir\Test\TestComponent.cshtml) - input
HtmlAttribute - - type=" - "
HtmlAttributeValue - (44:1,13 [4] x:\dir\subdir\Test\TestComponent.cshtml) -
IntermediateToken - (44:1,13 [4] x:\dir\subdir\Test\TestComponent.cshtml) - Html - text
HtmlAttribute - (56:1,25 [12] x:\dir\subdir\Test\TestComponent.cshtml) - value=" - "
CSharpExpressionAttributeValue - -
IntermediateToken - - CSharp - Microsoft.AspNetCore.Blazor.Components.BindMethods.GetValue(
IntermediateToken - (57:1,26 [11] x:\dir\subdir\Test\TestComponent.cshtml) - CSharp - CurrentDate
IntermediateToken - - CSharp - ,
IntermediateToken - - CSharp - "MM/dd/yyyy"
IntermediateToken - - CSharp - )
HtmlAttribute - (56:1,25 [12] x:\dir\subdir\Test\TestComponent.cshtml) - onchange=" - "
CSharpExpressionAttributeValue - -
IntermediateToken - - CSharp - Microsoft.AspNetCore.Blazor.Components.BindMethods.SetValueHandler(__value => CurrentDate = __value, CurrentDate, "MM/dd/yyyy")
CSharpCode - (111:2,12 [77] x:\dir\subdir\Test\TestComponent.cshtml)
IntermediateToken - (111:2,12 [77] x:\dir\subdir\Test\TestComponent.cshtml) - CSharp - \n public DateTime CurrentDate { get; set; } = new DateTime(2018, 1, 1);\n

View File

@ -8,21 +8,17 @@ Document -
MethodDeclaration - - protected override - void - BuildRenderTree
CSharpCode -
IntermediateToken - - CSharp - base.BuildRenderTree(builder);
HtmlContent -
IntermediateToken - - Html - <input
HtmlContent -
IntermediateToken - - Html - type="
IntermediateToken - (44:1,13 [4] x:\dir\subdir\Test\TestComponent.cshtml) - Html - text
IntermediateToken - - Html - "
HtmlAttribute - - =" - "
CSharpExpressionAttributeValue - -
IntermediateToken - - CSharp - Microsoft.AspNetCore.Blazor.Components.BindMethods.GetValue(
IntermediateToken - (57:1,26 [11] x:\dir\subdir\Test\TestComponent.cshtml) - CSharp - ParentValue
IntermediateToken - - CSharp - )
HtmlAttribute - - =" - "
CSharpExpressionAttributeValue - -
IntermediateToken - - CSharp - Microsoft.AspNetCore.Blazor.Components.BindMethods.SetValueHandler(__value => ParentValue = __value, ParentValue)
HtmlContent -
IntermediateToken - - Html - />
HtmlElement - (31:1,0 [41] x:\dir\subdir\Test\TestComponent.cshtml) - input
HtmlAttribute - - type=" - "
HtmlAttributeValue - (44:1,13 [4] x:\dir\subdir\Test\TestComponent.cshtml) -
IntermediateToken - (44:1,13 [4] x:\dir\subdir\Test\TestComponent.cshtml) - Html - text
HtmlAttribute - (56:1,25 [12] x:\dir\subdir\Test\TestComponent.cshtml) - value=" - "
CSharpExpressionAttributeValue - -
IntermediateToken - - CSharp - Microsoft.AspNetCore.Blazor.Components.BindMethods.GetValue(
IntermediateToken - (57:1,26 [11] x:\dir\subdir\Test\TestComponent.cshtml) - CSharp - ParentValue
IntermediateToken - - CSharp - )
HtmlAttribute - (56:1,25 [12] x:\dir\subdir\Test\TestComponent.cshtml) - onchange=" - "
CSharpExpressionAttributeValue - -
IntermediateToken - - CSharp - Microsoft.AspNetCore.Blazor.Components.BindMethods.SetValueHandler(__value => ParentValue = __value, ParentValue)
CSharpCode - (86:2,12 [50] x:\dir\subdir\Test\TestComponent.cshtml)
IntermediateToken - (86:2,12 [50] x:\dir\subdir\Test\TestComponent.cshtml) - CSharp - \n public int ParentValue { get; set; } = 42;\n

View File

@ -8,17 +8,14 @@ Document -
MethodDeclaration - - protected override - void - BuildRenderTree
CSharpCode -
IntermediateToken - - CSharp - base.BuildRenderTree(builder);
HtmlContent -
IntermediateToken - - Html - <input
HtmlAttribute - - =" - "
CSharpExpressionAttributeValue - -
IntermediateToken - - CSharp - Microsoft.AspNetCore.Blazor.Components.BindMethods.GetValue(
IntermediateToken - (45:1,14 [11] x:\dir\subdir\Test\TestComponent.cshtml) - CSharp - ParentValue
IntermediateToken - - CSharp - )
HtmlAttribute - - =" - "
CSharpExpressionAttributeValue - -
IntermediateToken - - CSharp - Microsoft.AspNetCore.Blazor.Components.BindMethods.SetValueHandler(__value => ParentValue = __value, ParentValue)
HtmlContent -
IntermediateToken - - Html - />
HtmlElement - (31:1,0 [29] x:\dir\subdir\Test\TestComponent.cshtml) - input
HtmlAttribute - (44:1,13 [12] x:\dir\subdir\Test\TestComponent.cshtml) - value=" - "
CSharpExpressionAttributeValue - -
IntermediateToken - - CSharp - Microsoft.AspNetCore.Blazor.Components.BindMethods.GetValue(
IntermediateToken - (45:1,14 [11] x:\dir\subdir\Test\TestComponent.cshtml) - CSharp - ParentValue
IntermediateToken - - CSharp - )
HtmlAttribute - (44:1,13 [12] x:\dir\subdir\Test\TestComponent.cshtml) - onchange=" - "
CSharpExpressionAttributeValue - -
IntermediateToken - - CSharp - Microsoft.AspNetCore.Blazor.Components.BindMethods.SetValueHandler(__value => ParentValue = __value, ParentValue)
CSharpCode - (74:2,12 [50] x:\dir\subdir\Test\TestComponent.cshtml)
IntermediateToken - (74:2,12 [50] x:\dir\subdir\Test\TestComponent.cshtml) - CSharp - \n public int ParentValue { get; set; } = 42;\n

View File

@ -8,7 +8,4 @@ Document -
MethodDeclaration - - protected override - void - BuildRenderTree
CSharpCode -
IntermediateToken - - CSharp - base.BuildRenderTree(builder);
TagHelper - (31:1,0 [15] x:\dir\subdir\Test\TestComponent.cshtml) - MyComponent - TagMode.SelfClosing
ComponentOpenExtensionNode - - Test.MyComponent
ComponentBodyExtensionNode -
ComponentCloseExtensionNode -
ComponentExtensionNode - (31:1,0 [15] x:\dir\subdir\Test\TestComponent.cshtml) - MyComponent - Test.MyComponent

View File

@ -8,17 +8,15 @@ Document -
MethodDeclaration - - protected override - void - BuildRenderTree
CSharpCode -
IntermediateToken - - CSharp - base.BuildRenderTree(builder);
TagHelper - (31:1,0 [91] x:\dir\subdir\Test\TestComponent.cshtml) - MyComponent - TagMode.StartTagAndEndTag
ComponentOpenExtensionNode - - Test.MyComponent
ComponentExtensionNode - (31:1,0 [91] x:\dir\subdir\Test\TestComponent.cshtml) - MyComponent - Test.MyComponent
HtmlContent - (57:1,26 [9] x:\dir\subdir\Test\TestComponent.cshtml)
IntermediateToken - (57:1,26 [9] x:\dir\subdir\Test\TestComponent.cshtml) - Html - Some text
HtmlElement - (66:1,35 [42] x:\dir\subdir\Test\TestComponent.cshtml) - some-child
HtmlAttribute - - -
HtmlAttributeValue - -
IntermediateToken - - Html - 1
HtmlContent - (84:1,53 [11] x:\dir\subdir\Test\TestComponent.cshtml)
IntermediateToken - (84:1,53 [11] x:\dir\subdir\Test\TestComponent.cshtml) - Html - Nested text
ComponentAttributeExtensionNode - (52:1,21 [3] x:\dir\subdir\Test\TestComponent.cshtml) - MyAttr - MyAttr
HtmlContent - (52:1,21 [3] x:\dir\subdir\Test\TestComponent.cshtml)
IntermediateToken - (52:1,21 [3] x:\dir\subdir\Test\TestComponent.cshtml) - Html - abc
ComponentBodyExtensionNode -
HtmlContent - (57:1,26 [51] x:\dir\subdir\Test\TestComponent.cshtml)
IntermediateToken - (57:1,26 [9] x:\dir\subdir\Test\TestComponent.cshtml) - Html - Some text
IntermediateToken - (66:1,35 [11] x:\dir\subdir\Test\TestComponent.cshtml) - Html - <some-child
IntermediateToken - (77:1,46 [6] x:\dir\subdir\Test\TestComponent.cshtml) - Html - a='1'
IntermediateToken - (83:1,52 [1] x:\dir\subdir\Test\TestComponent.cshtml) - Html - >
IntermediateToken - (84:1,53 [11] x:\dir\subdir\Test\TestComponent.cshtml) - Html - Nested text
IntermediateToken - (95:1,64 [13] x:\dir\subdir\Test\TestComponent.cshtml) - Html - </some-child>
ComponentCloseExtensionNode -

View File

@ -9,12 +9,9 @@ Document -
MethodDeclaration - - protected override - void - BuildRenderTree
CSharpCode -
IntermediateToken - - CSharp - base.BuildRenderTree(builder);
TagHelper - (67:2,0 [35] x:\dir\subdir\Test\TestComponent.cshtml) - MyComponent - TagMode.SelfClosing
ComponentOpenExtensionNode - - Test.MyComponent
ComponentExtensionNode - (67:2,0 [35] x:\dir\subdir\Test\TestComponent.cshtml) - MyComponent - Test.MyComponent
ComponentAttributeExtensionNode - (89:2,22 [10] x:\dir\subdir\Test\TestComponent.cshtml) - OnClick - OnClick
CSharpExpression - (90:2,23 [9] x:\dir\subdir\Test\TestComponent.cshtml)
IntermediateToken - (90:2,23 [9] x:\dir\subdir\Test\TestComponent.cshtml) - CSharp - Increment
ComponentBodyExtensionNode -
ComponentCloseExtensionNode -
CSharpCode - (118:4,12 [100] x:\dir\subdir\Test\TestComponent.cshtml)
IntermediateToken - (118:4,12 [100] x:\dir\subdir\Test\TestComponent.cshtml) - CSharp - \n private int counter;\n private void Increment(UIEventArgs e) {\n counter++;\n }\n

View File

@ -8,10 +8,7 @@ Document -
MethodDeclaration - - protected override - void - BuildRenderTree
CSharpCode -
IntermediateToken - - CSharp - base.BuildRenderTree(builder);
TagHelper - (31:1,0 [49] x:\dir\subdir\Test\TestComponent.cshtml) - MyComponent - TagMode.SelfClosing
ComponentOpenExtensionNode - - Test.MyComponent
ComponentExtensionNode - (31:1,0 [49] x:\dir\subdir\Test\TestComponent.cshtml) - MyComponent - Test.MyComponent
ComponentAttributeExtensionNode - (60:1,29 [16] x:\dir\subdir\Test\TestComponent.cshtml) - StringProperty - StringProperty
CSharpExpression - (62:1,31 [13] x:\dir\subdir\Test\TestComponent.cshtml)
IntermediateToken - (62:1,31 [13] x:\dir\subdir\Test\TestComponent.cshtml) - CSharp - 42.ToString()
ComponentBodyExtensionNode -
ComponentCloseExtensionNode -

View File

@ -8,12 +8,9 @@ Document -
MethodDeclaration - - protected override - void - BuildRenderTree
CSharpCode -
IntermediateToken - - CSharp - base.BuildRenderTree(builder);
TagHelper - (31:1,0 [49] x:\dir\subdir\Test\TestComponent.cshtml) - MyComponent - TagMode.SelfClosing
ComponentOpenExtensionNode - - Test.MyComponent
ComponentExtensionNode - (31:1,0 [49] x:\dir\subdir\Test\TestComponent.cshtml) - MyComponent - Test.MyComponent
ComponentAttributeExtensionNode - (53:1,22 [24] x:\dir\subdir\Test\TestComponent.cshtml) - OnClick - OnClick
CSharpExpression - (54:1,23 [23] x:\dir\subdir\Test\TestComponent.cshtml)
IntermediateToken - (55:1,24 [21] x:\dir\subdir\Test\TestComponent.cshtml) - CSharp - e => { Increment(); }
ComponentBodyExtensionNode -
ComponentCloseExtensionNode -
CSharpCode - (96:3,12 [87] x:\dir\subdir\Test\TestComponent.cshtml)
IntermediateToken - (96:3,12 [87] x:\dir\subdir\Test\TestComponent.cshtml) - CSharp - \n private int counter;\n private void Increment() {\n counter++;\n }\n

View File

@ -8,13 +8,10 @@ Document -
MethodDeclaration - - protected override - void - BuildRenderTree
CSharpCode -
IntermediateToken - - CSharp - base.BuildRenderTree(builder);
TagHelper - (31:1,0 [72] x:\dir\subdir\Test\TestComponent.cshtml) - MyComponent - TagMode.SelfClosing
ComponentOpenExtensionNode - - Test.MyComponent
ComponentExtensionNode - (31:1,0 [72] x:\dir\subdir\Test\TestComponent.cshtml) - MyComponent - Test.MyComponent
ComponentAttributeExtensionNode - - some-attribute -
HtmlContent - (60:1,29 [3] x:\dir\subdir\Test\TestComponent.cshtml)
IntermediateToken - (60:1,29 [3] x:\dir\subdir\Test\TestComponent.cshtml) - Html - foo
ComponentAttributeExtensionNode - - another-attribute -
CSharpExpression - (84:1,53 [16] x:\dir\subdir\Test\TestComponent.cshtml)
IntermediateToken - (86:1,55 [13] x:\dir\subdir\Test\TestComponent.cshtml) - CSharp - 43.ToString()
ComponentBodyExtensionNode -
ComponentCloseExtensionNode -

View File

@ -10,7 +10,4 @@ Document -
MethodDeclaration - - protected override - void - BuildRenderTree
CSharpCode -
IntermediateToken - - CSharp - base.BuildRenderTree(builder);
TagHelper - (76:3,0 [15] x:\dir\subdir\Test\TestComponent.cshtml) - MyComponent - TagMode.SelfClosing
ComponentOpenExtensionNode - - Test.MyComponent
ComponentBodyExtensionNode -
ComponentCloseExtensionNode -
ComponentExtensionNode - (76:3,0 [15] x:\dir\subdir\Test\TestComponent.cshtml) - MyComponent - Test.MyComponent

View File

@ -8,8 +8,7 @@ Document -
MethodDeclaration - - protected override - void - BuildRenderTree
CSharpCode -
IntermediateToken - - CSharp - base.BuildRenderTree(builder);
TagHelper - (31:1,0 [132] x:\dir\subdir\Test\TestComponent.cshtml) - MyComponent - TagMode.SelfClosing
ComponentOpenExtensionNode - - Test.MyComponent
ComponentExtensionNode - (31:1,0 [132] x:\dir\subdir\Test\TestComponent.cshtml) - MyComponent - Test.MyComponent
ComponentAttributeExtensionNode - (63:2,17 [3] x:\dir\subdir\Test\TestComponent.cshtml) - IntProperty - IntProperty
IntermediateToken - (63:2,17 [3] x:\dir\subdir\Test\TestComponent.cshtml) - CSharp - 123
ComponentAttributeExtensionNode - (87:3,18 [4] x:\dir\subdir\Test\TestComponent.cshtml) - BoolProperty - BoolProperty
@ -19,5 +18,3 @@ Document -
IntermediateToken - (114:4,20 [9] x:\dir\subdir\Test\TestComponent.cshtml) - Html - My string
ComponentAttributeExtensionNode - (146:5,20 [14] x:\dir\subdir\Test\TestComponent.cshtml) - ObjectProperty - ObjectProperty
IntermediateToken - (146:5,20 [14] x:\dir\subdir\Test\TestComponent.cshtml) - CSharp - new SomeType()
ComponentBodyExtensionNode -
ComponentCloseExtensionNode -

View File

@ -8,16 +8,13 @@ Document -
MethodDeclaration - - protected override - void - BuildRenderTree
CSharpCode -
IntermediateToken - - CSharp - base.BuildRenderTree(builder);
TagHelper - (31:1,0 [72] x:\dir\subdir\Test\TestComponent.cshtml) - MyComponent - TagMode.SelfClosing
ComponentOpenExtensionNode - - Test.MyComponent
ComponentExtensionNode - (31:1,0 [72] x:\dir\subdir\Test\TestComponent.cshtml) - MyComponent - Test.MyComponent
ComponentAttributeExtensionNode - - ParamBefore -
HtmlContent - (57:1,26 [6] x:\dir\subdir\Test\TestComponent.cshtml)
IntermediateToken - (57:1,26 [6] x:\dir\subdir\Test\TestComponent.cshtml) - Html - before
RefExtensionNode - (70:1,39 [10] x:\dir\subdir\Test\TestComponent.cshtml) - myInstance - Test.MyComponent
ComponentAttributeExtensionNode - - ParamAfter -
HtmlContent - (94:1,63 [5] x:\dir\subdir\Test\TestComponent.cshtml)
IntermediateToken - (94:1,63 [5] x:\dir\subdir\Test\TestComponent.cshtml) - Html - after
ComponentBodyExtensionNode -
RefExtensionNode - (70:1,39 [10] x:\dir\subdir\Test\TestComponent.cshtml) - myInstance - Test.MyComponent
ComponentCloseExtensionNode -
CSharpCode - (119:3,12 [44] x:\dir\subdir\Test\TestComponent.cshtml)
IntermediateToken - (119:3,12 [44] x:\dir\subdir\Test\TestComponent.cshtml) - CSharp - \n private Test.MyComponent myInstance;\n

View File

@ -8,19 +8,17 @@ Document -
MethodDeclaration - - protected override - void - BuildRenderTree
CSharpCode -
IntermediateToken - - CSharp - base.BuildRenderTree(builder);
TagHelper - (31:1,0 [96] x:\dir\subdir\Test\TestComponent.cshtml) - MyComponent - TagMode.StartTagAndEndTag
ComponentOpenExtensionNode - - Test.MyComponent
ComponentExtensionNode - (31:1,0 [96] x:\dir\subdir\Test\TestComponent.cshtml) - MyComponent - Test.MyComponent
HtmlContent - (76:1,45 [11] x:\dir\subdir\Test\TestComponent.cshtml)
IntermediateToken - (76:1,45 [11] x:\dir\subdir\Test\TestComponent.cshtml) - Html - \n Some
HtmlElement - (87:2,9 [16] x:\dir\subdir\Test\TestComponent.cshtml) - el
HtmlContent - (91:2,13 [7] x:\dir\subdir\Test\TestComponent.cshtml)
IntermediateToken - (91:2,13 [7] x:\dir\subdir\Test\TestComponent.cshtml) - Html - further
HtmlContent - (103:2,25 [10] x:\dir\subdir\Test\TestComponent.cshtml)
IntermediateToken - (103:2,25 [10] x:\dir\subdir\Test\TestComponent.cshtml) - Html - content\n
RefExtensionNode - (49:1,18 [10] x:\dir\subdir\Test\TestComponent.cshtml) - myInstance - Test.MyComponent
ComponentAttributeExtensionNode - - SomeProp -
HtmlContent - (71:1,40 [3] x:\dir\subdir\Test\TestComponent.cshtml)
IntermediateToken - (71:1,40 [3] x:\dir\subdir\Test\TestComponent.cshtml) - Html - val
ComponentBodyExtensionNode -
HtmlContent - (76:1,45 [37] x:\dir\subdir\Test\TestComponent.cshtml)
IntermediateToken - (76:1,45 [11] x:\dir\subdir\Test\TestComponent.cshtml) - Html - \n Some
IntermediateToken - (87:2,9 [4] x:\dir\subdir\Test\TestComponent.cshtml) - Html - <el>
IntermediateToken - (91:2,13 [7] x:\dir\subdir\Test\TestComponent.cshtml) - Html - further
IntermediateToken - (98:2,20 [5] x:\dir\subdir\Test\TestComponent.cshtml) - Html - </el>
IntermediateToken - (103:2,25 [10] x:\dir\subdir\Test\TestComponent.cshtml) - Html - content\n
RefExtensionNode - (49:1,18 [10] x:\dir\subdir\Test\TestComponent.cshtml) - myInstance - Test.MyComponent
ComponentCloseExtensionNode -
CSharpCode - (143:5,12 [44] x:\dir\subdir\Test\TestComponent.cshtml)
IntermediateToken - (143:5,12 [44] x:\dir\subdir\Test\TestComponent.cshtml) - CSharp - \n private Test.MyComponent myInstance;\n

View File

@ -8,22 +8,15 @@ Document -
MethodDeclaration - - protected override - void - BuildRenderTree
CSharpCode -
IntermediateToken - - CSharp - base.BuildRenderTree(builder);
HtmlContent -
IntermediateToken - - Html - <elem
HtmlContent -
IntermediateToken - - Html - attributebefore="
IntermediateToken - (23:0,23 [6] x:\dir\subdir\Test\TestComponent.cshtml) - Html - before
IntermediateToken - - Html - "
HtmlContent -
IntermediateToken - - Html - attributeafter="
IntermediateToken - (60:0,60 [5] x:\dir\subdir\Test\TestComponent.cshtml) - Html - after
IntermediateToken - - Html - "
RefExtensionNode - (36:0,36 [6] x:\dir\subdir\Test\TestComponent.cshtml) - myElem - Element
HtmlContent -
IntermediateToken - - Html - >
HtmlContent - (67:0,67 [5] x:\dir\subdir\Test\TestComponent.cshtml)
IntermediateToken - (67:0,67 [5] x:\dir\subdir\Test\TestComponent.cshtml) - Html - Hello
HtmlContent -
IntermediateToken - - Html - </elem>
HtmlElement - (0:0,0 [79] x:\dir\subdir\Test\TestComponent.cshtml) - elem
HtmlContent - (67:0,67 [5] x:\dir\subdir\Test\TestComponent.cshtml)
IntermediateToken - (67:0,67 [5] x:\dir\subdir\Test\TestComponent.cshtml) - Html - Hello
HtmlAttribute - - attributebefore=" - "
HtmlAttributeValue - (23:0,23 [6] x:\dir\subdir\Test\TestComponent.cshtml) -
IntermediateToken - (23:0,23 [6] x:\dir\subdir\Test\TestComponent.cshtml) - Html - before
RefExtensionNode - (36:0,36 [6] x:\dir\subdir\Test\TestComponent.cshtml) - myElem - Element
HtmlAttribute - - attributeafter=" - "
HtmlAttributeValue - (60:0,60 [5] x:\dir\subdir\Test\TestComponent.cshtml) -
IntermediateToken - (60:0,60 [5] x:\dir\subdir\Test\TestComponent.cshtml) - Html - after
CSharpCode - (95:2,12 [62] x:\dir\subdir\Test\TestComponent.cshtml)
IntermediateToken - (95:2,12 [62] x:\dir\subdir\Test\TestComponent.cshtml) - CSharp - \n private Microsoft.AspNetCore.Blazor.ElementRef myElem;\n

View File

@ -9,14 +9,11 @@ Document -
MethodDeclaration - - protected override - void - BuildRenderTree
CSharpCode -
IntermediateToken - - CSharp - base.BuildRenderTree(builder);
HtmlContent -
IntermediateToken - - Html - <input
HtmlAttribute - - =" - "
CSharpExpressionAttributeValue - -
IntermediateToken - - CSharp - Microsoft.AspNetCore.Blazor.Components.BindMethods.GetEventHandlerValue<Microsoft.AspNetCore.Blazor.UIMouseEventArgs>(
IntermediateToken - (53:1,17 [7] x:\dir\subdir\Test\TestComponent.cshtml) - CSharp - OnClick
IntermediateToken - - CSharp - )
HtmlContent -
IntermediateToken - - Html - />
HtmlElement - (36:1,0 [28] x:\dir\subdir\Test\TestComponent.cshtml) - input
HtmlAttribute - (52:1,16 [8] x:\dir\subdir\Test\TestComponent.cshtml) - onclick=" - "
CSharpExpressionAttributeValue - -
IntermediateToken - - CSharp - Microsoft.AspNetCore.Blazor.Components.BindMethods.GetEventHandlerValue<Microsoft.AspNetCore.Blazor.UIMouseEventArgs>(
IntermediateToken - (53:1,17 [7] x:\dir\subdir\Test\TestComponent.cshtml) - CSharp - OnClick
IntermediateToken - - CSharp - )
CSharpCode - (78:2,12 [44] x:\dir\subdir\Test\TestComponent.cshtml)
IntermediateToken - (78:2,12 [44] x:\dir\subdir\Test\TestComponent.cshtml) - CSharp - \n void OnClick(UIEventArgs e) {\n }\n

View File

@ -9,12 +9,9 @@ Document -
MethodDeclaration - - protected override - void - BuildRenderTree
CSharpCode -
IntermediateToken - - CSharp - base.BuildRenderTree(builder);
HtmlContent -
IntermediateToken - - Html - <input
HtmlAttribute - - =" - "
CSharpExpressionAttributeValue - -
IntermediateToken - - CSharp - Microsoft.AspNetCore.Blazor.Components.BindMethods.GetEventHandlerValue<Microsoft.AspNetCore.Blazor.UIMouseEventArgs>(
IntermediateToken - (54:1,18 [8] x:\dir\subdir\Test\TestComponent.cshtml) - CSharp - x => { }
IntermediateToken - - CSharp - )
HtmlContent -
IntermediateToken - - Html - />
HtmlElement - (36:1,0 [31] x:\dir\subdir\Test\TestComponent.cshtml) - input
HtmlAttribute - (52:1,16 [11] x:\dir\subdir\Test\TestComponent.cshtml) - onclick=" - "
CSharpExpressionAttributeValue - -
IntermediateToken - - CSharp - Microsoft.AspNetCore.Blazor.Components.BindMethods.GetEventHandlerValue<Microsoft.AspNetCore.Blazor.UIMouseEventArgs>(
IntermediateToken - (54:1,18 [8] x:\dir\subdir\Test\TestComponent.cshtml) - CSharp - x => { }
IntermediateToken - - CSharp - )

View File

@ -9,14 +9,11 @@ Document -
MethodDeclaration - - protected override - void - BuildRenderTree
CSharpCode -
IntermediateToken - - CSharp - base.BuildRenderTree(builder);
HtmlContent -
IntermediateToken - - Html - <input
HtmlAttribute - - =" - "
CSharpExpressionAttributeValue - -
IntermediateToken - - CSharp - Microsoft.AspNetCore.Blazor.Components.BindMethods.GetEventHandlerValue<Microsoft.AspNetCore.Blazor.UIMouseEventArgs>(
IntermediateToken - (53:1,17 [7] x:\dir\subdir\Test\TestComponent.cshtml) - CSharp - OnClick
IntermediateToken - - CSharp - )
HtmlContent -
IntermediateToken - - Html - />
HtmlElement - (36:1,0 [28] x:\dir\subdir\Test\TestComponent.cshtml) - input
HtmlAttribute - (52:1,16 [8] x:\dir\subdir\Test\TestComponent.cshtml) - onclick=" - "
CSharpExpressionAttributeValue - -
IntermediateToken - - CSharp - Microsoft.AspNetCore.Blazor.Components.BindMethods.GetEventHandlerValue<Microsoft.AspNetCore.Blazor.UIMouseEventArgs>(
IntermediateToken - (53:1,17 [7] x:\dir\subdir\Test\TestComponent.cshtml) - CSharp - OnClick
IntermediateToken - - CSharp - )
CSharpCode - (78:2,12 [49] x:\dir\subdir\Test\TestComponent.cshtml)
IntermediateToken - (78:2,12 [49] x:\dir\subdir\Test\TestComponent.cshtml) - CSharp - \n void OnClick(UIMouseEventArgs e) {\n }\n

View File

@ -9,14 +9,11 @@ Document -
MethodDeclaration - - protected override - void - BuildRenderTree
CSharpCode -
IntermediateToken - - CSharp - base.BuildRenderTree(builder);
HtmlContent -
IntermediateToken - - Html - <input
HtmlAttribute - - =" - "
CSharpExpressionAttributeValue - -
IntermediateToken - - CSharp - Microsoft.AspNetCore.Blazor.Components.BindMethods.GetEventHandlerValue<Microsoft.AspNetCore.Blazor.UIMouseEventArgs>(
IntermediateToken - (53:1,17 [7] x:\dir\subdir\Test\TestComponent.cshtml) - CSharp - OnClick
IntermediateToken - - CSharp - )
HtmlContent -
IntermediateToken - - Html - />
HtmlElement - (36:1,0 [28] x:\dir\subdir\Test\TestComponent.cshtml) - input
HtmlAttribute - (52:1,16 [8] x:\dir\subdir\Test\TestComponent.cshtml) - onclick=" - "
CSharpExpressionAttributeValue - -
IntermediateToken - - CSharp - Microsoft.AspNetCore.Blazor.Components.BindMethods.GetEventHandlerValue<Microsoft.AspNetCore.Blazor.UIMouseEventArgs>(
IntermediateToken - (53:1,17 [7] x:\dir\subdir\Test\TestComponent.cshtml) - CSharp - OnClick
IntermediateToken - - CSharp - )
CSharpCode - (78:2,12 [31] x:\dir\subdir\Test\TestComponent.cshtml)
IntermediateToken - (78:2,12 [31] x:\dir\subdir\Test\TestComponent.cshtml) - CSharp - \n void OnClick() {\n }\n

View File

@ -9,12 +9,9 @@ Document -
MethodDeclaration - - protected override - void - BuildRenderTree
CSharpCode -
IntermediateToken - - CSharp - base.BuildRenderTree(builder);
HtmlContent -
IntermediateToken - - Html - <input
HtmlAttribute - - =" - "
CSharpExpressionAttributeValue - -
IntermediateToken - - CSharp - Microsoft.AspNetCore.Blazor.Components.BindMethods.GetEventHandlerValue<Microsoft.AspNetCore.Blazor.UIMouseEventArgs>(
IntermediateToken - (54:1,18 [9] x:\dir\subdir\Test\TestComponent.cshtml) - CSharp - () => { }
IntermediateToken - - CSharp - )
HtmlContent -
IntermediateToken - - Html - />
HtmlElement - (36:1,0 [32] x:\dir\subdir\Test\TestComponent.cshtml) - input
HtmlAttribute - (52:1,16 [12] x:\dir\subdir\Test\TestComponent.cshtml) - onclick=" - "
CSharpExpressionAttributeValue - -
IntermediateToken - - CSharp - Microsoft.AspNetCore.Blazor.Components.BindMethods.GetEventHandlerValue<Microsoft.AspNetCore.Blazor.UIMouseEventArgs>(
IntermediateToken - (54:1,18 [9] x:\dir\subdir\Test\TestComponent.cshtml) - CSharp - () => { }
IntermediateToken - - CSharp - )

View File

@ -8,12 +8,9 @@ Document -
MethodDeclaration - - protected override - void - BuildRenderTree
CSharpCode -
IntermediateToken - - CSharp - base.BuildRenderTree(builder);
HtmlContent -
IntermediateToken - - Html - <input
HtmlAttribute - - =" - "
CSharpExpressionAttributeValue - -
IntermediateToken - - CSharp - Microsoft.AspNetCore.Blazor.Components.BindMethods.GetEventHandlerValue<Microsoft.AspNetCore.Blazor.UIMouseEventArgs>(
IntermediateToken - - CSharp - "foo"
IntermediateToken - - CSharp - )
HtmlContent -
IntermediateToken - - Html - />
HtmlElement - (0:0,0 [23] x:\dir\subdir\Test\TestComponent.cshtml) - input
HtmlAttribute - (16:0,16 [3] x:\dir\subdir\Test\TestComponent.cshtml) - onclick=" - "
CSharpExpressionAttributeValue - -
IntermediateToken - - CSharp - Microsoft.AspNetCore.Blazor.Components.BindMethods.GetEventHandlerValue<Microsoft.AspNetCore.Blazor.UIMouseEventArgs>(
IntermediateToken - - CSharp - "foo"
IntermediateToken - - CSharp - )

View File

@ -10,8 +10,8 @@ Document -
IntermediateToken - - CSharp - base.BuildRenderTree(builder);
CSharpExpression - (2:0,2 [10] x:\dir\subdir\Test\TestComponent.cshtml)
IntermediateToken - (2:0,2 [10] x:\dir\subdir\Test\TestComponent.cshtml) - CSharp - "My value"
HtmlContent - (13:0,13 [18] x:\dir\subdir\Test\TestComponent.cshtml)
HtmlContent - (13:0,13 [4] x:\dir\subdir\Test\TestComponent.cshtml)
IntermediateToken - (13:0,13 [4] x:\dir\subdir\Test\TestComponent.cshtml) - Html - \n\n
IntermediateToken - (17:2,0 [4] x:\dir\subdir\Test\TestComponent.cshtml) - Html - <h1>
IntermediateToken - (21:2,4 [5] x:\dir\subdir\Test\TestComponent.cshtml) - Html - Hello
IntermediateToken - (26:2,9 [5] x:\dir\subdir\Test\TestComponent.cshtml) - Html - </h1>
HtmlElement - (17:2,0 [14] x:\dir\subdir\Test\TestComponent.cshtml) - h1
HtmlContent - (21:2,4 [5] x:\dir\subdir\Test\TestComponent.cshtml)
IntermediateToken - (21:2,4 [5] x:\dir\subdir\Test\TestComponent.cshtml) - Html - Hello

View File

@ -8,12 +8,9 @@ Document -
MethodDeclaration - - protected override - void - BuildRenderTree
CSharpCode -
IntermediateToken - - CSharp - base.BuildRenderTree(builder);
TagHelper - (36:2,0 [22] x:\dir\subdir\Test\TestComponent.cshtml) - SomeOtherComponent - TagMode.SelfClosing
ComponentOpenExtensionNode - - Test.SomeOtherComponent
ComponentBodyExtensionNode -
ComponentCloseExtensionNode -
HtmlContent - (58:2,22 [18] x:\dir\subdir\Test\TestComponent.cshtml)
ComponentExtensionNode - (36:2,0 [22] x:\dir\subdir\Test\TestComponent.cshtml) - SomeOtherComponent - Test.SomeOtherComponent
HtmlContent - (58:2,22 [4] x:\dir\subdir\Test\TestComponent.cshtml)
IntermediateToken - (58:2,22 [4] x:\dir\subdir\Test\TestComponent.cshtml) - Html - \n\n
IntermediateToken - (62:4,0 [4] x:\dir\subdir\Test\TestComponent.cshtml) - Html - <h1>
IntermediateToken - (66:4,4 [5] x:\dir\subdir\Test\TestComponent.cshtml) - Html - Hello
IntermediateToken - (71:4,9 [5] x:\dir\subdir\Test\TestComponent.cshtml) - Html - </h1>
HtmlElement - (62:4,0 [14] x:\dir\subdir\Test\TestComponent.cshtml) - h1
HtmlContent - (66:4,4 [5] x:\dir\subdir\Test\TestComponent.cshtml)
IntermediateToken - (66:4,4 [5] x:\dir\subdir\Test\TestComponent.cshtml) - Html - Hello

View File

@ -8,7 +8,6 @@ Document -
MethodDeclaration - - protected override - void - BuildRenderTree
CSharpCode -
IntermediateToken - - CSharp - base.BuildRenderTree(builder);
HtmlContent - (15:1,0 [16] x:\dir\subdir\Test\TestComponent.cshtml)
IntermediateToken - (17:2,0 [4] x:\dir\subdir\Test\TestComponent.cshtml) - Html - <h1>
IntermediateToken - (21:2,4 [5] x:\dir\subdir\Test\TestComponent.cshtml) - Html - Hello
IntermediateToken - (26:2,9 [5] x:\dir\subdir\Test\TestComponent.cshtml) - Html - </h1>
HtmlElement - (17:2,0 [14] x:\dir\subdir\Test\TestComponent.cshtml) - h1
HtmlContent - (21:2,4 [5] x:\dir\subdir\Test\TestComponent.cshtml)
IntermediateToken - (21:2,4 [5] x:\dir\subdir\Test\TestComponent.cshtml) - Html - Hello

View File

@ -8,8 +8,7 @@ Document -
MethodDeclaration - - protected override - void - BuildRenderTree
CSharpCode -
IntermediateToken - - CSharp - base.BuildRenderTree(builder);
TagHelper - (31:1,0 [22] x:\dir\subdir\Test\TestComponent.cshtml) - Counter - TagMode.SelfClosing
ComponentOpenExtensionNode - - Test.Counter
ComponentExtensionNode - (31:1,0 [22] x:\dir\subdir\Test\TestComponent.cshtml) - Counter - Test.Counter
ComponentAttributeExtensionNode - (48:1,17 [1] x:\dir\subdir\Test\TestComponent.cshtml) - v -
CSharpExpression -
IntermediateToken - - CSharp - Microsoft.AspNetCore.Blazor.Components.BindMethods.GetValue(
@ -18,7 +17,5 @@ Document -
ComponentAttributeExtensionNode - (48:1,17 [1] x:\dir\subdir\Test\TestComponent.cshtml) - vChanged -
CSharpExpression -
IntermediateToken - - CSharp - Microsoft.AspNetCore.Blazor.Components.BindMethods.SetValueHandler(__value => y = __value, y)
ComponentBodyExtensionNode -
ComponentCloseExtensionNode -
CSharpCode - (67:2,12 [24] x:\dir\subdir\Test\TestComponent.cshtml)
IntermediateToken - (67:2,12 [24] x:\dir\subdir\Test\TestComponent.cshtml) - CSharp - \n string y = null;\n

View File

@ -8,15 +8,17 @@ Document -
MethodDeclaration - - protected override - void - BuildRenderTree
CSharpCode -
IntermediateToken - - CSharp - base.BuildRenderTree(builder);
HtmlContent - (0:0,0 [146] x:\dir\subdir\Test\TestComponent.cshtml)
IntermediateToken - (0:0,0 [5] x:\dir\subdir\Test\TestComponent.cshtml) - Html - <div>
IntermediateToken - (5:0,5 [6] x:\dir\subdir\Test\TestComponent.cshtml) - Html - \n
IntermediateToken - (11:1,4 [7] x:\dir\subdir\Test\TestComponent.cshtml) - Html - <script
IntermediateToken - (18:1,11 [18] x:\dir\subdir\Test\TestComponent.cshtml) - Html - src='some/url.js'
IntermediateToken - (36:1,29 [17] x:\dir\subdir\Test\TestComponent.cshtml) - Html - anotherattribute
IntermediateToken - (53:1,46 [24] x:\dir\subdir\Test\TestComponent.cshtml) - Html - suppress-error='BL9992'
IntermediateToken - (77:1,70 [1] x:\dir\subdir\Test\TestComponent.cshtml) - Html - >
IntermediateToken - (78:1,71 [49] x:\dir\subdir\Test\TestComponent.cshtml) - Html - \n some text\n some more text\n
IntermediateToken - (127:4,4 [9] x:\dir\subdir\Test\TestComponent.cshtml) - Html - </script>
IntermediateToken - (136:4,13 [2] x:\dir\subdir\Test\TestComponent.cshtml) - Html - \n
IntermediateToken - (138:5,0 [6] x:\dir\subdir\Test\TestComponent.cshtml) - Html - </div>
HtmlElement - (0:0,0 [144] x:\dir\subdir\Test\TestComponent.cshtml) - div
HtmlContent - (5:0,5 [6] x:\dir\subdir\Test\TestComponent.cshtml)
IntermediateToken - (5:0,5 [6] x:\dir\subdir\Test\TestComponent.cshtml) - Html - \n
HtmlElement - (11:1,4 [125] x:\dir\subdir\Test\TestComponent.cshtml) - script
HtmlAttribute - - -
HtmlAttributeValue - -
IntermediateToken - - Html - some/url.js
HtmlAttribute - - -
HtmlAttributeValue - -
IntermediateToken - - Html -
HtmlContent - (78:1,71 [49] x:\dir\subdir\Test\TestComponent.cshtml)
IntermediateToken - (78:1,71 [49] x:\dir\subdir\Test\TestComponent.cshtml) - Html - \n some text\n some more text\n
HtmlContent - (136:4,13 [2] x:\dir\subdir\Test\TestComponent.cshtml)
IntermediateToken - (136:4,13 [2] x:\dir\subdir\Test\TestComponent.cshtml) - Html - \n

View File

@ -8,10 +8,10 @@ Document -
MethodDeclaration - - protected override - void - BuildRenderTree
CSharpCode -
IntermediateToken - - CSharp - base.BuildRenderTree(builder);
HtmlContent - (0:0,0 [18] x:\dir\subdir\Test\TestComponent.cshtml)
IntermediateToken - (0:0,0 [4] x:\dir\subdir\Test\TestComponent.cshtml) - Html - <h1>
IntermediateToken - (4:0,4 [5] x:\dir\subdir\Test\TestComponent.cshtml) - Html - Hello
IntermediateToken - (9:0,9 [5] x:\dir\subdir\Test\TestComponent.cshtml) - Html - </h1>
HtmlElement - (0:0,0 [14] x:\dir\subdir\Test\TestComponent.cshtml) - h1
HtmlContent - (4:0,4 [5] x:\dir\subdir\Test\TestComponent.cshtml)
IntermediateToken - (4:0,4 [5] x:\dir\subdir\Test\TestComponent.cshtml) - Html - Hello
HtmlContent - (14:0,14 [4] x:\dir\subdir\Test\TestComponent.cshtml)
IntermediateToken - (14:0,14 [4] x:\dir\subdir\Test\TestComponent.cshtml) - Html - \n\n
CSharpExpression - (20:2,2 [10] x:\dir\subdir\Test\TestComponent.cshtml)
IntermediateToken - (20:2,2 [10] x:\dir\subdir\Test\TestComponent.cshtml) - CSharp - "My value"

View File

@ -8,12 +8,9 @@ Document -
MethodDeclaration - - protected override - void - BuildRenderTree
CSharpCode -
IntermediateToken - - CSharp - base.BuildRenderTree(builder);
HtmlContent - (31:1,0 [18] x:\dir\subdir\Test\TestComponent.cshtml)
IntermediateToken - (31:1,0 [4] x:\dir\subdir\Test\TestComponent.cshtml) - Html - <h1>
IntermediateToken - (35:1,4 [5] x:\dir\subdir\Test\TestComponent.cshtml) - Html - Hello
IntermediateToken - (40:1,9 [5] x:\dir\subdir\Test\TestComponent.cshtml) - Html - </h1>
HtmlElement - (31:1,0 [14] x:\dir\subdir\Test\TestComponent.cshtml) - h1
HtmlContent - (35:1,4 [5] x:\dir\subdir\Test\TestComponent.cshtml)
IntermediateToken - (35:1,4 [5] x:\dir\subdir\Test\TestComponent.cshtml) - Html - Hello
HtmlContent - (45:1,14 [4] x:\dir\subdir\Test\TestComponent.cshtml)
IntermediateToken - (45:1,14 [4] x:\dir\subdir\Test\TestComponent.cshtml) - Html - \n\n
TagHelper - (49:3,0 [22] x:\dir\subdir\Test\TestComponent.cshtml) - SomeOtherComponent - TagMode.SelfClosing
ComponentOpenExtensionNode - - Test.SomeOtherComponent
ComponentBodyExtensionNode -
ComponentCloseExtensionNode -
ComponentExtensionNode - (49:3,0 [22] x:\dir\subdir\Test\TestComponent.cshtml) - SomeOtherComponent - Test.SomeOtherComponent

View File

@ -9,7 +9,6 @@ Document -
MethodDeclaration - - protected override - void - BuildRenderTree
CSharpCode -
IntermediateToken - - CSharp - base.BuildRenderTree(builder);
HtmlContent - (0:0,0 [18] x:\dir\subdir\Test\TestComponent.cshtml)
IntermediateToken - (0:0,0 [4] x:\dir\subdir\Test\TestComponent.cshtml) - Html - <h1>
IntermediateToken - (4:0,4 [5] x:\dir\subdir\Test\TestComponent.cshtml) - Html - Hello
IntermediateToken - (9:0,9 [5] x:\dir\subdir\Test\TestComponent.cshtml) - Html - </h1>
HtmlElement - (0:0,0 [14] x:\dir\subdir\Test\TestComponent.cshtml) - h1
HtmlContent - (4:0,4 [5] x:\dir\subdir\Test\TestComponent.cshtml)
IntermediateToken - (4:0,4 [5] x:\dir\subdir\Test\TestComponent.cshtml) - Html - Hello

View File

@ -0,0 +1,446 @@
// 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.Generic;
using System.Linq;
using Microsoft.AspNetCore.Razor.Language;
using Microsoft.AspNetCore.Razor.Language.Intermediate;
using Xunit;
namespace Microsoft.AspNetCore.Blazor.Razor
{
public class ComponentDocumentRewritePassTest
{
public ComponentDocumentRewritePassTest()
{
var test = TagHelperDescriptorBuilder.Create("test", "test");
test.TagMatchingRule(b => b.TagName = "test");
TagHelpers = new List<TagHelperDescriptor>()
{
test.Build(),
};
Pass = new ComponentDocumentRewritePass();
Engine = RazorProjectEngine.Create(
BlazorExtensionInitializer.DefaultConfiguration,
RazorProjectFileSystem.Create(Environment.CurrentDirectory),
b =>
{
b.Features.Add(new ComponentDocumentClassifierPass());
b.Features.Add(Pass);
b.Features.Add(new StaticTagHelperFeature() { TagHelpers = TagHelpers, });
}).Engine;
}
private RazorEngine Engine { get; }
private ComponentDocumentRewritePass Pass { get; }
private List<TagHelperDescriptor> TagHelpers { get; }
[Fact]
public void Execute_RewritesHtml_Basic()
{
// Arrange
var document = CreateDocument(@"
<html>
<head cool=""beans"">
Hello, World!
</head>
</html>");
var documentNode = Lower(document);
// Act
Pass.Execute(document, documentNode);
// Assert
var method = documentNode.FindPrimaryMethod();
Assert.Collection(
method.Children,
c => Assert.IsType<CSharpCodeIntermediateNode>(c),
c => NodeAssert.Whitespace(c),
c => NodeAssert.Element(c, "html"));
var html = NodeAssert.Element(method.Children[2], "html");
Assert.Equal(2, html.Source.Value.AbsoluteIndex);
Assert.Equal(1, html.Source.Value.LineIndex);
Assert.Equal(0, html.Source.Value.CharacterIndex);
Assert.Equal(68, html.Source.Value.Length);
Assert.Collection(
html.Children,
c => NodeAssert.Whitespace(c),
c => NodeAssert.Element(c, "head"),
c => NodeAssert.Whitespace(c));
var head = NodeAssert.Element(html.Children[1], "head");
Assert.Equal(12, head.Source.Value.AbsoluteIndex);
Assert.Equal(2, head.Source.Value.LineIndex);
Assert.Equal(2, head.Source.Value.CharacterIndex);
Assert.Equal(49, head.Source.Value.Length);
Assert.Collection(
head.Children,
c => NodeAssert.Attribute(c, "cool", "beans"),
c => NodeAssert.Content(c, "Hello, World!"));
}
[Fact]
public void Execute_RewritesHtml_Mixed()
{
// Arrange
var document = CreateDocument(@"
<html>
<head cool=""beans"" csharp=""@yes"" mixed=""hi @there"">
</head>
</html>");
var documentNode = Lower(document);
// Act
Pass.Execute(document, documentNode);
// Assert
var method = documentNode.FindPrimaryMethod();
Assert.Collection(
method.Children,
c => Assert.IsType<CSharpCodeIntermediateNode>(c),
c => NodeAssert.Whitespace(c),
c => NodeAssert.Element(c, "html"));
var html = NodeAssert.Element(method.Children[2], "html");
Assert.Equal(2, html.Source.Value.AbsoluteIndex);
Assert.Equal(1, html.Source.Value.LineIndex);
Assert.Equal(0, html.Source.Value.CharacterIndex);
Assert.Equal(81, html.Source.Value.Length);
Assert.Collection(
html.Children,
c => NodeAssert.Whitespace(c),
c => NodeAssert.Element(c, "head"),
c => NodeAssert.Whitespace(c));
var head = NodeAssert.Element(html.Children[1], "head");
Assert.Equal(12, head.Source.Value.AbsoluteIndex);
Assert.Equal(2, head.Source.Value.LineIndex);
Assert.Equal(2, head.Source.Value.CharacterIndex);
Assert.Equal(62, head.Source.Value.Length);
Assert.Collection(
head.Children,
c => NodeAssert.Attribute(c, "cool", "beans"),
c => NodeAssert.CSharpAttribute(c, "csharp", "yes"),
c => Assert.IsType<HtmlAttributeIntermediateNode>(c),
c => NodeAssert.Whitespace(c));
var mixed = Assert.IsType<HtmlAttributeIntermediateNode>(head.Children[2]);
Assert.Collection(
mixed.Children,
c => Assert.IsType<HtmlAttributeValueIntermediateNode>(c),
c => Assert.IsType<CSharpExpressionAttributeValueIntermediateNode>(c));
}
[Fact]
public void Execute_RewritesHtml_WithCode()
{
// Arrange
var document = CreateDocument(@"
<html>
@if (some_bool)
{
<head cool=""beans"">
@hello
</head>
}
</html>");
var documentNode = Lower(document);
// Act
Pass.Execute(document, documentNode);
// Assert
var method = documentNode.FindPrimaryMethod();
Assert.Collection(
method.Children,
c => Assert.IsType<CSharpCodeIntermediateNode>(c),
c => NodeAssert.Whitespace(c),
c => NodeAssert.Element(c, "html"));
var html = NodeAssert.Element(method.Children[2], "html");
Assert.Equal(2, html.Source.Value.AbsoluteIndex);
Assert.Equal(1, html.Source.Value.LineIndex);
Assert.Equal(0, html.Source.Value.CharacterIndex);
Assert.Equal(90, html.Source.Value.Length);
Assert.Collection(
html.Children,
c => NodeAssert.Whitespace(c),
c => Assert.IsType<CSharpCodeIntermediateNode>(c),
c => Assert.IsType<CSharpCodeIntermediateNode>(c),
c => NodeAssert.Whitespace(c),
c => NodeAssert.Element(c, "head"),
c => NodeAssert.Whitespace(c),
c => Assert.IsType<CSharpCodeIntermediateNode>(c));
var head = NodeAssert.Element(html.Children[4], "head");
Assert.Equal(36, head.Source.Value.AbsoluteIndex);
Assert.Equal(4, head.Source.Value.LineIndex);
Assert.Equal(2, head.Source.Value.CharacterIndex);
Assert.Equal(42, head.Source.Value.Length);
Assert.Collection(
head.Children,
c => NodeAssert.Attribute(c, "cool", "beans"),
c => NodeAssert.Whitespace(c),
c => Assert.IsType<CSharpExpressionIntermediateNode>(c),
c => NodeAssert.Whitespace(c));
}
[Fact]
public void Execute_RewritesHtml_TagHelper()
{
// Arrange
var document = CreateDocument(@"
@addTagHelper ""*, test""
<html>
<test>
<head cool=""beans"">
Hello, World!
</head>
</test>
</html>");
var documentNode = Lower(document);
// Act
Pass.Execute(document, documentNode);
// Assert
var method = documentNode.FindPrimaryMethod();
Assert.Collection(
method.Children,
c => Assert.IsType<CSharpCodeIntermediateNode>(c),
c => NodeAssert.Whitespace(c),
c => Assert.IsType<DirectiveIntermediateNode>(c),
c => NodeAssert.Element(c, "html"));
var html = NodeAssert.Element(method.Children[3], "html");
Assert.Equal(27, html.Source.Value.AbsoluteIndex);
Assert.Equal(2, html.Source.Value.LineIndex);
Assert.Equal(0, html.Source.Value.CharacterIndex);
Assert.Equal(95, html.Source.Value.Length);
Assert.Collection(
html.Children,
c => NodeAssert.Whitespace(c),
c => Assert.IsType<TagHelperIntermediateNode>(c),
c => NodeAssert.Whitespace(c));
var body = html.Children
.OfType<TagHelperIntermediateNode>().Single().Children
.OfType<TagHelperBodyIntermediateNode>().Single();
Assert.Collection(
body.Children,
c => NodeAssert.Whitespace(c),
c => NodeAssert.Element(c, "head"),
c => NodeAssert.Whitespace(c));
var head = body.Children[1];
Assert.Equal(49, head.Source.Value.AbsoluteIndex);
Assert.Equal(4, head.Source.Value.LineIndex);
Assert.Equal(4, head.Source.Value.CharacterIndex);
Assert.Equal(53, head.Source.Value.Length);
Assert.Collection(
head.Children,
c => NodeAssert.Attribute(c, "cool", "beans"),
c => NodeAssert.Content(c, "Hello, World!"));
}
[Fact]
public void Execute_RewritesHtml_UnbalancedClosingTagAtTopLevel()
{
// Arrange
var document = CreateDocument(@"
</html>");
var documentNode = Lower(document);
// Act
Pass.Execute(document, documentNode);
// Assert
var method = documentNode.FindPrimaryMethod();
Assert.Collection(
method.Children,
c => Assert.IsType<CSharpCodeIntermediateNode>(c),
c => NodeAssert.Whitespace(c),
c => NodeAssert.Element(c, "html"));
var html = NodeAssert.Element(method.Children[2], "html");
Assert.Equal(2, html.Source.Value.AbsoluteIndex);
Assert.Equal(1, html.Source.Value.LineIndex);
Assert.Equal(0, html.Source.Value.CharacterIndex);
Assert.Equal(7, html.Source.Value.Length);
var diagnostic = Assert.Single(html.Diagnostics);
Assert.Same(BlazorDiagnosticFactory.UnexpectedClosingTag.Id, diagnostic.Id);
Assert.Equal(html.Source, diagnostic.Span);
}
[Fact]
public void Execute_RewritesHtml_MismatchedClosingTag()
{
// Arrange
var document = CreateDocument(@"
<html>
<div>
</span>
</html>");
var documentNode = Lower(document);
// Act
Pass.Execute(document, documentNode);
// Assert
var method = documentNode.FindPrimaryMethod();
Assert.Collection(
method.Children,
c => Assert.IsType<CSharpCodeIntermediateNode>(c),
c => NodeAssert.Whitespace(c),
c => NodeAssert.Element(c, "html"));
var html = NodeAssert.Element(method.Children[2], "html");
Assert.Collection(
html.Children,
c => NodeAssert.Whitespace(c),
c => NodeAssert.Element(c, "div"),
c => NodeAssert.Whitespace(c));
var div = NodeAssert.Element(html.Children[1], "div");
Assert.Equal(12, div.Source.Value.AbsoluteIndex);
Assert.Equal(2, div.Source.Value.LineIndex);
Assert.Equal(2, div.Source.Value.CharacterIndex);
Assert.Equal(5, div.Source.Value.Length);
var diagnostic = Assert.Single(div.Diagnostics);
Assert.Same(BlazorDiagnosticFactory.MismatchedClosingTag.Id, diagnostic.Id);
Assert.Equal(21,diagnostic.Span.AbsoluteIndex);
Assert.Equal(3, diagnostic.Span.LineIndex);
Assert.Equal(2, diagnostic.Span.CharacterIndex);
Assert.Equal(7, diagnostic.Span.Length);
}
[Fact]
public void Execute_RewritesHtml_MalformedHtmlAtEnd()
{
// Arrange
var document = CreateDocument(@"
<ht");
var documentNode = Lower(document);
// Act
Pass.Execute(document, documentNode);
// Assert
var method = documentNode.FindPrimaryMethod();
Assert.Collection(
method.Children,
c => Assert.IsType<CSharpCodeIntermediateNode>(c),
c => NodeAssert.Whitespace(c),
c => NodeAssert.Content(c, "<ht"));
var content = NodeAssert.Content(method.Children[2], "<ht");
var diagnostic = Assert.Single(content.Diagnostics);
Assert.Same(BlazorDiagnosticFactory.InvalidHtmlContent.Id, diagnostic.Id);
Assert.Equal(2, diagnostic.Span.AbsoluteIndex);
Assert.Equal(1, diagnostic.Span.LineIndex);
Assert.Equal(0, diagnostic.Span.CharacterIndex);
Assert.Equal(3, diagnostic.Span.Length);
}
[Fact]
public void Execute_RewritesHtml_UnclosedTags()
{
// Arrange
var document = CreateDocument(@"
<html>
<div>");
var documentNode = Lower(document);
// Act
Pass.Execute(document, documentNode);
// Assert
var method = documentNode.FindPrimaryMethod();
Assert.Collection(
method.Children,
c => Assert.IsType<CSharpCodeIntermediateNode>(c),
c => NodeAssert.Whitespace(c),
c => NodeAssert.Element(c, "html"));
var html = NodeAssert.Element(method.Children[2], "html");
Assert.Collection(
html.Children,
c => NodeAssert.Whitespace(c),
c => NodeAssert.Element(c, "div"));
var diagnostic = Assert.Single(html.Diagnostics);
Assert.Same(BlazorDiagnosticFactory.UnclosedTag.Id, diagnostic.Id);
Assert.Equal(2, diagnostic.Span.AbsoluteIndex);
Assert.Equal(1, diagnostic.Span.LineIndex);
Assert.Equal(0, diagnostic.Span.CharacterIndex);
Assert.Equal(6, diagnostic.Span.Length);
var div = NodeAssert.Element(html.Children[1], "div");
diagnostic = Assert.Single(div.Diagnostics);
Assert.Same(BlazorDiagnosticFactory.UnclosedTag.Id, diagnostic.Id);
Assert.Equal(12, diagnostic.Span.AbsoluteIndex);
Assert.Equal(2, diagnostic.Span.LineIndex);
Assert.Equal(2, diagnostic.Span.CharacterIndex);
Assert.Equal(5, diagnostic.Span.Length);
}
private RazorCodeDocument CreateDocument(string content)
{
// Normalize newlines since we are testing lengths of things.
content = content.Replace("\r", "");
content = content.Replace("\n", "\r\n");
var source = RazorSourceDocument.Create(content, "test.cshtml");
return RazorCodeDocument.Create(source);
}
private DocumentIntermediateNode Lower(RazorCodeDocument codeDocument)
{
for (var i = 0; i < Engine.Phases.Count; i++)
{
var phase = Engine.Phases[i];
if (phase is IRazorDocumentClassifierPhase)
{
break;
}
phase.Execute(codeDocument);
}
var document = codeDocument.GetDocumentIntermediateNode();
Engine.Features.OfType<ComponentDocumentClassifierPass>().Single().Execute(codeDocument, document);
return document;
}
private class StaticTagHelperFeature : ITagHelperFeature
{
public RazorEngine Engine { get; set; }
public List<TagHelperDescriptor> TagHelpers { get; set; }
public IReadOnlyList<TagHelperDescriptor> GetDescriptors()
{
return TagHelpers;
}
}
}
}

View File

@ -10,6 +10,7 @@
used to compile this assembly.
-->
<PreserveCompilationContext>true</PreserveCompilationContext>
<LangVersion>7.1</LangVersion>
</PropertyGroup>
<ItemGroup>

View File

@ -0,0 +1,126 @@
// 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.Text;
using Microsoft.AspNetCore.Razor.Language.Intermediate;
using Xunit;
namespace Microsoft.AspNetCore.Blazor.Razor
{
internal static class NodeAssert
{
public static HtmlAttributeIntermediateNode Attribute(IntermediateNode node, string attributeName, string attributeValue)
{
Assert.NotNull(node);
var attributeNode = Assert.IsType<HtmlAttributeIntermediateNode>(node);
Assert.Equal(attributeName, attributeNode.AttributeName);
var attributeValueNode = Assert.IsType<HtmlAttributeValueIntermediateNode>(Assert.Single(attributeNode.Children));
var actual = new StringBuilder();
for (var i = 0; i < attributeValueNode.Children.Count; i++)
{
var token = Assert.IsType<IntermediateToken>(attributeValueNode.Children[i]);
Assert.Equal(TokenKind.Html, token.Kind);
actual.Append(token.Content);
}
Assert.Equal(attributeValue, actual.ToString());
return attributeNode;
}
public static HtmlAttributeIntermediateNode Attribute(IntermediateNodeCollection nodes, string attributeName, string attributeValue)
{
Assert.NotNull(nodes);
return Attribute(Assert.Single(nodes), attributeName, attributeValue);
}
public static HtmlContentIntermediateNode Content(IntermediateNode node, string content, bool trim = true)
{
Assert.NotNull(node);
var contentNode = Assert.IsType<HtmlContentIntermediateNode>(node);
var actual = new StringBuilder();
for (var i = 0; i < contentNode.Children.Count; i++)
{
var token = Assert.IsType<IntermediateToken>(contentNode.Children[i]);
Assert.Equal(TokenKind.Html, token.Kind);
actual.Append(token.Content);
}
Assert.Equal(content, trim ? actual.ToString().Trim() : actual.ToString());
return contentNode;
}
public static HtmlContentIntermediateNode Content(IntermediateNodeCollection nodes, string content, bool trim = true)
{
Assert.NotNull(nodes);
return Content(Assert.Single(nodes), content, trim);
}
public static HtmlAttributeIntermediateNode CSharpAttribute(IntermediateNode node, string attributeName, string attributeValue)
{
Assert.NotNull(node);
var attributeNode = Assert.IsType<HtmlAttributeIntermediateNode>(node);
Assert.Equal(attributeName, attributeNode.AttributeName);
var attributeValueNode = Assert.IsType<CSharpExpressionAttributeValueIntermediateNode>(Assert.Single(attributeNode.Children));
var actual = new StringBuilder();
for (var i = 0; i < attributeValueNode.Children.Count; i++)
{
var token = Assert.IsType<IntermediateToken>(attributeValueNode.Children[i]);
Assert.Equal(TokenKind.CSharp, token.Kind);
actual.Append(token.Content);
}
Assert.Equal(attributeValue, actual.ToString());
return attributeNode;
}
public static HtmlAttributeIntermediateNode CSharpAttribute(IntermediateNodeCollection nodes, string attributeName, string attributeValue)
{
Assert.NotNull(nodes);
return Attribute(Assert.Single(nodes), attributeName, attributeValue);
}
public static HtmlElementIntermediateNode Element(IntermediateNode node, string tagName)
{
Assert.NotNull(node);
var elementNode = Assert.IsType<HtmlElementIntermediateNode>(node);
Assert.Equal(tagName, elementNode.TagName);
return elementNode;
}
public static HtmlElementIntermediateNode Element(IntermediateNodeCollection nodes, string tagName)
{
Assert.NotNull(nodes);
return Element(Assert.Single(nodes), tagName);
}
public static HtmlContentIntermediateNode Whitespace(IntermediateNode node)
{
Assert.NotNull(node);
var contentNode = Assert.IsType<HtmlContentIntermediateNode>(node);
for (var i = 0; i < contentNode.Children.Count; i++)
{
var token = Assert.IsType<IntermediateToken>(contentNode.Children[i]);
Assert.Equal(TokenKind.Html, token.Kind);
Assert.True(string.IsNullOrWhiteSpace(token.Content));
}
return contentNode;
}
public static HtmlContentIntermediateNode Whitespace(IntermediateNodeCollection nodes)
{
Assert.NotNull(nodes);
return Whitespace(Assert.Single(nodes));
}
}
}