Remove old <c:Foo> syntax
This commit is contained in:
parent
d175b4d38a
commit
ffadeecb45
|
|
@ -11,19 +11,6 @@ namespace Microsoft.AspNetCore.Blazor.Razor
|
|||
{
|
||||
internal static class BlazorDiagnosticFactory
|
||||
{
|
||||
public static readonly RazorDiagnosticDescriptor InvalidComponentAttributeSyntax = new RazorDiagnosticDescriptor(
|
||||
"BL9980",
|
||||
() => "Wrong syntax for '{0}' on '{1}': As a temporary " +
|
||||
$"limitation, component attributes must be expressed with C# syntax. For example, " +
|
||||
$"SomeParam=@(\"Some value\") is allowed, but SomeParam=\"Some value\" is not.",
|
||||
RazorDiagnosticSeverity.Error);
|
||||
|
||||
public static RazorDiagnostic Create_InvalidComponentAttributeSynx(TextPosition position, SourceSpan? span, string attributeName, string componentName)
|
||||
{
|
||||
span = CalculateSourcePosition(span, position);
|
||||
return RazorDiagnostic.Create(InvalidComponentAttributeSyntax, span ?? SourceSpan.Undefined, attributeName, componentName);
|
||||
}
|
||||
|
||||
public static readonly RazorDiagnosticDescriptor UnexpectedClosingTag = new RazorDiagnosticDescriptor(
|
||||
"BL9981",
|
||||
() => "Unexpected closing tag '{0}' with no matching start tag.",
|
||||
|
|
|
|||
|
|
@ -219,38 +219,18 @@ namespace Microsoft.AspNetCore.Blazor.Razor
|
|||
{
|
||||
var nextTag = nextToken.AsTag();
|
||||
var tagNameOriginalCase = GetTagNameWithOriginalCase(originalHtmlContent, nextTag);
|
||||
var isComponent = TryGetComponentTypeNameFromTagName(tagNameOriginalCase, out var componentTypeName);
|
||||
|
||||
if (nextToken.Type == HtmlTokenType.StartTag)
|
||||
{
|
||||
_scopeStack.IncrementCurrentScopeChildCount(context);
|
||||
if (isComponent)
|
||||
{
|
||||
codeWriter
|
||||
.WriteStartMethodInvocation($"{_scopeStack.BuilderVarName}.{nameof(BlazorApi.RenderTreeBuilder.OpenComponent)}<{componentTypeName}>")
|
||||
.Write((_sourceSequence++).ToString())
|
||||
.WriteEndMethodInvocation();
|
||||
}
|
||||
else
|
||||
{
|
||||
codeWriter
|
||||
.WriteStartMethodInvocation($"{_scopeStack.BuilderVarName}.{nameof(BlazorApi.RenderTreeBuilder.OpenElement)}")
|
||||
.Write((_sourceSequence++).ToString())
|
||||
.WriteParameterSeparator()
|
||||
.WriteStringLiteral(nextTag.Data)
|
||||
.WriteEndMethodInvocation();
|
||||
}
|
||||
|
||||
if (isComponent && nextTag.Attributes.Count > 0)
|
||||
{
|
||||
var diagnostic = BlazorDiagnosticFactory.Create_InvalidComponentAttributeSynx(
|
||||
nextTag.Position,
|
||||
node.Source,
|
||||
nextTag.Attributes[0].Key,
|
||||
tagNameOriginalCase);
|
||||
throw new RazorCompilerException(diagnostic);
|
||||
}
|
||||
|
||||
codeWriter
|
||||
.WriteStartMethodInvocation($"{_scopeStack.BuilderVarName}.{nameof(BlazorApi.RenderTreeBuilder.OpenElement)}")
|
||||
.Write((_sourceSequence++).ToString())
|
||||
.WriteParameterSeparator()
|
||||
.WriteStringLiteral(nextTag.Data)
|
||||
.WriteEndMethodInvocation();
|
||||
|
||||
foreach (var attribute in nextTag.Attributes)
|
||||
{
|
||||
WriteAttribute(codeWriter, attribute.Key, attribute.Value);
|
||||
|
|
@ -274,25 +254,20 @@ namespace Microsoft.AspNetCore.Blazor.Razor
|
|||
_currentElementAttributeTokens.Clear();
|
||||
}
|
||||
|
||||
_scopeStack.OpenScope(
|
||||
tagName: isComponent ? tagNameOriginalCase : nextTag.Data,
|
||||
isComponent: isComponent);
|
||||
_scopeStack.OpenScope( tagName: nextTag.Data, isComponent: false);
|
||||
}
|
||||
|
||||
if (nextToken.Type == HtmlTokenType.EndTag
|
||||
|| nextTag.IsSelfClosing
|
||||
|| (!isComponent && htmlVoidElementsLookup.Contains(nextTag.Data)))
|
||||
|| htmlVoidElementsLookup.Contains(nextTag.Data))
|
||||
{
|
||||
_scopeStack.CloseScope(
|
||||
context: context,
|
||||
tagName: isComponent ? tagNameOriginalCase : nextTag.Data,
|
||||
isComponent: isComponent,
|
||||
tagName: nextTag.Data,
|
||||
isComponent: false,
|
||||
source: CalculateSourcePosition(node.Source, nextToken.Position));
|
||||
var closeMethodName = isComponent
|
||||
? nameof(BlazorApi.RenderTreeBuilder.CloseComponent)
|
||||
: nameof(BlazorApi.RenderTreeBuilder.CloseElement);
|
||||
codeWriter
|
||||
.WriteStartMethodInvocation($"{_scopeStack.BuilderVarName}.{closeMethodName}")
|
||||
.WriteStartMethodInvocation($"{_scopeStack.BuilderVarName}.{BlazorApi.RenderTreeBuilder.CloseElement}")
|
||||
.WriteEndMethodInvocation();
|
||||
}
|
||||
break;
|
||||
|
|
@ -559,32 +534,6 @@ namespace Microsoft.AspNetCore.Blazor.Razor
|
|||
return document.Substring(tagToken.Position.Position + offset, tagToken.Name.Length);
|
||||
}
|
||||
|
||||
private bool TryGetComponentTypeNameFromTagName(string tagName, out string componentTypeName)
|
||||
{
|
||||
// Determine whether 'tagName' represents a Blazor component, and if so, return the
|
||||
// name of the component's .NET type. The type name doesn't have to be fully-qualified,
|
||||
// because it's up to the developer to put in whatever @using statements are required.
|
||||
|
||||
// TODO: Remove this temporary syntax and make the compiler smart enough to infer it
|
||||
// directly. This could either work by having a configurable list of non-component tag names
|
||||
// (which would default to all standard HTML elements, plus anything that contains a '-'
|
||||
// character, since those are mandatory for custom HTML elements and prohibited for .NET
|
||||
// type names), or better, could somehow know what .NET types are in scope at this point
|
||||
// in the compilation and treat everything else as a non-component element.
|
||||
|
||||
const string temporaryPrefix = "c:";
|
||||
if (tagName.StartsWith(temporaryPrefix, StringComparison.Ordinal))
|
||||
{
|
||||
componentTypeName = tagName.Substring(temporaryPrefix.Length);
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
componentTypeName = null;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private void WriteAttribute(CodeWriter codeWriter, string key, object value)
|
||||
{
|
||||
BeginWriteAttribute(codeWriter, key);
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@
|
|||
<div class='container-fluid'>
|
||||
<div class='row'>
|
||||
<div class='col-sm-3'>
|
||||
<c:NavMenu />
|
||||
<NavMenu />
|
||||
</div>
|
||||
<div class='col-sm-9'>
|
||||
@Body
|
||||
|
|
|
|||
|
|
@ -13,20 +13,19 @@
|
|||
<div class='navbar-collapse collapse'>
|
||||
<ul class='nav navbar-nav'>
|
||||
<li>
|
||||
<!-- The 'c:' prefix and parens are workarounds for a Razor compilation issue and will be removed soon. -->
|
||||
<c:NavLink href=@("/")>
|
||||
<NavLink href="/">
|
||||
<span class='glyphicon glyphicon-home'></span> Home
|
||||
</c:NavLink>
|
||||
</NavLink>
|
||||
</li>
|
||||
<li>
|
||||
<c:NavLink href=@("/counter")>
|
||||
<NavLink href="/counter">
|
||||
<span class='glyphicon glyphicon-education'></span> Counter
|
||||
</c:NavLink>
|
||||
</NavLink>
|
||||
</li>
|
||||
<li>
|
||||
<c:NavLink href=@("/fetchdata")>
|
||||
<NavLink href="/fetchdata">
|
||||
<span class='glyphicon glyphicon-th-list'></span> Fetch data
|
||||
</c:NavLink>
|
||||
</NavLink>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@
|
|||
<div class='container-fluid'>
|
||||
<div class='row'>
|
||||
<div class='col-sm-3'>
|
||||
<c:NavMenu />
|
||||
<NavMenu />
|
||||
</div>
|
||||
<div class='col-sm-9'>
|
||||
@Body
|
||||
|
|
|
|||
|
|
@ -13,20 +13,19 @@
|
|||
<div class='navbar-collapse collapse'>
|
||||
<ul class='nav navbar-nav'>
|
||||
<li>
|
||||
<!-- The 'c:' prefix and parens are workarounds for a Razor compilation issue and will be removed soon. -->
|
||||
<c:NavLink href=@("/")>
|
||||
<NavLink href="/">
|
||||
<span class='glyphicon glyphicon-home'></span> Home
|
||||
</c:NavLink>
|
||||
</NavLink>
|
||||
</li>
|
||||
<li>
|
||||
<c:NavLink href=@("/counter")>
|
||||
<NavLink href="/counter">
|
||||
<span class='glyphicon glyphicon-education'></span> Counter
|
||||
</c:NavLink>
|
||||
</NavLink>
|
||||
</li>
|
||||
<li>
|
||||
<c:NavLink href=@("/fetchdata")>
|
||||
<NavLink href="/fetchdata">
|
||||
<span class='glyphicon glyphicon-th-list'></span> Fetch data
|
||||
</c:NavLink>
|
||||
</NavLink>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -7,44 +7,6 @@ namespace Microsoft.AspNetCore.Blazor.Build.Test
|
|||
{
|
||||
public class DiagnosticRazorIntegrationTest : RazorIntegrationTestBase
|
||||
{
|
||||
[Fact]
|
||||
public void TemporaryComponentSyntaxRejectsParametersExpressedAsPlainHtmlAttributes()
|
||||
{
|
||||
// This is a temporary syntax restriction. Currently you can write:
|
||||
// <c:MyComponent MyParam=@("My value") />
|
||||
// ... but are *not* allowed to write:
|
||||
// <c:MyComponent MyParam="My value" />
|
||||
// This is because until we get the improved taghelper-based tooling,
|
||||
// we're using AngleSharp to parse the plain HTML attributes, and it
|
||||
// suffers from limitations:
|
||||
// * Loses the casing of attribute names (MyParam becomes myparam)
|
||||
// * Doesn't recognize MyBool=true as an bool (becomes mybool="true"),
|
||||
// plus equivalent for other primitives like enum values
|
||||
// So to avoid people getting runtime errors, we're currently imposing
|
||||
// the compile-time restriction that component params have to be given
|
||||
// as C# expressions, e.g., MyBool=@true and MyString=@("Hello")
|
||||
|
||||
// Arrange/Act
|
||||
var result = CompileToCSharp(
|
||||
$"Line 1\n" +
|
||||
$"Some text <c:MyComponent MyParam=\"My value\" />");
|
||||
|
||||
// Assert
|
||||
Assert.Collection(
|
||||
result.Diagnostics,
|
||||
item =>
|
||||
{
|
||||
Assert.Equal("BL9980", item.Id);
|
||||
Assert.Equal(
|
||||
$"Wrong syntax for 'myparam' on 'c:MyComponent': As a temporary " +
|
||||
$"limitation, component attributes must be expressed with C# syntax. For " +
|
||||
$"example, SomeParam=@(\"Some value\") is allowed, but SomeParam=\"Some value\" " +
|
||||
$"is not.", item.GetMessage());
|
||||
Assert.Equal(1, item.Span.LineIndex);
|
||||
Assert.Equal(10, item.Span.CharacterIndex);
|
||||
});
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void RejectsEndTagWithNoStartTag()
|
||||
{
|
||||
|
|
|
|||
Loading…
Reference in New Issue