Use DocumentClassifierPassBase
Workaround issue with the model directive disappearing
This commit is contained in:
parent
8b03e9ef73
commit
bc3a741eee
|
|
@ -1,177 +0,0 @@
|
|||
// 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.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.IO;
|
||||
using Microsoft.AspNetCore.Razor.Evolution;
|
||||
using Microsoft.AspNetCore.Razor.Evolution.Intermediate;
|
||||
using Microsoft.Extensions.Primitives;
|
||||
|
||||
namespace Microsoft.AspNetCore.Mvc.Razor.Host
|
||||
{
|
||||
public abstract class BaseDocumentClassifierPass : IRazorIRPass
|
||||
{
|
||||
public RazorEngine Engine { get; set; }
|
||||
|
||||
// We want to run before the default, but after others since this is the MVC default.
|
||||
public virtual int Order => RazorIRPass.DefaultDocumentClassifierOrder - 1;
|
||||
|
||||
protected abstract string BaseType { get; }
|
||||
|
||||
public DocumentIRNode Execute(RazorCodeDocument codeDocument, DocumentIRNode irDocument)
|
||||
{
|
||||
if (irDocument.DocumentKind != null)
|
||||
{
|
||||
return irDocument;
|
||||
}
|
||||
|
||||
var documentKind = ClassifyDocument(codeDocument, irDocument);
|
||||
if (documentKind == null)
|
||||
{
|
||||
return irDocument;
|
||||
}
|
||||
|
||||
irDocument.DocumentKind = documentKind;
|
||||
|
||||
return ExecuteCore(codeDocument, irDocument);
|
||||
}
|
||||
|
||||
protected virtual DocumentIRNode ExecuteCore(RazorCodeDocument codeDocument, DocumentIRNode irDocument)
|
||||
{
|
||||
// Rewrite a use default namespace and class declaration.
|
||||
var children = new List<RazorIRNode>(irDocument.Children);
|
||||
irDocument.Children.Clear();
|
||||
|
||||
var @namespace = new NamespaceDeclarationIRNode
|
||||
{
|
||||
Content = "AspNetCore",
|
||||
};
|
||||
|
||||
var @class = new ClassDeclarationIRNode
|
||||
{
|
||||
AccessModifier = "public",
|
||||
Name = GetClassName(codeDocument.Source.Filename) ?? "GeneratedClass",
|
||||
BaseType = BaseType,
|
||||
};
|
||||
|
||||
var method = new RazorMethodDeclarationIRNode()
|
||||
{
|
||||
AccessModifier = "public",
|
||||
Modifiers = new List<string>() { "async", "override" },
|
||||
Name = "ExecuteAsync",
|
||||
ReturnType = "Task",
|
||||
};
|
||||
|
||||
var documentBuilder = RazorIRBuilder.Create(irDocument);
|
||||
|
||||
var namespaceBuilder = RazorIRBuilder.Create(documentBuilder.Current);
|
||||
namespaceBuilder.Push(@namespace);
|
||||
|
||||
var classBuilder = RazorIRBuilder.Create(namespaceBuilder.Current);
|
||||
classBuilder.Push(@class);
|
||||
|
||||
var methodBuilder = RazorIRBuilder.Create(classBuilder.Current);
|
||||
methodBuilder.Push(method);
|
||||
|
||||
var visitor = new Visitor(documentBuilder, namespaceBuilder, classBuilder, methodBuilder);
|
||||
|
||||
for (var i = 0; i < children.Count; i++)
|
||||
{
|
||||
visitor.Visit(children[i]);
|
||||
}
|
||||
|
||||
return irDocument;
|
||||
}
|
||||
|
||||
protected abstract string ClassifyDocument(RazorCodeDocument codeDocument, DocumentIRNode irDocument);
|
||||
|
||||
private static string GetClassName(string filename)
|
||||
{
|
||||
if (filename == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
return SanitizeClassName("Generated_" + Path.GetFileNameWithoutExtension(filename));
|
||||
}
|
||||
|
||||
// CSharp Spec §2.4.2
|
||||
private static bool IsIdentifierStart(char character)
|
||||
{
|
||||
return char.IsLetter(character) ||
|
||||
character == '_' ||
|
||||
CharUnicodeInfo.GetUnicodeCategory(character) == UnicodeCategory.LetterNumber;
|
||||
}
|
||||
|
||||
public static bool IsIdentifierPart(char character)
|
||||
{
|
||||
return char.IsDigit(character) ||
|
||||
IsIdentifierStart(character) ||
|
||||
IsIdentifierPartByUnicodeCategory(character);
|
||||
}
|
||||
|
||||
private static bool IsIdentifierPartByUnicodeCategory(char character)
|
||||
{
|
||||
var category = CharUnicodeInfo.GetUnicodeCategory(character);
|
||||
|
||||
return category == UnicodeCategory.NonSpacingMark || // Mn
|
||||
category == UnicodeCategory.SpacingCombiningMark || // Mc
|
||||
category == UnicodeCategory.ConnectorPunctuation || // Pc
|
||||
category == UnicodeCategory.Format; // Cf
|
||||
}
|
||||
|
||||
public static string SanitizeClassName(string inputName)
|
||||
{
|
||||
if (!IsIdentifierStart(inputName[0]) && IsIdentifierPart(inputName[0]))
|
||||
{
|
||||
inputName = "_" + inputName;
|
||||
}
|
||||
|
||||
var builder = new InplaceStringBuilder(inputName.Length);
|
||||
for (var i = 0; i < inputName.Length; i++)
|
||||
{
|
||||
var ch = inputName[i];
|
||||
builder.Append(IsIdentifierPart(ch) ? ch : '_');
|
||||
}
|
||||
|
||||
return builder.ToString();
|
||||
}
|
||||
|
||||
private class Visitor : RazorIRNodeVisitor
|
||||
{
|
||||
private readonly RazorIRBuilder _document;
|
||||
private readonly RazorIRBuilder _namespace;
|
||||
private readonly RazorIRBuilder _class;
|
||||
private readonly RazorIRBuilder _method;
|
||||
|
||||
public Visitor(RazorIRBuilder document, RazorIRBuilder @namespace, RazorIRBuilder @class, RazorIRBuilder method)
|
||||
{
|
||||
_document = document;
|
||||
_namespace = @namespace;
|
||||
_class = @class;
|
||||
_method = method;
|
||||
}
|
||||
|
||||
public override void VisitChecksum(ChecksumIRNode node)
|
||||
{
|
||||
_document.Insert(0, node);
|
||||
}
|
||||
|
||||
public override void VisitUsingStatement(UsingStatementIRNode node)
|
||||
{
|
||||
_namespace.AddAfter<UsingStatementIRNode>(node);
|
||||
}
|
||||
|
||||
public override void VisitDeclareTagHelperFields(DeclareTagHelperFieldsIRNode node)
|
||||
{
|
||||
_class.Insert(0, node);
|
||||
}
|
||||
|
||||
public override void VisitDefault(RazorIRNode node)
|
||||
{
|
||||
_method.Add(node);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,60 @@
|
|||
using System.Globalization;
|
||||
using Microsoft.Extensions.Primitives;
|
||||
|
||||
namespace Microsoft.AspNetCore.Mvc.Razor.Internal
|
||||
{
|
||||
public static class ClassName
|
||||
{
|
||||
public static string GetClassNameFromPath(string path)
|
||||
{
|
||||
if (string.IsNullOrEmpty(path))
|
||||
{
|
||||
return path;
|
||||
}
|
||||
|
||||
return SanitizeClassName(path);
|
||||
}
|
||||
|
||||
// CSharp Spec §2.4.2
|
||||
private static bool IsIdentifierStart(char character)
|
||||
{
|
||||
return char.IsLetter(character) ||
|
||||
character == '_' ||
|
||||
CharUnicodeInfo.GetUnicodeCategory(character) == UnicodeCategory.LetterNumber;
|
||||
}
|
||||
|
||||
public static bool IsIdentifierPart(char character)
|
||||
{
|
||||
return char.IsDigit(character) ||
|
||||
IsIdentifierStart(character) ||
|
||||
IsIdentifierPartByUnicodeCategory(character);
|
||||
}
|
||||
|
||||
private static bool IsIdentifierPartByUnicodeCategory(char character)
|
||||
{
|
||||
var category = CharUnicodeInfo.GetUnicodeCategory(character);
|
||||
|
||||
return category == UnicodeCategory.NonSpacingMark || // Mn
|
||||
category == UnicodeCategory.SpacingCombiningMark || // Mc
|
||||
category == UnicodeCategory.ConnectorPunctuation || // Pc
|
||||
category == UnicodeCategory.Format; // Cf
|
||||
}
|
||||
|
||||
private static string SanitizeClassName(string inputName)
|
||||
{
|
||||
if (!IsIdentifierStart(inputName[0]) && IsIdentifierPart(inputName[0]))
|
||||
{
|
||||
inputName = "_" + inputName;
|
||||
}
|
||||
|
||||
var builder = new InplaceStringBuilder(inputName.Length);
|
||||
for (var i = 0; i < inputName.Length; i++)
|
||||
{
|
||||
var ch = inputName[i];
|
||||
builder.Append(IsIdentifierPart(ch) ? ch : '_');
|
||||
}
|
||||
|
||||
return builder.ToString();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -42,11 +42,12 @@ namespace Microsoft.AspNetCore.Mvc.Razor.Host
|
|||
var tokens = directive.Tokens.ToArray();
|
||||
if (tokens.Length >= 1)
|
||||
{
|
||||
document.Parent = directive;
|
||||
return tokens[0].Content;
|
||||
}
|
||||
}
|
||||
|
||||
if (document.DocumentKind == RazorPageDocumentClassifier.DocumentKind)
|
||||
if (document.DocumentKind == RazorPageDocumentClassifier.RazorPageDocumentKind)
|
||||
{
|
||||
return visitor.Class.Name;
|
||||
}
|
||||
|
|
@ -94,6 +95,15 @@ namespace Microsoft.AspNetCore.Mvc.Razor.Host
|
|||
|
||||
public IList<DirectiveIRNode> ModelDirectives { get; } = new List<DirectiveIRNode>();
|
||||
|
||||
public override void VisitDocument(DocumentIRNode node)
|
||||
{
|
||||
if (node.Parent != null)
|
||||
{
|
||||
ModelDirectives.Add((DirectiveIRNode)node.Parent);
|
||||
}
|
||||
base.VisitDocument(node);
|
||||
}
|
||||
|
||||
public override void VisitClass(ClassDeclarationIRNode node)
|
||||
{
|
||||
if (Class == null)
|
||||
|
|
|
|||
|
|
@ -1,18 +1,35 @@
|
|||
// 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.Internal;
|
||||
using Microsoft.AspNetCore.Razor.Evolution;
|
||||
using Microsoft.AspNetCore.Razor.Evolution.Intermediate;
|
||||
|
||||
namespace Microsoft.AspNetCore.Mvc.Razor.Host
|
||||
{
|
||||
public class MvcViewDocumentClassifierPass : BaseDocumentClassifierPass
|
||||
public class MvcViewDocumentClassifierPass : DocumentClassifierPassBase
|
||||
{
|
||||
public static readonly string DocumentKind = "mvc.1.0.view";
|
||||
public readonly string MvcViewDocumentKind = "mvc.1.0.view";
|
||||
|
||||
protected override string BaseType => "Microsoft.AspNetCore.Mvc.Razor.RazorPage<TModel>";
|
||||
protected override string DocumentKind => MvcViewDocumentKind;
|
||||
|
||||
protected override string ClassifyDocument(RazorCodeDocument codeDocument, DocumentIRNode irDocument)
|
||||
=> DocumentKind;
|
||||
protected override bool IsMatch(RazorCodeDocument codeDocument, DocumentIRNode irDocument) => true;
|
||||
|
||||
protected override void OnDocumentStructureCreated(
|
||||
RazorCodeDocument codeDocument,
|
||||
NamespaceDeclarationIRNode @namespace,
|
||||
ClassDeclarationIRNode @class,
|
||||
RazorMethodDeclarationIRNode method)
|
||||
{
|
||||
base.OnDocumentStructureCreated(codeDocument, @namespace, @class, method);
|
||||
@class.Name = ClassName.GetClassNameFromPath(codeDocument.Source.Filename);
|
||||
@class.BaseType = "Microsoft.AspNetCore.Mvc.Razor.RazorPage<TModel>";
|
||||
@class.AccessModifier = "public";
|
||||
@namespace.Content = "AspNetCore";
|
||||
method.Name = "ExecuteAsync";
|
||||
method.Modifiers = new[] { "async", "override" };
|
||||
method.AccessModifier = "public";
|
||||
method.ReturnType = $"global::{typeof(System.Threading.Tasks.Task).FullName}";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@ namespace Microsoft.AspNetCore.Mvc.Razor.Host
|
|||
|
||||
public DocumentIRNode Execute(RazorCodeDocument codeDocument, DocumentIRNode irDocument)
|
||||
{
|
||||
if (irDocument.DocumentKind != RazorPageDocumentClassifier.DocumentKind)
|
||||
if (irDocument.DocumentKind != RazorPageDocumentClassifier.RazorPageDocumentKind)
|
||||
{
|
||||
return irDocument;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,26 +1,35 @@
|
|||
// 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.Internal;
|
||||
using Microsoft.AspNetCore.Razor.Evolution;
|
||||
using Microsoft.AspNetCore.Razor.Evolution.Intermediate;
|
||||
|
||||
namespace Microsoft.AspNetCore.Mvc.Razor.Host
|
||||
{
|
||||
public class RazorPageDocumentClassifier : BaseDocumentClassifierPass
|
||||
public class RazorPageDocumentClassifier : DocumentClassifierPassBase
|
||||
{
|
||||
public static readonly string DocumentKind = "mvc.1.0.razor-page";
|
||||
public static readonly string RazorPageDocumentKind = "mvc.1.0.razor-page";
|
||||
|
||||
protected override string BaseType => "Microsoft.AspNetCore.Mvc.RazorPages.Page";
|
||||
protected override string DocumentKind => RazorPageDocumentKind;
|
||||
|
||||
protected override string ClassifyDocument(RazorCodeDocument codeDocument, DocumentIRNode irDocument)
|
||||
protected override bool IsMatch(RazorCodeDocument codeDocument, DocumentIRNode irDocument)
|
||||
{
|
||||
string routePrefix;
|
||||
if (PageDirective.TryGetRouteTemplate(irDocument, out routePrefix))
|
||||
{
|
||||
return DocumentKind;
|
||||
}
|
||||
return PageDirective.TryGetRouteTemplate(irDocument, out routePrefix);
|
||||
}
|
||||
|
||||
return null;
|
||||
protected override void OnDocumentStructureCreated(RazorCodeDocument codeDocument, NamespaceDeclarationIRNode @namespace, ClassDeclarationIRNode @class, RazorMethodDeclarationIRNode method)
|
||||
{
|
||||
base.OnDocumentStructureCreated(codeDocument, @namespace, @class, method);
|
||||
@class.BaseType = "Microsoft.AspNetCore.Mvc.RazorPages.Page";
|
||||
@class.Name = ClassName.GetClassNameFromPath(codeDocument.Source.Filename);
|
||||
@class.AccessModifier = "public";
|
||||
@namespace.Content = "AspNetCore";
|
||||
method.Name = "ExecuteAsync";
|
||||
method.Modifiers = new[] { "async", "override" };
|
||||
method.AccessModifier = "public";
|
||||
method.ReturnType = $"global::{typeof(System.Threading.Tasks.Task).FullName}";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1518,7 +1518,7 @@ namespace Microsoft.AspNetCore.Mvc.Razor
|
|||
{
|
||||
get
|
||||
{
|
||||
var bufferedWriter = Assert.IsType<ViewBufferTextWriter>(Writer);
|
||||
var bufferedWriter = Assert.IsType<ViewBufferTextWriter>(Output);
|
||||
using (var stringWriter = new StringWriter())
|
||||
{
|
||||
bufferedWriter.Buffer.WriteTo(stringWriter, HtmlEncoder);
|
||||
|
|
|
|||
Loading…
Reference in New Issue