Allow optional quotes around tag helper directives

Fixes #636
This commit is contained in:
Pranav K 2015-12-28 10:35:51 -08:00
parent 77b74b0c96
commit e1aa888165
19 changed files with 397 additions and 106 deletions

View File

@ -10,6 +10,19 @@ namespace Microsoft.AspNet.Razor.Chunks.Generators
/// </summary>
public class AddTagHelperChunkGenerator : SpanChunkGenerator
{
private readonly string _lookupText;
/// <summary>
/// Initializes a new instance of <see cref="AddTagHelperChunkGenerator"/>.
/// </summary>
/// <param name="lookupText">
/// Text used to look up <see cref="Compilation.TagHelpers.TagHelperDescriptor"/>s that should be added.
/// </param>
public AddTagHelperChunkGenerator(string lookupText)
{
_lookupText = lookupText;
}
/// <summary>
/// Generates <see cref="AddTagHelperChunk"/>s.
/// </summary>
@ -20,9 +33,7 @@ namespace Microsoft.AspNet.Razor.Chunks.Generators
/// the current chunk generation process.</param>
public override void GenerateChunk(Span target, ChunkGeneratorContext context)
{
var lookupText = target.Content.Trim();
context.ChunkTreeBuilder.AddAddTagHelperChunk(lookupText, target);
context.ChunkTreeBuilder.AddAddTagHelperChunk(_lookupText, target);
}
}
}

View File

@ -10,6 +10,19 @@ namespace Microsoft.AspNet.Razor.Chunks.Generators
/// </summary>
public class RemoveTagHelperChunkGenerator : SpanChunkGenerator
{
private readonly string _lookupText;
/// <summary>
/// Initializes a new instance of <see cref="RemoveTagHelperChunkGenerator"/>.
/// </summary>
/// <param name="lookupText">
/// Text used to look up <see cref="Compilation.TagHelpers.TagHelperDescriptor"/>s that should be removed.
/// </param>
public RemoveTagHelperChunkGenerator(string lookupText)
{
_lookupText = lookupText;
}
/// <summary>
/// Generates <see cref="RemoveTagHelperChunk"/>s.
/// </summary>
@ -20,9 +33,7 @@ namespace Microsoft.AspNet.Razor.Chunks.Generators
/// the current chunk generation process.</param>
public override void GenerateChunk(Span target, ChunkGeneratorContext context)
{
var lookupText = target.Content.Trim();
context.ChunkTreeBuilder.AddRemoveTagHelperChunk(lookupText, target);
context.ChunkTreeBuilder.AddRemoveTagHelperChunk(_lookupText, target);
}
}
}

View File

@ -11,6 +11,19 @@ namespace Microsoft.AspNet.Razor.Chunks.Generators
/// </summary>
public class TagHelperPrefixDirectiveChunkGenerator : SpanChunkGenerator
{
private readonly string _prefix;
/// <summary>
/// Initializes a new instance of <see cref="TagHelperPrefixDirectiveChunkGenerator"/>.
/// </summary>
/// <param name="prefix">
/// Text used as a required prefix when matching HTML.
/// </param>
public TagHelperPrefixDirectiveChunkGenerator(string prefix)
{
_prefix = prefix;
}
/// <summary>
/// Generates <see cref="TagHelperPrefixDirectiveChunk"/>s.
/// </summary>
@ -21,9 +34,7 @@ namespace Microsoft.AspNet.Razor.Chunks.Generators
/// the current chunk generation process.</param>
public override void GenerateChunk(Span target, ChunkGeneratorContext context)
{
var prefix = target.Content.Trim();
context.ChunkTreeBuilder.AddTagHelperPrefixDirectiveChunk(prefix, target);
context.ChunkTreeBuilder.AddTagHelperPrefixDirectiveChunk(_prefix, target);
}
}
}

View File

@ -5,6 +5,7 @@ using System;
using System.Diagnostics;
using System.Globalization;
using Microsoft.AspNet.Razor.Chunks;
using Microsoft.AspNet.Razor.Parser.SyntaxTree;
namespace Microsoft.AspNet.Razor.CodeGenerators.Visitors
{
@ -74,20 +75,20 @@ namespace Microsoft.AspNet.Razor.CodeGenerators.Visitors
protected override void Visit(TagHelperPrefixDirectiveChunk chunk)
{
VisitTagHelperDirectiveChunk(chunk.Prefix, chunk);
VisitTagHelperDirectiveChunk(chunk);
}
protected override void Visit(AddTagHelperChunk chunk)
{
VisitTagHelperDirectiveChunk(chunk.LookupText, chunk);
VisitTagHelperDirectiveChunk(chunk);
}
protected override void Visit(RemoveTagHelperChunk chunk)
{
VisitTagHelperDirectiveChunk(chunk.LookupText, chunk);
VisitTagHelperDirectiveChunk(chunk);
}
private void VisitTagHelperDirectiveChunk(string text, Chunk chunk)
private void VisitTagHelperDirectiveChunk(Chunk chunk)
{
// We should always be in design time mode because of the calling AcceptTree method verification.
Debug.Assert(Context.Host.DesignTimeMode);
@ -98,16 +99,26 @@ namespace Microsoft.AspNet.Razor.CodeGenerators.Visitors
Writer.WriteVariableDeclaration("string", TagHelperDirectiveSyntaxHelper, "null");
}
Writer
.WriteStartAssignment(TagHelperDirectiveSyntaxHelper)
.Write("\"");
var text = ((Span)chunk.Association).Content.Trim();
Writer.WriteStartAssignment(TagHelperDirectiveSyntaxHelper);
if (!text.StartsWith("\"", StringComparison.Ordinal))
{
Writer.Write("\"");
}
using (new CSharpLineMappingWriter(Writer, chunk.Start, text.Length))
{
Writer.Write(text);
}
Writer.WriteLine("\";");
if (!text.EndsWith("\"", StringComparison.Ordinal))
{
Writer.Write("\"");
}
Writer.WriteLine(";");
}
}
}

