diff --git a/src/Microsoft.Blazor.Build/Core/RazorCompilation/RazorCompiler.cs b/src/Microsoft.Blazor.Build/Core/RazorCompilation/RazorCompiler.cs
index 4bb29643db..8e2fcb3042 100644
--- a/src/Microsoft.Blazor.Build/Core/RazorCompilation/RazorCompiler.cs
+++ b/src/Microsoft.Blazor.Build/Core/RazorCompilation/RazorCompiler.cs
@@ -1,30 +1,91 @@
// 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.IO;
+using System.Linq;
+using System.Text.RegularExpressions;
namespace Microsoft.Blazor.Build.Core.RazorCompilation
{
+ ///
+ /// Provides facilities for transforming Razor files into Blazor component classes.
+ ///
public class RazorCompiler
{
- public ICollection CompileFiles(IEnumerable inputPaths, string outputNamespace, TextWriter resultOutput, TextWriter verboseOutput)
- {
- var diagnostics = new List();
+ // TODO: Relax this to allow for whatever C# allows
+ private static Regex ClassNameRegex
+ = new Regex("^[a-z][a-z0-9_]*$", RegexOptions.IgnoreCase);
- foreach (var inputFilePath in inputPaths)
+ ///
+ /// Writes C# source code representing Blazor components defined by Razor files.
+ ///
+ /// Paths to the input files.
+ /// The namespace for the generated classes.
+ /// A to which C# source code will be written.
+ /// If not null, additional information will be written to this .
+ /// A collection of instances representing any warnings or errors that were encountered.
+ public ICollection CompileFiles(IEnumerable inputPaths, string outputNamespace, TextWriter resultOutput, TextWriter verboseOutput)
+ => inputPaths.SelectMany(
+ path => CompileSingleFile(path, outputNamespace, resultOutput, verboseOutput)).ToList();
+
+ ///
+ /// Writes C# source code representing a Blazor component defined by a Razor file.
+ ///
+ /// The path to the input file.
+ /// The namespace for the generated class.
+ /// A to which C# source code will be written.
+ /// If not null, additional information will be written to this .
+ /// An enumerable of instances representing any warnings or errors that were encountered.
+ public IEnumerable CompileSingleFile(string inputFilePath, string outputNamespace, TextWriter resultOutput, TextWriter verboseOutput)
+ {
+ if (resultOutput == null)
{
- verboseOutput?.WriteLine($"Compiling {inputFilePath}...");
- resultOutput.WriteLine($"// TODO: Compile {inputFilePath}");
- diagnostics.Add(new RazorCompilerDiagnostic(
- RazorCompilerDiagnostic.DiagnosticType.Warning,
- inputFilePath,
- 1,
- 1,
- "Compiler not implemented"));
+ throw new ArgumentNullException(nameof(resultOutput));
}
- return diagnostics;
+ try
+ {
+ verboseOutput?.WriteLine($"Compiling {inputFilePath}...");
+ var className = GetClassName(inputFilePath);
+
+ resultOutput.WriteLine($"namespace {outputNamespace} {{");
+ resultOutput.WriteLine($"public class {className}");
+ resultOutput.WriteLine("{");
+ resultOutput.WriteLine("}");
+ resultOutput.WriteLine("}");
+ resultOutput.WriteLine();
+
+ return Enumerable.Empty();
+ }
+ catch (RazorCompilerException ex)
+ {
+ return new[] { ex.ToDiagnostic(inputFilePath) };
+ }
+ catch (Exception ex)
+ {
+ return new[]
+ {
+ new RazorCompilerDiagnostic(
+ RazorCompilerDiagnostic.DiagnosticType.Error,
+ inputFilePath,
+ 1,
+ 1,
+ $"Unexpected exception: {ex.Message}{Environment.NewLine}{ex.StackTrace}")
+ };
+ }
+ }
+
+ private static string GetClassName(string inputFilePath)
+ {
+ var basename = Path.GetFileNameWithoutExtension(inputFilePath);
+ if (!ClassNameRegex.IsMatch(basename))
+ {
+ throw new RazorCompilerException($"Invalid name '{basename}'. The name must be valid for a C# class name.");
+ }
+
+ return basename;
}
}
}
diff --git a/src/Microsoft.Blazor.Build/Core/RazorCompilation/RazorCompilerException.cs b/src/Microsoft.Blazor.Build/Core/RazorCompilation/RazorCompilerException.cs
new file mode 100644
index 0000000000..27508c5985
--- /dev/null
+++ b/src/Microsoft.Blazor.Build/Core/RazorCompilation/RazorCompilerException.cs
@@ -0,0 +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;
+
+namespace Microsoft.Blazor.Build.Core.RazorCompilation
+{
+ ///
+ /// Represents a fatal error during the transformation of a Blazor component from
+ /// Razor source code to C# source code.
+ ///
+ internal class RazorCompilerException : Exception
+ {
+ public RazorCompilerException(string message): base(message)
+ {
+ }
+
+ public RazorCompilerDiagnostic ToDiagnostic(string sourceFilePath)
+ => new RazorCompilerDiagnostic(
+ RazorCompilerDiagnostic.DiagnosticType.Error,
+ sourceFilePath,
+ line: 1, // Later it might be necessary to take line/col constructor args, but not needed yet
+ column: 1,
+ message: Message);
+ }
+}
diff --git a/src/Microsoft.Blazor.Build/targets/RazorCompilation.targets b/src/Microsoft.Blazor.Build/targets/RazorCompilation.targets
index 8682a2a1b2..290fc0e884 100644
--- a/src/Microsoft.Blazor.Build/targets/RazorCompilation.targets
+++ b/src/Microsoft.Blazor.Build/targets/RazorCompilation.targets
@@ -1,9 +1,4 @@
-
-
-
-
+
BlazorComponents