[Fixes #183] Fix error with double transition in value attribute
This commit is contained in:
parent
d6cb4229a9
commit
c680d6b953
|
|
@ -149,7 +149,7 @@ namespace Microsoft.AspNet.Razor.Parser
|
|||
var current = CurrentSymbol;
|
||||
if (At(CSharpSymbolType.StringLiteral) && CurrentSymbol.Content.Length > 0 && CurrentSymbol.Content[0] == SyntaxConstants.TransitionCharacter)
|
||||
{
|
||||
Tuple<CSharpSymbol, CSharpSymbol> split = Language.SplitSymbol(CurrentSymbol, 1, CSharpSymbolType.Transition);
|
||||
var split = Language.SplitSymbol(CurrentSymbol, 1, CSharpSymbolType.Transition);
|
||||
current = split.Item1;
|
||||
Context.Source.Position = split.Item2.Start.AbsoluteIndex;
|
||||
NextToken();
|
||||
|
|
|
|||
|
|
@ -316,7 +316,7 @@ namespace Microsoft.AspNet.Razor.Parser
|
|||
var matched = RemoveTag(tags, tagName, tagStart);
|
||||
|
||||
if (tags.Count == 0 &&
|
||||
// Note tagName may contain a '!' escape character. This ensures </!text> doesn't match here.
|
||||
// Note tagName may contain a '!' escape character. This ensures </!text> doesn't match here.
|
||||
// </!text> tags are treated like any other escaped HTML end tag.
|
||||
string.Equals(tagName, SyntaxConstants.TextTagName, StringComparison.OrdinalIgnoreCase) &&
|
||||
matched)
|
||||
|
|
@ -491,7 +491,7 @@ namespace Microsoft.AspNet.Razor.Parser
|
|||
private void AttributePrefix(IEnumerable<HtmlSymbol> whitespace, IEnumerable<HtmlSymbol> nameSymbols)
|
||||
{
|
||||
// First, determine if this is a 'data-' attribute (since those can't use conditional attributes)
|
||||
LocationTagged<string> name = nameSymbols.GetContent(Span.Start);
|
||||
var name = nameSymbols.GetContent(Span.Start);
|
||||
var attributeCanBeConditional = !name.Value.StartsWith("data-", StringComparison.OrdinalIgnoreCase);
|
||||
|
||||
// Accept the whitespace and name
|
||||
|
|
@ -507,7 +507,7 @@ namespace Microsoft.AspNet.Razor.Parser
|
|||
}
|
||||
|
||||
// We now have the prefix: (i.e. ' foo="')
|
||||
LocationTagged<string> prefix = Span.GetContent();
|
||||
var prefix = Span.GetContent();
|
||||
|
||||
if (attributeCanBeConditional)
|
||||
{
|
||||
|
|
@ -521,7 +521,7 @@ namespace Microsoft.AspNet.Razor.Parser
|
|||
}
|
||||
|
||||
// Capture the suffix
|
||||
LocationTagged<string> suffix = new LocationTagged<string>(string.Empty, CurrentLocation);
|
||||
var suffix = new LocationTagged<string>(string.Empty, CurrentLocation);
|
||||
if (quote != HtmlSymbolType.Unknown && At(quote))
|
||||
{
|
||||
suffix = CurrentSymbol.GetContent();
|
||||
|
|
@ -554,23 +554,45 @@ namespace Microsoft.AspNet.Razor.Parser
|
|||
{
|
||||
var prefixStart = CurrentLocation;
|
||||
var prefix = ReadWhile(sym => sym.Type == HtmlSymbolType.WhiteSpace || sym.Type == HtmlSymbolType.NewLine);
|
||||
Accept(prefix);
|
||||
|
||||
if (At(HtmlSymbolType.Transition))
|
||||
{
|
||||
var valueStart = CurrentLocation;
|
||||
PutCurrentBack();
|
||||
|
||||
// Output the prefix but as a null-span. DynamicAttributeBlockCodeGenerator will render it
|
||||
Span.CodeGenerator = SpanCodeGenerator.Null;
|
||||
|
||||
// Dynamic value, start a new block and set the code generator
|
||||
using (Context.StartBlock(BlockType.Markup))
|
||||
if (NextIs(HtmlSymbolType.Transition))
|
||||
{
|
||||
Context.CurrentBlock.CodeGenerator =
|
||||
new DynamicAttributeBlockCodeGenerator(prefix.GetContent(prefixStart), valueStart);
|
||||
// Wrapping this in a block so that the ConditionalAttributeCollapser doesn't rewrite it.
|
||||
using (Context.StartBlock(BlockType.Markup))
|
||||
{
|
||||
Accept(prefix);
|
||||
|
||||
OtherParserBlock();
|
||||
// Render a single "@" in place of "@@".
|
||||
Span.CodeGenerator = new LiteralAttributeCodeGenerator(
|
||||
prefix.GetContent(prefixStart),
|
||||
new LocationTagged<string>(CurrentSymbol.GetContent(), CurrentLocation));
|
||||
AcceptAndMoveNext();
|
||||
Output(SpanKind.Markup, AcceptedCharacters.None);
|
||||
|
||||
Span.CodeGenerator = SpanCodeGenerator.Null;
|
||||
AcceptAndMoveNext();
|
||||
Output(SpanKind.Markup, AcceptedCharacters.None);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Accept(prefix);
|
||||
var valueStart = CurrentLocation;
|
||||
PutCurrentBack();
|
||||
|
||||
// Output the prefix but as a null-span. DynamicAttributeBlockCodeGenerator will render it
|
||||
Span.CodeGenerator = SpanCodeGenerator.Null;
|
||||
|
||||
// Dynamic value, start a new block and set the code generator
|
||||
using (Context.StartBlock(BlockType.Markup))
|
||||
{
|
||||
Context.CurrentBlock.CodeGenerator =
|
||||
new DynamicAttributeBlockCodeGenerator(prefix.GetContent(prefixStart), valueStart);
|
||||
|
||||
OtherParserBlock();
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (At(HtmlSymbolType.Text) &&
|
||||
|
|
@ -578,6 +600,8 @@ namespace Microsoft.AspNet.Razor.Parser
|
|||
CurrentSymbol.Content[0] == '~' &&
|
||||
NextIs(HtmlSymbolType.ForwardSlash))
|
||||
{
|
||||
Accept(prefix);
|
||||
|
||||
// Virtual Path value
|
||||
var valueStart = CurrentLocation;
|
||||
VirtualPath();
|
||||
|
|
@ -587,6 +611,8 @@ namespace Microsoft.AspNet.Razor.Parser
|
|||
}
|
||||
else
|
||||
{
|
||||
Accept(prefix);
|
||||
|
||||
// Literal value
|
||||
// 'quote' should be "Unknown" if not quoted and symbols coming from the tokenizer should never have "Unknown" type.
|
||||
var value = ReadWhile(sym =>
|
||||
|
|
@ -719,7 +745,7 @@ namespace Microsoft.AspNet.Razor.Parser
|
|||
Tuple<HtmlSymbol, SourceLocation> tag = Tuple.Create(tagName, _lastTagStart);
|
||||
|
||||
if (tags.Count == 0 &&
|
||||
// Note tagName may contain a '!' escape character. This ensures <!text> doesn't match here.
|
||||
// Note tagName may contain a '!' escape character. This ensures <!text> doesn't match here.
|
||||
// <!text> tags are treated like any other escaped HTML start tag.
|
||||
string.Equals(tag.Item1.Content, SyntaxConstants.TextTagName, StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
|
|
|
|||
|
|
@ -277,15 +277,14 @@ namespace Microsoft.AspNet.Razor.Test.Framework
|
|||
// Evaluate the result
|
||||
var collector = new ErrorCollector();
|
||||
|
||||
// Link all the nodes
|
||||
expectedRoot.LinkNodes();
|
||||
|
||||
if (expectedRoot == null)
|
||||
{
|
||||
Assert.Null(actualRoot);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Link all the nodes
|
||||
expectedRoot.LinkNodes();
|
||||
Assert.NotNull(actualRoot);
|
||||
EvaluateSyntaxTreeNode(collector, actualRoot, expectedRoot);
|
||||
if (collector.Success)
|
||||
|
|
@ -412,7 +411,7 @@ namespace Microsoft.AspNet.Razor.Test.Framework
|
|||
actual.TagName,
|
||||
actual.SelfClosing);
|
||||
}
|
||||
|
||||
|
||||
var expectedAttributes = expected.Attributes.GetEnumerator();
|
||||
var actualAttributes = actual.Attributes.GetEnumerator();
|
||||
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ using Microsoft.AspNet.Razor.Parser;
|
|||
using Microsoft.AspNet.Razor.Parser.SyntaxTree;
|
||||
using Microsoft.AspNet.Razor.Test.Framework;
|
||||
using Microsoft.AspNet.Razor.Text;
|
||||
using Microsoft.AspNet.Razor.Tokenizer;
|
||||
using Microsoft.AspNet.Razor.Tokenizer.Symbols;
|
||||
using Xunit;
|
||||
|
||||
|
|
@ -704,8 +705,8 @@ catch(bar) { baz(); }", BlockType.Statement, SpanKind.Code);
|
|||
Factory.Markup("<a"),
|
||||
new MarkupBlock(
|
||||
new AttributeBlockCodeGenerator(
|
||||
"href",
|
||||
new LocationTagged<string>(" href=\"", 183 + Environment.NewLine.Length * 5, 5, 30),
|
||||
"href",
|
||||
new LocationTagged<string>(" href=\"", 183 + Environment.NewLine.Length * 5, 5, 30),
|
||||
new LocationTagged<string>("\"", 246 + Environment.NewLine.Length * 5, 5, 93)),
|
||||
Factory.Markup(" href=\"").With(SpanCodeGenerator.Null),
|
||||
new MarkupBlock(
|
||||
|
|
@ -736,6 +737,322 @@ catch(bar) { baz(); }", BlockType.Statement, SpanKind.Code);
|
|||
Factory.Code(" }").AsStatement().Accepts(AcceptedCharacters.None)));
|
||||
}
|
||||
|
||||
public static TheoryData BlockWithEscapedTransitionData
|
||||
{
|
||||
get
|
||||
{
|
||||
var factory = CreateDefaultSpanFactory();
|
||||
var datetimeBlock = new ExpressionBlock(
|
||||
factory.CodeTransition(),
|
||||
factory.Code("DateTime.Now")
|
||||
.AsImplicitExpression(CSharpCodeParser.DefaultKeywords)
|
||||
.Accepts(AcceptedCharacters.NonWhiteSpace));
|
||||
|
||||
return new TheoryData<string, Block>
|
||||
{
|
||||
{
|
||||
// Double transition in attribute value
|
||||
"{<span foo='@@' />}",
|
||||
CreateStatementBlock(
|
||||
new MarkupBlock(
|
||||
new MarkupTagBlock(
|
||||
factory.Markup("<span"),
|
||||
new MarkupBlock(
|
||||
new AttributeBlockCodeGenerator("foo", new LocationTagged<string>(" foo='", 6, 0, 6), new LocationTagged<string>("'", 14, 0, 14)),
|
||||
factory.Markup(" foo='").With(SpanCodeGenerator.Null),
|
||||
new MarkupBlock(
|
||||
factory.Markup("@").With(new LiteralAttributeCodeGenerator(new LocationTagged<string>(string.Empty, 12, 0, 12), new LocationTagged<string>("@", 12, 0, 12))).Accepts(AcceptedCharacters.None),
|
||||
factory.Markup("@").With(SpanCodeGenerator.Null).Accepts(AcceptedCharacters.None)),
|
||||
factory.Markup("'").With(SpanCodeGenerator.Null)),
|
||||
factory.Markup(" />").Accepts(AcceptedCharacters.None))))
|
||||
},
|
||||
{
|
||||
// Double transition at the end of attribute value
|
||||
"{<span foo='abc@@' />}",
|
||||
CreateStatementBlock(
|
||||
new MarkupBlock(
|
||||
new MarkupTagBlock(
|
||||
factory.Markup("<span"),
|
||||
new MarkupBlock(
|
||||
new AttributeBlockCodeGenerator("foo", new LocationTagged<string>(" foo='", 6, 0, 6), new LocationTagged<string>("'", 17, 0, 17)),
|
||||
factory.Markup(" foo='").With(SpanCodeGenerator.Null),
|
||||
factory.Markup("abc").With(new LiteralAttributeCodeGenerator(new LocationTagged<string>(string.Empty, 12, 0, 12), new LocationTagged<string>("abc", 12, 0, 12))),
|
||||
new MarkupBlock(
|
||||
factory.Markup("@").With(new LiteralAttributeCodeGenerator(new LocationTagged<string>(string.Empty, 15, 0, 15), new LocationTagged<string>("@", 15, 0, 15))).Accepts(AcceptedCharacters.None),
|
||||
factory.Markup("@").With(SpanCodeGenerator.Null).Accepts(AcceptedCharacters.None)),
|
||||
factory.Markup("'").With(SpanCodeGenerator.Null)),
|
||||
factory.Markup(" />").Accepts(AcceptedCharacters.None))))
|
||||
},
|
||||
{
|
||||
// Double transition at the beginning attribute value
|
||||
"{<span foo='@@def' />}",
|
||||
CreateStatementBlock(
|
||||
new MarkupBlock(
|
||||
new MarkupTagBlock(
|
||||
factory.Markup("<span"),
|
||||
new MarkupBlock(
|
||||
new AttributeBlockCodeGenerator("foo", new LocationTagged<string>(" foo='", 6, 0, 6), new LocationTagged<string>("'", 17, 0, 17)),
|
||||
factory.Markup(" foo='").With(SpanCodeGenerator.Null),
|
||||
new MarkupBlock(
|
||||
factory.Markup("@").With(new LiteralAttributeCodeGenerator(new LocationTagged<string>(string.Empty, 12, 0, 12), new LocationTagged<string>("@", 12, 0, 12))).Accepts(AcceptedCharacters.None),
|
||||
factory.Markup("@").With(SpanCodeGenerator.Null).Accepts(AcceptedCharacters.None)),
|
||||
factory.Markup("def").With(new LiteralAttributeCodeGenerator(new LocationTagged<string>(string.Empty, 14, 0, 14), new LocationTagged<string>("def", 14, 0, 14))),
|
||||
factory.Markup("'").With(SpanCodeGenerator.Null)),
|
||||
factory.Markup(" />").Accepts(AcceptedCharacters.None))))
|
||||
},
|
||||
{
|
||||
// Double transition in between attribute value
|
||||
"{<span foo='abc @@ def' />}",
|
||||
CreateStatementBlock(
|
||||
new MarkupBlock(
|
||||
new MarkupTagBlock(
|
||||
factory.Markup("<span"),
|
||||
new MarkupBlock(
|
||||
new AttributeBlockCodeGenerator("foo", new LocationTagged<string>(" foo='", 6, 0, 6), new LocationTagged<string>("'", 22, 0, 22)),
|
||||
factory.Markup(" foo='").With(SpanCodeGenerator.Null),
|
||||
factory.Markup("abc").With(new LiteralAttributeCodeGenerator(new LocationTagged<string>(string.Empty, 12, 0, 12), new LocationTagged<string>("abc", 12, 0, 12))),
|
||||
new MarkupBlock(
|
||||
factory.Markup(" @").With(new LiteralAttributeCodeGenerator(new LocationTagged<string>(" ", 15, 0, 15), new LocationTagged<string>("@", 16, 0, 16))).Accepts(AcceptedCharacters.None),
|
||||
factory.Markup("@").With(SpanCodeGenerator.Null).Accepts(AcceptedCharacters.None)),
|
||||
factory.Markup(" def").With(new LiteralAttributeCodeGenerator(new LocationTagged<string>(" ", 18, 0, 18), new LocationTagged<string>("def", 19, 0, 19))),
|
||||
factory.Markup("'").With(SpanCodeGenerator.Null)),
|
||||
factory.Markup(" />").Accepts(AcceptedCharacters.None))))
|
||||
},
|
||||
{
|
||||
// Double transition with expression block
|
||||
"{<span foo='@@@DateTime.Now' />}",
|
||||
CreateStatementBlock(
|
||||
new MarkupBlock(
|
||||
new MarkupTagBlock(
|
||||
factory.Markup("<span"),
|
||||
new MarkupBlock(
|
||||
new AttributeBlockCodeGenerator("foo", new LocationTagged<string>(" foo='", 6, 0, 6), new LocationTagged<string>("'", 27, 0, 27)),
|
||||
factory.Markup(" foo='").With(SpanCodeGenerator.Null),
|
||||
new MarkupBlock(
|
||||
factory.Markup("@").With(new LiteralAttributeCodeGenerator(new LocationTagged<string>(string.Empty, 12, 0, 12), new LocationTagged<string>("@", 12, 0, 12))).Accepts(AcceptedCharacters.None),
|
||||
factory.Markup("@").With(SpanCodeGenerator.Null).Accepts(AcceptedCharacters.None)),
|
||||
new MarkupBlock(
|
||||
new DynamicAttributeBlockCodeGenerator(new LocationTagged<string>(string.Empty, 14, 0, 14), 14, 0, 14),
|
||||
factory.EmptyHtml().With(SpanCodeGenerator.Null),
|
||||
datetimeBlock),
|
||||
factory.Markup("'").With(SpanCodeGenerator.Null)),
|
||||
factory.Markup(" />").Accepts(AcceptedCharacters.None))))
|
||||
},
|
||||
{
|
||||
"{<span foo='@DateTime.Now @@' />}",
|
||||
CreateStatementBlock(
|
||||
new MarkupBlock(
|
||||
new MarkupTagBlock(
|
||||
factory.Markup("<span"),
|
||||
new MarkupBlock(
|
||||
new AttributeBlockCodeGenerator("foo", new LocationTagged<string>(" foo='", 6, 0, 6), new LocationTagged<string>("'", 28, 0, 28)),
|
||||
factory.Markup(" foo='").With(SpanCodeGenerator.Null),
|
||||
new MarkupBlock(
|
||||
new DynamicAttributeBlockCodeGenerator(new LocationTagged<string>(string.Empty, 12, 0, 12), 12, 0, 12),
|
||||
datetimeBlock),
|
||||
new MarkupBlock(
|
||||
factory.Markup(" @").With(new LiteralAttributeCodeGenerator(new LocationTagged<string>(" ", 25, 0, 25), new LocationTagged<string>("@", 26, 0, 26))).Accepts(AcceptedCharacters.None),
|
||||
factory.Markup("@").With(SpanCodeGenerator.Null).Accepts(AcceptedCharacters.None)),
|
||||
factory.Markup("'").With(SpanCodeGenerator.Null)),
|
||||
factory.Markup(" />").Accepts(AcceptedCharacters.None))))
|
||||
},
|
||||
{
|
||||
"{<span foo='@DateTime.Now@@' />}",
|
||||
CreateStatementBlock(
|
||||
new MarkupBlock(
|
||||
new MarkupTagBlock(
|
||||
factory.Markup("<span"),
|
||||
new MarkupBlock(
|
||||
new AttributeBlockCodeGenerator("foo", new LocationTagged<string>(" foo='", 6, 0, 6), new LocationTagged<string>("'", 27, 0, 27)),
|
||||
factory.Markup(" foo='").With(SpanCodeGenerator.Null),
|
||||
new MarkupBlock(
|
||||
new DynamicAttributeBlockCodeGenerator(new LocationTagged<string>(string.Empty, 12, 0, 12), 12, 0, 12),
|
||||
datetimeBlock),
|
||||
new MarkupBlock(
|
||||
factory.Markup("@").With(new LiteralAttributeCodeGenerator(new LocationTagged<string>(string.Empty, 25, 0, 25), new LocationTagged<string>("@", 25, 0, 25))).Accepts(AcceptedCharacters.None),
|
||||
factory.Markup("@").With(SpanCodeGenerator.Null).Accepts(AcceptedCharacters.None)),
|
||||
factory.Markup("'").With(SpanCodeGenerator.Null)),
|
||||
factory.Markup(" />").Accepts(AcceptedCharacters.None))))
|
||||
},
|
||||
{
|
||||
"{<span foo='@(2+3)@@@DateTime.Now' />}",
|
||||
CreateStatementBlock(
|
||||
new MarkupBlock(
|
||||
new MarkupTagBlock(
|
||||
factory.Markup("<span"),
|
||||
new MarkupBlock(
|
||||
new AttributeBlockCodeGenerator("foo", new LocationTagged<string>(" foo='", 6, 0, 6), new LocationTagged<string>("'", 33, 0, 33)),
|
||||
factory.Markup(" foo='").With(SpanCodeGenerator.Null),
|
||||
new MarkupBlock(
|
||||
new DynamicAttributeBlockCodeGenerator(new LocationTagged<string>(string.Empty, 12, 0, 12), 12, 0, 12),
|
||||
new ExpressionBlock(
|
||||
factory.CodeTransition(),
|
||||
factory.MetaCode("(").With(SpanCodeGenerator.Null).Accepts(AcceptedCharacters.None),
|
||||
factory.Code("2+3").AsExpression(),
|
||||
factory.MetaCode(")").With(SpanCodeGenerator.Null).Accepts(AcceptedCharacters.None))),
|
||||
new MarkupBlock(
|
||||
factory.Markup("@").With(new LiteralAttributeCodeGenerator(new LocationTagged<string>(string.Empty, 18, 0, 18), new LocationTagged<string>("@", 18, 0, 18))).Accepts(AcceptedCharacters.None),
|
||||
factory.Markup("@").With(SpanCodeGenerator.Null).Accepts(AcceptedCharacters.None)),
|
||||
new MarkupBlock(
|
||||
new DynamicAttributeBlockCodeGenerator(new LocationTagged<string>(string.Empty, 20, 0, 20), 20, 0, 20),
|
||||
factory.EmptyHtml().With(SpanCodeGenerator.Null),
|
||||
datetimeBlock),
|
||||
factory.Markup("'").With(SpanCodeGenerator.Null)),
|
||||
factory.Markup(" />").Accepts(AcceptedCharacters.None))))
|
||||
},
|
||||
{
|
||||
"{<span foo='@@@(2+3)' />}",
|
||||
CreateStatementBlock(
|
||||
new MarkupBlock(
|
||||
new MarkupTagBlock(
|
||||
factory.Markup("<span"),
|
||||
new MarkupBlock(
|
||||
new AttributeBlockCodeGenerator("foo", new LocationTagged<string>(" foo='", 6, 0, 6), new LocationTagged<string>("'", 20, 0, 20)),
|
||||
factory.Markup(" foo='").With(SpanCodeGenerator.Null),
|
||||
new MarkupBlock(
|
||||
factory.Markup("@").With(new LiteralAttributeCodeGenerator(new LocationTagged<string>(string.Empty, 12, 0, 12), new LocationTagged<string>("@", 12, 0, 12))).Accepts(AcceptedCharacters.None),
|
||||
factory.Markup("@").With(SpanCodeGenerator.Null).Accepts(AcceptedCharacters.None)),
|
||||
new MarkupBlock(
|
||||
new DynamicAttributeBlockCodeGenerator(new LocationTagged<string>(string.Empty, 14, 0, 14), 14, 0, 14),
|
||||
factory.EmptyHtml().With(SpanCodeGenerator.Null),
|
||||
new ExpressionBlock(
|
||||
factory.CodeTransition(),
|
||||
factory.MetaCode("(").With(SpanCodeGenerator.Null).Accepts(AcceptedCharacters.None),
|
||||
factory.Code("2+3").AsExpression(),
|
||||
factory.MetaCode(")").With(SpanCodeGenerator.Null).Accepts(AcceptedCharacters.None))),
|
||||
factory.Markup("'").With(SpanCodeGenerator.Null)),
|
||||
factory.Markup(" />").Accepts(AcceptedCharacters.None))))
|
||||
},
|
||||
{
|
||||
// Double transition with email in attribute value
|
||||
"{<span foo='abc@def.com @@' />}",
|
||||
CreateStatementBlock(
|
||||
new MarkupBlock(
|
||||
new MarkupTagBlock(
|
||||
factory.Markup("<span"),
|
||||
new MarkupBlock(
|
||||
new AttributeBlockCodeGenerator("foo", new LocationTagged<string>(" foo='", 6, 0, 6), new LocationTagged<string>("'", 26, 0, 26)),
|
||||
factory.Markup(" foo='").With(SpanCodeGenerator.Null),
|
||||
factory.Markup("abc@def.com").With(new LiteralAttributeCodeGenerator(new LocationTagged<string>(string.Empty, 12, 0, 12), new LocationTagged<string>("abc@def.com", 12, 0, 12))),
|
||||
new MarkupBlock(
|
||||
factory.Markup(" @").With(new LiteralAttributeCodeGenerator(new LocationTagged<string>(" ", 23, 0, 23), new LocationTagged<string>("@", 24, 0, 24))).Accepts(AcceptedCharacters.None),
|
||||
factory.Markup("@").With(SpanCodeGenerator.Null).Accepts(AcceptedCharacters.None)),
|
||||
factory.Markup("'").With(SpanCodeGenerator.Null)),
|
||||
factory.Markup(" />").Accepts(AcceptedCharacters.None))))
|
||||
},
|
||||
{
|
||||
"{<span foo='abc@@def.com @@' />}",
|
||||
CreateStatementBlock(
|
||||
new MarkupBlock(
|
||||
new MarkupTagBlock(
|
||||
factory.Markup("<span"),
|
||||
new MarkupBlock(
|
||||
new AttributeBlockCodeGenerator("foo", new LocationTagged<string>(" foo='", 6, 0, 6), new LocationTagged<string>("'", 27, 0, 27)),
|
||||
factory.Markup(" foo='").With(SpanCodeGenerator.Null),
|
||||
factory.Markup("abc").With(new LiteralAttributeCodeGenerator(new LocationTagged<string>(string.Empty, 12, 0, 12), new LocationTagged<string>("abc", 12, 0, 12))),
|
||||
new MarkupBlock(
|
||||
factory.Markup("@").With(new LiteralAttributeCodeGenerator(new LocationTagged<string>(string.Empty, 15, 0, 15), new LocationTagged<string>("@", 15, 0, 15))).Accepts(AcceptedCharacters.None),
|
||||
factory.Markup("@").With(SpanCodeGenerator.Null).Accepts(AcceptedCharacters.None)),
|
||||
factory.Markup("def.com").With(new LiteralAttributeCodeGenerator(new LocationTagged<string>(string.Empty, 17, 0, 17), new LocationTagged<string>("def.com", 17, 0, 17))),
|
||||
new MarkupBlock(
|
||||
factory.Markup(" @").With(new LiteralAttributeCodeGenerator(new LocationTagged<string>(" ", 24, 0, 24), new LocationTagged<string>("@", 25, 0, 25))).Accepts(AcceptedCharacters.None),
|
||||
factory.Markup("@").With(SpanCodeGenerator.Null).Accepts(AcceptedCharacters.None)),
|
||||
factory.Markup("'").With(SpanCodeGenerator.Null)),
|
||||
factory.Markup(" />").Accepts(AcceptedCharacters.None))))
|
||||
},
|
||||
{
|
||||
// Double transition in complex regex in attribute value
|
||||
@"{<span foo=""/^[a-z0-9!#$%&'*+\/=?^_`{|}~.-]+@@[a-z0-9]([a-z0-9-]*[a-z0-9])?\.([a-z0-9]([a-z0-9-]*[a-z0-9])?)*$/i"" />}",
|
||||
CreateStatementBlock(
|
||||
new MarkupBlock(
|
||||
new MarkupTagBlock(
|
||||
factory.Markup("<span"),
|
||||
new MarkupBlock(
|
||||
new AttributeBlockCodeGenerator("foo", new LocationTagged<string>(" foo=\"", 6, 0, 6), new LocationTagged<string>("\"", 112, 0, 112)),
|
||||
factory.Markup(" foo=\"").With(SpanCodeGenerator.Null),
|
||||
factory.Markup(@"/^[a-z0-9!#$%&'*+\/=?^_`{|}~.-]+").With(new LiteralAttributeCodeGenerator(new LocationTagged<string>(string.Empty, 12, 0, 12), new LocationTagged<string>(@"/^[a-z0-9!#$%&'*+\/=?^_`{|}~.-]+", 12, 0, 12))),
|
||||
new MarkupBlock(
|
||||
factory.Markup("@").With(new LiteralAttributeCodeGenerator(new LocationTagged<string>(string.Empty, 44, 0, 44), new LocationTagged<string>("@", 44, 0, 44))).Accepts(AcceptedCharacters.None),
|
||||
factory.Markup("@").With(SpanCodeGenerator.Null).Accepts(AcceptedCharacters.None)),
|
||||
factory.Markup(@"[a-z0-9]([a-z0-9-]*[a-z0-9])?\.([a-z0-9]([a-z0-9-]*[a-z0-9])?)*$/i").With(new LiteralAttributeCodeGenerator(new LocationTagged<string>(string.Empty, 46, 0, 46), new LocationTagged<string>(@"[a-z0-9]([a-z0-9-]*[a-z0-9])?\.([a-z0-9]([a-z0-9-]*[a-z0-9])?)*$/i", 46, 0, 46))),
|
||||
factory.Markup("\"").With(SpanCodeGenerator.Null)),
|
||||
factory.Markup(" />").Accepts(AcceptedCharacters.None))))
|
||||
},
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[MemberData(nameof(BlockWithEscapedTransitionData))]
|
||||
public void ParseBlock_WithDoubleTransition_DoesNotThrow(string input, Block expected)
|
||||
{
|
||||
// Act & Assert
|
||||
ParseBlockTest(input, expected);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ParseBlock_WithDoubleTransition_EndOfFile_Throws()
|
||||
{
|
||||
// Arrange
|
||||
var expected = new StatementBlock(
|
||||
Factory.MetaCode("{").Accepts(AcceptedCharacters.None),
|
||||
new MarkupBlock(
|
||||
new MarkupTagBlock(
|
||||
Factory.Markup("<span"),
|
||||
new MarkupBlock(
|
||||
new AttributeBlockCodeGenerator("foo", new LocationTagged<string>(" foo='", 6, 0, 6), new LocationTagged<string>(string.Empty, 14, 0, 14)),
|
||||
Factory.Markup(" foo='").With(SpanCodeGenerator.Null),
|
||||
new MarkupBlock(
|
||||
Factory.Markup("@").With(new LiteralAttributeCodeGenerator(new LocationTagged<string>(string.Empty, 12, 0, 12), new LocationTagged<string>("@", 12, 0, 12))).Accepts(AcceptedCharacters.None),
|
||||
Factory.Markup("@").With(SpanCodeGenerator.Null).Accepts(AcceptedCharacters.None)))),
|
||||
Factory.EmptyHtml()));
|
||||
var expectedErrors = new RazorError[]
|
||||
{
|
||||
new RazorError(@"End of file or an unexpected character was reached before the ""span"" tag could be parsed. Elements inside markup blocks must be complete. They must either be self-closing (""<br />"") or have matching end tags (""<p>Hello</p>""). If you intended to display a ""<"" character, use the ""<"" HTML entity.", new SourceLocation(1, 0, 1)),
|
||||
new RazorError(@"The code block is missing a closing ""}"" character. Make sure you have a matching ""}"" character for all the ""{"" characters within this block, and that none of the ""}"" characters are being interpreted as markup.", new SourceLocation(0, 0, 0)),
|
||||
};
|
||||
|
||||
// Act & Assert
|
||||
ParseBlockTest("{<span foo='@@", expected, expectedErrors);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ParseBlock_WithUnexpectedTransitionsInAttributeValue_Throws()
|
||||
{
|
||||
// Arrange
|
||||
var expected = new StatementBlock(
|
||||
Factory.MetaCode("{").Accepts(AcceptedCharacters.None),
|
||||
new MarkupBlock(
|
||||
new MarkupTagBlock(
|
||||
Factory.Markup("<span"),
|
||||
new MarkupBlock(
|
||||
new AttributeBlockCodeGenerator("foo", new LocationTagged<string>(" foo='", 6, 0, 6), new LocationTagged<string>("'", 15, 0, 15)),
|
||||
Factory.Markup(" foo='").With(SpanCodeGenerator.Null),
|
||||
new MarkupBlock(
|
||||
new DynamicAttributeBlockCodeGenerator(new LocationTagged<string>(string.Empty, 12, 0, 12), 12, 0, 12),
|
||||
new ExpressionBlock(
|
||||
Factory.CodeTransition(),
|
||||
Factory.EmptyCSharp().AsImplicitExpression(CSharpCodeParser.DefaultKeywords).Accepts(AcceptedCharacters.NonWhiteSpace))),
|
||||
new MarkupBlock(
|
||||
new DynamicAttributeBlockCodeGenerator(new LocationTagged<string>(" ", 13, 0, 13), 13, 0, 13),
|
||||
Factory.Markup(" ").With(SpanCodeGenerator.Null),
|
||||
new ExpressionBlock(
|
||||
Factory.CodeTransition(),
|
||||
Factory.EmptyCSharp().AsImplicitExpression(CSharpCodeParser.DefaultKeywords).Accepts(AcceptedCharacters.NonWhiteSpace))),
|
||||
Factory.Markup("'").With(SpanCodeGenerator.Null)),
|
||||
Factory.Markup(" />").Accepts(AcceptedCharacters.None))),
|
||||
Factory.EmptyCSharp().AsStatement(),
|
||||
Factory.MetaCode("}").Accepts(AcceptedCharacters.None));
|
||||
var expectedErrors = new RazorError[]
|
||||
{
|
||||
new RazorError(@"A space or line break was encountered after the ""@"" character. Only valid identifiers, keywords, comments, ""("" and ""{"" are valid at the start of a code block and they must occur immediately following ""@"" with no space in between.", new SourceLocation(13, 0, 13)),
|
||||
new RazorError(@"""' />}"" is not valid at the start of a code block. Only identifiers, keywords, comments, ""("" and ""{"" are valid.", new SourceLocation(15, 0, 15)),
|
||||
};
|
||||
|
||||
// Act & Assert
|
||||
ParseBlockTest("{<span foo='@ @' />}", expected, expectedErrors);
|
||||
}
|
||||
|
||||
private void RunRazorCommentBetweenClausesTest(string preComment, string postComment, AcceptedCharacters acceptedCharacters = AcceptedCharacters.Any)
|
||||
{
|
||||
ParseBlockTest(preComment + "@* Foo *@ @* Bar *@" + postComment,
|
||||
|
|
@ -786,5 +1103,24 @@ catch(bar) { baz(); }", BlockType.Statement, SpanKind.Code);
|
|||
.Accepts(acceptedCharacters)),
|
||||
errors);
|
||||
}
|
||||
|
||||
private static SpanFactory CreateDefaultSpanFactory()
|
||||
{
|
||||
return new SpanFactory
|
||||
{
|
||||
MarkupTokenizerFactory = doc => new HtmlTokenizer(doc),
|
||||
CodeTokenizerFactory = doc => new CSharpTokenizer(doc)
|
||||
};
|
||||
}
|
||||
|
||||
private static StatementBlock CreateStatementBlock(MarkupBlock block)
|
||||
{
|
||||
var factory = CreateDefaultSpanFactory();
|
||||
return new StatementBlock(
|
||||
factory.MetaCode("{").Accepts(AcceptedCharacters.None),
|
||||
block,
|
||||
factory.EmptyCSharp().AsStatement(),
|
||||
factory.MetaCode("}").Accepts(AcceptedCharacters.None));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,6 +6,8 @@ using Microsoft.AspNet.Razor.Generator;
|
|||
using Microsoft.AspNet.Razor.Parser;
|
||||
using Microsoft.AspNet.Razor.Parser.SyntaxTree;
|
||||
using Microsoft.AspNet.Razor.Test.Framework;
|
||||
using Microsoft.AspNet.Razor.Text;
|
||||
using Microsoft.AspNet.Razor.Tokenizer;
|
||||
using Xunit;
|
||||
|
||||
namespace Microsoft.AspNet.Razor.Test.Parser.CSharp
|
||||
|
|
@ -443,5 +445,84 @@ namespace Microsoft.AspNet.Razor.Test.Parser.CSharp
|
|||
Factory.MetaCode("}").Accepts(AcceptedCharacters.None)),
|
||||
Factory.EmptyHtml()));
|
||||
}
|
||||
|
||||
public static TheoryData SectionWithEscapedTransitionData
|
||||
{
|
||||
get
|
||||
{
|
||||
var factory = CreateDefaultSpanFactory();
|
||||
|
||||
return new TheoryData<string, Block>
|
||||
{
|
||||
{
|
||||
"@section s {<span foo='@@' />}",
|
||||
new MarkupBlock(
|
||||
factory.EmptyHtml(),
|
||||
new SectionBlock(new SectionCodeGenerator("s"),
|
||||
factory.CodeTransition(),
|
||||
factory.MetaCode("section s {")
|
||||
.AutoCompleteWith(null, atEndOfSpan: true),
|
||||
new MarkupBlock(
|
||||
new MarkupTagBlock(
|
||||
factory.Markup("<span"),
|
||||
new MarkupBlock(
|
||||
new AttributeBlockCodeGenerator("foo", new LocationTagged<string>(" foo='", 17, 0, 17), new LocationTagged<string>("'", 25, 0, 25)),
|
||||
factory.Markup(" foo='").With(SpanCodeGenerator.Null),
|
||||
new MarkupBlock(
|
||||
factory.Markup("@").With(new LiteralAttributeCodeGenerator(new LocationTagged<string>(string.Empty, 23, 0, 23), new LocationTagged<string>("@", 23, 0, 23))).Accepts(AcceptedCharacters.None),
|
||||
factory.Markup("@").With(SpanCodeGenerator.Null).Accepts(AcceptedCharacters.None)),
|
||||
factory.Markup("'").With(SpanCodeGenerator.Null)),
|
||||
factory.Markup(" />"))),
|
||||
factory.MetaCode("}").Accepts(AcceptedCharacters.None)),
|
||||
factory.EmptyHtml())
|
||||
},
|
||||
{
|
||||
"@section s {<span foo='@DateTime.Now @@' />}",
|
||||
new MarkupBlock(
|
||||
factory.EmptyHtml(),
|
||||
new SectionBlock(new SectionCodeGenerator("s"),
|
||||
factory.CodeTransition(),
|
||||
factory.MetaCode("section s {")
|
||||
.AutoCompleteWith(null, atEndOfSpan: true),
|
||||
new MarkupBlock(
|
||||
new MarkupTagBlock(
|
||||
factory.Markup("<span"),
|
||||
new MarkupBlock(
|
||||
new AttributeBlockCodeGenerator("foo", new LocationTagged<string>(" foo='", 17, 0, 17), new LocationTagged<string>("'", 39, 0, 39)),
|
||||
factory.Markup(" foo='").With(SpanCodeGenerator.Null),
|
||||
new MarkupBlock(
|
||||
new DynamicAttributeBlockCodeGenerator(new LocationTagged<string>(string.Empty, 23, 0, 23), 23, 0, 23),
|
||||
new ExpressionBlock(
|
||||
factory.CodeTransition(),
|
||||
factory.Code("DateTime.Now")
|
||||
.AsImplicitExpression(CSharpCodeParser.DefaultKeywords)
|
||||
.Accepts(AcceptedCharacters.NonWhiteSpace))),
|
||||
new MarkupBlock(
|
||||
factory.Markup(" @").With(new LiteralAttributeCodeGenerator(new LocationTagged<string>(" ", 36, 0, 36), new LocationTagged<string>("@", 37, 0, 37))).Accepts(AcceptedCharacters.None),
|
||||
factory.Markup("@").With(SpanCodeGenerator.Null).Accepts(AcceptedCharacters.None)),
|
||||
factory.Markup("'").With(SpanCodeGenerator.Null)),
|
||||
factory.Markup(" />"))),
|
||||
factory.MetaCode("}").Accepts(AcceptedCharacters.None)),
|
||||
factory.EmptyHtml())
|
||||
},
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[MemberData(nameof(SectionWithEscapedTransitionData))]
|
||||
public void ParseSectionBlock_WithDoubleTransition_DoesNotThrow(string input, Block expected)
|
||||
{
|
||||
ParseDocumentTest(input, expected);
|
||||
}
|
||||
|
||||
private static SpanFactory CreateDefaultSpanFactory()
|
||||
{
|
||||
return new SpanFactory
|
||||
{
|
||||
MarkupTokenizerFactory = doc => new HtmlTokenizer(doc),
|
||||
CodeTokenizerFactory = doc => new CSharpTokenizer(doc)
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,9 +3,11 @@
|
|||
|
||||
using System;
|
||||
using Microsoft.AspNet.Razor.Editor;
|
||||
using Microsoft.AspNet.Razor.Generator;
|
||||
using Microsoft.AspNet.Razor.Parser;
|
||||
using Microsoft.AspNet.Razor.Parser.SyntaxTree;
|
||||
using Microsoft.AspNet.Razor.Test.Framework;
|
||||
using Microsoft.AspNet.Razor.Text;
|
||||
using Microsoft.AspNet.Razor.Tokenizer.Symbols;
|
||||
using Xunit;
|
||||
|
||||
|
|
@ -272,6 +274,49 @@ namespace Microsoft.AspNet.Razor.Test.Parser.CSharp
|
|||
GetNestedTemplateError(69));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ParseBlock_WithDoubleTransition_DoesNotThrow()
|
||||
{
|
||||
// Arrange
|
||||
var testTemplateWithDoubleTransitionCode = " @<p foo='@@'>Foo #@item</p>";
|
||||
var testTemplateWithDoubleTransition = new TemplateBlock(
|
||||
new MarkupBlock(
|
||||
Factory.MarkupTransition(),
|
||||
new MarkupTagBlock(
|
||||
Factory.Markup("<p"),
|
||||
new MarkupBlock(
|
||||
new AttributeBlockCodeGenerator("foo", new LocationTagged<string>(" foo='", 46, 0, 46), new LocationTagged<string>("'", 54, 0, 54)),
|
||||
Factory.Markup(" foo='").With(SpanCodeGenerator.Null),
|
||||
new MarkupBlock(
|
||||
Factory.Markup("@").With(new LiteralAttributeCodeGenerator(new LocationTagged<string>(string.Empty, 52, 0, 52), new LocationTagged<string>("@", 52, 0, 52))).Accepts(AcceptedCharacters.None),
|
||||
Factory.Markup("@").With(SpanCodeGenerator.Null).Accepts(AcceptedCharacters.None)),
|
||||
Factory.Markup("'").With(SpanCodeGenerator.Null)),
|
||||
Factory.Markup(">").Accepts(AcceptedCharacters.None)),
|
||||
Factory.Markup("Foo #"),
|
||||
new ExpressionBlock(
|
||||
Factory.CodeTransition(),
|
||||
Factory.Code("item")
|
||||
.AsImplicitExpression(CSharpCodeParser.DefaultKeywords)
|
||||
.Accepts(AcceptedCharacters.NonWhiteSpace)
|
||||
),
|
||||
new MarkupTagBlock(
|
||||
Factory.Markup("</p>").Accepts(AcceptedCharacters.None))
|
||||
)
|
||||
);
|
||||
|
||||
var expected = new StatementBlock(
|
||||
Factory.MetaCode("{").Accepts(AcceptedCharacters.None),
|
||||
Factory.Code(" var foo = bar; Html.ExecuteTemplate(foo, ")
|
||||
.AsStatement()
|
||||
.AutoCompleteWith(autoCompleteString: null),
|
||||
testTemplateWithDoubleTransition,
|
||||
Factory.Code("); ").AsStatement(),
|
||||
Factory.MetaCode("}").Accepts(AcceptedCharacters.None));
|
||||
|
||||
// Act & Assert
|
||||
ParseBlockTest("{ var foo = bar; Html.ExecuteTemplate(foo," + testTemplateWithDoubleTransitionCode + "); }", expected);
|
||||
}
|
||||
|
||||
private static RazorError GetNestedTemplateError(int characterIndex)
|
||||
{
|
||||
return new RazorError(RazorResources.ParseError_InlineMarkup_Blocks_Cannot_Be_Nested, new SourceLocation(characterIndex, 0, characterIndex));
|
||||
|
|
|
|||
|
|
@ -206,6 +206,31 @@ namespace Microsoft.AspNet.Razor.Test.Parser.Html
|
|||
Factory.Markup(" />"))));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ConditionalAttributeCollapserDoesNotRewriteEscapedTransitions()
|
||||
{
|
||||
// Act
|
||||
var results = ParseDocument("<span foo='@@' />");
|
||||
var rewritingContext = new RewritingContext(results.Document, new ErrorSink());
|
||||
new ConditionalAttributeCollapser(new HtmlMarkupParser().BuildSpan).Rewrite(rewritingContext);
|
||||
var rewritten = rewritingContext.SyntaxTree;
|
||||
|
||||
// Assert
|
||||
Assert.Equal(0, results.ParserErrors.Count());
|
||||
EvaluateParseTree(rewritten,
|
||||
new MarkupBlock(
|
||||
new MarkupTagBlock(
|
||||
Factory.Markup("<span"),
|
||||
new MarkupBlock(
|
||||
new AttributeBlockCodeGenerator("foo", new LocationTagged<string>(" foo='", 5, 0, 5), new LocationTagged<string>("'", 13, 0, 13)),
|
||||
Factory.Markup(" foo='").With(SpanCodeGenerator.Null),
|
||||
new MarkupBlock(
|
||||
Factory.Markup("@").With(new LiteralAttributeCodeGenerator(new LocationTagged<string>(string.Empty, 11, 0, 11), new LocationTagged<string>("@", 11, 0, 11))).Accepts(AcceptedCharacters.None),
|
||||
Factory.Markup("@").With(SpanCodeGenerator.Null).Accepts(AcceptedCharacters.None)),
|
||||
Factory.Markup("'").With(SpanCodeGenerator.Null)),
|
||||
Factory.Markup(" />"))));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ConditionalAttributesDoNotCreateExtraDataForEntirelyLiteralAttribute()
|
||||
{
|
||||
|
|
|
|||
|
|
@ -2,11 +2,13 @@
|
|||
// 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 Microsoft.AspNet.Razor.Generator;
|
||||
using Microsoft.AspNet.Razor.Parser;
|
||||
using Microsoft.AspNet.Razor.Parser.SyntaxTree;
|
||||
using Microsoft.AspNet.Razor.Test.Framework;
|
||||
using Microsoft.AspNet.Razor.Text;
|
||||
using Microsoft.AspNet.Razor.Tokenizer;
|
||||
using Xunit;
|
||||
|
||||
namespace Microsoft.AspNet.Razor.Test.Parser.Html
|
||||
|
|
@ -281,5 +283,302 @@ namespace Microsoft.AspNet.Razor.Test.Parser.Html
|
|||
var content = Nested1000.ReadAllText();
|
||||
ParseDocument(content);
|
||||
}
|
||||
|
||||
public static TheoryData BlockWithEscapedTransitionData
|
||||
{
|
||||
get
|
||||
{
|
||||
var factory = CreateDefaultSpanFactory();
|
||||
var datetimeBlock = new ExpressionBlock(
|
||||
factory.CodeTransition(),
|
||||
factory.Code("DateTime.Now")
|
||||
.AsImplicitExpression(CSharpCodeParser.DefaultKeywords)
|
||||
.Accepts(AcceptedCharacters.NonWhiteSpace));
|
||||
|
||||
return new TheoryData<string, Block>
|
||||
{
|
||||
{
|
||||
// Double transition in attribute value
|
||||
"<span foo='@@' />",
|
||||
new MarkupBlock(
|
||||
new MarkupTagBlock(
|
||||
factory.Markup("<span"),
|
||||
new MarkupBlock(
|
||||
new AttributeBlockCodeGenerator("foo", new LocationTagged<string>(" foo='", 5, 0, 5), new LocationTagged<string>("'", 13, 0, 13)),
|
||||
factory.Markup(" foo='").With(SpanCodeGenerator.Null),
|
||||
new MarkupBlock(
|
||||
factory.Markup("@").With(new LiteralAttributeCodeGenerator(new LocationTagged<string>(string.Empty, 11, 0, 11), new LocationTagged<string>("@", 11, 0, 11))).Accepts(AcceptedCharacters.None),
|
||||
factory.Markup("@").With(SpanCodeGenerator.Null).Accepts(AcceptedCharacters.None)),
|
||||
factory.Markup("'").With(SpanCodeGenerator.Null)),
|
||||
factory.Markup(" />")))
|
||||
},
|
||||
{
|
||||
// Double transition at the end of attribute value
|
||||
"<span foo='abc@@' />",
|
||||
new MarkupBlock(
|
||||
new MarkupTagBlock(
|
||||
factory.Markup("<span"),
|
||||
new MarkupBlock(
|
||||
new AttributeBlockCodeGenerator("foo", new LocationTagged<string>(" foo='", 5, 0, 5), new LocationTagged<string>("'", 16, 0, 16)),
|
||||
factory.Markup(" foo='").With(SpanCodeGenerator.Null),
|
||||
factory.Markup("abc").With(new LiteralAttributeCodeGenerator(new LocationTagged<string>(string.Empty, 11, 0, 11), new LocationTagged<string>("abc", 11, 0, 11))),
|
||||
new MarkupBlock(
|
||||
factory.Markup("@").With(new LiteralAttributeCodeGenerator(new LocationTagged<string>(string.Empty, 14, 0, 14), new LocationTagged<string>("@", 14, 0, 14))).Accepts(AcceptedCharacters.None),
|
||||
factory.Markup("@").With(SpanCodeGenerator.Null).Accepts(AcceptedCharacters.None)),
|
||||
factory.Markup("'").With(SpanCodeGenerator.Null)),
|
||||
factory.Markup(" />")))
|
||||
},
|
||||
{
|
||||
// Double transition at the beginning of attribute value
|
||||
"<span foo='@@def' />",
|
||||
new MarkupBlock(
|
||||
new MarkupTagBlock(
|
||||
factory.Markup("<span"),
|
||||
new MarkupBlock(
|
||||
new AttributeBlockCodeGenerator("foo", new LocationTagged<string>(" foo='", 5, 0, 5), new LocationTagged<string>("'", 16, 0, 16)),
|
||||
factory.Markup(" foo='").With(SpanCodeGenerator.Null),
|
||||
new MarkupBlock(
|
||||
factory.Markup("@").With(new LiteralAttributeCodeGenerator(new LocationTagged<string>(string.Empty, 11, 0, 11), new LocationTagged<string>("@", 11, 0, 11))).Accepts(AcceptedCharacters.None),
|
||||
factory.Markup("@").With(SpanCodeGenerator.Null).Accepts(AcceptedCharacters.None)),
|
||||
factory.Markup("def").With(new LiteralAttributeCodeGenerator(new LocationTagged<string>(string.Empty, 13, 0, 13), new LocationTagged<string>("def", 13, 0, 13))),
|
||||
factory.Markup("'").With(SpanCodeGenerator.Null)),
|
||||
factory.Markup(" />")))
|
||||
},
|
||||
{
|
||||
// Double transition in between attribute value
|
||||
"<span foo='abc @@ def' />",
|
||||
new MarkupBlock(
|
||||
new MarkupTagBlock(
|
||||
factory.Markup("<span"),
|
||||
new MarkupBlock(
|
||||
new AttributeBlockCodeGenerator("foo", new LocationTagged<string>(" foo='", 5, 0, 5), new LocationTagged<string>("'", 21, 0, 21)),
|
||||
factory.Markup(" foo='").With(SpanCodeGenerator.Null),
|
||||
factory.Markup("abc").With(new LiteralAttributeCodeGenerator(new LocationTagged<string>(string.Empty, 11, 0, 11), new LocationTagged<string>("abc", 11, 0, 11))),
|
||||
new MarkupBlock(
|
||||
factory.Markup(" @").With(new LiteralAttributeCodeGenerator(new LocationTagged<string>(" ", 14, 0, 14), new LocationTagged<string>("@", 15, 0, 15))).Accepts(AcceptedCharacters.None),
|
||||
factory.Markup("@").With(SpanCodeGenerator.Null).Accepts(AcceptedCharacters.None)),
|
||||
factory.Markup(" def").With(new LiteralAttributeCodeGenerator(new LocationTagged<string>(" ", 17, 0, 17), new LocationTagged<string>("def", 18, 0, 18))),
|
||||
factory.Markup("'").With(SpanCodeGenerator.Null)),
|
||||
factory.Markup(" />")))
|
||||
},
|
||||
{
|
||||
// Double transition with expression block
|
||||
"<span foo='@@@DateTime.Now' />",
|
||||
new MarkupBlock(
|
||||
new MarkupTagBlock(
|
||||
factory.Markup("<span"),
|
||||
new MarkupBlock(
|
||||
new AttributeBlockCodeGenerator("foo", new LocationTagged<string>(" foo='", 5, 0, 5), new LocationTagged<string>("'", 26, 0, 26)),
|
||||
factory.Markup(" foo='").With(SpanCodeGenerator.Null),
|
||||
new MarkupBlock(
|
||||
factory.Markup("@").With(new LiteralAttributeCodeGenerator(new LocationTagged<string>(string.Empty, 11, 0, 11), new LocationTagged<string>("@", 11, 0, 11))).Accepts(AcceptedCharacters.None),
|
||||
factory.Markup("@").With(SpanCodeGenerator.Null).Accepts(AcceptedCharacters.None)),
|
||||
new MarkupBlock(
|
||||
new DynamicAttributeBlockCodeGenerator(new LocationTagged<string>(string.Empty, 13, 0, 13), 13, 0, 13),
|
||||
factory.EmptyHtml().With(SpanCodeGenerator.Null),
|
||||
datetimeBlock),
|
||||
factory.Markup("'").With(SpanCodeGenerator.Null)),
|
||||
factory.Markup(" />")))
|
||||
},
|
||||
{
|
||||
"<span foo='@DateTime.Now @@' />",
|
||||
new MarkupBlock(
|
||||
new MarkupTagBlock(
|
||||
factory.Markup("<span"),
|
||||
new MarkupBlock(
|
||||
new AttributeBlockCodeGenerator("foo", new LocationTagged<string>(" foo='", 5, 0, 5), new LocationTagged<string>("'", 27, 0, 27)),
|
||||
factory.Markup(" foo='").With(SpanCodeGenerator.Null),
|
||||
new MarkupBlock(
|
||||
new DynamicAttributeBlockCodeGenerator(new LocationTagged<string>(string.Empty, 11, 0, 11), 11, 0, 11),
|
||||
datetimeBlock),
|
||||
new MarkupBlock(
|
||||
factory.Markup(" @").With(new LiteralAttributeCodeGenerator(new LocationTagged<string>(" ", 24, 0, 24), new LocationTagged<string>("@", 25, 0, 25))).Accepts(AcceptedCharacters.None),
|
||||
factory.Markup("@").With(SpanCodeGenerator.Null).Accepts(AcceptedCharacters.None)),
|
||||
factory.Markup("'").With(SpanCodeGenerator.Null)),
|
||||
factory.Markup(" />")))
|
||||
},
|
||||
{
|
||||
"<span foo='@(2+3)@@@DateTime.Now' />",
|
||||
new MarkupBlock(
|
||||
new MarkupTagBlock(
|
||||
factory.Markup("<span"),
|
||||
new MarkupBlock(
|
||||
new AttributeBlockCodeGenerator("foo", new LocationTagged<string>(" foo='", 5, 0, 5), new LocationTagged<string>("'", 32, 0, 32)),
|
||||
factory.Markup(" foo='").With(SpanCodeGenerator.Null),
|
||||
new MarkupBlock(
|
||||
new DynamicAttributeBlockCodeGenerator(new LocationTagged<string>(string.Empty, 11, 0, 11), 11, 0, 11),
|
||||
new ExpressionBlock(
|
||||
factory.CodeTransition(),
|
||||
factory.MetaCode("(").With(SpanCodeGenerator.Null).Accepts(AcceptedCharacters.None),
|
||||
factory.Code("2+3").AsExpression(),
|
||||
factory.MetaCode(")").With(SpanCodeGenerator.Null).Accepts(AcceptedCharacters.None))),
|
||||
new MarkupBlock(
|
||||
factory.Markup("@").With(new LiteralAttributeCodeGenerator(new LocationTagged<string>(string.Empty, 17, 0, 17), new LocationTagged<string>("@", 17, 0, 17))).Accepts(AcceptedCharacters.None),
|
||||
factory.Markup("@").With(SpanCodeGenerator.Null).Accepts(AcceptedCharacters.None)),
|
||||
new MarkupBlock(
|
||||
new DynamicAttributeBlockCodeGenerator(new LocationTagged<string>(string.Empty, 19, 0, 19), 19, 0, 19),
|
||||
factory.EmptyHtml().With(SpanCodeGenerator.Null),
|
||||
datetimeBlock),
|
||||
factory.Markup("'").With(SpanCodeGenerator.Null)),
|
||||
factory.Markup(" />")))
|
||||
},
|
||||
{
|
||||
"<span foo='@@@(2+3)' />",
|
||||
new MarkupBlock(
|
||||
new MarkupTagBlock(
|
||||
factory.Markup("<span"),
|
||||
new MarkupBlock(
|
||||
new AttributeBlockCodeGenerator("foo", new LocationTagged<string>(" foo='", 5, 0, 5), new LocationTagged<string>("'", 19, 0, 19)),
|
||||
factory.Markup(" foo='").With(SpanCodeGenerator.Null),
|
||||
new MarkupBlock(
|
||||
factory.Markup("@").With(new LiteralAttributeCodeGenerator(new LocationTagged<string>(string.Empty, 11, 0, 11), new LocationTagged<string>("@", 11, 0, 11))).Accepts(AcceptedCharacters.None),
|
||||
factory.Markup("@").With(SpanCodeGenerator.Null).Accepts(AcceptedCharacters.None)),
|
||||
new MarkupBlock(
|
||||
new DynamicAttributeBlockCodeGenerator(new LocationTagged<string>(string.Empty, 13, 0, 13), 13, 0, 13),
|
||||
factory.EmptyHtml().With(SpanCodeGenerator.Null),
|
||||
new ExpressionBlock(
|
||||
factory.CodeTransition(),
|
||||
factory.MetaCode("(").With(SpanCodeGenerator.Null).Accepts(AcceptedCharacters.None),
|
||||
factory.Code("2+3").AsExpression(),
|
||||
factory.MetaCode(")").With(SpanCodeGenerator.Null).Accepts(AcceptedCharacters.None))),
|
||||
factory.Markup("'").With(SpanCodeGenerator.Null)),
|
||||
factory.Markup(" />")))
|
||||
},
|
||||
{
|
||||
"<span foo='@DateTime.Now@@' />",
|
||||
new MarkupBlock(
|
||||
new MarkupTagBlock(
|
||||
factory.Markup("<span"),
|
||||
new MarkupBlock(
|
||||
new AttributeBlockCodeGenerator("foo", new LocationTagged<string>(" foo='", 5, 0, 5), new LocationTagged<string>("'", 26, 0, 26)),
|
||||
factory.Markup(" foo='").With(SpanCodeGenerator.Null),
|
||||
new MarkupBlock(
|
||||
new DynamicAttributeBlockCodeGenerator(new LocationTagged<string>(string.Empty, 11, 0, 11), 11, 0, 11),
|
||||
datetimeBlock),
|
||||
new MarkupBlock(
|
||||
factory.Markup("@").With(new LiteralAttributeCodeGenerator(new LocationTagged<string>(string.Empty, 24, 0, 24), new LocationTagged<string>("@", 24, 0, 24))).Accepts(AcceptedCharacters.None),
|
||||
factory.Markup("@").With(SpanCodeGenerator.Null).Accepts(AcceptedCharacters.None)),
|
||||
factory.Markup("'").With(SpanCodeGenerator.Null)),
|
||||
factory.Markup(" />")))
|
||||
},
|
||||
{
|
||||
// Double transition with email in attribute value
|
||||
"<span foo='abc@def.com @@' />",
|
||||
new MarkupBlock(
|
||||
new MarkupTagBlock(
|
||||
factory.Markup("<span"),
|
||||
new MarkupBlock(
|
||||
new AttributeBlockCodeGenerator("foo", new LocationTagged<string>(" foo='", 5, 0, 5), new LocationTagged<string>("'", 25, 0, 25)),
|
||||
factory.Markup(" foo='").With(SpanCodeGenerator.Null),
|
||||
factory.Markup("abc@def.com").With(new LiteralAttributeCodeGenerator(new LocationTagged<string>(string.Empty, 11, 0, 11), new LocationTagged<string>("abc@def.com", 11, 0, 11))),
|
||||
new MarkupBlock(
|
||||
factory.Markup(" @").With(new LiteralAttributeCodeGenerator(new LocationTagged<string>(" ", 22, 0, 22), new LocationTagged<string>("@", 23, 0, 23))).Accepts(AcceptedCharacters.None),
|
||||
factory.Markup("@").With(SpanCodeGenerator.Null).Accepts(AcceptedCharacters.None)),
|
||||
factory.Markup("'").With(SpanCodeGenerator.Null)),
|
||||
factory.Markup(" />")))
|
||||
},
|
||||
{
|
||||
"<span foo='abc@@def.com @@' />",
|
||||
new MarkupBlock(
|
||||
new MarkupTagBlock(
|
||||
factory.Markup("<span"),
|
||||
new MarkupBlock(
|
||||
new AttributeBlockCodeGenerator("foo", new LocationTagged<string>(" foo='", 5, 0, 5), new LocationTagged<string>("'", 26, 0, 26)),
|
||||
factory.Markup(" foo='").With(SpanCodeGenerator.Null),
|
||||
factory.Markup("abc").With(new LiteralAttributeCodeGenerator(new LocationTagged<string>(string.Empty, 11, 0, 11), new LocationTagged<string>("abc", 11, 0, 11))),
|
||||
new MarkupBlock(
|
||||
factory.Markup("@").With(new LiteralAttributeCodeGenerator(new LocationTagged<string>(string.Empty, 14, 0, 14), new LocationTagged<string>("@", 14, 0, 14))).Accepts(AcceptedCharacters.None),
|
||||
factory.Markup("@").With(SpanCodeGenerator.Null).Accepts(AcceptedCharacters.None)),
|
||||
factory.Markup("def.com").With(new LiteralAttributeCodeGenerator(new LocationTagged<string>(string.Empty, 16, 0, 16), new LocationTagged<string>("def.com", 16, 0, 16))),
|
||||
new MarkupBlock(
|
||||
factory.Markup(" @").With(new LiteralAttributeCodeGenerator(new LocationTagged<string>(" ", 23, 0, 23), new LocationTagged<string>("@", 24, 0, 24))).Accepts(AcceptedCharacters.None),
|
||||
factory.Markup("@").With(SpanCodeGenerator.Null).Accepts(AcceptedCharacters.None)),
|
||||
factory.Markup("'").With(SpanCodeGenerator.Null)),
|
||||
factory.Markup(" />")))
|
||||
},
|
||||
{
|
||||
// Double transition before end of file
|
||||
"<span foo='@@",
|
||||
new MarkupBlock(
|
||||
new MarkupTagBlock(
|
||||
factory.Markup("<span"),
|
||||
new MarkupBlock(
|
||||
new AttributeBlockCodeGenerator("foo", new LocationTagged<string>(" foo='", 5, 0, 5), new LocationTagged<string>(string.Empty, 13, 0, 13)),
|
||||
factory.Markup(" foo='").With(SpanCodeGenerator.Null),
|
||||
new MarkupBlock(
|
||||
factory.Markup("@").With(new LiteralAttributeCodeGenerator(new LocationTagged<string>(string.Empty, 11, 0, 11), new LocationTagged<string>("@", 11, 0, 11))).Accepts(AcceptedCharacters.None),
|
||||
factory.Markup("@").With(SpanCodeGenerator.Null).Accepts(AcceptedCharacters.None)))),
|
||||
factory.EmptyHtml())
|
||||
},
|
||||
{
|
||||
// Double transition in complex regex in attribute value
|
||||
@"<span foo=""/^[a-z0-9!#$%&'*+\/=?^_`{|}~.-]+@@[a-z0-9]([a-z0-9-]*[a-z0-9])?\.([a-z0-9]([a-z0-9-]*[a-z0-9])?)*$/i"" />",
|
||||
new MarkupBlock(
|
||||
new MarkupTagBlock(
|
||||
factory.Markup("<span"),
|
||||
new MarkupBlock(
|
||||
new AttributeBlockCodeGenerator("foo", new LocationTagged<string>(" foo=\"", 5, 0, 5), new LocationTagged<string>("\"", 111, 0, 111)),
|
||||
factory.Markup(" foo=\"").With(SpanCodeGenerator.Null),
|
||||
factory.Markup(@"/^[a-z0-9!#$%&'*+\/=?^_`{|}~.-]+").With(new LiteralAttributeCodeGenerator(new LocationTagged<string>(string.Empty, 11, 0, 11), new LocationTagged<string>(@"/^[a-z0-9!#$%&'*+\/=?^_`{|}~.-]+", 11, 0, 11))),
|
||||
new MarkupBlock(
|
||||
factory.Markup("@").With(new LiteralAttributeCodeGenerator(new LocationTagged<string>(string.Empty, 43, 0, 43), new LocationTagged<string>("@", 43, 0, 43))).Accepts(AcceptedCharacters.None),
|
||||
factory.Markup("@").With(SpanCodeGenerator.Null).Accepts(AcceptedCharacters.None)),
|
||||
factory.Markup(@"[a-z0-9]([a-z0-9-]*[a-z0-9])?\.([a-z0-9]([a-z0-9-]*[a-z0-9])?)*$/i").With(new LiteralAttributeCodeGenerator(new LocationTagged<string>(string.Empty, 45, 0, 45), new LocationTagged<string>(@"[a-z0-9]([a-z0-9-]*[a-z0-9])?\.([a-z0-9]([a-z0-9-]*[a-z0-9])?)*$/i", 45, 0, 45))),
|
||||
factory.Markup("\"").With(SpanCodeGenerator.Null)),
|
||||
factory.Markup(" />")))
|
||||
},
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[MemberData(nameof(BlockWithEscapedTransitionData))]
|
||||
public void ParseBlock_WithDoubleTransition_DoesNotThrow(string input, Block expected)
|
||||
{
|
||||
// Act & Assert
|
||||
ParseDocumentTest(input, expected);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ParseDocument_WithUnexpectedTransitionsInAttributeValue_Throws()
|
||||
{
|
||||
// Arrange
|
||||
var expected = new MarkupBlock(
|
||||
new MarkupTagBlock(
|
||||
Factory.Markup("<span"),
|
||||
new MarkupBlock(
|
||||
new AttributeBlockCodeGenerator("foo", new LocationTagged<string>(" foo='", 5, 0, 5), new LocationTagged<string>("'", 14, 0, 14)),
|
||||
Factory.Markup(" foo='").With(SpanCodeGenerator.Null),
|
||||
new MarkupBlock(
|
||||
new DynamicAttributeBlockCodeGenerator(new LocationTagged<string>(string.Empty, 11, 0, 11), 11, 0, 11),
|
||||
new ExpressionBlock(
|
||||
Factory.CodeTransition(),
|
||||
Factory.EmptyCSharp().AsImplicitExpression(CSharpCodeParser.DefaultKeywords).Accepts(AcceptedCharacters.NonWhiteSpace))),
|
||||
new MarkupBlock(
|
||||
new DynamicAttributeBlockCodeGenerator(new LocationTagged<string>(" ", 12, 0, 12), 12, 0, 12),
|
||||
Factory.Markup(" ").With(SpanCodeGenerator.Null),
|
||||
new ExpressionBlock(
|
||||
Factory.CodeTransition().Accepts(AcceptedCharacters.None).With(SpanCodeGenerator.Null),
|
||||
Factory.EmptyCSharp().AsImplicitExpression(CSharpCodeParser.DefaultKeywords).Accepts(AcceptedCharacters.NonWhiteSpace))),
|
||||
Factory.Markup("'").With(SpanCodeGenerator.Null)),
|
||||
Factory.Markup(" />")));
|
||||
var expectedErrors = new RazorError[]
|
||||
{
|
||||
new RazorError(@"A space or line break was encountered after the ""@"" character. Only valid identifiers, keywords, comments, ""("" and ""{"" are valid at the start of a code block and they must occur immediately following ""@"" with no space in between.", new SourceLocation(12, 0, 12)),
|
||||
new RazorError(@"""' />"" is not valid at the start of a code block. Only identifiers, keywords, comments, ""("" and ""{"" are valid.", new SourceLocation(14, 0, 14)),
|
||||
};
|
||||
|
||||
// Act & Assert
|
||||
ParseDocumentTest("<span foo='@ @' />", expected, expectedErrors);
|
||||
}
|
||||
|
||||
private static SpanFactory CreateDefaultSpanFactory()
|
||||
{
|
||||
return new SpanFactory
|
||||
{
|
||||
MarkupTokenizerFactory = doc => new HtmlTokenizer(doc),
|
||||
CodeTokenizerFactory = doc => new CSharpTokenizer(doc)
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -352,6 +352,24 @@ namespace Microsoft.AspNet.Razor.Test.TagHelpers
|
|||
},
|
||||
children: factory.Markup("words and spaces")))
|
||||
},
|
||||
{
|
||||
"<div style=\"\" class=\"btn\" catchAll=\"@@hi\" >words and spaces</div>",
|
||||
new MarkupBlock(
|
||||
new MarkupTagHelperBlock(
|
||||
"div",
|
||||
attributes: new List<KeyValuePair<string, SyntaxTreeNode>>
|
||||
{
|
||||
new KeyValuePair<string, SyntaxTreeNode>("style", new MarkupBlock()),
|
||||
new KeyValuePair<string, SyntaxTreeNode>("class", factory.Markup("btn")),
|
||||
new KeyValuePair<string, SyntaxTreeNode>("catchAll",
|
||||
new MarkupBlock(
|
||||
new MarkupBlock(
|
||||
factory.Markup("@").Accepts(AcceptedCharacters.None),
|
||||
factory.Markup("@").With(SpanCodeGenerator.Null).Accepts(AcceptedCharacters.None)),
|
||||
factory.Markup("hi"))),
|
||||
},
|
||||
children: factory.Markup("words and spaces")))
|
||||
},
|
||||
{
|
||||
"<div style=\"@DateTime.Now\" class=\"@DateTime.Now\" catchAll=\"@DateTime.Now\" >words and " +
|
||||
"spaces</div>",
|
||||
|
|
@ -1143,6 +1161,32 @@ namespace Microsoft.AspNet.Razor.Test.TagHelpers
|
|||
})),
|
||||
availableDescriptorsText
|
||||
},
|
||||
{
|
||||
"<PREFIXmyth2 bound=\"@@@DateTime.Now\" />",
|
||||
new MarkupBlock(
|
||||
new MarkupTagHelperBlock(
|
||||
"PREFIXmyth2",
|
||||
selfClosing: true,
|
||||
attributes: new List<KeyValuePair<string, SyntaxTreeNode>>
|
||||
{
|
||||
{
|
||||
new KeyValuePair<string, SyntaxTreeNode>(
|
||||
"bound",
|
||||
new MarkupBlock(
|
||||
new MarkupBlock(
|
||||
factory.Markup("@").Accepts(AcceptedCharacters.None),
|
||||
factory.Markup("@").With(SpanCodeGenerator.Null).Accepts(AcceptedCharacters.None)),
|
||||
new MarkupBlock(
|
||||
factory.EmptyHtml(),
|
||||
new ExpressionBlock(
|
||||
factory.CodeTransition(),
|
||||
factory.Code("DateTime.Now")
|
||||
.AsImplicitExpression(CSharpCodeParser.DefaultKeywords)
|
||||
.Accepts(AcceptedCharacters.NonWhiteSpace)))))
|
||||
}
|
||||
})),
|
||||
availableDescriptorsText
|
||||
},
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
@ -2175,6 +2219,41 @@ namespace Microsoft.AspNet.Razor.Test.TagHelpers
|
|||
absoluteIndex: 2, lineIndex: 0, columnIndex: 2)
|
||||
}
|
||||
},
|
||||
{
|
||||
"@{<!p class=\"btn@@}",
|
||||
buildPartialStatementBlock(
|
||||
() => new MarkupBlock(
|
||||
new MarkupTagBlock(
|
||||
factory.Markup("<"),
|
||||
factory.BangEscape(),
|
||||
factory.Markup("p"),
|
||||
new MarkupBlock(
|
||||
new AttributeBlockCodeGenerator(
|
||||
name: "class",
|
||||
prefix: new LocationTagged<string>(" class=\"", 5, 0, 5),
|
||||
suffix: new LocationTagged<string>(string.Empty, 19, 0, 19)),
|
||||
factory.Markup(" class=\"").With(SpanCodeGenerator.Null),
|
||||
factory.Markup("btn").With(
|
||||
new LiteralAttributeCodeGenerator(
|
||||
prefix: new LocationTagged<string>(string.Empty, 13, 0, 13),
|
||||
value: new LocationTagged<string>("btn", 13, 0, 13))),
|
||||
new MarkupBlock(
|
||||
factory.Markup("@").With(new LiteralAttributeCodeGenerator(new LocationTagged<string>(string.Empty, 16, 0, 16), new LocationTagged<string>("@", 16, 0, 16))).Accepts(AcceptedCharacters.None),
|
||||
factory.Markup("@").With(SpanCodeGenerator.Null).Accepts(AcceptedCharacters.None)),
|
||||
factory.Markup("}").With(
|
||||
new LiteralAttributeCodeGenerator(
|
||||
prefix: new LocationTagged<string>(string.Empty, 18, 0, 18),
|
||||
value: new LocationTagged<string>("}", 18, 0, 18))))))),
|
||||
new []
|
||||
{
|
||||
new RazorError(
|
||||
errorMatchingBrace,
|
||||
absoluteIndex: 1, lineIndex: 0, columnIndex: 1),
|
||||
new RazorError(
|
||||
string.Format(errorEOFMatchingBrace, "!p"),
|
||||
absoluteIndex: 2, lineIndex: 0, columnIndex: 2)
|
||||
}
|
||||
},
|
||||
{
|
||||
"@{<!p class=\"btn\"}",
|
||||
buildPartialStatementBlock(
|
||||
|
|
@ -3697,6 +3776,75 @@ namespace Microsoft.AspNet.Razor.Test.TagHelpers
|
|||
new MarkupBlock(factory.Markup("Time:"), dateTimeNow))
|
||||
}))
|
||||
},
|
||||
{
|
||||
"<person age=\"12\" birthday=\"DateTime.Now\" name=\"Time: @@ @DateTime.Now\" />",
|
||||
new MarkupBlock(
|
||||
new MarkupTagHelperBlock("person",
|
||||
selfClosing: true,
|
||||
attributes: new List<KeyValuePair<string, SyntaxTreeNode>>
|
||||
{
|
||||
new KeyValuePair<string, SyntaxTreeNode>("age", factory.CodeMarkup("12")),
|
||||
new KeyValuePair<string, SyntaxTreeNode>(
|
||||
"birthday",
|
||||
factory.CodeMarkup("DateTime.Now")),
|
||||
new KeyValuePair<string, SyntaxTreeNode>(
|
||||
"name",
|
||||
new MarkupBlock(
|
||||
factory.Markup("Time:"),
|
||||
new MarkupBlock(
|
||||
factory.Markup(" @").Accepts(AcceptedCharacters.None),
|
||||
factory.Markup("@").With(SpanCodeGenerator.Null).Accepts(AcceptedCharacters.None)),
|
||||
dateTimeNow))
|
||||
}))
|
||||
},
|
||||
{
|
||||
"<person age=\"12\" birthday=\"DateTime.Now\" name=\"@@BoundStringAttribute\" />",
|
||||
new MarkupBlock(
|
||||
new MarkupTagHelperBlock("person",
|
||||
selfClosing: true,
|
||||
attributes: new List<KeyValuePair<string, SyntaxTreeNode>>
|
||||
{
|
||||
new KeyValuePair<string, SyntaxTreeNode>("age", factory.CodeMarkup("12")),
|
||||
new KeyValuePair<string, SyntaxTreeNode>(
|
||||
"birthday",
|
||||
factory.CodeMarkup("DateTime.Now")),
|
||||
new KeyValuePair<string, SyntaxTreeNode>(
|
||||
"name",
|
||||
new MarkupBlock(
|
||||
new MarkupBlock(
|
||||
factory.Markup("@").Accepts(AcceptedCharacters.None),
|
||||
factory.Markup("@").With(SpanCodeGenerator.Null).Accepts(AcceptedCharacters.None)),
|
||||
factory.Markup("BoundStringAttribute")))
|
||||
}))
|
||||
},
|
||||
{
|
||||
"<person age=\"@@@(11+1)\" birthday=\"DateTime.Now\" name=\"Time: @DateTime.Now\" />",
|
||||
new MarkupBlock(
|
||||
new MarkupTagHelperBlock("person",
|
||||
selfClosing: true,
|
||||
attributes: new List<KeyValuePair<string, SyntaxTreeNode>>
|
||||
{
|
||||
new KeyValuePair<string, SyntaxTreeNode>(
|
||||
"age",
|
||||
new MarkupBlock(
|
||||
new MarkupBlock(
|
||||
factory.Markup("@").Accepts(AcceptedCharacters.None),
|
||||
factory.Markup("@").With(SpanCodeGenerator.Null).Accepts(AcceptedCharacters.None)),
|
||||
new MarkupBlock(
|
||||
factory.EmptyHtml(),
|
||||
new ExpressionBlock(
|
||||
factory.CodeTransition(),
|
||||
factory.MetaCode("(").Accepts(AcceptedCharacters.None),
|
||||
factory.Code("11+1").AsExpression(),
|
||||
factory.MetaCode(")").Accepts(AcceptedCharacters.None))))),
|
||||
new KeyValuePair<string, SyntaxTreeNode>(
|
||||
"birthday",
|
||||
factory.CodeMarkup("DateTime.Now")),
|
||||
new KeyValuePair<string, SyntaxTreeNode>(
|
||||
"name",
|
||||
new MarkupBlock(factory.Markup("Time:"), dateTimeNow))
|
||||
}))
|
||||
},
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
@ -4535,6 +4683,25 @@ namespace Microsoft.AspNet.Razor.Test.TagHelpers
|
|||
}),
|
||||
factory.Markup(" World")))
|
||||
};
|
||||
yield return new object[] {
|
||||
"<p>Hello <script class=\"@@foo@bar.com\" style=\"color:red;\"></script> World</p>",
|
||||
new MarkupBlock(
|
||||
new MarkupTagHelperBlock("p",
|
||||
factory.Markup("Hello "),
|
||||
new MarkupTagHelperBlock("script",
|
||||
new List<KeyValuePair<string, SyntaxTreeNode>>
|
||||
{
|
||||
new KeyValuePair<string, SyntaxTreeNode>(
|
||||
"class",
|
||||
new MarkupBlock(
|
||||
new MarkupBlock(
|
||||
factory.Markup("@").Accepts(AcceptedCharacters.None),
|
||||
factory.Markup("@").With(SpanCodeGenerator.Null).Accepts(AcceptedCharacters.None)),
|
||||
factory.Markup("foo@bar.com"))),
|
||||
new KeyValuePair<string, SyntaxTreeNode>("style", factory.Markup("color:red;"))
|
||||
}),
|
||||
factory.Markup(" World")))
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -4651,6 +4818,25 @@ namespace Microsoft.AspNet.Razor.Test.TagHelpers
|
|||
},
|
||||
factory.Markup("Hello World")))
|
||||
};
|
||||
yield return new object[] {
|
||||
"<p class=foo dynamic=@DateTime.Now style=color@@:red;>Hello World</p>",
|
||||
new MarkupBlock(
|
||||
new MarkupTagHelperBlock("p",
|
||||
new List<KeyValuePair<string, SyntaxTreeNode>>
|
||||
{
|
||||
new KeyValuePair<string, SyntaxTreeNode>("class", factory.Markup("foo")),
|
||||
new KeyValuePair<string, SyntaxTreeNode>("dynamic", new MarkupBlock(dateTimeNow)),
|
||||
new KeyValuePair<string, SyntaxTreeNode>(
|
||||
"style",
|
||||
new MarkupBlock(
|
||||
factory.Markup("color"),
|
||||
new MarkupBlock(
|
||||
factory.Markup("@").Accepts(AcceptedCharacters.None),
|
||||
factory.Markup("@").With(SpanCodeGenerator.Null).Accepts(AcceptedCharacters.None)),
|
||||
factory.Markup(":red;")))
|
||||
},
|
||||
factory.Markup("Hello World")))
|
||||
};
|
||||
yield return new object[] {
|
||||
"<p class=foo dynamic=@DateTime.Now>Hello</p> <p style=color:red; dynamic=@DateTime.Now>World</p>",
|
||||
new MarkupBlock(
|
||||
|
|
|
|||
Loading…
Reference in New Issue