View File

@ -25,17 +25,21 @@ namespace Microsoft.AspNet.Razor.Parser
{
TagHelperDirective(
SyntaxConstants.CSharp.TagHelperPrefixKeyword,
new TagHelperPrefixDirectiveChunkGenerator());
prefix => new TagHelperPrefixDirectiveChunkGenerator(prefix));
}
protected virtual void AddTagHelperDirective()
{
TagHelperDirective(SyntaxConstants.CSharp.AddTagHelperKeyword, new AddTagHelperChunkGenerator());
TagHelperDirective(
SyntaxConstants.CSharp.AddTagHelperKeyword,
lookupText => new AddTagHelperChunkGenerator(lookupText));
}
protected virtual void RemoveTagHelperDirective()
{
TagHelperDirective(SyntaxConstants.CSharp.RemoveTagHelperKeyword, new RemoveTagHelperChunkGenerator());
TagHelperDirective(
SyntaxConstants.CSharp.RemoveTagHelperKeyword,
lookupText => new RemoveTagHelperChunkGenerator(lookupText));
}
protected virtual void SectionDirective()
@ -285,7 +289,7 @@ namespace Microsoft.AspNet.Razor.Parser
Output(SpanKind.Code, AcceptedCharacters.AnyExceptNewline);
}
private void TagHelperDirective(string keyword, ISpanChunkGenerator chunkGenerator)
private void TagHelperDirective(string keyword, Func<string, ISpanChunkGenerator> chunkGeneratorFactory)
{
AssertDirective(keyword);
var keywordStartLocation = CurrentLocation;
@ -305,12 +309,15 @@ namespace Microsoft.AspNet.Razor.Parser
// to the document. We can't accept it.
Output(SpanKind.MetaCode, foundWhitespace ? AcceptedCharacters.None : AcceptedCharacters.AnyExceptNewline);
ISpanChunkGenerator chunkGenerator;
if (EndOfFile || At(CSharpSymbolType.NewLine))
{
Context.OnError(
keywordStartLocation,
RazorResources.FormatParseError_DirectiveMustHaveValue(keyword),
keywordLength);
chunkGenerator = chunkGeneratorFactory(string.Empty);
}
else
{
@ -320,6 +327,34 @@ namespace Microsoft.AspNet.Razor.Parser
// Parse to the end of the line. Essentially accepts anything until end of line, comments, invalid code
// etc.
AcceptUntil(CSharpSymbolType.NewLine);
// Pull out the value and remove whitespaces and optional quotes
var rawValue = Span.GetContent().Value.Trim();
var startsWithQuote = rawValue.StartsWith("\"", StringComparison.Ordinal);
var endsWithQuote = rawValue.EndsWith("\"", StringComparison.Ordinal);
if (startsWithQuote != endsWithQuote)
{
Context.OnError(
startLocation,
RazorResources.FormatParseError_IncompleteQuotesAroundDirective(keyword),
rawValue.Length);
}
else if (startsWithQuote)
{
if (rawValue.Length > 2)
{
// Remove extra quotes
rawValue = rawValue.Substring(1, rawValue.Length - 2);
}
else
{
// raw value is only quotes
rawValue = string.Empty;
}
}
chunkGenerator = chunkGeneratorFactory(rawValue);
}
Span.ChunkGenerator = chunkGenerator;

View File

@ -4,9 +4,8 @@
using System;
using System.Collections.Generic;
using Microsoft.AspNet.Razor.Chunks.Generators;
using Microsoft.AspNet.Razor.Parser.SyntaxTree;
using Microsoft.AspNet.Razor.Compilation.TagHelpers;
using System.Diagnostics;
using Microsoft.AspNet.Razor.Parser.SyntaxTree;
namespace Microsoft.AspNet.Razor.Parser.TagHelpers
{

View File

@ -1546,6 +1546,22 @@ namespace Microsoft.AspNet.Razor
return string.Format(CultureInfo.CurrentCulture, GetString("ParseError_HelperDirectiveNotAvailable"), p0);
}
/// <summary>
/// Optional quote around the directive '{0}' is missing the corresponding opening or closing quote.
/// </summary>
internal static string ParseError_IncompleteQuotesAroundDirective
{
get { return GetString("ParseError_IncompleteQuotesAroundDirective"); }
}
/// <summary>
/// Optional quote around the directive '{0}' is missing the corresponding opening or closing quote.
/// </summary>
internal static string FormatParseError_IncompleteQuotesAroundDirective(object p0)
{
return string.Format(CultureInfo.CurrentCulture, GetString("ParseError_IncompleteQuotesAroundDirective"), p0);
}
private static string GetString(string name, params string[] formatterNames)
{
var value = _resourceManager.GetString(name);

View File

@ -425,4 +425,7 @@ Instead, wrap the contents of the block in "{{}}":
<data name="ParseError_HelperDirectiveNotAvailable" xml:space="preserve">
<value>The {0} directive is not supported.</value>
</data>
<data name="ParseError_IncompleteQuotesAroundDirective" xml:space="preserve">
<value>Optional quote around the directive '{0}' is missing the corresponding opening or closing quote.</value>
</data>
</root>

View File

@ -404,11 +404,12 @@ namespace Microsoft.AspNet.Razor.Test.Generator
{
get
{
return new TheoryData<string, // Test name
string, // Baseline name
IEnumerable<TagHelperDescriptor>, // TagHelperDescriptors provided
IEnumerable<TagHelperDescriptor>, // Expected TagHelperDescriptors
bool> // Design time mode.
return new TheoryData<
string, // Test name
string, // Baseline name
IEnumerable<TagHelperDescriptor>, // TagHelperDescriptors provided
IEnumerable<TagHelperDescriptor>, // Expected TagHelperDescriptors
bool> // Design time mode.
{
{
"SingleTagHelper",
@ -527,9 +528,10 @@ namespace Microsoft.AspNet.Razor.Test.Generator
tagHelperDescriptors: tagHelperDescriptors,
onResults: (results) =>
{
Assert.Equal(expectedTagHelperDescriptors,
results.TagHelperDescriptors,
TagHelperDescriptorComparer.Default);
Assert.Equal(
expectedTagHelperDescriptors,
results.TagHelperDescriptors,
TagHelperDescriptorComparer.Default);
},
designTimeMode: designTimeMode);
}
@ -569,25 +571,25 @@ namespace Microsoft.AspNet.Razor.Test.Generator
"BasicTagHelpers",
"BasicTagHelpers.DesignTime",
DefaultPAndInputTagHelperDescriptors,
new List<LineMapping>
new[]
{
BuildLineMapping(
documentAbsoluteIndex: 14,
documentLineIndex: 0,
documentCharacterOffsetIndex: 14,
generatedAbsoluteIndex: 372,
generatedAbsoluteIndex: 371,
generatedLineIndex: 12,
generatedCharacterOffsetIndex: 48,
contentLength: 15),
generatedCharacterOffsetIndex: 47,
contentLength: 17),
BuildLineMapping(
documentAbsoluteIndex: 200,
documentAbsoluteIndex: 202,
documentLineIndex: 5,
generatedAbsoluteIndex: 1293,
generatedLineIndex: 31,
characterOffsetIndex: 38,
contentLength: 23),
BuildLineMapping(
documentAbsoluteIndex: 283,
documentAbsoluteIndex: 285,
documentLineIndex: 6,
documentCharacterOffsetIndex: 40,
generatedAbsoluteIndex: 1934,
@ -600,18 +602,18 @@ namespace Microsoft.AspNet.Razor.Test.Generator
"BasicTagHelpers.Prefixed",
"BasicTagHelpers.Prefixed.DesignTime",
PrefixedPAndInputTagHelperDescriptors,
new List<LineMapping>
new[]
{
BuildLineMapping(
documentAbsoluteIndex: 17,
documentLineIndex: 0,
documentCharacterOffsetIndex: 17,
generatedAbsoluteIndex: 381,
generatedAbsoluteIndex: 380,
generatedLineIndex: 12,
generatedCharacterOffsetIndex: 48,
contentLength: 3),
generatedCharacterOffsetIndex: 47,
contentLength: 5),
BuildLineMapping(
documentAbsoluteIndex: 36,
documentAbsoluteIndex: 38,
documentLineIndex: 1,
documentCharacterOffsetIndex: 14,
generatedAbsoluteIndex: 436,
@ -619,7 +621,7 @@ namespace Microsoft.AspNet.Razor.Test.Generator
generatedCharacterOffsetIndex: 48,
contentLength: 15),
BuildLineMapping(
documentAbsoluteIndex: 222,
documentAbsoluteIndex: 224,
documentLineIndex: 7,
generatedAbsoluteIndex: 1437,
generatedLineIndex: 33,

View File

@ -332,24 +332,24 @@ namespace Microsoft.AspNet.Razor.Test.Framework
.Accepts(AcceptedCharacters.AnyExceptNewline);
}
public SpanConstructor AsAddTagHelper()
public SpanConstructor AsAddTagHelper(string lookupText)
{
return _self
.With(new AddTagHelperChunkGenerator())
.With(new AddTagHelperChunkGenerator(lookupText))
.Accepts(AcceptedCharacters.AnyExceptNewline);
}
public SpanConstructor AsRemoveTagHelper()
public SpanConstructor AsRemoveTagHelper(string lookupText)
{
return _self
.With(new RemoveTagHelperChunkGenerator())
.With(new RemoveTagHelperChunkGenerator(lookupText))
.Accepts(AcceptedCharacters.AnyExceptNewline);
}
public SpanConstructor AsTagHelperPrefixDirective()
public SpanConstructor AsTagHelperPrefixDirective(string prefix)
{
return _self
.With(new TagHelperPrefixDirectiveChunkGenerator())
.With(new TagHelperPrefixDirectiveChunkGenerator(prefix))
.Accepts(AcceptedCharacters.AnyExceptNewline);
}

View File

@ -11,6 +11,19 @@ namespace Microsoft.AspNet.Razor.Test.Parser.CSharp
{
public class CSharpDirectivesTest : CsHtmlCodeParserTestBase
{
[Fact]
public void TagHelperPrefixDirective_NoValueSucceeds()
{
ParseBlockTest("@tagHelperPrefix \"\"",
new DirectiveBlock(
Factory.CodeTransition(),
Factory
.MetaCode(SyntaxConstants.CSharp.TagHelperPrefixKeyword + " ")
.Accepts(AcceptedCharacters.None),
Factory.Code("\"\"")
.AsTagHelperPrefixDirective(string.Empty)));
}
[Fact]
public void TagHelperPrefixDirective_Succeeds()
{
@ -21,7 +34,20 @@ namespace Microsoft.AspNet.Razor.Test.Parser.CSharp
.MetaCode(SyntaxConstants.CSharp.TagHelperPrefixKeyword + " ")
.Accepts(AcceptedCharacters.None),
Factory.Code("Foo")
.AsTagHelperPrefixDirective()));
.AsTagHelperPrefixDirective("Foo")));
}
[Fact]
public void TagHelperPrefixDirective_WithQuotes_Succeeds()
{
ParseBlockTest("@tagHelperPrefix \"Foo\"",
new DirectiveBlock(
Factory.CodeTransition(),
Factory
.MetaCode(SyntaxConstants.CSharp.TagHelperPrefixKeyword + " ")
.Accepts(AcceptedCharacters.None),
Factory.Code("\"Foo\"")
.AsTagHelperPrefixDirective("Foo")));
}
[Fact]
@ -34,7 +60,7 @@ namespace Microsoft.AspNet.Razor.Test.Parser.CSharp
.MetaCode(SyntaxConstants.CSharp.TagHelperPrefixKeyword + " ")
.Accepts(AcceptedCharacters.None),
Factory.EmptyCSharp()
.AsTagHelperPrefixDirective()
.AsTagHelperPrefixDirective(string.Empty)
.Accepts(AcceptedCharacters.AnyExceptNewline)),
new RazorError(
RazorResources.FormatParseError_DirectiveMustHaveValue(
@ -42,6 +68,58 @@ namespace Microsoft.AspNet.Razor.Test.Parser.CSharp
absoluteIndex: 1, lineIndex: 0, columnIndex: 1, length: 15));
}
[Fact]
public void TagHelperPrefixDirective_StartQuoteRequiresDoubleQuotesAroundValue()
{
ParseBlockTest("@tagHelperPrefix \"Foo",
new DirectiveBlock(
Factory.CodeTransition(),
Factory
.MetaCode(SyntaxConstants.CSharp.TagHelperPrefixKeyword + " ")
.Accepts(AcceptedCharacters.None),
Factory.Code("\"Foo")
.AsTagHelperPrefixDirective("Foo")),
new RazorError(
RazorResources.ParseError_Unterminated_String_Literal,
absoluteIndex: 17, lineIndex: 0, columnIndex: 17, length: 1),
new RazorError(
RazorResources.FormatParseError_IncompleteQuotesAroundDirective(
SyntaxConstants.CSharp.TagHelperPrefixKeyword),
absoluteIndex: 17, lineIndex: 0, columnIndex: 17, length: 4));
}
[Fact]
public void TagHelperPrefixDirective_EndQuoteRequiresDoubleQuotesAroundValue()
{
ParseBlockTest("@tagHelperPrefix Foo \"",
new DirectiveBlock(
Factory.CodeTransition(),
Factory
.MetaCode(SyntaxConstants.CSharp.TagHelperPrefixKeyword + " ")
.Accepts(AcceptedCharacters.None),
Factory.Code("Foo \"")
.AsTagHelperPrefixDirective("Foo")),
new RazorError(
RazorResources.ParseError_Unterminated_String_Literal,
absoluteIndex: 23, lineIndex: 0, columnIndex: 23, length: 1),
new RazorError(
RazorResources.FormatParseError_IncompleteQuotesAroundDirective(
SyntaxConstants.CSharp.TagHelperPrefixKeyword),
absoluteIndex: 17, lineIndex: 0, columnIndex: 17, length: 7));
}
[Fact]
public void RemoveTagHelperDirective_NoValue_Succeeds()
{
ParseBlockTest("@removeTagHelper \"\"",
new DirectiveBlock(
Factory.CodeTransition(),
Factory.MetaCode(SyntaxConstants.CSharp.RemoveTagHelperKeyword + " ")
.Accepts(AcceptedCharacters.None),
Factory.Code("\"\"")
.AsRemoveTagHelper(string.Empty)));
}
[Fact]
public void RemoveTagHelperDirective_Succeeds()
{
@ -51,7 +129,19 @@ namespace Microsoft.AspNet.Razor.Test.Parser.CSharp
Factory.MetaCode(SyntaxConstants.CSharp.RemoveTagHelperKeyword + " ")
.Accepts(AcceptedCharacters.None),
Factory.Code("Foo")
.AsRemoveTagHelper()));
.AsRemoveTagHelper("Foo")));
}
[Fact]
public void RemoveTagHelperDirective_WithQuotes_Succeeds()
{
ParseBlockTest("@removeTagHelper \"Foo\"",
new DirectiveBlock(
Factory.CodeTransition(),
Factory.MetaCode(SyntaxConstants.CSharp.RemoveTagHelperKeyword + " ")
.Accepts(AcceptedCharacters.None),
Factory.Code("\"Foo\"")
.AsRemoveTagHelper("Foo")));
}
[Fact]
@ -63,7 +153,7 @@ namespace Microsoft.AspNet.Razor.Test.Parser.CSharp
Factory.MetaCode(SyntaxConstants.CSharp.RemoveTagHelperKeyword + " ")
.Accepts(AcceptedCharacters.None),
Factory.Code("Foo, Bar ")
.AsRemoveTagHelper()
.AsRemoveTagHelper("Foo, Bar")
.Accepts(AcceptedCharacters.AnyExceptNewline)));
}
@ -76,7 +166,7 @@ namespace Microsoft.AspNet.Razor.Test.Parser.CSharp
Factory.MetaCode(SyntaxConstants.CSharp.RemoveTagHelperKeyword + " ")
.Accepts(AcceptedCharacters.None),
Factory.EmptyCSharp()
.AsRemoveTagHelper()
.AsRemoveTagHelper(string.Empty)
.Accepts(AcceptedCharacters.AnyExceptNewline)),
new RazorError(
RazorResources.FormatParseError_DirectiveMustHaveValue(
@ -84,6 +174,57 @@ namespace Microsoft.AspNet.Razor.Test.Parser.CSharp
absoluteIndex: 1, lineIndex: 0, columnIndex: 1, length: 15));
}
[Fact]
public void RemoveTagHelperDirective_StartQuoteRequiresDoubleQuotesAroundValue()
{
ParseBlockTest("@removeTagHelper \"Foo",
new DirectiveBlock(
Factory.CodeTransition(),
Factory.MetaCode(SyntaxConstants.CSharp.RemoveTagHelperKeyword + " ")
.Accepts(AcceptedCharacters.None),
Factory.Code("\"Foo")
.AsRemoveTagHelper("Foo")),
new RazorError(
RazorResources.ParseError_Unterminated_String_Literal,
absoluteIndex: 17, lineIndex: 0, columnIndex: 17, length: 1),
new RazorError(
RazorResources.FormatParseError_IncompleteQuotesAroundDirective(
SyntaxConstants.CSharp.RemoveTagHelperKeyword),
absoluteIndex: 17, lineIndex: 0, columnIndex: 17, length: 4));
}
[Fact]
public void RemoveTagHelperDirective_EndQuoteRequiresDoubleQuotesAroundValue()
{
ParseBlockTest("@removeTagHelper Foo\"",
new DirectiveBlock(
Factory.CodeTransition(),
Factory.MetaCode(SyntaxConstants.CSharp.RemoveTagHelperKeyword + " ")
.Accepts(AcceptedCharacters.None),
Factory.Code("Foo\"")
.AsRemoveTagHelper("Foo")
.Accepts(AcceptedCharacters.AnyExceptNewline)),
new RazorError(
RazorResources.ParseError_Unterminated_String_Literal,
absoluteIndex: 20, lineIndex: 0, columnIndex: 20, length: 1),
new RazorError(
RazorResources.FormatParseError_IncompleteQuotesAroundDirective(
SyntaxConstants.CSharp.RemoveTagHelperKeyword),
absoluteIndex: 17, lineIndex: 0, columnIndex: 17, length: 4));
}
[Fact]
public void AddTagHelperDirective_NoValue_Succeeds()
{
ParseBlockTest("@addTagHelper \"\"",
new DirectiveBlock(
Factory.CodeTransition(),
Factory.MetaCode(SyntaxConstants.CSharp.AddTagHelperKeyword + " ")
.Accepts(AcceptedCharacters.None),
Factory.Code("\"\"")
.AsAddTagHelper(string.Empty)));
}
[Fact]
public void AddTagHelperDirective_Succeeds()
{
@ -93,7 +234,19 @@ namespace Microsoft.AspNet.Razor.Test.Parser.CSharp
Factory.MetaCode(SyntaxConstants.CSharp.AddTagHelperKeyword + " ")
.Accepts(AcceptedCharacters.None),
Factory.Code("Foo")
.AsAddTagHelper()));
.AsAddTagHelper("Foo")));
}
[Fact]
public void AddTagHelperDirective_WithQuotes_Succeeds()
{
ParseBlockTest("@addTagHelper \"Foo\"",
new DirectiveBlock(
Factory.CodeTransition(),
Factory.MetaCode(SyntaxConstants.CSharp.AddTagHelperKeyword + " ")
.Accepts(AcceptedCharacters.None),
Factory.Code("\"Foo\"")
.AsAddTagHelper("Foo")));
}
[Fact]
@ -105,7 +258,7 @@ namespace Microsoft.AspNet.Razor.Test.Parser.CSharp
Factory.MetaCode(SyntaxConstants.CSharp.AddTagHelperKeyword + " ")
.Accepts(AcceptedCharacters.None),
Factory.Code("Foo, Bar ")
.AsAddTagHelper()));
.AsAddTagHelper("Foo, Bar")));
}
[Fact]
@ -117,13 +270,52 @@ namespace Microsoft.AspNet.Razor.Test.Parser.CSharp
Factory.MetaCode(SyntaxConstants.CSharp.AddTagHelperKeyword + " ")
.Accepts(AcceptedCharacters.None),
Factory.EmptyCSharp()
.AsAddTagHelper()
.AsAddTagHelper(string.Empty)
.Accepts(AcceptedCharacters.AnyExceptNewline)),
new RazorError(
RazorResources.FormatParseError_DirectiveMustHaveValue(SyntaxConstants.CSharp.AddTagHelperKeyword),
absoluteIndex: 1, lineIndex: 0, columnIndex: 1, length: 12));
}
[Fact]
public void AddTagHelperDirective_StartQuoteRequiresDoubleQuotesAroundValue()
{
ParseBlockTest("@addTagHelper \"Foo",
new DirectiveBlock(
Factory.CodeTransition(),
Factory.MetaCode(SyntaxConstants.CSharp.AddTagHelperKeyword + " ")
.Accepts(AcceptedCharacters.None),
Factory.Code("\"Foo")
.AsAddTagHelper("Foo")),
new RazorError(
RazorResources.ParseError_Unterminated_String_Literal,
absoluteIndex: 14, lineIndex: 0, columnIndex: 14, length: 1),
new RazorError(
RazorResources.FormatParseError_IncompleteQuotesAroundDirective(
SyntaxConstants.CSharp.AddTagHelperKeyword),
absoluteIndex: 14, lineIndex: 0, columnIndex: 14, length: 4));
}
[Fact]
public void AddTagHelperDirective_EndQuoteRequiresDoubleQuotesAroundValue()
{
ParseBlockTest("@addTagHelper Foo\"",
new DirectiveBlock(
Factory.CodeTransition(),
Factory.MetaCode(SyntaxConstants.CSharp.AddTagHelperKeyword + " ")
.Accepts(AcceptedCharacters.None),
Factory.Code("Foo\"")
.AsAddTagHelper("Foo")
.Accepts(AcceptedCharacters.AnyExceptNewline)),
new RazorError(
RazorResources.ParseError_Unterminated_String_Literal,
absoluteIndex: 17, lineIndex: 0, columnIndex: 17, length: 1),
new RazorError(
RazorResources.FormatParseError_IncompleteQuotesAroundDirective(
SyntaxConstants.CSharp.AddTagHelperKeyword),
absoluteIndex: 14, lineIndex: 0, columnIndex: 14, length: 4));
}
[Fact]
public void InheritsDirective()
{

View File

@ -29,10 +29,10 @@ namespace Microsoft.AspNet.Razor.Compilation.TagHelpers
resolver.Object,
new ErrorSink());
var document = new MarkupBlock(
Factory.Code("one").AsAddTagHelper(),
Factory.Code("two").AsRemoveTagHelper(),
Factory.Code("three").AsRemoveTagHelper(),
Factory.Code("four").AsTagHelperPrefixDirective());
Factory.Code("one").AsAddTagHelper("one"),
Factory.Code("two").AsRemoveTagHelper("two"),
Factory.Code("three").AsRemoveTagHelper("three"),
Factory.Code("four").AsTagHelperPrefixDirective("four"));
// Act
tagHelperDirectiveSpanVisitor.GetDescriptors(document);
@ -48,10 +48,10 @@ namespace Microsoft.AspNet.Razor.Compilation.TagHelpers
var resolver = new TestTagHelperDescriptorResolver();
var tagHelperDirectiveSpanVisitor = new TagHelperDirectiveSpanVisitor(resolver, new ErrorSink());
var document = new MarkupBlock(
Factory.Code("one").AsAddTagHelper(),
Factory.Code("two").AsRemoveTagHelper(),
Factory.Code("three").AsRemoveTagHelper(),
Factory.Code("four").AsTagHelperPrefixDirective());
Factory.Code("one").AsAddTagHelper("one"),
Factory.Code("two").AsRemoveTagHelper("two"),
Factory.Code("three").AsRemoveTagHelper("three"),
Factory.Code("four").AsTagHelperPrefixDirective("four"));
var expectedDescriptors = new TagHelperDirectiveDescriptor[]
{
new TagHelperDirectiveDescriptor
@ -134,10 +134,10 @@ namespace Microsoft.AspNet.Razor.Compilation.TagHelpers
return new TagHelperDescriptorResolutionContext(expectedEndDirectiveDescriptors, errorSink);
});
var document = new MarkupBlock(
Factory.Code("one").AsAddTagHelper(),
Factory.Code("two").AsRemoveTagHelper(),
Factory.Code("three").AsRemoveTagHelper(),
Factory.Code("four").AsTagHelperPrefixDirective());
Factory.Code("one").AsAddTagHelper("one"),
Factory.Code("two").AsRemoveTagHelper("two"),
Factory.Code("three").AsRemoveTagHelper("three"),
Factory.Code("four").AsTagHelperPrefixDirective("four"));
// Act
@ -161,7 +161,7 @@ namespace Microsoft.AspNet.Razor.Compilation.TagHelpers
Factory
.MetaCode(SyntaxConstants.CSharp.TagHelperPrefixKeyword + " ")
.Accepts(AcceptedCharacters.None),
Factory.Code("something").AsTagHelperPrefixDirective()));
Factory.Code("something").AsTagHelperPrefixDirective("something")));
var expectedDirectiveDescriptor =
new TagHelperDirectiveDescriptor
{
@ -191,7 +191,7 @@ namespace Microsoft.AspNet.Razor.Compilation.TagHelpers
Factory.CodeTransition(),
Factory.MetaCode(SyntaxConstants.CSharp.RemoveTagHelperKeyword + " ")
.Accepts(AcceptedCharacters.None),
Factory.Code("something").AsAddTagHelper())
Factory.Code("something").AsAddTagHelper("something"))
);
var expectedRegistration = new TagHelperDirectiveDescriptor
{
@ -218,7 +218,7 @@ namespace Microsoft.AspNet.Razor.Compilation.TagHelpers
Factory.CodeTransition(),
Factory.MetaCode(SyntaxConstants.CSharp.RemoveTagHelperKeyword + " ")
.Accepts(AcceptedCharacters.None),
Factory.Code("something").AsRemoveTagHelper())
Factory.Code("something").AsRemoveTagHelper("something"))
);
var expectedRegistration = new TagHelperDirectiveDescriptor
{

View File

@ -1,4 +1,4 @@
#pragma checksum "BasicTagHelpers.cshtml" "{ff1816ec-aa5e-4d10-87f7-6f4963833460}" "5ac93855b03fe3c5d7e0c927f4ebbb8c67711220"
#pragma checksum "BasicTagHelpers.cshtml" "{ff1816ec-aa5e-4d10-87f7-6f4963833460}" "3cdbdfa1515b87565e2f00812f0093dbe8e49667"
namespace TestOutput
{
using System.Threading.Tasks;
@ -24,11 +24,11 @@ namespace TestOutput
public override async Task ExecuteAsync()
{
__tagHelperRunner = __tagHelperRunner ?? new global::Microsoft.AspNet.Razor.Runtime.TagHelperRunner();
Instrumentation.BeginContext(31, 71, true);
Instrumentation.BeginContext(33, 71, true);
WriteLiteral("\r\n<div data-animation=\"fade\" class=\"randomNonTagHelperAttribute\">\r\n ");
Instrumentation.EndContext();
__tagHelperExecutionContext = __tagHelperScopeManager.Begin("p", global::Microsoft.AspNet.Razor.TagHelpers.TagMode.StartTagAndEndTag, "test", async() => {
Instrumentation.BeginContext(143, 10, true);
Instrumentation.BeginContext(145, 10, true);
WriteLiteral("\r\n ");
Instrumentation.EndContext();
__tagHelperExecutionContext = __tagHelperScopeManager.Begin("p", global::Microsoft.AspNet.Razor.TagHelpers.TagMode.StartTagAndEndTag, "test", async() => {
@ -37,11 +37,11 @@ namespace TestOutput
__TestNamespace_PTagHelper = CreateTagHelper<global::TestNamespace.PTagHelper>();
__tagHelperExecutionContext.Add(__TestNamespace_PTagHelper);
__tagHelperExecutionContext.Output = await __tagHelperRunner.RunAsync(__tagHelperExecutionContext);
Instrumentation.BeginContext(153, 7, false);
Instrumentation.BeginContext(155, 7, false);
Write(__tagHelperExecutionContext.Output);
Instrumentation.EndContext();
__tagHelperExecutionContext = __tagHelperScopeManager.End();
Instrumentation.BeginContext(160, 10, true);
Instrumentation.BeginContext(162, 10, true);
WriteLiteral("\r\n ");
Instrumentation.EndContext();
__tagHelperExecutionContext = __tagHelperScopeManager.Begin("input", global::Microsoft.AspNet.Razor.TagHelpers.TagMode.StartTagOnly, "test", async() => {
@ -65,11 +65,11 @@ namespace TestOutput
__tagHelperExecutionContext.AddTagHelperAttribute("type", __TestNamespace_InputTagHelper.Type);
__TestNamespace_InputTagHelper2.Type = __TestNamespace_InputTagHelper.Type;
__tagHelperExecutionContext.Output = await __tagHelperRunner.RunAsync(__tagHelperExecutionContext);
Instrumentation.BeginContext(170, 71, false);
Instrumentation.BeginContext(172, 71, false);
Write(__tagHelperExecutionContext.Output);
Instrumentation.EndContext();
__tagHelperExecutionContext = __tagHelperScopeManager.End();
Instrumentation.BeginContext(241, 10, true);
Instrumentation.BeginContext(243, 10, true);
WriteLiteral("\r\n ");
Instrumentation.EndContext();
__tagHelperExecutionContext = __tagHelperScopeManager.Begin("input", global::Microsoft.AspNet.Razor.TagHelpers.TagMode.SelfClosing, "test", async() => {
@ -89,11 +89,11 @@ __TestNamespace_InputTagHelper2.Checked = **From custom attribute code renderer*
#line hidden
__tagHelperExecutionContext.AddTagHelperAttribute("checked", __TestNamespace_InputTagHelper2.Checked);
__tagHelperExecutionContext.Output = await __tagHelperRunner.RunAsync(__tagHelperExecutionContext);
Instrumentation.BeginContext(251, 39, false);
Instrumentation.BeginContext(253, 39, false);
Write(__tagHelperExecutionContext.Output);
Instrumentation.EndContext();
__tagHelperExecutionContext = __tagHelperScopeManager.End();
Instrumentation.BeginContext(290, 6, true);
Instrumentation.BeginContext(292, 6, true);
WriteLiteral("\r\n ");
Instrumentation.EndContext();
}
@ -107,11 +107,11 @@ __TestNamespace_InputTagHelper2.Checked = **From custom attribute code renderer*
{
__tagHelperExecutionContext.Output.Content = await __tagHelperExecutionContext.Output.GetChildContentAsync();
}
Instrumentation.BeginContext(102, 198, false);
Instrumentation.BeginContext(104, 198, false);
Write(__tagHelperExecutionContext.Output);
Instrumentation.EndContext();
__tagHelperExecutionContext = __tagHelperScopeManager.End();
Instrumentation.BeginContext(300, 8, true);
Instrumentation.BeginContext(302, 8, true);
WriteLiteral("\r\n</div>");
Instrumentation.EndContext();
}

View File

@ -1,4 +1,4 @@
#pragma checksum "BasicTagHelpers.Prefixed.cshtml" "{ff1816ec-aa5e-4d10-87f7-6f4963833460}" "58d527033ea3d1d7e092e5e3561d80a474d60e97"
#pragma checksum "BasicTagHelpers.Prefixed.cshtml" "{ff1816ec-aa5e-4d10-87f7-6f4963833460}" "859f448778119fd3043b1f19ea3d1f695558d6a6"
namespace TestOutput
{
using System;
@ -25,11 +25,11 @@ namespace TestOutput
public override async Task ExecuteAsync()
{
__tagHelperRunner = __tagHelperRunner ?? new global::Microsoft.AspNet.Razor.Runtime.TagHelperRunner();
Instrumentation.BeginContext(53, 52, true);
Instrumentation.BeginContext(55, 52, true);
WriteLiteral("\r\n<THSdiv class=\"randomNonTagHelperAttribute\">\r\n ");
Instrumentation.EndContext();
__tagHelperExecutionContext = __tagHelperScopeManager.Begin("p", global::Microsoft.AspNet.Razor.TagHelpers.TagMode.StartTagAndEndTag, "test", async() => {
Instrumentation.BeginContext(131, 56, true);
Instrumentation.BeginContext(133, 56, true);
WriteLiteral("\r\n <p></p>\r\n <input type=\"text\">\r\n ");
Instrumentation.EndContext();
__tagHelperExecutionContext = __tagHelperScopeManager.Begin("input", global::Microsoft.AspNet.Razor.TagHelpers.TagMode.StartTagOnly, "test", async() => {
@ -49,11 +49,11 @@ namespace TestOutput
#line hidden
__tagHelperExecutionContext.AddTagHelperAttribute("checked", __TestNamespace_InputTagHelper2.Checked);
__tagHelperExecutionContext.Output = await __tagHelperRunner.RunAsync(__tagHelperExecutionContext);
Instrumentation.BeginContext(187, 41, false);
Instrumentation.BeginContext(189, 41, false);
Write(__tagHelperExecutionContext.Output);
Instrumentation.EndContext();
__tagHelperExecutionContext = __tagHelperScopeManager.End();
Instrumentation.BeginContext(228, 6, true);
Instrumentation.BeginContext(230, 6, true);
WriteLiteral("\r\n ");
Instrumentation.EndContext();
}
@ -66,11 +66,11 @@ namespace TestOutput
{
__tagHelperExecutionContext.Output.Content = await __tagHelperExecutionContext.Output.GetChildContentAsync();
}
Instrumentation.BeginContext(105, 136, false);
Instrumentation.BeginContext(107, 136, false);
Write(__tagHelperExecutionContext.Output);
Instrumentation.EndContext();
__tagHelperExecutionContext = __tagHelperScopeManager.End();
Instrumentation.BeginContext(241, 11, true);
Instrumentation.BeginContext(243, 11, true);
WriteLiteral("\r\n</THSdiv>");
Instrumentation.EndContext();
}

View File

@ -1,4 +1,4 @@
#pragma checksum "BasicTagHelpers.RemoveTagHelper.cshtml" "{ff1816ec-aa5e-4d10-87f7-6f4963833460}" "69b58621318bc8f4c0498f15f088da6220f94ffe"
#pragma checksum "BasicTagHelpers.RemoveTagHelper.cshtml" "{ff1816ec-aa5e-4d10-87f7-6f4963833460}" "4cc0436af5a28bdf170d94f0ae03ff19aff89b88"
namespace TestOutput
{
using System;
@ -14,7 +14,7 @@ namespace TestOutput
#pragma warning disable 1998
public override async Task ExecuteAsync()
{
Instrumentation.BeginContext(68, 187, true);
Instrumentation.BeginContext(70, 187, true);
WriteLiteral("\r\n<div class=\"randomNonTagHelperAttribute\">\r\n <p class=\"Hello World\">\r\n " +
" <p></p>\r\n <input type=\"text\" />\r\n <input type=\"checkbox\" checked=" +
"\"true\"/>\r\n </p>\r\n</div>");

View File

@ -1,4 +1,4 @@
#pragma checksum "BasicTagHelpers.cshtml" "{ff1816ec-aa5e-4d10-87f7-6f4963833460}" "5ac93855b03fe3c5d7e0c927f4ebbb8c67711220"
#pragma checksum "BasicTagHelpers.cshtml" "{ff1816ec-aa5e-4d10-87f7-6f4963833460}" "3cdbdfa1515b87565e2f00812f0093dbe8e49667"
namespace TestOutput
{
using System;
@ -25,11 +25,11 @@ namespace TestOutput
public override async Task ExecuteAsync()
{
__tagHelperRunner = __tagHelperRunner ?? new global::Microsoft.AspNet.Razor.Runtime.TagHelperRunner();
Instrumentation.BeginContext(31, 71, true);
Instrumentation.BeginContext(33, 71, true);
WriteLiteral("\r\n<div data-animation=\"fade\" class=\"randomNonTagHelperAttribute\">\r\n ");
Instrumentation.EndContext();
__tagHelperExecutionContext = __tagHelperScopeManager.Begin("p", global::Microsoft.AspNet.Razor.TagHelpers.TagMode.StartTagAndEndTag, "test", async() => {
Instrumentation.BeginContext(143, 10, true);
Instrumentation.BeginContext(145, 10, true);
WriteLiteral("\r\n ");
Instrumentation.EndContext();
__tagHelperExecutionContext = __tagHelperScopeManager.Begin("p", global::Microsoft.AspNet.Razor.TagHelpers.TagMode.StartTagAndEndTag, "test", async() => {
@ -38,11 +38,11 @@ namespace TestOutput
__TestNamespace_PTagHelper = CreateTagHelper<global::TestNamespace.PTagHelper>();
__tagHelperExecutionContext.Add(__TestNamespace_PTagHelper);
__tagHelperExecutionContext.Output = await __tagHelperRunner.RunAsync(__tagHelperExecutionContext);
Instrumentation.BeginContext(153, 7, false);
Instrumentation.BeginContext(155, 7, false);
Write(__tagHelperExecutionContext.Output);
Instrumentation.EndContext();
__tagHelperExecutionContext = __tagHelperScopeManager.End();
Instrumentation.BeginContext(160, 10, true);
Instrumentation.BeginContext(162, 10, true);
WriteLiteral("\r\n ");
Instrumentation.EndContext();
__tagHelperExecutionContext = __tagHelperScopeManager.Begin("input", global::Microsoft.AspNet.Razor.TagHelpers.TagMode.StartTagOnly, "test", async() => {
@ -66,11 +66,11 @@ namespace TestOutput
__tagHelperExecutionContext.AddTagHelperAttribute("type", __TestNamespace_InputTagHelper.Type);
__TestNamespace_InputTagHelper2.Type = __TestNamespace_InputTagHelper.Type;
__tagHelperExecutionContext.Output = await __tagHelperRunner.RunAsync(__tagHelperExecutionContext);
Instrumentation.BeginContext(170, 71, false);
Instrumentation.BeginContext(172, 71, false);
Write(__tagHelperExecutionContext.Output);
Instrumentation.EndContext();
__tagHelperExecutionContext = __tagHelperScopeManager.End();
Instrumentation.BeginContext(241, 10, true);
Instrumentation.BeginContext(243, 10, true);
WriteLiteral("\r\n ");
Instrumentation.EndContext();
__tagHelperExecutionContext = __tagHelperScopeManager.Begin("input", global::Microsoft.AspNet.Razor.TagHelpers.TagMode.SelfClosing, "test", async() => {
@ -90,11 +90,11 @@ __TestNamespace_InputTagHelper2.Checked = true;
#line hidden
__tagHelperExecutionContext.AddTagHelperAttribute("checked", __TestNamespace_InputTagHelper2.Checked);
__tagHelperExecutionContext.Output = await __tagHelperRunner.RunAsync(__tagHelperExecutionContext);
Instrumentation.BeginContext(251, 39, false);
Instrumentation.BeginContext(253, 39, false);
Write(__tagHelperExecutionContext.Output);
Instrumentation.EndContext();
__tagHelperExecutionContext = __tagHelperScopeManager.End();
Instrumentation.BeginContext(290, 6, true);
Instrumentation.BeginContext(292, 6, true);
WriteLiteral("\r\n ");
Instrumentation.EndContext();
}
@ -108,11 +108,11 @@ __TestNamespace_InputTagHelper2.Checked = true;
{
__tagHelperExecutionContext.Output.Content = await __tagHelperExecutionContext.Output.GetChildContentAsync();
}
Instrumentation.BeginContext(102, 198, false);
Instrumentation.BeginContext(104, 198, false);
Write(__tagHelperExecutionContext.Output);
Instrumentation.EndContext();
__tagHelperExecutionContext = __tagHelperScopeManager.End();
Instrumentation.BeginContext(300, 8, true);
Instrumentation.BeginContext(302, 8, true);
WriteLiteral("\r\n</div>");
Instrumentation.EndContext();
}

View File

@ -1,4 +1,4 @@
@tagHelperPrefix THS
@tagHelperPrefix "THS"
@addTagHelper something, nice
<THSdiv class="randomNonTagHelperAttribute">

View File

@ -1,5 +1,5 @@
@addTagHelper something, nice
@removeTagHelper doesntmatter, nice
@removeTagHelper "doesntmatter, nice"
<div class="randomNonTagHelperAttribute">
<p class="Hello World">

View File

@ -1,4 +1,4 @@
@addTagHelper something, nice
@addTagHelper "something, nice"
<div data-animation="fade" class="randomNonTagHelperAttribute">
<p class="Hello World" data-delay="1000">