Skip to content
This repository was archived by the owner on Dec 19, 2018. It is now read-only.

Commit e2dd09c

Browse files
committed
[Fixes #881] Added TagHelper IR support
1 parent 61b2b0d commit e2dd09c

30 files changed

+947
-9
lines changed

src/Microsoft.AspNetCore.Razor.Evolution/DefaultRazorIRLoweringPhase.cs

Lines changed: 139 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -159,7 +159,6 @@ public override void VisitEndExpressionBlock(ExpressionChunkGenerator chunkGener
159159
contentLength,
160160
sourceRangeStart.FilePath ?? _codeDocument.Source.Filename);
161161
}
162-
163162
}
164163

165164
public override void VisitExpressionSpan(ExpressionChunkGenerator chunkGenerator, Span span)
@@ -253,6 +252,145 @@ public override void VisitEndDirectiveBlock(DirectiveChunkGenerator chunkGenerat
253252
Builder.Pop();
254253
}
255254

255+
public override void VisitStartTagHelperBlock(TagHelperChunkGenerator chunkGenerator, Block block)
256+
{
257+
var tagHelperBlock = block as TagHelperBlock;
258+
if (tagHelperBlock == null)
259+
{
260+
return;
261+
}
262+
263+
DeclareTagHelperFields(tagHelperBlock);
264+
265+
Builder.Push(new TagHelperIRNode());
266+
267+
Builder.Push(new InitializeTagHelperStructureIRNode()
268+
{
269+
TagName = tagHelperBlock.TagName,
270+
TagMode = tagHelperBlock.TagMode
271+
});
272+
}
273+
274+
public override void VisitEndTagHelperBlock(TagHelperChunkGenerator chunkGenerator, Block block)
275+
{
276+
var tagHelperBlock = block as TagHelperBlock;
277+
if (tagHelperBlock == null)
278+
{
279+
return;
280+
}
281+
282+
Builder.Pop(); // Pop InitializeTagHelperStructureIRNode
283+
284+
AddTagHelperCreation(tagHelperBlock.Descriptors);
285+
AddTagHelperAttributes(tagHelperBlock.Attributes, tagHelperBlock.Descriptors);
286+
AddExecuteTagHelpers();
287+
288+
Builder.Pop(); // Pop TagHelperIRNode
289+
}
290+
291+
public override void VisitAddTagHelperSpan(AddTagHelperChunkGenerator chunkGenerator, Span span)
292+
{
293+
}
294+
295+
public override void VisitRemoveTagHelperSpan(RemoveTagHelperChunkGenerator chunkGenerator, Span span)
296+
{
297+
}
298+
299+
public override void VisitTagHelperPrefixDirectiveSpan(TagHelperPrefixDirectiveChunkGenerator chunkGenerator, Span span)
300+
{
301+
}
302+
303+
private void DeclareTagHelperFields(TagHelperBlock block)
304+
{
305+
var declareFieldsNode = Class.Children.OfType<DeclareTagHelperFieldsIRNode>().SingleOrDefault();
306+
if (declareFieldsNode == null)
307+
{
308+
declareFieldsNode = new DeclareTagHelperFieldsIRNode();
309+
declareFieldsNode.Parent = Class;
310+
311+
var methodIndex = Class.Children.IndexOf(Method);
312+
Class.Children.Insert(methodIndex, declareFieldsNode);
313+
}
314+
315+
foreach (var descriptor in block.Descriptors)
316+
{
317+
declareFieldsNode.UsedTagHelperTypeNames.Add(descriptor.TypeName);
318+
}
319+
}
320+
321+
private void AddTagHelperCreation(IEnumerable<TagHelperDescriptor> descriptors)
322+
{
323+
foreach (var descriptor in descriptors)
324+
{
325+
var createTagHelper = new CreateTagHelperIRNode()
326+
{
327+
TagHelperTypeName = descriptor.TypeName,
328+
Descriptor = descriptor
329+
};
330+
331+
Builder.Add(createTagHelper);
332+
}
333+
}
334+
335+
private void AddTagHelperAttributes(IList<TagHelperAttributeNode> attributes, IEnumerable<TagHelperDescriptor> descriptors)
336+
{
337+
var renderedBoundAttributeNames = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
338+
foreach (var attribute in attributes)
339+
{
340+
var attributeValueNode = attribute.Value;
341+
var associatedDescriptors = descriptors.Where(descriptor =>
342+
descriptor.Attributes.Any(attributeDescriptor => attributeDescriptor.IsNameMatch(attribute.Name)));
343+
344+
if (associatedDescriptors.Any() && renderedBoundAttributeNames.Add(attribute.Name))
345+
{
346+
if (attributeValueNode == null)
347+
{
348+
// Minimized attributes are not valid for bound attributes. TagHelperBlockRewriter has already
349+
// logged an error if it was a bound attribute; so we can skip.
350+
continue;
351+
}
352+
353+
foreach (var associatedDescriptor in associatedDescriptors)
354+
{
355+
var associatedAttributeDescriptor = associatedDescriptor.Attributes.First(
356+
attributeDescriptor => attributeDescriptor.IsNameMatch(attribute.Name));
357+
var setTagHelperProperty = new SetTagHelperPropertyIRNode()
358+
{
359+
PropertyName = associatedAttributeDescriptor.PropertyName,
360+
AttributeName = attribute.Name,
361+
TagHelperTypeName = associatedDescriptor.TypeName,
362+
Descriptor = associatedAttributeDescriptor,
363+
ValueStyle = attribute.ValueStyle
364+
};
365+
366+
Builder.Push(setTagHelperProperty);
367+
attributeValueNode.Accept(this);
368+
Builder.Pop();
369+
}
370+
}
371+
else
372+
{
373+
var addHtmlAttribute = new AddTagHelperHtmlAttributeIRNode()
374+
{
375+
Name = attribute.Name,
376+
ValueStyle = attribute.ValueStyle
377+
};
378+
379+
Builder.Push(addHtmlAttribute);
380+
if (attributeValueNode != null)
381+
{
382+
attributeValueNode.Accept(this);
383+
}
384+
Builder.Pop();
385+
}
386+
}
387+
}
388+
389+
private void AddExecuteTagHelpers()
390+
{
391+
Builder.Add(new ExecuteTagHelpersIRNode());
392+
}
393+
256394
private MappingLocation BuildSourceRangeFromNode(SyntaxTreeNode node)
257395
{
258396
var location = node.Start;

src/Microsoft.AspNetCore.Razor.Evolution/HtmlNodeOptimizationPass.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ internal class HtmlNodeOptimizationPass : IRazorSyntaxTreePass
99
{
1010
public RazorEngine Engine { get; set; }
1111

12-
public int Order => 150;
12+
public int Order => 100;
1313

1414
public RazorSyntaxTree Execute(RazorCodeDocument codeDocument, RazorSyntaxTree syntaxTree)
1515
{
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
// Copyright (c) .NET Foundation. 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 Microsoft.AspNetCore.Razor.Evolution.Legacy;
7+
8+
namespace Microsoft.AspNetCore.Razor.Evolution.Intermediate
9+
{
10+
internal class AddTagHelperHtmlAttributeIRNode : RazorIRNode
11+
{
12+
public override IList<RazorIRNode> Children { get; } = new List<RazorIRNode>();
13+
14+
public override RazorIRNode Parent { get; set; }
15+
16+
internal override MappingLocation SourceRange { get; set; }
17+
18+
public string Name { get; set; }
19+
20+
internal HtmlAttributeValueStyle ValueStyle { get; set; }
21+
22+
public override void Accept(RazorIRNodeVisitor visitor)
23+
{
24+
if (visitor == null)
25+
{
26+
throw new ArgumentNullException(nameof(visitor));
27+
}
28+
29+
visitor.VisitAddTagHelperHtmlAttribute(this);
30+
}
31+
32+
public override TResult Accept<TResult>(RazorIRNodeVisitor<TResult> visitor)
33+
{
34+
if (visitor == null)
35+
{
36+
throw new ArgumentNullException(nameof(visitor));
37+
}
38+
39+
return visitor.VisitAddTagHelperHtmlAttribute(this);
40+
}
41+
}
42+
}
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
// Copyright (c) .NET Foundation. 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 Microsoft.AspNetCore.Razor.Evolution.Legacy;
7+
8+
namespace Microsoft.AspNetCore.Razor.Evolution.Intermediate
9+
{
10+
internal class CreateTagHelperIRNode : RazorIRNode
11+
{
12+
public override IList<RazorIRNode> Children { get; } = EmptyArray;
13+
14+
public override RazorIRNode Parent { get; set; }
15+
16+
internal override MappingLocation SourceRange { get; set; }
17+
18+
public string TagHelperTypeName { get; set; }
19+
20+
internal TagHelperDescriptor Descriptor { get; set; }
21+
22+
public override void Accept(RazorIRNodeVisitor visitor)
23+
{
24+
if (visitor == null)
25+
{
26+
throw new ArgumentNullException(nameof(visitor));
27+
}
28+
29+
visitor.VisitCreateTagHelper(this);
30+
}
31+
32+
public override TResult Accept<TResult>(RazorIRNodeVisitor<TResult> visitor)
33+
{
34+
if (visitor == null)
35+
{
36+
throw new ArgumentNullException(nameof(visitor));
37+
}
38+
39+
return visitor.VisitCreateTagHelper(this);
40+
}
41+
}
42+
}
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
// Copyright (c) .NET Foundation. 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 Microsoft.AspNetCore.Razor.Evolution.Legacy;
7+
8+
namespace Microsoft.AspNetCore.Razor.Evolution.Intermediate
9+
{
10+
internal class DeclareTagHelperFieldsIRNode : RazorIRNode
11+
{
12+
public override IList<RazorIRNode> Children { get; } = EmptyArray;
13+
14+
public override RazorIRNode Parent { get; set; }
15+
16+
internal override MappingLocation SourceRange { get; set; }
17+
18+
public ISet<string> UsedTagHelperTypeNames { get; set; } = new HashSet<string>(StringComparer.Ordinal);
19+
20+
public override void Accept(RazorIRNodeVisitor visitor)
21+
{
22+
if (visitor == null)
23+
{
24+
throw new ArgumentNullException(nameof(visitor));
25+
}
26+
27+
visitor.VisitDeclareTagHelperFields(this);
28+
}
29+
30+
public override TResult Accept<TResult>(RazorIRNodeVisitor<TResult> visitor)
31+
{
32+
if (visitor == null)
33+
{
34+
throw new ArgumentNullException(nameof(visitor));
35+
}
36+
37+
return visitor.VisitDeclareTagHelperFields(this);
38+
}
39+
}
40+
}
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
// Copyright (c) .NET Foundation. 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 Microsoft.AspNetCore.Razor.Evolution.Legacy;
7+
8+
namespace Microsoft.AspNetCore.Razor.Evolution.Intermediate
9+
{
10+
internal class ExecuteTagHelpersIRNode : RazorIRNode
11+
{
12+
public override IList<RazorIRNode> Children { get; } = new List<RazorIRNode>();
13+
14+
public override RazorIRNode Parent { get; set; }
15+
16+
internal override MappingLocation SourceRange { get; set; }
17+
18+
public override void Accept(RazorIRNodeVisitor visitor)
19+
{
20+
if (visitor == null)
21+
{
22+
throw new ArgumentNullException(nameof(visitor));
23+
}
24+
25+
visitor.VisitExecuteTagHelpers(this);
26+
}
27+
28+
public override TResult Accept<TResult>(RazorIRNodeVisitor<TResult> visitor)
29+
{
30+
if (visitor == null)
31+
{
32+
throw new ArgumentNullException(nameof(visitor));
33+
}
34+
35+
return visitor.VisitExecuteTagHelpers(this);
36+
}
37+
}
38+
}
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
// Copyright (c) .NET Foundation. 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 Microsoft.AspNetCore.Razor.Evolution.Legacy;
7+
8+
namespace Microsoft.AspNetCore.Razor.Evolution.Intermediate
9+
{
10+
internal class InitializeTagHelperStructureIRNode : RazorIRNode
11+
{
12+
public override IList<RazorIRNode> Children { get; } = new List<RazorIRNode>();
13+
14+
public override RazorIRNode Parent { get; set; }
15+
16+
internal override MappingLocation SourceRange { get; set; }
17+
18+
public string TagName { get; set; }
19+
20+
internal TagMode TagMode { get; set; }
21+
22+
public override void Accept(RazorIRNodeVisitor visitor)
23+
{
24+
if (visitor == null)
25+
{
26+
throw new ArgumentNullException(nameof(visitor));
27+
}
28+
29+
visitor.VisitInitializeTagHelperStructure(this);
30+
}
31+
32+
public override TResult Accept<TResult>(RazorIRNodeVisitor<TResult> visitor)
33+
{
34+
if (visitor == null)
35+
{
36+
throw new ArgumentNullException(nameof(visitor));
37+
}
38+
39+
return visitor.VisitInitializeTagHelperStructure(this);
40+
}
41+
}
42+
}

0 commit comments

Comments
 (0)