Add support for relative paths
* Move path munging in to Razor SDK * Use AssignTargetPath to determine the target path for outputs and embedded resources Fixes #1829 Fixes #1847 Fixes #1999
This commit is contained in:
parent
5a93f68ccc
commit
84beb5985f
|
|
@ -36,3 +36,5 @@ global.json
|
||||||
BenchmarkDotNet.Artifacts/
|
BenchmarkDotNet.Artifacts/
|
||||||
Microsoft.VisualStudio.RazorExtension.nuget.props
|
Microsoft.VisualStudio.RazorExtension.nuget.props
|
||||||
Microsoft.VisualStudio.RazorExtension.nuget.targets
|
Microsoft.VisualStudio.RazorExtension.nuget.targets
|
||||||
|
msbuild.binlog
|
||||||
|
msbuild.log
|
||||||
|
|
|
||||||
|
|
@ -25,9 +25,9 @@
|
||||||
-->
|
-->
|
||||||
<Target
|
<Target
|
||||||
Name="_HashRazorGenerateInputs"
|
Name="_HashRazorGenerateInputs"
|
||||||
Condition="'@(RazorGenerate)'!=''">
|
Condition="'@(RazorGenerateWithTargetPath)' != ''">
|
||||||
|
|
||||||
<Hash ItemsToHash="@(RazorGenerate)">
|
<Hash ItemsToHash="@(RazorGenerateWithTargetPath)">
|
||||||
<Output TaskParameter="HashResult" PropertyName="_RazorGenerateInputsHash" />
|
<Output TaskParameter="HashResult" PropertyName="_RazorGenerateInputsHash" />
|
||||||
</Hash>
|
</Hash>
|
||||||
|
|
||||||
|
|
@ -51,7 +51,7 @@
|
||||||
DependsOnTargets="Compile"
|
DependsOnTargets="Compile"
|
||||||
Inputs="$(MSBuildAllProjects);@(RazorReferencePath)"
|
Inputs="$(MSBuildAllProjects);@(RazorReferencePath)"
|
||||||
Outputs="$(_RazorTagHelperInputCache)"
|
Outputs="$(_RazorTagHelperInputCache)"
|
||||||
Condition="'@(RazorGenerate)'!=''">
|
Condition="'@(RazorGenerateWithTargetPath)' != ''">
|
||||||
|
|
||||||
<!--
|
<!--
|
||||||
We're manipulating our output directly here because we want to separate the actual up-to-date check
|
We're manipulating our output directly here because we want to separate the actual up-to-date check
|
||||||
|
|
@ -81,9 +81,13 @@
|
||||||
</RazorTagHelper>
|
</RazorTagHelper>
|
||||||
</Target>
|
</Target>
|
||||||
|
|
||||||
<Target Name="_ResolveRazorGenerateOutputs">
|
<Target Name="_ResolveRazorGenerateOutputs" Condition="'@(RazorGenerateWithTargetPath)' != ''">
|
||||||
|
<Error
|
||||||
|
Text="RazorGenerateWithTargetPath item '%(RazorGenerateWithTargetPath.Identity)' does not specify required metadata 'GeneratedOutput'."
|
||||||
|
Condition="'%(RazorGenerateWithTargetPath.GeneratedOutput)' == ''" />
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<_RazorGenerateOutput Include="%(RazorGenerate.GeneratedOutput)" Condition="'%(RazorGenerate.GeneratedOutput)'!=''"/>
|
<_RazorGenerateOutput Include="%(RazorGenerateWithTargetPath.GeneratedOutput)" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
</Target>
|
</Target>
|
||||||
|
|
||||||
|
|
@ -97,9 +101,9 @@
|
||||||
<Target
|
<Target
|
||||||
Name="RazorCoreGenerate"
|
Name="RazorCoreGenerate"
|
||||||
DependsOnTargets="$(RazorCoreGenerateDependsOn)"
|
DependsOnTargets="$(RazorCoreGenerateDependsOn)"
|
||||||
Inputs="$(MSBuildAllProjects);$(_RazorGenerateInputsHashFile);$(_RazorTagHelperOutputCache);@(RazorGenerate)"
|
Inputs="$(MSBuildAllProjects);$(_RazorGenerateInputsHashFile);$(_RazorTagHelperOutputCache);@(RazorGenerateWithTargetPath)"
|
||||||
Outputs="@(_RazorGenerateOutput)"
|
Outputs="@(_RazorGenerateOutput)"
|
||||||
Condition="'@(RazorGenerate)'!= ''">
|
Condition="'@(RazorGenerateWithTargetPath)'!= ''">
|
||||||
|
|
||||||
<RemoveDir
|
<RemoveDir
|
||||||
Directories="$(RazorGenerateIntermediateOutputPath)"
|
Directories="$(RazorGenerateIntermediateOutputPath)"
|
||||||
|
|
@ -115,10 +119,9 @@
|
||||||
ToolAssembly="$(_RazorToolAssembly)"
|
ToolAssembly="$(_RazorToolAssembly)"
|
||||||
UseServer="$(UseRazorBuildServer)"
|
UseServer="$(UseRazorBuildServer)"
|
||||||
PipeName="$(_RazorBuildServerPipeName)"
|
PipeName="$(_RazorBuildServerPipeName)"
|
||||||
Sources="@(RazorGenerate)"
|
Sources="@(RazorGenerateWithTargetPath)"
|
||||||
ProjectRoot="$(MSBuildProjectDirectory)"
|
ProjectRoot="$(MSBuildProjectDirectory)"
|
||||||
TagHelperManifest="$(_RazorTagHelperOutputCache)"
|
TagHelperManifest="$(_RazorTagHelperOutputCache)" />
|
||||||
OutputPath="$(RazorGenerateIntermediateOutputPath)" />
|
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<FileWrites Include="@(_RazorGenerateOutput)" />
|
<FileWrites Include="@(_RazorGenerateOutput)" />
|
||||||
|
|
@ -132,18 +135,6 @@
|
||||||
<Target Name="_ResolveGeneratedRazorCompileInputs">
|
<Target Name="_ResolveGeneratedRazorCompileInputs">
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<RazorCompile Include="@(_RazorGenerateOutput)" />
|
<RazorCompile Include="@(_RazorGenerateOutput)" />
|
||||||
<RazorEmbeddedResource Include="@(RazorGenerate)" Condition="$(EmbedRazorGenerateSources)">
|
|
||||||
<LogicalName>/$([System.String]::Copy('%(Identity)').Replace('\','/'))</LogicalName>
|
|
||||||
<Type>Non-Resx</Type>
|
|
||||||
<WithCulture>false</WithCulture>
|
|
||||||
</RazorEmbeddedResource>
|
|
||||||
</ItemGroup>
|
|
||||||
|
|
||||||
<!-- Similar to _GenerateCompileInputs -->
|
|
||||||
<ItemGroup>
|
|
||||||
<_RazorCoreCompileResourceInputs
|
|
||||||
Include="@(RazorEmbeddedResource)"
|
|
||||||
Condition="'%(RazorEmbeddedResource.WithCulture)'=='false' and '%(RazorEmbeddedResource.Type)'=='Non-Resx' " />
|
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
</Target>
|
</Target>
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -8,7 +8,7 @@ using System.Linq;
|
||||||
|
|
||||||
namespace Microsoft.AspNetCore.Razor.Language
|
namespace Microsoft.AspNetCore.Razor.Language
|
||||||
{
|
{
|
||||||
internal class FileSystemRazorProject : RazorProject
|
internal class FileSystemRazorProject : RazorProjectFileSystem
|
||||||
{
|
{
|
||||||
public FileSystemRazorProject(string root)
|
public FileSystemRazorProject(string root)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -8,6 +8,8 @@ using System.Runtime.CompilerServices;
|
||||||
[assembly: InternalsVisibleTo("Microsoft.AspNetCore.Razor.Language.Test, PublicKey=0024000004800000940000000602000000240000525341310004000001000100f33a29044fa9d740c9b3213a93e57c84b472c84e0b8a0e1ae48e67a9f8f6de9d5f7f3d52ac23e48ac51801f1dc950abe901da34d2a9e3baadb141a17c77ef3c565dd5ee5054b91cf63bb3c6ab83f72ab3aafe93d0fc3c2348b764fafb0b1c0733de51459aeab46580384bf9d74c4e28164b7cde247f891ba07891c9d872ad2bb")]
|
[assembly: InternalsVisibleTo("Microsoft.AspNetCore.Razor.Language.Test, PublicKey=0024000004800000940000000602000000240000525341310004000001000100f33a29044fa9d740c9b3213a93e57c84b472c84e0b8a0e1ae48e67a9f8f6de9d5f7f3d52ac23e48ac51801f1dc950abe901da34d2a9e3baadb141a17c77ef3c565dd5ee5054b91cf63bb3c6ab83f72ab3aafe93d0fc3c2348b764fafb0b1c0733de51459aeab46580384bf9d74c4e28164b7cde247f891ba07891c9d872ad2bb")]
|
||||||
[assembly: InternalsVisibleTo("Microsoft.AspNetCore.Razor.TagHelperTool, PublicKey=0024000004800000940000000602000000240000525341310004000001000100f33a29044fa9d740c9b3213a93e57c84b472c84e0b8a0e1ae48e67a9f8f6de9d5f7f3d52ac23e48ac51801f1dc950abe901da34d2a9e3baadb141a17c77ef3c565dd5ee5054b91cf63bb3c6ab83f72ab3aafe93d0fc3c2348b764fafb0b1c0733de51459aeab46580384bf9d74c4e28164b7cde247f891ba07891c9d872ad2bb")]
|
[assembly: InternalsVisibleTo("Microsoft.AspNetCore.Razor.TagHelperTool, PublicKey=0024000004800000940000000602000000240000525341310004000001000100f33a29044fa9d740c9b3213a93e57c84b472c84e0b8a0e1ae48e67a9f8f6de9d5f7f3d52ac23e48ac51801f1dc950abe901da34d2a9e3baadb141a17c77ef3c565dd5ee5054b91cf63bb3c6ab83f72ab3aafe93d0fc3c2348b764fafb0b1c0733de51459aeab46580384bf9d74c4e28164b7cde247f891ba07891c9d872ad2bb")]
|
||||||
[assembly: InternalsVisibleTo("Microsoft.AspNetCore.Razor.Test.Common, PublicKey=0024000004800000940000000602000000240000525341310004000001000100f33a29044fa9d740c9b3213a93e57c84b472c84e0b8a0e1ae48e67a9f8f6de9d5f7f3d52ac23e48ac51801f1dc950abe901da34d2a9e3baadb141a17c77ef3c565dd5ee5054b91cf63bb3c6ab83f72ab3aafe93d0fc3c2348b764fafb0b1c0733de51459aeab46580384bf9d74c4e28164b7cde247f891ba07891c9d872ad2bb")]
|
[assembly: InternalsVisibleTo("Microsoft.AspNetCore.Razor.Test.Common, PublicKey=0024000004800000940000000602000000240000525341310004000001000100f33a29044fa9d740c9b3213a93e57c84b472c84e0b8a0e1ae48e67a9f8f6de9d5f7f3d52ac23e48ac51801f1dc950abe901da34d2a9e3baadb141a17c77ef3c565dd5ee5054b91cf63bb3c6ab83f72ab3aafe93d0fc3c2348b764fafb0b1c0733de51459aeab46580384bf9d74c4e28164b7cde247f891ba07891c9d872ad2bb")]
|
||||||
|
[assembly: InternalsVisibleTo("Microsoft.AspNetCore.Razor.Tools.Test, PublicKey=0024000004800000940000000602000000240000525341310004000001000100f33a29044fa9d740c9b3213a93e57c84b472c84e0b8a0e1ae48e67a9f8f6de9d5f7f3d52ac23e48ac51801f1dc950abe901da34d2a9e3baadb141a17c77ef3c565dd5ee5054b91cf63bb3c6ab83f72ab3aafe93d0fc3c2348b764fafb0b1c0733de51459aeab46580384bf9d74c4e28164b7cde247f891ba07891c9d872ad2bb")]
|
||||||
|
[assembly: InternalsVisibleTo("rzc, PublicKey=0024000004800000940000000602000000240000525341310004000001000100f33a29044fa9d740c9b3213a93e57c84b472c84e0b8a0e1ae48e67a9f8f6de9d5f7f3d52ac23e48ac51801f1dc950abe901da34d2a9e3baadb141a17c77ef3c565dd5ee5054b91cf63bb3c6ab83f72ab3aafe93d0fc3c2348b764fafb0b1c0733de51459aeab46580384bf9d74c4e28164b7cde247f891ba07891c9d872ad2bb")]
|
||||||
[assembly: InternalsVisibleTo("Microsoft.CodeAnalysis.Razor, PublicKey=0024000004800000940000000602000000240000525341310004000001000100f33a29044fa9d740c9b3213a93e57c84b472c84e0b8a0e1ae48e67a9f8f6de9d5f7f3d52ac23e48ac51801f1dc950abe901da34d2a9e3baadb141a17c77ef3c565dd5ee5054b91cf63bb3c6ab83f72ab3aafe93d0fc3c2348b764fafb0b1c0733de51459aeab46580384bf9d74c4e28164b7cde247f891ba07891c9d872ad2bb")]
|
[assembly: InternalsVisibleTo("Microsoft.CodeAnalysis.Razor, PublicKey=0024000004800000940000000602000000240000525341310004000001000100f33a29044fa9d740c9b3213a93e57c84b472c84e0b8a0e1ae48e67a9f8f6de9d5f7f3d52ac23e48ac51801f1dc950abe901da34d2a9e3baadb141a17c77ef3c565dd5ee5054b91cf63bb3c6ab83f72ab3aafe93d0fc3c2348b764fafb0b1c0733de51459aeab46580384bf9d74c4e28164b7cde247f891ba07891c9d872ad2bb")]
|
||||||
[assembly: InternalsVisibleTo("Microsoft.CodeAnalysis.Razor.Test, PublicKey=0024000004800000940000000602000000240000525341310004000001000100f33a29044fa9d740c9b3213a93e57c84b472c84e0b8a0e1ae48e67a9f8f6de9d5f7f3d52ac23e48ac51801f1dc950abe901da34d2a9e3baadb141a17c77ef3c565dd5ee5054b91cf63bb3c6ab83f72ab3aafe93d0fc3c2348b764fafb0b1c0733de51459aeab46580384bf9d74c4e28164b7cde247f891ba07891c9d872ad2bb")]
|
[assembly: InternalsVisibleTo("Microsoft.CodeAnalysis.Razor.Test, PublicKey=0024000004800000940000000602000000240000525341310004000001000100f33a29044fa9d740c9b3213a93e57c84b472c84e0b8a0e1ae48e67a9f8f6de9d5f7f3d52ac23e48ac51801f1dc950abe901da34d2a9e3baadb141a17c77ef3c565dd5ee5054b91cf63bb3c6ab83f72ab3aafe93d0fc3c2348b764fafb0b1c0733de51459aeab46580384bf9d74c4e28164b7cde247f891ba07891c9d872ad2bb")]
|
||||||
[assembly: InternalsVisibleTo("Microsoft.CodeAnalysis.Razor.Workspaces.Test, PublicKey=0024000004800000940000000602000000240000525341310004000001000100f33a29044fa9d740c9b3213a93e57c84b472c84e0b8a0e1ae48e67a9f8f6de9d5f7f3d52ac23e48ac51801f1dc950abe901da34d2a9e3baadb141a17c77ef3c565dd5ee5054b91cf63bb3c6ab83f72ab3aafe93d0fc3c2348b764fafb0b1c0733de51459aeab46580384bf9d74c4e28164b7cde247f891ba07891c9d872ad2bb")]
|
[assembly: InternalsVisibleTo("Microsoft.CodeAnalysis.Razor.Workspaces.Test, PublicKey=0024000004800000940000000602000000240000525341310004000001000100f33a29044fa9d740c9b3213a93e57c84b472c84e0b8a0e1ae48e67a9f8f6de9d5f7f3d52ac23e48ac51801f1dc950abe901da34d2a9e3baadb141a17c77ef3c565dd5ee5054b91cf63bb3c6ab83f72ab3aafe93d0fc3c2348b764fafb0b1c0733de51459aeab46580384bf9d74c4e28164b7cde247f891ba07891c9d872ad2bb")]
|
||||||
|
|
|
||||||
|
|
@ -1870,6 +1870,34 @@ namespace Microsoft.AspNetCore.Razor.Language
|
||||||
internal static string FormatRazorLanguageVersion_InvalidVersion(object p0)
|
internal static string FormatRazorLanguageVersion_InvalidVersion(object p0)
|
||||||
=> string.Format(CultureInfo.CurrentCulture, GetString("RazorLanguageVersion_InvalidVersion"), p0);
|
=> string.Format(CultureInfo.CurrentCulture, GetString("RazorLanguageVersion_InvalidVersion"), p0);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// File path '{0}' does not belong to the directory '{1}'.
|
||||||
|
/// </summary>
|
||||||
|
internal static string VirtualFileSystem_FileDoesNotBelongToDirectory
|
||||||
|
{
|
||||||
|
get => GetString("VirtualFileSystem_FileDoesNotBelongToDirectory");
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// File path '{0}' does not belong to the directory '{1}'.
|
||||||
|
/// </summary>
|
||||||
|
internal static string FormatVirtualFileSystem_FileDoesNotBelongToDirectory(object p0, object p1)
|
||||||
|
=> string.Format(CultureInfo.CurrentCulture, GetString("VirtualFileSystem_FileDoesNotBelongToDirectory"), p0, p1);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The file path '{0}' is invalid. File path is the root relative path of the file starting with '/' and should not contain any '\' characters.
|
||||||
|
/// </summary>
|
||||||
|
internal static string VirtualFileSystem_InvalidRelativePath
|
||||||
|
{
|
||||||
|
get => GetString("VirtualFileSystem_InvalidRelativePath");
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The file path '{0}' is invalid. File path is the root relative path of the file starting with '/' and should not contain any '\' characters.
|
||||||
|
/// </summary>
|
||||||
|
internal static string FormatVirtualFileSystem_InvalidRelativePath(object p0)
|
||||||
|
=> string.Format(CultureInfo.CurrentCulture, GetString("VirtualFileSystem_InvalidRelativePath"), p0);
|
||||||
|
|
||||||
private static string GetString(string name, params string[] formatterNames)
|
private static string GetString(string name, params string[] formatterNames)
|
||||||
{
|
{
|
||||||
var value = _resourceManager.GetString(name);
|
var value = _resourceManager.GetString(name);
|
||||||
|
|
|
||||||
|
|
@ -5,5 +5,14 @@ namespace Microsoft.AspNetCore.Razor.Language
|
||||||
{
|
{
|
||||||
public abstract class RazorProjectFileSystem : RazorProject
|
public abstract class RazorProjectFileSystem : RazorProject
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Create a Razor project based on a physical file system.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="rootDirectoryPath">The directory to root the file system at.</param>
|
||||||
|
/// <returns>A <see cref="RazorProject"/></returns>
|
||||||
|
public static new RazorProjectFileSystem Create(string rootDirectoryPath)
|
||||||
|
{
|
||||||
|
return new FileSystemRazorProject(rootDirectoryPath);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -536,4 +536,10 @@ Instead, wrap the contents of the block in "{{}}":
|
||||||
<data name="RazorLanguageVersion_InvalidVersion" xml:space="preserve">
|
<data name="RazorLanguageVersion_InvalidVersion" xml:space="preserve">
|
||||||
<value>The Razor language version '{0}' is unrecognized or not supported by this version of Razor.</value>
|
<value>The Razor language version '{0}' is unrecognized or not supported by this version of Razor.</value>
|
||||||
</data>
|
</data>
|
||||||
|
<data name="VirtualFileSystem_FileDoesNotBelongToDirectory" xml:space="preserve">
|
||||||
|
<value>File path '{0}' does not belong to the directory '{1}'.</value>
|
||||||
|
</data>
|
||||||
|
<data name="VirtualFileSystem_InvalidRelativePath" xml:space="preserve">
|
||||||
|
<value>The file path '{0}' is invalid. File path is the root relative path of the file starting with '/' and should not contain any '\' characters.</value>
|
||||||
|
</data>
|
||||||
</root>
|
</root>
|
||||||
|
|
@ -0,0 +1,216 @@
|
||||||
|
// 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.Diagnostics;
|
||||||
|
using System.Linq;
|
||||||
|
|
||||||
|
namespace Microsoft.AspNetCore.Razor.Language
|
||||||
|
{
|
||||||
|
internal class VirtualRazorProjectFileSystem : RazorProjectFileSystem
|
||||||
|
{
|
||||||
|
private readonly DirectoryNode Root = new DirectoryNode("/");
|
||||||
|
|
||||||
|
public override IEnumerable<RazorProjectItem> EnumerateItems(string basePath)
|
||||||
|
{
|
||||||
|
|
||||||
|
basePath = NormalizeAndEnsureValidPath(basePath);
|
||||||
|
var directory = Root.GetDirectory(basePath);
|
||||||
|
return directory?.EnumerateItems() ?? Enumerable.Empty<RazorProjectItem>();
|
||||||
|
}
|
||||||
|
|
||||||
|
public override RazorProjectItem GetItem(string path)
|
||||||
|
{
|
||||||
|
path = NormalizeAndEnsureValidPath(path);
|
||||||
|
return Root.GetItem(path) ?? new NotFoundProjectItem(string.Empty, path);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Add(RazorProjectItem projectItem)
|
||||||
|
{
|
||||||
|
if (projectItem == null)
|
||||||
|
{
|
||||||
|
throw new ArgumentNullException(nameof(projectItem));
|
||||||
|
}
|
||||||
|
|
||||||
|
var filePath = NormalizeAndEnsureValidPath(projectItem.FilePath);
|
||||||
|
Root.AddFile(new FileNode(filePath, projectItem));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Internal for testing
|
||||||
|
[DebuggerDisplay("{Path}")]
|
||||||
|
internal class DirectoryNode
|
||||||
|
{
|
||||||
|
public DirectoryNode(string path)
|
||||||
|
{
|
||||||
|
Path = path;
|
||||||
|
}
|
||||||
|
|
||||||
|
public string Path { get; }
|
||||||
|
|
||||||
|
public List<DirectoryNode> Directories { get; } = new List<DirectoryNode>();
|
||||||
|
|
||||||
|
public List<FileNode> Files { get; } = new List<FileNode>();
|
||||||
|
|
||||||
|
public void AddFile(FileNode fileNode)
|
||||||
|
{
|
||||||
|
var filePath = fileNode.Path;
|
||||||
|
if (!filePath.StartsWith(Path, StringComparison.OrdinalIgnoreCase))
|
||||||
|
{
|
||||||
|
var message = Resources.FormatVirtualFileSystem_FileDoesNotBelongToDirectory(fileNode.Path, Path);
|
||||||
|
throw new InvalidOperationException(message);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Look for the first / that appears in the path after the current directory path.
|
||||||
|
var directoryPath = GetDirectoryPath(filePath);
|
||||||
|
var directory = GetOrAddDirectory(this, directoryPath, createIfNotExists: true);
|
||||||
|
Debug.Assert(directory != null);
|
||||||
|
directory.Files.Add(fileNode);
|
||||||
|
}
|
||||||
|
|
||||||
|
public DirectoryNode GetDirectory(string path)
|
||||||
|
{
|
||||||
|
if (!path.StartsWith(Path, StringComparison.OrdinalIgnoreCase))
|
||||||
|
{
|
||||||
|
var message = Resources.FormatVirtualFileSystem_FileDoesNotBelongToDirectory(path, Path);
|
||||||
|
throw new InvalidOperationException(message);
|
||||||
|
}
|
||||||
|
|
||||||
|
return GetOrAddDirectory(this, path);
|
||||||
|
}
|
||||||
|
|
||||||
|
public IEnumerable<RazorProjectItem> EnumerateItems()
|
||||||
|
{
|
||||||
|
foreach (var file in Files)
|
||||||
|
{
|
||||||
|
yield return file.ProjectItem;
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (var directory in Directories)
|
||||||
|
{
|
||||||
|
foreach (var file in directory.EnumerateItems())
|
||||||
|
{
|
||||||
|
yield return file;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public RazorProjectItem GetItem(string path)
|
||||||
|
{
|
||||||
|
if (!path.StartsWith(Path, StringComparison.OrdinalIgnoreCase))
|
||||||
|
{
|
||||||
|
throw new InvalidOperationException(Resources.FormatVirtualFileSystem_FileDoesNotBelongToDirectory(path, Path));
|
||||||
|
}
|
||||||
|
|
||||||
|
var directoryPath = GetDirectoryPath(path);
|
||||||
|
var directory = GetOrAddDirectory(this, directoryPath);
|
||||||
|
if (directory == null)
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (var file in directory.Files)
|
||||||
|
{
|
||||||
|
var filePath = file.Path;
|
||||||
|
var directoryLength = directory.Path.Length;
|
||||||
|
|
||||||
|
// path, filePath -> /Views/Home/Index.cshtml
|
||||||
|
// directory.Path -> /Views/Home/
|
||||||
|
// We only need to match the file name portion since we've already matched the directory segment.
|
||||||
|
if (string.Compare(path, directoryLength, filePath, directoryLength, path.Length - directoryLength, StringComparison.OrdinalIgnoreCase) == 0)
|
||||||
|
{
|
||||||
|
return file.ProjectItem;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static string GetDirectoryPath(string path)
|
||||||
|
{
|
||||||
|
// /dir1/dir2/file.cshtml -> /dir1/dir2/
|
||||||
|
var fileNameIndex = path.LastIndexOf('/');
|
||||||
|
if (fileNameIndex == -1)
|
||||||
|
{
|
||||||
|
return path;
|
||||||
|
}
|
||||||
|
|
||||||
|
return path.Substring(0, fileNameIndex + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static DirectoryNode GetOrAddDirectory(
|
||||||
|
DirectoryNode directory,
|
||||||
|
string path,
|
||||||
|
bool createIfNotExists = false)
|
||||||
|
{
|
||||||
|
Debug.Assert(!string.IsNullOrEmpty(path));
|
||||||
|
if (path[path.Length - 1] != '/')
|
||||||
|
{
|
||||||
|
path += '/';
|
||||||
|
}
|
||||||
|
|
||||||
|
int index;
|
||||||
|
while ((index = path.IndexOf('/', directory.Path.Length)) != -1 && index != path.Length)
|
||||||
|
{
|
||||||
|
var subDirectory = FindSubDirectory(directory, path);
|
||||||
|
|
||||||
|
if (subDirectory == null)
|
||||||
|
{
|
||||||
|
if (createIfNotExists)
|
||||||
|
{
|
||||||
|
var directoryPath = path.Substring(0, index + 1); // + 1 to include trailing slash
|
||||||
|
subDirectory = new DirectoryNode(directoryPath);
|
||||||
|
directory.Directories.Add(subDirectory);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
directory = subDirectory;
|
||||||
|
}
|
||||||
|
|
||||||
|
return directory;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static DirectoryNode FindSubDirectory(DirectoryNode parentDirectory, string path)
|
||||||
|
{
|
||||||
|
for (var i = 0; i < parentDirectory.Directories.Count; i++)
|
||||||
|
{
|
||||||
|
// ParentDirectory.Path -> /Views/Home/
|
||||||
|
// CurrentDirectory.Path -> /Views/Home/SubDir/
|
||||||
|
// Path -> /Views/Home/SubDir/MorePath/File.cshtml
|
||||||
|
// Each invocation of FindSubDirectory returns the immediate subdirectory along the path to the file.
|
||||||
|
|
||||||
|
var currentDirectory = parentDirectory.Directories[i];
|
||||||
|
var directoryPath = currentDirectory.Path;
|
||||||
|
var startIndex = parentDirectory.Path.Length;
|
||||||
|
var directoryNameLength = directoryPath.Length - startIndex;
|
||||||
|
|
||||||
|
if (string.Compare(path, startIndex, directoryPath, startIndex, directoryPath.Length - startIndex, StringComparison.OrdinalIgnoreCase) == 0)
|
||||||
|
{
|
||||||
|
return currentDirectory;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Internal for testing
|
||||||
|
[DebuggerDisplay("{Path}")]
|
||||||
|
internal struct FileNode
|
||||||
|
{
|
||||||
|
public FileNode(string path, RazorProjectItem projectItem)
|
||||||
|
{
|
||||||
|
Path = path;
|
||||||
|
ProjectItem = projectItem;
|
||||||
|
}
|
||||||
|
|
||||||
|
public string Path { get; }
|
||||||
|
|
||||||
|
public RazorProjectItem ProjectItem { get; }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -69,9 +69,9 @@ namespace Microsoft.AspNetCore.Razor.Tasks
|
||||||
{
|
{
|
||||||
if (Debug)
|
if (Debug)
|
||||||
{
|
{
|
||||||
|
Log.LogMessage(MessageImportance.High, "Waiting for debugger in pid: {0}", Process.GetCurrentProcess().Id);
|
||||||
while (!Debugger.IsAttached)
|
while (!Debugger.IsAttached)
|
||||||
{
|
{
|
||||||
Log.LogMessage(MessageImportance.High, "Waiting for debugger in pid: {0}", Process.GetCurrentProcess().Id);
|
|
||||||
Thread.Sleep(TimeSpan.FromSeconds(3));
|
Thread.Sleep(TimeSpan.FromSeconds(3));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -174,5 +174,18 @@ namespace Microsoft.AspNetCore.Razor.Tasks
|
||||||
CommandLineUtilities.SplitCommandLineIntoArguments(responseFileCommands, removeHashComments: true);
|
CommandLineUtilities.SplitCommandLineIntoArguments(responseFileCommands, removeHashComments: true);
|
||||||
return responseFileArguments.ToList();
|
return responseFileArguments.ToList();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected override bool HandleTaskExecutionErrors()
|
||||||
|
{
|
||||||
|
if (!HasLoggedErrors)
|
||||||
|
{
|
||||||
|
var toolCommand = Path.GetFileNameWithoutExtension(ToolAssembly) + " " + Command;
|
||||||
|
// Show a slightly better error than the standard ToolTask message that says "dotnet" failed.
|
||||||
|
Log.LogError($"{toolCommand} exited with code {ExitCode}.");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return base.HandleTaskExecutionErrors();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,28 +1,44 @@
|
||||||
// Copyright (c) .NET Foundation. All rights reserved.
|
// 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.
|
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||||
|
|
||||||
|
using System.IO;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using Microsoft.Build.Framework;
|
using Microsoft.Build.Framework;
|
||||||
using Microsoft.CodeAnalysis.CommandLine;
|
|
||||||
|
|
||||||
namespace Microsoft.AspNetCore.Razor.Tasks
|
namespace Microsoft.AspNetCore.Razor.Tasks
|
||||||
{
|
{
|
||||||
public class RazorGenerate : DotNetToolTask
|
public class RazorGenerate : DotNetToolTask
|
||||||
{
|
{
|
||||||
|
private const string GeneratedOutput = "GeneratedOutput";
|
||||||
|
private const string TargetPath = "TargetPath";
|
||||||
|
private const string FullPath = "FullPath";
|
||||||
|
|
||||||
[Required]
|
[Required]
|
||||||
public string[] Sources { get; set; }
|
public ITaskItem[] Sources { get; set; }
|
||||||
|
|
||||||
[Required]
|
[Required]
|
||||||
public string ProjectRoot { get; set; }
|
public string ProjectRoot { get; set; }
|
||||||
|
|
||||||
[Required]
|
|
||||||
public string OutputPath { get; set; }
|
|
||||||
|
|
||||||
[Required]
|
[Required]
|
||||||
public string TagHelperManifest { get; set; }
|
public string TagHelperManifest { get; set; }
|
||||||
|
|
||||||
internal override string Command => "generate";
|
internal override string Command => "generate";
|
||||||
|
|
||||||
|
protected override bool ValidateParameters()
|
||||||
|
{
|
||||||
|
for (var i = 0; i < Sources.Length; i++)
|
||||||
|
{
|
||||||
|
if (!EnsureRequiredMetadata(Sources[i], FullPath) ||
|
||||||
|
!EnsureRequiredMetadata(Sources[i], GeneratedOutput) ||
|
||||||
|
!EnsureRequiredMetadata(Sources[i], TargetPath))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return base.ValidateParameters();
|
||||||
|
}
|
||||||
|
|
||||||
protected override string GenerateResponseFileCommands()
|
protected override string GenerateResponseFileCommands()
|
||||||
{
|
{
|
||||||
var builder = new StringBuilder();
|
var builder = new StringBuilder();
|
||||||
|
|
@ -31,19 +47,37 @@ namespace Microsoft.AspNetCore.Razor.Tasks
|
||||||
|
|
||||||
for (var i = 0; i < Sources.Length; i++)
|
for (var i = 0; i < Sources.Length; i++)
|
||||||
{
|
{
|
||||||
builder.AppendLine(Sources[i]);
|
var input = Sources[i];
|
||||||
|
builder.AppendLine("-s");
|
||||||
|
builder.AppendLine(input.GetMetadata(FullPath));
|
||||||
|
|
||||||
|
builder.AppendLine("-r");
|
||||||
|
builder.AppendLine(input.GetMetadata(TargetPath));
|
||||||
|
|
||||||
|
builder.AppendLine("-o");
|
||||||
|
var outputPath = Path.Combine(ProjectRoot, input.GetMetadata(GeneratedOutput));
|
||||||
|
builder.AppendLine(outputPath);
|
||||||
}
|
}
|
||||||
|
|
||||||
builder.AppendLine("-p");
|
builder.AppendLine("-p");
|
||||||
builder.AppendLine(ProjectRoot);
|
builder.AppendLine(ProjectRoot);
|
||||||
|
|
||||||
builder.AppendLine("-o");
|
|
||||||
builder.AppendLine(OutputPath);
|
|
||||||
|
|
||||||
builder.AppendLine("-t");
|
builder.AppendLine("-t");
|
||||||
builder.AppendLine(TagHelperManifest);
|
builder.AppendLine(TagHelperManifest);
|
||||||
|
|
||||||
return builder.ToString();
|
return builder.ToString();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private bool EnsureRequiredMetadata(ITaskItem item, string metadataName)
|
||||||
|
{
|
||||||
|
var value = item.GetMetadata(metadataName);
|
||||||
|
if (string.IsNullOrEmpty(value))
|
||||||
|
{
|
||||||
|
Log.LogError($"Missing required metadata '{metadataName}' for '{item.ItemSpec}.");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,45 @@
|
||||||
|
// 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 Microsoft.AspNetCore.Razor.Language;
|
||||||
|
|
||||||
|
namespace Microsoft.AspNetCore.Razor.Tools
|
||||||
|
{
|
||||||
|
internal class CompositeRazorProjectFileSystem : RazorProjectFileSystem
|
||||||
|
{
|
||||||
|
public CompositeRazorProjectFileSystem(IReadOnlyList<RazorProjectFileSystem> projects)
|
||||||
|
{
|
||||||
|
Projects = projects ?? throw new ArgumentNullException(nameof(projects));
|
||||||
|
}
|
||||||
|
|
||||||
|
public IReadOnlyList<RazorProjectFileSystem> Projects { get; }
|
||||||
|
|
||||||
|
public override IEnumerable<RazorProjectItem> EnumerateItems(string basePath)
|
||||||
|
{
|
||||||
|
foreach (var project in Projects)
|
||||||
|
{
|
||||||
|
foreach (var result in project.EnumerateItems(basePath))
|
||||||
|
{
|
||||||
|
yield return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public override RazorProjectItem GetItem(string path)
|
||||||
|
{
|
||||||
|
RazorProjectItem razorProjectItem = null;
|
||||||
|
foreach (var project in Projects)
|
||||||
|
{
|
||||||
|
razorProjectItem = project.GetItem(path);
|
||||||
|
if (razorProjectItem != null && razorProjectItem.Exists)
|
||||||
|
{
|
||||||
|
return razorProjectItem;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return razorProjectItem;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -16,9 +16,9 @@ namespace Microsoft.AspNetCore.Razor.Tools
|
||||||
{
|
{
|
||||||
args = args.Skip(1).ToArray();
|
args = args.Skip(1).ToArray();
|
||||||
|
|
||||||
|
Console.WriteLine("Waiting for debugger in pid: {0}", Process.GetCurrentProcess().Id);
|
||||||
while (!Debugger.IsAttached)
|
while (!Debugger.IsAttached)
|
||||||
{
|
{
|
||||||
Console.WriteLine("Waiting for debugger in pid: {0}", Process.GetCurrentProcess().Id);
|
|
||||||
Thread.Sleep(TimeSpan.FromSeconds(3));
|
Thread.Sleep(TimeSpan.FromSeconds(3));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -13,20 +13,30 @@ using Newtonsoft.Json;
|
||||||
|
|
||||||
namespace Microsoft.AspNetCore.Razor.Tools
|
namespace Microsoft.AspNetCore.Razor.Tools
|
||||||
{
|
{
|
||||||
|
internal class Builder<T>
|
||||||
|
{
|
||||||
|
public static Builder<T> Make(CommandBase result) => null;
|
||||||
|
|
||||||
|
public static Builder<T> Make(T result) => null;
|
||||||
|
}
|
||||||
|
|
||||||
internal class GenerateCommand : CommandBase
|
internal class GenerateCommand : CommandBase
|
||||||
{
|
{
|
||||||
public GenerateCommand(Application parent)
|
public GenerateCommand(Application parent)
|
||||||
: base(parent, "generate")
|
: base(parent, "generate")
|
||||||
{
|
{
|
||||||
Sources = Argument("sources", ".cshtml files to compile", multipleValues: true);
|
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);
|
||||||
ProjectDirectory = Option("-p", "project root directory", CommandOptionType.SingleValue);
|
ProjectDirectory = Option("-p", "project root directory", CommandOptionType.SingleValue);
|
||||||
OutputDirectory = Option("-o", "output directory", CommandOptionType.SingleValue);
|
|
||||||
TagHelperManifest = Option("-t", "tag helper manifest file", CommandOptionType.SingleValue);
|
TagHelperManifest = Option("-t", "tag helper manifest file", CommandOptionType.SingleValue);
|
||||||
}
|
}
|
||||||
|
|
||||||
public CommandArgument Sources { get; }
|
public CommandOption Sources { get; }
|
||||||
|
|
||||||
public CommandOption OutputDirectory { get; }
|
public CommandOption Outputs { get; }
|
||||||
|
|
||||||
|
public CommandOption RelativePaths { get; }
|
||||||
|
|
||||||
public CommandOption ProjectDirectory { get; }
|
public CommandOption ProjectDirectory { get; }
|
||||||
|
|
||||||
|
|
@ -36,25 +46,30 @@ namespace Microsoft.AspNetCore.Razor.Tools
|
||||||
{
|
{
|
||||||
var result = ExecuteCore(
|
var result = ExecuteCore(
|
||||||
projectDirectory: ProjectDirectory.Value(),
|
projectDirectory: ProjectDirectory.Value(),
|
||||||
outputDirectory: OutputDirectory.Value(),
|
|
||||||
tagHelperManifest: TagHelperManifest.Value(),
|
tagHelperManifest: TagHelperManifest.Value(),
|
||||||
sources: Sources.Values.ToArray());
|
sources: Sources.Values,
|
||||||
|
outputs: Outputs.Values,
|
||||||
|
relativePaths: RelativePaths.Values);
|
||||||
|
|
||||||
return Task.FromResult(result);
|
return Task.FromResult(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override bool ValidateArguments()
|
protected override bool ValidateArguments()
|
||||||
{
|
{
|
||||||
if (string.IsNullOrEmpty(OutputDirectory.Value()))
|
if (Sources.Values.Count == 0)
|
||||||
{
|
{
|
||||||
Error.WriteLine($"{OutputDirectory.ValueName} not specified.");
|
Error.WriteLine($"{Sources.ValueName} should have at least one value.");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Sources.Values.Count == 0)
|
if (Outputs.Values.Count != Sources.Values.Count)
|
||||||
{
|
{
|
||||||
Error.WriteLine($"{Sources.Name} should have at least one value.");
|
Error.WriteLine($"{Sources.ValueName} has {Sources.Values.Count}, but {Outputs.ValueName} has {Outputs.Values.Count}.");
|
||||||
return false;
|
}
|
||||||
|
|
||||||
|
if (RelativePaths.Values.Count != Sources.Values.Count)
|
||||||
|
{
|
||||||
|
Error.WriteLine($"{Sources.ValueName} has {Sources.Values.Count}, but {RelativePaths.ValueName} has {RelativePaths.Values.Count}.");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (string.IsNullOrEmpty(ProjectDirectory.Value()))
|
if (string.IsNullOrEmpty(ProjectDirectory.Value()))
|
||||||
|
|
@ -65,10 +80,14 @@ namespace Microsoft.AspNetCore.Razor.Tools
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
private int ExecuteCore(string projectDirectory, string outputDirectory, string tagHelperManifest, string[] sources)
|
private int ExecuteCore(
|
||||||
|
string projectDirectory,
|
||||||
|
string tagHelperManifest,
|
||||||
|
List<string> sources,
|
||||||
|
List<string> outputs,
|
||||||
|
List<string> relativePaths)
|
||||||
{
|
{
|
||||||
tagHelperManifest = Path.Combine(projectDirectory, tagHelperManifest);
|
tagHelperManifest = Path.Combine(projectDirectory, tagHelperManifest);
|
||||||
outputDirectory = Path.Combine(projectDirectory, outputDirectory);
|
|
||||||
|
|
||||||
var tagHelpers = GetTagHelpers(tagHelperManifest);
|
var tagHelpers = GetTagHelpers(tagHelperManifest);
|
||||||
|
|
||||||
|
|
@ -79,10 +98,18 @@ namespace Microsoft.AspNetCore.Razor.Tools
|
||||||
b.Features.Add(new StaticTagHelperFeature() { TagHelpers = tagHelpers, });
|
b.Features.Add(new StaticTagHelperFeature() { TagHelpers = tagHelpers, });
|
||||||
});
|
});
|
||||||
|
|
||||||
var templateEngine = new MvcRazorTemplateEngine(engine, RazorProject.Create(projectDirectory));
|
|
||||||
|
|
||||||
var sourceItems = GetRazorFiles(projectDirectory, sources);
|
var inputItems = GetInputItems(projectDirectory, sources, outputs, relativePaths);
|
||||||
var results = GenerateCode(templateEngine, sourceItems);
|
var compositeProject = new CompositeRazorProjectFileSystem(
|
||||||
|
new[]
|
||||||
|
{
|
||||||
|
GetVirtualRazorProjectSystem(inputItems),
|
||||||
|
RazorProjectFileSystem.Create(projectDirectory),
|
||||||
|
});
|
||||||
|
|
||||||
|
var templateEngine = new MvcRazorTemplateEngine(engine, compositeProject);
|
||||||
|
|
||||||
|
var results = GenerateCode(templateEngine, inputItems);
|
||||||
|
|
||||||
var success = true;
|
var success = true;
|
||||||
|
|
||||||
|
|
@ -97,16 +124,30 @@ namespace Microsoft.AspNetCore.Razor.Tools
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var viewFile = result.ViewFileInfo.ViewEnginePath.Substring(1);
|
var outputFilePath = result.InputItem.OutputPath;
|
||||||
var outputFileName = Path.ChangeExtension(viewFile, ".cs");
|
|
||||||
|
|
||||||
var outputFilePath = Path.Combine(outputDirectory, outputFileName);
|
|
||||||
File.WriteAllText(outputFilePath, result.CSharpDocument.GeneratedCode);
|
File.WriteAllText(outputFilePath, result.CSharpDocument.GeneratedCode);
|
||||||
}
|
}
|
||||||
|
|
||||||
return success ? 0 : -1;
|
return success ? 0 : -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private VirtualRazorProjectFileSystem GetVirtualRazorProjectSystem(SourceItem[] inputItems)
|
||||||
|
{
|
||||||
|
var project = new VirtualRazorProjectFileSystem();
|
||||||
|
foreach (var item in inputItems)
|
||||||
|
{
|
||||||
|
var projectItem = new FileSystemRazorProjectItem(
|
||||||
|
basePath: "/",
|
||||||
|
filePath: item.FilePath,
|
||||||
|
relativePhysicalPath: item.RelativePhysicalPath,
|
||||||
|
file: new FileInfo(item.SourcePath));
|
||||||
|
|
||||||
|
project.Add(projectItem);
|
||||||
|
}
|
||||||
|
|
||||||
|
return project;
|
||||||
|
}
|
||||||
|
|
||||||
private IReadOnlyList<TagHelperDescriptor> GetTagHelpers(string tagHelperManifest)
|
private IReadOnlyList<TagHelperDescriptor> GetTagHelpers(string tagHelperManifest)
|
||||||
{
|
{
|
||||||
if (!File.Exists(tagHelperManifest))
|
if (!File.Exists(tagHelperManifest))
|
||||||
|
|
@ -127,33 +168,27 @@ namespace Microsoft.AspNetCore.Razor.Tools
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private List<SourceItem> GetRazorFiles(string projectDirectory, string[] sources)
|
private SourceItem[] GetInputItems(string projectDirectory, List<string> sources, List<string> outputs, List<string> relativePath)
|
||||||
{
|
{
|
||||||
var trimLength = projectDirectory.EndsWith("/") ? projectDirectory.Length - 1 : projectDirectory.Length;
|
var items = new SourceItem[sources.Count];
|
||||||
|
for (var i = 0; i < items.Length; i++)
|
||||||
var items = new List<SourceItem>(sources.Length);
|
|
||||||
for (var i = 0; i < sources.Length; i++)
|
|
||||||
{
|
{
|
||||||
var fullPath = Path.Combine(projectDirectory, sources[i]);
|
var outputPath = Path.Combine(projectDirectory, outputs[i]);
|
||||||
if (fullPath.StartsWith(projectDirectory, StringComparison.OrdinalIgnoreCase))
|
items[i] = new SourceItem(sources[i], outputs[i], relativePath[i]);
|
||||||
{
|
|
||||||
var viewEnginePath = fullPath.Substring(trimLength).Replace('\\', '/');
|
|
||||||
items.Add(new SourceItem(fullPath, viewEnginePath));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return items;
|
return items;
|
||||||
}
|
}
|
||||||
|
|
||||||
private OutputItem[] GenerateCode(RazorTemplateEngine templateEngine, IReadOnlyList<SourceItem> sources)
|
private OutputItem[] GenerateCode(RazorTemplateEngine templateEngine, SourceItem[] inputs)
|
||||||
{
|
{
|
||||||
var outputs = new OutputItem[sources.Count];
|
var outputs = new OutputItem[inputs.Length];
|
||||||
Parallel.For(0, outputs.Length, new ParallelOptions() { MaxDegreeOfParallelism = 4 }, i =>
|
Parallel.For(0, outputs.Length, new ParallelOptions() { MaxDegreeOfParallelism = 4 }, i =>
|
||||||
{
|
{
|
||||||
var source = sources[i];
|
var inputItem = inputs[i];
|
||||||
|
|
||||||
var csharpDocument = templateEngine.GenerateCode(source.ViewEnginePath);
|
var csharpDocument = templateEngine.GenerateCode(inputItem.FilePath);
|
||||||
outputs[i] = new OutputItem(source, csharpDocument);
|
outputs[i] = new OutputItem(inputItem, csharpDocument);
|
||||||
});
|
});
|
||||||
|
|
||||||
return outputs;
|
return outputs;
|
||||||
|
|
@ -162,43 +197,37 @@ namespace Microsoft.AspNetCore.Razor.Tools
|
||||||
private struct OutputItem
|
private struct OutputItem
|
||||||
{
|
{
|
||||||
public OutputItem(
|
public OutputItem(
|
||||||
SourceItem viewFileInfo,
|
SourceItem inputItem,
|
||||||
RazorCSharpDocument cSharpDocument)
|
RazorCSharpDocument cSharpDocument)
|
||||||
{
|
{
|
||||||
ViewFileInfo = viewFileInfo;
|
InputItem = inputItem;
|
||||||
CSharpDocument = cSharpDocument;
|
CSharpDocument = cSharpDocument;
|
||||||
}
|
}
|
||||||
|
|
||||||
public SourceItem ViewFileInfo { get; }
|
public SourceItem InputItem { get; }
|
||||||
|
|
||||||
public RazorCSharpDocument CSharpDocument { get; }
|
public RazorCSharpDocument CSharpDocument { get; }
|
||||||
}
|
}
|
||||||
|
|
||||||
private struct SourceItem
|
private struct SourceItem
|
||||||
{
|
{
|
||||||
public SourceItem(string fullPath, string viewEnginePath)
|
public SourceItem(string sourcePath, string outputPath, string physicalRelativePath)
|
||||||
{
|
{
|
||||||
FullPath = fullPath;
|
SourcePath = sourcePath;
|
||||||
ViewEnginePath = viewEnginePath;
|
OutputPath = outputPath;
|
||||||
|
RelativePhysicalPath = physicalRelativePath;
|
||||||
|
FilePath = '/' + physicalRelativePath
|
||||||
|
.Replace(Path.DirectorySeparatorChar, '/')
|
||||||
|
.Replace("//", "/");
|
||||||
}
|
}
|
||||||
|
|
||||||
public string FullPath { get; }
|
public string SourcePath { get; }
|
||||||
|
|
||||||
public string ViewEnginePath { get; }
|
public string OutputPath { get; }
|
||||||
|
|
||||||
public Stream CreateReadStream()
|
public string RelativePhysicalPath { get; }
|
||||||
{
|
|
||||||
// We are setting buffer size to 1 to prevent FileStream from allocating it's internal buffer
|
public string FilePath { get; }
|
||||||
// 0 causes constructor to throw
|
|
||||||
var bufferSize = 1;
|
|
||||||
return new FileStream(
|
|
||||||
FullPath,
|
|
||||||
FileMode.Open,
|
|
||||||
FileAccess.Read,
|
|
||||||
FileShare.ReadWrite,
|
|
||||||
bufferSize,
|
|
||||||
FileOptions.Asynchronous | FileOptions.SequentialScan);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private class StaticTagHelperFeature : ITagHelperFeature
|
private class StaticTagHelperFeature : ITagHelperFeature
|
||||||
|
|
@ -210,4 +239,4 @@ namespace Microsoft.AspNetCore.Razor.Tools
|
||||||
public IReadOnlyList<TagHelperDescriptor> GetDescriptors() => TagHelpers;
|
public IReadOnlyList<TagHelperDescriptor> GetDescriptors() => TagHelpers;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -31,6 +31,7 @@ Copyright (c) .NET Foundation. All rights reserved.
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<PrepareForRazorGenerateDependsOn>
|
<PrepareForRazorGenerateDependsOn>
|
||||||
ResolveRazorGenerateInputs;
|
ResolveRazorGenerateInputs;
|
||||||
|
AssignRazorGenerateTargetPaths;
|
||||||
ResolveAssemblyReferenceRazorGenerateInputs;
|
ResolveAssemblyReferenceRazorGenerateInputs;
|
||||||
_EnsureRazorCompilerReferenced;
|
_EnsureRazorCompilerReferenced;
|
||||||
ResolveTagHelperRazorGenerateInputs
|
ResolveTagHelperRazorGenerateInputs
|
||||||
|
|
@ -48,6 +49,7 @@ Copyright (c) .NET Foundation. All rights reserved.
|
||||||
</PrepareForRazorCompileDependsOn>
|
</PrepareForRazorCompileDependsOn>
|
||||||
|
|
||||||
<ResolveRazorCompileInputsDependsOn>
|
<ResolveRazorCompileInputsDependsOn>
|
||||||
|
ResolveRazorEmbeddedResources
|
||||||
</ResolveRazorCompileInputsDependsOn>
|
</ResolveRazorCompileInputsDependsOn>
|
||||||
|
|
||||||
<RazorCompileDependsOn>
|
<RazorCompileDependsOn>
|
||||||
|
|
@ -221,11 +223,17 @@ Copyright (c) .NET Foundation. All rights reserved.
|
||||||
<ItemGroup Condition="'$(EnableDefaultRazorGenerateItems)'=='true'">
|
<ItemGroup Condition="'$(EnableDefaultRazorGenerateItems)'=='true'">
|
||||||
<RazorGenerate Include="@(Content)" Condition="'%(Content.Extension)'=='.cshtml'" />
|
<RazorGenerate Include="@(Content)" Condition="'%(Content.Extension)'=='.cshtml'" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
</Target>
|
||||||
|
|
||||||
|
<Target Name="AssignRazorGenerateTargetPaths" Condition="'@(RazorGenerate)' != ''">
|
||||||
|
<AssignTargetPath Files="@(RazorGenerate)" RootFolder="$(MSBuildProjectDirectory)">
|
||||||
|
<Output TaskParameter="AssignedFiles" ItemName="RazorGenerateWithTargetPath" />
|
||||||
|
</AssignTargetPath>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<RazorGenerate Update="@(RazorGenerate)" Condtion="'%(RazorGenerate.GeneratedOutput)'==''">
|
<RazorGenerateWithTargetPath Condition="'%(RazorGenerateWithTargetPath.GeneratedOutput)' == ''">
|
||||||
<GeneratedOutput>$(RazorGenerateIntermediateOutputPath)%(RelativeDir)%(Filename).cs</GeneratedOutput>
|
<GeneratedOutput>$(RazorGenerateIntermediateOutputPath)$([System.IO.Path]::ChangeExtension('%(RazorGenerateWithTargetPath.TargetPath)', '.cs'))</GeneratedOutput>
|
||||||
</RazorGenerate>
|
</RazorGenerateWithTargetPath>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
</Target>
|
</Target>
|
||||||
|
|
||||||
|
|
@ -249,6 +257,21 @@ Copyright (c) .NET Foundation. All rights reserved.
|
||||||
<Target Name="ResolveRazorCompileInputs" DependsOnTargets="$(ResolveRazorCompileInputsDependsOn)">
|
<Target Name="ResolveRazorCompileInputs" DependsOnTargets="$(ResolveRazorCompileInputsDependsOn)">
|
||||||
</Target>
|
</Target>
|
||||||
|
|
||||||
|
<Target Name="ResolveRazorEmbeddedResources" Condition="'$(EmbedRazorGenerateSources)'=='true'">
|
||||||
|
<ItemGroup>
|
||||||
|
<RazorEmbeddedResource Include="@(RazorGenerateWithTargetPath)">
|
||||||
|
<LogicalName>/$([System.String]::Copy('%(RazorGenerateWithTargetPath.TargetPath)').Replace('\','/'))</LogicalName>
|
||||||
|
<Type>Non-Resx</Type>
|
||||||
|
<WithCulture>false</WithCulture>
|
||||||
|
</RazorEmbeddedResource>
|
||||||
|
|
||||||
|
<!-- Similar to _GenerateCompileInputs -->
|
||||||
|
<_RazorCoreCompileResourceInputs
|
||||||
|
Include="@(RazorEmbeddedResource)"
|
||||||
|
Condition="'%(RazorEmbeddedResource.WithCulture)'=='false' and '%(RazorEmbeddedResource.Type)'=='Non-Resx' " />
|
||||||
|
</ItemGroup>
|
||||||
|
</Target>
|
||||||
|
|
||||||
<!--
|
<!--
|
||||||
This target is called after PrepareForPublish when RazorCompileOnPublish=true so that we can hook into publish.
|
This target is called after PrepareForPublish when RazorCompileOnPublish=true so that we can hook into publish.
|
||||||
This target just hooks up other targets since Publish and PrepareForPublish don't have a DependsOnTargets
|
This target just hooks up other targets since Publish and PrepareForPublish don't have a DependsOnTargets
|
||||||
|
|
|
||||||
|
|
@ -314,7 +314,6 @@ namespace Microsoft.AspNetCore.Razor.Design.IntegrationTests
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private class BuildFailedException : MSBuildXunitException
|
private class BuildFailedException : MSBuildXunitException
|
||||||
{
|
{
|
||||||
public BuildFailedException(MSBuildResult result)
|
public BuildFailedException(MSBuildResult result)
|
||||||
|
|
|
||||||
|
|
@ -2,9 +2,9 @@
|
||||||
// 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.IO;
|
using System.IO;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Microsoft.AspNetCore.Testing.xunit;
|
using Microsoft.AspNetCore.Testing.xunit;
|
||||||
using Microsoft.DotNet.PlatformAbstractions;
|
|
||||||
using Xunit;
|
using Xunit;
|
||||||
|
|
||||||
namespace Microsoft.AspNetCore.Razor.Design.IntegrationTests
|
namespace Microsoft.AspNetCore.Razor.Design.IntegrationTests
|
||||||
|
|
@ -33,7 +33,7 @@ namespace Microsoft.AspNetCore.Razor.Design.IntegrationTests
|
||||||
Assert.FileExists(result, OutputPath, "SimpleMvc.PrecompiledViews.dll");
|
Assert.FileExists(result, OutputPath, "SimpleMvc.PrecompiledViews.dll");
|
||||||
Assert.FileExists(result, OutputPath, "SimpleMvc.PrecompiledViews.pdb");
|
Assert.FileExists(result, OutputPath, "SimpleMvc.PrecompiledViews.pdb");
|
||||||
|
|
||||||
if (RuntimeEnvironment.OperatingSystemPlatform != Platform.Darwin)
|
if (!RuntimeInformation.IsOSPlatform(OSPlatform.OSX))
|
||||||
{
|
{
|
||||||
// GetFullPath on OSX doesn't work well in travis. We end up computing a different path than will
|
// GetFullPath on OSX doesn't work well in travis. We end up computing a different path than will
|
||||||
// end up in the MSBuild logs.
|
// end up in the MSBuild logs.
|
||||||
|
|
@ -194,5 +194,27 @@ namespace Microsoft.AspNetCore.Razor.Design.IntegrationTests
|
||||||
Assert.FileExists(result, OutputPath, "ClassLibrary.PrecompiledViews.dll");
|
Assert.FileExists(result, OutputPath, "ClassLibrary.PrecompiledViews.dll");
|
||||||
Assert.FileExists(result, OutputPath, "ClassLibrary.PrecompiledViews.pdb");
|
Assert.FileExists(result, OutputPath, "ClassLibrary.PrecompiledViews.pdb");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
[InitializeTestProject("SimplePages", "LinkedDir")]
|
||||||
|
public async Task Build_SetsUpEmbeddedResourcesWithLogicalName()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var additionalProjectContent = @"
|
||||||
|
<ItemGroup>
|
||||||
|
<Content Include=""..\LinkedDir\LinkedFile.cshtml"" Link=""LinkedFileOut\LinkedFile.cshtml"" />
|
||||||
|
</ItemGroup>
|
||||||
|
";
|
||||||
|
AddProjectFileContent(additionalProjectContent);
|
||||||
|
Directory.CreateDirectory(Path.Combine(Project.DirectoryPath, "..", "LinkedDir"));
|
||||||
|
|
||||||
|
var result = await DotnetMSBuild("Build", "/t:_IntrospectRazorEmbeddedResources /p:RazorCompileOnBuild=true /p:EmbedRazorGenerateSources=true");
|
||||||
|
|
||||||
|
Assert.BuildPassed(result);
|
||||||
|
|
||||||
|
Assert.BuildOutputContainsLine(result, $@"CompileResource: {Path.Combine("Pages", "Index.cshtml")} /Pages/Index.cshtml");
|
||||||
|
Assert.BuildOutputContainsLine(result, $@"CompileResource: {Path.Combine("Areas", "Products", "Pages", "_ViewStart.cshtml")} /Areas/Products/Pages/_ViewStart.cshtml");
|
||||||
|
Assert.BuildOutputContainsLine(result, $@"CompileResource: {Path.Combine("..", "LinkedDir", "LinkedFile.cshtml")} /LinkedFileOut/LinkedFile.cshtml");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,7 @@
|
||||||
// Copyright (c) .NET Foundation. All rights reserved.
|
// 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.
|
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||||
|
|
||||||
using System.IO;
|
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Microsoft.DotNet.PlatformAbstractions;
|
|
||||||
using Xunit;
|
using Xunit;
|
||||||
|
|
||||||
namespace Microsoft.AspNetCore.Razor.Design.IntegrationTests
|
namespace Microsoft.AspNetCore.Razor.Design.IntegrationTests
|
||||||
|
|
|
||||||
|
|
@ -5,10 +5,8 @@ using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Reflection;
|
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using Microsoft.AspNetCore.Testing;
|
using Microsoft.AspNetCore.Testing;
|
||||||
using Moq;
|
|
||||||
|
|
||||||
namespace Microsoft.AspNetCore.Razor.Design.IntegrationTests
|
namespace Microsoft.AspNetCore.Razor.Design.IntegrationTests
|
||||||
{
|
{
|
||||||
|
|
@ -100,7 +98,7 @@ $@"<Project>
|
||||||
</Project>";
|
</Project>";
|
||||||
File.WriteAllText(Path.Combine(projectDestination, "Before.Directory.Build.props"), beforeDirectoryPropsContent);
|
File.WriteAllText(Path.Combine(projectDestination, "Before.Directory.Build.props"), beforeDirectoryPropsContent);
|
||||||
|
|
||||||
new List<string> { "Directory.Build.props", "Directory.Build.targets" }
|
new List<string> { "Directory.Build.props", "Directory.Build.targets", "RazorTest.Introspection.targets" }
|
||||||
.ForEach(file =>
|
.ForEach(file =>
|
||||||
{
|
{
|
||||||
var source = Path.Combine(testAppsRoot, file);
|
var source = Path.Combine(testAppsRoot, file);
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,7 @@
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Microsoft.AspNetCore.Testing.xunit;
|
using Microsoft.AspNetCore.Testing.xunit;
|
||||||
using Xunit;
|
using Xunit;
|
||||||
|
|
@ -196,7 +197,7 @@ namespace Microsoft.AspNetCore.Razor.Design.IntegrationTests
|
||||||
|
|
||||||
// We shouldn't need to hash the files
|
// We shouldn't need to hash the files
|
||||||
Assert.FileDoesNotExist(result, Path.Combine(IntermediateOutputPath, "SimpleMvc.RazorCoreGenerate.cache"));
|
Assert.FileDoesNotExist(result, Path.Combine(IntermediateOutputPath, "SimpleMvc.RazorCoreGenerate.cache"));
|
||||||
|
|
||||||
Assert.FileCountEquals(result, 0, RazorIntermediateOutputPath, "*.cs");
|
Assert.FileCountEquals(result, 0, RazorIntermediateOutputPath, "*.cs");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -204,14 +205,12 @@ namespace Microsoft.AspNetCore.Razor.Design.IntegrationTests
|
||||||
[InitializeTestProject("SimpleMvc")]
|
[InitializeTestProject("SimpleMvc")]
|
||||||
public async Task RazorGenerate_MvcRazorFilesToCompile_OverridesDefaultItems()
|
public async Task RazorGenerate_MvcRazorFilesToCompile_OverridesDefaultItems()
|
||||||
{
|
{
|
||||||
var content = @"
|
var projectContent = @"
|
||||||
<Project>
|
<ItemGroup>
|
||||||
<ItemGroup>
|
<MvcRazorFilesToCompile Include=""Views/Home/About.cshtml"" />
|
||||||
<MvcRazorFilesToCompile Include=""Views/Home/About.cshtml"" />
|
</ItemGroup>
|
||||||
</ItemGroup>
|
|
||||||
</Project>
|
|
||||||
";
|
";
|
||||||
File.WriteAllText(Path.Combine(Project.DirectoryPath, "After.Directory.Build.props"), content);
|
AddProjectFileContent(projectContent);
|
||||||
|
|
||||||
var result = await DotnetMSBuild(RazorGenerateTarget);
|
var result = await DotnetMSBuild(RazorGenerateTarget);
|
||||||
|
|
||||||
|
|
@ -225,17 +224,15 @@ namespace Microsoft.AspNetCore.Razor.Design.IntegrationTests
|
||||||
[InitializeTestProject("SimpleMvc")]
|
[InitializeTestProject("SimpleMvc")]
|
||||||
public async Task RazorGenerate_EnableDefaultRazorGenerateItems_False_OverridesDefaultItems()
|
public async Task RazorGenerate_EnableDefaultRazorGenerateItems_False_OverridesDefaultItems()
|
||||||
{
|
{
|
||||||
var content = @"
|
var projectContent = @"
|
||||||
<Project>
|
<PropertyGroup>
|
||||||
<PropertyGroup>
|
<EnableDefaultRazorGenerateItems>false</EnableDefaultRazorGenerateItems>
|
||||||
<EnableDefaultRazorGenerateItems>false</EnableDefaultRazorGenerateItems>
|
</PropertyGroup>
|
||||||
</PropertyGroup>
|
<ItemGroup>
|
||||||
<ItemGroup>
|
<RazorGenerate Include=""Views/Home/About.cshtml"" />
|
||||||
<RazorGenerate Include=""Views/Home/About.cshtml"" />
|
</ItemGroup>
|
||||||
</ItemGroup>
|
|
||||||
</Project>
|
|
||||||
";
|
";
|
||||||
File.WriteAllText(Path.Combine(Project.DirectoryPath, "After.Directory.Build.props"), content);
|
AddProjectFileContent(projectContent);
|
||||||
|
|
||||||
var result = await DotnetMSBuild(RazorGenerateTarget);
|
var result = await DotnetMSBuild(RazorGenerateTarget);
|
||||||
|
|
||||||
|
|
@ -245,9 +242,61 @@ namespace Microsoft.AspNetCore.Razor.Design.IntegrationTests
|
||||||
Assert.FileCountEquals(result, 1, RazorIntermediateOutputPath, "*.cs");
|
Assert.FileCountEquals(result, 1, RazorIntermediateOutputPath, "*.cs");
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact(Skip = "Fails due to #1999")]
|
[Fact]
|
||||||
|
[InitializeTestProject("SimpleMvc", "LinkedDir")]
|
||||||
|
public async Task RazorGenerate_WorksWithLinkedFiles()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var projectContent = @"
|
||||||
|
<ItemGroup>
|
||||||
|
<Content Include=""..\LinkedDir\LinkedFile.cshtml"" />
|
||||||
|
<Content Include=""..\LinkedDir\LinkedFile2.cshtml"" Link=""LinkedFileOut\LinkedFile2.cshtml"" />
|
||||||
|
<Content Include=""..\LinkedDir\LinkedFile3.cshtml"" Link=""LinkedFileOut\LinkedFileWithRename.cshtml"" />
|
||||||
|
</ItemGroup>
|
||||||
|
";
|
||||||
|
AddProjectFileContent(projectContent);
|
||||||
|
|
||||||
|
var result = await DotnetMSBuild(RazorGenerateTarget, "/t:_IntrospectRazorGenerateWithTargetPath");
|
||||||
|
|
||||||
|
Assert.BuildPassed(result);
|
||||||
|
|
||||||
|
Assert.FileExists(result, RazorIntermediateOutputPath, "LinkedFile.cs");
|
||||||
|
Assert.FileExists(result, RazorIntermediateOutputPath, "LinkedFileOut", "LinkedFile2.cs");
|
||||||
|
Assert.FileExists(result, RazorIntermediateOutputPath, "LinkedFileOut", "LinkedFileWithRename.cs");
|
||||||
|
|
||||||
|
Assert.BuildOutputContainsLine(result, $@"RazorGenerateWithTargetPath: {Path.Combine("..", "LinkedDir", "LinkedFile.cshtml")} LinkedFile.cshtml {Path.Combine(RazorIntermediateOutputPath, "LinkedFile.cs")}");
|
||||||
|
Assert.BuildOutputContainsLine(result, $@"RazorGenerateWithTargetPath: {Path.Combine("..", "LinkedDir", "LinkedFile2.cshtml")} LinkedFileOut\LinkedFile2.cshtml {Path.Combine(RazorIntermediateOutputPath, "LinkedFileOut", "LinkedFile2.cs")}");
|
||||||
|
Assert.BuildOutputContainsLine(result, $@"RazorGenerateWithTargetPath: {Path.Combine("..", "LinkedDir", "LinkedFile3.cshtml")} LinkedFileOut\LinkedFileWithRename.cshtml {Path.Combine(RazorIntermediateOutputPath, "LinkedFileOut", "LinkedFileWithRename.cs")}");
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
[InitializeTestProject("SimpleMvc", "LinkedDir")]
|
||||||
|
public async Task RazorGenerate_PrintsErrorsFromLinkedFiles()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var file = @"..\LinkedDir\LinkedErrorFile.cshtml";
|
||||||
|
var projectContent = $@"
|
||||||
|
<ItemGroup>
|
||||||
|
<Content Include=""{file}"" Link=""LinkedFileOut\LinkedFile.cshtml"" />
|
||||||
|
</ItemGroup>
|
||||||
|
";
|
||||||
|
AddProjectFileContent(projectContent);
|
||||||
|
|
||||||
|
var result = await DotnetMSBuild(RazorGenerateTarget);
|
||||||
|
|
||||||
|
Assert.BuildFailed(result);
|
||||||
|
if (!RuntimeInformation.IsOSPlatform(OSPlatform.OSX))
|
||||||
|
{
|
||||||
|
// GetFullPath on OSX doesn't work well in travis. We end up computing a different path than will
|
||||||
|
// end up in the MSBuild logs.
|
||||||
|
var errorLocation = Path.GetFullPath(Path.Combine(Project.DirectoryPath, "..", "LinkedDir", "LinkedErrorFile.cshtml")) + "(1,2)";
|
||||||
|
Assert.BuildError(result, "RZ1006", errorLocation);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
[InitializeTestProject("SimpleMvc")]
|
[InitializeTestProject("SimpleMvc")]
|
||||||
public async Task RazorGenerate_FileWithAbsolutePath_IgnoresFile()
|
public async Task RazorGenerate_FileWithAbsolutePath()
|
||||||
{
|
{
|
||||||
// In preview1 we totally ignore files that are specified with an absolute path
|
// In preview1 we totally ignore files that are specified with an absolute path
|
||||||
var filePath = Path.Combine(Project.SolutionPath, "temp.cshtml");
|
var filePath = Path.Combine(Project.SolutionPath, "temp.cshtml");
|
||||||
|
|
@ -258,7 +307,7 @@ namespace Microsoft.AspNetCore.Razor.Design.IntegrationTests
|
||||||
<Content Include=""{filePath}""/>
|
<Content Include=""{filePath}""/>
|
||||||
</ItemGroup>");
|
</ItemGroup>");
|
||||||
|
|
||||||
var result = await DotnetMSBuild(RazorGenerateTarget);
|
var result = await DotnetMSBuild(RazorGenerateTarget, "/t:_IntrospectRazorGenerateWithTargetPath");
|
||||||
|
|
||||||
Assert.BuildPassed(result);
|
Assert.BuildPassed(result);
|
||||||
|
|
||||||
|
|
@ -274,7 +323,9 @@ namespace Microsoft.AspNetCore.Razor.Design.IntegrationTests
|
||||||
Assert.FileExists(result, RazorIntermediateOutputPath, "Views", "Shared", "_Layout.cs");
|
Assert.FileExists(result, RazorIntermediateOutputPath, "Views", "Shared", "_Layout.cs");
|
||||||
Assert.FileExists(result, RazorIntermediateOutputPath, "Views", "Shared", "_ValidationScriptsPartial.cs");
|
Assert.FileExists(result, RazorIntermediateOutputPath, "Views", "Shared", "_ValidationScriptsPartial.cs");
|
||||||
Assert.FileExists(result, RazorIntermediateOutputPath, "Views", "Shared", "Error.cs");
|
Assert.FileExists(result, RazorIntermediateOutputPath, "Views", "Shared", "Error.cs");
|
||||||
Assert.FileCountEquals(result, 8, RazorIntermediateOutputPath, "*.cs");
|
Assert.FileExists(result, RazorIntermediateOutputPath, "temp.cs");
|
||||||
|
Assert.FileCountEquals(result, 9, RazorIntermediateOutputPath, "*.cs");
|
||||||
|
Assert.BuildOutputContainsLine(result, $@"RazorGenerateWithTargetPath: {filePath} temp.cshtml {Path.Combine(RazorIntermediateOutputPath, "temp.cs")}");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,400 @@
|
||||||
|
// 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 Xunit;
|
||||||
|
using DirectoryNode = Microsoft.AspNetCore.Razor.Language.VirtualRazorProjectFileSystem.DirectoryNode;
|
||||||
|
using FileNode = Microsoft.AspNetCore.Razor.Language.VirtualRazorProjectFileSystem.FileNode;
|
||||||
|
|
||||||
|
namespace Microsoft.AspNetCore.Razor.Language
|
||||||
|
{
|
||||||
|
public class VirtualRazorProjectFileSystemTest
|
||||||
|
{
|
||||||
|
[Fact]
|
||||||
|
public void GetItem_ReturnsNotFound_IfFileDoesNotExistInRoot()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var path = "/root-file.cshtml";
|
||||||
|
var projectSystem = new VirtualRazorProjectFileSystem();
|
||||||
|
|
||||||
|
// Act
|
||||||
|
projectSystem.Add(new TestRazorProjectItem("/different-file.cshtml"));
|
||||||
|
var result = projectSystem.GetItem(path);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.False(result.Exists);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void GetItem_ReturnsItemAddedToRoot()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var path = "/root-file.cshtml";
|
||||||
|
var projectSystem = new VirtualRazorProjectFileSystem();
|
||||||
|
var projectItem = new TestRazorProjectItem(path);
|
||||||
|
|
||||||
|
// Act
|
||||||
|
projectSystem.Add(projectItem);
|
||||||
|
var actual = projectSystem.GetItem(path);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.Same(projectItem, actual);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Theory]
|
||||||
|
[InlineData("/subDirectory/file.cshtml")]
|
||||||
|
[InlineData("/subDirectory/dir2/file.cshtml")]
|
||||||
|
[InlineData("/subDirectory/dir2/dir3/file.cshtml")]
|
||||||
|
public void GetItem_ReturnsItemAddedToNestedDirectory(string path)
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var projectSystem = new VirtualRazorProjectFileSystem();
|
||||||
|
var projectItem = new TestRazorProjectItem(path);
|
||||||
|
|
||||||
|
// Act
|
||||||
|
projectSystem.Add(projectItem);
|
||||||
|
var actual = projectSystem.GetItem(path);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.Same(projectItem, actual);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void GetItem_ReturnsNotFound_WhenNestedDirectoryDoesNotExist()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var projectSystem = new VirtualRazorProjectFileSystem();
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var actual = projectSystem.GetItem("/subDirectory/dir3/file.cshtml");
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.False(actual.Exists);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void GetItem_ReturnsNotFound_WhenNestedDirectoryDoesNotExist_AndPeerDirectoryExists()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var projectSystem = new VirtualRazorProjectFileSystem();
|
||||||
|
var projectItem = new TestRazorProjectItem("/subDirectory/dir2/file.cshtml");
|
||||||
|
|
||||||
|
// Act
|
||||||
|
projectSystem.Add(projectItem);
|
||||||
|
var actual = projectSystem.GetItem("/subDirectory/dir3/file.cshtml");
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.False(actual.Exists);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void GetItem_ReturnsNotFound_WhenFileDoesNotExistInNestedDirectory()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var projectSystem = new VirtualRazorProjectFileSystem();
|
||||||
|
var projectItem = new TestRazorProjectItem("/subDirectory/dir2/file.cshtml");
|
||||||
|
|
||||||
|
// Act
|
||||||
|
projectSystem.Add(projectItem);
|
||||||
|
var actual = projectSystem.GetItem("/subDirectory/dir2/file2.cshtml");
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.False(actual.Exists);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void EnumerateItems_AtRoot_ReturnsAllFiles()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var projectSystem = new VirtualRazorProjectFileSystem();
|
||||||
|
var file1 = new TestRazorProjectItem("/subDirectory/dir2/file1.cshtml");
|
||||||
|
var file2 = new TestRazorProjectItem("/file2.cshtml");
|
||||||
|
var file3 = new TestRazorProjectItem("/dir3/file3.cshtml");
|
||||||
|
var file4 = new TestRazorProjectItem("/subDirectory/file4.cshtml");
|
||||||
|
projectSystem.Add(file1);
|
||||||
|
projectSystem.Add(file2);
|
||||||
|
projectSystem.Add(file3);
|
||||||
|
projectSystem.Add(file4);
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var result = projectSystem.EnumerateItems("/");
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.Equal(new[] { file2, file4, file1, file3 }, result);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void EnumerateItems_AtSubDirectory_ReturnsAllFilesUnderDirectoryHierarchy()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var projectSystem = new VirtualRazorProjectFileSystem();
|
||||||
|
var file1 = new TestRazorProjectItem("/subDirectory/dir2/file1.cshtml");
|
||||||
|
var file2 = new TestRazorProjectItem("/file2.cshtml");
|
||||||
|
var file3 = new TestRazorProjectItem("/dir3/file3.cshtml");
|
||||||
|
var file4 = new TestRazorProjectItem("/subDirectory/file4.cshtml");
|
||||||
|
projectSystem.Add(file1);
|
||||||
|
projectSystem.Add(file2);
|
||||||
|
projectSystem.Add(file3);
|
||||||
|
projectSystem.Add(file4);
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var result = projectSystem.EnumerateItems("/subDirectory");
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.Equal(new[] { file4, file1 }, result);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void EnumerateItems_WithNoFilesInRoot_ReturnsEmptySequence()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var projectSystem = new VirtualRazorProjectFileSystem();
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var result = projectSystem.EnumerateItems("/");
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.Empty(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void EnumerateItems_ForNonExistentDirectory_ReturnsEmptySequence()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var projectSystem = new VirtualRazorProjectFileSystem();
|
||||||
|
projectSystem.Add(new TestRazorProjectItem("/subDirectory/dir2/file1.cshtml"));
|
||||||
|
projectSystem.Add(new TestRazorProjectItem("/file2.cshtml"));
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var result = projectSystem.EnumerateItems("/dir3");
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.Empty(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void GetHierarchicalItems_Works()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var projectSystem = new VirtualRazorProjectFileSystem();
|
||||||
|
var viewImport1 = new TestRazorProjectItem("/_ViewImports.cshtml");
|
||||||
|
var viewImport2 = new TestRazorProjectItem("/Views/Home/_ViewImports.cshtml");
|
||||||
|
projectSystem.Add(viewImport1);
|
||||||
|
projectSystem.Add(viewImport2);
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var items = projectSystem.FindHierarchicalItems("/", "/Views/Home/Index.cshtml", "_ViewImports.cshtml");
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.Collection(
|
||||||
|
items,
|
||||||
|
item => Assert.Same(viewImport2, item),
|
||||||
|
item => Assert.False(item.Exists),
|
||||||
|
item => Assert.Same(viewImport1, item));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void DirectoryNode_GetDirectory_ReturnsRoot()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var root = new DirectoryNode("/");
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var result = root.GetDirectory("/");
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.Same(root, result);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void DirectoryNode_GetDirectory_ReturnsNull_IfDirectoryDoesNotExist()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var root = new DirectoryNode("/");
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var result = root.GetDirectory("/does-not/exist");
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.Null(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void DirectoryNode_AddFile_CanAddToRoot()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var root = new DirectoryNode("/");
|
||||||
|
var projectItem = new TestRazorProjectItem("/File.txt");
|
||||||
|
|
||||||
|
// Act
|
||||||
|
root.AddFile(new FileNode("/File.txt", projectItem));
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.Empty(root.Directories);
|
||||||
|
Assert.Collection(
|
||||||
|
root.Files,
|
||||||
|
file => Assert.Same(projectItem, file.ProjectItem));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void DirectoryNode_AddFile_CanAddToNestedDirectory()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var root = new DirectoryNode("/");
|
||||||
|
var projectItem = new TestRazorProjectItem("/Pages/Shared/_Layout.cshtml");
|
||||||
|
|
||||||
|
// Act
|
||||||
|
root.AddFile(new FileNode("/Pages/Shared/_Layout.cshtml", projectItem));
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.Collection(
|
||||||
|
root.Directories,
|
||||||
|
directory =>
|
||||||
|
{
|
||||||
|
Assert.Equal("/Pages/", directory.Path);
|
||||||
|
Assert.Empty(directory.Files);
|
||||||
|
|
||||||
|
Assert.Collection(
|
||||||
|
directory.Directories,
|
||||||
|
subDirectory =>
|
||||||
|
{
|
||||||
|
Assert.Equal("/Pages/Shared/", subDirectory.Path);
|
||||||
|
Assert.Collection(
|
||||||
|
subDirectory.Files,
|
||||||
|
file => Assert.Same(projectItem, file.ProjectItem));
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void DirectoryNode_AddMultipleFiles_ToSameDirectory()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var root = new DirectoryNode("/");
|
||||||
|
var projectItem1 = new TestRazorProjectItem("/Pages/Shared/_Layout.cshtml");
|
||||||
|
var projectItem2 = new TestRazorProjectItem("/Pages/Shared/_Partial.cshtml");
|
||||||
|
|
||||||
|
// Act
|
||||||
|
root.AddFile(new FileNode(projectItem1.FilePath, projectItem1));
|
||||||
|
root.AddFile(new FileNode(projectItem2.FilePath, projectItem2));
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.Collection(
|
||||||
|
root.Directories,
|
||||||
|
directory =>
|
||||||
|
{
|
||||||
|
Assert.Equal("/Pages/", directory.Path);
|
||||||
|
Assert.Empty(directory.Files);
|
||||||
|
|
||||||
|
Assert.Collection(
|
||||||
|
directory.Directories,
|
||||||
|
subDirectory =>
|
||||||
|
{
|
||||||
|
Assert.Equal("/Pages/Shared/", subDirectory.Path);
|
||||||
|
Assert.Collection(
|
||||||
|
subDirectory.Files,
|
||||||
|
file => Assert.Same(projectItem1, file.ProjectItem),
|
||||||
|
file => Assert.Same(projectItem2, file.ProjectItem));
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void DirectoryNode_AddsFiles_ToSiblingDirectories()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var root = new DirectoryNode("/");
|
||||||
|
var projectItem1 = new TestRazorProjectItem("/Pages/Products/Index.cshtml");
|
||||||
|
var projectItem2 = new TestRazorProjectItem("/Pages/Accounts/About.cshtml");
|
||||||
|
|
||||||
|
// Act
|
||||||
|
root.AddFile(new FileNode(projectItem1.FilePath, projectItem1));
|
||||||
|
root.AddFile(new FileNode(projectItem2.FilePath, projectItem2));
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.Collection(
|
||||||
|
root.Directories,
|
||||||
|
directory =>
|
||||||
|
{
|
||||||
|
Assert.Equal("/Pages/", directory.Path);
|
||||||
|
Assert.Empty(directory.Files);
|
||||||
|
|
||||||
|
Assert.Collection(
|
||||||
|
directory.Directories,
|
||||||
|
subDirectory =>
|
||||||
|
{
|
||||||
|
Assert.Equal("/Pages/Products/", subDirectory.Path);
|
||||||
|
Assert.Collection(
|
||||||
|
subDirectory.Files,
|
||||||
|
file => Assert.Same(projectItem1, file.ProjectItem));
|
||||||
|
},
|
||||||
|
subDirectory =>
|
||||||
|
{
|
||||||
|
Assert.Equal("/Pages/Accounts/", subDirectory.Path);
|
||||||
|
Assert.Collection(
|
||||||
|
subDirectory.Files,
|
||||||
|
file => Assert.Same(projectItem2, file.ProjectItem));
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void DirectoryNode_GetItem_ReturnsItemAtRoot()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var root = new DirectoryNode("/");
|
||||||
|
var projectItem = new TestRazorProjectItem("/_ViewStart.cshtml");
|
||||||
|
root.AddFile(new FileNode(projectItem.FilePath, projectItem));
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var result = root.GetItem(projectItem.FilePath);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.Same(result, projectItem);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void DirectoryNode_GetItem_WhenFilePathSharesSameNameAsSiblingDirectory()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var root = new DirectoryNode("/");
|
||||||
|
var projectItem1 = new TestRazorProjectItem("/Home.cshtml");
|
||||||
|
var projectItem2 = new TestRazorProjectItem("/Home/About.cshtml");
|
||||||
|
root.AddFile(new FileNode(projectItem1.FilePath, projectItem1));
|
||||||
|
root.AddFile(new FileNode(projectItem2.FilePath, projectItem2));
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var result = root.GetItem(projectItem1.FilePath);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.Same(result, projectItem1);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void DirectoryNode_GetItem_WhenFileNameIsSameAsDirectoryName()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var projectItem1 = new TestRazorProjectItem("/Home/Home.cshtml");
|
||||||
|
var projectItem2 = new TestRazorProjectItem("/Home/About.cshtml");
|
||||||
|
var root = new DirectoryNode("/")
|
||||||
|
{
|
||||||
|
Directories =
|
||||||
|
{
|
||||||
|
new DirectoryNode("/Home/")
|
||||||
|
{
|
||||||
|
Files =
|
||||||
|
{
|
||||||
|
new FileNode(projectItem1.FilePath, projectItem1),
|
||||||
|
new FileNode(projectItem2.FilePath, projectItem2),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var result = root.GetItem(projectItem1.FilePath);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.Same(result, projectItem1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -28,7 +28,7 @@ namespace Microsoft.AspNetCore.Razor.Language
|
||||||
|
|
||||||
public override string RelativePhysicalPath { get; }
|
public override string RelativePhysicalPath { get; }
|
||||||
|
|
||||||
public override bool Exists => true;
|
public override bool Exists { get; } = true;
|
||||||
|
|
||||||
public string Content { get; set; } = "Default content";
|
public string Content { get; set; } = "Default content";
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,81 @@
|
||||||
|
// 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.Linq;
|
||||||
|
using Microsoft.AspNetCore.Razor.Language;
|
||||||
|
using Moq;
|
||||||
|
using Xunit;
|
||||||
|
|
||||||
|
namespace Microsoft.AspNetCore.Razor.Tools
|
||||||
|
{
|
||||||
|
public class CompositeRazorProjectFileSystemTest
|
||||||
|
{
|
||||||
|
[Fact]
|
||||||
|
public void EnumerateItems_ReturnsResultsFromAllFileSystems()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var basePath = "base-path";
|
||||||
|
var file1 = new TestRazorProjectItem("file1");
|
||||||
|
var file2 = new TestRazorProjectItem("file2");
|
||||||
|
var file3 = new TestRazorProjectItem("file3");
|
||||||
|
var fileSystem1 = Mock.Of<RazorProjectFileSystem>(
|
||||||
|
f => f.EnumerateItems(basePath) == new[] { file1 });
|
||||||
|
var fileSystem2 = Mock.Of<RazorProjectFileSystem>(
|
||||||
|
f => f.EnumerateItems(basePath) == Enumerable.Empty<RazorProjectItem>());
|
||||||
|
var fileSystem3 = Mock.Of<RazorProjectFileSystem>(
|
||||||
|
f => f.EnumerateItems(basePath) == new[] { file2, file3, });
|
||||||
|
|
||||||
|
var compositeRazorProjectFileSystem = new CompositeRazorProjectFileSystem(new[] { fileSystem1, fileSystem2, fileSystem3 });
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var result = compositeRazorProjectFileSystem.EnumerateItems(basePath);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.Equal(new[] { file1, file2, file3 }, result);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void EnumerateItems_ReturnsEmptySequence_IfNoFileSystemReturnsResults()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var basePath = "base-path";
|
||||||
|
var fileSystem1 = Mock.Of<RazorProjectFileSystem>(
|
||||||
|
f => f.EnumerateItems(basePath) == Enumerable.Empty<RazorProjectItem>());
|
||||||
|
var fileSystem2 = Mock.Of<RazorProjectFileSystem>(
|
||||||
|
f => f.EnumerateItems(basePath) == Enumerable.Empty<RazorProjectItem>());
|
||||||
|
|
||||||
|
var compositeRazorProjectFileSystem = new CompositeRazorProjectFileSystem(new[] { fileSystem1, fileSystem2 });
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var result = compositeRazorProjectFileSystem.EnumerateItems(basePath);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.Empty(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void GetItem_ReturnsFirstInstanceThatExists()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var basePath = "base-path";
|
||||||
|
var filePath = "file-path";
|
||||||
|
var file1 = new NotFoundProjectItem(basePath, filePath);
|
||||||
|
var file2 = new TestRazorProjectItem(filePath);
|
||||||
|
RazorProjectItem nullItem = null;
|
||||||
|
var fileSystem1 = Mock.Of<RazorProjectFileSystem>(
|
||||||
|
f => f.GetItem(filePath) == file1);
|
||||||
|
var fileSystem2 = Mock.Of<RazorProjectFileSystem>(
|
||||||
|
f => f.GetItem(filePath) == nullItem);
|
||||||
|
var fileSystem3 = Mock.Of<RazorProjectFileSystem>(
|
||||||
|
f => f.GetItem(filePath) == file2);
|
||||||
|
|
||||||
|
var compositeRazorProjectFileSystem = new CompositeRazorProjectFileSystem(new[] { fileSystem1, fileSystem2, fileSystem3 });
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var result = compositeRazorProjectFileSystem.GetItem(filePath);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.Same(file2, result);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -6,6 +6,7 @@
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ProjectReference Include="..\..\src\Microsoft.AspNetCore.Razor.Tools\Microsoft.AspNetCore.Razor.Tools.csproj" />
|
<ProjectReference Include="..\..\src\Microsoft.AspNetCore.Razor.Tools\Microsoft.AspNetCore.Razor.Tools.csproj" />
|
||||||
|
<ProjectReference Include="..\Microsoft.AspNetCore.Razor.Test.Common\Microsoft.AspNetCore.Razor.Test.Common.csproj" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
|
|
||||||
|
|
@ -1,2 +1,3 @@
|
||||||
<Project>
|
<Project>
|
||||||
|
<Import Project="RazorTest.Introspection.targets" />
|
||||||
</Project>
|
</Project>
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1 @@
|
||||||
|
@(
|
||||||
|
|
@ -0,0 +1 @@
|
||||||
|
@DateTime.UtcNow
|
||||||
|
|
@ -0,0 +1 @@
|
||||||
|
@DateTime.UtcNow
|
||||||
|
|
@ -0,0 +1 @@
|
||||||
|
@DateTime.UtcNow
|
||||||
|
|
@ -0,0 +1,9 @@
|
||||||
|
<Project>
|
||||||
|
<Target Name="_IntrospectRazorGenerateWithTargetPath">
|
||||||
|
<Message Text="RazorGenerateWithTargetPath: %(RazorGenerateWithTargetPath.Identity) %(RazorGenerateWithTargetPath.TargetPath) %(RazorGenerateWithTargetPath.GeneratedOutput)" Importance="High" />
|
||||||
|
</Target>
|
||||||
|
|
||||||
|
<Target Name="_IntrospectRazorEmbeddedResources">
|
||||||
|
<Message Text="CompileResource: %(_RazorCoreCompileResourceInputs.Identity) %(_RazorCoreCompileResourceInputs.LogicalName)" Importance="High" />
|
||||||
|
</Target>
|
||||||
|
</Project>
|
||||||
Loading…
Reference in New Issue