From 40633dde21a1ce42bb56f762ca8f74ca0c1cd512 Mon Sep 17 00:00:00 2001 From: Ryan Nowak Date: Mon, 14 Jan 2019 08:24:20 -0800 Subject: [PATCH] Add attribute only bindings and fix dotnet/aspnetcore-tooling#6373 Adds a new API for WTE to call given a TagHelperBinding to determine if the binding should colorize/classify only the attributes of the HTML element in source code. This is driven by a new metadata item that the Components 'directive attributes' all set. There's no way for a user to access this feature via tag helpers currently, but it could be added easily in the future. Also fixing dotnet/aspnetcore-tooling#6376 while I'm in there. :+1: \n\nCommit migrated from https://github.com/dotnet/aspnetcore-tooling/commit/df449beea9085221a1ba75ee61dcfbd2beb3aa34 --- .../src/Legacy/TagHelperBlockRewriter.cs | 2 +- .../src/Legacy/TagHelperParseTreeRewriter.cs | 4 +- .../src/TagHelperBinding.cs | 46 +++++++++++++++++-- .../src/TagHelperMetadata.cs | 2 + .../src/BindTagHelperDescriptorProvider.cs | 2 + ...EventHandlerTagHelperDescriptorProvider.cs | 2 +- .../src/RefTagHelperDescriptorProvider.cs | 15 ++++++ .../BindTagHelperDescriptorProviderTest.cs | 2 + ...tHandlerTagHelperDescriptorProviderTest.cs | 5 +- .../RefTagHelperDescriptorProviderTest.cs | 3 ++ 10 files changed, 72 insertions(+), 11 deletions(-) diff --git a/src/Razor/Microsoft.AspNetCore.Razor.Language/src/Legacy/TagHelperBlockRewriter.cs b/src/Razor/Microsoft.AspNetCore.Razor.Language/src/Legacy/TagHelperBlockRewriter.cs index fefcf4aeee..23a0a488a1 100644 --- a/src/Razor/Microsoft.AspNetCore.Razor.Language/src/Legacy/TagHelperBlockRewriter.cs +++ b/src/Razor/Microsoft.AspNetCore.Razor.Language/src/Legacy/TagHelperBlockRewriter.cs @@ -40,7 +40,7 @@ namespace Microsoft.AspNetCore.Razor.Language.Legacy foreach (var descriptor in bindingResult.Descriptors) { - var boundRules = bindingResult.GetBoundRules(descriptor); + var boundRules = bindingResult.Mappings[descriptor]; var nonDefaultRule = boundRules.FirstOrDefault(rule => rule.TagStructure != TagStructure.Unspecified); if (nonDefaultRule?.TagStructure == TagStructure.WithoutEndTag) diff --git a/src/Razor/Microsoft.AspNetCore.Razor.Language/src/Legacy/TagHelperParseTreeRewriter.cs b/src/Razor/Microsoft.AspNetCore.Razor.Language/src/Legacy/TagHelperParseTreeRewriter.cs index 47f96d7d3b..1619f42240 100644 --- a/src/Razor/Microsoft.AspNetCore.Razor.Language/src/Legacy/TagHelperParseTreeRewriter.cs +++ b/src/Razor/Microsoft.AspNetCore.Razor.Language/src/Legacy/TagHelperParseTreeRewriter.cs @@ -336,7 +336,7 @@ namespace Microsoft.AspNetCore.Razor.Language.Legacy foreach (var descriptor in tagHelperBinding.Descriptors) { - var boundRules = tagHelperBinding.GetBoundRules(descriptor); + var boundRules = tagHelperBinding.Mappings[descriptor]; var invalidRule = boundRules.FirstOrDefault(rule => rule.TagStructure == TagStructure.WithoutEndTag); if (invalidRule != null) @@ -456,7 +456,7 @@ namespace Microsoft.AspNetCore.Razor.Language.Legacy TagStructure? baseStructure = null; foreach (var descriptor in bindingResult.Descriptors) { - var boundRules = bindingResult.GetBoundRules(descriptor); + var boundRules = bindingResult.Mappings[descriptor]; foreach (var rule in boundRules) { if (rule.TagStructure != TagStructure.Unspecified) diff --git a/src/Razor/Microsoft.AspNetCore.Razor.Language/src/TagHelperBinding.cs b/src/Razor/Microsoft.AspNetCore.Razor.Language/src/TagHelperBinding.cs index a5590c536e..4b88cf5b12 100644 --- a/src/Razor/Microsoft.AspNetCore.Razor.Language/src/TagHelperBinding.cs +++ b/src/Razor/Microsoft.AspNetCore.Razor.Language/src/TagHelperBinding.cs @@ -1,14 +1,13 @@ // Copyright (c) .NET Foundation. All rights reserved. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. +using System; using System.Collections.Generic; namespace Microsoft.AspNetCore.Razor.Language { public sealed class TagHelperBinding { - private IReadOnlyDictionary> _mappings; - internal TagHelperBinding( string tagName, IReadOnlyList> attributes, @@ -19,12 +18,42 @@ namespace Microsoft.AspNetCore.Razor.Language TagName = tagName; Attributes = attributes; ParentTagName = parentTagName; + Mappings = mappings; TagHelperPrefix = tagHelperPrefix; - _mappings = mappings; } - public IEnumerable Descriptors => _mappings.Keys; + public IEnumerable Descriptors => Mappings.Keys; + + /// + /// Gets a value that indicates whether the the binding matched on attributes only. + /// + /// false if the entire element should be classified as a tag helper. + /// + /// If this returns true, use TagHelperFactsService.GetBoundTagHelperAttributes to find the + /// set of attributes that should be considered part of the match. + /// + public bool IsAttributeMatch + { + get + { + foreach (var descriptor in Mappings.Keys) + { + if (!descriptor.Metadata.TryGetValue(TagHelperMetadata.Common.ClassifyAttributesOnly, out var value) || + !string.Equals(value, bool.TrueString, StringComparison.OrdinalIgnoreCase)) + { + return false; + } + } + + // All the matching tag helpers want to be classified with **attributes only**. + // + // Ex: (components) + // + //