Remove references to Razor from RazorPageGenerator

This commit is contained in:
Pranav K 2017-02-22 19:16:38 -08:00
parent 3772c7c343
commit c83741f11c
5 changed files with 187 additions and 62 deletions

View File

@ -19,7 +19,7 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution
NuGet.config = NuGet.config NuGet.config = NuGet.config
EndProjectSection EndProjectSection
EndProject EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "RazorPageGenerator", "src\RazorPageGenerator\RazorPageGenerator.csproj", "{7BE58880-36AD-4CD5-9E16-2A5AFEA790EF}" Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "RazorPageGenerator", "src\RazorPageGenerator\RazorPageGenerator.csproj", "{7BE58880-36AD-4CD5-9E16-2A5AFEA790EF}"
EndProject EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.Razor.Evolution", "src\Microsoft.AspNetCore.Razor.Evolution\Microsoft.AspNetCore.Razor.Evolution.csproj", "{932F3C9C-A6C0-40D3-BA50-9309886242FC}" Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.Razor.Evolution", "src\Microsoft.AspNetCore.Razor.Evolution\Microsoft.AspNetCore.Razor.Evolution.csproj", "{932F3C9C-A6C0-40D3-BA50-9309886242FC}"
EndProject EndProject

View File

@ -4,6 +4,7 @@
using System; using System;
using System.Linq; using System.Linq;
using Microsoft.AspNetCore.Razor.Evolution.CodeGeneration; using Microsoft.AspNetCore.Razor.Evolution.CodeGeneration;
using Microsoft.AspNetCore.Razor.Evolution.Intermediate;
namespace Microsoft.AspNetCore.Razor.Evolution namespace Microsoft.AspNetCore.Razor.Evolution
{ {
@ -57,6 +58,48 @@ namespace Microsoft.AspNetCore.Razor.Evolution
return builder; return builder;
} }
public static IRazorEngineBuilder SetClassName(this IRazorEngineBuilder builder, string className)
{
if (builder == null)
{
throw new ArgumentNullException(nameof(builder));
}
ConfigureClass(builder, (document, @class) => @class.Name = className);
return builder;
}
public static IRazorEngineBuilder ConfigureClass(
this IRazorEngineBuilder builder,
Action<RazorCodeDocument, ClassDeclarationIRNode> 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;
}
public static IRazorEngineBuilder SetNamespace(this IRazorEngineBuilder 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;
}
private static IRazorDirectiveFeature GetDirectiveFeature(IRazorEngineBuilder builder) private static IRazorDirectiveFeature GetDirectiveFeature(IRazorEngineBuilder builder)
{ {
var directiveFeature = builder.Features.OfType<IRazorDirectiveFeature>().FirstOrDefault(); var directiveFeature = builder.Features.OfType<IRazorDirectiveFeature>().FirstOrDefault();

View File

@ -2,10 +2,11 @@
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System; using System;
using System.Collections.Generic;
using System.IO; using System.IO;
using System.Linq; using System.Linq;
using Microsoft.AspNetCore.Razor; using System.Text;
using Microsoft.AspNetCore.Razor.CodeGenerators; using Microsoft.AspNetCore.Razor.Evolution;
namespace RazorPageGenerator namespace RazorPageGenerator
{ {
@ -23,7 +24,20 @@ namespace RazorPageGenerator
var rootNamespace = args[0]; var rootNamespace = args[0];
var targetProjectDirectory = Directory.GetCurrentDirectory(); var targetProjectDirectory = Directory.GetCurrentDirectory();
var razorEngine = RazorEngine.Create(builder =>
{
builder
.SetNamespace(rootNamespace)
.SetBaseType("Microsoft.Extensions.RazorViews.BaseView")
.ConfigureClass((document, @class) =>
{
@class.Name = Path.GetFileNameWithoutExtension(document.Source.Filename);
@class.AccessModifier = "internal";
});
builder.Features.Add(new RemovePragamaChecksumFeature());
});
var viewDirectories = Directory.EnumerateDirectories(targetProjectDirectory, "Views", SearchOption.AllDirectories); var viewDirectories = Directory.EnumerateDirectories(targetProjectDirectory, "Views", SearchOption.AllDirectories);
@ -32,8 +46,11 @@ namespace RazorPageGenerator
{ {
Console.WriteLine(); Console.WriteLine();
Console.WriteLine(" Generating code files for views in {0}", viewDir); Console.WriteLine(" Generating code files for views in {0}", viewDir);
var razorProject = new FileSystemRazorProject(viewDir);
var templateEngine = new RazorTemplateEngine(razorEngine, razorProject);
var cshtmlFiles = Directory.EnumerateFiles(viewDir, "*.cshtml");
var cshtmlFiles = razorProject.EnumerateItems("");
if (!cshtmlFiles.Any()) if (!cshtmlFiles.Any())
{ {
@ -41,10 +58,10 @@ namespace RazorPageGenerator
continue; continue;
} }
foreach (var fileName in cshtmlFiles) foreach (var item in cshtmlFiles)
{ {
Console.WriteLine(" Generating code file for view {0}...", Path.GetFileName(fileName)); Console.WriteLine(" Generating code file for view {0}...", item.Filename);
GenerateCodeFile(fileName, rootNamespace); GenerateCodeFile(templateEngine, item);
Console.WriteLine(" Done!"); Console.WriteLine(" Done!");
fileCount++; fileCount++;
} }
@ -55,66 +72,104 @@ namespace RazorPageGenerator
Console.WriteLine(); Console.WriteLine();
} }
private static void GenerateCodeFile(string cshtmlFilePath, string rootNamespace) private static void GenerateCodeFile(RazorTemplateEngine templateEngine, RazorProjectItem projectItem)
{ {
var basePath = Path.GetDirectoryName(cshtmlFilePath); var cSharpDocument = templateEngine.GenerateCode(projectItem);
var fileName = Path.GetFileName(cshtmlFilePath); if (cSharpDocument.Diagnostics.Any())
var fileNameNoExtension = Path.GetFileNameWithoutExtension(fileName); {
var codeLang = new CSharpRazorCodeLanguage(); var diagnostics = string.Join(Environment.NewLine, cSharpDocument.Diagnostics);
var host = new RazorEngineHost(codeLang); Console.WriteLine($"One or more parse errors encountered. This will not prevent the generator from continuing: {Environment.NewLine}{diagnostics}.");
host.DefaultBaseClass = "Microsoft.Extensions.RazorViews.BaseView"; }
host.GeneratedClassContext = new GeneratedClassContext(
executeMethodName: GeneratedClassContext.DefaultExecuteMethodName,
writeMethodName: GeneratedClassContext.DefaultWriteMethodName,
writeLiteralMethodName: GeneratedClassContext.DefaultWriteLiteralMethodName,
writeToMethodName: "WriteTo",
writeLiteralToMethodName: "WriteLiteralTo",
templateTypeName: "HelperResult",
defineSectionMethodName: "DefineSection",
generatedTagHelperContext: new GeneratedTagHelperContext());
var engine = new RazorTemplateEngine(host);
var cshtmlContent = File.ReadAllText(cshtmlFilePath); var generatedCodeFilePath = Path.ChangeExtension(
cshtmlContent = ProcessFileIncludes(basePath, cshtmlContent); ((FileSystemRazorProjectItem)projectItem).FileInfo.FullName,
".Designer.cs");
var generatorResults = engine.GenerateCode( File.WriteAllText(generatedCodeFilePath, cSharpDocument.GeneratedCode);
input: new StringReader(cshtmlContent),
className: fileNameNoExtension,
rootNamespace: Path.GetFileName(rootNamespace),
sourceFileName: fileName);
var generatedCode = generatorResults.GeneratedCode;
// Make the generated class 'internal' instead of 'public'
generatedCode = generatedCode.Replace("public class", "internal class");
File.WriteAllText(Path.Combine(basePath, string.Format("{0}.Designer.cs", fileNameNoExtension)), generatedCode);
} }
private static string ProcessFileIncludes(string basePath, string cshtmlContent) private class FileSystemRazorProject : RazorProject
{ {
var startMatch = "<%$ include: "; private readonly string _basePath;
var endMatch = " %>";
var startIndex = 0; public FileSystemRazorProject(string basePath)
while (startIndex < cshtmlContent.Length)
{ {
startIndex = cshtmlContent.IndexOf(startMatch, startIndex); _basePath = basePath;
if (startIndex == -1) }
{
break; public override IEnumerable<RazorProjectItem> EnumerateItems(string basePath)
} {
var endIndex = cshtmlContent.IndexOf(endMatch, startIndex); return new DirectoryInfo(_basePath)
if (endIndex == -1) .EnumerateFiles("*.cshtml", SearchOption.TopDirectoryOnly)
{ .Select(file => GetItem(basePath, file));
throw new InvalidOperationException("Invalid include file format. Usage example: <%$ include: ErrorPage.js %>"); }
}
var includeFileName = cshtmlContent.Substring(startIndex + startMatch.Length, endIndex - (startIndex + startMatch.Length)); public override RazorProjectItem GetItem(string path) => throw new NotSupportedException();
Console.WriteLine(" Inlining file {0}", includeFileName);
var includeFileContent = File.ReadAllText(Path.Combine(basePath, includeFileName)); private RazorProjectItem GetItem(string basePath, FileInfo file)
cshtmlContent = cshtmlContent.Substring(0, startIndex) + includeFileContent + cshtmlContent.Substring(endIndex + endMatch.Length); {
startIndex = startIndex + includeFileContent.Length; if (!file.Exists)
{
throw new FileNotFoundException($"{file.FullName} does not exist.");
}
return new FileSystemRazorProjectItem(basePath, file);
}
}
private class FileSystemRazorProjectItem : RazorProjectItem
{
public FileSystemRazorProjectItem(string basePath, FileInfo fileInfo)
{
BasePath = basePath;
Path = fileInfo.Name;
FileInfo = fileInfo;
}
public FileInfo FileInfo { get; }
public override string BasePath { get; }
public override string Path { get; }
// Mask the full name since we don't want a developer's local file paths to be commited.
public override string PhysicalPath => FileInfo.Name;
public override bool Exists => true;
public override Stream Read()
{
var processedContent = ProcessFileIncludes();
return new MemoryStream(Encoding.UTF8.GetBytes(processedContent));
}
private string ProcessFileIncludes()
{
var basePath = FileInfo.DirectoryName;
var cshtmlContent = File.ReadAllText(FileInfo.FullName);
var startMatch = "<%$ include: ";
var endMatch = " %>";
var startIndex = 0;
while (startIndex < cshtmlContent.Length)
{
startIndex = cshtmlContent.IndexOf(startMatch, startIndex);
if (startIndex == -1)
{
break;
}
var endIndex = cshtmlContent.IndexOf(endMatch, startIndex);
if (endIndex == -1)
{
throw new InvalidOperationException($"Invalid include file format in {FileInfo.FullName}. Usage example: <%$ include: ErrorPage.js %>");
}
var includeFileName = cshtmlContent.Substring(startIndex + startMatch.Length, endIndex - (startIndex + startMatch.Length));
Console.WriteLine(" Inlining file {0}", includeFileName);
var includeFileContent = File.ReadAllText(System.IO.Path.Combine(basePath, includeFileName));
cshtmlContent = cshtmlContent.Substring(0, startIndex) + includeFileContent + cshtmlContent.Substring(endIndex + endMatch.Length);
startIndex = startIndex + includeFileContent.Length;
}
return cshtmlContent;
} }
return cshtmlContent;
} }
} }
} }

