1+ // Copyright (c) Microsoft Open Technologies, Inc. All rights reserved.
2+ // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
3+
4+ using System ;
5+ using System . Collections . Generic ;
6+ using System . Linq ;
7+ using System . Reflection ;
8+ using Microsoft . AspNet . Razor . TagHelpers ;
9+
10+ namespace Microsoft . AspNet . Razor . Runtime . TagHelpers
11+ {
12+ /// <summary>
13+ /// Used to resolve <see cref="TagHelperDescriptor"/>s.
14+ /// </summary>
15+ public class TagHelperDescriptorResolver : ITagHelperDescriptorResolver
16+ {
17+ private const string TagHelperNameEnding = "TagHelper" ;
18+ private const ContentBehavior DefaultContentBehavior = default ( ContentBehavior ) ;
19+
20+ private ITagHelperTypeResolver _tagHelperTypeResolver ;
21+
22+ /// <summary>
23+ /// Instantiates a new instance of the <see cref="TagHelperDescriptorResolver"/> class.
24+ /// </summary>
25+ /// <param name="tagHelperTypeResolver">
26+ /// A type resolver used to resolve tag helper <see cref="Type"/>s.
27+ /// </param>
28+ public TagHelperDescriptorResolver ( [ NotNull ] ITagHelperTypeResolver tagHelperTypeResolver )
29+ {
30+ _tagHelperTypeResolver = tagHelperTypeResolver ;
31+ }
32+
33+ /// <summary>
34+ /// Resolves <see cref="TagHelperDescriptor"/>s based on the given <paramref name="lookupText"/>.
35+ /// </summary>
36+ /// <param name="lookupText">
37+ /// A <see cref="string"/> location on where to find tag helper <see cref="Type"/>s.
38+ /// </param>
39+ /// <returns>An <see cref="IEnumerable{TagHelperDescriptor}"/> that represent tag helpers associated with the
40+ /// given <paramref name="lookupText"/>.</returns>
41+ public IEnumerable < TagHelperDescriptor > Resolve ( string lookupText )
42+ {
43+ var tagHelperTypes = _tagHelperTypeResolver . Resolve ( lookupText ) ;
44+
45+ var descriptors = tagHelperTypes . Select ( GetTagHelperDescriptors ) ;
46+
47+ // TODO: Validate no conflicting ContentBehaviors after:
48+ // https://github.com/aspnet/Razor/issues/122 and https://github.com/aspnet/Razor/issues/120
49+
50+ return descriptors ;
51+ }
52+
53+ // TODO: Make this method return multiple TagHelperDescriptors based on a TagNameAttribute:
54+ // https://github.com/aspnet/Razor/issues/120
55+ private static TagHelperDescriptor GetTagHelperDescriptors ( Type type )
56+ {
57+ var tagName = GetTagNameTarget ( type ) ;
58+ // Tag helpers can't be generic so dont need to worry about that.
59+ var tagHelperTypeName = type . Namespace + "." + type . Name ;
60+ var attributeDescriptors = GetTagHelperAttributeDescriptors ( type ) ;
61+ var contentBehavior = GetContentBehavior ( type ) ;
62+
63+ return new TagHelperDescriptor ( tagName ,
64+ tagHelperTypeName ,
65+ contentBehavior ,
66+ attributeDescriptors ) ;
67+ }
68+
69+ // TODO: Make this method support TagNameAttribute targets: https://github.com/aspnet/Razor/issues/120
70+ private static string GetTagNameTarget ( Type tagHelperType )
71+ {
72+ var name = tagHelperType . Name ;
73+
74+ if ( name . EndsWith ( TagHelperNameEnding , StringComparison . OrdinalIgnoreCase ) )
75+ {
76+ name = name . Substring ( 0 , name . Length - TagHelperNameEnding . Length ) ;
77+ }
78+
79+ return name ;
80+ }
81+
82+ private static IEnumerable < TagHelperAttributeDescriptor > GetTagHelperAttributeDescriptors ( Type type )
83+ {
84+ var typeInfo = type . GetTypeInfo ( ) ;
85+ var properties = typeInfo . DeclaredProperties . Where ( IsValidTagHelperProperty ) ;
86+ var attributeDescriptors = properties . Select ( ToTagHelperAttributeDescriptor ) ;
87+
88+ // TODO: Validate no conflicting HTML attribute names: https://github.com/aspnet/Razor/issues/121
89+
90+ return attributeDescriptors ;
91+ }
92+
93+ // TODO: Make the HTML attribute name support names from a AttributeNameAttribute:
94+ // https://github.com/aspnet/Razor/issues/121
95+ private static TagHelperAttributeDescriptor ToTagHelperAttributeDescriptor ( PropertyInfo property )
96+ {
97+ return new TagHelperAttributeDescriptor ( property . Name , property ) ;
98+ }
99+
100+ // TODO: Make the content behavior pull from a ContentBehaviorAttribute: https://github.com/aspnet/Razor/issues/122
101+ private static ContentBehavior GetContentBehavior ( Type type )
102+ {
103+ return DefaultContentBehavior ;
104+ }
105+
106+ private static bool IsValidTagHelperProperty ( PropertyInfo property )
107+ {
108+ return property . GetMethod != null &&
109+ property . SetMethod != null &&
110+ property . GetMethod . IsPublic &&
111+ property . SetMethod . IsPublic ;
112+ }
113+ }
114+ }
0 commit comments