diff --git a/src/Razor/Microsoft.AspNetCore.Razor.Language/src/Components/ComponentDocumentClassifierPass.cs b/src/Razor/Microsoft.AspNetCore.Razor.Language/src/Components/ComponentDocumentClassifierPass.cs index 2e1f24cdb5..a48f49994f 100644 --- a/src/Razor/Microsoft.AspNetCore.Razor.Language/src/Components/ComponentDocumentClassifierPass.cs +++ b/src/Razor/Microsoft.AspNetCore.Razor.Language/src/Components/ComponentDocumentClassifierPass.cs @@ -22,7 +22,7 @@ namespace Microsoft.AspNetCore.Razor.Language.Components protected override bool IsMatch(RazorCodeDocument codeDocument, DocumentIntermediateNode documentNode) { - return codeDocument.GetInputDocumentKind() == InputDocumentKind.Component; + return string.Equals(codeDocument.GetFileKind(), FileKinds.Component); } protected override void OnDocumentStructureCreated(RazorCodeDocument codeDocument, NamespaceDeclarationIntermediateNode @namespace, ClassDeclarationIntermediateNode @class, MethodDeclarationIntermediateNode method) diff --git a/src/Razor/Microsoft.AspNetCore.Razor.Language/src/DefaultRazorProjectEngine.cs b/src/Razor/Microsoft.AspNetCore.Razor.Language/src/DefaultRazorProjectEngine.cs index a560a0030a..4b9b50ef8e 100644 --- a/src/Razor/Microsoft.AspNetCore.Razor.Language/src/DefaultRazorProjectEngine.cs +++ b/src/Razor/Microsoft.AspNetCore.Razor.Language/src/DefaultRazorProjectEngine.cs @@ -68,10 +68,10 @@ namespace Microsoft.AspNetCore.Razor.Language var importItems = importFeature.GetImports(projectItem); var importSourceDocuments = GetImportSourceDocuments(importItems); - return CreateCodeDocumentCore(sourceDocument, importSourceDocuments, tagHelpers: null); + return CreateCodeDocumentCore(sourceDocument, projectItem.FileKind, importSourceDocuments, tagHelpers: null); } - internal override RazorCodeDocument CreateCodeDocumentCore(RazorSourceDocument sourceDocument, IReadOnlyList importSourceDocuments, IReadOnlyList tagHelpers) + internal override RazorCodeDocument CreateCodeDocumentCore(RazorSourceDocument sourceDocument, string fileKind, IReadOnlyList importSourceDocuments, IReadOnlyList tagHelpers) { if (sourceDocument == null) { @@ -84,6 +84,11 @@ namespace Microsoft.AspNetCore.Razor.Language var codeDocument = RazorCodeDocument.Create(sourceDocument, importSourceDocuments, parserOptions, codeGenerationOptions); codeDocument.SetTagHelpers(tagHelpers); + if (fileKind != null) + { + codeDocument.SetFileKind(fileKind); + } + return codeDocument; } @@ -100,10 +105,10 @@ namespace Microsoft.AspNetCore.Razor.Language var importItems = importFeature.GetImports(projectItem); var importSourceDocuments = GetImportSourceDocuments(importItems, suppressExceptions: true); - return CreateCodeDocumentDesignTimeCore(sourceDocument, importSourceDocuments, tagHelpers: null); + return CreateCodeDocumentDesignTimeCore(sourceDocument, projectItem.FileKind, importSourceDocuments, tagHelpers: null); } - internal override RazorCodeDocument CreateCodeDocumentDesignTimeCore(RazorSourceDocument sourceDocument, IReadOnlyList importSourceDocuments, IReadOnlyList tagHelpers) + internal override RazorCodeDocument CreateCodeDocumentDesignTimeCore(RazorSourceDocument sourceDocument, string fileKind, IReadOnlyList importSourceDocuments, IReadOnlyList tagHelpers) { if (sourceDocument == null) { @@ -116,6 +121,11 @@ namespace Microsoft.AspNetCore.Razor.Language var codeDocument = RazorCodeDocument.Create(sourceDocument, importSourceDocuments, parserOptions, codeGenerationOptions); codeDocument.SetTagHelpers(tagHelpers); + if (fileKind != null) + { + codeDocument.SetFileKind(fileKind); + } + return codeDocument; } diff --git a/src/Razor/Microsoft.AspNetCore.Razor.Language/src/DefaultRazorProjectFileSystem.cs b/src/Razor/Microsoft.AspNetCore.Razor.Language/src/DefaultRazorProjectFileSystem.cs index 9283088cd1..8fdefe7d1c 100644 --- a/src/Razor/Microsoft.AspNetCore.Razor.Language/src/DefaultRazorProjectFileSystem.cs +++ b/src/Razor/Microsoft.AspNetCore.Razor.Language/src/DefaultRazorProjectFileSystem.cs @@ -34,12 +34,13 @@ namespace Microsoft.AspNetCore.Razor.Language return directory .EnumerateFiles("*.cshtml", SearchOption.AllDirectories) + .Concat(directory.EnumerateFiles("*.razor", SearchOption.AllDirectories)) .Select(file => { var relativePhysicalPath = file.FullName.Substring(absoluteBasePath.Length + 1); // Include leading separator var filePath = "/" + relativePhysicalPath.Replace(Path.DirectorySeparatorChar, '/'); - return new DefaultRazorProjectItem(basePath, filePath, relativePhysicalPath, file); + return new DefaultRazorProjectItem(basePath, filePath, relativePhysicalPath, fileKind: null, file); }); } @@ -57,7 +58,7 @@ namespace Microsoft.AspNetCore.Razor.Language var relativePhysicalPath = file.FullName.Substring(absoluteBasePath.Length + 1); // Include leading separator var filePath = "/" + relativePhysicalPath.Replace(Path.DirectorySeparatorChar, '/'); - return new DefaultRazorProjectItem("/", filePath, relativePhysicalPath, new FileInfo(absolutePath)); + return new DefaultRazorProjectItem("/", filePath, relativePhysicalPath, fileKind: null, new FileInfo(absolutePath)); } protected override string NormalizeAndEnsureValidPath(string path) diff --git a/src/Razor/Microsoft.AspNetCore.Razor.Language/src/DefaultRazorProjectItem.cs b/src/Razor/Microsoft.AspNetCore.Razor.Language/src/DefaultRazorProjectItem.cs index 5a3590a121..082ed4666a 100644 --- a/src/Razor/Microsoft.AspNetCore.Razor.Language/src/DefaultRazorProjectItem.cs +++ b/src/Razor/Microsoft.AspNetCore.Razor.Language/src/DefaultRazorProjectItem.cs @@ -7,18 +7,22 @@ namespace Microsoft.AspNetCore.Razor.Language { internal class DefaultRazorProjectItem : RazorProjectItem { + private readonly string _fileKind; + /// /// Initializes a new instance of . /// /// The base path. /// The physical path of the base path. /// The path. + /// The file kind. If null, the document kind will be inferred from the file extension. /// The . - public DefaultRazorProjectItem(string basePath, string filePath, string relativePhysicalPath, FileInfo file) + public DefaultRazorProjectItem(string basePath, string filePath, string relativePhysicalPath, string fileKind, FileInfo file) { BasePath = basePath; FilePath = filePath; RelativePhysicalPath = relativePhysicalPath; + _fileKind = fileKind; File = file; } @@ -34,6 +38,8 @@ namespace Microsoft.AspNetCore.Razor.Language public override string RelativePhysicalPath { get; } + public override string FileKind => _fileKind ?? base.FileKind; + public override Stream Read() => new FileStream(PhysicalPath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite | FileShare.Delete); } } \ No newline at end of file diff --git a/src/Razor/Microsoft.AspNetCore.Razor.Language/src/Intermediate/InputDocumentKind.cs b/src/Razor/Microsoft.AspNetCore.Razor.Language/src/FileKinds.cs similarity index 61% rename from src/Razor/Microsoft.AspNetCore.Razor.Language/src/Intermediate/InputDocumentKind.cs rename to src/Razor/Microsoft.AspNetCore.Razor.Language/src/FileKinds.cs index 7adf2bd8b5..a1163e702e 100644 --- a/src/Razor/Microsoft.AspNetCore.Razor.Language/src/Intermediate/InputDocumentKind.cs +++ b/src/Razor/Microsoft.AspNetCore.Razor.Language/src/FileKinds.cs @@ -1,12 +1,12 @@ // 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.AspNetCore.Razor.Language.Intermediate +namespace Microsoft.AspNetCore.Razor.Language { - internal static class InputDocumentKind + internal static class FileKinds { public static readonly string Component = "component"; - public static readonly string MvcFile = "mvc"; + public static readonly string Legacy = "mvc"; } } diff --git a/src/Razor/Microsoft.AspNetCore.Razor.Language/src/RazorCodeDocumentExtensions.cs b/src/Razor/Microsoft.AspNetCore.Razor.Language/src/RazorCodeDocumentExtensions.cs index 6b0a9fde9e..5d31bfcf73 100644 --- a/src/Razor/Microsoft.AspNetCore.Razor.Language/src/RazorCodeDocumentExtensions.cs +++ b/src/Razor/Microsoft.AspNetCore.Razor.Language/src/RazorCodeDocumentExtensions.cs @@ -169,24 +169,24 @@ namespace Microsoft.AspNetCore.Razor.Language document.Items[typeof(RazorCodeGenerationOptions)] = codeGenerationOptions; } - public static string GetInputDocumentKind(this RazorCodeDocument document) + public static string GetFileKind(this RazorCodeDocument document) { if (document == null) { throw new ArgumentNullException(nameof(document)); } - return (string)document.Items[typeof(InputDocumentKind)]; + return (string)document.Items[typeof(FileKinds)]; } - public static void SetInputDocumentKind(this RazorCodeDocument document, string kind) + public static void SetFileKind(this RazorCodeDocument document, string fileKind) { if (document == null) { throw new ArgumentNullException(nameof(document)); } - document.Items[typeof(InputDocumentKind)] = kind; + document.Items[typeof(FileKinds)] = fileKind; } private class ImportSyntaxTreesHolder diff --git a/src/Razor/Microsoft.AspNetCore.Razor.Language/src/RazorProjectEngine.cs b/src/Razor/Microsoft.AspNetCore.Razor.Language/src/RazorProjectEngine.cs index d37936dbd6..e6ef8738c7 100644 --- a/src/Razor/Microsoft.AspNetCore.Razor.Language/src/RazorProjectEngine.cs +++ b/src/Razor/Microsoft.AspNetCore.Razor.Language/src/RazorProjectEngine.cs @@ -35,14 +35,14 @@ namespace Microsoft.AspNetCore.Razor.Language return codeDocument; } - internal virtual RazorCodeDocument Process(RazorSourceDocument source, IReadOnlyList importSources, IReadOnlyList tagHelpers) + internal virtual RazorCodeDocument Process(RazorSourceDocument source, string fileKind, IReadOnlyList importSources, IReadOnlyList tagHelpers) { if (source == null) { throw new ArgumentNullException(nameof(source)); } - var codeDocument = CreateCodeDocumentCore(source, importSources, tagHelpers); + var codeDocument = CreateCodeDocumentCore(source, fileKind, importSources, tagHelpers); ProcessCore(codeDocument); return codeDocument; } @@ -59,30 +59,40 @@ namespace Microsoft.AspNetCore.Razor.Language return codeDocument; } - internal virtual RazorCodeDocument ProcessDesignTime(RazorSourceDocument source, IReadOnlyList importSources, IReadOnlyList tagHelpers) + internal virtual RazorCodeDocument ProcessDesignTime(RazorSourceDocument source, string fileKind, IReadOnlyList importSources, IReadOnlyList tagHelpers) { if (source == null) { throw new ArgumentNullException(nameof(source)); } - var codeDocument = CreateCodeDocumentDesignTimeCore(source, importSources, tagHelpers); + var codeDocument = CreateCodeDocumentDesignTimeCore(source, fileKind, importSources, tagHelpers); ProcessCore(codeDocument); return codeDocument; } protected abstract RazorCodeDocument CreateCodeDocumentCore(RazorProjectItem projectItem); - internal virtual RazorCodeDocument CreateCodeDocumentCore(RazorSourceDocument source, IReadOnlyList importSources, IReadOnlyList tagHelpers) + internal virtual RazorCodeDocument CreateCodeDocumentCore(RazorSourceDocument source, string fileKind, IReadOnlyList importSources, IReadOnlyList tagHelpers) { - return RazorCodeDocument.Create(source, importSources); + var codeDocument = RazorCodeDocument.Create(source, importSources); + if (fileKind != null) + { + codeDocument.SetFileKind(fileKind); + } + return codeDocument; } protected abstract RazorCodeDocument CreateCodeDocumentDesignTimeCore(RazorProjectItem projectItem); - internal virtual RazorCodeDocument CreateCodeDocumentDesignTimeCore(RazorSourceDocument source, IReadOnlyList importSources, IReadOnlyList tagHelpers) + internal virtual RazorCodeDocument CreateCodeDocumentDesignTimeCore(RazorSourceDocument source, string fileKind, IReadOnlyList importSources, IReadOnlyList tagHelpers) { - return RazorCodeDocument.Create(source, importSources); + var codeDocument = RazorCodeDocument.Create(source, importSources); + if (fileKind != null) + { + codeDocument.SetFileKind(fileKind); + } + return codeDocument; } protected abstract void ProcessCore(RazorCodeDocument codeDocument); diff --git a/src/Razor/Microsoft.AspNetCore.Razor.Language/src/RazorProjectItem.cs b/src/Razor/Microsoft.AspNetCore.Razor.Language/src/RazorProjectItem.cs index 6aecb94daa..cdc50b8948 100644 --- a/src/Razor/Microsoft.AspNetCore.Razor.Language/src/RazorProjectItem.cs +++ b/src/Razor/Microsoft.AspNetCore.Razor.Language/src/RazorProjectItem.cs @@ -1,8 +1,11 @@ // 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.Diagnostics; using System.IO; +using Microsoft.AspNetCore.Razor.Language.Components; +using Microsoft.AspNetCore.Razor.Language.Intermediate; namespace Microsoft.AspNetCore.Razor.Language { @@ -35,6 +38,28 @@ namespace Microsoft.AspNetCore.Razor.Language /// public virtual string RelativePhysicalPath => null; + /// + /// Gets the document kind that should be used for the generated document. If possible this will be inferred from the file path. May be null. + /// + public virtual string FileKind + { + get + { + if (FilePath == null) + { + return null; + } + else if (string.Equals(".razor", Path.GetExtension(FilePath), StringComparison.OrdinalIgnoreCase)) + { + return FileKinds.Component; + } + else + { + return FileKinds.Legacy; + } + } + } + /// /// Gets the file contents as readonly . /// diff --git a/src/Razor/Microsoft.AspNetCore.Razor.Tools/src/GenerateCommand.cs b/src/Razor/Microsoft.AspNetCore.Razor.Tools/src/GenerateCommand.cs index 338c496033..401183445f 100644 --- a/src/Razor/Microsoft.AspNetCore.Razor.Tools/src/GenerateCommand.cs +++ b/src/Razor/Microsoft.AspNetCore.Razor.Tools/src/GenerateCommand.cs @@ -23,7 +23,7 @@ namespace Microsoft.AspNetCore.Razor.Tools Sources = Option("-s", ".cshtml files to compile", CommandOptionType.MultipleValue); Outputs = Option("-o", "Generated output file path", CommandOptionType.MultipleValue); RelativePaths = Option("-r", "Relative path", CommandOptionType.MultipleValue); - DocumentKinds = Option("-k", "Document kind", CommandOptionType.MultipleValue); + FileKinds = Option("-k", "File kind", CommandOptionType.MultipleValue); ProjectDirectory = Option("-p", "project root directory", CommandOptionType.SingleValue); TagHelperManifest = Option("-t", "tag helper manifest file", CommandOptionType.SingleValue); Version = Option("-v|--version", "Razor language version", CommandOptionType.SingleValue); @@ -39,7 +39,7 @@ namespace Microsoft.AspNetCore.Razor.Tools public CommandOption RelativePaths { get; } - public CommandOption DocumentKinds { get; } + public CommandOption FileKinds { get; } public CommandOption ProjectDirectory { get; } @@ -74,7 +74,7 @@ namespace Microsoft.AspNetCore.Razor.Tools var version = RazorLanguageVersion.Parse(Version.Value()); var configuration = RazorConfiguration.Create(version, Configuration.Value(), extensions); - var sourceItems = GetSourceItems(ProjectDirectory.Value(), Sources.Values, Outputs.Values, RelativePaths.Values, DocumentKinds.Values); + var sourceItems = GetSourceItems(ProjectDirectory.Value(), Sources.Values, Outputs.Values, RelativePaths.Values, FileKinds.Values); var result = ExecuteCore( configuration: configuration, @@ -105,11 +105,11 @@ namespace Microsoft.AspNetCore.Razor.Tools return false; } - if (DocumentKinds.Values.Count != 0 && DocumentKinds.Values.Count != Sources.Values.Count) + if (FileKinds.Values.Count != 0 && FileKinds.Values.Count != Sources.Values.Count) { - // 2.x tasks do not specify DocumentKinds - in which case, no values will be present. If a kind for one document is specified, we expect as many kind entries + // 2.x tasks do not specify FileKinds - in which case, no values will be present. If a kind for one file is specified, we expect as many kind entries // as sources. - Error.WriteLine($"{Sources.Description} has {Sources.Values.Count}, but {DocumentKinds.Description} has {DocumentKinds.Values.Count} values."); + Error.WriteLine($"{Sources.Description} has {Sources.Values.Count}, but {FileKinds.Description} has {FileKinds.Values.Count} values."); return false; } @@ -171,7 +171,6 @@ namespace Microsoft.AspNetCore.Razor.Tools var engine = RazorProjectEngine.Create(configuration, compositeFileSystem, b => { b.Features.Add(new StaticTagHelperFeature() { TagHelpers = tagHelpers, }); - b.Features.Add(new InputDocumentKindClassifierPass(sourceItems)); if (GenerateDeclaration.HasValue()) { @@ -223,6 +222,7 @@ namespace Microsoft.AspNetCore.Razor.Tools basePath: "/", filePath: item.FilePath, relativePhysicalPath: item.RelativePhysicalPath, + fileKind: item.FileKind, file: new FileInfo(item.SourcePath)); project.Add(projectItem); @@ -251,15 +251,15 @@ namespace Microsoft.AspNetCore.Razor.Tools } } - private SourceItem[] GetSourceItems(string projectDirectory, List sources, List outputs, List relativePath, List documentKinds) + private SourceItem[] GetSourceItems(string projectDirectory, List sources, List outputs, List relativePath, List fileKinds) { var items = new SourceItem[sources.Count]; for (var i = 0; i < items.Length; i++) { var outputPath = Path.Combine(projectDirectory, outputs[i]); - var documentKind = documentKinds.Count > 0 ? documentKinds[i] : "mvc"; + var fileKind = fileKinds.Count > 0 ? fileKinds[i] : "mvc"; - items[i] = new SourceItem(sources[i], outputs[i], relativePath[i], documentKind); + items[i] = new SourceItem(sources[i], outputs[i], relativePath[i], fileKind); } return items; @@ -297,7 +297,7 @@ namespace Microsoft.AspNetCore.Razor.Tools private readonly struct SourceItem { - public SourceItem(string sourcePath, string outputPath, string physicalRelativePath, string documentKind) + public SourceItem(string sourcePath, string outputPath, string physicalRelativePath, string fileKind) { SourcePath = sourcePath; OutputPath = outputPath; @@ -305,7 +305,7 @@ namespace Microsoft.AspNetCore.Razor.Tools FilePath = '/' + physicalRelativePath .Replace(Path.DirectorySeparatorChar, '/') .Replace("//", "/"); - DocumentKind = documentKind; + FileKind = fileKind; } public string SourcePath { get; } @@ -316,7 +316,7 @@ namespace Microsoft.AspNetCore.Razor.Tools public string FilePath { get; } - public string DocumentKind { get; } + public string FileKind { get; } } private class StaticTagHelperFeature : ITagHelperFeature @@ -342,31 +342,5 @@ namespace Microsoft.AspNetCore.Razor.Tools options.SuppressPrimaryMethodBody = true; } } - - private class InputDocumentKindClassifierPass : RazorEngineFeatureBase, IRazorDocumentClassifierPass - { - public InputDocumentKindClassifierPass(SourceItem[] sourceItems) - { - DocumentKinds = new Dictionary(sourceItems.Length, StringComparer.OrdinalIgnoreCase); - for (var i = 0; i < sourceItems.Length; i++) - { - var item = sourceItems[i]; - DocumentKinds[item.SourcePath] = item.DocumentKind; - } - } - - // Run before other document classifiers - public int Order => -1000; - - public Dictionary DocumentKinds { get; } - - public void Execute(RazorCodeDocument codeDocument, DocumentIntermediateNode documentNode) - { - if (DocumentKinds.TryGetValue(codeDocument.Source.FilePath, out var kind)) - { - codeDocument.SetInputDocumentKind(kind); - } - } - } } } diff --git a/src/Razor/test/Microsoft.AspNetCore.Razor.Test.Common/Language/TestRazorProjectItem.cs b/src/Razor/test/Microsoft.AspNetCore.Razor.Test.Common/Language/TestRazorProjectItem.cs index d4f03fbf0d..e811043206 100644 --- a/src/Razor/test/Microsoft.AspNetCore.Razor.Test.Common/Language/TestRazorProjectItem.cs +++ b/src/Razor/test/Microsoft.AspNetCore.Razor.Test.Common/Language/TestRazorProjectItem.cs @@ -8,20 +8,26 @@ namespace Microsoft.AspNetCore.Razor.Language { public class TestRazorProjectItem : RazorProjectItem { + private readonly string _fileKind; + public TestRazorProjectItem( string filePath, string physicalPath = null, string relativePhysicalPath = null, - string basePath = "/") + string basePath = "/", + string fileKind = null) { FilePath = filePath; PhysicalPath = physicalPath; RelativePhysicalPath = relativePhysicalPath; BasePath = basePath; + _fileKind = fileKind; } public override string BasePath { get; } + public override string FileKind => _fileKind ?? base.FileKind; + public override string FilePath { get; } public override string PhysicalPath { get; }