From 8d4491d4b86eab1e9b406571adb38cd85782f647 Mon Sep 17 00:00:00 2001 From: Steve Sanderson Date: Thu, 11 Jan 2018 10:31:49 +0000 Subject: [PATCH] Begin Razor build command --- .../Cli/Commands/BuildRazorCommand.cs | 80 +++++++++++++++++++ src/Microsoft.Blazor.Build/Cli/Program.cs | 1 + .../Core/RazorCompilation/RazorCompiler.cs | 30 +++++++ .../RazorCompilerDiagnostic.cs | 40 ++++++++++ .../targets/RazorCompilation.targets | 5 +- 5 files changed, 152 insertions(+), 4 deletions(-) create mode 100644 src/Microsoft.Blazor.Build/Cli/Commands/BuildRazorCommand.cs create mode 100644 src/Microsoft.Blazor.Build/Core/RazorCompilation/RazorCompiler.cs create mode 100644 src/Microsoft.Blazor.Build/Core/RazorCompilation/RazorCompilerDiagnostic.cs diff --git a/src/Microsoft.Blazor.Build/Cli/Commands/BuildRazorCommand.cs b/src/Microsoft.Blazor.Build/Cli/Commands/BuildRazorCommand.cs new file mode 100644 index 0000000000..0a9280bac2 --- /dev/null +++ b/src/Microsoft.Blazor.Build/Cli/Commands/BuildRazorCommand.cs @@ -0,0 +1,80 @@ +// 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 Microsoft.Blazor.Build.Core.RazorCompilation; +using Microsoft.Extensions.CommandLineUtils; +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; + +namespace Microsoft.Blazor.Build.Cli.Commands +{ + internal class BuildRazorCommand + { + public static void Command(CommandLineApplication command) + { + // Later, we might want to have the complete list of inputs passed in from MSBuild + // so developers can include/exclude whatever they want. The MVC Razor view precompiler + // does this by writing the list to a temporary 'response' file then passing the path + // to that file into its build executable (see: https://github.com/aspnet/MvcPrecompilation/blob/dev/src/Microsoft.AspNetCore.Mvc.Razor.ViewCompilation/build/netstandard2.0/Microsoft.AspNetCore.Mvc.Razor.ViewCompilation.targets) + // For now it's sufficient to assume we want to include '**\*.cshtml' + var sourceDirPath = command.Option("--source", + "The path to the directory containing Razor files", + CommandOptionType.SingleValue); + var outputFilePath = command.Option("--output", + "The location where the resulting C# source file should be written", + CommandOptionType.SingleValue); + var verboseFlag = command.Option("--verbose", + "Indicates that verbose console output should written", + CommandOptionType.NoValue); + + command.OnExecute(() => + { + if (!VerifyRequiredOptionsProvided(sourceDirPath, outputFilePath)) + { + return 1; + } + + var sourceDirPathValue = sourceDirPath.Value(); + if (!Directory.Exists(sourceDirPathValue)) + { + Console.WriteLine($"ERROR: Directory not found: {sourceDirPathValue}"); + return 1; + } + + var inputRazorFilePaths = FindRazorFiles(sourceDirPathValue).ToList(); + using (var outputWriter = new StreamWriter(outputFilePath.Value())) + { + var diagnostics = new RazorCompiler().CompileFiles( + inputRazorFilePaths, + "Blazor", // TODO: Add required option for namespace + outputWriter, + verboseFlag.HasValue() ? Console.Out : null); + + foreach (var diagnostic in diagnostics) + { + Console.WriteLine(diagnostic.FormatForConsole()); + } + + var hasError = diagnostics.Any(item => item.Type == RazorCompilerDiagnostic.DiagnosticType.Error); + return hasError ? 1 : 0; + } + }); + } + + private static IEnumerable FindRazorFiles(string rootDirPath) + => Directory.GetFiles(rootDirPath, "*.cshtml", SearchOption.AllDirectories); + + private static bool VerifyRequiredOptionsProvided(params CommandOption[] options) + { + var violations = options.Where(o => !o.HasValue()).ToList(); + foreach (var violation in violations) + { + Console.WriteLine($"ERROR: No value specified for required option '{violation.LongName}'."); + } + + return !violations.Any(); + } + } +} diff --git a/src/Microsoft.Blazor.Build/Cli/Program.cs b/src/Microsoft.Blazor.Build/Cli/Program.cs index 43397c486c..5fb15fbd4f 100644 --- a/src/Microsoft.Blazor.Build/Cli/Program.cs +++ b/src/Microsoft.Blazor.Build/Cli/Program.cs @@ -17,6 +17,7 @@ namespace Microsoft.Blazor.Build app.HelpOption("-?|-h|--help"); app.Command("build", BuildCommand.Command); + app.Command("buildrazor", BuildRazorCommand.Command); if (args.Length > 0) { diff --git a/src/Microsoft.Blazor.Build/Core/RazorCompilation/RazorCompiler.cs b/src/Microsoft.Blazor.Build/Core/RazorCompilation/RazorCompiler.cs new file mode 100644 index 0000000000..4bb29643db --- /dev/null +++ b/src/Microsoft.Blazor.Build/Core/RazorCompilation/RazorCompiler.cs @@ -0,0 +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.Collections.Generic; +using System.IO; + +namespace Microsoft.Blazor.Build.Core.RazorCompilation +{ + public class RazorCompiler + { + public ICollection CompileFiles(IEnumerable inputPaths, string outputNamespace, TextWriter resultOutput, TextWriter verboseOutput) + { + var diagnostics = new List(); + + foreach (var inputFilePath in inputPaths) + { + verboseOutput?.WriteLine($"Compiling {inputFilePath}..."); + resultOutput.WriteLine($"// TODO: Compile {inputFilePath}"); + diagnostics.Add(new RazorCompilerDiagnostic( + RazorCompilerDiagnostic.DiagnosticType.Warning, + inputFilePath, + 1, + 1, + "Compiler not implemented")); + } + + return diagnostics; + } + } +} diff --git a/src/Microsoft.Blazor.Build/Core/RazorCompilation/RazorCompilerDiagnostic.cs b/src/Microsoft.Blazor.Build/Core/RazorCompilation/RazorCompilerDiagnostic.cs new file mode 100644 index 0000000000..10a18f645f --- /dev/null +++ b/src/Microsoft.Blazor.Build/Core/RazorCompilation/RazorCompilerDiagnostic.cs @@ -0,0 +1,40 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +namespace Microsoft.Blazor.Build.Core.RazorCompilation +{ + public class RazorCompilerDiagnostic + { + public DiagnosticType Type { get; } + public string SourceFilePath { get; } + public int Line { get; } + public int Column { get; } + public string Message { get; } + + internal RazorCompilerDiagnostic( + DiagnosticType type, + string sourceFilePath, + int line, + int column, + string message) + { + Type = type; + SourceFilePath = sourceFilePath; + Line = line; + Column = column; + Message = message; + } + + public enum DiagnosticType + { + Warning, + Error + } + + public string FormatForConsole() + => $"{SourceFilePath}({Line},{Column}): {FormatTypeAndCodeForConsole()}: {Message}"; + + private string FormatTypeAndCodeForConsole() + => $"{Type.ToString().ToLowerInvariant()} Blazor"; + } +} diff --git a/src/Microsoft.Blazor.Build/targets/RazorCompilation.targets b/src/Microsoft.Blazor.Build/targets/RazorCompilation.targets index 0ebdfe6848..8682a2a1b2 100644 --- a/src/Microsoft.Blazor.Build/targets/RazorCompilation.targets +++ b/src/Microsoft.Blazor.Build/targets/RazorCompilation.targets @@ -5,15 +5,12 @@ that the Razor components can be referenced with intellisense from .cs files. --> - - - BlazorComponents true $(IntermediateOutputPath)BlazorRazorComponents.g.cs - +