public override void VisitMarkupAttributeBlock(MarkupAttributeBlockSyntax node) { Visit(node.NamePrefix); AddSemanticRange(node.Name, RazorSemanticTokensLegend.MarkupAttribute); Visit(node.NameSuffix); AddSemanticRange(node.EqualsToken, RazorSemanticTokensLegend.MarkupOperator); Visit(node.ValuePrefix); Visit(node.Value); Visit(node.ValueSuffix); }
public override void VisitMarkupAttributeBlock(MarkupAttributeBlockSyntax node) { WriteBlock(node, FormattingBlockKind.Markup, n => { var equalsSyntax = SyntaxFactory.MarkupTextLiteral(new SyntaxList <SyntaxToken>(node.EqualsToken)); var mergedAttributePrefix = SyntaxUtilities.MergeTextLiterals(node.NamePrefix, node.Name, node.NameSuffix, equalsSyntax, node.ValuePrefix); Visit(mergedAttributePrefix); Visit(node.Value); Visit(node.ValueSuffix); }); }
// Example // <input` checked="hello-world @false"`/> // Name=checked // Prefix= checked=" // Suffix=" public override void VisitMarkupAttributeBlock(MarkupAttributeBlockSyntax node) { var prefixTokens = MergeLiterals( node.NamePrefix?.LiteralTokens, node.Name.LiteralTokens, node.NameSuffix?.LiteralTokens, node.EqualsToken == null ? new SyntaxList <SyntaxToken>() : new SyntaxList <SyntaxToken>(node.EqualsToken), node.ValuePrefix?.LiteralTokens); var prefix = (MarkupTextLiteralSyntax)SyntaxFactory.MarkupTextLiteral(prefixTokens).Green.CreateRed(node, node.NamePrefix?.Position ?? node.Name.Position); var name = node.Name.GetContent(); if (name.StartsWith("data-", StringComparison.OrdinalIgnoreCase) && !_featureFlags.EXPERIMENTAL_AllowConditionalDataDashAttributes) { Visit(prefix); Visit(node.Value); Visit(node.ValueSuffix); } else { if (node.Value != null && node.Value.ChildNodes().All(c => c is MarkupLiteralAttributeValueSyntax)) { // We need to do what ConditionalAttributeCollapser used to do. var literalAttributeValueNodes = node.Value.ChildNodes().Cast <MarkupLiteralAttributeValueSyntax>().ToArray(); var valueTokens = SyntaxListBuilder <SyntaxToken> .Create(); for (var i = 0; i < literalAttributeValueNodes.Length; i++) { var mergedValue = MergeAttributeValue(literalAttributeValueNodes[i]); valueTokens.AddRange(mergedValue.LiteralTokens); } var rewritten = SyntaxFactory.MarkupTextLiteral(valueTokens.ToList()); var mergedLiterals = MergeLiterals(prefix?.LiteralTokens, rewritten.LiteralTokens, node.ValueSuffix?.LiteralTokens); var mergedAttribute = SyntaxFactory.MarkupTextLiteral(mergedLiterals).Green.CreateRed(node.Parent, node.Position); Visit(mergedAttribute); } else { _builder.Push(new HtmlAttributeIntermediateNode() { AttributeName = node.Name.GetContent(), Prefix = prefix.GetContent(), Suffix = node.ValueSuffix?.GetContent() ?? string.Empty, Source = BuildSourceSpanFromNode(node), }); VisitAttributeValue(node.Value); _builder.Pop(); } } }
private static TryParseResult TryParseAttribute( string tagName, MarkupAttributeBlockSyntax attributeBlock, IEnumerable <TagHelperDescriptor> descriptors, ErrorSink errorSink, HashSet <string> processedBoundAttributeNames) { // Have a name now. Able to determine correct isBoundNonStringAttribute value. var result = CreateTryParseResult(attributeBlock.Name.GetContent(), descriptors, processedBoundAttributeNames); if (attributeBlock.ValuePrefix == null) { // We are purposefully not persisting NoQuotes even for unbound attributes because it is still possible to // rewrite the values that introduces a space like in UrlResolutionTagHelper. // The other case is it could be an expression, treat NoQuotes and DoubleQuotes equivalently. We purposefully do not persist NoQuotes // ValueStyles at code generation time to protect users from rendering dynamic content with spaces // that can break attributes. // Ex: <tag my-attribute=@value /> where @value results in the test "hello world". // This way, the above code would render <tag my-attribute="hello world" />. result.AttributeStructure = AttributeStructure.DoubleQuotes; } else { var lastToken = attributeBlock.ValuePrefix.GetLastToken(); switch (lastToken.Kind) { case SyntaxKind.DoubleQuote: result.AttributeStructure = AttributeStructure.DoubleQuotes; break; case SyntaxKind.SingleQuote: result.AttributeStructure = AttributeStructure.SingleQuotes; break; default: result.AttributeStructure = AttributeStructure.Minimized; break; } } var attributeValue = attributeBlock.Value; if (attributeValue == null) { var builder = SyntaxListBuilder <RazorSyntaxNode> .Create(); // Add a marker for attribute value when there are no quotes like, <p class= > builder.Add(SyntaxFactory.MarkupTextLiteral(new SyntaxList <SyntaxToken>())); attributeValue = SyntaxFactory.GenericBlock(builder.ToList()); } var rewrittenValue = RewriteAttributeValue(result, attributeValue); var rewritten = SyntaxFactory.MarkupTagHelperAttribute( attributeBlock.NamePrefix, attributeBlock.Name, attributeBlock.NameSuffix, attributeBlock.EqualsToken, attributeBlock.ValuePrefix, rewrittenValue, attributeBlock.ValueSuffix); rewritten = rewritten.WithTagHelperAttributeInfo( new TagHelperAttributeInfo(result.AttributeName, result.AttributeStructure, result.IsBoundAttribute)); result.RewrittenAttribute = rewritten; return(result); }
private static MarkupTagHelperDirectiveAttributeSyntax RewriteToDirectiveAttribute( MarkupAttributeBlockSyntax attributeBlock, TryParseResult result, MarkupTagHelperAttributeValueSyntax rewrittenValue) { // // Consider, <Foo @bind:param="..." /> // We're now going to rewrite @bind:param from a regular MarkupAttributeBlock to a MarkupTagHelperDirectiveAttribute. // We need to split the name "@bind:param" into four parts, // @ - Transition (MetaCode) // bind - Name (Text) // : - Colon (MetaCode) // param - ParameterName (Text) // var attributeName = result.AttributeName; var attributeNameSyntax = attributeBlock.Name; var transition = SyntaxFactory.RazorMetaCode( new SyntaxList <SyntaxToken>(SyntaxFactory.MissingToken(SyntaxKind.Transition))); RazorMetaCodeSyntax colon = null; MarkupTextLiteralSyntax parameterName = null; if (attributeName.StartsWith("@", StringComparison.Ordinal)) { attributeName = attributeName.Substring(1); var attributeNameToken = SyntaxFactory.Token(SyntaxKind.Text, attributeName); attributeNameSyntax = SyntaxFactory.MarkupTextLiteral().AddLiteralTokens(attributeNameToken); var transitionToken = SyntaxFactory.Token(SyntaxKind.Transition, "@"); transition = SyntaxFactory.RazorMetaCode(new SyntaxList <SyntaxToken>(transitionToken)); } if (attributeName.IndexOf(':') != -1) { var segments = attributeName.Split(new[] { ':' }, 2); var attributeNameToken = SyntaxFactory.Token(SyntaxKind.Text, segments[0]); attributeNameSyntax = SyntaxFactory.MarkupTextLiteral().AddLiteralTokens(attributeNameToken); var colonToken = SyntaxFactory.Token(SyntaxKind.Colon, ":"); colon = SyntaxFactory.RazorMetaCode(new SyntaxList <SyntaxToken>(colonToken)); var parameterNameToken = SyntaxFactory.Token(SyntaxKind.Text, segments[1]); parameterName = SyntaxFactory.MarkupTextLiteral().AddLiteralTokens(parameterNameToken); } var rewritten = SyntaxFactory.MarkupTagHelperDirectiveAttribute( attributeBlock.NamePrefix, transition, attributeNameSyntax, colon, parameterName, attributeBlock.NameSuffix, attributeBlock.EqualsToken, attributeBlock.ValuePrefix, rewrittenValue, attributeBlock.ValueSuffix); rewritten = rewritten.WithTagHelperAttributeInfo( new TagHelperAttributeInfo(result.AttributeName, parameterName?.GetContent(), result.AttributeStructure, result.IsBoundAttribute, isDirectiveAttribute: true)); return(rewritten); }
public override void VisitMarkupAttributeBlock(MarkupAttributeBlockSyntax node) { AddSemanticRange(node.Name, SyntaxKind.MarkupAttributeBlock); AddSemanticRange(node.EqualsToken); base.VisitMarkupAttributeBlock(node); }