This changes the bind lowering pass to be more tolerant of unexpected
and invalid content.
This commit is contained in:
Ryan Nowak 2018-07-05 11:06:11 -07:00
parent 844e38e641
commit 8724b84a14
2 changed files with 42 additions and 7 deletions

View File

@ -1,4 +1,4 @@
// Copyright (c) .NET Foundation. All rights reserved. // 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. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System.Collections.Generic; using System.Collections.Generic;
@ -478,19 +478,30 @@ namespace Microsoft.AspNetCore.Blazor.Razor
{ {
// This case can be hit for a 'string' attribute. We want to turn it into // This case can be hit for a 'string' attribute. We want to turn it into
// an expression. // an expression.
var content = "\"" + ((IntermediateToken)htmlContentNode.Children.Single()).Content + "\""; var content = "\"" + string.Join(string.Empty, htmlContentNode.Children.OfType<IntermediateToken>().Select(t => t.Content)) + "\"";
return new IntermediateToken() { Kind = TokenKind.CSharp, Content = content }; return new IntermediateToken() { Kind = TokenKind.CSharp, Content = content };
} }
else if (node.Children[0] is CSharpExpressionIntermediateNode cSharpNode) else if (node.Children[0] is CSharpExpressionIntermediateNode cSharpNode)
{ {
// This case can be hit when the attribute has an explicit @ inside, which // This case can be hit when the attribute has an explicit @ inside, which
// 'escapes' any special sugar we provide for codegen. // 'escapes' any special sugar we provide for codegen.
return ((IntermediateToken)cSharpNode.Children.Single()); return GetToken(cSharpNode);
} }
else else
{ {
// This is the common case for 'mixed' content // This is the common case for 'mixed' content
return ((IntermediateToken)node.Children.Single()); return GetToken(node);
}
// In error cases we won't have a single token, but we still want to generate the code.
IntermediateToken GetToken(IntermediateNode parent)
{
return
parent.Children.Count == 1 ? (IntermediateToken)parent.Children[0] : new IntermediateToken()
{
Kind = TokenKind.CSharp,
Content = string.Join(string.Empty, parent.Children.OfType<IntermediateToken>().Select(t => t.Content)),
};
} }
} }
} }

View File

@ -1,4 +1,4 @@
// Copyright (c) .NET Foundation. All rights reserved. // 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. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System; using System;
@ -33,20 +33,28 @@ namespace Test
[Parameter] Action<int> ValueChanged { get; set; } [Parameter] Action<int> ValueChanged { get; set; }
[Parameter] string AnotherValue { get; set; } [Parameter] string AnotherValue { get; set; }
} }
public class ModelState
{
public Action<string> Bind(Func<string, string> func) => throw null;
}
} }
")); "));
var text = @" var text = @"
@addTagHelper *, TestAssembly @addTagHelper *, TestAssembly
<div> <div>
<MyComponent bind-Value=""myValue"" AnotherValue=""hi""/> <MyComponent bind-Value=""myValue"" AnotherValue=""hi""/>
<input type=""text"" bind=""@value"" /> <input type=""text"" bind=""@this.ModelState.Bind(x => x)"" />
<button ref=""_button"" onsubmit=""@FormSubmitted"">Click me</button> <button ref=""_button"" onsubmit=""@FormSubmitted"">Click me</button>
</div> </div>
<MyComponent <MyComponent
IntProperty=""123"" IntProperty=""123""
BoolProperty=""true"" BoolProperty=""true""
StringProperty=""My string"" StringProperty=""My string""
ObjectProperty=""new SomeType()""/>"; ObjectProperty=""new SomeType()""/>
@functions {
Test.ModelState ModelState { get; set; }
}";
for (var i = 0; i <= text.Length; i++) for (var i = 0; i <= text.Length; i++)
{ {
@ -66,5 +74,21 @@ Exception:
} }
} }
} }
[Fact] // Regression test for #1068
public void Regression_1068()
{
// Arrange
// Act
var generated = CompileToCSharp(@"
<input type=""text"" bind="" />
@functions {
Test.ModelState ModelState { get; set; }
}
");
// Assert
}
} }
} }