View File

@ -1,4 +1,4 @@
<Project Sdk="Microsoft.NET.Sdk.Web"> <Project Sdk="Microsoft.NET.Sdk">
<Import Project="..\..\build\common.props" /> <Import Project="..\..\build\common.props" />
@ -11,7 +11,7 @@
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<ProjectReference Include="..\Microsoft.AspNetCore.Razor\Microsoft.AspNetCore.Razor.csproj" /> <ProjectReference Include="..\Microsoft.AspNetCore.Razor.Evolution\Microsoft.AspNetCore.Razor.Evolution.csproj" />
</ItemGroup> </ItemGroup>
</Project> </Project>

View File

@ -0,0 +1,27 @@
using System;
using Microsoft.AspNetCore.Razor.Evolution;
using Microsoft.AspNetCore.Razor.Evolution.Intermediate;
namespace RazorPageGenerator
{
class RemovePragamaChecksumFeature : RazorIRPassBase, IRazorIROptimizationPass
{
public override void ExecuteCore(RazorCodeDocument codeDocument, DocumentIRNode irDocument)
{
var walker = new Walker();
walker.Visit(irDocument);
walker.ChecksumNode.Parent.Children.Remove(walker.ChecksumNode);
}
private class Walker : RazorIRNodeWalker
{
public ChecksumIRNode ChecksumNode { get; private set; }
public override void VisitChecksum(ChecksumIRNode node)
{
ChecksumNode = node;
}
}
}
}