diff --git a/Razor.sln b/Razor.sln index 81568c0722..c59344b6c9 100644 --- a/Razor.sln +++ b/Razor.sln @@ -1,7 +1,6 @@ - Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio 14 -VisualStudioVersion = 14.0.24720.0 +VisualStudioVersion = 14.0.25420.1 MinimumVisualStudioVersion = 10.0.40219.1 Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{3C0D6505-79B3-49D0-B4C3-176F0F1836ED}" EndProject @@ -23,6 +22,10 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution NuGet.config = NuGet.config EndProjectSection EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "tools", "tools", "{A53A3B44-0456-4832-87F6-5BA85224851C}" +EndProject +Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "RazorPageGenerator", "tools\RazorPageGenerator\RazorPageGenerator.xproj", "{0FC7CE11-DC10-499E-8B91-8D9CADAEFBEB}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -49,6 +52,10 @@ Global {E3A2A305-634D-4BA6-95DB-AA06D6C442B0}.Debug|Any CPU.Build.0 = Debug|Any CPU {E3A2A305-634D-4BA6-95DB-AA06D6C442B0}.Release|Any CPU.ActiveCfg = Release|Any CPU {E3A2A305-634D-4BA6-95DB-AA06D6C442B0}.Release|Any CPU.Build.0 = Release|Any CPU + {0FC7CE11-DC10-499E-8B91-8D9CADAEFBEB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {0FC7CE11-DC10-499E-8B91-8D9CADAEFBEB}.Debug|Any CPU.Build.0 = Debug|Any CPU + {0FC7CE11-DC10-499E-8B91-8D9CADAEFBEB}.Release|Any CPU.ActiveCfg = Release|Any CPU + {0FC7CE11-DC10-499E-8B91-8D9CADAEFBEB}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -59,5 +66,6 @@ Global {D0196096-1B01-4133-AACE-1A10A0F7247C} = {3C0D6505-79B3-49D0-B4C3-176F0F1836ED} {0535998A-E32C-4D1A-80D1-0B15A513C471} = {92463391-81BE-462B-AC3C-78C6C760741F} {E3A2A305-634D-4BA6-95DB-AA06D6C442B0} = {3C0D6505-79B3-49D0-B4C3-176F0F1836ED} + {0FC7CE11-DC10-499E-8B91-8D9CADAEFBEB} = {A53A3B44-0456-4832-87F6-5BA85224851C} EndGlobalSection EndGlobal diff --git a/tools/RazorPageGenerator/Program.cs b/tools/RazorPageGenerator/Program.cs new file mode 100644 index 0000000000..02210e1352 --- /dev/null +++ b/tools/RazorPageGenerator/Program.cs @@ -0,0 +1,120 @@ +// 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.Linq; +using Microsoft.AspNetCore.Razor; +using Microsoft.AspNetCore.Razor.CodeGenerators; + +namespace RazorPageGenerator +{ + public class Program + { + public static void Main(string[] args) + { + if (args == null || args.Length != 1) + { + Console.WriteLine("Invalid argument(s)."); + Console.WriteLine("Usage: dotnet razorpagegenerator "); + Console.WriteLine("Example: dotnet razorpagegenerator Microsoft.AspNetCore.Diagnostics.RazorViews"); + return; + } + + var rootNamespace = args[0]; + var targetProjectDirectory = Directory.GetCurrentDirectory(); + + + var viewDirectories = Directory.EnumerateDirectories(targetProjectDirectory, "Views", SearchOption.AllDirectories); + + var fileCount = 0; + foreach (var viewDir in viewDirectories) + { + Console.WriteLine(); + Console.WriteLine(" Generating code files for views in {0}", viewDir); + + var cshtmlFiles = Directory.EnumerateFiles(viewDir, "*.cshtml"); + + if (!cshtmlFiles.Any()) + { + Console.WriteLine(" No .cshtml files were found."); + continue; + } + + foreach (var fileName in cshtmlFiles) + { + Console.WriteLine(" Generating code file for view {0}...", Path.GetFileName(fileName)); + GenerateCodeFile(fileName, rootNamespace); + Console.WriteLine(" Done!"); + fileCount++; + } + } + + Console.WriteLine(); + Console.WriteLine("{0} files successfully generated.", fileCount); + Console.WriteLine(); + } + + private static void GenerateCodeFile(string cshtmlFilePath, string rootNamespace) + { + var basePath = Path.GetDirectoryName(cshtmlFilePath); + var fileName = Path.GetFileName(cshtmlFilePath); + var fileNameNoExtension = Path.GetFileNameWithoutExtension(fileName); + var codeLang = new CSharpRazorCodeLanguage(); + var host = new RazorEngineHost(codeLang); + 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); + cshtmlContent = ProcessFileIncludes(basePath, cshtmlContent); + + var generatorResults = engine.GenerateCode( + 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) + { + 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. 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(Path.Combine(basePath, includeFileName)); + cshtmlContent = cshtmlContent.Substring(0, startIndex) + includeFileContent + cshtmlContent.Substring(endIndex + endMatch.Length); + startIndex = startIndex + includeFileContent.Length; + } + return cshtmlContent; + } + } +} diff --git a/tools/RazorPageGenerator/RazorPageGenerator.xproj b/tools/RazorPageGenerator/RazorPageGenerator.xproj new file mode 100644 index 0000000000..950e957d69 --- /dev/null +++ b/tools/RazorPageGenerator/RazorPageGenerator.xproj @@ -0,0 +1,19 @@ + + + + 14.0.25420 + $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) + + + + 0fc7ce11-dc10-499e-8b91-8d9cadaefbeb + RazorPageGenerator + .\obj + .\bin\ + + + + 2.0 + + + \ No newline at end of file diff --git a/tools/RazorPageGenerator/project.json b/tools/RazorPageGenerator/project.json new file mode 100644 index 0000000000..56ecbcbab3 --- /dev/null +++ b/tools/RazorPageGenerator/project.json @@ -0,0 +1,19 @@ +{ + "version": "1.1.0-*", + "description": "Builds Razor pages for views in a project", + "buildOptions": { + "warningsAsErrors": true, + "emitEntryPoint": true, + "outputName": "dotnet-razorpagegenerator" + }, + "dependencies": { + "Microsoft.AspNetCore.Razor": "1.1.0-*", + "Microsoft.NETCore.App": { + "version": "1.0.0", + "type": "platform" + } + }, + "frameworks": { + "netcoreapp1.0": {} + } +} \ No newline at end of file