Fix aspnet/Mvc#6296 sanitize class and namespace
The new @namespace directive isn't sanitizing class and namespace names when generating them. This means that a file-system-legal character like '-' will show up in a class name, and that's not good. Note that the old code paths (document classifiers) already had tests for this and did it properly. It was only missing from @namespace.
This commit is contained in:
parent
e391ac7a3c
commit
2a88d6efcf
|
|
@ -4,9 +4,9 @@
|
||||||
using System.Globalization;
|
using System.Globalization;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
|
|
||||||
namespace Microsoft.AspNetCore.Mvc.Razor.Extensions.Internal
|
namespace Microsoft.AspNetCore.Mvc.Razor.Extensions
|
||||||
{
|
{
|
||||||
public static class ClassName
|
internal static class ClassName
|
||||||
{
|
{
|
||||||
public static string GetClassNameFromPath(string path)
|
public static string GetClassNameFromPath(string path)
|
||||||
{
|
{
|
||||||
|
|
@ -43,7 +43,7 @@ namespace Microsoft.AspNetCore.Mvc.Razor.Extensions.Internal
|
||||||
category == UnicodeCategory.Format; // Cf
|
category == UnicodeCategory.Format; // Cf
|
||||||
}
|
}
|
||||||
|
|
||||||
private static string SanitizeClassName(string inputName)
|
public static string SanitizeClassName(string inputName)
|
||||||
{
|
{
|
||||||
if (!IsIdentifierStart(inputName[0]) && IsIdentifierPart(inputName[0]))
|
if (!IsIdentifierStart(inputName[0]) && IsIdentifierPart(inputName[0]))
|
||||||
{
|
{
|
||||||
|
|
@ -3,7 +3,6 @@
|
||||||
|
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using Microsoft.AspNetCore.Mvc.Razor.Extensions.Internal;
|
|
||||||
using Microsoft.AspNetCore.Razor.Language;
|
using Microsoft.AspNetCore.Razor.Language;
|
||||||
|
|
||||||
namespace Microsoft.AspNetCore.Mvc.Razor.Extensions
|
namespace Microsoft.AspNetCore.Mvc.Razor.Extensions
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,6 @@
|
||||||
// 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 Microsoft.AspNetCore.Mvc.Razor.Extensions.Internal;
|
|
||||||
using Microsoft.AspNetCore.Razor.Language;
|
using Microsoft.AspNetCore.Razor.Language;
|
||||||
using Microsoft.AspNetCore.Razor.Language.Intermediate;
|
using Microsoft.AspNetCore.Razor.Language.Intermediate;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -63,13 +63,14 @@ namespace Microsoft.AspNetCore.Mvc.Razor.Extensions
|
||||||
{
|
{
|
||||||
// Beautify the class name since we're using a hierarchy for namespaces.
|
// Beautify the class name since we're using a hierarchy for namespaces.
|
||||||
var @class = visitor.FirstClass;
|
var @class = visitor.FirstClass;
|
||||||
|
var prefix = Path.GetFileNameWithoutExtension(codeDocument.Source.FileName);
|
||||||
if (@class != null && irDocument.DocumentKind == RazorPageDocumentClassifierPass.RazorPageDocumentKind)
|
if (@class != null && irDocument.DocumentKind == RazorPageDocumentClassifierPass.RazorPageDocumentKind)
|
||||||
{
|
{
|
||||||
@class.Name = Path.GetFileNameWithoutExtension(codeDocument.Source.FileName) + "_Page";
|
@class.Name = ClassName.SanitizeClassName(prefix + "_Page");
|
||||||
}
|
}
|
||||||
else if (@class != null && irDocument.DocumentKind == MvcViewDocumentClassifierPass.MvcViewDocumentKind)
|
else if (@class != null && irDocument.DocumentKind == MvcViewDocumentClassifierPass.MvcViewDocumentKind)
|
||||||
{
|
{
|
||||||
@class.Name = Path.GetFileNameWithoutExtension(codeDocument.Source.FileName) + "_View";
|
@class.Name = ClassName.SanitizeClassName(prefix + "_View");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -125,7 +126,7 @@ namespace Microsoft.AspNetCore.Mvc.Razor.Extensions
|
||||||
for (var i = 0; i < segments.Length - 1; i++)
|
for (var i = 0; i < segments.Length - 1; i++)
|
||||||
{
|
{
|
||||||
builder.Append('.');
|
builder.Append('.');
|
||||||
builder.Append(segments[i]);
|
builder.Append(ClassName.SanitizeClassName(segments[i]));
|
||||||
}
|
}
|
||||||
|
|
||||||
@namespace = builder.ToString();
|
@namespace = builder.ToString();
|
||||||
|
|
|
||||||
|
|
@ -4,9 +4,9 @@
|
||||||
using System;
|
using System;
|
||||||
using Microsoft.AspNetCore.Razor.Language;
|
using Microsoft.AspNetCore.Razor.Language;
|
||||||
|
|
||||||
namespace Microsoft.AspNetCore.Mvc.Razor.Extensions.Internal
|
namespace Microsoft.AspNetCore.Mvc.Razor.Extensions
|
||||||
{
|
{
|
||||||
public static class RazorCodeDocumentExtensions
|
internal static class RazorCodeDocumentExtensions
|
||||||
{
|
{
|
||||||
private const string RelativePathKey = "relative-path";
|
private const string RelativePathKey = "relative-path";
|
||||||
|
|
||||||
|
|
@ -1,7 +1,6 @@
|
||||||
// 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 Microsoft.AspNetCore.Mvc.Razor.Extensions.Internal;
|
|
||||||
using Microsoft.AspNetCore.Razor.Language;
|
using Microsoft.AspNetCore.Razor.Language;
|
||||||
using Microsoft.AspNetCore.Razor.Language.Intermediate;
|
using Microsoft.AspNetCore.Razor.Language.Intermediate;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,6 @@
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using Microsoft.AspNetCore.Mvc.Razor.Extensions.Internal;
|
|
||||||
using Microsoft.AspNetCore.Razor.Language;
|
using Microsoft.AspNetCore.Razor.Language;
|
||||||
using Moq;
|
using Moq;
|
||||||
using Xunit;
|
using Xunit;
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,6 @@
|
||||||
// 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 Microsoft.AspNetCore.Mvc.Razor.Extensions.Internal;
|
|
||||||
using Microsoft.AspNetCore.Razor.Language;
|
using Microsoft.AspNetCore.Razor.Language;
|
||||||
using Microsoft.AspNetCore.Razor.Language.Intermediate;
|
using Microsoft.AspNetCore.Razor.Language.Intermediate;
|
||||||
using Xunit;
|
using Xunit;
|
||||||
|
|
|
||||||
|
|
@ -196,6 +196,44 @@ namespace Microsoft.AspNetCore.Mvc.Razor.Extensions
|
||||||
Assert.Equal("AddUser_Page", @class.Name);
|
Assert.Equal("AddUser_Page", @class.Name);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Handles cases where invalid characters appears in filenames. Note that we don't sanitize the part of
|
||||||
|
// the namespace that you put in an import, just the file-based-suffix. Garbage in, garbage out.
|
||||||
|
[Fact]
|
||||||
|
public void Pass_SetsNamespaceAndClassName_SanitizesClassAndNamespace()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var document = new DocumentIRNode();
|
||||||
|
var builder = RazorIRBuilder.Create(document);
|
||||||
|
|
||||||
|
builder.Push(new DirectiveIRNode()
|
||||||
|
{
|
||||||
|
Descriptor = NamespaceDirective.Directive,
|
||||||
|
Source = new SourceSpan("/Account/_ViewImports.cshtml", 0, 0, 0, 0),
|
||||||
|
});
|
||||||
|
builder.Add(new DirectiveTokenIRNode() { Content = "WebApplication.Account" });
|
||||||
|
builder.Pop();
|
||||||
|
|
||||||
|
var @namespace = new NamespaceDeclarationIRNode() { Content = "default" };
|
||||||
|
builder.Push(@namespace);
|
||||||
|
|
||||||
|
var @class = new ClassDeclarationIRNode() { Name = "default" };
|
||||||
|
builder.Add(@class);
|
||||||
|
|
||||||
|
document.DocumentKind = RazorPageDocumentClassifierPass.RazorPageDocumentKind;
|
||||||
|
|
||||||
|
var codeDocument = RazorCodeDocument.Create(RazorSourceDocument.Create("ignored", "/Account/Manage-Info/Add+User.cshtml"));
|
||||||
|
|
||||||
|
var pass = new NamespaceDirective.Pass();
|
||||||
|
pass.Engine = RazorEngine.CreateEmpty(b => { });
|
||||||
|
|
||||||
|
// Act
|
||||||
|
pass.Execute(codeDocument, document);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.Equal("WebApplication.Account.Manage_Info", @namespace.Content);
|
||||||
|
Assert.Equal("Add_User_Page", @class.Name);
|
||||||
|
}
|
||||||
|
|
||||||
// This is the case where the source file sets the namespace.
|
// This is the case where the source file sets the namespace.
|
||||||
[Fact]
|
[Fact]
|
||||||
public void Pass_SetsNamespaceAndClassName_ComputedFromSource_ForView()
|
public void Pass_SetsNamespaceAndClassName_ComputedFromSource_ForView()
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,6 @@
|
||||||
// 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 Microsoft.AspNetCore.Mvc.Razor.Extensions.Internal;
|
|
||||||
using Microsoft.AspNetCore.Razor.Language;
|
using Microsoft.AspNetCore.Razor.Language;
|
||||||
using Microsoft.AspNetCore.Razor.Language.Intermediate;
|
using Microsoft.AspNetCore.Razor.Language.Intermediate;
|
||||||
using Xunit;
|
using Xunit;
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue