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:
Ryan Nowak 2017-05-19 08:54:24 -07:00
parent e391ac7a3c
commit 2a88d6efcf
10 changed files with 47 additions and 14 deletions

View File

@ -4,9 +4,9 @@
using System.Globalization;
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)
{
@ -43,7 +43,7 @@ namespace Microsoft.AspNetCore.Mvc.Razor.Extensions.Internal
category == UnicodeCategory.Format; // Cf
}
private static string SanitizeClassName(string inputName)
public static string SanitizeClassName(string inputName)
{
if (!IsIdentifierStart(inputName[0]) && IsIdentifierPart(inputName[0]))
{

View File

@ -3,7 +3,6 @@
using System.IO;
using System.Text;
using Microsoft.AspNetCore.Mvc.Razor.Extensions.Internal;
using Microsoft.AspNetCore.Razor.Language;
namespace Microsoft.AspNetCore.Mvc.Razor.Extensions

View File

@ -1,7 +1,6 @@
// 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 Microsoft.AspNetCore.Mvc.Razor.Extensions.Internal;
using Microsoft.AspNetCore.Razor.Language;
using Microsoft.AspNetCore.Razor.Language.Intermediate;

View File

@ -63,13 +63,14 @@ namespace Microsoft.AspNetCore.Mvc.Razor.Extensions
{
// Beautify the class name since we're using a hierarchy for namespaces.
var @class = visitor.FirstClass;
var prefix = Path.GetFileNameWithoutExtension(codeDocument.Source.FileName);
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)
{
@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++)
{
builder.Append('.');
builder.Append(segments[i]);
builder.Append(ClassName.SanitizeClassName(segments[i]));
}
@namespace = builder.ToString();

View File

@ -4,9 +4,9 @@
using System;
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";

View File

@ -1,7 +1,6 @@
// 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 Microsoft.AspNetCore.Mvc.Razor.Extensions.Internal;
using Microsoft.AspNetCore.Razor.Language;
using Microsoft.AspNetCore.Razor.Language.Intermediate;

View File

@ -4,7 +4,6 @@
using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.AspNetCore.Mvc.Razor.Extensions.Internal;
using Microsoft.AspNetCore.Razor.Language;
using Moq;
using Xunit;

View File

@ -2,7 +2,6 @@
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System.IO;
using Microsoft.AspNetCore.Mvc.Razor.Extensions.Internal;
using Microsoft.AspNetCore.Razor.Language;
using Microsoft.AspNetCore.Razor.Language.Intermediate;
using Xunit;

View File

@ -196,6 +196,44 @@ namespace Microsoft.AspNetCore.Mvc.Razor.Extensions
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.
[Fact]
public void Pass_SetsNamespaceAndClassName_ComputedFromSource_ForView()

View File

@ -2,7 +2,6 @@
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System.IO;
using Microsoft.AspNetCore.Mvc.Razor.Extensions.Internal;
using Microsoft.AspNetCore.Razor.Language;
using Microsoft.AspNetCore.Razor.Language.Intermediate;
using Xunit;