Add model for differentiating design time and runtime parsing.

- If needed, a phase/feature can always retrieve the syntax tree to lookup whether the parse tree was made in a "design time" fashion.
- Future DesignTime / Runtime specific bits will be added to their corresponding `AddRuntimeDefaults`/`AddDesignTimeDefaults` methods.
This commit is contained in:
N. Taylor Mullen 2016-12-14 12:31:53 -08:00
parent 6ae3feff29
commit 61b2b0d4e7
7 changed files with 162 additions and 14 deletions

View File

@ -0,0 +1,19 @@
// 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.Evolution
{
internal class DefaultRazorDesignTimeCSharpLoweringPhase : RazorEnginePhaseBase, IRazorCSharpLoweringPhase
{
protected override void ExecuteCore(RazorCodeDocument codeDocument)
{
var irDocument = codeDocument.GetIRDocument();
ThrowForMissingDependency(irDocument);
var syntaxTree = codeDocument.GetSyntaxTree();
ThrowForMissingDependency(syntaxTree);
// Render design time CSharp
}
}
}

View File

@ -1,6 +1,7 @@
// Copyright (c) .NET Foundation. All rights reserved. // 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. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using System.Collections.Generic; using System.Collections.Generic;
namespace Microsoft.AspNetCore.Razor.Evolution namespace Microsoft.AspNetCore.Razor.Evolution
@ -17,6 +18,8 @@ namespace Microsoft.AspNetCore.Razor.Evolution
public IList<IRazorEnginePhase> Phases { get; } public IList<IRazorEnginePhase> Phases { get; }
public bool DesignTime { get; set; }
public RazorEngine Build() public RazorEngine Build()
{ {
var features = new IRazorEngineFeature[Features.Count]; var features = new IRazorEngineFeature[Features.Count];

View File

@ -11,7 +11,7 @@ using Microsoft.AspNetCore.Razor.Evolution.Legacy;
namespace Microsoft.AspNetCore.Razor.Evolution namespace Microsoft.AspNetCore.Razor.Evolution
{ {
internal class DefaultRazorCSharpLoweringPhase : RazorEnginePhaseBase, IRazorCSharpLoweringPhase internal class DefaultRazorRuntimeCSharpLoweringPhase : RazorEnginePhaseBase, IRazorCSharpLoweringPhase
{ {
protected override void ExecuteCore(RazorCodeDocument codeDocument) protected override void ExecuteCore(RazorCodeDocument codeDocument)
{ {

View File

@ -11,6 +11,8 @@ namespace Microsoft.AspNetCore.Razor.Evolution
IList<IRazorEnginePhase> Phases { get; } IList<IRazorEnginePhase> Phases { get; }
bool DesignTime { get; set; }
RazorEngine Build(); RazorEngine Build();
} }
} }

View File

@ -17,6 +17,24 @@ namespace Microsoft.AspNetCore.Razor.Evolution
{ {
var builder = new DefaultRazorEngineBuilder(); var builder = new DefaultRazorEngineBuilder();
AddDefaults(builder); AddDefaults(builder);
AddRuntimeDefaults(builder);
configure?.Invoke(builder);
return builder.Build();
}
public static RazorEngine CreateDesignTime()
{
return CreateDesignTime(configure: null);
}
public static RazorEngine CreateDesignTime(Action<IRazorEngineBuilder> configure)
{
var builder = new DefaultRazorEngineBuilder()
{
DesignTime = true,
};
AddDefaults(builder);
AddDesignTimeDefaults(builder);
configure?.Invoke(builder); configure?.Invoke(builder);
return builder.Build(); return builder.Build();
} }
@ -34,7 +52,6 @@ namespace Microsoft.AspNetCore.Razor.Evolution
builder.Phases.Add(new DefaultRazorSyntaxTreePhase()); builder.Phases.Add(new DefaultRazorSyntaxTreePhase());
builder.Phases.Add(new DefaultRazorIRLoweringPhase()); builder.Phases.Add(new DefaultRazorIRLoweringPhase());
builder.Phases.Add(new DefaultRazorIRPhase()); builder.Phases.Add(new DefaultRazorIRPhase());
builder.Phases.Add(new DefaultRazorCSharpLoweringPhase());
// Syntax Tree passes // Syntax Tree passes
builder.Features.Add(new DefaultDirectiveSyntaxTreePass()); builder.Features.Add(new DefaultDirectiveSyntaxTreePass());
@ -45,10 +62,34 @@ namespace Microsoft.AspNetCore.Razor.Evolution
builder.Features.Add(new DefaultDirectiveIRPass()); builder.Features.Add(new DefaultDirectiveIRPass());
} }
internal static void AddRuntimeDefaults(IRazorEngineBuilder builder)
{
builder.Phases.Add(new DefaultRazorRuntimeCSharpLoweringPhase());
}
internal static void AddDesignTimeDefaults(IRazorEngineBuilder builder)
{
builder.Phases.Add(new DefaultRazorDesignTimeCSharpLoweringPhase());
builder.Features.Add(new ConfigureDesignTimeOptions());
}
public abstract IReadOnlyList<IRazorEngineFeature> Features { get; } public abstract IReadOnlyList<IRazorEngineFeature> Features { get; }
public abstract IReadOnlyList<IRazorEnginePhase> Phases { get; } public abstract IReadOnlyList<IRazorEnginePhase> Phases { get; }
public abstract void Process(RazorCodeDocument document); public abstract void Process(RazorCodeDocument document);
internal class ConfigureDesignTimeOptions : IRazorConfigureParserFeature
{
public RazorEngine Engine { get; set; }
public int Order { get; set; }
public void Configure(RazorParserOptions options)
{
options.DesignTimeMode = true;
}
}
} }
} }

