Moved TagHelperBinder from pass to a phase

This commit is contained in:
Ajay Bhargav Baaskaran 2017-05-10 16:25:36 -07:00
parent eb3c47b6ca
commit 4bc1a76e22
5 changed files with 88 additions and 55 deletions

View File

@ -8,24 +8,23 @@ using Microsoft.AspNetCore.Razor.Language.Legacy;
namespace Microsoft.AspNetCore.Razor.Language
{
internal class TagHelperBinderSyntaxTreePass : IRazorSyntaxTreePass
internal class DefaultRazorTagHelperBinderPhase : RazorEnginePhaseBase, IRazorTagHelperBinderPhase
{
private static HashSet<char> InvalidNonWhitespaceNameCharacters = new HashSet<char>(new[]
{
'@', '!', '<', '/', '?', '[', '>', ']', '=', '"', '\'', '*'
});
public RazorEngine Engine { get; set; }
public int Order => 150;
public RazorSyntaxTree Execute(RazorCodeDocument codeDocument, RazorSyntaxTree syntaxTree)
protected override void ExecuteCore(RazorCodeDocument codeDocument)
{
var syntaxTree = codeDocument.GetSyntaxTree();
ThrowForMissingDependency(syntaxTree);
var resolver = Engine.Features.OfType<ITagHelperFeature>().FirstOrDefault()?.Resolver;
if (resolver == null)
{
// No resolver, nothing to do.
return syntaxTree;
return;
}
// We need to find directives in all of the *imports* as well as in the main razor file
@ -63,7 +62,7 @@ namespace Microsoft.AspNetCore.Razor.Language
if (errorSink.Errors.Count == 0 && errorList.Count == 0)
{
// No TagHelpers and errors, no op.
return syntaxTree;
return;
}
}
else
@ -80,7 +79,7 @@ namespace Microsoft.AspNetCore.Razor.Language
var diagnostics = CombineErrors(syntaxTree.Diagnostics, errorList);
var newSyntaxTree = RazorSyntaxTree.Create(root, syntaxTree.Source, diagnostics, syntaxTree.Options);
return newSyntaxTree;
codeDocument.SetSyntaxTree(newSyntaxTree);
}
// Internal for testing

View File

@ -0,0 +1,9 @@
// 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.
namespace Microsoft.AspNetCore.Razor.Language
{
public interface IRazorTagHelperBinderPhase : IRazorEnginePhase
{
}
}

View File

@ -53,6 +53,7 @@ namespace Microsoft.AspNetCore.Razor.Language
{
builder.Phases.Add(new DefaultRazorParsingPhase());
builder.Phases.Add(new DefaultRazorSyntaxTreePhase());
builder.Phases.Add(new DefaultRazorTagHelperBinderPhase());
builder.Phases.Add(new DefaultRazorIRLoweringPhase());
builder.Phases.Add(new DefaultRazorDocumentClassifierPhase());
builder.Phases.Add(new DefaultRazorDirectiveClassifierPhase());
@ -66,7 +67,6 @@ namespace Microsoft.AspNetCore.Razor.Language
// Syntax Tree passes
builder.Features.Add(new DefaultDirectiveSyntaxTreePass());
builder.Features.Add(new HtmlNodeOptimizationPass());
builder.Features.Add(new TagHelperBinderSyntaxTreePass());
// IR Passes
builder.Features.Add(new DefaultDocumentClassifierPass());

View File

@ -3,15 +3,15 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.AspNetCore.Razor.Language.Legacy;
using Xunit;
using System.Linq;
using Moq;
using System.Text;
namespace Microsoft.AspNetCore.Razor.Language
{
public class TagHelperBinderSyntaxTreePassTest
public class DefaultRazorTagHelperBinderPhaseTest
{
[Fact]
public void Execute_CanHandleSingleLengthAddTagHelperDirective()
@ -22,7 +22,7 @@ namespace Microsoft.AspNetCore.Razor.Language
builder.AddTagHelpers(new TagHelperDescriptor[0]);
});
var pass = new TagHelperBinderSyntaxTreePass()
var phase = new DefaultRazorTagHelperBinderPhase()
{
Engine = engine,
};
@ -47,11 +47,13 @@ namespace Microsoft.AspNetCore.Razor.Language
var sourceDocument = TestRazorSourceDocument.Create(content, fileName: null);
var codeDocument = RazorCodeDocument.Create(sourceDocument);
var originalTree = RazorSyntaxTree.Parse(sourceDocument);
codeDocument.SetSyntaxTree(originalTree);
// Act
var rewrittenTree = pass.Execute(codeDocument, originalTree);
phase.Execute(codeDocument);
// Assert
var rewrittenTree = codeDocument.GetSyntaxTree();
Assert.Equal(expectedDiagnostics, rewrittenTree.Diagnostics);
}
@ -64,7 +66,7 @@ namespace Microsoft.AspNetCore.Razor.Language
builder.AddTagHelpers(new TagHelperDescriptor[0]);
});
var pass = new TagHelperBinderSyntaxTreePass()
var phase = new DefaultRazorTagHelperBinderPhase()
{
Engine = engine,
};
@ -89,11 +91,13 @@ namespace Microsoft.AspNetCore.Razor.Language
var sourceDocument = TestRazorSourceDocument.Create(content, fileName: null);
var codeDocument = RazorCodeDocument.Create(sourceDocument);
var originalTree = RazorSyntaxTree.Parse(sourceDocument);
codeDocument.SetSyntaxTree(originalTree);
// Act
var rewrittenTree = pass.Execute(codeDocument, originalTree);
phase.Execute(codeDocument);
// Assert
var rewrittenTree = codeDocument.GetSyntaxTree();
Assert.Equal(expectedDiagnostics, rewrittenTree.Diagnostics);
}
@ -106,7 +110,7 @@ namespace Microsoft.AspNetCore.Razor.Language
builder.AddTagHelpers(new TagHelperDescriptor[0]);
});
var pass = new TagHelperBinderSyntaxTreePass()
var phase = new DefaultRazorTagHelperBinderPhase()
{
Engine = engine,
};
@ -131,11 +135,13 @@ namespace Microsoft.AspNetCore.Razor.Language
var sourceDocument = TestRazorSourceDocument.Create(content, fileName: null);
var codeDocument = RazorCodeDocument.Create(sourceDocument);
var originalTree = RazorSyntaxTree.Parse(sourceDocument);
codeDocument.SetSyntaxTree(originalTree);
// Act
var rewrittenTree = pass.Execute(codeDocument, originalTree);
phase.Execute(codeDocument);
// Assert
var rewrittenTree = codeDocument.GetSyntaxTree();
Assert.Equal(expectedDiagnostics, rewrittenTree.Diagnostics);
}
@ -158,7 +164,7 @@ namespace Microsoft.AspNetCore.Razor.Language
});
});
var pass = new TagHelperBinderSyntaxTreePass()
var phase = new DefaultRazorTagHelperBinderPhase()
{
Engine = engine,
};
@ -166,11 +172,13 @@ namespace Microsoft.AspNetCore.Razor.Language
var sourceDocument = CreateTestSourceDocument();
var codeDocument = RazorCodeDocument.Create(sourceDocument);
var originalTree = RazorSyntaxTree.Parse(sourceDocument);
codeDocument.SetSyntaxTree(originalTree);
// Act
var rewrittenTree = pass.Execute(codeDocument, originalTree);
phase.Execute(codeDocument);
// Assert
var rewrittenTree = codeDocument.GetSyntaxTree();
Assert.Empty(rewrittenTree.Diagnostics);
Assert.Equal(3, rewrittenTree.Root.Children.Count);
var formTagHelper = Assert.IsType<TagHelperBlock>(rewrittenTree.Root.Children[2]);
@ -205,7 +213,7 @@ namespace Microsoft.AspNetCore.Razor.Language
builder.AddTagHelpers(new[] { descriptor });
});
var pass = new TagHelperBinderSyntaxTreePass()
var phase = new DefaultRazorTagHelperBinderPhase()
{
Engine = engine,
};
@ -218,11 +226,13 @@ namespace Microsoft.AspNetCore.Razor.Language
var sourceDocument = TestRazorSourceDocument.Create(content);
var codeDocument = RazorCodeDocument.Create(sourceDocument);
var originalTree = RazorSyntaxTree.Parse(sourceDocument);
codeDocument.SetSyntaxTree(originalTree);
// Act
var rewrittenTree = pass.Execute(codeDocument, originalTree);
phase.Execute(codeDocument);
// Assert
var rewrittenTree = codeDocument.GetSyntaxTree();
Assert.Empty(rewrittenTree.Diagnostics);
Assert.Equal(3, rewrittenTree.Root.Children.Count);
@ -256,7 +266,7 @@ namespace Microsoft.AspNetCore.Razor.Language
builder.AddTagHelpers(new[] { descriptor });
});
var pass = new TagHelperBinderSyntaxTreePass()
var phase = new DefaultRazorTagHelperBinderPhase()
{
Engine = engine,
};
@ -269,11 +279,13 @@ namespace Microsoft.AspNetCore.Razor.Language
var sourceDocument = TestRazorSourceDocument.Create(content);
var codeDocument = RazorCodeDocument.Create(sourceDocument);
var originalTree = RazorSyntaxTree.Parse(sourceDocument);
codeDocument.SetSyntaxTree(originalTree);
// Act
var rewrittenTree = pass.Execute(codeDocument, originalTree);
phase.Execute(codeDocument);
// Assert
var rewrittenTree = codeDocument.GetSyntaxTree();
Assert.Empty(rewrittenTree.Diagnostics);
Assert.Equal(3, rewrittenTree.Root.Children.Count);
@ -287,18 +299,20 @@ namespace Microsoft.AspNetCore.Razor.Language
{
// Arrange
var engine = RazorEngine.Create();
var pass = new TagHelperBinderSyntaxTreePass()
var phase = new DefaultRazorTagHelperBinderPhase()
{
Engine = engine,
};
var sourceDocument = CreateTestSourceDocument();
var codeDocument = RazorCodeDocument.Create(sourceDocument);
var originalTree = RazorSyntaxTree.Parse(sourceDocument);
codeDocument.SetSyntaxTree(originalTree);
// Act
var outputTree = pass.Execute(codeDocument, originalTree);
phase.Execute(codeDocument);
// Assert
var outputTree = codeDocument.GetSyntaxTree();
Assert.Empty(outputTree.Diagnostics);
Assert.Same(originalTree, outputTree);
}
@ -311,18 +325,20 @@ namespace Microsoft.AspNetCore.Razor.Language
{
builder.Features.Add(Mock.Of<ITagHelperFeature>());
});
var pass = new TagHelperBinderSyntaxTreePass()
var phase = new DefaultRazorTagHelperBinderPhase()
{
Engine = engine,
};
var sourceDocument = CreateTestSourceDocument();
var codeDocument = RazorCodeDocument.Create(sourceDocument);
var originalTree = RazorSyntaxTree.Parse(sourceDocument);
codeDocument.SetSyntaxTree(originalTree);
// Act
var outputTree = pass.Execute(codeDocument, originalTree);
phase.Execute(codeDocument);
// Assert
var outputTree = codeDocument.GetSyntaxTree();
Assert.Empty(outputTree.Diagnostics);
Assert.Same(originalTree, outputTree);
}
@ -336,7 +352,7 @@ namespace Microsoft.AspNetCore.Razor.Language
builder.Features.Add(new TestTagHelperFeature());
});
var pass = new TagHelperBinderSyntaxTreePass()
var phase = new DefaultRazorTagHelperBinderPhase()
{
Engine = engine,
};
@ -345,11 +361,13 @@ namespace Microsoft.AspNetCore.Razor.Language
var sourceDocument = TestRazorSourceDocument.Create("Hello, world");
var codeDocument = RazorCodeDocument.Create(sourceDocument);
var originalTree = RazorSyntaxTree.Parse(sourceDocument);
codeDocument.SetSyntaxTree(originalTree);
// Act
var outputTree = pass.Execute(codeDocument, originalTree);
phase.Execute(codeDocument);
// Assert
var outputTree = codeDocument.GetSyntaxTree();
Assert.Empty(outputTree.Diagnostics);
Assert.Same(originalTree, outputTree);
}
@ -363,7 +381,7 @@ namespace Microsoft.AspNetCore.Razor.Language
builder.Features.Add(new TestTagHelperFeature());
});
var pass = new TagHelperBinderSyntaxTreePass()
var phase = new DefaultRazorTagHelperBinderPhase()
{
Engine = engine,
};
@ -372,9 +390,10 @@ namespace Microsoft.AspNetCore.Razor.Language
var sourceDocument = TestRazorSourceDocument.Create("Hello, world");
var codeDocument = RazorCodeDocument.Create(sourceDocument);
var originalTree = RazorSyntaxTree.Parse(sourceDocument);
codeDocument.SetSyntaxTree(originalTree);
// Act
var outputTree = pass.Execute(codeDocument, originalTree);
phase.Execute(codeDocument);
// Assert
var context = codeDocument.GetTagHelperContext();
@ -393,7 +412,7 @@ namespace Microsoft.AspNetCore.Razor.Language
builder.Features.Add(Mock.Of<ITagHelperFeature>(f => f.Resolver == resolver));
});
var pass = new TagHelperBinderSyntaxTreePass()
var phase = new DefaultRazorTagHelperBinderPhase()
{
Engine = engine,
};
@ -408,11 +427,13 @@ namespace Microsoft.AspNetCore.Razor.Language
originalTree.Source,
new[] { initialError },
originalTree.Options);
codeDocument.SetSyntaxTree(erroredOriginalTree);
// Act
var outputTree = pass.Execute(codeDocument, erroredOriginalTree);
phase.Execute(codeDocument);
// Assert
var outputTree = codeDocument.GetSyntaxTree();
Assert.Empty(originalTree.Diagnostics);
Assert.NotSame(erroredOriginalTree, outputTree);
Assert.Equal(new[] { initialError, resolverError }, outputTree.Diagnostics);
@ -431,7 +452,7 @@ namespace Microsoft.AspNetCore.Razor.Language
var descriptorError = RazorDiagnosticFactory.CreateTagHelper_InvalidTargetedTagNameNullOrWhitespace();
var pass = new TagHelperBinderSyntaxTreePass()
var phase = new DefaultRazorTagHelperBinderPhase()
{
Engine = engine,
};
@ -439,11 +460,13 @@ namespace Microsoft.AspNetCore.Razor.Language
var sourceDocument = CreateTestSourceDocument();
var codeDocument = RazorCodeDocument.Create(sourceDocument);
var originalTree = RazorSyntaxTree.Parse(sourceDocument);
codeDocument.SetSyntaxTree(originalTree);
// Act
var outputTree = pass.Execute(codeDocument, originalTree);
phase.Execute(codeDocument);
// Assert
var outputTree = codeDocument.GetSyntaxTree();
Assert.Empty(originalTree.Diagnostics);
Assert.Equal(new[] { resolverError, descriptorError }, outputTree.Diagnostics);
}
@ -467,7 +490,7 @@ namespace Microsoft.AspNetCore.Razor.Language
});
});
var pass = new TagHelperBinderSyntaxTreePass()
var phase = new DefaultRazorTagHelperBinderPhase()
{
Engine = engine,
};
@ -490,11 +513,13 @@ namespace Microsoft.AspNetCore.Razor.Language
length: 4));
var erroredOriginalTree = RazorSyntaxTree.Create(originalTree.Root, originalTree.Source, new[] { initialError }, originalTree.Options);
codeDocument.SetSyntaxTree(erroredOriginalTree);
// Act
var outputTree = pass.Execute(codeDocument, erroredOriginalTree);
phase.Execute(codeDocument);
// Assert
var outputTree = codeDocument.GetSyntaxTree();
Assert.Empty(originalTree.Diagnostics);
Assert.NotSame(erroredOriginalTree, outputTree);
Assert.Equal(new[] { initialError, expectedRewritingError }, outputTree.Diagnostics);
@ -511,7 +536,7 @@ namespace Microsoft.AspNetCore.Razor.Language
{
// Arrange
var errorSink = new ErrorSink();
var pass = new TagHelperBinderSyntaxTreePass();
var phase = new DefaultRazorTagHelperBinderPhase();
var directive = new TagHelperDirectiveDescriptor()
{
@ -523,7 +548,7 @@ namespace Microsoft.AspNetCore.Razor.Language
var expected = new SourceLocation(assemblyLocation, 0, assemblyLocation);
// Act
var result = pass.ParseAddOrRemoveDirective(directive, errorSink);
var result = phase.ParseAddOrRemoveDirective(directive, errorSink);
// Assert
Assert.Empty(errorSink.Errors);
@ -733,12 +758,12 @@ namespace Microsoft.AspNetCore.Razor.Language
// Arrange
var errorSink = new ErrorSink();
var pass = new TagHelperBinderSyntaxTreePass();
var phase = new DefaultRazorTagHelperBinderPhase();
// Act
foreach (var directive in ((IEnumerable<TagHelperDirectiveDescriptor>)directives))
{
Assert.False(pass.IsValidTagHelperPrefix(directive.DirectiveText, directive.Location, errorSink));
Assert.False(phase.IsValidTagHelperPrefix(directive.DirectiveText, directive.Location, errorSink));
}
// Assert
@ -883,11 +908,11 @@ namespace Microsoft.AspNetCore.Razor.Language
{
// Arrange
var errorSink = new ErrorSink();
var pass = new TagHelperBinderSyntaxTreePass();
var phase = new DefaultRazorTagHelperBinderPhase();
var document = RazorCodeDocument.Create(new DefaultRazorSourceDocument("Test content", encoding: Encoding.UTF8, fileName: "TestFile"));
// Act
var prefix = pass.ProcessTagHelperPrefix(((IEnumerable<TagHelperDirectiveDescriptor>)directiveDescriptors).ToList(), document, errorSink);
var prefix = phase.ProcessTagHelperPrefix(((IEnumerable<TagHelperDirectiveDescriptor>)directiveDescriptors).ToList(), document, errorSink);
// Assert
Assert.Empty(errorSink.Errors);
@ -1104,12 +1129,12 @@ namespace Microsoft.AspNetCore.Razor.Language
// Arrange
var errorSink = new ErrorSink();
var pass = new TagHelperBinderSyntaxTreePass();
var phase = new DefaultRazorTagHelperBinderPhase();
var expected = (IEnumerable<TagHelperDescriptor>)expectedDescriptors;
// Act
var results = pass.ProcessDirectives(
var results = phase.ProcessDirectives(
new List<TagHelperDirectiveDescriptor>((IEnumerable<TagHelperDirectiveDescriptor>)directiveDescriptors),
new List<TagHelperDescriptor>((IEnumerable<TagHelperDescriptor>)tagHelpers),
errorSink);
@ -1272,10 +1297,10 @@ namespace Microsoft.AspNetCore.Razor.Language
// Arrange
var errorSink = new ErrorSink();
var pass = new TagHelperBinderSyntaxTreePass();
var phase = new DefaultRazorTagHelperBinderPhase();
// Act
var results = pass.ProcessDirectives(
var results = phase.ProcessDirectives(
new List<TagHelperDirectiveDescriptor>((IEnumerable<TagHelperDirectiveDescriptor>)directiveDescriptors),
new List<TagHelperDescriptor>((IEnumerable<TagHelperDescriptor>)tagHelpers),
errorSink);
@ -1311,7 +1336,7 @@ namespace Microsoft.AspNetCore.Razor.Language
{
// Arrange
var errorSink = new ErrorSink();
var pass = new TagHelperBinderSyntaxTreePass();
var phase = new DefaultRazorTagHelperBinderPhase();
var directives = new[]
{
@ -1323,7 +1348,7 @@ namespace Microsoft.AspNetCore.Razor.Language
};
// Act
var results = pass.ProcessDirectives(
var results = phase.ProcessDirectives(
directives,
new[] { Valid_PlainTagHelperDescriptor, Valid_InheritedTagHelperDescriptor },
errorSink);
@ -1352,7 +1377,7 @@ namespace Microsoft.AspNetCore.Razor.Language
{
// Arrange
var errorSink = new ErrorSink();
var pass = new TagHelperBinderSyntaxTreePass();
var phase = new DefaultRazorTagHelperBinderPhase();
var directive = new TagHelperDirectiveDescriptor()
{
@ -1367,7 +1392,7 @@ namespace Microsoft.AspNetCore.Razor.Language
directiveText);
// Act
var result = pass.ParseAddOrRemoveDirective(directive, errorSink);
var result = phase.ParseAddOrRemoveDirective(directive, errorSink);
// Assert
Assert.Null(result);

View File

@ -151,7 +151,6 @@ namespace Microsoft.AspNetCore.Razor.Language
feature => Assert.IsType<DefaultRazorTargetExtensionFeature>(feature),
feature => Assert.IsType<DefaultDirectiveSyntaxTreePass>(feature),
feature => Assert.IsType<HtmlNodeOptimizationPass>(feature),
feature => Assert.IsType<TagHelperBinderSyntaxTreePass>(feature),
feature => Assert.IsType<DefaultDocumentClassifierPass>(feature),
feature => Assert.IsType<DefaultDirectiveIRPass>(feature),
feature => Assert.IsType<DirectiveRemovalIROptimizationPass>(feature),
@ -165,6 +164,7 @@ namespace Microsoft.AspNetCore.Razor.Language
phases,
phase => Assert.IsType<DefaultRazorParsingPhase>(phase),
phase => Assert.IsType<DefaultRazorSyntaxTreePhase>(phase),
phase => Assert.IsType<DefaultRazorTagHelperBinderPhase>(phase),
phase => Assert.IsType<DefaultRazorIRLoweringPhase>(phase),
phase => Assert.IsType<DefaultRazorDocumentClassifierPhase>(phase),
phase => Assert.IsType<DefaultRazorDirectiveClassifierPhase>(phase),
@ -180,7 +180,6 @@ namespace Microsoft.AspNetCore.Razor.Language
feature => Assert.IsType<DefaultRazorTargetExtensionFeature>(feature),
feature => Assert.IsType<DefaultDirectiveSyntaxTreePass>(feature),
feature => Assert.IsType<HtmlNodeOptimizationPass>(feature),
feature => Assert.IsType<TagHelperBinderSyntaxTreePass>(feature),
feature => Assert.IsType<DefaultDocumentClassifierPass>(feature),
feature => Assert.IsType<DefaultDirectiveIRPass>(feature),
feature => Assert.IsType<DirectiveRemovalIROptimizationPass>(feature),
@ -195,6 +194,7 @@ namespace Microsoft.AspNetCore.Razor.Language
phases,
phase => Assert.IsType<DefaultRazorParsingPhase>(phase),
phase => Assert.IsType<DefaultRazorSyntaxTreePhase>(phase),
phase => Assert.IsType<DefaultRazorTagHelperBinderPhase>(phase),
phase => Assert.IsType<DefaultRazorIRLoweringPhase>(phase),
phase => Assert.IsType<DefaultRazorDocumentClassifierPhase>(phase),
phase => Assert.IsType<DefaultRazorDirectiveClassifierPhase>(phase),