Move to RazorProjectEngine.

- Instead of using Razor/Mvc TemplateEngine use `RazorProjectEngine`. This involved changing several locations (each of which used `RazorTemplateEngine` in an entirely different way) to use the RazorProjectEngine's two Process methods.
- Changed an unused public API `VisualStudioRazorParser.TemplateEngine` to `VisualStudioRazorParser.RazorProjectEngine`.
- Ported the remainder of `RazorEngineBuilder`'s extension methods over to `RazorProjectEngineBuilder`. These were used in tests and our `RazorGenerate` tool.
- Added a few test helper methods/classes to enable simple testing of the `RazorProjectEngine`.
- Resolved several test hacks that were working around little discrepancies each of the `RazorTemplateEngine` APIs.
- Changed the template engine factory service to be a project engine factory service.
This commit is contained in:
N. Taylor Mullen 2018-02-09 17:28:16 -08:00
parent 0c6ec09958
commit 133eff3119
28 changed files with 471 additions and 287 deletions

View File

@ -2,7 +2,6 @@
// 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.IO;
using BenchmarkDotNet.Attributes;
using Microsoft.AspNetCore.Mvc.Razor.Extensions;
@ -21,33 +20,22 @@ namespace Microsoft.AspNetCore.Razor.Performance
}
var root = current;
var engine = RazorEngine.Create(b => { RazorExtensions.Register(b); });
var fileSystem = RazorProjectFileSystem.Create(root.FullName);
ProjectEngine = RazorProjectEngine.Create(RazorConfiguration.Default, fileSystem, b => RazorExtensions.Register(b)); ;
DesignTimeTemplateEngine = new MvcRazorTemplateEngine(RazorEngine.CreateDesignTime(b => { RazorExtensions.Register(b); }), fileSystem);
RuntimeTemplateEngine = new MvcRazorTemplateEngine(RazorEngine.Create(b => { RazorExtensions.Register(b); }), fileSystem);
var codeDocument = RuntimeTemplateEngine.CreateCodeDocument(Path.Combine(root.FullName, "MSN.cshtml"));
Imports = codeDocument.Imports;
MSN = codeDocument.Source;
MSN = fileSystem.GetItem(Path.Combine(root.FullName, "MSN.cshtml"));
}
public RazorTemplateEngine DesignTimeTemplateEngine { get; }
public RazorProjectEngine ProjectEngine { get; }
public RazorTemplateEngine RuntimeTemplateEngine { get; }
public IReadOnlyList<RazorSourceDocument> Imports { get; }
public RazorSourceDocument MSN { get; }
public RazorProjectItem MSN { get; }
[Benchmark(Description = "Razor Design Time Code Generation of MSN.com")]
public void CodeGeneration_DesignTime_LargeStaticFile()
{
var codeDocument = RazorCodeDocument.Create(MSN, Imports);
var generated = DesignTimeTemplateEngine.GenerateCode(codeDocument);
var codeDocument = ProjectEngine.ProcessDesignTime(MSN);
var generated = codeDocument.GetCSharpDocument();
if (generated.Diagnostics.Count != 0)
{
@ -58,8 +46,8 @@ namespace Microsoft.AspNetCore.Razor.Performance
[Benchmark(Description = "Razor Runtime Code Generation of MSN.com")]
public void CodeGeneration_Runtime_LargeStaticFile()
{
var codeDocument = RazorCodeDocument.Create(MSN, Imports);
var generated = RuntimeTemplateEngine.GenerateCode(codeDocument);
var codeDocument = ProjectEngine.Process(MSN);
var generated = codeDocument.GetCSharpDocument();
if (generated.Diagnostics.Count != 0)
{

View File

@ -2,6 +2,7 @@
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System.Runtime.CompilerServices;
[assembly: InternalsVisibleTo("Microsoft.AspNetCore.Razor.Performance, PublicKey=0024000004800000940000000602000000240000525341310004000001000100f33a29044fa9d740c9b3213a93e57c84b472c84e0b8a0e1ae48e67a9f8f6de9d5f7f3d52ac23e48ac51801f1dc950abe901da34d2a9e3baadb141a17c77ef3c565dd5ee5054b91cf63bb3c6ab83f72ab3aafe93d0fc3c2348b764fafb0b1c0733de51459aeab46580384bf9d74c4e28164b7cde247f891ba07891c9d872ad2bb")]
[assembly: InternalsVisibleTo("Microsoft.AspNetCore.Mvc.Razor.Extensions.Test, PublicKey=0024000004800000940000000602000000240000525341310004000001000100f33a29044fa9d740c9b3213a93e57c84b472c84e0b8a0e1ae48e67a9f8f6de9d5f7f3d52ac23e48ac51801f1dc950abe901da34d2a9e3baadb141a17c77ef3c565dd5ee5054b91cf63bb3c6ab83f72ab3aafe93d0fc3c2348b764fafb0b1c0733de51459aeab46580384bf9d74c4e28164b7cde247f891ba07891c9d872ad2bb")]
[assembly: InternalsVisibleTo("Microsoft.AspNetCore.Mvc.Razor.Extensions.Version1_X.Test, PublicKey=0024000004800000940000000602000000240000525341310004000001000100f33a29044fa9d740c9b3213a93e57c84b472c84e0b8a0e1ae48e67a9f8f6de9d5f7f3d52ac23e48ac51801f1dc950abe901da34d2a9e3baadb141a17c77ef3c565dd5ee5054b91cf63bb3c6ab83f72ab3aafe93d0fc3c2348b764fafb0b1c0733de51459aeab46580384bf9d74c4e28164b7cde247f891ba07891c9d872ad2bb")]
[assembly: InternalsVisibleTo("Microsoft.AspNetCore.Razor.GenerateTool, PublicKey=0024000004800000940000000602000000240000525341310004000001000100f33a29044fa9d740c9b3213a93e57c84b472c84e0b8a0e1ae48e67a9f8f6de9d5f7f3d52ac23e48ac51801f1dc950abe901da34d2a9e3baadb141a17c77ef3c565dd5ee5054b91cf63bb3c6ab83f72ab3aafe93d0fc3c2348b764fafb0b1c0733de51459aeab46580384bf9d74c4e28164b7cde247f891ba07891c9d872ad2bb")]

View File

@ -2,13 +2,77 @@
// 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.Linq;
using Microsoft.AspNetCore.Razor.Language.CodeGeneration;
using Microsoft.AspNetCore.Razor.Language.Intermediate;
namespace Microsoft.AspNetCore.Razor.Language
{
public static class RazorProjectEngineBuilderExtensions
{
/// <summary>
/// Registers a class configuration delegate that gets invoked during code generation.
/// </summary>
/// <param name="builder">The <see cref="RazorProjectEngineBuilder"/>.</param>
/// <param name="configureClass"><see cref="Action"/> invoked to configure
/// <see cref="ClassDeclarationIntermediateNode"/> during code generation.</param>
/// <returns>The <see cref="RazorProjectEngineBuilder"/>.</returns>
public static RazorProjectEngineBuilder ConfigureClass(
this RazorProjectEngineBuilder builder,
Action<RazorCodeDocument, ClassDeclarationIntermediateNode> configureClass)
{
if (builder == null)
{
throw new ArgumentNullException(nameof(builder));
}
if (configureClass == null)
{
throw new ArgumentNullException(nameof(configureClass));
}
var configurationFeature = GetDefaultDocumentClassifierPassFeature(builder);
configurationFeature.ConfigureClass.Add(configureClass);
return builder;
}
/// <summary>
/// Sets the base type for generated types.
/// </summary>
/// <param name="builder">The <see cref="RazorProjectEngineBuilder"/>.</param>
/// <param name="baseType">The name of the base type.</param>
/// <returns>The <see cref="RazorProjectEngineBuilder"/>.</returns>
public static RazorProjectEngineBuilder SetBaseType(this RazorProjectEngineBuilder builder, string baseType)
{
if (builder == null)
{
throw new ArgumentNullException(nameof(builder));
}
var configurationFeature = GetDefaultDocumentClassifierPassFeature(builder);
configurationFeature.ConfigureClass.Add((document, @class) => @class.BaseType = baseType);
return builder;
}
/// <summary>
/// Sets the namespace for generated types.
/// </summary>
/// <param name="builder">The <see cref="RazorProjectEngineBuilder"/>.</param>
/// <param name="namespaceName">The name of the namespace.</param>
/// <returns>The <see cref="RazorProjectEngineBuilder"/>.</returns>
public static RazorProjectEngineBuilder SetNamespace(this RazorProjectEngineBuilder builder, string namespaceName)
{
if (builder == null)
{
throw new ArgumentNullException(nameof(builder));
}
var configurationFeature = GetDefaultDocumentClassifierPassFeature(builder);
configurationFeature.ConfigureNamespace.Add((document, @namespace) => @namespace.Content = namespaceName);
return builder;
}
public static void SetImportFeature(this RazorProjectEngineBuilder builder, IImportProjectFeature feature)
{
if (builder == null)
@ -79,6 +143,27 @@ namespace Microsoft.AspNetCore.Razor.Language
return builder;
}
/// <summary>
/// Adds the provided <see cref="RazorSourceDocument" /> documents as imports to all documents processed
/// by the <see cref="RazorProjectEngine"/>.
/// </summary>
/// <param name="builder">The <see cref="RazorProjectEngineBuilder"/>.</param>
/// <param name="imports">The collection of imports.</param>
/// <returns>The <see cref="RazorProjectEngineBuilder"/>.</returns>
public static RazorProjectEngineBuilder AddDefaultImports(this RazorProjectEngineBuilder builder, params RazorSourceDocument[] imports)
{
if (builder == null)
{
throw new ArgumentNullException(nameof(builder));
}
var existingImportFeature = builder.Features.OfType<IImportProjectFeature>().First();
var testImportFeature = new AdditionalImportsProjectFeature(existingImportFeature, imports);
builder.SetImportFeature(testImportFeature);
return builder;
}
private static IRazorDirectiveFeature GetDirectiveFeature(RazorProjectEngineBuilder builder)
{
var directiveFeature = builder.Features.OfType<IRazorDirectiveFeature>().FirstOrDefault();
@ -102,5 +187,47 @@ namespace Microsoft.AspNetCore.Razor.Language
return targetExtensionFeature;
}
private static DefaultDocumentClassifierPassFeature GetDefaultDocumentClassifierPassFeature(RazorProjectEngineBuilder builder)
{
var configurationFeature = builder.Features.OfType<DefaultDocumentClassifierPassFeature>().FirstOrDefault();
if (configurationFeature == null)
{
configurationFeature = new DefaultDocumentClassifierPassFeature();
builder.Features.Add(configurationFeature);
}
return configurationFeature;
}
private class AdditionalImportsProjectFeature : RazorProjectEngineFeatureBase, IImportProjectFeature
{
private readonly IImportProjectFeature _existingImportFeature;
private readonly RazorSourceDocument[] _imports;
public override RazorProjectEngine ProjectEngine
{
get => base.ProjectEngine;
set
{
_existingImportFeature.ProjectEngine = value;
base.ProjectEngine = value;
}
}
public AdditionalImportsProjectFeature(IImportProjectFeature existingImportFeature, params RazorSourceDocument[] imports)
{
_existingImportFeature = existingImportFeature;
_imports = imports;
}
public IReadOnlyList<RazorSourceDocument> GetImports(RazorProjectItem projectItem)
{
var imports = _existingImportFeature.GetImports(projectItem).ToList();
imports.AddRange(_imports);
return imports;
}
}
}
}

View File

@ -3,24 +3,25 @@
using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.AspNetCore.Razor.Language;
namespace Microsoft.AspNetCore.Razor.Tools
{
internal class CompositeRazorProjectFileSystem : RazorProjectFileSystem
{
public CompositeRazorProjectFileSystem(IReadOnlyList<RazorProjectFileSystem> projects)
public CompositeRazorProjectFileSystem(IReadOnlyList<RazorProjectFileSystem> fileSystems)
{
Projects = projects ?? throw new ArgumentNullException(nameof(projects));
FileSystems = fileSystems ?? throw new ArgumentNullException(nameof(fileSystems));
}
public IReadOnlyList<RazorProjectFileSystem> Projects { get; }
public IReadOnlyList<RazorProjectFileSystem> FileSystems { get; }
public override IEnumerable<RazorProjectItem> EnumerateItems(string basePath)
{
foreach (var project in Projects)
foreach (var fileSystem in FileSystems)
{
foreach (var result in project.EnumerateItems(basePath))
foreach (var result in fileSystem.EnumerateItems(basePath))
{
yield return result;
}
@ -30,9 +31,9 @@ namespace Microsoft.AspNetCore.Razor.Tools
public override RazorProjectItem GetItem(string path)
{
RazorProjectItem razorProjectItem = null;
foreach (var project in Projects)
foreach (var fileSystem in FileSystems)
{
razorProjectItem = project.GetItem(path);
razorProjectItem = fileSystem.GetItem(path);
if (razorProjectItem != null && razorProjectItem.Exists)
{
return razorProjectItem;

View File

@ -3,6 +3,7 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc.Razor.Extensions;
@ -90,26 +91,20 @@ namespace Microsoft.AspNetCore.Razor.Tools
tagHelperManifest = Path.Combine(projectDirectory, tagHelperManifest);
var tagHelpers = GetTagHelpers(tagHelperManifest);
var engine = RazorEngine.Create(b =>
var inputItems = GetInputItems(projectDirectory, sources, outputs, relativePaths);
var compositeFileSystem = new CompositeRazorProjectFileSystem(new[]
{
GetVirtualRazorProjectSystem(inputItems),
RazorProjectFileSystem.Create(projectDirectory),
});
var projectEngine = RazorProjectEngine.Create(RazorConfiguration.Default, compositeFileSystem, b =>
{
RazorExtensions.Register(b);
b.Features.Add(new StaticTagHelperFeature() { TagHelpers = tagHelpers, });
});
var inputItems = GetInputItems(projectDirectory, sources, outputs, relativePaths);
var compositeProject = new CompositeRazorProjectFileSystem(
new[]
{
GetVirtualRazorProjectSystem(inputItems),
RazorProjectFileSystem.Create(projectDirectory),
});
var templateEngine = new MvcRazorTemplateEngine(engine, compositeProject);
var results = GenerateCode(templateEngine, inputItems);
var results = GenerateCode(projectEngine, inputItems);
var success = true;
@ -180,14 +175,15 @@ namespace Microsoft.AspNetCore.Razor.Tools
return items;
}
private OutputItem[] GenerateCode(RazorTemplateEngine templateEngine, SourceItem[] inputs)
private OutputItem[] GenerateCode(RazorProjectEngine projectEngine, SourceItem[] inputs)
{
var outputs = new OutputItem[inputs.Length];
Parallel.For(0, outputs.Length, new ParallelOptions() { MaxDegreeOfParallelism = 4 }, i =>
Parallel.For(0, outputs.Length, new ParallelOptions() { MaxDegreeOfParallelism = Debugger.IsAttached ? 1 : 4 }, i =>
{
var inputItem = inputs[i];
var csharpDocument = templateEngine.GenerateCode(inputItem.FilePath);
var projectItem = projectEngine.FileSystem.GetItem(inputItem.FilePath);
var codeDocument = projectEngine.Process(projectItem);
var csharpDocument = codeDocument.GetCSharpDocument();
outputs[i] = new OutputItem(inputItem, csharpDocument);
});

View File

@ -7,8 +7,8 @@ using Microsoft.CodeAnalysis.Host;
namespace Microsoft.CodeAnalysis.Razor
{
internal abstract class RazorTemplateEngineFactoryService : ILanguageService
internal abstract class RazorProjectEngineFactoryService : ILanguageService
{
public abstract RazorTemplateEngine Create(string projectPath, Action<IRazorEngineBuilder> configure);
public abstract RazorProjectEngine Create(string projectPath, Action<RazorProjectEngineBuilder> configure);
}
}

View File

@ -6,6 +6,7 @@ using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading;
using Microsoft.AspNetCore.Razor.Language;
using Microsoft.AspNetCore.Razor.Language.Legacy;
@ -18,10 +19,10 @@ namespace Microsoft.VisualStudio.Editor.Razor
private MainThreadState _main;
private BackgroundThread _bg;
public BackgroundParser(RazorTemplateEngine templateEngine, string filePath)
public BackgroundParser(RazorProjectEngine projectEngine, string filePath, string projectDirectory)
{
_main = new MainThreadState(filePath);
_bg = new BackgroundThread(_main, templateEngine, filePath);
_bg = new BackgroundThread(_main, projectEngine, filePath, projectDirectory);
_main.ResultsReady += (sender, args) => OnResultsReady(args);
}
@ -233,22 +234,25 @@ namespace Microsoft.VisualStudio.Editor.Razor
private class BackgroundThread : ThreadStateBase
{
private readonly string _filePath;
private readonly string _relativeFilePath;
private readonly string _projectDirectory;
private MainThreadState _main;
private Thread _backgroundThread;
private CancellationToken _shutdownToken;
private RazorTemplateEngine _templateEngine;
private string _filePath;
private RazorProjectEngine _projectEngine;
private RazorSyntaxTree _currentSyntaxTree;
private IList<Edit> _previouslyDiscarded = new List<Edit>();
public BackgroundThread(MainThreadState main, RazorTemplateEngine templateEngine, string fileName)
public BackgroundThread(MainThreadState main, RazorProjectEngine projectEngine, string filePath, string projectDirectory)
{
// Run on MAIN thread!
_main = main;
_shutdownToken = _main.CancelToken;
_templateEngine = templateEngine;
_filePath = fileName;
_projectEngine = projectEngine;
_filePath = filePath;
_relativeFilePath = GetNormalizedRelativeFilePath(filePath, projectDirectory);
_projectDirectory = projectDirectory;
_backgroundThread = new Thread(WorkerLoop);
SetThreadId(_backgroundThread.ManagedThreadId);
}
@ -262,8 +266,6 @@ namespace Microsoft.VisualStudio.Editor.Razor
// **** BACKGROUND THREAD ****
private void WorkerLoop()
{
var fileNameOnly = Path.GetFileName(_filePath);
try
{
EnsureOnThread();
@ -347,14 +349,31 @@ namespace Microsoft.VisualStudio.Editor.Razor
{
EnsureOnThread();
var sourceDocument = new TextSnapshotSourceDocument(snapshot, _filePath);
var imports = _templateEngine.GetImports(_filePath);
var projectItem = new TextSnapshotProjectItem(snapshot, _projectDirectory, _relativeFilePath, _filePath);
var codeDocument = _projectEngine.ProcessDesignTime(projectItem);
var codeDocument = RazorCodeDocument.Create(sourceDocument, imports);
_templateEngine.GenerateCode(codeDocument);
return codeDocument;
}
private string GetNormalizedRelativeFilePath(string filePath, string projectDirectory)
{
if (filePath.StartsWith(projectDirectory, StringComparison.OrdinalIgnoreCase))
{
filePath = filePath.Substring(projectDirectory.Length);
}
if (filePath.Length > 1)
{
filePath = filePath.Replace('\\', '/');
if (filePath[0] != '/')
{
filePath = "/" + filePath;
}
}
return filePath;
}
}
private class WorkParcel

View File

@ -5,6 +5,7 @@ using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using Microsoft.AspNetCore.Razor.Language;
using Microsoft.CodeAnalysis.Razor;
@ -15,7 +16,7 @@ namespace Microsoft.VisualStudio.Editor.Razor
private readonly FileChangeTrackerFactory _fileChangeTrackerFactory;
private readonly ForegroundDispatcher _foregroundDispatcher;
private readonly ErrorReporter _errorReporter;
private readonly RazorTemplateEngineFactoryService _templateEngineFactoryService;
private readonly RazorProjectEngineFactoryService _projectEngineFactoryService;
private readonly Dictionary<string, ImportTracker> _importTrackerCache;
public override event EventHandler<ImportChangedEventArgs> Changed;
@ -24,7 +25,7 @@ namespace Microsoft.VisualStudio.Editor.Razor
ForegroundDispatcher foregroundDispatcher,
ErrorReporter errorReporter,
FileChangeTrackerFactory fileChangeTrackerFactory,
RazorTemplateEngineFactoryService templateEngineFactoryService)
RazorProjectEngineFactoryService projectEngineFactoryService)
{
if (foregroundDispatcher == null)
{
@ -41,15 +42,15 @@ namespace Microsoft.VisualStudio.Editor.Razor
throw new ArgumentNullException(nameof(fileChangeTrackerFactory));
}
if (templateEngineFactoryService == null)
if (projectEngineFactoryService == null)
{
throw new ArgumentNullException(nameof(templateEngineFactoryService));
throw new ArgumentNullException(nameof(projectEngineFactoryService));
}
_foregroundDispatcher = foregroundDispatcher;
_errorReporter = errorReporter;
_fileChangeTrackerFactory = fileChangeTrackerFactory;
_templateEngineFactoryService = templateEngineFactoryService;
_projectEngineFactoryService = projectEngineFactoryService;
_importTrackerCache = new Dictionary<string, ImportTracker>(StringComparer.OrdinalIgnoreCase);
}
@ -115,10 +116,26 @@ namespace Microsoft.VisualStudio.Editor.Razor
private IEnumerable<RazorProjectItem> GetImportItems(VisualStudioDocumentTracker tracker)
{
var projectDirectory = Path.GetDirectoryName(tracker.ProjectPath);
var templateEngine = _templateEngineFactoryService.Create(projectDirectory, _ => { });
var imports = templateEngine.GetImportItems(tracker.FilePath);
var projectEngine = _projectEngineFactoryService.Create(projectDirectory, _ => { });
var trackerItem = projectEngine.FileSystem.GetItem(tracker.FilePath);
var importFeature = projectEngine.ProjectFeatures.OfType<IImportProjectFeature>().FirstOrDefault();
return imports;
// There should always be an import feature unless someone has misconfigured their RazorProjectEngine.
// In that case once we attempt to parse the Razor file we'll explode and give the a user a decent
// error message; for now, lets just be extra protective and assume 0 imports to not give a bad error.
var imports = importFeature?.GetImports(trackerItem) ?? Enumerable.Empty<RazorSourceDocument>();
var physicalImports = imports.Where(import => import.FilePath != null);
// Now that we have non-dynamic imports we need to get their RazorProjectItem equivalents so we have their
// physical file paths (according to the FileSystem).
var projectItems = new List<RazorProjectItem>();
foreach (var physicalImport in physicalImports)
{
var projectItem = projectEngine.FileSystem.GetItem(physicalImport.FilePath);
projectItems.Add(projectItem);
}
return projectItems;
}
private void OnChanged(ImportTracker importTracker, FileChangeKind changeKind)

View File

@ -35,13 +35,13 @@ namespace Microsoft.VisualStudio.Editor.Razor
var errorReporter = languageServices.WorkspaceServices.GetRequiredService<ErrorReporter>();
var fileChangeTrackerFactory = languageServices.GetRequiredService<FileChangeTrackerFactory>();
var templateEngineFactoryService = languageServices.GetRequiredService<RazorTemplateEngineFactoryService>();
var projectEngineFactoryService = languageServices.GetRequiredService<RazorProjectEngineFactoryService>();
return new DefaultImportDocumentManager(
_foregroundDispatcher,
errorReporter,
fileChangeTrackerFactory,
templateEngineFactoryService);
projectEngineFactoryService);
}
}
}

View File

@ -12,7 +12,7 @@ using MvcLatest = Microsoft.AspNetCore.Mvc.Razor.Extensions;
namespace Microsoft.VisualStudio.Editor.Razor
{
internal class DefaultTemplateEngineFactoryService : RazorTemplateEngineFactoryService
internal class DefaultProjectEngineFactoryService : RazorProjectEngineFactoryService
{
private readonly static MvcExtensibilityConfiguration DefaultConfiguration = new MvcExtensibilityConfiguration(
RazorLanguageVersion.Version_2_0,
@ -22,7 +22,7 @@ namespace Microsoft.VisualStudio.Editor.Razor
private readonly ProjectSnapshotManager _projectManager;
public DefaultTemplateEngineFactoryService(ProjectSnapshotManager projectManager)
public DefaultProjectEngineFactoryService(ProjectSnapshotManager projectManager)
{
if (projectManager == null)
{
@ -32,7 +32,7 @@ namespace Microsoft.VisualStudio.Editor.Razor
_projectManager = projectManager;
}
public override RazorTemplateEngine Create(string projectPath, Action<IRazorEngineBuilder> configure)
public override RazorProjectEngine Create(string projectPath, Action<RazorProjectEngineBuilder> configure)
{
if (projectPath == null)
{
@ -43,12 +43,14 @@ 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>());
RazorEngine engine;
var razorConfiguration = new RazorConfiguration(razorLanguageVersion, "unnamed", Array.Empty<RazorExtension>());
var fileSystem = RazorProjectFileSystem.Create(projectPath);
RazorProjectEngine projectEngine;
if (razorLanguageVersion.Major == 1)
{
engine = RazorEngine.CreateCore(razorConfiguration, true, b =>
projectEngine = RazorProjectEngine.Create(razorConfiguration, fileSystem, b =>
{
configure?.Invoke(b);
@ -59,24 +61,18 @@ namespace Microsoft.VisualStudio.Editor.Razor
Mvc1_X.RazorExtensions.RegisterViewComponentTagHelpers(b);
}
});
var templateEngine = new Mvc1_X.MvcRazorTemplateEngine(engine, RazorProjectFileSystem.Create(projectPath));
templateEngine.Options.ImportsFileName = "_ViewImports.cshtml";
return templateEngine;
}
else
{
engine = RazorEngine.CreateCore(razorConfiguration, true, b =>
projectEngine = RazorProjectEngine.Create(razorConfiguration, fileSystem, b =>
{
configure?.Invoke(b);
MvcLatest.RazorExtensions.Register(b);
});
var templateEngine = new MvcLatest.MvcRazorTemplateEngine(engine, RazorProjectFileSystem.Create(projectPath));
templateEngine.Options.ImportsFileName = "_ViewImports.cshtml";
return templateEngine;
}
return projectEngine;
}
private ProjectSnapshot FindProject(string directory)

View File

@ -8,12 +8,12 @@ using Microsoft.CodeAnalysis.Razor.ProjectSystem;
namespace Microsoft.VisualStudio.Editor.Razor
{
[ExportLanguageServiceFactory(typeof(RazorTemplateEngineFactoryService), RazorLanguage.Name, ServiceLayer.Default)]
internal class DefaultTemplateEngineFactoryServiceFactory : ILanguageServiceFactory
[ExportLanguageServiceFactory(typeof(RazorProjectEngineFactoryService), RazorLanguage.Name, ServiceLayer.Default)]
internal class DefaultProjectEngineFactoryServiceFactory : ILanguageServiceFactory
{
public ILanguageService CreateLanguageService(HostLanguageServices languageServices)
{
return new DefaultTemplateEngineFactoryService(languageServices.GetRequiredService<ProjectSnapshotManager>());
return new DefaultProjectEngineFactoryService(languageServices.GetRequiredService<ProjectSnapshotManager>());
}
}
}

View File

@ -31,9 +31,9 @@ namespace Microsoft.VisualStudio.Editor.Razor
private readonly VisualStudioCompletionBroker _completionBroker;
private readonly VisualStudioDocumentTracker _documentTracker;
private readonly ForegroundDispatcher _dispatcher;
private readonly RazorTemplateEngineFactoryService _templateEngineFactory;
private readonly RazorProjectEngineFactoryService _projectEngineFactory;
private readonly ErrorReporter _errorReporter;
private RazorTemplateEngine _templateEngine;
private RazorProjectEngine _projectEngine;
private RazorCodeDocument _codeDocument;
private ITextSnapshot _snapshot;
private bool _disposed;
@ -47,7 +47,7 @@ namespace Microsoft.VisualStudio.Editor.Razor
public DefaultVisualStudioRazorParser(
ForegroundDispatcher dispatcher,
VisualStudioDocumentTracker documentTracker,
RazorTemplateEngineFactoryService templateEngineFactory,
RazorProjectEngineFactoryService projectEngineFactory,
ErrorReporter errorReporter,
VisualStudioCompletionBroker completionBroker)
{
@ -61,9 +61,9 @@ namespace Microsoft.VisualStudio.Editor.Razor
throw new ArgumentNullException(nameof(documentTracker));
}
if (templateEngineFactory == null)
if (projectEngineFactory == null)
{
throw new ArgumentNullException(nameof(templateEngineFactory));
throw new ArgumentNullException(nameof(projectEngineFactory));
}
if (errorReporter == null)
@ -77,7 +77,7 @@ namespace Microsoft.VisualStudio.Editor.Razor
}
_dispatcher = dispatcher;
_templateEngineFactory = templateEngineFactory;
_projectEngineFactory = projectEngineFactory;
_errorReporter = errorReporter;
_completionBroker = completionBroker;
_documentTracker = documentTracker;
@ -85,7 +85,7 @@ namespace Microsoft.VisualStudio.Editor.Razor
_documentTracker.ContextChanged += DocumentTracker_ContextChanged;
}
public override RazorTemplateEngine TemplateEngine => _templateEngine;
public override RazorProjectEngine ProjectEngine => _projectEngine;
public override string FilePath => _documentTracker.FilePath;
@ -170,8 +170,8 @@ namespace Microsoft.VisualStudio.Editor.Razor
_dispatcher.AssertForegroundThread();
var projectDirectory = Path.GetDirectoryName(_documentTracker.ProjectPath);
_templateEngine = _templateEngineFactory.Create(projectDirectory, ConfigureTemplateEngine);
_parser = new BackgroundParser(TemplateEngine, FilePath);
_projectEngine = _projectEngineFactory.Create(projectDirectory, ConfigureProjectEngine);
_parser = new BackgroundParser(ProjectEngine, FilePath, projectDirectory);
_parser.ResultsReady += OnResultsReady;
_parser.Start();
@ -383,7 +383,7 @@ namespace Microsoft.VisualStudio.Editor.Razor
DocumentStructureChanged?.Invoke(this, args);
}
private void ConfigureTemplateEngine(IRazorEngineBuilder builder)
private void ConfigureProjectEngine(RazorProjectEngineBuilder builder)
{
builder.Features.Add(new VisualStudioParserOptionsFeature(_documentTracker.EditorSettings));
builder.Features.Add(new VisualStudioTagHelperFeature(_documentTracker.TagHelpers));

View File

@ -9,7 +9,7 @@ namespace Microsoft.VisualStudio.Editor.Razor
internal class DefaultVisualStudioRazorParserFactory : VisualStudioRazorParserFactory
{
private readonly ForegroundDispatcher _dispatcher;
private readonly RazorTemplateEngineFactoryService _templateEngineFactoryService;
private readonly RazorProjectEngineFactoryService _projectEngineFactoryService;
private readonly VisualStudioCompletionBroker _completionBroker;
private readonly ErrorReporter _errorReporter;
@ -17,7 +17,7 @@ namespace Microsoft.VisualStudio.Editor.Razor
ForegroundDispatcher dispatcher,
ErrorReporter errorReporter,
VisualStudioCompletionBroker completionBroker,
RazorTemplateEngineFactoryService templateEngineFactoryService)
RazorProjectEngineFactoryService projectEngineFactoryService)
{
if (dispatcher == null)
{
@ -34,15 +34,15 @@ namespace Microsoft.VisualStudio.Editor.Razor
throw new ArgumentNullException(nameof(completionBroker));
}
if (templateEngineFactoryService == null)
if (projectEngineFactoryService == null)
{
throw new ArgumentNullException(nameof(templateEngineFactoryService));
throw new ArgumentNullException(nameof(projectEngineFactoryService));
}
_dispatcher = dispatcher;
_errorReporter = errorReporter;
_completionBroker = completionBroker;
_templateEngineFactoryService = templateEngineFactoryService;
_projectEngineFactoryService = projectEngineFactoryService;
}
public override VisualStudioRazorParser Create(VisualStudioDocumentTracker documentTracker)
@ -57,7 +57,7 @@ namespace Microsoft.VisualStudio.Editor.Razor
var parser = new DefaultVisualStudioRazorParser(
_dispatcher,
documentTracker,
_templateEngineFactoryService,
_projectEngineFactoryService,
_errorReporter,
_completionBroker);
return parser;

View File

@ -35,13 +35,13 @@ namespace Microsoft.VisualStudio.Editor.Razor
var workspaceServices = languageServices.WorkspaceServices;
var errorReporter = workspaceServices.GetRequiredService<ErrorReporter>();
var completionBroker = languageServices.GetRequiredService<VisualStudioCompletionBroker>();
var templateEngineFactoryService = languageServices.GetRequiredService<RazorTemplateEngineFactoryService>();
var projectEngineFactoryService = languageServices.GetRequiredService<RazorProjectEngineFactoryService>();
return new DefaultVisualStudioRazorParserFactory(
_foregroundDispatcher,
errorReporter,
completionBroker,
templateEngineFactoryService);
projectEngineFactoryService);
}
}
}

View File

@ -0,0 +1,65 @@
// 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.IO;
using System.Text;
using Microsoft.AspNetCore.Razor.Language;
using Microsoft.VisualStudio.Text;
namespace Microsoft.VisualStudio.Editor.Razor
{
internal class TextSnapshotProjectItem : RazorProjectItem
{
private readonly ITextSnapshot _snapshot;
public TextSnapshotProjectItem(ITextSnapshot snapshot, string projectDirectory, string relativeFilePath, string filePath)
{
if (snapshot == null)
{
throw new ArgumentNullException(nameof(snapshot));
}
if (string.IsNullOrEmpty(projectDirectory))
{
throw new ArgumentException(Resources.ArgumentCannotBeNullOrEmpty, nameof(projectDirectory));
}
if (string.IsNullOrEmpty(relativeFilePath))
{
throw new ArgumentException(Resources.ArgumentCannotBeNullOrEmpty, nameof(relativeFilePath));
}
if (string.IsNullOrEmpty(filePath))
{
throw new ArgumentException(Resources.ArgumentCannotBeNullOrEmpty, nameof(filePath));
}
_snapshot = snapshot;
BasePath = projectDirectory;
FilePath = relativeFilePath;
PhysicalPath = filePath;
}
public override string BasePath { get; }
public override string FilePath { get; }
public override string PhysicalPath { get; }
public override bool Exists => true;
public override Stream Read()
{
var charArray = _snapshot.ToCharArray(0, _snapshot.Length);
// We can assume UTF8 because the call path that reads from RazorProjectItem => SourceDocument
// can't determine the encoding and always assumes Encoding.UTF8. This is something that we might
// want to revisit in the future.
var bytes = Encoding.UTF8.GetBytes(charArray);
var memoryStream = new MemoryStream(bytes);
return memoryStream;
}
}
}

View File

@ -1,79 +0,0 @@
// 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.Text;
using Microsoft.AspNetCore.Razor.Language;
using Microsoft.VisualStudio.Text;
namespace Microsoft.VisualStudio.Editor.Razor
{
internal class TextSnapshotSourceDocument : RazorSourceDocument
{
private readonly ITextSnapshot _buffer;
private readonly RazorSourceLineCollection _lines;
public TextSnapshotSourceDocument(ITextSnapshot snapshot, string filePath)
{
if (snapshot == null)
{
throw new ArgumentNullException(nameof(snapshot));
}
if (filePath == null)
{
throw new ArgumentNullException(nameof(filePath));
}
_buffer = snapshot;
FilePath = filePath;
_lines = new DefaultRazorSourceLineCollection(this);
}
public override char this[int position] => _buffer[position];
public override Encoding Encoding => Encoding.UTF8;
public override int Length => _buffer.Length;
public override RazorSourceLineCollection Lines => _lines;
public override string FilePath { get; }
public override void CopyTo(int sourceIndex, char[] destination, int destinationIndex, int count)
{
if (destination == null)
{
throw new ArgumentNullException(nameof(destination));
}
if (sourceIndex < 0)
{
throw new ArgumentOutOfRangeException(nameof(sourceIndex));
}
if (destinationIndex < 0)
{
throw new ArgumentOutOfRangeException(nameof(destinationIndex));
}
if (count < 0 || count > Length - sourceIndex || count > destination.Length - destinationIndex)
{
throw new ArgumentOutOfRangeException(nameof(count));
}
if (count == 0)
{
return;
}
for (var i = 0; i < count; i++)
{
destination[destinationIndex + i] = this[sourceIndex + i];
}
}
public override byte[] GetChecksum() => throw new NotImplementedException();
}
}

View File

@ -11,7 +11,7 @@ namespace Microsoft.VisualStudio.Editor.Razor
{
public abstract event EventHandler<DocumentStructureChangedEventArgs> DocumentStructureChanged;
public abstract RazorTemplateEngine TemplateEngine { get; }
public abstract RazorProjectEngine ProjectEngine { get; }
public abstract string FilePath { get; }

View File

@ -31,8 +31,8 @@ Examples:
var rootNamespace = args[0];
var targetProjectDirectory = args.Length > 1 ? args[1] : Directory.GetCurrentDirectory();
var razorEngine = CreateRazorEngine(rootNamespace);
var results = MainCore(razorEngine, targetProjectDirectory);
var projectEngine = CreateProjectEngine(rootNamespace, targetProjectDirectory);
var results = MainCore(projectEngine, targetProjectDirectory);
foreach (var result in results)
{
@ -45,9 +45,10 @@ Examples:
return 0;
}
public static RazorEngine CreateRazorEngine(string rootNamespace, Action<IRazorEngineBuilder> configure = null)
public static RazorProjectEngine CreateProjectEngine(string rootNamespace, string targetProjectDirectory, Action<RazorProjectEngineBuilder> configure = null)
{
var razorEngine = RazorEngine.Create(builder =>
var fileSystem = RazorProjectFileSystem.Create(targetProjectDirectory);
var projectEngine = RazorProjectEngine.Create(RazorConfiguration.Default, fileSystem, builder =>
{
builder
.SetNamespace(rootNamespace)
@ -66,20 +67,18 @@ Examples:
{
configure(builder);
}
});
return razorEngine;
}
public static IList<RazorPageGeneratorResult> MainCore(RazorEngine razorEngine, string targetProjectDirectory)
{
var viewDirectories = Directory.EnumerateDirectories(targetProjectDirectory, "Views", SearchOption.AllDirectories);
var razorProject = RazorProjectFileSystem.Create(targetProjectDirectory);
var templateEngine = new RazorTemplateEngine(razorEngine, razorProject);
templateEngine.Options.DefaultImports = RazorSourceDocument.Create(@"
builder.AddDefaultImports(RazorSourceDocument.Create(@"
@using System
@using System.Threading.Tasks
", fileName: null);
", fileName: null));
});
return projectEngine;
}
public static IList<RazorPageGeneratorResult> MainCore(RazorProjectEngine projectEngine, string targetProjectDirectory)
{
var viewDirectories = Directory.EnumerateDirectories(targetProjectDirectory, "Views", SearchOption.AllDirectories);
var fileCount = 0;
var results = new List<RazorPageGeneratorResult>();
@ -88,7 +87,7 @@ Examples:
Console.WriteLine();
Console.WriteLine(" Generating code files for views in {0}", viewDir);
var viewDirPath = viewDir.Substring(targetProjectDirectory.Length).Replace('\\', '/');
var cshtmlFiles = razorProject.EnumerateItems(viewDirPath);
var cshtmlFiles = projectEngine.FileSystem.EnumerateItems(viewDirPath);
if (!cshtmlFiles.Any())
{
@ -99,7 +98,7 @@ Examples:
foreach (var item in cshtmlFiles)
{
Console.WriteLine(" Generating code file for view {0}...", item.FileName);
results.Add(GenerateCodeFile(templateEngine, item));
results.Add(GenerateCodeFile(projectEngine, item));
Console.WriteLine(" Done!");
fileCount++;
}
@ -108,10 +107,11 @@ Examples:
return results;
}
private static RazorPageGeneratorResult GenerateCodeFile(RazorTemplateEngine templateEngine, RazorProjectItem projectItem)
private static RazorPageGeneratorResult GenerateCodeFile(RazorProjectEngine projectEngine, RazorProjectItem projectItem)
{
var projectItemWrapper = new FileSystemRazorProjectItemWrapper(projectItem);
var cSharpDocument = templateEngine.GenerateCode(projectItemWrapper);
var codeDocument = projectEngine.Process(projectItemWrapper);
var cSharpDocument = codeDocument.GetCSharpDocument();
if (cSharpDocument.Diagnostics.Any())
{
var diagnostics = string.Join(Environment.NewLine, cSharpDocument.Diagnostics);

View File

@ -0,0 +1,70 @@
// 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;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Razor.Language.IntegrationTests;
using Microsoft.AspNetCore.Razor.Language.Intermediate;
namespace Microsoft.AspNetCore.Razor.Language
{
public static class RazorProjectEngineBuilderExtensions
{
public static RazorProjectEngineBuilder AddTagHelpers(this RazorProjectEngineBuilder builder, params TagHelperDescriptor[] tagHelpers)
{
return AddTagHelpers(builder, (IEnumerable<TagHelperDescriptor>)tagHelpers);
}
public static RazorProjectEngineBuilder AddTagHelpers(this RazorProjectEngineBuilder builder, IEnumerable<TagHelperDescriptor> tagHelpers)
{
var feature = (TestTagHelperFeature)builder.Features.OfType<ITagHelperFeature>().FirstOrDefault();
if (feature == null)
{
feature = new TestTagHelperFeature();
builder.Features.Add(feature);
}
feature.TagHelpers.AddRange(tagHelpers);
return builder;
}
public static RazorProjectEngineBuilder ConfigureDocumentClassifier(this RazorProjectEngineBuilder builder)
{
var feature = builder.Features.OfType<DefaultDocumentClassifierPassFeature>().FirstOrDefault();
if (feature == null)
{
feature = new DefaultDocumentClassifierPassFeature();
builder.Features.Add(feature);
}
feature.ConfigureNamespace.Clear();
feature.ConfigureClass.Clear();
feature.ConfigureMethod.Clear();
feature.ConfigureNamespace.Add((RazorCodeDocument codeDocument, NamespaceDeclarationIntermediateNode node) =>
{
node.Content = "Microsoft.AspNetCore.Razor.Language.IntegrationTests.TestFiles";
});
feature.ConfigureClass.Add((RazorCodeDocument codeDocument, ClassDeclarationIntermediateNode node) =>
{
node.ClassName = IntegrationTestBase.FileName.Replace('/', '_');
node.Modifiers.Clear();
node.Modifiers.Add("public");
});
feature.ConfigureMethod.Add((RazorCodeDocument codeDocument, MethodDeclarationIntermediateNode node) =>
{
node.Modifiers.Clear();
node.Modifiers.Add("public");
node.Modifiers.Add("async");
node.MethodName = "ExecuteAsync";
node.ReturnType = typeof(Task).FullName;
});
return builder;
}
}
}

View File

@ -4,11 +4,10 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace Microsoft.AspNetCore.Razor.Language
{
public class TestRazorProjectFileSystem : RazorProjectFileSystem
internal class TestRazorProjectFileSystem : DefaultRazorProjectFileSystem
{
public static RazorProjectFileSystem Empty = new TestRazorProjectFileSystem();
@ -19,7 +18,7 @@ namespace Microsoft.AspNetCore.Razor.Language
{
}
public TestRazorProjectFileSystem(IList<RazorProjectItem> items)
public TestRazorProjectFileSystem(IList<RazorProjectItem> items) : base("/")
{
_lookup = items.ToDictionary(item => item.FilePath);
}

View File

@ -2,6 +2,8 @@
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System.Runtime.CompilerServices;
[assembly: InternalsVisibleTo("Microsoft.AspNetCore.Mvc.Razor.Extensions.Test, PublicKey=0024000004800000940000000602000000240000525341310004000001000100f33a29044fa9d740c9b3213a93e57c84b472c84e0b8a0e1ae48e67a9f8f6de9d5f7f3d52ac23e48ac51801f1dc950abe901da34d2a9e3baadb141a17c77ef3c565dd5ee5054b91cf63bb3c6ab83f72ab3aafe93d0fc3c2348b764fafb0b1c0733de51459aeab46580384bf9d74c4e28164b7cde247f891ba07891c9d872ad2bb")]
[assembly: InternalsVisibleTo("Microsoft.AspNetCore.Mvc.Razor.Extensions.Version1_X.Test, PublicKey=0024000004800000940000000602000000240000525341310004000001000100f33a29044fa9d740c9b3213a93e57c84b472c84e0b8a0e1ae48e67a9f8f6de9d5f7f3d52ac23e48ac51801f1dc950abe901da34d2a9e3baadb141a17c77ef3c565dd5ee5054b91cf63bb3c6ab83f72ab3aafe93d0fc3c2348b764fafb0b1c0733de51459aeab46580384bf9d74c4e28164b7cde247f891ba07891c9d872ad2bb")]
[assembly: InternalsVisibleTo("Microsoft.AspNetCore.Razor.Language.Test, PublicKey=0024000004800000940000000602000000240000525341310004000001000100f33a29044fa9d740c9b3213a93e57c84b472c84e0b8a0e1ae48e67a9f8f6de9d5f7f3d52ac23e48ac51801f1dc950abe901da34d2a9e3baadb141a17c77ef3c565dd5ee5054b91cf63bb3c6ab83f72ab3aafe93d0fc3c2348b764fafb0b1c0733de51459aeab46580384bf9d74c4e28164b7cde247f891ba07891c9d872ad2bb")]
[assembly: InternalsVisibleTo("Microsoft.CodeAnalysis.Razor.Test, PublicKey=0024000004800000940000000602000000240000525341310004000001000100f33a29044fa9d740c9b3213a93e57c84b472c84e0b8a0e1ae48e67a9f8f6de9d5f7f3d52ac23e48ac51801f1dc950abe901da34d2a9e3baadb141a17c77ef3c565dd5ee5054b91cf63bb3c6ab83f72ab3aafe93d0fc3c2348b764fafb0b1c0733de51459aeab46580384bf9d74c4e28164b7cde247f891ba07891c9d872ad2bb")]
[assembly: InternalsVisibleTo("Microsoft.CodeAnalysis.Razor.Workspaces.Test, PublicKey=0024000004800000940000000602000000240000525341310004000001000100f33a29044fa9d740c9b3213a93e57c84b472c84e0b8a0e1ae48e67a9f8f6de9d5f7f3d52ac23e48ac51801f1dc950abe901da34d2a9e3baadb141a17c77ef3c565dd5ee5054b91cf63bb3c6ab83f72ab3aafe93d0fc3c2348b764fafb0b1c0733de51459aeab46580384bf9d74c4e28164b7cde247f891ba07891c9d872ad2bb")]

View File

@ -21,7 +21,7 @@ namespace Microsoft.VisualStudio.Editor.Razor
var testImportsPath = "C:\\path\\to\\project\\_ViewImports.cshtml";
var tracker = Mock.Of<VisualStudioDocumentTracker>(t => t.FilePath == filePath && t.ProjectPath == projectPath);
var anotherTracker = Mock.Of<VisualStudioDocumentTracker>(t => t.FilePath == anotherFilePath && t.ProjectPath == projectPath);
var templateEngineFactoryService = GetTemplateEngineFactoryService();
var templateEngineFactoryService = GetProjectEngineFactoryService();
var fileChangeTracker = new Mock<FileChangeTracker>();
fileChangeTracker.Setup(f => f.FilePath).Returns(testImportsPath);
var fileChangeTrackerFactory = new Mock<FileChangeTrackerFactory>();
@ -58,12 +58,12 @@ namespace Microsoft.VisualStudio.Editor.Razor
Assert.True(called);
}
private RazorTemplateEngineFactoryService GetTemplateEngineFactoryService()
private RazorProjectEngineFactoryService GetProjectEngineFactoryService()
{
var projectManager = new Mock<ProjectSnapshotManager>();
projectManager.Setup(p => p.Projects).Returns(Array.Empty<ProjectSnapshot>());
var service = new DefaultTemplateEngineFactoryService(projectManager.Object);
var service = new DefaultProjectEngineFactoryService(projectManager.Object);
return service;
}
}

View File

@ -137,12 +137,12 @@ namespace Microsoft.VisualStudio.Editor.Razor
manager.OnUnsubscribed(tracker);
}
private RazorTemplateEngineFactoryService GetTemplateEngineFactoryService()
private RazorProjectEngineFactoryService GetTemplateEngineFactoryService()
{
var projectManager = new Mock<ProjectSnapshotManager>();
projectManager.Setup(p => p.Projects).Returns(Array.Empty<ProjectSnapshot>());
var service = new DefaultTemplateEngineFactoryService(projectManager.Object);
var service = new DefaultProjectEngineFactoryService(projectManager.Object);
return service;
}
}

View File

@ -14,9 +14,9 @@ using MvcLatest = Microsoft.AspNetCore.Mvc.Razor.Extensions;
namespace Microsoft.VisualStudio.Editor.Razor
{
public class DefaultTemplateEngineFactoryServiceTest
public class DefaultProjectEngineFactoryServiceTest
{
public DefaultTemplateEngineFactoryServiceTest()
public DefaultProjectEngineFactoryServiceTest()
{
Project project = null;
@ -35,7 +35,7 @@ namespace Microsoft.VisualStudio.Editor.Razor
public Workspace Workspace { get; }
[Fact]
public void Create_CreatesDesignTimeTemplateEngine_ForLatest()
public void Create_CreatesTemplateEngine_ForLatest()
{
// Arrange
var projectManager = new TestProjectSnapshotManager(Workspace);
@ -49,13 +49,12 @@ namespace Microsoft.VisualStudio.Editor.Razor
new ProjectExtensibilityAssembly(new AssemblyIdentity("Microsoft.AspNetCore.Razor", new Version("2.0.0.0")))),
});
var factoryService = new DefaultTemplateEngineFactoryService(projectManager);
var factoryService = new DefaultProjectEngineFactoryService(projectManager);
// Act
var engine = factoryService.Create("/TestPath/SomePath/", b =>
{
b.Features.Add(new MyCoolNewFeature());
Assert.True(b.DesignTime);
});
// Assert
@ -65,7 +64,7 @@ namespace Microsoft.VisualStudio.Editor.Razor
}
[Fact]
public void Create_CreatesDesignTimeTemplateEngine_ForVersion1_1()
public void Create_CreatesTemplateEngine_ForVersion1_1()
{
// Arrange
var projectManager = new TestProjectSnapshotManager(Workspace);
@ -79,13 +78,12 @@ namespace Microsoft.VisualStudio.Editor.Razor
new ProjectExtensibilityAssembly(new AssemblyIdentity("Microsoft.AspNetCore.Razor", new Version("1.1.3.0")))),
});
var factoryService = new DefaultTemplateEngineFactoryService(projectManager);
var factoryService = new DefaultProjectEngineFactoryService(projectManager);
// Act
var engine = factoryService.Create("/TestPath/SomePath/", b =>
{
b.Features.Add(new MyCoolNewFeature());
Assert.True(b.DesignTime);
});
// Assert
@ -109,7 +107,7 @@ namespace Microsoft.VisualStudio.Editor.Razor
new ProjectExtensibilityAssembly(new AssemblyIdentity("Microsoft.AspNetCore.Razor", new Version("1.0.0.0")))),
});
var factoryService = new DefaultTemplateEngineFactoryService(projectManager);
var factoryService = new DefaultProjectEngineFactoryService(projectManager);
// Act
var engine = factoryService.Create("/TestPath/SomePath/", b =>
@ -138,13 +136,12 @@ namespace Microsoft.VisualStudio.Editor.Razor
new ProjectExtensibilityAssembly(new AssemblyIdentity("Microsoft.AspNetCore.Razor", new Version("3.0.0.0")))),
});
var factoryService = new DefaultTemplateEngineFactoryService(projectManager);
var factoryService = new DefaultProjectEngineFactoryService(projectManager);
// Act
var engine = factoryService.Create("/TestPath/SomePath/", b =>
{
b.Features.Add(new MyCoolNewFeature());
Assert.True(b.DesignTime);
});
// Assert
@ -159,13 +156,12 @@ namespace Microsoft.VisualStudio.Editor.Razor
// Arrange
var projectManager = new TestProjectSnapshotManager(Workspace);
var factoryService = new DefaultTemplateEngineFactoryService(projectManager);
var factoryService = new DefaultProjectEngineFactoryService(projectManager);
// Act
var engine = factoryService.Create("/TestPath/DifferentPath/", b =>
{
b.Features.Add(new MyCoolNewFeature());
Assert.True(b.DesignTime);
});
// Assert
@ -181,13 +177,12 @@ namespace Microsoft.VisualStudio.Editor.Razor
var projectManager = new TestProjectSnapshotManager(Workspace);
projectManager.ProjectAdded(Project);
var factoryService = new DefaultTemplateEngineFactoryService(projectManager);
var factoryService = new DefaultProjectEngineFactoryService(projectManager);
// Act
var engine = factoryService.Create("/TestPath/DifferentPath/", b =>
{
b.Features.Add(new MyCoolNewFeature());
Assert.True(b.DesignTime);
});
// Assert

View File

@ -3,7 +3,6 @@
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Diagnostics;
using System.Linq;
using System.Threading;
@ -525,34 +524,27 @@ namespace Microsoft.VisualStudio.Editor.Razor
return new TestParserManager(parser);
}
private static RazorTemplateEngineFactoryService CreateTemplateEngineFactory(
private static RazorProjectEngineFactoryService CreateTemplateEngineFactory(
string path = TestLinePragmaFileName,
IEnumerable<TagHelperDescriptor> tagHelpers = null)
{
var engine = RazorEngine.CreateDesignTime(builder =>
var fileSystem = new TestRazorProjectFileSystem();
var projectEngine = RazorProjectEngine.Create(RazorConfiguration.Default, fileSystem, builder =>
{
RazorExtensions.Register(builder);
builder.AddDefaultImports(RazorSourceDocument.Create("@addTagHelper *, Test", "_TestImports.cshtml"));
if (tagHelpers != null)
{
builder.AddTagHelpers(tagHelpers);
}
});
// GetImports on RazorTemplateEngine will at least check that the item exists, so we need to pretend
// that it does.
var items = new List<RazorProjectItem>();
items.Add(new TestRazorProjectItem(path));
var projectEngineFactoryService = Mock.Of<RazorProjectEngineFactoryService>(
service => service.Create(It.IsAny<string>(), It.IsAny<Action<RazorProjectEngineBuilder>>()) == projectEngine);
var project = new TestRazorProjectFileSystem(items);
var templateEngine = new RazorTemplateEngine(engine, project);
templateEngine.Options.DefaultImports = RazorSourceDocument.Create("@addTagHelper *, Test", "_TestImports.cshtml");
var templateEngineFactory = Mock.Of<RazorTemplateEngineFactoryService>(
service => service.Create(It.IsAny<string>(), It.IsAny<Action<IRazorEngineBuilder>>()) == templateEngine);
return templateEngineFactory;
return projectEngineFactoryService;
}
private async Task RunTypeKeywordTestAsync(string keyword)

View File

@ -32,7 +32,7 @@ namespace Microsoft.VisualStudio.Editor.Razor
var parser = new DefaultVisualStudioRazorParser(
Dispatcher,
CreateDocumentTracker(),
Mock.Of<RazorTemplateEngineFactoryService>(),
Mock.Of<RazorProjectEngineFactoryService>(),
new DefaultErrorReporter(),
Mock.Of<VisualStudioCompletionBroker>());
parser.Dispose();
@ -48,7 +48,7 @@ namespace Microsoft.VisualStudio.Editor.Razor
var parser = new DefaultVisualStudioRazorParser(
Dispatcher,
CreateDocumentTracker(),
Mock.Of<RazorTemplateEngineFactoryService>(),
Mock.Of<RazorProjectEngineFactoryService>(),
new DefaultErrorReporter(),
Mock.Of<VisualStudioCompletionBroker>());
parser.Dispose();
@ -64,7 +64,7 @@ namespace Microsoft.VisualStudio.Editor.Razor
var parser = new DefaultVisualStudioRazorParser(
Dispatcher,
CreateDocumentTracker(),
Mock.Of<RazorTemplateEngineFactoryService>(),
Mock.Of<RazorProjectEngineFactoryService>(),
new DefaultErrorReporter(),
Mock.Of<VisualStudioCompletionBroker>());
parser.Dispose();
@ -80,7 +80,7 @@ namespace Microsoft.VisualStudio.Editor.Razor
using (var parser = new DefaultVisualStudioRazorParser(
Dispatcher,
CreateDocumentTracker(),
Mock.Of<RazorTemplateEngineFactoryService>(),
Mock.Of<RazorProjectEngineFactoryService>(),
new DefaultErrorReporter(),
Mock.Of<VisualStudioCompletionBroker>()))
{
@ -108,7 +108,7 @@ namespace Microsoft.VisualStudio.Editor.Razor
using (var parser = new DefaultVisualStudioRazorParser(
Dispatcher,
documentTracker,
Mock.Of<RazorTemplateEngineFactoryService>(),
Mock.Of<RazorProjectEngineFactoryService>(),
new DefaultErrorReporter(),
Mock.Of<VisualStudioCompletionBroker>()))
{
@ -139,7 +139,7 @@ namespace Microsoft.VisualStudio.Editor.Razor
using (var parser = new DefaultVisualStudioRazorParser(
Dispatcher,
CreateDocumentTracker(),
Mock.Of<RazorTemplateEngineFactoryService>(),
Mock.Of<RazorProjectEngineFactoryService>(),
new DefaultErrorReporter(),
Mock.Of<VisualStudioCompletionBroker>())
{
@ -169,7 +169,7 @@ namespace Microsoft.VisualStudio.Editor.Razor
using (var parser = new DefaultVisualStudioRazorParser(
Dispatcher,
CreateDocumentTracker(),
Mock.Of<RazorTemplateEngineFactoryService>(),
Mock.Of<RazorProjectEngineFactoryService>(),
new DefaultErrorReporter(),
Mock.Of<VisualStudioCompletionBroker>())
{
@ -198,7 +198,7 @@ namespace Microsoft.VisualStudio.Editor.Razor
using (var parser = new DefaultVisualStudioRazorParser(
Dispatcher,
CreateDocumentTracker(),
Mock.Of<RazorTemplateEngineFactoryService>(),
Mock.Of<RazorProjectEngineFactoryService>(),
new DefaultErrorReporter(),
Mock.Of<VisualStudioCompletionBroker>()))
{
@ -222,7 +222,7 @@ namespace Microsoft.VisualStudio.Editor.Razor
using (var parser = new DefaultVisualStudioRazorParser(
Dispatcher,
documentTracker,
Mock.Of<RazorTemplateEngineFactoryService>(),
Mock.Of<RazorProjectEngineFactoryService>(),
new DefaultErrorReporter(),
Mock.Of<VisualStudioCompletionBroker>()))
{
@ -242,7 +242,7 @@ namespace Microsoft.VisualStudio.Editor.Razor
using (var parser = new DefaultVisualStudioRazorParser(
Dispatcher,
CreateDocumentTracker(isSupportedProject: true),
Mock.Of<RazorTemplateEngineFactoryService>(),
Mock.Of<RazorProjectEngineFactoryService>(),
new DefaultErrorReporter(),
Mock.Of<VisualStudioCompletionBroker>()))
{
@ -261,7 +261,7 @@ namespace Microsoft.VisualStudio.Editor.Razor
using (var parser = new DefaultVisualStudioRazorParser(
Dispatcher,
CreateDocumentTracker(isSupportedProject: false),
Mock.Of<RazorTemplateEngineFactoryService>(),
Mock.Of<RazorProjectEngineFactoryService>(),
new DefaultErrorReporter(),
Mock.Of<VisualStudioCompletionBroker>()))
{

View File

@ -3,14 +3,12 @@
using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.AspNetCore.Mvc.Razor.Extensions;
using Microsoft.AspNetCore.Razor.Language;
using Microsoft.AspNetCore.Razor.Language.Legacy;
using Microsoft.VisualStudio.Test;
using Microsoft.VisualStudio.Text;
using Xunit;
using Span = Microsoft.AspNetCore.Razor.Language.Legacy.Span;
namespace Microsoft.VisualStudio.Editor.Razor
{
@ -44,12 +42,13 @@ namespace Microsoft.VisualStudio.Editor.Razor
{
builder.Build()
};
var templateEngine = CreateTemplateEngine(tagHelpers: descriptors);
var document = TestRazorCodeDocument.Create(
TestRazorSourceDocument.Create(edit.OldSnapshot.GetText()),
new[] { templateEngine.Options.DefaultImports });
templateEngine.Engine.Process(document);
var syntaxTree = document.GetSyntaxTree();
var projectEngine = CreateProjectEngine(tagHelpers: descriptors);
var projectItem = new TestRazorProjectItem("Index.cshtml")
{
Content = edit.OldSnapshot.GetText()
};
var codeDocument = projectEngine.Process(projectItem);
var syntaxTree = codeDocument.GetSyntaxTree();
var parser = new RazorSyntaxTreePartialParser(syntaxTree);
// Act
@ -115,12 +114,13 @@ namespace Microsoft.VisualStudio.Editor.Razor
attribute.SetPropertyName("StringAttribute");
});
var descriptors = new[] { builder.Build() };
var templateEngine = CreateTemplateEngine(tagHelpers: descriptors);
var document = TestRazorCodeDocument.Create(
TestRazorSourceDocument.Create(edit.OldSnapshot.GetText()),
new[] { templateEngine.Options.DefaultImports });
templateEngine.Engine.Process(document);
var syntaxTree = document.GetSyntaxTree();
var projectEngine = CreateProjectEngine(tagHelpers: descriptors);
var sourceDocument = new TestRazorProjectItem("Index.cshtml")
{
Content = edit.OldSnapshot.GetText()
};
var codeDocument = projectEngine.Process(sourceDocument);
var syntaxTree = codeDocument.GetSyntaxTree();
var parser = new RazorSyntaxTreePartialParser(syntaxTree);
// Act
@ -548,7 +548,7 @@ namespace Microsoft.VisualStudio.Editor.Razor
private void RunPartialParseRejectionTest(TestEdit edit, PartialParseResultInternal additionalFlags = 0)
{
var templateEngine = CreateTemplateEngine();
var templateEngine = CreateProjectEngine();
var document = TestRazorCodeDocument.Create(edit.OldSnapshot.GetText());
templateEngine.Engine.Process(document);
var syntaxTree = document.GetSyntaxTree();
@ -560,7 +560,7 @@ namespace Microsoft.VisualStudio.Editor.Razor
private static void RunPartialParseTest(TestEdit edit, Block expectedTree, PartialParseResultInternal additionalFlags = 0)
{
var templateEngine = CreateTemplateEngine();
var templateEngine = CreateProjectEngine();
var document = TestRazorCodeDocument.Create(edit.OldSnapshot.GetText());
templateEngine.Engine.Process(document);
var syntaxTree = document.GetSyntaxTree();
@ -580,30 +580,24 @@ namespace Microsoft.VisualStudio.Editor.Razor
return new TestEdit(sourceChange, oldSnapshot, changedSnapshot);
}
private static RazorTemplateEngine CreateTemplateEngine(
private static RazorProjectEngine CreateProjectEngine(
string path = "C:\\This\\Path\\Is\\Just\\For\\Line\\Pragmas.cshtml",
IEnumerable<TagHelperDescriptor> tagHelpers = null)
{
var engine = RazorEngine.CreateDesignTime(builder =>
var fileSystem = new TestRazorProjectFileSystem();
var projectEngine = RazorProjectEngine.Create(RazorConfiguration.Default, fileSystem, builder =>
{
RazorExtensions.Register(builder);
builder.AddDefaultImports(RazorSourceDocument.Create("@addTagHelper *, Test", "_TestImports.cshtml"));
if (tagHelpers != null)
{
builder.AddTagHelpers(tagHelpers);
}
});
// GetImports on RazorTemplateEngine will at least check that the item exists, so we need to pretend
// that it does.
var items = new List<RazorProjectItem>();
items.Add(new TestRazorProjectItem(path));
var project = new TestRazorProjectFileSystem(items);
var templateEngine = new RazorTemplateEngine(engine, project);
templateEngine.Options.DefaultImports = RazorSourceDocument.Create("@addTagHelper *, Test", "_TestImports.cshtml");
return templateEngine;
return projectEngine;
}
}
}

View File

@ -35,9 +35,10 @@ namespace RazorPageGenerator.Test
{
// Arrange
var projectDirectory = TestProject.GetProjectDirectory(GetType());
var razorEngine = Program.CreateRazorEngine("Microsoft.AspNetCore.TestGenerated");
var projectEngine = Program.CreateProjectEngine("Microsoft.AspNetCore.TestGenerated", projectDirectory);
// Act
var results = Program.MainCore(razorEngine, projectDirectory);
var results = Program.MainCore(projectEngine, projectDirectory);
// Assert
Assert.Collection(results,