Get rid of RazorConfiguration.DesignTime

This change makes it so that we no longer create 'design time' engines.
The choice of design time or runtime is made when we initiate a code
generation operation.

Options instances are now created as part of the CodeDocument
initialization. Our existing code can still be created using a
RazorEngine so our passes that initialize the options still support the
old code path.
This commit is contained in:
Ryan Nowak 2018-02-13 13:23:56 -08:00
parent 010b43cedf
commit 82579b6333
49 changed files with 874 additions and 225 deletions

View File

@ -29,7 +29,7 @@ namespace Microsoft.AspNetCore.Mvc.Razor.Extensions.Version1_X
}
builder.AddDirective(Directive);
builder.Features.Add(new Pass(builder.Configuration.DesignTime));
builder.Features.Add(new Pass());
return builder;
}
@ -64,13 +64,6 @@ namespace Microsoft.AspNetCore.Mvc.Razor.Extensions.Version1_X
internal class Pass : IntermediateNodePassBase, IRazorDirectiveClassifierPass
{
private readonly bool _designTime;
public Pass(bool designTime)
{
_designTime = designTime;
}
// Runs after the @inherits directive
public override int Order => 5;
@ -79,7 +72,7 @@ namespace Microsoft.AspNetCore.Mvc.Razor.Extensions.Version1_X
var visitor = new Visitor();
var modelType = GetModelType(documentNode, visitor);
if (_designTime)
if (documentNode.Options.DesignTime)
{
// Alias the TModel token to a known type.
// This allows design time compilation to succeed for Razor files where the token isn't replaced.
@ -143,7 +136,7 @@ namespace Microsoft.AspNetCore.Mvc.Razor.Extensions.Version1_X
}
builder.AddDirective(Directive);
builder.Features.Add(new Pass(builder.DesignTime));
builder.Features.Add(new Pass());
return builder;
}
#endregion

View File