View File

@ -8,13 +8,13 @@ using Xunit;
namespace Microsoft.AspNetCore.Razor.Evolution namespace Microsoft.AspNetCore.Razor.Evolution
{ {
public class DefaultRazorCSharpLoweringPhaseTest public class DefaultRazorRuntimeCSharpLoweringPhaseTest
{ {
[Fact] [Fact]
public void Execute_ThrowsForMissingDependency() public void Execute_ThrowsForMissingDependency()
{ {
// Arrange // Arrange
var phase = new DefaultRazorCSharpLoweringPhase(); var phase = new DefaultRazorRuntimeCSharpLoweringPhase();
var engine = RazorEngine.CreateEmpty(b => b.Phases.Add(phase)); var engine = RazorEngine.CreateEmpty(b => b.Phases.Add(phase));
@ -23,7 +23,7 @@ namespace Microsoft.AspNetCore.Razor.Evolution
// Act & Assert // Act & Assert
ExceptionAssert.Throws<InvalidOperationException>( ExceptionAssert.Throws<InvalidOperationException>(
() => phase.Execute(codeDocument), () => phase.Execute(codeDocument),
$"The '{nameof(DefaultRazorCSharpLoweringPhase)}' phase requires a '{nameof(DocumentIRNode)}' " + $"The '{nameof(DefaultRazorRuntimeCSharpLoweringPhase)}' phase requires a '{nameof(DocumentIRNode)}' " +
$"provided by the '{nameof(RazorCodeDocument)}'."); $"provided by the '{nameof(RazorCodeDocument)}'.");
} }
} }

View File

@ -11,7 +11,7 @@ namespace Microsoft.AspNetCore.Razor.Evolution
public class RazorEngineTest public class RazorEngineTest
{ {
[Fact] [Fact]
public void Create_NoArg_CreatesDefaultEngine() public void Create_NoArg_CreatesDefaultRuntimeEngine()
{ {
// Arrange // Arrange
// Act // Act
@ -19,12 +19,25 @@ namespace Microsoft.AspNetCore.Razor.Evolution
// Assert // Assert
Assert.IsType<DefaultRazorEngine>(engine); Assert.IsType<DefaultRazorEngine>(engine);
AssertDefaultFeatures(engine.Features); AssertDefaultRuntimeFeatures(engine.Features);
AssertDefaultPhases(engine.Phases); AssertDefaultRuntimePhases(engine.Phases);
} }
[Fact] [Fact]
public void Create_Null_CreatesDefaultEngine() public void CreateDesignTime_NoArg_CreatesDefaultDesignTimeEngine()
{
// Arrange
// Act
var engine = RazorEngine.CreateDesignTime();
// Assert
Assert.IsType<DefaultRazorEngine>(engine);
AssertDefaultDesignTimeFeatures(engine.Features);
AssertDefaultDesignTimePhases(engine.Phases);
}
[Fact]
public void Create_Null_CreatesDefaultRuntimeEngine()
{ {
// Arrange // Arrange
// Act // Act
@ -32,8 +45,21 @@ namespace Microsoft.AspNetCore.Razor.Evolution
// Assert // Assert
Assert.IsType<DefaultRazorEngine>(engine); Assert.IsType<DefaultRazorEngine>(engine);
AssertDefaultFeatures(engine.Features); AssertDefaultRuntimeFeatures(engine.Features);
AssertDefaultPhases(engine.Phases); AssertDefaultRuntimePhases(engine.Phases);
}
[Fact]
public void CreateDesignTime_Null_CreatesDefaultDesignTimeEngine()
{
// Arrange
// Act
var engine = RazorEngine.CreateDesignTime(configure: null);
// Assert
Assert.IsType<DefaultRazorEngine>(engine);
AssertDefaultDesignTimeFeatures(engine.Features);
AssertDefaultDesignTimePhases(engine.Phases);
} }
[Fact] [Fact]
@ -71,7 +97,42 @@ namespace Microsoft.AspNetCore.Razor.Evolution
p => Assert.Same(phases[1], p)); p => Assert.Same(phases[1], p));
} }
private static void AssertDefaultFeatures(IEnumerable<IRazorEngineFeature> features) [Fact]
public void CreateDesignTime_Lambda_AddsFeaturesAndPhases()
{
// Arrange
IRazorEngineFeature[] features = null;
IRazorEnginePhase[] phases = null;
// Act
var engine = RazorEngine.CreateDesignTime(builder =>
{
builder.Features.Clear();
builder.Phases.Clear();
builder.Features.Add(Mock.Of<IRazorEngineFeature>());
builder.Features.Add(Mock.Of<IRazorEngineFeature>());
builder.Phases.Add(Mock.Of<IRazorEnginePhase>());
builder.Phases.Add(Mock.Of<IRazorEnginePhase>());
features = builder.Features.ToArray();
phases = builder.Phases.ToArray();
});
// Assert
Assert.Collection(
engine.Features,
f => Assert.Same(features[0], f),
f => Assert.Same(features[1], f));
Assert.Collection(
engine.Phases,
p => Assert.Same(phases[0], p),
p => Assert.Same(phases[1], p));
}
private static void AssertDefaultRuntimeFeatures(IEnumerable<IRazorEngineFeature> features)
{ {
Assert.Collection( Assert.Collection(
features, features,
@ -81,7 +142,7 @@ namespace Microsoft.AspNetCore.Razor.Evolution
feature => Assert.IsType<DefaultDirectiveIRPass>(feature)); feature => Assert.IsType<DefaultDirectiveIRPass>(feature));
} }
private static void AssertDefaultPhases(IReadOnlyList<IRazorEnginePhase> phases) private static void AssertDefaultRuntimePhases(IReadOnlyList<IRazorEnginePhase> phases)
{ {
Assert.Collection( Assert.Collection(
phases, phases,
@ -89,7 +150,29 @@ namespace Microsoft.AspNetCore.Razor.Evolution
phase => Assert.IsType<DefaultRazorSyntaxTreePhase>(phase), phase => Assert.IsType<DefaultRazorSyntaxTreePhase>(phase),
phase => Assert.IsType<DefaultRazorIRLoweringPhase>(phase), phase => Assert.IsType<DefaultRazorIRLoweringPhase>(phase),
phase => Assert.IsType<DefaultRazorIRPhase>(phase), phase => Assert.IsType<DefaultRazorIRPhase>(phase),
phase => Assert.IsType<DefaultRazorCSharpLoweringPhase>(phase)); phase => Assert.IsType<DefaultRazorRuntimeCSharpLoweringPhase>(phase));
}
private static void AssertDefaultDesignTimeFeatures(IEnumerable<IRazorEngineFeature> features)
{
Assert.Collection(
features,
feature => Assert.IsType<DefaultDirectiveSyntaxTreePass>(feature),
feature => Assert.IsType<TagHelperBinderSyntaxTreePass>(feature),
feature => Assert.IsType<HtmlNodeOptimizationPass>(feature),
feature => Assert.IsType<DefaultDirectiveIRPass>(feature),
feature => Assert.IsType<RazorEngine.ConfigureDesignTimeOptions>(feature));
}
private static void AssertDefaultDesignTimePhases(IReadOnlyList<IRazorEnginePhase> phases)
{
Assert.Collection(
phases,
phase => Assert.IsType<DefaultRazorParsingPhase>(phase),
phase => Assert.IsType<DefaultRazorSyntaxTreePhase>(phase),
phase => Assert.IsType<DefaultRazorIRLoweringPhase>(phase),
phase => Assert.IsType<DefaultRazorIRPhase>(phase),
phase => Assert.IsType<DefaultRazorDesignTimeCSharpLoweringPhase>(phase));
} }
} }
} }