diff --git a/src/Assets/TestProjects/RazorSimpleMvc/Views/Home/#F{}i+l!e.cshtml b/src/Assets/TestProjects/RazorSimpleMvc/Views/Home/#F{}i+l!e.cshtml new file mode 100644 index 000000000000..1882da9f18a8 --- /dev/null +++ b/src/Assets/TestProjects/RazorSimpleMvc/Views/Home/#F{}i+l!e.cshtml @@ -0,0 +1 @@ +

Just a file with a special character in the name!

\ No newline at end of file diff --git a/src/RazorSdk/SourceGenerators/RazorSourceGenerationContext.cs b/src/RazorSdk/SourceGenerators/RazorSourceGenerationContext.cs index 579daca0b927..d3e0b0a08049 100644 --- a/src/RazorSdk/SourceGenerators/RazorSourceGenerationContext.cs +++ b/src/RazorSdk/SourceGenerators/RazorSourceGenerationContext.cs @@ -4,6 +4,7 @@ using System; using System.Collections.Generic; using System.Linq; +using System.Text; using Microsoft.AspNetCore.Razor.Language; using Microsoft.CodeAnalysis; @@ -147,6 +148,8 @@ private static (IReadOnlyList razorFiles, IReadOnlyList '_', - var @default => @default, - }); + case ':' or '\\' or '/': + case char ch when !char.IsLetterOrDigit(ch): + builder.Append('_'); + break; + default: + builder.Append(filePath[i]); + break; + } } return builder.ToString(); diff --git a/src/RazorSdk/Targets/Microsoft.NET.Sdk.Razor.SourceGenerators.targets b/src/RazorSdk/Targets/Microsoft.NET.Sdk.Razor.SourceGenerators.targets index 956273483627..b0f3b359a602 100644 --- a/src/RazorSdk/Targets/Microsoft.NET.Sdk.Razor.SourceGenerators.targets +++ b/src/RazorSdk/Targets/Microsoft.NET.Sdk.Razor.SourceGenerators.targets @@ -10,6 +10,8 @@ Copyright (c) .NET Foundation. All rights reserved. + + @@ -45,7 +47,6 @@ Copyright (c) .NET Foundation. All rights reserved. - @@ -70,6 +71,15 @@ Copyright (c) .NET Foundation. All rights reserved. <_RazorAdditionalFile Remove="@(_RazorAdditionalFile)" Condition="$([MSBuild]::IsOSPlatform(`Windows`))" /> <_RazorAdditionalFile Include="@(_RazorOmnisharpWorkAround)" Condition="$([MSBuild]::IsOSPlatform(`Windows`))" /> + + + + + + + + <_RazorAdditionalFile Remove="@(_RazorAdditionalFile)" /> + <_RazorAdditionalFile Include="@(_RazorSpecialCharacterWorkaround)" /> diff --git a/src/RazorSdk/Tasks/EncodeRazorInputItem.cs b/src/RazorSdk/Tasks/EncodeRazorInputItem.cs new file mode 100644 index 000000000000..ac8c8fda5b10 --- /dev/null +++ b/src/RazorSdk/Tasks/EncodeRazorInputItem.cs @@ -0,0 +1,48 @@ +// 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.Numerics; +using System.Security.Cryptography; +using System.Text; +using System.Text.RegularExpressions; +using Microsoft.Build.Framework; +using Microsoft.Build.Utilities; + +namespace Microsoft.AspNetCore.Razor.Tasks +{ + // The compiler leverages .editorconfig files to transfer information between + // msbuild and the compiler. However, the transfer of data from MSBuild to the + // .editorconfig file to the source generator, causes a lot of issues as strings + // are transferred from one type to another. For example, the editorconfig file + // interprets "#" as comments and omits them from the produced AnalyzerConfigOptions. + // Characters like {} in the filename cause issues with resolving the type. To work + // around this, we encode everything before writing it to the editorconfig then decode + // inside the Razor source generator. + public class EncodeRazorInputItem : Task + { + [Required] + public ITaskItem[] RazorInputItems { get; set; } + + [Output] + public ITaskItem[] EncodedRazorInputItems { get; set; } + + public override bool Execute() + { + EncodedRazorInputItems = new ITaskItem[RazorInputItems.Length]; + + for (var i = 0; i < RazorInputItems.Length; i++) + { + var input = RazorInputItems[i]; + var targetPath = Convert.ToBase64String(Encoding.UTF8.GetBytes(input.GetMetadata("TargetPath"))); + + var outputItem = new TaskItem(input); + outputItem.SetMetadata("TargetPath", targetPath); + + EncodedRazorInputItems[i] = outputItem; + } + + return !Log.HasLoggedErrors; + } + } +} diff --git a/src/Tests/Microsoft.NET.Sdk.Razor.Tests/ScopedCssIntegrationTests.cs b/src/Tests/Microsoft.NET.Sdk.Razor.Tests/ScopedCssIntegrationTests.cs index 470be38927f4..586f3b7f31ce 100644 --- a/src/Tests/Microsoft.NET.Sdk.Razor.Tests/ScopedCssIntegrationTests.cs +++ b/src/Tests/Microsoft.NET.Sdk.Razor.Tests/ScopedCssIntegrationTests.cs @@ -102,7 +102,7 @@ public void CanOverrideScopeIdentifiers() var scoped = Path.Combine(intermediateOutputPath, "scopedcss", "Styles", "Pages", "Counter.rz.scp.css"); new FileInfo(scoped).Should().Exist(); new FileInfo(scoped).Should().Contain("b-overriden"); - var generated = Path.Combine(intermediateOutputPath, "generated", "Microsoft.NET.Sdk.Razor.SourceGenerators", "Microsoft.NET.Sdk.Razor.SourceGenerators.RazorSourceGenerator", "_Components_Pages_Counter.razor.cs"); + var generated = Path.Combine(intermediateOutputPath, "generated", "Microsoft.NET.Sdk.Razor.SourceGenerators", "Microsoft.NET.Sdk.Razor.SourceGenerators.RazorSourceGenerator", "_Components_Pages_Counter_razor.cs"); new FileInfo(generated).Should().Exist(); new FileInfo(generated).Should().Contain("b-overriden"); new FileInfo(Path.Combine(intermediateOutputPath, "scopedcss", "Components", "Pages", "Index.razor.rz.scp.css")).Should().NotExist(); @@ -327,7 +327,7 @@ public void Build_RemovingScopedCssAndBuilding_UpdatesGeneratedCodeAndBundle() new FileInfo(generatedBundle).Should().Exist(); var generatedProjectBundle = Path.Combine(intermediateOutputPath, "scopedcss", "projectbundle", "ComponentApp.bundle.scp.css"); new FileInfo(generatedProjectBundle).Should().Exist(); - var generatedCounter = Path.Combine(intermediateOutputPath, "generated", "Microsoft.NET.Sdk.Razor.SourceGenerators", "Microsoft.NET.Sdk.Razor.SourceGenerators.RazorSourceGenerator", "_Components_Pages_Counter.razor.cs"); + var generatedCounter = Path.Combine(intermediateOutputPath, "generated", "Microsoft.NET.Sdk.Razor.SourceGenerators", "Microsoft.NET.Sdk.Razor.SourceGenerators.RazorSourceGenerator", "_Components_Pages_Counter_razor.cs"); new FileInfo(generatedCounter).Should().Exist(); var componentThumbprint = FileThumbPrint.Create(generatedCounter);