@ -10,7 +10,7 @@ using Microsoft.AspNetCore.Razor.Language;
namespace Microsoft.AspNetCore.Mvc.Razor.Extensions.Version1_X
{
internal class DefaultMvcImportFeature : RazorProjectEngineFeatureBase, IRazorImportFeature
internal class MvcImportProjectFeature : RazorProjectEngineFeatureBase, IImportProjectFeature
{
private const string ImportsFileName = "_ViewImports.cshtml";

View File

@ -16,8 +16,6 @@ namespace Microsoft.AspNetCore.Mvc.Razor.Extensions.Version1_X
throw new ArgumentNullException(nameof(builder));
}
EnsureDesignTime(builder);
InjectDirective.Register(builder);
ModelDirective.Register(builder);
@ -37,7 +35,7 @@ namespace Microsoft.AspNetCore.Mvc.Razor.Extensions.Version1_X
builder.Features.Add(new ModelExpressionPass());
builder.Features.Add(new MvcViewDocumentClassifierPass());
builder.SetImportFeature(new DefaultMvcImportFeature());
builder.SetImportFeature(new MvcImportProjectFeature());
}
public static void RegisterViewComponentTagHelpers(RazorProjectEngineBuilder builder)
@ -47,22 +45,10 @@ namespace Microsoft.AspNetCore.Mvc.Razor.Extensions.Version1_X
throw new ArgumentNullException(nameof(builder));
}
EnsureDesignTime(builder);
builder.Features.Add(new ViewComponentTagHelperPass());
builder.AddTargetExtension(new ViewComponentTagHelperTargetExtension());
}
private static void EnsureDesignTime(RazorProjectEngineBuilder builder)
{
if (builder.Configuration.DesignTime)
{
return;
}
throw new NotSupportedException(Resources.RuntimeCodeGenerationNotSupported);
}
#region Obsolete
public static void Register(IRazorEngineBuilder builder)
{

View File

@ -14,6 +14,11 @@ namespace Microsoft.AspNetCore.Mvc.Razor.Extensions
protected override void ExecuteCore(RazorCodeDocument codeDocument, DocumentIntermediateNode documentNode)
{
if (documentNode.Options.DesignTime)
{
return;
}
var @namespace = documentNode.FindPrimaryNamespace();
if (@namespace == null || string.IsNullOrEmpty(@namespace.Content))
{

View File

@ -15,6 +15,11 @@ namespace Microsoft.AspNetCore.Mvc.Razor.Extensions
protected override void ExecuteCore(RazorCodeDocument codeDocument, DocumentIntermediateNode documentNode)
{
if (documentNode.Options.DesignTime)
{
return;
}
var walker = new Visitor();
walker.VisitDocument(documentNode);

View File

@ -29,7 +29,7 @@ namespace Microsoft.AspNetCore.Mvc.Razor.Extensions
}
builder.AddDirective(Directive);
builder.Features.Add(new Pass(builder.Configuration.DesignTime));
builder.Features.Add(new Pass());
return builder;
}
@ -71,13 +71,6 @@ namespace Microsoft.AspNetCore.Mvc.Razor.Extensions
internal class Pass : IntermediateNodePassBase, IRazorDirectiveClassifierPass
{
private readonly bool _designTime;
public Pass(bool designTime)
{
_designTime = designTime;
}
// Runs after the @inherits directive
public override int Order => 5;
@ -86,7 +79,7 @@ namespace Microsoft.AspNetCore.Mvc.Razor.Extensions
var visitor = new Visitor();
var modelType = GetModelType(documentNode, visitor);
if (_designTime)
if (documentNode.Options.DesignTime)
{
// Alias the TModel token to a known type.
// This allows design time compilation to succeed for Razor files where the token isn't replaced.
@ -150,7 +143,7 @@ namespace Microsoft.AspNetCore.Mvc.Razor.Extensions
}
builder.AddDirective(Directive);
builder.Features.Add(new Pass(builder.DesignTime));
builder.Features.Add(new Pass());
return builder;
}
#endregion

View File

@ -10,7 +10,7 @@ using Microsoft.AspNetCore.Razor.Language;
namespace Microsoft.AspNetCore.Mvc.Razor.Extensions
{
internal class DefaultMvcImportFeature : RazorProjectEngineFeatureBase, IRazorImportFeature
internal class MvcImportProjectFeature : RazorProjectEngineFeatureBase, IImportProjectFeature
{
private const string ImportsFileName = "_ViewImports.cshtml";

View File

@ -36,14 +36,10 @@ namespace Microsoft.AspNetCore.Mvc.Razor.Extensions
builder.Features.Add(new ViewComponentTagHelperPass());
builder.Features.Add(new RazorPageDocumentClassifierPass());
builder.Features.Add(new MvcViewDocumentClassifierPass());
builder.Features.Add(new AssemblyAttributeInjectionPass());
builder.Features.Add(new InstrumentationPass());
if (!builder.Configuration.DesignTime)
{
builder.Features.Add(new AssemblyAttributeInjectionPass());
builder.Features.Add(new InstrumentationPass());
}
builder.SetImportFeature(new DefaultMvcImportFeature());
builder.SetImportFeature(new MvcImportProjectFeature());
}
#region Obsolete

View File

@ -6,7 +6,7 @@ using System.Collections.Generic;
namespace Microsoft.AspNetCore.Razor.Language
{
internal class DefaultRazorImportFeature : RazorProjectEngineFeatureBase, IRazorImportFeature
internal class DefaultImportProjectFeature : RazorProjectEngineFeatureBase, IImportProjectFeature
{
public IReadOnlyList<RazorSourceDocument> GetImports(RazorProjectItem projectItem) => Array.Empty<RazorSourceDocument>();
}

View File

@ -1,16 +1,30 @@
// 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;
namespace Microsoft.AspNetCore.Razor.Language
{
internal class DefaultRazorCodeGenerationOptionsBuilder : RazorCodeGenerationOptionsBuilder
{
public DefaultRazorCodeGenerationOptionsBuilder(bool designTime)
private bool _designTime;
public DefaultRazorCodeGenerationOptionsBuilder(RazorConfiguration configuration)
{
DesignTime = designTime;
if (configuration == null)
{
throw new ArgumentNullException(nameof(configuration));
}
}
public override bool DesignTime { get; }
public DefaultRazorCodeGenerationOptionsBuilder(bool designTime)
{
_designTime = designTime;
}
public override RazorConfiguration Configuration { get; }
public override bool DesignTime => _designTime;
public override int IndentSize { get; set; } = 4;
@ -22,5 +36,10 @@ namespace Microsoft.AspNetCore.Razor.Language
{
return new DefaultRazorCodeGenerationOptions(IndentWithTabs, IndentSize, DesignTime, SuppressChecksum, SuppressMetadataAttributes);
}
public override void SetDesignTime(bool designTime)
{
_designTime = designTime;
}
}
}

View File

@ -0,0 +1,32 @@
// 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.Linq;
namespace Microsoft.AspNetCore.Razor.Language
{
internal class DefaultRazorCodeGenerationOptionsFactoryProjectFeature : RazorProjectEngineFeatureBase, IRazorCodeGenerationOptionsFactoryProjectFeature
{
private IConfigureRazorCodeGenerationOptionsFeature[] _configureOptions;
protected override void OnInitialized()
{
_configureOptions = ProjectEngine.EngineFeatures.OfType<IConfigureRazorCodeGenerationOptionsFeature>().ToArray();
}
public RazorCodeGenerationOptions Create(Action<RazorCodeGenerationOptionsBuilder> configure)
{
var builder = new DefaultRazorCodeGenerationOptionsBuilder(ProjectEngine.Configuration);
configure?.Invoke(builder);
for (var i = 0; i < _configureOptions.Length; i++)
{
_configureOptions[i].Configure(builder);
}
var options = builder.Build();
return options;
}
}
}

View File

@ -5,7 +5,9 @@ using System.Linq;
namespace Microsoft.AspNetCore.Razor.Language
{
#pragma warning disable CS0618 // Type or member is obsolete
internal class DefaultRazorCodeGenerationOptionsFeature : RazorEngineFeatureBase, IRazorCodeGenerationOptionsFeature
#pragma warning restore CS0618 // Type or member is obsolete
{
private readonly bool _designTime;
private IConfigureRazorCodeGenerationOptionsFeature[] _configureOptions;

View File

@ -11,6 +11,7 @@ using Microsoft.AspNetCore.Razor.Language.Legacy;
namespace Microsoft.AspNetCore.Razor.Language
{
#pragma warning disable CS0618 // Type or member is obsolete
internal class DefaultRazorIntermediateNodeLoweringPhase : RazorEnginePhaseBase, IRazorIntermediateNodeLoweringPhase
{
private IRazorCodeGenerationOptionsFeature _optionsFeature;
@ -31,7 +32,7 @@ namespace Microsoft.AspNetCore.Razor.Language
var document = new DocumentIntermediateNode();
var builder = IntermediateNodeBuilder.Create(document);
document.Options = _optionsFeature.GetOptions();
document.Options = codeDocument.GetCodeGenerationOptions() ?? _optionsFeature.GetOptions();
var namespaces = new Dictionary<string, SourceSpan?>(StringComparer.Ordinal);
@ -785,4 +786,5 @@ namespace Microsoft.AspNetCore.Razor.Language
private static bool IsMalformed(List<RazorDiagnostic> diagnostics)
=> diagnostics.Count > 0 && diagnostics.Any(diagnostic => diagnostic.Severity == RazorDiagnosticSeverity.Error);
}
#pragma warning restore CS0618 // Type or member is obsolete
}

View File

@ -9,23 +9,43 @@ namespace Microsoft.AspNetCore.Razor.Language
{
internal class DefaultRazorParserOptionsBuilder : RazorParserOptionsBuilder
{
public DefaultRazorParserOptionsBuilder(bool designTime, RazorLanguageVersion version)
private bool _designTime;
public DefaultRazorParserOptionsBuilder(RazorConfiguration configuration)
{
DesignTime = designTime;
Version = version;
if (configuration == null)
{
throw new ArgumentNullException(nameof(configuration));
}
Configuration = configuration;
LanguageVersion = configuration.LanguageVersion;
}
public override bool DesignTime { get; }
public DefaultRazorParserOptionsBuilder(bool designTime, RazorLanguageVersion version)
{
_designTime = designTime;
LanguageVersion = version;
}
public override RazorConfiguration Configuration { get; }
public override bool DesignTime => _designTime;
public override ICollection<DirectiveDescriptor> Directives { get; } = new List<DirectiveDescriptor>();
public override bool ParseLeadingDirectives { get; set; }
public override RazorLanguageVersion Version { get; }
public override RazorLanguageVersion LanguageVersion { get; }
public override RazorParserOptions Build()
{
return new DefaultRazorParserOptions(Directives.ToArray(), DesignTime, ParseLeadingDirectives, Version);
return new DefaultRazorParserOptions(Directives.ToArray(), DesignTime, ParseLeadingDirectives, LanguageVersion);
}
public override void SetDesignTime(bool designTime)
{
_designTime = designTime;
}
}
}

View File

@ -0,0 +1,32 @@
// 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.Linq;
namespace Microsoft.AspNetCore.Razor.Language
{
internal class DefaultRazorParserOptionsFactoryProjectFeature : RazorProjectEngineFeatureBase, IRazorParserOptionsFactoryProjectFeature
{
private IConfigureRazorParserOptionsFeature[] _configureOptions;
protected override void OnInitialized()
{
_configureOptions = ProjectEngine.EngineFeatures.OfType<IConfigureRazorParserOptionsFeature>().ToArray();
}
public RazorParserOptions Create(Action<RazorParserOptionsBuilder> configure)
{
var builder = new DefaultRazorParserOptionsBuilder(ProjectEngine.Configuration);
configure?.Invoke(builder);
for (var i = 0; i < _configureOptions.Length; i++)
{
_configureOptions[i].Configure(builder);
}
var options = builder.Build();
return options;
}
}
}

View File

@ -5,7 +5,9 @@ using System.Linq;
namespace Microsoft.AspNetCore.Razor.Language
{
#pragma warning disable CS0618 // Type or member is obsolete
internal class DefaultRazorParserOptionsFeature : RazorEngineFeatureBase, IRazorParserOptionsFeature
#pragma warning restore CS0618 // Type or member is obsolete
{
private readonly bool _designTime;
private readonly RazorLanguageVersion _version;

View File

@ -3,6 +3,7 @@
namespace Microsoft.AspNetCore.Razor.Language
{
#pragma warning disable CS0618 // Type or member is obsolete
internal class DefaultRazorParsingPhase : RazorEnginePhaseBase, IRazorParsingPhase
{
private IRazorParserOptionsFeature _optionsFeature;
@ -14,7 +15,7 @@ namespace Microsoft.AspNetCore.Razor.Language
protected override void ExecuteCore(RazorCodeDocument codeDocument)
{
var options = _optionsFeature.GetOptions();
var options = codeDocument.GetParserOptions() ??_optionsFeature.GetOptions();
var syntaxTree = RazorSyntaxTree.Parse(codeDocument.Source, options);
codeDocument.SetSyntaxTree(syntaxTree);
@ -26,4 +27,5 @@ namespace Microsoft.AspNetCore.Razor.Language
codeDocument.SetImportSyntaxTrees(importSyntaxTrees);
}
}
#pragma warning restore CS0618 // Type or member is obsolete
}

View File

@ -10,10 +10,16 @@ namespace Microsoft.AspNetCore.Razor.Language
internal class DefaultRazorProjectEngine : RazorProjectEngine
{
public DefaultRazorProjectEngine(
RazorConfiguration configuration,
RazorEngine engine,
RazorProjectFileSystem fileSystem,
IReadOnlyList<IRazorProjectEngineFeature> features)
IReadOnlyList<IRazorProjectEngineFeature> projectFeatures)
{
if (configuration == null)
{
throw new ArgumentNullException(nameof(configuration));
}
if (engine == null)
{
throw new ArgumentNullException(nameof(engine));
@ -24,39 +30,87 @@ namespace Microsoft.AspNetCore.Razor.Language
throw new ArgumentNullException(nameof(fileSystem));
}
if (features == null)
if (projectFeatures == null)
{
throw new ArgumentNullException(nameof(features));
throw new ArgumentNullException(nameof(projectFeatures));
}
Configuration = configuration;
Engine = engine;
FileSystem = fileSystem;
Features = features;
ProjectFeatures = projectFeatures;
for (var i = 0; i < features.Count; i++)
for (var i = 0; i < projectFeatures.Count; i++)
{
features[i].ProjectEngine = this;
projectFeatures[i].ProjectEngine = this;
}
}
public override RazorConfiguration Configuration { get; }
public override RazorProjectFileSystem FileSystem { get; }
public override RazorEngine Engine { get; }
public override IReadOnlyList<IRazorProjectEngineFeature> Features { get; }
public override IReadOnlyList<IRazorProjectEngineFeature> ProjectFeatures { get; }
public override RazorCodeDocument Process(RazorProjectItem projectItem)
protected override void ConfigureParserOptions(RazorParserOptionsBuilder builder)
{
if (builder == null)
{
throw new ArgumentNullException(nameof(builder));
}
}
protected override void ConfigureDesignTimeParserOptions(RazorParserOptionsBuilder builder)
{
if (builder == null)
{
throw new ArgumentNullException(nameof(builder));
}
builder.SetDesignTime(true);
}
protected override void ConfigureCodeGenerationOptions(RazorCodeGenerationOptionsBuilder builder)
{
if (builder == null)
{
throw new ArgumentNullException(nameof(builder));
}
}
protected override void ConfigureDesignTimeCodeGenerationOptions(RazorCodeGenerationOptionsBuilder builder)
{
if (builder == null)
{
throw new ArgumentNullException(nameof(builder));
}
builder.SetDesignTime(true);
builder.SuppressChecksum = true;
builder.SuppressMetadataAttributes = true;
}
protected override RazorCodeDocument ProcessCore(
RazorProjectItem projectItem,
Action<RazorParserOptionsBuilder> configureParser,
Action<RazorCodeGenerationOptionsBuilder> configureCodeGeneration)
{
if (projectItem == null)
{
throw new ArgumentNullException(nameof(projectItem));
}
var importFeature = GetRequiredFeature<IRazorImportFeature>();
var imports = importFeature.GetImports(projectItem);
var sourceDocument = RazorSourceDocument.ReadFrom(projectItem);
var codeDocument = RazorCodeDocument.Create(sourceDocument, imports);
var importFeature = GetRequiredFeature<IImportProjectFeature>();
var imports = importFeature.GetImports(projectItem);
var parserOptions = GetRequiredFeature<IRazorParserOptionsFactoryProjectFeature>().Create(configureParser);
var codeGenerationOptions = GetRequiredFeature<IRazorCodeGenerationOptionsFactoryProjectFeature>().Create(configureCodeGeneration);
var codeDocument = RazorCodeDocument.Create(sourceDocument, imports, parserOptions, codeGenerationOptions);
Engine.Process(codeDocument);
@ -65,7 +119,7 @@ namespace Microsoft.AspNetCore.Razor.Language
private TFeature GetRequiredFeature<TFeature>() where TFeature : IRazorProjectEngineFeature
{
var feature = Features.OfType<TFeature>().FirstOrDefault();
var feature = ProjectFeatures.OfType<TFeature>().FirstOrDefault();
if (feature == null)
{
throw new InvalidOperationException(

View File

@ -22,29 +22,19 @@ namespace Microsoft.AspNetCore.Razor.Language
Phases = new List<IRazorEnginePhase>();
}
public override RazorConfiguration Configuration { get; }
public override RazorProjectFileSystem FileSystem { get; }
public override ICollection<IRazorFeature> Features { get; }
public override IList<IRazorEnginePhase> Phases { get; }
public override RazorConfiguration Configuration { get; }
public override RazorProjectEngine Build()
{
RazorEngine engine = null;
if (Configuration.DesignTime)
{
engine = RazorEngine.CreateDesignTimeEmpty(ConfigureRazorEngine);
}
else
{
engine = RazorEngine.CreateEmpty(ConfigureRazorEngine);
}
var projectEngineFeatures = Features.OfType<IRazorProjectEngineFeature>().ToArray();
var projectEngine = new DefaultRazorProjectEngine(engine, FileSystem, projectEngineFeatures);
var engine = RazorEngine.CreateEmpty(ConfigureRazorEngine);
var projectFeatures = Features.OfType<IRazorProjectEngineFeature>().ToArray();
var projectEngine = new DefaultRazorProjectEngine(Configuration, engine, FileSystem, projectFeatures);
return projectEngine;
}

View File

@ -16,8 +16,6 @@ namespace Microsoft.AspNetCore.Razor.Language.Extensions
{
private static readonly string[] PrivateModifiers = new string[] { "private" };
public bool DesignTime { get; set; }
public string RunnerVariableName { get; set; } = "__tagHelperRunner";
public string StringValueBufferVariableName { get; set; } = "__tagHelperStringValueBuffer";
@ -82,7 +80,7 @@ namespace Microsoft.AspNetCore.Razor.Language.Extensions
throw new InvalidOperationException(message);
}
if (DesignTime)
if (context.Options.DesignTime)
{
context.RenderChildren(node);
}
@ -136,7 +134,7 @@ namespace Microsoft.AspNetCore.Razor.Language.Extensions
.Write(CreateTagHelperMethodName)
.WriteLine("<global::" + node.TypeName + ">();");
if (!DesignTime)
if (!context.Options.DesignTime)
{
context.CodeWriter.WriteInstanceMethodInvocation(
ExecutionContextVariableName,
@ -153,7 +151,7 @@ namespace Microsoft.AspNetCore.Razor.Language.Extensions
throw new InvalidOperationException(message);
}
if (!DesignTime)
if (!context.Options.DesignTime)
{
context.CodeWriter
.Write("await ")
@ -200,7 +198,7 @@ namespace Microsoft.AspNetCore.Razor.Language.Extensions
throw new InvalidOperationException(message);
}
if (DesignTime)
if (context.Options.DesignTime)
{
context.RenderChildren(node);
}
@ -284,7 +282,7 @@ namespace Microsoft.AspNetCore.Razor.Language.Extensions
throw new InvalidOperationException(message);
}
if (!DesignTime)
if (!context.Options.DesignTime)
{
// Ensure that the property we're trying to set has initialized its dictionary bound properties.
if (node.IsIndexerNameMatch &&
@ -338,7 +336,7 @@ namespace Microsoft.AspNetCore.Razor.Language.Extensions
// If we get there, this is the first time seeing this property so we need to evaluate the expression.
if (node.BoundAttribute.ExpectsStringValue(node.AttributeName))
{
if (DesignTime)
if (context.Options.DesignTime)
{
context.RenderChildren(node);
@ -370,7 +368,7 @@ namespace Microsoft.AspNetCore.Razor.Language.Extensions
}
else
{
if (DesignTime)
if (context.Options.DesignTime)
{
var firstMappedChild = node.Children.FirstOrDefault(child => child.Source != null) as IntermediateNode;
var valueStart = firstMappedChild?.Source;
@ -456,7 +454,7 @@ namespace Microsoft.AspNetCore.Razor.Language.Extensions
}
}
if (!DesignTime)
if (!context.Options.DesignTime)
{
// We need to inform the context of the attribute value.
context.CodeWriter
@ -474,7 +472,7 @@ namespace Microsoft.AspNetCore.Razor.Language.Extensions
public void WriteTagHelperRuntime(CodeRenderingContext context, DefaultTagHelperRuntimeIntermediateNode node)
{
if (!DesignTime)
if (!context.Options.DesignTime)
{
context.CodeWriter.WriteLine("#line hidden");
@ -566,7 +564,7 @@ namespace Microsoft.AspNetCore.Razor.Language.Extensions
}
else if (node is IntermediateToken token)
{
if (DesignTime && node.Source != null)
if (context.Options.DesignTime && node.Source != null)
{
context.AddSourceMappingFor(node);
}

View File

@ -15,6 +15,13 @@ namespace Microsoft.AspNetCore.Razor.Language.Extensions
protected override void ExecuteCore(RazorCodeDocument codeDocument, DocumentIntermediateNode documentNode)
{
// Only supports design time. This pass rewrites directives so they will have the right design time
// behavior and would break things if it ran for runtime.
if (!documentNode.Options.DesignTime)
{
return;
}
var walker = new DesignTimeHelperWalker();
walker.VisitDocument(documentNode);
}

View File

@ -15,6 +15,12 @@ namespace Microsoft.AspNetCore.Razor.Language.Extensions
protected override void ExecuteCore(RazorCodeDocument codeDocument, DocumentIntermediateNode documentNode)
{
// There's no value in executing this pass at design time, it just prevents some allocations.
if (documentNode.Options.DesignTime)
{
return;
}
var walker = new PreallocatedTagHelperWalker();
walker.VisitDocument(documentNode);
}

View File

@ -5,7 +5,7 @@ using System.Collections.Generic;
namespace Microsoft.AspNetCore.Razor.Language
{
public interface IRazorImportFeature : IRazorProjectEngineFeature
public interface IImportProjectFeature : IRazorProjectEngineFeature
{
IReadOnlyList<RazorSourceDocument> GetImports(RazorProjectItem projectItem);
}

View File

@ -0,0 +1,12 @@
// 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;
namespace Microsoft.AspNetCore.Razor.Language
{
internal interface IRazorCodeGenerationOptionsFactoryProjectFeature : IRazorProjectEngineFeature
{
RazorCodeGenerationOptions Create(Action<RazorCodeGenerationOptionsBuilder> configure);
}
}

View File

@ -1,8 +1,11 @@
// 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;
namespace Microsoft.AspNetCore.Razor.Language
{
[Obsolete("In Razor 2.1 and newer, use RazorCodeDocument.GetCodeGenerationOptions().")]
public interface IRazorCodeGenerationOptionsFeature : IRazorEngineFeature
{
RazorCodeGenerationOptions GetOptions();

View File

@ -0,0 +1,12 @@
// 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;
namespace Microsoft.AspNetCore.Razor.Language
{
internal interface IRazorParserOptionsFactoryProjectFeature : IRazorProjectEngineFeature
{
RazorParserOptions Create(Action<RazorParserOptionsBuilder> configure);
}
}

View File

@ -1,8 +1,11 @@
// 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;
namespace Microsoft.AspNetCore.Razor.Language
{
[Obsolete("In Razor 2.1 and newer, use RazorCodeDocument.GetParserOptions().")]
public interface IRazorParserOptionsFeature : IRazorEngineFeature
{
RazorParserOptions GetOptions();

View File

@ -30,6 +30,23 @@ namespace Microsoft.AspNetCore.Razor.Language
return new DefaultRazorCodeDocument(source, imports);
}
public static RazorCodeDocument Create(
RazorSourceDocument source,
IEnumerable<RazorSourceDocument> imports,
RazorParserOptions parserOptions,
RazorCodeGenerationOptions codeGenerationOptions)
{
if (source == null)
{
throw new ArgumentNullException(nameof(source));
}
var codeDocument = new DefaultRazorCodeDocument(source, imports);
codeDocument.SetParserOptions(parserOptions);
codeDocument.SetCodeGenerationOptions(codeGenerationOptions);
return codeDocument;
}
public abstract IReadOnlyList<RazorSourceDocument> Imports { get; }
public abstract ItemCollection Items { get; }

View File

@ -109,6 +109,46 @@ namespace Microsoft.AspNetCore.Razor.Language
document.Items[typeof(RazorCSharpDocument)] = csharp;
}
public static RazorParserOptions GetParserOptions(this RazorCodeDocument document)
{
if (document == null)
{
throw new ArgumentNullException(nameof(document));
}
return (RazorParserOptions)document.Items[typeof(RazorParserOptions)];
}
public static void SetParserOptions(this RazorCodeDocument document, RazorParserOptions parserOptions)
{
if (document == null)
{
throw new ArgumentNullException(nameof(document));
}
document.Items[typeof(RazorParserOptions)] = parserOptions;
}
public static RazorCodeGenerationOptions GetCodeGenerationOptions(this RazorCodeDocument document)
{
if (document == null)
{
throw new ArgumentNullException(nameof(document));
}
return (RazorCodeGenerationOptions)document.Items[typeof(RazorCodeGenerationOptions)];
}
public static void SetCodeGenerationOptions(this RazorCodeDocument document, RazorCodeGenerationOptions codeGenerationOptions)
{
if (document == null)
{
throw new ArgumentNullException(nameof(document));
}
document.Items[typeof(RazorCodeGenerationOptions)] = codeGenerationOptions;
}
private class ImportSyntaxTreesHolder
{
public ImportSyntaxTreesHolder(IReadOnlyList<RazorSyntaxTree> syntaxTrees)

View File

@ -5,6 +5,8 @@ namespace Microsoft.AspNetCore.Razor.Language
{
public abstract class RazorCodeGenerationOptionsBuilder
{
public virtual RazorConfiguration Configuration => null;
public abstract bool DesignTime { get; }
public abstract int IndentSize { get; set; }
@ -41,5 +43,9 @@ namespace Microsoft.AspNetCore.Razor.Language
public virtual bool SuppressMetadataAttributes { get; set; }
public abstract RazorCodeGenerationOptions Build();
public virtual void SetDesignTime(bool designTime)
{
}
}
}

View File

@ -12,22 +12,12 @@ namespace Microsoft.AspNetCore.Razor.Language
public static readonly RazorConfiguration Default = new RazorConfiguration(
RazorLanguageVersion.Latest,
"unnamed",
Array.Empty<RazorExtension>(),
designTime: false);
// This is used only in some back-compat scenarios. We don't expose it because there's no
// use case for anyone else to use it.
internal static readonly RazorConfiguration DefaultDesignTime = new RazorConfiguration(
RazorLanguageVersion.Latest,
"unnamed",
Array.Empty<RazorExtension>(),
designTime: true);
Array.Empty<RazorExtension>());
public RazorConfiguration(
RazorLanguageVersion languageVersion,
string configurationName,
IEnumerable<RazorExtension> extensions,
bool designTime)
IEnumerable<RazorExtension> extensions)
{
if (languageVersion == null)
{
@ -47,7 +37,6 @@ namespace Microsoft.AspNetCore.Razor.Language
LanguageVersion = languageVersion;
ConfigurationName = configurationName;
Extensions = extensions.ToArray();
DesignTime = designTime;
}
public string ConfigurationName { get; }
@ -55,7 +44,5 @@ namespace Microsoft.AspNetCore.Razor.Language
public IReadOnlyList<RazorExtension> Extensions { get; }
public RazorLanguageVersion LanguageVersion { get; }
public bool DesignTime { get; }
}
}

View File

@ -17,27 +17,27 @@ namespace Microsoft.AspNetCore.Razor.Language
return Create(configure: null);
}
public static RazorEngine Create(Action<IRazorEngineBuilder> configure) => CreateCore(RazorConfiguration.Default, configure);
public static RazorEngine Create(Action<IRazorEngineBuilder> configure) => CreateCore(RazorConfiguration.Default, false, configure);
public static RazorEngine CreateDesignTime()
{
return CreateDesignTime(configure: null);
}
public static RazorEngine CreateDesignTime(Action<IRazorEngineBuilder> configure) => CreateCore(RazorConfiguration.DefaultDesignTime, configure);
public static RazorEngine CreateDesignTime(Action<IRazorEngineBuilder> configure) => CreateCore(RazorConfiguration.Default, true, configure);
// Internal since RazorEngine APIs are going to be obsolete.
internal static RazorEngine CreateCore(RazorConfiguration configuration, Action<IRazorEngineBuilder> configure)
internal static RazorEngine CreateCore(RazorConfiguration configuration, bool designTime, Action<IRazorEngineBuilder> configure)
{
if (configuration == null)
{
throw new ArgumentNullException(nameof(configuration));
}
var builder = new DefaultRazorEngineBuilder(configuration.DesignTime);
var builder = new DefaultRazorEngineBuilder(designTime);
AddDefaults(builder);
if (configuration.DesignTime)
if (designTime)
{
AddDefaultDesignTimeFeatures(configuration, builder.Features);
}
@ -152,7 +152,7 @@ namespace Microsoft.AspNetCore.Razor.Language
var targetExtension = features.OfType<IRazorTargetExtensionFeature>().FirstOrDefault();
Debug.Assert(targetExtension != null);
targetExtension.TargetExtensions.Add(new DefaultTagHelperTargetExtension() { DesignTime = false });
targetExtension.TargetExtensions.Add(new DefaultTagHelperTargetExtension());
targetExtension.TargetExtensions.Add(new PreallocatedAttributeTargetExtension());
}
@ -170,7 +170,7 @@ namespace Microsoft.AspNetCore.Razor.Language
var targetExtension = features.OfType<IRazorTargetExtensionFeature>().FirstOrDefault();
Debug.Assert(targetExtension != null);
targetExtension.TargetExtensions.Add(new DefaultTagHelperTargetExtension() { DesignTime = true });
targetExtension.TargetExtensions.Add(new DefaultTagHelperTargetExtension());
targetExtension.TargetExtensions.Add(new DesignTimeDirectiveTargetExtension());
}

View File

@ -1,21 +1,26 @@
// 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.Language
{
public abstract class RazorParserOptionsBuilder
{
public virtual RazorConfiguration Configuration => null;
public abstract bool DesignTime { get; }
public abstract ICollection<DirectiveDescriptor> Directives { get; }
public abstract bool ParseLeadingDirectives { get; set; }
public virtual RazorLanguageVersion Version { get; }
public virtual RazorLanguageVersion LanguageVersion { get; }
public abstract RazorParserOptions Build();
public virtual void SetDesignTime(bool designTime)
{
}
}
}

View File

@ -3,26 +3,63 @@
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Razor.Language.Extensions;
namespace Microsoft.AspNetCore.Razor.Language
{
public abstract class RazorProjectEngine
{
public abstract RazorConfiguration Configuration { get; }
public abstract RazorProjectFileSystem FileSystem { get; }
public abstract RazorEngine Engine { get; }
public abstract IReadOnlyList<IRazorProjectEngineFeature> Features { get; }
public IReadOnlyList<IRazorEngineFeature> EngineFeatures => Engine.Features;
public abstract RazorCodeDocument Process(RazorProjectItem projectItem);
public IReadOnlyList<IRazorEnginePhase> Phases => Engine.Phases;
public static RazorProjectEngine Create(RazorProjectFileSystem fileSystem) => Create(fileSystem, configure: null);
public abstract IReadOnlyList<IRazorProjectEngineFeature> ProjectFeatures { get; }
public static RazorProjectEngine Create(RazorProjectFileSystem fileSystem, Action<RazorProjectEngineBuilder> configure) => Create(fileSystem, RazorConfiguration.Default, configure);
protected abstract void ConfigureParserOptions(RazorParserOptionsBuilder builder);
protected abstract void ConfigureDesignTimeParserOptions(RazorParserOptionsBuilder builder);
protected abstract void ConfigureCodeGenerationOptions(RazorCodeGenerationOptionsBuilder builder);
protected abstract void ConfigureDesignTimeCodeGenerationOptions(RazorCodeGenerationOptionsBuilder builder);
public virtual RazorCodeDocument Process(RazorProjectItem projectItem)
{
if (projectItem == null)
{
throw new ArgumentNullException(nameof(projectItem));
}
return ProcessCore(projectItem, ConfigureParserOptions, ConfigureCodeGenerationOptions);
}
public virtual RazorCodeDocument ProcessDesignTime(RazorProjectItem projectItem)
{
if (projectItem == null)
{
throw new ArgumentNullException(nameof(projectItem));
}
return ProcessCore(projectItem, ConfigureDesignTimeParserOptions, ConfigureDesignTimeCodeGenerationOptions);
}
protected abstract RazorCodeDocument ProcessCore(
RazorProjectItem projectItem,
Action<RazorParserOptionsBuilder> configureParser,
Action<RazorCodeGenerationOptionsBuilder> configureCodeGeneration);
public static RazorProjectEngine Create(RazorConfiguration configuration, RazorProjectFileSystem fileSystem) => Create(configuration, fileSystem, configure: null);
public static RazorProjectEngine Create(
RazorProjectFileSystem fileSystem,
RazorConfiguration configuration,
RazorProjectFileSystem fileSystem,
Action<RazorProjectEngineBuilder> configure)
{
if (fileSystem == null)
@ -37,54 +74,90 @@ namespace Microsoft.AspNetCore.Razor.Language
var builder = new DefaultRazorProjectEngineBuilder(configuration, fileSystem);
AddDefaults(builder);
if (configuration.DesignTime)
{
AddDesignTimeDefaults(builder);
}
else
{
AddRuntimeDefaults(builder);
}
RazorEngine.AddDefaultPhases(builder.Phases);
AddDefaultsFeatures(builder.Features);
configure?.Invoke(builder);
return builder.Build();
}
private static void AddDefaults(RazorProjectEngineBuilder builder)
private static void AddDefaultsFeatures(ICollection<IRazorFeature> features)
{
builder.Features.Add(new DefaultRazorImportFeature());
}
features.Add(new DefaultImportProjectFeature());
private static void AddDesignTimeDefaults(RazorProjectEngineBuilder builder)
{
var engineFeatures = new List<IRazorEngineFeature>();
RazorEngine.AddDefaultFeatures(engineFeatures);
RazorEngine.AddDefaultDesignTimeFeatures(builder.Configuration, engineFeatures);
// General extensibility
features.Add(new DefaultRazorDirectiveFeature());
features.Add(new DefaultMetadataIdentifierFeature());
AddEngineFeaturesAndPhases(builder, engineFeatures);
}
// Options features
features.Add(new DefaultRazorParserOptionsFactoryProjectFeature());
features.Add(new DefaultRazorCodeGenerationOptionsFactoryProjectFeature());
private static void AddRuntimeDefaults(RazorProjectEngineBuilder builder)
{
var engineFeatures = new List<IRazorEngineFeature>();
RazorEngine.AddDefaultFeatures(engineFeatures);
RazorEngine.AddDefaultRuntimeFeatures(builder.Configuration, engineFeatures);
// Legacy options features
//
// These features are obsolete as of 2.1. Our code will resolve this but not invoke them.
features.Add(new DefaultRazorParserOptionsFeature(designTime: false, version: RazorLanguageVersion.Version_2_0));
features.Add(new DefaultRazorCodeGenerationOptionsFeature(designTime: false));
AddEngineFeaturesAndPhases(builder, engineFeatures);
}
// Syntax Tree passes
features.Add(new DefaultDirectiveSyntaxTreePass());
features.Add(new HtmlNodeOptimizationPass());
features.Add(new PreallocatedTagHelperAttributeOptimizationPass());
private static void AddEngineFeaturesAndPhases(RazorProjectEngineBuilder builder, IReadOnlyList<IRazorEngineFeature> engineFeatures)
{
for (var i = 0; i < engineFeatures.Count; i++)
// Intermediate Node Passes
features.Add(new DefaultDocumentClassifierPass());
features.Add(new MetadataAttributePass());
features.Add(new DesignTimeDirectivePass());
features.Add(new DirectiveRemovalOptimizationPass());
features.Add(new DefaultTagHelperOptimizationPass());
// Default Code Target Extensions
var targetExtensionFeature = new DefaultRazorTargetExtensionFeature();
features.Add(targetExtensionFeature);
targetExtensionFeature.TargetExtensions.Add(new MetadataAttributeTargetExtension());
targetExtensionFeature.TargetExtensions.Add(new DefaultTagHelperTargetExtension());
targetExtensionFeature.TargetExtensions.Add(new PreallocatedAttributeTargetExtension());
targetExtensionFeature.TargetExtensions.Add(new DesignTimeDirectiveTargetExtension());
// Default configuration
var configurationFeature = new DefaultDocumentClassifierPassFeature();
features.Add(configurationFeature);
configurationFeature.ConfigureClass.Add((document, @class) =>
{
var engineFeature = engineFeatures[i];
builder.Features.Add(engineFeature);
}
@class.ClassName = "Template";
@class.Modifiers.Add("public");
});
RazorEngine.AddDefaultPhases(builder.Phases);
configurationFeature.ConfigureNamespace.Add((document, @namespace) =>
{
@namespace.Content = "Razor";
});
configurationFeature.ConfigureMethod.Add((document, method) =>
{
method.MethodName = "ExecuteAsync";
method.ReturnType = $"global::{typeof(Task).FullName}";
method.Modifiers.Add("public");
method.Modifiers.Add("async");
method.Modifiers.Add("override");
});
}
internal static void AddDefaultRuntimeFeatures(RazorConfiguration configuration, ICollection<IRazorEngineFeature> features)
{
// Configure options
features.Add(new DefaultRazorParserOptionsFeature(designTime: false, version: configuration.LanguageVersion));
features.Add(new DefaultRazorCodeGenerationOptionsFeature(designTime: false));
}
internal static void AddDefaultDesignTimeFeatures(RazorConfiguration configuration, ICollection<IRazorEngineFeature> features)
{
// Configure options
features.Add(new DefaultRazorParserOptionsFeature(designTime: true, version: configuration.LanguageVersion));
features.Add(new DefaultRazorCodeGenerationOptionsFeature(designTime: true));
features.Add(new SuppressChecksumOptionsFeature());
}
}
}

View File

@ -7,14 +7,14 @@ namespace Microsoft.AspNetCore.Razor.Language
{
public abstract class RazorProjectEngineBuilder
{
public abstract RazorConfiguration Configuration { get; }
public abstract RazorProjectFileSystem FileSystem { get; }
public abstract ICollection<IRazorFeature> Features { get; }
public abstract IList<IRazorEnginePhase> Phases { get; }
public abstract RazorConfiguration Configuration { get; }
public abstract RazorProjectEngine Build();
}
}

View File

@ -9,7 +9,7 @@ namespace Microsoft.AspNetCore.Razor.Language
{
public static class RazorProjectEngineBuilderExtensions
{
public static void SetImportFeature(this RazorProjectEngineBuilder builder, IRazorImportFeature feature)
public static void SetImportFeature(this RazorProjectEngineBuilder builder, IImportProjectFeature feature)
{
if (builder == null)
{
@ -22,7 +22,7 @@ namespace Microsoft.AspNetCore.Razor.Language
}
// Remove any existing import features in favor of the new one we're given.
var existingFeatures = builder.Features.OfType<IRazorImportFeature>().ToArray();
var existingFeatures = builder.Features.OfType<IImportProjectFeature>().ToArray();
foreach (var existingFeature in existingFeatures)
{
builder.Features.Remove(existingFeature);

View File

@ -43,12 +43,12 @@ namespace Microsoft.VisualStudio.Editor.Razor
var project = FindProject(projectPath);
var configuration = (project?.Configuration as MvcExtensibilityConfiguration) ?? DefaultConfiguration;
var razorLanguageVersion = configuration.LanguageVersion;
var razorConfiguration = new RazorConfiguration(razorLanguageVersion, "unnamed", Array.Empty<RazorExtension>(), designTime: true);
var razorConfiguration = new RazorConfiguration(razorLanguageVersion, "unnamed", Array.Empty<RazorExtension>());
RazorEngine engine;
if (razorLanguageVersion.Major == 1)
{
engine = RazorEngine.CreateCore(razorConfiguration, b =>
engine = RazorEngine.CreateCore(razorConfiguration, true, b =>
{
configure?.Invoke(b);
@ -66,7 +66,7 @@ namespace Microsoft.VisualStudio.Editor.Razor
}
else
{
engine = RazorEngine.CreateCore(razorConfiguration, b =>
engine = RazorEngine.CreateCore(razorConfiguration, true, b =>
{
configure?.Invoke(b);

View File

@ -13,7 +13,11 @@ namespace Microsoft.AspNetCore.Mvc.Razor.Extensions
public void Execute_NoOps_IfNamespaceNodeIsMissing()
{
// Arrange
var irDocument = new DocumentIntermediateNode();
var irDocument = new DocumentIntermediateNode()
{
Options = RazorCodeGenerationOptions.CreateDefault(),
};
var pass = new AssemblyAttributeInjectionPass
{
Engine = RazorEngine.Create(),
@ -30,7 +34,10 @@ namespace Microsoft.AspNetCore.Mvc.Razor.Extensions
public void Execute_NoOps_IfNamespaceNodeHasEmptyContent()
{
// Arrange
var irDocument = new DocumentIntermediateNode();
var irDocument = new DocumentIntermediateNode()
{
Options = RazorCodeGenerationOptions.CreateDefault(),
};
var builder = IntermediateNodeBuilder.Create(irDocument);
var @namespace = new NamespaceDeclarationIntermediateNode() { Content = string.Empty };
@namespace.Annotations[CommonAnnotations.PrimaryNamespace] = CommonAnnotations.PrimaryNamespace;
@ -53,7 +60,11 @@ namespace Microsoft.AspNetCore.Mvc.Razor.Extensions
public void Execute_NoOps_IfClassNameNodeIsMissing()
{
// Arrange
var irDocument = new DocumentIntermediateNode();
var irDocument = new DocumentIntermediateNode()
{
Options = RazorCodeGenerationOptions.CreateDefault(),
};
var builder = IntermediateNodeBuilder.Create(irDocument);
var @namespace = new NamespaceDeclarationIntermediateNode() { Content = "SomeNamespace" };
builder.Push(@namespace);
@ -67,7 +78,8 @@ namespace Microsoft.AspNetCore.Mvc.Razor.Extensions
pass.Execute(TestRazorCodeDocument.CreateEmpty(), irDocument);
// Assert
Assert.Collection(irDocument.Children,
Assert.Collection(
irDocument.Children,
node => Assert.Same(@namespace, node));
}
@ -75,7 +87,10 @@ namespace Microsoft.AspNetCore.Mvc.Razor.Extensions
public void Execute_NoOps_IfClassNameIsEmpty()
{
// Arrange
var irDocument = new DocumentIntermediateNode();
var irDocument = new DocumentIntermediateNode()
{
Options = RazorCodeGenerationOptions.CreateDefault(),
};
var builder = IntermediateNodeBuilder.Create(irDocument);
var @namespace = new NamespaceDeclarationIntermediateNode
{
@ -115,6 +130,7 @@ namespace Microsoft.AspNetCore.Mvc.Razor.Extensions
var irDocument = new DocumentIntermediateNode
{
DocumentKind = "Default",
Options = RazorCodeGenerationOptions.CreateDefault(),
};
var builder = IntermediateNodeBuilder.Create(irDocument);
var @namespace = new NamespaceDeclarationIntermediateNode() { Content = "SomeNamespace" };
@ -138,7 +154,54 @@ namespace Microsoft.AspNetCore.Mvc.Razor.Extensions
pass.Execute(TestRazorCodeDocument.CreateEmpty(), irDocument);
// Assert
Assert.Collection(irDocument.Children,
Assert.Collection(
irDocument.Children,
node => Assert.Same(@namespace, node));
}
[Fact]
public void Execute_NoOps_ForDesignTime()
{
// Arrange
var irDocument = new DocumentIntermediateNode
{
DocumentKind = MvcViewDocumentClassifierPass.MvcViewDocumentKind,
Options = RazorCodeGenerationOptions.CreateDesignTimeDefault(),
};
var builder = IntermediateNodeBuilder.Create(irDocument);
var @namespace = new NamespaceDeclarationIntermediateNode
{
Content = "SomeNamespace",
Annotations =
{
[CommonAnnotations.PrimaryNamespace] = CommonAnnotations.PrimaryNamespace
},
};
builder.Push(@namespace);
var @class = new ClassDeclarationIntermediateNode
{
ClassName = "SomeName",
Annotations =
{
[CommonAnnotations.PrimaryClass] = CommonAnnotations.PrimaryClass,
},
};
builder.Add(@class);
var pass = new AssemblyAttributeInjectionPass
{
Engine = RazorEngine.Create(),
};
var source = TestRazorSourceDocument.Create("test", new RazorSourceDocumentProperties(filePath: null, relativePath: "/Views/Index.cshtml"));
var document = RazorCodeDocument.Create(source);
// Act
pass.Execute(document, irDocument);
// Assert
Assert.Collection(
irDocument.Children,
node => Assert.Same(@namespace, node));
}
@ -150,6 +213,7 @@ namespace Microsoft.AspNetCore.Mvc.Razor.Extensions
var irDocument = new DocumentIntermediateNode
{
DocumentKind = MvcViewDocumentClassifierPass.MvcViewDocumentKind,
Options = RazorCodeGenerationOptions.CreateDefault(),
};
var builder = IntermediateNodeBuilder.Create(irDocument);
var @namespace = new NamespaceDeclarationIntermediateNode
@ -202,6 +266,7 @@ namespace Microsoft.AspNetCore.Mvc.Razor.Extensions
var irDocument = new DocumentIntermediateNode
{
DocumentKind = MvcViewDocumentClassifierPass.MvcViewDocumentKind,
Options = RazorCodeGenerationOptions.CreateDefault(),
};
var builder = IntermediateNodeBuilder.Create(irDocument);
var @namespace = new NamespaceDeclarationIntermediateNode
@ -254,6 +319,7 @@ namespace Microsoft.AspNetCore.Mvc.Razor.Extensions
var irDocument = new DocumentIntermediateNode
{
DocumentKind = RazorPageDocumentClassifierPass.RazorPageDocumentKind,
Options = RazorCodeGenerationOptions.CreateDefault(),
};
var builder = IntermediateNodeBuilder.Create(irDocument);
var pageDirective = new DirectiveIntermediateNode
@ -313,6 +379,7 @@ namespace Microsoft.AspNetCore.Mvc.Razor.Extensions
var irDocument = new DocumentIntermediateNode
{
DocumentKind = MvcViewDocumentClassifierPass.MvcViewDocumentKind,
Options = RazorCodeGenerationOptions.CreateDefault(),
};
var builder = IntermediateNodeBuilder.Create(irDocument);
var @namespace = new NamespaceDeclarationIntermediateNode

View File

@ -17,7 +17,7 @@ namespace Microsoft.AspNetCore.Mvc.Razor.Extensions
var imports = new List<RazorSourceDocument>();
// Act
DefaultMvcImportFeature.AddDefaultDirectivesImport(imports);
MvcImportProjectFeature.AddDefaultDirectivesImport(imports);
// Assert
var import = Assert.Single(imports);
@ -37,7 +37,7 @@ namespace Microsoft.AspNetCore.Mvc.Razor.Extensions
new TestRazorProjectItem("/Contact/_ViewImports.cshtml"),
projectItem,
});
var mvcImportFeature = new DefaultMvcImportFeature()
var mvcImportFeature = new MvcImportProjectFeature()
{
ProjectEngine = Mock.Of<RazorProjectEngine>(projectEngine => projectEngine.FileSystem == testFileSystem)
};
@ -58,7 +58,7 @@ namespace Microsoft.AspNetCore.Mvc.Razor.Extensions
var imports = new List<RazorSourceDocument>();
var projectItem = new TestRazorProjectItem("/Pages/Contact/Index.cshtml");
var testFileSystem = new TestRazorProjectFileSystem(new[] { projectItem });
var mvcImportFeature = new DefaultMvcImportFeature()
var mvcImportFeature = new MvcImportProjectFeature()
{
ProjectEngine = Mock.Of<RazorProjectEngine>(projectEngine => projectEngine.FileSystem == testFileSystem)
};

View File

@ -10,11 +10,47 @@ namespace Microsoft.AspNetCore.Mvc.Razor.Extensions
{
public class InstrumentationPassTest
{
[Fact]
public void InstrumentationPass_NoOps_ForDesignTime()
{
// Arrange
var document = new DocumentIntermediateNode()
{
Options = RazorCodeGenerationOptions.CreateDesignTimeDefault(),
};
var builder = IntermediateNodeBuilder.Create(document);
builder.Push(new HtmlContentIntermediateNode());
builder.Add(new IntermediateToken()
{
Content = "Hi",
Kind = TokenKind.Html,
});
builder.Pop();
var pass = new InstrumentationPass()
{
Engine = RazorEngine.CreateEmpty(b => { }),
};
// Act
pass.Execute(TestRazorCodeDocument.CreateEmpty(), document);
// Assert
Children(
document,
n => IntermediateNodeAssert.Html("Hi", n));
}
[Fact]
public void InstrumentationPass_InstrumentsHtml()
{
// Arrange
var document = new DocumentIntermediateNode();
var document = new DocumentIntermediateNode()
{
Options = RazorCodeGenerationOptions.CreateDefault(),
};
var builder = IntermediateNodeBuilder.Create(document);
builder.Push(new HtmlContentIntermediateNode()
@ -49,7 +85,11 @@ namespace Microsoft.AspNetCore.Mvc.Razor.Extensions
public void InstrumentationPass_SkipsHtml_WithoutLocation()
{
// Arrange
var document = new DocumentIntermediateNode();
var document = new DocumentIntermediateNode()
{
Options = RazorCodeGenerationOptions.CreateDefault(),
};
var builder = IntermediateNodeBuilder.Create(document);
builder.Push(new HtmlContentIntermediateNode());
builder.Add(new IntermediateToken()
@ -77,7 +117,11 @@ namespace Microsoft.AspNetCore.Mvc.Razor.Extensions
public void InstrumentationPass_InstrumentsCSharpExpression()
{
// Arrange
var document = new DocumentIntermediateNode();
var document = new DocumentIntermediateNode()
{
Options = RazorCodeGenerationOptions.CreateDefault(),
};
var builder = IntermediateNodeBuilder.Create(document);
builder.Push(new CSharpExpressionIntermediateNode()
{
@ -109,7 +153,11 @@ namespace Microsoft.AspNetCore.Mvc.Razor.Extensions
public void InstrumentationPass_SkipsCSharpExpression_WithoutLocation()
{
// Arrange
var document = new DocumentIntermediateNode();
var document = new DocumentIntermediateNode()
{
Options = RazorCodeGenerationOptions.CreateDefault(),
};
var builder = IntermediateNodeBuilder.Create(document);
builder.Push(new CSharpExpressionIntermediateNode());
builder.Add(new IntermediateToken()
@ -136,7 +184,11 @@ namespace Microsoft.AspNetCore.Mvc.Razor.Extensions
public void InstrumentationPass_SkipsCSharpExpression_InsideTagHelperAttribute()
{
// Arrange
var document = new DocumentIntermediateNode();
var document = new DocumentIntermediateNode()
{
Options = RazorCodeGenerationOptions.CreateDefault(),
};
var builder = IntermediateNodeBuilder.Create(document);
builder.Push(new TagHelperIntermediateNode());
@ -183,7 +235,11 @@ namespace Microsoft.AspNetCore.Mvc.Razor.Extensions
public void InstrumentationPass_SkipsCSharpExpression_InsideTagHelperProperty()
{
// Arrange
var document = new DocumentIntermediateNode();
var document = new DocumentIntermediateNode()
{
Options = RazorCodeGenerationOptions.CreateDefault(),
};
var builder = IntermediateNodeBuilder.Create(document);
builder.Push(new TagHelperIntermediateNode());
@ -230,7 +286,11 @@ namespace Microsoft.AspNetCore.Mvc.Razor.Extensions
public void InstrumentationPass_InstrumentsTagHelper()
{
// Arrange
var document = new DocumentIntermediateNode();
var document = new DocumentIntermediateNode()
{
Options = RazorCodeGenerationOptions.CreateDefault(),
};
var builder = IntermediateNodeBuilder.Create(document);
builder.Add(new TagHelperIntermediateNode()
{
@ -257,7 +317,11 @@ namespace Microsoft.AspNetCore.Mvc.Razor.Extensions
public void InstrumentationPass_SkipsTagHelper_WithoutLocation()
{
// Arrange
var document = new DocumentIntermediateNode();
var document = new DocumentIntermediateNode()
{
Options = RazorCodeGenerationOptions.CreateDefault(),
};
var builder = IntermediateNodeBuilder.Create(document);
builder.Push(new TagHelperIntermediateNode());

View File

@ -61,7 +61,7 @@ namespace Microsoft.AspNetCore.Mvc.Razor.Extensions
");
var engine = CreateEngine();
var pass = new ModelDirective.Pass(designTime: false)
var pass = new ModelDirective.Pass()
{
Engine = engine,
};
@ -88,7 +88,7 @@ namespace Microsoft.AspNetCore.Mvc.Razor.Extensions
");
var engine = CreateEngine();
var pass = new ModelDirective.Pass(designTime: false)
var pass = new ModelDirective.Pass()
{
Engine = engine,
};
@ -114,7 +114,7 @@ namespace Microsoft.AspNetCore.Mvc.Razor.Extensions
");
var engine = CreateEngine();
var pass = new ModelDirective.Pass(designTime: false)
var pass = new ModelDirective.Pass()
{
Engine = engine,
};
@ -139,7 +139,7 @@ namespace Microsoft.AspNetCore.Mvc.Razor.Extensions
");
var engine = CreateEngine();
var pass = new ModelDirective.Pass(designTime: false)
var pass = new ModelDirective.Pass()
{
Engine = engine,
};
@ -163,8 +163,8 @@ namespace Microsoft.AspNetCore.Mvc.Razor.Extensions
@inherits BaseType<TModel>
");
var engine = CreateEngine();
var pass = new ModelDirective.Pass(designTime: true)
var engine = CreateDesignTimeEngine();
var pass = new ModelDirective.Pass()
{
Engine = engine,
};
@ -193,8 +193,8 @@ namespace Microsoft.AspNetCore.Mvc.Razor.Extensions
@model SomeType
");
var engine = CreateEngine();
var pass = new ModelDirective.Pass(designTime: true)
var engine = CreateDesignTimeEngine();
var pass = new ModelDirective.Pass()
{
Engine = engine,
};
@ -246,6 +246,18 @@ namespace Microsoft.AspNetCore.Mvc.Razor.Extensions
});
}
private RazorEngine CreateDesignTimeEngine()
{
return RazorEngine.CreateDesignTime(b =>
{
// Notice we're not registering the ModelDirective.Pass here so we can run it on demand.
b.AddDirective(ModelDirective.Directive);
// There's some special interaction with the inherits directive
InheritsDirective.Register(b);
});
}
private DocumentIntermediateNode CreateIRDocument(RazorEngine engine, RazorCodeDocument codeDocument)
{
for (var i = 0; i < engine.Phases.Count; i++)

View File

@ -17,7 +17,7 @@ namespace Microsoft.AspNetCore.Mvc.Razor.Extensions.Version1_X
var imports = new List<RazorSourceDocument>();
// Act
DefaultMvcImportFeature.AddDefaultDirectivesImport(imports);
MvcImportProjectFeature.AddDefaultDirectivesImport(imports);
// Assert
var import = Assert.Single(imports);
@ -37,7 +37,7 @@ namespace Microsoft.AspNetCore.Mvc.Razor.Extensions.Version1_X
new TestRazorProjectItem("/Contact/_ViewImports.cshtml"),
projectItem,
});
var mvcImportFeature = new DefaultMvcImportFeature()
var mvcImportFeature = new MvcImportProjectFeature()
{
ProjectEngine = Mock.Of<RazorProjectEngine>(projectEngine => projectEngine.FileSystem == testFileSystem)
};
@ -58,7 +58,7 @@ namespace Microsoft.AspNetCore.Mvc.Razor.Extensions.Version1_X
var imports = new List<RazorSourceDocument>();
var projectItem = new TestRazorProjectItem("/Pages/Contact/Index.cshtml");
var testFileSystem = new TestRazorProjectFileSystem(new[] { projectItem });
var mvcImportFeature = new DefaultMvcImportFeature()
var mvcImportFeature = new MvcImportProjectFeature()
{
ProjectEngine = Mock.Of<RazorProjectEngine>(projectEngine => projectEngine.FileSystem == testFileSystem)
};

View File

@ -61,7 +61,7 @@ namespace Microsoft.AspNetCore.Mvc.Razor.Extensions.Version1_X
");
var engine = CreateEngine();
var pass = new ModelDirective.Pass(designTime: false)
var pass = new ModelDirective.Pass()
{
Engine = engine,
};
@ -88,7 +88,7 @@ namespace Microsoft.AspNetCore.Mvc.Razor.Extensions.Version1_X
");
var engine = CreateEngine();
var pass = new ModelDirective.Pass(designTime: false)
var pass = new ModelDirective.Pass()
{
Engine = engine,
};
@ -114,7 +114,7 @@ namespace Microsoft.AspNetCore.Mvc.Razor.Extensions.Version1_X
");
var engine = CreateEngine();
var pass = new ModelDirective.Pass(designTime: false)
var pass = new ModelDirective.Pass()
{
Engine = engine,
};
@ -139,7 +139,7 @@ namespace Microsoft.AspNetCore.Mvc.Razor.Extensions.Version1_X
");
var engine = CreateEngine();
var pass = new ModelDirective.Pass(designTime: false)
var pass = new ModelDirective.Pass()
{
Engine = engine,
};
@ -163,8 +163,8 @@ namespace Microsoft.AspNetCore.Mvc.Razor.Extensions.Version1_X
@inherits BaseType<TModel>
");
var engine = CreateEngine();
var pass = new ModelDirective.Pass(designTime: true)
var engine = CreateDesignTimeEngine();
var pass = new ModelDirective.Pass()
{
Engine = engine,
};
@ -193,8 +193,8 @@ namespace Microsoft.AspNetCore.Mvc.Razor.Extensions.Version1_X
@model SomeType
");
var engine = CreateEngine();
var pass = new ModelDirective.Pass(designTime: true)
var engine = CreateDesignTimeEngine();
var pass = new ModelDirective.Pass()
{
Engine = engine,
};
@ -246,6 +246,18 @@ namespace Microsoft.AspNetCore.Mvc.Razor.Extensions.Version1_X
});
}
private RazorEngine CreateDesignTimeEngine()
{
return RazorEngine.CreateDesignTime(b =>
{
// Notice we're not registering the ModelDirective.Pass here so we can run it on demand.
b.AddDirective(ModelDirective.Directive);
// There's some special interaction with the inherits directive
InheritsDirective.Register(b);
});
}
private DocumentIntermediateNode CreateIRDocument(RazorEngine engine, RazorCodeDocument codeDocument)
{
for (var i = 0; i < engine.Phases.Count; i++)

View File

@ -8,16 +8,61 @@ namespace Microsoft.AspNetCore.Razor.Language
{
public class DefaultRazorProjectEngineIntegrationTest
{
[Fact]
public void Process_SetsOptions_Runtime()
{
// Arrange
var projectItem = new TestRazorProjectItem("Index.cshtml");
var projectEngine = RazorProjectEngine.Create(RazorConfiguration.Default, TestRazorProjectFileSystem.Empty);
// Act
var codeDocument = projectEngine.Process(projectItem);
// Assert
var parserOptions = codeDocument.GetParserOptions();
Assert.False(parserOptions.DesignTime);
var codeGenerationOptions = codeDocument.GetCodeGenerationOptions();
Assert.False(codeGenerationOptions.DesignTime);
Assert.False(codeGenerationOptions.SuppressChecksum);
Assert.False(codeGenerationOptions.SuppressMetadataAttributes);
}
[Fact]
public void ProcessDesignTime_SetsOptions_DesignTime()
{
// Arrange
var projectItem = new TestRazorProjectItem("Index.cshtml");
var projectEngine = RazorProjectEngine.Create(RazorConfiguration.Default, TestRazorProjectFileSystem.Empty);
// Act
var codeDocument = projectEngine.ProcessDesignTime(projectItem);
// Assert
var parserOptions = codeDocument.GetParserOptions();
Assert.True(parserOptions.DesignTime);
var codeGenerationOptions = codeDocument.GetCodeGenerationOptions();
Assert.True(codeGenerationOptions.DesignTime);
Assert.True(codeGenerationOptions.SuppressChecksum);
Assert.True(codeGenerationOptions.SuppressMetadataAttributes);
}
[Fact]
public void Process_GetsImportsFromFeature()
{
// Arrange
var projectItem = new TestRazorProjectItem("Index.cshtml");
var testImport = TestRazorSourceDocument.Create();
var importFeature = new Mock<IRazorImportFeature>();
importFeature.Setup(feature => feature.GetImports(It.IsAny<RazorProjectItem>()))
var importFeature = new Mock<IImportProjectFeature>();
importFeature
.Setup(feature => feature.GetImports(It.IsAny<RazorProjectItem>()))
.Returns(new[] { testImport });
var projectEngine = RazorProjectEngine.Create(TestRazorProjectFileSystem.Empty, builder =>
var projectEngine = RazorProjectEngine.Create(RazorConfiguration.Default, TestRazorProjectFileSystem.Empty, builder =>
{
builder.SetImportFeature(importFeature.Object);
});
@ -35,7 +80,7 @@ namespace Microsoft.AspNetCore.Razor.Language
{
// Arrange
var projectItem = new TestRazorProjectItem("Index.cshtml");
var projectEngine = RazorProjectEngine.Create(TestRazorProjectFileSystem.Empty);
var projectEngine = RazorProjectEngine.Create(RazorConfiguration.Default, TestRazorProjectFileSystem.Empty);
// Act
var codeDocument = projectEngine.Process(projectItem);

View File

@ -68,7 +68,7 @@ namespace Microsoft.AspNetCore.Razor.Language.Extensions
public void WriteTagHelperBody_DesignTime_WritesChildren()
{
// Arrange
var extension = new DefaultTagHelperTargetExtension() { DesignTime = true };
var extension = new DefaultTagHelperTargetExtension();
var context = TestCodeRenderingContext.CreateDesignTime();
var tagHelperNode = new TagHelperIntermediateNode();
@ -133,7 +133,7 @@ namespace Microsoft.AspNetCore.Razor.Language.Extensions
public void WriteTagHelperCreate_DesignTime_RendersCorrectly_UsesSpecifiedTagHelperType()
{
// Arrange
var extension = new DefaultTagHelperTargetExtension() { DesignTime = true };
var extension = new DefaultTagHelperTargetExtension();
var context = TestCodeRenderingContext.CreateDesignTime();
var tagHelperNode = new TagHelperIntermediateNode();
@ -190,7 +190,7 @@ __tagHelperExecutionContext.Add(__TestNamespace_MyTagHelper);
public void WriteTagHelperExecute_DesignTime_WritesNothing()
{
// Arrange
var extension = new DefaultTagHelperTargetExtension() { DesignTime = true };
var extension = new DefaultTagHelperTargetExtension();
var context = TestCodeRenderingContext.CreateDesignTime();
var tagHelperNode = new TagHelperIntermediateNode();
@ -243,7 +243,7 @@ __tagHelperExecutionContext = __tagHelperScopeManager.End();
public void WriteTagHelperHtmlAttribute_DesignTime_WritesNothing()
{
// Arrange
var extension = new DefaultTagHelperTargetExtension() { DesignTime = true };
var extension = new DefaultTagHelperTargetExtension();
var context = TestCodeRenderingContext.CreateDesignTime();
var tagHelperNode = new TagHelperIntermediateNode();
@ -431,7 +431,7 @@ EndAddHtmlAttributeValues(__tagHelperExecutionContext);
public void WriteTagHelperProperty_DesignTime_StringProperty_HtmlContent_RendersCorrectly()
{
// Arrange
var extension = new DefaultTagHelperTargetExtension() { DesignTime = true };
var extension = new DefaultTagHelperTargetExtension();
var context = TestCodeRenderingContext.CreateDesignTime();
var tagHelperNode = new TagHelperIntermediateNode();
@ -472,7 +472,7 @@ __InputTagHelper.StringProp = ""value"";
public void WriteTagHelperProperty_DesignTime_StringProperty_NonHtmlContent_RendersCorrectly()
{
// Arrange
var extension = new DefaultTagHelperTargetExtension() { DesignTime = true };
var extension = new DefaultTagHelperTargetExtension();
var context = TestCodeRenderingContext.CreateDesignTime();
var tagHelperNode = new TagHelperIntermediateNode();
@ -513,7 +513,7 @@ __InputTagHelper.StringProp = string.Empty;
public void WriteTagHelperProperty_DesignTime_NonStringProperty_RendersCorrectly()
{
// Arrange
var extension = new DefaultTagHelperTargetExtension() { DesignTime = true };
var extension = new DefaultTagHelperTargetExtension();
var context = TestCodeRenderingContext.CreateDesignTime();
var tagHelperNode = new TagHelperIntermediateNode();
@ -560,7 +560,7 @@ __InputTagHelper.IntProp = 32;
public void WriteTagHelperProperty_DesignTime_NonStringProperty_SecondUseOfAttribute()
{
// Arrange
var extension = new DefaultTagHelperTargetExtension() { DesignTime = true };
var extension = new DefaultTagHelperTargetExtension();
var context = TestCodeRenderingContext.CreateDesignTime();
var tagHelperNode = new TagHelperIntermediateNode();
@ -602,7 +602,7 @@ __InputTagHelper.IntProp = 32;
public void WriteTagHelperProperty_DesignTime_NonStringProperty_RendersCorrectly_WithoutLocation()
{
// Arrange
var extension = new DefaultTagHelperTargetExtension() { DesignTime = true };
var extension = new DefaultTagHelperTargetExtension();
var context = TestCodeRenderingContext.CreateDesignTime();
var tagHelperNode = new TagHelperIntermediateNode();
@ -642,7 +642,7 @@ __InputTagHelper.IntProp = 32;
public void WriteTagHelperProperty_DesignTime_NonStringIndexer_RendersCorrectly()
{
// Arrange
var extension = new DefaultTagHelperTargetExtension() { DesignTime = true };
var extension = new DefaultTagHelperTargetExtension();
var context = TestCodeRenderingContext.CreateDesignTime();
var tagHelperNode = new TagHelperIntermediateNode();
@ -687,7 +687,7 @@ __InputTagHelper.IntIndexer[""bound""] = 32;
public void WriteTagHelperProperty_DesignTime_NonStringIndexer_RendersCorrectly_WithoutLocation()
{
// Arrange
var extension = new DefaultTagHelperTargetExtension() { DesignTime = true };
var extension = new DefaultTagHelperTargetExtension();
var context = TestCodeRenderingContext.CreateDesignTime();
var tagHelperNode = new TagHelperIntermediateNode();
@ -1064,7 +1064,7 @@ __tagHelperExecutionContext.AddTagHelperAttribute(""foo-bound"", __InputTagHelpe
public void WriteTagHelperRuntime_DesignTime_WritesNothing()
{
// Arrange
var extension = new DefaultTagHelperTargetExtension() { DesignTime = true };
var extension = new DefaultTagHelperTargetExtension();
var context = TestCodeRenderingContext.CreateDesignTime();
var node = new DefaultTagHelperRuntimeIntermediateNode();

View File

@ -148,5 +148,67 @@ namespace Microsoft.AspNetCore.Razor.Language
// Assert
Assert.Same(expected, codeDocument.Items[typeof(TagHelperDocumentContext)]);
}
[Fact]
public void GetParserOptions_ReturnsSyntaxTree()
{
// Arrange
var codeDocument = TestRazorCodeDocument.CreateEmpty();
var expected = RazorParserOptions.CreateDefault();
codeDocument.Items[typeof(RazorParserOptions)] = expected;
// Act
var actual = codeDocument.GetParserOptions();
// Assert
Assert.Same(expected, actual);
}
[Fact]
public void SetParserOptions_SetsSyntaxTree()
{
// Arrange
var codeDocument = TestRazorCodeDocument.CreateEmpty();
var expected = RazorParserOptions.CreateDefault();
// Act
codeDocument.SetParserOptions(expected);
// Assert
Assert.Same(expected, codeDocument.Items[typeof(RazorParserOptions)]);
}
[Fact]
public void GetCodeGenerationOptions_ReturnsSyntaxTree()
{
// Arrange
var codeDocument = TestRazorCodeDocument.CreateEmpty();
var expected = RazorCodeGenerationOptions.CreateDefault();
codeDocument.Items[typeof(RazorCodeGenerationOptions)] = expected;
// Act
var actual = codeDocument.GetCodeGenerationOptions();
// Assert
Assert.Same(expected, actual);
}
[Fact]
public void SetCodeGenerationOptions_SetsSyntaxTree()
{
// Arrange
var codeDocument = TestRazorCodeDocument.CreateEmpty();
var expected = RazorCodeGenerationOptions.CreateDefault();
// Act
codeDocument.SetCodeGenerationOptions(expected);
// Assert
Assert.Same(expected, codeDocument.Items[typeof(RazorCodeGenerationOptions)]);
}
}
}

View File

@ -145,7 +145,7 @@ namespace Microsoft.AspNetCore.Razor.Language
Assert.Collection(
feature.TargetExtensions,
extension => Assert.IsType<MetadataAttributeTargetExtension>(extension),
extension => Assert.False(Assert.IsType<DefaultTagHelperTargetExtension>(extension).DesignTime),
extension => Assert.IsType<DefaultTagHelperTargetExtension>(extension),
extension => Assert.IsType<PreallocatedAttributeTargetExtension>(extension));
}
@ -190,7 +190,7 @@ namespace Microsoft.AspNetCore.Razor.Language
Assert.Collection(
feature.TargetExtensions,
extension => Assert.IsType<MetadataAttributeTargetExtension>(extension),
extension => Assert.True(Assert.IsType<DefaultTagHelperTargetExtension>(extension).DesignTime),
extension => Assert.IsType<DefaultTagHelperTargetExtension>(extension),
extension => Assert.IsType<DesignTimeDirectiveTargetExtension>(extension));
}

View File

@ -14,11 +14,11 @@ namespace Microsoft.AspNetCore.Razor.Language
{
// Arrange
var builder = new DefaultRazorProjectEngineBuilder(RazorConfiguration.Default, Mock.Of<RazorProjectFileSystem>());
var testFeature1 = Mock.Of<IRazorImportFeature>();
var testFeature2 = Mock.Of<IRazorImportFeature>();
var testFeature1 = Mock.Of<IImportProjectFeature>();
var testFeature2 = Mock.Of<IImportProjectFeature>();
builder.Features.Add(testFeature1);
builder.Features.Add(testFeature2);
var newFeature = Mock.Of<IRazorImportFeature>();
var newFeature = Mock.Of<IImportProjectFeature>();
// Act
builder.SetImportFeature(newFeature);

View File

@ -0,0 +1,85 @@
// 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.Collections.Generic;
using System.Linq;
using Microsoft.AspNetCore.Razor.Language.Extensions;
using Moq;
using Xunit;
namespace Microsoft.AspNetCore.Razor.Language.Test
{
public class RazorProjectEngineTest
{
[Fact]
public void CreateDesignTime_Lambda_AddsFeaturesAndPhases()
{
// Arrange
// Act
var engine = RazorProjectEngine.Create(RazorConfiguration.Default, Mock.Of<RazorProjectFileSystem>());
// Assert
AssertDefaultPhases(engine);
AssertDefaultFeatures(engine);
AssertDefaultDirectives(engine);
AssertDefaultTargetExtensions(engine);
}
private static void AssertDefaultPhases(RazorProjectEngine engine)
{
Assert.Collection(
engine.Phases,
phase => Assert.IsType<DefaultRazorParsingPhase>(phase),
phase => Assert.IsType<DefaultRazorSyntaxTreePhase>(phase),
phase => Assert.IsType<DefaultRazorTagHelperBinderPhase>(phase),
phase => Assert.IsType<DefaultRazorIntermediateNodeLoweringPhase>(phase),
phase => Assert.IsType<DefaultRazorDocumentClassifierPhase>(phase),
phase => Assert.IsType<DefaultRazorDirectiveClassifierPhase>(phase),
phase => Assert.IsType<DefaultRazorOptimizationPhase>(phase),
phase => Assert.IsType<DefaultRazorCSharpLoweringPhase>(phase));
}
private static void AssertDefaultFeatures(RazorProjectEngine engine)
{
var features = engine.EngineFeatures.OrderBy(f => f.GetType().Name).ToArray();
Assert.Collection(
features,
feature => Assert.IsType<DefaultDirectiveSyntaxTreePass>(feature),
feature => Assert.IsType<DefaultDocumentClassifierPass>(feature),
feature => Assert.IsType<DefaultDocumentClassifierPassFeature>(feature),
feature => Assert.IsType<DefaultMetadataIdentifierFeature>(feature),
feature => Assert.IsType<DefaultRazorCodeGenerationOptionsFeature>(feature),
feature => Assert.IsType<DefaultRazorDirectiveFeature>(feature),
feature => Assert.IsType<DefaultRazorParserOptionsFeature>(feature),
feature => Assert.IsType<DefaultRazorTargetExtensionFeature>(feature),
feature => Assert.IsType<DefaultTagHelperOptimizationPass>(feature),
feature => Assert.IsType<DesignTimeDirectivePass>(feature),
feature => Assert.IsType<DirectiveRemovalOptimizationPass>(feature),
feature => Assert.IsType<HtmlNodeOptimizationPass>(feature),
feature => Assert.IsType<MetadataAttributePass>(feature),
feature => Assert.IsType<PreallocatedTagHelperAttributeOptimizationPass>(feature));
}
private static void AssertDefaultDirectives(RazorProjectEngine engine)
{
var feature = engine.EngineFeatures.OfType<IRazorDirectiveFeature>().FirstOrDefault();
Assert.NotNull(feature);
Assert.Empty(feature.Directives);
}
private static void AssertDefaultTargetExtensions(RazorProjectEngine engine)
{
var feature = engine.EngineFeatures.OfType<IRazorTargetExtensionFeature>().FirstOrDefault();
Assert.NotNull(feature);
var extensions = feature.TargetExtensions.OrderBy(f => f.GetType().Name).ToArray();
Assert.Collection(
extensions,
extension => Assert.IsType<DefaultTagHelperTargetExtension>(extension),
extension => Assert.IsType<DesignTimeDirectiveTargetExtension>(extension),
extension => Assert.IsType<MetadataAttributeTargetExtension>(extension),
extension => Assert.IsType<PreallocatedAttributeTargetExtension>(extension));
}
}
}