// Internal for testing internal IReadOnlyList <KeyValuePair <string, string> > GetAttributeNameValuePairs(MarkupTagBlockSyntax tagBlock) { // Need to calculate how many children we should take that represent the attributes. var childrenOffset = IsPartialTag(tagBlock) ? 0 : 1; var childCount = tagBlock.Children.Count - childrenOffset; if (childCount <= 1) { return(Array.Empty <KeyValuePair <string, string> >()); } _htmlAttributeTracker.Clear(); var attributes = _htmlAttributeTracker; for (var i = 1; i < childCount; i++) { if (tagBlock.Children[i] is CSharpCodeBlockSyntax) { // Code blocks in the attribute area of tags mangles following attributes. // It's also not supported by TagHelpers, bail early to avoid creating bad attribute value pairs. break; } if (tagBlock.Children[i] is MarkupMinimizedAttributeBlockSyntax minimizedAttributeBlock) { if (minimizedAttributeBlock.Name == null) { _attributeValueBuilder.Append(InvalidAttributeValueMarker); continue; } var minimizedAttribute = new KeyValuePair <string, string>(minimizedAttributeBlock.Name.GetContent(), string.Empty); attributes.Add(minimizedAttribute); continue; } if (!(tagBlock.Children[i] is MarkupAttributeBlockSyntax attributeBlock)) { // If the parser thought these aren't attributes, we don't care about them. Move on. continue; } if (attributeBlock.Name == null) { _attributeValueBuilder.Append(InvalidAttributeValueMarker); continue; } if (attributeBlock.Value != null) { for (var j = 0; j < attributeBlock.Value.Children.Count; j++) { var child = attributeBlock.Value.Children[j]; if (child is MarkupLiteralAttributeValueSyntax literalValue) { _attributeValueBuilder.Append(literalValue.GetContent()); } else { _attributeValueBuilder.Append(InvalidAttributeValueMarker); } } } var attributeName = attributeBlock.Name.GetContent(); var attributeValue = _attributeValueBuilder.ToString(); var attribute = new KeyValuePair <string, string>(attributeName, attributeValue); attributes.Add(attribute); _attributeValueBuilder.Clear(); } return(attributes); }
private SourceLocation GetTagDeclarationErrorStart(MarkupTagBlockSyntax tagBlock) { var advanceBy = IsEndTag(tagBlock) ? "</" : "<"; return(SourceLocationTracker.Advance(tagBlock.GetSourceLocation(_source), advanceBy)); }
private bool TryRewriteTagHelperEnd(MarkupTagBlockSyntax tagBlock, out MarkupTagHelperEndTagSyntax rewritten) { rewritten = null; var tagName = tagBlock.GetTagName(); // Could not determine tag name, it can't be a TagHelper, continue on and track the element. if (tagName == null) { return(false); } var tracker = CurrentTagHelperTracker; var tagNameScope = tracker?.TagName ?? string.Empty; if (!IsPotentialTagHelper(tagName, tagBlock)) { return(false); } // Validate that our end tag matches the currently scoped tag, if not we may need to error. if (tagNameScope.Equals(tagName, StringComparison.OrdinalIgnoreCase)) { // If there are additional end tags required before we can build our block it means we're in a // situation like this: <myth req="..."><myth></myth></myth> where we're at the inside </myth>. if (tracker.OpenMatchingTags > 0) { tracker.OpenMatchingTags--; return(false); } ValidateTagSyntax(tagName, tagBlock); _trackerStack.Pop(); } else { var tagHelperBinding = _tagHelperBinder.GetBinding( tagName, attributes: Array.Empty <KeyValuePair <string, string> >(), parentTagName: CurrentParentTagName, parentIsTagHelper: CurrentParentIsTagHelper); // If there are not TagHelperDescriptors associated with the end tag block that also have no // required attributes then it means we can't be a TagHelper, bail out. if (tagHelperBinding == null) { return(false); } foreach (var descriptor in tagHelperBinding.Descriptors) { var boundRules = tagHelperBinding.GetBoundRules(descriptor); var invalidRule = boundRules.FirstOrDefault(rule => rule.TagStructure == TagStructure.WithoutEndTag); if (invalidRule != null) { // End tag TagHelper that states it shouldn't have an end tag. _errorSink.OnError( RazorDiagnosticFactory.CreateParsing_TagHelperMustNotHaveAnEndTag( new SourceSpan(SourceLocationTracker.Advance(tagBlock.GetSourceLocation(_source), "</"), tagName.Length), tagName, descriptor.DisplayName, invalidRule.TagStructure)); return(false); } } } rewritten = SyntaxFactory.MarkupTagHelperEndTag(tagBlock.Children); return(true); }
private bool TryRewriteTagHelperStart(MarkupTagBlockSyntax tagBlock, out MarkupTagHelperStartTagSyntax rewritten, out TagHelperInfo tagHelperInfo) { rewritten = null; tagHelperInfo = null; // Get tag name of the current block var tagName = tagBlock.GetTagName(); // Could not determine tag name, it can't be a TagHelper, continue on and track the element. if (tagName == null) { return(false); } TagHelperBinding tagHelperBinding; if (!IsPotentialTagHelper(tagName, tagBlock)) { return(false); } var tracker = CurrentTagHelperTracker; var tagNameScope = tracker?.TagName ?? string.Empty; // We're now in a start tag block, we first need to see if the tag block is a tag helper. var elementAttributes = GetAttributeNameValuePairs(tagBlock); tagHelperBinding = _tagHelperBinder.GetBinding( tagName, elementAttributes, CurrentParentTagName, CurrentParentIsTagHelper); // If there aren't any TagHelperDescriptors registered then we aren't a TagHelper if (tagHelperBinding == null) { // If the current tag matches the current TagHelper scope it means the parent TagHelper matched // all the required attributes but the current one did not; therefore, we need to increment the // OpenMatchingTags counter for current the TagHelperBlock so we don't end it too early. // ex: <myth req="..."><myth></myth></myth> We don't want the first myth to close on the inside // tag. if (string.Equals(tagNameScope, tagName, StringComparison.OrdinalIgnoreCase)) { tracker.OpenMatchingTags++; } return(false); } ValidateParentAllowsTagHelper(tagName, tagBlock); ValidateBinding(tagHelperBinding, tagName, tagBlock); // We're in a start TagHelper block. var validTagStructure = ValidateTagSyntax(tagName, tagBlock); var startTag = TagHelperBlockRewriter.Rewrite( tagName, validTagStructure, _featureFlags, tagBlock, tagHelperBinding, _errorSink, _source); var tagMode = TagHelperBlockRewriter.GetTagMode(tagBlock, tagHelperBinding, _errorSink); tagHelperInfo = new TagHelperInfo(tagName, tagMode, tagHelperBinding); rewritten = startTag; return(true); }
public override void VisitMarkupTagBlock(MarkupTagBlockSyntax node) { WriteBlock(node, BlockKindInternal.Tag, base.VisitMarkupTagBlock); }
public static bool IsSelfClosing(this MarkupTagBlockSyntax tagBlock) { return(IsSelfClosingCore(tagBlock)); }
public static string GetTagName(this MarkupTagBlockSyntax tagBlock) { return(GetTagNameCore(tagBlock)); }