Expose source start/end tags on TagHelperBlocks.

- This is to enable the DesignTime to understand TagHelperBlocks full source structure in order to auto format the document.
This commit is contained in:
N. Taylor Mullen 2015-03-16 21:17:43 -07:00
parent 44b530dd22
commit 36f02690d2
4 changed files with 72 additions and 25 deletions

View File

@ -32,6 +32,8 @@ namespace Microsoft.AspNet.Razor.Parser.TagHelpers
Attributes = new Dictionary<string, SyntaxTreeNode>(source.Attributes);
_start = source.Start;
SelfClosing = source.SelfClosing;
SourceStartTag = source.SourceStartTag;
SourceEndTag = source.SourceEndTag;
source.Reset();
@ -41,6 +43,18 @@ namespace Microsoft.AspNet.Razor.Parser.TagHelpers
}
}
/// <summary>
/// Gets the unrewritten source start tag.
/// </summary>
/// <remarks>This is used by design time to properly format <see cref="TagHelperBlock"/>s.</remarks>
public Block SourceStartTag { get; }
/// <summary>
/// Gets the unrewritten source end tag.
/// </summary>
/// <remarks>This is used by design time to properly format <see cref="TagHelperBlock"/>s.</remarks>
public Block SourceEndTag { get; }
/// <summary>
/// Indicates whether or not the tag is self closing.
/// </summary>
@ -70,6 +84,18 @@ namespace Microsoft.AspNet.Razor.Parser.TagHelpers
/// </summary>
public string TagName { get; private set; }
public override int Length
{
get
{
var startTagLength = SourceStartTag?.Length ?? 0;
var childrenLength = base.Length;
var endTagLength = SourceEndTag?.Length ?? 0;
return startTagLength + childrenLength + endTagLength;
}
}
/// <inheritdoc />
public override string ToString()
{
@ -99,11 +125,12 @@ namespace Microsoft.AspNet.Razor.Parser.TagHelpers
/// <inheritdoc />
public override int GetHashCode()
{
return HashCodeCombiner.Start()
.Add(TagName)
.Add(Attributes)
.Add(base.GetHashCode())
.CombinedHash;
return HashCodeCombiner
.Start()
.Add(TagName)
.Add(Attributes)
.Add(base.GetHashCode())
.CombinedHash;
}
}
}

View File

@ -74,6 +74,18 @@ namespace Microsoft.AspNet.Razor.Parser.TagHelpers
}
}
/// <summary>
/// Gets or sets the unrewritten source start tag.
/// </summary>
/// <remarks>This is used by design time to properly format <see cref="TagHelperBlock"/>s.</remarks>
public Block SourceStartTag { get; set; }
/// <summary>
/// Gets or sets the unrewritten source end tag.
/// </summary>
/// <remarks>This is used by design time to properly format <see cref="TagHelperBlock"/>s.</remarks>
public Block SourceEndTag { get; set; }
/// <summary>
/// Gets a value indicating whether or not the tag in the Razor source was self-closing.
/// </summary>

View File

@ -17,11 +17,12 @@ namespace Microsoft.AspNet.Razor.Parser.TagHelpers.Internal
{
private static readonly string StringTypeName = typeof(string).FullName;
public static TagHelperBlockBuilder Rewrite(string tagName,
bool validStructure,
Block tag,
IEnumerable<TagHelperDescriptor> descriptors,
ParserErrorSink errorSink)
public static TagHelperBlockBuilder Rewrite(
string tagName,
bool validStructure,
Block tag,
IEnumerable<TagHelperDescriptor> descriptors,
ParserErrorSink errorSink)
{
// There will always be at least one child for the '<'.
var start = tag.Children.First().Start;
@ -74,8 +75,8 @@ namespace Microsoft.AspNet.Razor.Parser.TagHelpers.Internal
// Check if it's a bound attribute that is not of type string and happens to be null or whitespace.
string attributeValueType;
if (attributeValueTypes.TryGetValue(attribute.Key, out attributeValueType) &&
!IsStringAttribute(attributeValueType) &&
IsNullOrWhitespaceAttributeValue(attribute.Value))
!IsStringAttribute(attributeValueType) &&
IsNullOrWhitespaceAttributeValue(attribute.Value))
{
var errorLocation = GetAttributeNameStartLocation(child);

View File

@ -121,11 +121,16 @@ namespace Microsoft.AspNet.Razor.Parser.TagHelpers.Internal
var validTagStructure = ValidTagStructure(tagName, tagBlock, context);
var builder = TagHelperBlockRewriter.Rewrite(tagName,
validTagStructure,
tagBlock,
descriptors,
context.ErrorSink);
var builder = TagHelperBlockRewriter.Rewrite(
tagName,
validTagStructure,
tagBlock,
descriptors,
context.ErrorSink);
// Track the original start tag so the editor knows where each piece of the TagHelperBlock lies
// for formatting.
builder.SourceStartTag = tagBlock;
// Found a new tag helper block
TrackTagHelperBlock(builder);
@ -134,7 +139,7 @@ namespace Microsoft.AspNet.Razor.Parser.TagHelpers.Internal
// within the tag... complete it.
if (builder.SelfClosing)
{
BuildCurrentlyTrackedTagHelperBlock();
BuildCurrentlyTrackedTagHelperBlock(endTag: null);
}
}
else
@ -149,14 +154,14 @@ namespace Microsoft.AspNet.Razor.Parser.TagHelpers.Internal
{
ValidTagStructure(tagName, tagBlock, context);
BuildCurrentlyTrackedTagHelperBlock();
BuildCurrentlyTrackedTagHelperBlock(tagBlock);
}
else
{
// Current tag helper scope does not match the end tag. Attempt to recover the tag
// helper by looking up the previous tag helper scopes for a matching tag. If we
// can't recover it means there was no corresponding tag helper begin tag.
if (TryRecoverTagHelper(tagName, context))
if (TryRecoverTagHelper(tagName, tagBlock, context))
{
ValidTagStructure(tagName, tagBlock, context);
@ -230,9 +235,11 @@ namespace Microsoft.AspNet.Razor.Parser.TagHelpers.Internal
}
}
private void BuildCurrentlyTrackedTagHelperBlock()
private void BuildCurrentlyTrackedTagHelperBlock(Block endTag)
{
_tagStack.Pop();
// Track the original end tag so the editor knows where each piece of the TagHelperBlock lies
// for formatting.
_tagStack.Pop().SourceEndTag = endTag;
BuildCurrentlyTrackedBlock();
}
@ -268,7 +275,7 @@ namespace Microsoft.AspNet.Razor.Parser.TagHelpers.Internal
TrackBlock(builder);
}
private bool TryRecoverTagHelper(string tagName, RewritingContext context)
private bool TryRecoverTagHelper(string tagName, Block endTag, RewritingContext context)
{
var malformedTagHelperCount = 0;
@ -289,7 +296,7 @@ namespace Microsoft.AspNet.Razor.Parser.TagHelpers.Internal
BuildMalformedTagHelpers(malformedTagHelperCount, context);
// One final build, this is the build that completes our target tag helper block which is not malformed.
BuildCurrentlyTrackedTagHelperBlock();
BuildCurrentlyTrackedTagHelperBlock(endTag);
// We were able to recover
return true;
@ -310,7 +317,7 @@ namespace Microsoft.AspNet.Razor.Parser.TagHelpers.Internal
RazorResources.FormatTagHelpersParseTreeRewriter_FoundMalformedTagHelper(
malformedTagHelper.TagName));
BuildCurrentlyTrackedTagHelperBlock();
BuildCurrentlyTrackedTagHelperBlock(endTag: null);
}
}