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.
// 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.Evolution
@ -17,6 +18,8 @@ namespace Microsoft.AspNetCore.Razor.Evolution
public IList<IRazorEnginePhase> Phases { get; }
public bool DesignTime { get; set; }
public RazorEngine Build()
{
var features = new IRazorEngineFeature[Features.Count];

View File

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

View File

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

View File

@ -17,6 +17,24 @@ namespace Microsoft.AspNetCore.Razor.Evolution
{
var builder = new DefaultRazorEngineBuilder();
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);
return builder.Build();
}
@ -34,7 +52,6 @@ namespace Microsoft.AspNetCore.Razor.Evolution
builder.Phases.Add(new DefaultRazorSyntaxTreePhase());
builder.Phases.Add(new DefaultRazorIRLoweringPhase());
builder.Phases.Add(new DefaultRazorIRPhase());
builder.Phases.Add(new DefaultRazorCSharpLoweringPhase());
// Syntax Tree passes
builder.Features.Add(new DefaultDirectiveSyntaxTreePass());
@ -45,10 +62,34 @@ namespace Microsoft.AspNetCore.Razor.Evolution
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<IRazorEnginePhase> Phases { get; }
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
{
public class DefaultRazorCSharpLoweringPhaseTest
public class DefaultRazorRuntimeCSharpLoweringPhaseTest
{
[Fact]
public void Execute_ThrowsForMissingDependency()
{
// Arrange
var phase = new DefaultRazorCSharpLoweringPhase();
var phase = new DefaultRazorRuntimeCSharpLoweringPhase();
var engine = RazorEngine.CreateEmpty(b => b.Phases.Add(phase));
@ -23,7 +23,7 @@ namespace Microsoft.AspNetCore.Razor.Evolution
// Act & Assert
ExceptionAssert.Throws<InvalidOperationException>(
() => phase.Execute(codeDocument),
$"The '{nameof(DefaultRazorCSharpLoweringPhase)}' phase requires a '{nameof(DocumentIRNode)}' " +
$"The '{nameof(DefaultRazorRuntimeCSharpLoweringPhase)}' phase requires a '{nameof(DocumentIRNode)}' " +
$"provided by the '{nameof(RazorCodeDocument)}'.");
}
}

View File

@ -11,7 +11,7 @@ namespace Microsoft.AspNetCore.Razor.Evolution
public class RazorEngineTest
{
[Fact]
public void Create_NoArg_CreatesDefaultEngine()
public void Create_NoArg_CreatesDefaultRuntimeEngine()
{
// Arrange
// Act
@ -19,12 +19,25 @@ namespace Microsoft.AspNetCore.Razor.Evolution
// Assert
Assert.IsType<DefaultRazorEngine>(engine);
AssertDefaultFeatures(engine.Features);
AssertDefaultPhases(engine.Phases);
AssertDefaultRuntimeFeatures(engine.Features);
AssertDefaultRuntimePhases(engine.Phases);
}
[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
// Act
@ -32,8 +45,21 @@ namespace Microsoft.AspNetCore.Razor.Evolution
// Assert
Assert.IsType<DefaultRazorEngine>(engine);
AssertDefaultFeatures(engine.Features);
AssertDefaultPhases(engine.Phases);
AssertDefaultRuntimeFeatures(engine.Features);
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]
@ -71,7 +97,42 @@ namespace Microsoft.AspNetCore.Razor.Evolution
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(
features,
@ -81,7 +142,7 @@ namespace Microsoft.AspNetCore.Razor.Evolution
feature => Assert.IsType<DefaultDirectiveIRPass>(feature));
}
private static void AssertDefaultPhases(IReadOnlyList<IRazorEnginePhase> phases)
private static void AssertDefaultRuntimePhases(IReadOnlyList<IRazorEnginePhase> phases)
{
Assert.Collection(
phases,
@ -89,7 +150,29 @@ namespace Microsoft.AspNetCore.Razor.Evolution
phase => Assert.IsType<DefaultRazorSyntaxTreePhase>(phase),
phase => Assert.IsType<DefaultRazorIRLoweringPhase>(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));
}
}
}