First cut of adding API sets
This change defines stages for IR processing. The comments in RazorIRPass really explain the details. I've also made the preliminary changes to the stuff we've built so far to follow the new conventions. This is building towards multitargeting for Razor, being able to target both Razor Pages and Razor MVC Views from the same engine, being able to target different codegen and methods from within the same engine.
This commit is contained in:
parent
f45afb6c19
commit
e84bc66700
|
|
@ -10,21 +10,16 @@ namespace Microsoft.AspNetCore.Razor.Evolution
|
|||
{
|
||||
internal class DefaultDirectiveIRPass : RazorIRPassBase
|
||||
{
|
||||
RazorParserOptions _parserOptions;
|
||||
public override int Order => RazorIRPass.DefaultDirectiveClassifierOrder;
|
||||
|
||||
public override int Order => 150;
|
||||
|
||||
protected override void OnIntialized(RazorCodeDocument codeDocument)
|
||||
public override DocumentIRNode ExecuteCore(RazorCodeDocument codeDocument, DocumentIRNode irDocument)
|
||||
{
|
||||
var syntaxTree = codeDocument.GetSyntaxTree();
|
||||
ThrowForMissingDocumentDependency(syntaxTree);
|
||||
|
||||
_parserOptions = syntaxTree.Options;
|
||||
}
|
||||
var parserOptions = syntaxTree.Options;
|
||||
|
||||
public override DocumentIRNode ExecuteCore(DocumentIRNode irDocument)
|
||||
{
|
||||
var designTime = _parserOptions.DesignTimeMode;
|
||||
var designTime = parserOptions.DesignTimeMode;
|
||||
var walker = new DirectiveWalker(designTime);
|
||||
walker.VisitDocument(irDocument);
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,123 @@
|
|||
// 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 Microsoft.AspNetCore.Razor.Evolution.Intermediate;
|
||||
|
||||
namespace Microsoft.AspNetCore.Razor.Evolution
|
||||
{
|
||||
internal class DefaultDocumentClassifier : RazorIRPassBase
|
||||
{
|
||||
public override int Order => RazorIRPass.DefaultDocumentClassifierOrder;
|
||||
|
||||
public static string DocumentKind = "default";
|
||||
|
||||
public override DocumentIRNode ExecuteCore(RazorCodeDocument codeDocument, DocumentIRNode irDocument)
|
||||
{
|
||||
if (irDocument.DocumentKind != null)
|
||||
{
|
||||
return irDocument;
|
||||
}
|
||||
|
||||
irDocument.DocumentKind = DocumentKind;
|
||||
|
||||
// Rewrite a use default namespace and class declaration.
|
||||
var children = new List<RazorIRNode>(irDocument.Children);
|
||||
irDocument.Children.Clear();
|
||||
|
||||
var @namespace = new NamespaceDeclarationIRNode()
|
||||
{
|
||||
//Content = "GeneratedNamespace",
|
||||
};
|
||||
|
||||
var @class = new ClassDeclarationIRNode()
|
||||
{
|
||||
//AccessModifier = "public",
|
||||
//Name = "GeneratedClass",
|
||||
};
|
||||
|
||||
var method = new RazorMethodDeclarationIRNode()
|
||||
{
|
||||
//AccessModifier = "public",
|
||||
// Modifiers = new List<string>() { "async" },
|
||||
//Name = "Execute",
|
||||
//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;
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
internal override void VisitDeclareTagHelperFields(DeclareTagHelperFieldsIRNode node)
|
||||
{
|
||||
_class.Insert(0, node);
|
||||
}
|
||||
|
||||
public override void VisitDefault(RazorIRNode node)
|
||||
{
|
||||
_method.Add(node);
|
||||
}
|
||||
}
|
||||
|
||||
public void Foo()
|
||||
{
|
||||
//// For prettiness, let's insert the usings before the class declaration.
|
||||
//var i = 0;
|
||||
//for (; i < Namespace.Children.Count; i++)
|
||||
//{
|
||||
// if (Namespace.Children[i] is ClassDeclarationIRNode)
|
||||
// {
|
||||
// break;
|
||||
// }
|
||||
//}
|
||||
|
||||
//var @using = new UsingStatementIRNode()
|
||||
//{
|
||||
// Content = namespaceImport,
|
||||
// SourceRange = BuildSourceRangeFromNode(span),
|
||||
//};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -18,57 +18,51 @@ namespace Microsoft.AspNetCore.Razor.Evolution
|
|||
|
||||
var visitor = new Visitor(codeDocument, syntaxTree.Options);
|
||||
|
||||
var i = 0;
|
||||
var builder = visitor.Builder;
|
||||
foreach (var namespaceImport in syntaxTree.Options.NamespaceImports)
|
||||
{
|
||||
if (visitor.Namespaces.Add(namespaceImport))
|
||||
{
|
||||
var @using = new UsingStatementIRNode()
|
||||
{
|
||||
Content = namespaceImport,
|
||||
};
|
||||
|
||||
builder.Insert(i++, @using);
|
||||
}
|
||||
}
|
||||
|
||||
var checksum = ChecksumIRNode.Create(codeDocument.Source);
|
||||
visitor.Builder.Insert(0, checksum);
|
||||
|
||||
visitor.VisitBlock(syntaxTree.Root);
|
||||
|
||||
|
||||
var irDocument = (DocumentIRNode)visitor.Builder.Build();
|
||||
codeDocument.SetIRDocument(irDocument);
|
||||
}
|
||||
|
||||
private class Visitor : ParserVisitor
|
||||
{
|
||||
private readonly Stack<RazorIRBuilder> _builders;
|
||||
private readonly RazorParserOptions _options;
|
||||
private readonly RazorCodeDocument _codeDocument;
|
||||
|
||||
private DeclareTagHelperFieldsIRNode _tagHelperFields;
|
||||
|
||||
public Visitor(RazorCodeDocument codeDocument, RazorParserOptions options)
|
||||
{
|
||||
_codeDocument = codeDocument;
|
||||
_options = options;
|
||||
_builders = new Stack<RazorIRBuilder>();
|
||||
var document = RazorIRBuilder.Document();
|
||||
_builders.Push(document);
|
||||
|
||||
var checksum = ChecksumIRNode.Create(codeDocument.Source);
|
||||
Builder.Add(checksum);
|
||||
Namespaces = new HashSet<string>();
|
||||
|
||||
Namespace = new NamespaceDeclarationIRNode();
|
||||
Builder.Push(Namespace);
|
||||
|
||||
foreach (var namespaceImport in options.NamespaceImports)
|
||||
{
|
||||
var @using = new UsingStatementIRNode()
|
||||
{
|
||||
Content = namespaceImport,
|
||||
Parent = Namespace,
|
||||
};
|
||||
|
||||
Builder.Add(@using);
|
||||
}
|
||||
|
||||
Class = new ClassDeclarationIRNode();
|
||||
Builder.Push(Class);
|
||||
|
||||
Method = new RazorMethodDeclarationIRNode();
|
||||
Builder.Push(Method);
|
||||
Builder = RazorIRBuilder.Document();
|
||||
}
|
||||
|
||||
public RazorIRBuilder Builder => _builders.Peek();
|
||||
public RazorIRBuilder Builder { get; }
|
||||
|
||||
public NamespaceDeclarationIRNode Namespace { get; }
|
||||
|
||||
public ClassDeclarationIRNode Class { get; }
|
||||
|
||||
public RazorMethodDeclarationIRNode Method { get; }
|
||||
public HashSet<string> Namespaces { get; }
|
||||
|
||||
// Example
|
||||
// <input` checked="hello-world @false"`/>
|
||||
|
|
@ -254,31 +248,15 @@ namespace Microsoft.AspNetCore.Razor.Evolution
|
|||
{
|
||||
var namespaceImport = chunkGenerator.Namespace.Trim();
|
||||
|
||||
if (_options.NamespaceImports.Contains(namespaceImport, StringComparer.Ordinal))
|
||||
// Track seen namespaces so we don't add duplicates from options.
|
||||
if (Namespaces.Add(namespaceImport))
|
||||
{
|
||||
// Already added by default
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// For prettiness, let's insert the usings before the class declaration.
|
||||
var i = 0;
|
||||
for (; i < Namespace.Children.Count; i++)
|
||||
{
|
||||
if (Namespace.Children[i] is ClassDeclarationIRNode)
|
||||
Builder.Add(new UsingStatementIRNode()
|
||||
{
|
||||
break;
|
||||
}
|
||||
Content = namespaceImport,
|
||||
SourceRange = BuildSourceRangeFromNode(span),
|
||||
});
|
||||
}
|
||||
|
||||
var @using = new UsingStatementIRNode()
|
||||
{
|
||||
Content = namespaceImport,
|
||||
Parent = Namespace,
|
||||
SourceRange = BuildSourceRangeFromNode(span),
|
||||
};
|
||||
|
||||
Namespace.Children.Insert(i, @using);
|
||||
}
|
||||
|
||||
public override void VisitDirectiveToken(DirectiveTokenChunkGenerator chunkGenerator, Span span)
|
||||
|
|
@ -355,19 +333,15 @@ namespace Microsoft.AspNetCore.Razor.Evolution
|
|||
|
||||
private void DeclareTagHelperFields(TagHelperBlock block)
|
||||
{
|
||||
var declareFieldsNode = Class.Children.OfType<DeclareTagHelperFieldsIRNode>().SingleOrDefault();
|
||||
if (declareFieldsNode == null)
|
||||
if (_tagHelperFields == null)
|
||||
{
|
||||
declareFieldsNode = new DeclareTagHelperFieldsIRNode();
|
||||
declareFieldsNode.Parent = Class;
|
||||
|
||||
var methodIndex = Class.Children.IndexOf(Method);
|
||||
Class.Children.Insert(methodIndex, declareFieldsNode);
|
||||
_tagHelperFields = new DeclareTagHelperFieldsIRNode();
|
||||
Builder.Add(_tagHelperFields);
|
||||
}
|
||||
|
||||
foreach (var descriptor in block.Descriptors)
|
||||
{
|
||||
declareFieldsNode.UsedTagHelperTypeNames.Add(descriptor.TypeName);
|
||||
_tagHelperFields.UsedTagHelperTypeNames.Add(descriptor.TypeName);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -31,8 +31,27 @@ namespace Microsoft.AspNetCore.Razor.Evolution.Intermediate
|
|||
throw new ArgumentNullException(nameof(node));
|
||||
}
|
||||
|
||||
Push(node);
|
||||
Pop();
|
||||
node.Parent = Current;
|
||||
Current.Children.Add(node);
|
||||
}
|
||||
|
||||
public override void Insert(int index, RazorIRNode node)
|
||||
{
|
||||
if (index < 0 || index - Current.Children.Count > 0)
|
||||
{
|
||||
throw new ArgumentOutOfRangeException(nameof(index));
|
||||
}
|
||||
|
||||
node.Parent = Current;
|
||||
if (index == Current.Children.Count)
|
||||
{
|
||||
// Allow inserting at 'Children.Count' to be friendlier than List<> typically is.
|
||||
Current.Children.Add(node);
|
||||
}
|
||||
else
|
||||
{
|
||||
Current.Children.Insert(index, node);
|
||||
}
|
||||
}
|
||||
|
||||
public override RazorIRNode Build()
|
||||
|
|
|
|||
|
|
@ -11,6 +11,8 @@ namespace Microsoft.AspNetCore.Razor.Evolution.Intermediate
|
|||
{
|
||||
public override IList<RazorIRNode> Children { get; } = new List<RazorIRNode>();
|
||||
|
||||
public string DocumentKind { get; set; }
|
||||
|
||||
public override RazorIRNode Parent { get; set; }
|
||||
|
||||
internal override MappingLocation SourceRange { get; set; }
|
||||
|
|
|
|||
|
|
@ -28,6 +28,8 @@ namespace Microsoft.AspNetCore.Razor.Evolution.Intermediate
|
|||
|
||||
public abstract void Add(RazorIRNode node);
|
||||
|
||||
public abstract void Insert(int index, RazorIRNode node);
|
||||
|
||||
public abstract RazorIRNode Build();
|
||||
|
||||
public abstract void Push(RazorIRNode node);
|
||||
|
|
|
|||
|
|
@ -0,0 +1,25 @@
|
|||
// 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.
|
||||
|
||||
namespace Microsoft.AspNetCore.Razor.Evolution.Intermediate
|
||||
{
|
||||
public static class RazorIRBuilderExtensions
|
||||
{
|
||||
public static void AddAfter<TNode>(this RazorIRBuilder builder, RazorIRNode node)
|
||||
where TNode : RazorIRNode
|
||||
{
|
||||
var children = builder.Current.Children;
|
||||
var i = children.Count - 1;
|
||||
for (; i >= 0; i--)
|
||||
{
|
||||
var child = children[i];
|
||||
if (child is TNode || child.GetType() == node.GetType())
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
builder.Insert(i + 1, node);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -12,9 +12,9 @@ namespace Microsoft.AspNetCore.Razor.Evolution
|
|||
{
|
||||
internal const string DesignTimeVariable = "__o";
|
||||
|
||||
public override int Order => 25;
|
||||
public override int Order => RazorIRPass.DirectiveClassifierOrder;
|
||||
|
||||
public override DocumentIRNode ExecuteCore(DocumentIRNode irDocument)
|
||||
public override DocumentIRNode ExecuteCore(RazorCodeDocument codeDocument, DocumentIRNode irDocument)
|
||||
{
|
||||
var walker = new DesignTimeHelperWalker();
|
||||
walker.VisitDocument(irDocument);
|
||||
|
|
|
|||
|
|
@ -59,6 +59,7 @@ namespace Microsoft.AspNetCore.Razor.Evolution
|
|||
builder.Features.Add(new TagHelperBinderSyntaxTreePass());
|
||||
|
||||
// IR Passes
|
||||
builder.Features.Add(new DefaultDocumentClassifier());
|
||||
builder.Features.Add(new DefaultDirectiveIRPass());
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,87 @@
|
|||
// 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.Razor.Evolution.Intermediate;
|
||||
|
||||
namespace Microsoft.AspNetCore.Razor.Evolution
|
||||
{
|
||||
/// <summary>
|
||||
/// Provides constants for ordering of <see cref="IRazorIRPass"/> objects. When implementing an
|
||||
/// <see cref="IRazorIRPass"/>, choose a value for <see cref="IRazorIRPass.Order"/> according to
|
||||
/// the logical task that must be performed.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// <para>
|
||||
/// <see cref="IRazorIRPass"/> objects are executed according to an ascending ordering of the
|
||||
/// <see cref="IRazorIRPass.Order"/> property. The default configuration of <see cref="RazorEngine"/>
|
||||
/// prescribes a logical ordering of specific phases of IR processing.
|
||||
/// </para>
|
||||
/// <para>
|
||||
/// The IR document is first produced by <see cref="IRazorIRLoweringPhase"/>. At this point no IR passes have
|
||||
/// been executed. The default <see cref="IRazorIRLoweringPhase"/> will perform a mechanical transformation
|
||||
/// of the syntax tree to IR resulting in a mostly flat structure. It is up to later phases to give the document
|
||||
/// structure and semantics according to a document kind. The default <see cref="IRazorIRLoweringPhase"/> is
|
||||
/// also responsible for synthesizing IR nodes for global cross-current concerns such as checksums or global settings.
|
||||
/// </para>
|
||||
/// <para>
|
||||
/// The first phase of IR procesing is document classification. IR passes in this phase should classify the
|
||||
/// document according to any relevant criteria (project configuration, file extension, directive) and modify
|
||||
/// the IR tree to suit the desired document shape. Document classifiers should also set
|
||||
/// <see cref="DocumentIRNode.DocumentKind"/> to prevent other classifiers from running. If no classifier
|
||||
/// matches the document, then it will be classified as "generic" and processed according to set
|
||||
/// of reasonable defaults.
|
||||
/// </para>
|
||||
/// <para>
|
||||
/// The second phase of IR processing is directive classification. IR passes in this phase should interpret
|
||||
/// directives and processing them accordingly by transforming IR nodes or adding diagnostics to the IR. At
|
||||
/// this time the document kind has been identified, so any directive that can't be applied should trigger
|
||||
/// errors. If implementing a document kind that diverges from the standard structure of Razor documents
|
||||
/// it may be necessary to reimplement processing of default directives.
|
||||
/// </para>
|
||||
/// <para>
|
||||
/// The last phase of IR processing is lowering. IR passes in this phase perform some kind of transformation
|
||||
/// on the IR that optimizes the generated code. The key distinction here is that information may be discarded
|
||||
/// during this phase.
|
||||
/// </para>
|
||||
/// <para>
|
||||
/// Finally, the <see cref="IRazorCSharpLoweringPhase"/> transforms the IR document into generated C# code.
|
||||
/// At this time any directives or IR constructs that cannot be understood by code generation will result
|
||||
/// in an error.
|
||||
/// </para>
|
||||
/// </remarks>
|
||||
public static class RazorIRPass
|
||||
{
|
||||
/// <summary>
|
||||
/// An <see cref="IRazorIRPass"/> that implements a document classifier should use this value as its
|
||||
/// <see cref="IRazorIRPass.Order"/>.
|
||||
/// </summary>
|
||||
public static readonly int DocumentClassifierOrder = 1100;
|
||||
|
||||
/// <summary>
|
||||
/// <see cref="IRazorIRPass.Order"/> value used by the default document classifier.
|
||||
/// </summary>
|
||||
public static readonly int DefaultDocumentClassifierOrder = 1900;
|
||||
|
||||
/// <summary>
|
||||
/// An <see cref="IRazorIRPass"/> that implements a directive classifier should use this value as its
|
||||
/// <see cref="IRazorIRPass.Order"/>.
|
||||
/// </summary>
|
||||
public static readonly int DirectiveClassifierOrder = 2100;
|
||||
|
||||
/// <summary>
|
||||
/// <see cref="IRazorIRPass.Order"/> value used by the default directive classifier.
|
||||
/// </summary>
|
||||
public static readonly int DefaultDirectiveClassifierOrder = 2900;
|
||||
|
||||
/// <summary>
|
||||
/// An <see cref="IRazorIRPass"/> that implements a lowering phase should use this value as its
|
||||
/// <see cref="IRazorIRPass.Order"/>.
|
||||
/// </summary>
|
||||
public static readonly int LoweringOrder = 4100;
|
||||
|
||||
/// <summary>
|
||||
/// <see cref="IRazorIRPass.Order"/> value used by the default lowering phase.
|
||||
/// </summary>
|
||||
public static readonly int DefaultLoweringOrder = 4900;
|
||||
}
|
||||
}
|
||||
|
|
@ -8,9 +8,24 @@ namespace Microsoft.AspNetCore.Razor.Evolution
|
|||
{
|
||||
internal abstract class RazorIRPassBase : IRazorIRPass
|
||||
{
|
||||
public RazorEngine Engine { get; set; }
|
||||
private RazorEngine _engine;
|
||||
|
||||
public virtual int Order => 0;
|
||||
public RazorEngine Engine
|
||||
{
|
||||
get { return _engine; }
|
||||
set
|
||||
{
|
||||
if (value == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(value));
|
||||
}
|
||||
|
||||
_engine = value;
|
||||
OnIntialized();
|
||||
}
|
||||
}
|
||||
|
||||
public abstract int Order { get; }
|
||||
|
||||
protected void ThrowForMissingDocumentDependency<TDocumentDependency>(TDocumentDependency value)
|
||||
{
|
||||
|
|
@ -36,7 +51,7 @@ namespace Microsoft.AspNetCore.Razor.Evolution
|
|||
}
|
||||
}
|
||||
|
||||
protected virtual void OnIntialized(RazorCodeDocument codeDocument)
|
||||
protected virtual void OnIntialized()
|
||||
{
|
||||
}
|
||||
|
||||
|
|
@ -57,11 +72,9 @@ namespace Microsoft.AspNetCore.Razor.Evolution
|
|||
throw new InvalidOperationException(Resources.FormatPhaseMustBeInitialized(nameof(Engine)));
|
||||
}
|
||||
|
||||
OnIntialized(codeDocument);
|
||||
|
||||
return ExecuteCore(irDocument);
|
||||
return ExecuteCore(codeDocument, irDocument);
|
||||
}
|
||||
|
||||
public abstract DocumentIRNode ExecuteCore(DocumentIRNode irDocument);
|
||||
public abstract DocumentIRNode ExecuteCore(RazorCodeDocument codeDocument, DocumentIRNode irDocument);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -180,7 +180,7 @@ namespace Microsoft.AspNetCore.Razor.Evolution
|
|||
{
|
||||
var phase = engine.Phases[i];
|
||||
phase.Execute(codeDocument);
|
||||
|
||||
|
||||
if (phase is IRazorIRLoweringPhase)
|
||||
{
|
||||
break;
|
||||
|
|
@ -189,6 +189,9 @@ namespace Microsoft.AspNetCore.Razor.Evolution
|
|||
|
||||
var irDocument = codeDocument.GetIRDocument();
|
||||
Assert.NotNull(irDocument);
|
||||
|
||||
// These tests depend on the document->namespace->class structure.
|
||||
irDocument = new DefaultDocumentClassifier() { Engine = engine, }.Execute(codeDocument, irDocument);
|
||||
return irDocument;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,149 @@
|
|||
// 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.Razor.Evolution.Intermediate;
|
||||
using Xunit;
|
||||
using static Microsoft.AspNetCore.Razor.Evolution.Intermediate.RazorIRAssert;
|
||||
|
||||
namespace Microsoft.AspNetCore.Razor.Evolution
|
||||
{
|
||||
public class DefaultDocumentClassifierTest
|
||||
{
|
||||
[Fact]
|
||||
public void Execute_IgnoresDocumentsWithDocumentKind()
|
||||
{
|
||||
// Arrange
|
||||
var irDocument = new DocumentIRNode()
|
||||
{
|
||||
DocumentKind = "ignore",
|
||||
};
|
||||
|
||||
var pass = new DefaultDocumentClassifier();
|
||||
pass.Engine = RazorEngine.CreateEmpty(b => { });
|
||||
|
||||
// Act
|
||||
pass.Execute(TestRazorCodeDocument.CreateEmpty(), irDocument);
|
||||
|
||||
// Assert
|
||||
Assert.Equal("ignore", irDocument.DocumentKind);
|
||||
NoChildren(irDocument);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Execute_CreatesClassStructure()
|
||||
{
|
||||
// Arrange
|
||||
var irDocument = new DocumentIRNode();
|
||||
|
||||
var pass = new DefaultDocumentClassifier();
|
||||
pass.Engine = RazorEngine.CreateEmpty(b =>{ });
|
||||
|
||||
// Act
|
||||
pass.Execute(TestRazorCodeDocument.CreateEmpty(), irDocument);
|
||||
|
||||
// Assert
|
||||
Assert.Equal(DefaultDocumentClassifier.DocumentKind, irDocument.DocumentKind);
|
||||
|
||||
var @namespace = SingleChild<NamespaceDeclarationIRNode>(irDocument);
|
||||
var @class = SingleChild<ClassDeclarationIRNode>(@namespace);
|
||||
var method = SingleChild<RazorMethodDeclarationIRNode>(@class);
|
||||
NoChildren(method);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Execute_AddsCheckumFirstToDocument()
|
||||
{
|
||||
// Arrange
|
||||
var irDocument = new DocumentIRNode();
|
||||
|
||||
var builder = RazorIRBuilder.Create(irDocument);
|
||||
builder.Add(new ChecksumIRNode());
|
||||
|
||||
var pass = new DefaultDocumentClassifier();
|
||||
pass.Engine = RazorEngine.CreateEmpty(b => { });
|
||||
|
||||
// Act
|
||||
pass.Execute(TestRazorCodeDocument.CreateEmpty(), irDocument);
|
||||
|
||||
// Assert
|
||||
Children(
|
||||
irDocument,
|
||||
n => Assert.IsType<ChecksumIRNode>(n),
|
||||
n => Assert.IsType<NamespaceDeclarationIRNode>(n));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Execute_AddsUsingsToNamespace()
|
||||
{
|
||||
// Arrange
|
||||
var irDocument = new DocumentIRNode();
|
||||
|
||||
var builder = RazorIRBuilder.Create(irDocument);
|
||||
builder.Add(new UsingStatementIRNode());
|
||||
|
||||
var pass = new DefaultDocumentClassifier();
|
||||
pass.Engine = RazorEngine.CreateEmpty(b => { });
|
||||
|
||||
// Act
|
||||
pass.Execute(TestRazorCodeDocument.CreateEmpty(), irDocument);
|
||||
|
||||
// Assert
|
||||
var @namespace = SingleChild<NamespaceDeclarationIRNode>(irDocument);
|
||||
Children(
|
||||
@namespace,
|
||||
n => Assert.IsType<UsingStatementIRNode>(n),
|
||||
n => Assert.IsType<ClassDeclarationIRNode>(n));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Execute_AddsTagHelperFieldsToClass()
|
||||
{
|
||||
// Arrange
|
||||
var irDocument = new DocumentIRNode();
|
||||
|
||||
var builder = RazorIRBuilder.Create(irDocument);
|
||||
builder.Add(new DeclareTagHelperFieldsIRNode());
|
||||
|
||||
var pass = new DefaultDocumentClassifier();
|
||||
pass.Engine = RazorEngine.CreateEmpty(b => { });
|
||||
|
||||
// Act
|
||||
pass.Execute(TestRazorCodeDocument.CreateEmpty(), irDocument);
|
||||
|
||||
// Assert
|
||||
var @namespace = SingleChild<NamespaceDeclarationIRNode>(irDocument);
|
||||
var @class = SingleChild<ClassDeclarationIRNode>(@namespace);
|
||||
Children(
|
||||
@class,
|
||||
n => Assert.IsType<DeclareTagHelperFieldsIRNode>(n),
|
||||
n => Assert.IsType<RazorMethodDeclarationIRNode>(n));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Execute_AddsTheRestToMethod()
|
||||
{
|
||||
// Arrange
|
||||
var irDocument = new DocumentIRNode();
|
||||
|
||||
var builder = RazorIRBuilder.Create(irDocument);
|
||||
builder.Add(new HtmlContentIRNode());
|
||||
builder.Add(new CSharpStatementIRNode());
|
||||
|
||||
var pass = new DefaultDocumentClassifier();
|
||||
pass.Engine = RazorEngine.CreateEmpty(b => { });
|
||||
|
||||
// Act
|
||||
pass.Execute(TestRazorCodeDocument.CreateEmpty(), irDocument);
|
||||
|
||||
// Assert
|
||||
var @namespace = SingleChild<NamespaceDeclarationIRNode>(irDocument);
|
||||
var @class = SingleChild<ClassDeclarationIRNode>(@namespace);
|
||||
var method = SingleChild<RazorMethodDeclarationIRNode>(@class);
|
||||
Children(
|
||||
method,
|
||||
n => Assert.IsType<HtmlContentIRNode>(n),
|
||||
n => Assert.IsType<CSharpStatementIRNode>(n));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1466,7 +1466,9 @@ namespace Microsoft.AspNetCore.Razor.Evolution.IntegrationTests
|
|||
|
||||
private class ApiSetsIRTestAdapter : RazorIRPassBase
|
||||
{
|
||||
public override DocumentIRNode ExecuteCore(DocumentIRNode irDocument)
|
||||
public override int Order => RazorIRPass.LoweringOrder;
|
||||
|
||||
public override DocumentIRNode ExecuteCore(RazorCodeDocument codeDocument, DocumentIRNode irDocument)
|
||||
{
|
||||
var walker = new ApiSetsIRWalker();
|
||||
walker.Visit(irDocument);
|
||||
|
|
|
|||
|
|
@ -0,0 +1,9 @@
|
|||
// 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.
|
||||
|
||||
namespace Microsoft.AspNetCore.Razor.Evolution.IntegrationTests
|
||||
{
|
||||
public class PageDocumentIntegrationTest
|
||||
{
|
||||
}
|
||||
}
|
||||
|
|
@ -107,7 +107,7 @@ namespace Microsoft.AspNetCore.Razor.Evolution.Intermediate
|
|||
}
|
||||
|
||||
[Fact]
|
||||
public void Add_DoesPushAndPop()
|
||||
public void Add_AddsToChildrenAndSetsParent()
|
||||
{
|
||||
// Arrange
|
||||
var builder = new DefaultRazorIRBuilder();
|
||||
|
|
@ -126,6 +126,72 @@ namespace Microsoft.AspNetCore.Razor.Evolution.Intermediate
|
|||
Assert.Collection(parent.Children, n => Assert.Same(node, n));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Insert_AddsToChildrenAndSetsParent_EmptyCollection()
|
||||
{
|
||||
// Arrange
|
||||
var builder = new DefaultRazorIRBuilder();
|
||||
|
||||
var parent = new BasicIRNode();
|
||||
builder.Push(parent);
|
||||
|
||||
var node = new BasicIRNode();
|
||||
|
||||
// Act
|
||||
builder.Insert(0, node);
|
||||
|
||||
// Assert
|
||||
Assert.Same(parent, builder.Current);
|
||||
Assert.Same(parent, node.Parent);
|
||||
Assert.Collection(parent.Children, n => Assert.Same(node, n));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Insert_AddsToChildrenAndSetsParent_NonEmpyCollection()
|
||||
{
|
||||
// Arrange
|
||||
var builder = new DefaultRazorIRBuilder();
|
||||
|
||||
var parent = new BasicIRNode();
|
||||
builder.Push(parent);
|
||||
|
||||
var child = new BasicIRNode();
|
||||
builder.Add(child);
|
||||
|
||||
var node = new BasicIRNode();
|
||||
|
||||
// Act
|
||||
builder.Insert(0, node);
|
||||
|
||||
// Assert
|
||||
Assert.Same(parent, builder.Current);
|
||||
Assert.Same(parent, node.Parent);
|
||||
Assert.Collection(parent.Children, n => Assert.Same(node, n), n => Assert.Same(child, n));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Insert_AddsToChildrenAndSetsParent_NonEmpyCollection_AtEnd()
|
||||
{
|
||||
// Arrange
|
||||
var builder = new DefaultRazorIRBuilder();
|
||||
|
||||
var parent = new BasicIRNode();
|
||||
builder.Push(parent);
|
||||
|
||||
var child = new BasicIRNode();
|
||||
builder.Add(child);
|
||||
|
||||
var node = new BasicIRNode();
|
||||
|
||||
// Act
|
||||
builder.Insert(1, node);
|
||||
|
||||
// Assert
|
||||
Assert.Same(parent, builder.Current);
|
||||
Assert.Same(parent, node.Parent);
|
||||
Assert.Collection(parent.Children, n => Assert.Same(child, n), n => Assert.Same(node, n));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Build_PopsMultipleLevels()
|
||||
{
|
||||
|
|
|
|||
|
|
@ -1,20 +1,20 @@
|
|||
// 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 static Microsoft.AspNetCore.Razor.Evolution.Intermediate.RazorIRAssert;
|
||||
using Xunit;
|
||||
using System;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.Razor.Evolution.Legacy;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.Razor.Evolution.Legacy;
|
||||
using Xunit;
|
||||
using static Microsoft.AspNetCore.Razor.Evolution.Intermediate.RazorIRAssert;
|
||||
|
||||
namespace Microsoft.AspNetCore.Razor.Evolution.Intermediate
|
||||
{
|
||||
public class DefaultRazorIRLoweringPhaseIntegrationTest
|
||||
{
|
||||
[Fact]
|
||||
public void Lower_EmptyDocument()
|
||||
public void Lower_EmptyDocument_AddsGlobalUsingsAndNamespace()
|
||||
{
|
||||
// Arrange
|
||||
var codeDocument = TestRazorCodeDocument.CreateEmpty();
|
||||
|
|
@ -25,15 +25,8 @@ namespace Microsoft.AspNetCore.Razor.Evolution.Intermediate
|
|||
// Assert
|
||||
Children(irDocument,
|
||||
n => Assert.IsType<ChecksumIRNode>(n),
|
||||
n => Assert.IsType<NamespaceDeclarationIRNode>(n));
|
||||
var @namespace = irDocument.Children[1];
|
||||
Children(@namespace,
|
||||
n => Assert.IsType<UsingStatementIRNode>(n),
|
||||
n => Assert.IsType<UsingStatementIRNode>(n),
|
||||
n => Assert.IsType<ClassDeclarationIRNode>(n));
|
||||
var @class = @namespace.Children[2];
|
||||
var method = SingleChild<RazorMethodDeclarationIRNode>(@class);
|
||||
Assert.Empty(method.Children);
|
||||
n => Using("System", n),
|
||||
n => Using("System.Threading.Tasks", n));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
|
|
@ -48,17 +41,9 @@ namespace Microsoft.AspNetCore.Razor.Evolution.Intermediate
|
|||
// Assert
|
||||
Children(irDocument,
|
||||
n => Assert.IsType<ChecksumIRNode>(n),
|
||||
n => Assert.IsType<NamespaceDeclarationIRNode>(n));
|
||||
var @namespace = irDocument.Children[1];
|
||||
Children(@namespace,
|
||||
n => Assert.IsType<UsingStatementIRNode>(n),
|
||||
n => Assert.IsType<UsingStatementIRNode>(n),
|
||||
n => Assert.IsType<ClassDeclarationIRNode>(n));
|
||||
var @class = @namespace.Children[2];
|
||||
var method = SingleChild<RazorMethodDeclarationIRNode>(@class);
|
||||
var html = SingleChild<HtmlContentIRNode>(method);
|
||||
|
||||
Assert.Equal("Hello, World!", html.Content);
|
||||
n => Html("Hello, World!", n));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
|
|
@ -78,15 +63,8 @@ namespace Microsoft.AspNetCore.Razor.Evolution.Intermediate
|
|||
// Assert
|
||||
Children(irDocument,
|
||||
n => Assert.IsType<ChecksumIRNode>(n),
|
||||
n => Assert.IsType<NamespaceDeclarationIRNode>(n));
|
||||
var @namespace = irDocument.Children[1];
|
||||
Children(@namespace,
|
||||
n => Assert.IsType<UsingStatementIRNode>(n),
|
||||
n => Assert.IsType<UsingStatementIRNode>(n),
|
||||
n => Assert.IsType<ClassDeclarationIRNode>(n));
|
||||
var @class = @namespace.Children[2];
|
||||
var method = SingleChild<RazorMethodDeclarationIRNode>(@class);
|
||||
Children(method,
|
||||
n => Html(
|
||||
@"
|
||||
<html>
|
||||
|
|
@ -115,15 +93,8 @@ namespace Microsoft.AspNetCore.Razor.Evolution.Intermediate
|
|||
// Assert
|
||||
Children(irDocument,
|
||||
n => Assert.IsType<ChecksumIRNode>(n),
|
||||
n => Assert.IsType<NamespaceDeclarationIRNode>(n));
|
||||
var @namespace = irDocument.Children[1];
|
||||
Children(@namespace,
|
||||
n => Assert.IsType<UsingStatementIRNode>(n),
|
||||
n => Assert.IsType<UsingStatementIRNode>(n),
|
||||
n => Assert.IsType<ClassDeclarationIRNode>(n));
|
||||
var @class = @namespace.Children[2];
|
||||
var method = SingleChild<RazorMethodDeclarationIRNode>(@class);
|
||||
Children(method,
|
||||
n => Html(
|
||||
@"
|
||||
<html>
|
||||
|
|
@ -157,16 +128,12 @@ namespace Microsoft.AspNetCore.Razor.Evolution.Intermediate
|
|||
// Assert
|
||||
Children(irDocument,
|
||||
n => Assert.IsType<ChecksumIRNode>(n),
|
||||
n => Assert.IsType<NamespaceDeclarationIRNode>(n));
|
||||
var @namespace = irDocument.Children[1];
|
||||
Children(@namespace,
|
||||
n => Assert.IsType<UsingStatementIRNode>(n),
|
||||
n => Assert.IsType<UsingStatementIRNode>(n),
|
||||
n => Assert.IsType<ClassDeclarationIRNode>(n));
|
||||
var @class = @namespace.Children[2];
|
||||
Children(@class,
|
||||
n => Assert.IsType<RazorMethodDeclarationIRNode>(n),
|
||||
n => Assert.IsType<CSharpStatementIRNode>(n));
|
||||
n => Directive(
|
||||
"functions",
|
||||
n,
|
||||
c => Assert.IsType<CSharpStatementIRNode>(c)));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
|
|
@ -181,12 +148,8 @@ namespace Microsoft.AspNetCore.Razor.Evolution.Intermediate
|
|||
// Assert
|
||||
Children(irDocument,
|
||||
n => Assert.IsType<ChecksumIRNode>(n),
|
||||
n => Assert.IsType<NamespaceDeclarationIRNode>(n));
|
||||
var @namespace = irDocument.Children[1];
|
||||
Children(@namespace,
|
||||
n => Using("System", n),
|
||||
n => Using(typeof(Task).Namespace, n),
|
||||
n => Assert.IsType<ClassDeclarationIRNode>(n));
|
||||
n => Using(typeof(Task).Namespace, n));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
|
|
@ -209,28 +172,23 @@ namespace Microsoft.AspNetCore.Razor.Evolution.Intermediate
|
|||
// Assert
|
||||
Children(irDocument,
|
||||
n => Assert.IsType<ChecksumIRNode>(n),
|
||||
n => Assert.IsType<NamespaceDeclarationIRNode>(n));
|
||||
var @namespace = irDocument.Children[1];
|
||||
Children(@namespace,
|
||||
n => Using("System", n),
|
||||
n => Using(typeof(Task).Namespace, n),
|
||||
n => Assert.IsType<ClassDeclarationIRNode>(n));
|
||||
var @class = @namespace.Children[2];
|
||||
Children(@class,
|
||||
n => TagHelperFieldDeclaration(n, "SpanTagHelper"),
|
||||
n => Assert.IsType<RazorMethodDeclarationIRNode>(n));
|
||||
var method = @class.Children[1];
|
||||
var tagHelperNode = SingleChild<TagHelperIRNode>(method);
|
||||
Children(tagHelperNode,
|
||||
n => TagHelperStructure("span", TagMode.StartTagAndEndTag, n),
|
||||
n => Assert.IsType<CreateTagHelperIRNode>(n),
|
||||
n => TagHelperHtmlAttribute(
|
||||
"val",
|
||||
HtmlAttributeValueStyle.DoubleQuotes,
|
||||
n,
|
||||
v => CSharpAttributeValue(string.Empty, "Hello", v),
|
||||
v => LiteralAttributeValue(" ", "World", v)),
|
||||
n => Assert.IsType<ExecuteTagHelpersIRNode>(n));
|
||||
n =>
|
||||
{
|
||||
var tagHelperNode = Assert.IsType<TagHelperIRNode>(n);
|
||||
Children(tagHelperNode,
|
||||
c => TagHelperStructure("span", TagMode.StartTagAndEndTag, c),
|
||||
c => Assert.IsType<CreateTagHelperIRNode>(c),
|
||||
c => TagHelperHtmlAttribute(
|
||||
"val",
|
||||
HtmlAttributeValueStyle.DoubleQuotes,
|
||||
c,
|
||||
v => CSharpAttributeValue(string.Empty, "Hello", v),
|
||||
v => LiteralAttributeValue(" ", "World", v)),
|
||||
c => Assert.IsType<ExecuteTagHelpersIRNode>(c));
|
||||
});
|
||||
}
|
||||
|
||||
[Fact]
|
||||
|
|
@ -256,28 +214,23 @@ namespace Microsoft.AspNetCore.Razor.Evolution.Intermediate
|
|||
// Assert
|
||||
Children(irDocument,
|
||||
n => Assert.IsType<ChecksumIRNode>(n),
|
||||
n => Assert.IsType<NamespaceDeclarationIRNode>(n));
|
||||
var @namespace = irDocument.Children[1];
|
||||
Children(@namespace,
|
||||
n => Using("System", n),
|
||||
n => Using(typeof(Task).Namespace, n),
|
||||
n => Assert.IsType<ClassDeclarationIRNode>(n));
|
||||
var @class = @namespace.Children[2];
|
||||
Children(@class,
|
||||
n => TagHelperFieldDeclaration(n, "InputTagHelper"),
|
||||
n => Assert.IsType<RazorMethodDeclarationIRNode>(n));
|
||||
var method = @class.Children[1];
|
||||
var tagHelperNode = SingleChild<TagHelperIRNode>(method);
|
||||
Children(tagHelperNode,
|
||||
n => TagHelperStructure("input", TagMode.SelfClosing, n),
|
||||
n => Assert.IsType<CreateTagHelperIRNode>(n),
|
||||
n => SetTagHelperProperty(
|
||||
"bound",
|
||||
"FooProp",
|
||||
HtmlAttributeValueStyle.SingleQuotes,
|
||||
n,
|
||||
v => Html("foo", v)),
|
||||
n => Assert.IsType<ExecuteTagHelpersIRNode>(n));
|
||||
n =>
|
||||
{
|
||||
var tagHelperNode = Assert.IsType<TagHelperIRNode>(n);
|
||||
Children(tagHelperNode,
|
||||
c => TagHelperStructure("input", TagMode.SelfClosing, c),
|
||||
c => Assert.IsType<CreateTagHelperIRNode>(c),
|
||||
c => SetTagHelperProperty(
|
||||
"bound",
|
||||
"FooProp",
|
||||
HtmlAttributeValueStyle.SingleQuotes,
|
||||
c,
|
||||
v => Html("foo", v)),
|
||||
c => Assert.IsType<ExecuteTagHelpersIRNode>(c));
|
||||
});
|
||||
}
|
||||
|
||||
private DocumentIRNode Lower(RazorCodeDocument codeDocument)
|
||||
|
|
@ -287,15 +240,17 @@ namespace Microsoft.AspNetCore.Razor.Evolution.Intermediate
|
|||
|
||||
private DocumentIRNode Lower(RazorCodeDocument codeDocument, IEnumerable<TagHelperDescriptor> descriptors)
|
||||
{
|
||||
var engine = RazorEngine.Create(
|
||||
builder => builder.Features.Add(new TagHelperFeature(new TestTagHelperDescriptorResolver(descriptors))));
|
||||
var engine = RazorEngine.Create(builder =>
|
||||
{
|
||||
builder.Features.Add(new TagHelperFeature(new TestTagHelperDescriptorResolver(descriptors)));
|
||||
});
|
||||
|
||||
for (var i = 0; i < engine.Phases.Count; i++)
|
||||
{
|
||||
var phase = engine.Phases[i];
|
||||
phase.Execute(codeDocument);
|
||||
|
||||
if (phase is IRazorIRPhase)
|
||||
if (phase is IRazorIRLoweringPhase)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
|
@ -303,6 +258,7 @@ namespace Microsoft.AspNetCore.Razor.Evolution.Intermediate
|
|||
|
||||
var irDocument = codeDocument.GetIRDocument();
|
||||
Assert.NotNull(irDocument);
|
||||
|
||||
return irDocument;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,132 @@
|
|||
// 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.Evolution.Legacy;
|
||||
using Microsoft.AspNetCore.Testing;
|
||||
using Xunit;
|
||||
|
||||
namespace Microsoft.AspNetCore.Razor.Evolution.Intermediate
|
||||
{
|
||||
public class RazorIRBuilderExtensionsTest
|
||||
{
|
||||
[Fact]
|
||||
public void AddAfter_EmptyList()
|
||||
{
|
||||
// Arrange
|
||||
var builder = RazorIRBuilder.Document();
|
||||
|
||||
var node = new BasicIRNode3();
|
||||
|
||||
// Act
|
||||
builder.AddAfter<BasicIRNode>(node);
|
||||
|
||||
// Assert
|
||||
Assert.Collection(builder.Current.Children, n => Assert.Same(node, n));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void AddAfter_AfterMatch()
|
||||
{
|
||||
// Arrange
|
||||
var builder = RazorIRBuilder.Document();
|
||||
builder.Add(new BasicIRNode());
|
||||
builder.Add(new BasicIRNode());
|
||||
builder.Add(new BasicIRNode3());
|
||||
|
||||
var node = new BasicIRNode3();
|
||||
|
||||
// Act
|
||||
builder.AddAfter<BasicIRNode>(node);
|
||||
|
||||
// Assert
|
||||
Assert.Collection(
|
||||
builder.Current.Children,
|
||||
n => Assert.IsType<BasicIRNode>(n),
|
||||
n => Assert.IsType<BasicIRNode>(n),
|
||||
n => Assert.IsType<BasicIRNode3>(n),
|
||||
n => Assert.Same(node, n));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void AddAfter_AfterMatch_Noncontinuous()
|
||||
{
|
||||
// Arrange
|
||||
var builder = RazorIRBuilder.Document();
|
||||
builder.Add(new BasicIRNode());
|
||||
builder.Add(new BasicIRNode2());
|
||||
builder.Add(new BasicIRNode());
|
||||
|
||||
var node = new BasicIRNode3();
|
||||
|
||||
// Act
|
||||
builder.AddAfter<BasicIRNode>(node);
|
||||
|
||||
// Assert
|
||||
Assert.Collection(
|
||||
builder.Current.Children,
|
||||
n => Assert.IsType<BasicIRNode>(n),
|
||||
n => Assert.IsType<BasicIRNode2>(n),
|
||||
n => Assert.IsType<BasicIRNode>(n),
|
||||
n => Assert.Same(node, n));
|
||||
}
|
||||
|
||||
private class BasicIRNode : RazorIRNode
|
||||
{
|
||||
public override IList<RazorIRNode> Children { get; } = new List<RazorIRNode>();
|
||||
|
||||
public override RazorIRNode Parent { get; set; }
|
||||
|
||||
internal override MappingLocation SourceRange { get; set; }
|
||||
|
||||
public override void Accept(RazorIRNodeVisitor visitor)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public override TResult Accept<TResult>(RazorIRNodeVisitor<TResult> visitor)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
|
||||
private class BasicIRNode2 : RazorIRNode
|
||||
{
|
||||
public override IList<RazorIRNode> Children { get; } = new List<RazorIRNode>();
|
||||
|
||||
public override RazorIRNode Parent { get; set; }
|
||||
|
||||
internal override MappingLocation SourceRange { get; set; }
|
||||
|
||||
public override void Accept(RazorIRNodeVisitor visitor)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public override TResult Accept<TResult>(RazorIRNodeVisitor<TResult> visitor)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
|
||||
private class BasicIRNode3 : RazorIRNode
|
||||
{
|
||||
public override IList<RazorIRNode> Children { get; } = new List<RazorIRNode>();
|
||||
|
||||
public override RazorIRNode Parent { get; set; }
|
||||
|
||||
internal override MappingLocation SourceRange { get; set; }
|
||||
|
||||
public override void Accept(RazorIRNodeVisitor visitor)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public override TResult Accept<TResult>(RazorIRNodeVisitor<TResult> visitor)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -139,6 +139,7 @@ namespace Microsoft.AspNetCore.Razor.Evolution
|
|||
feature => Assert.IsType<DefaultDirectiveSyntaxTreePass>(feature),
|
||||
feature => Assert.IsType<HtmlNodeOptimizationPass>(feature),
|
||||
feature => Assert.IsType<TagHelperBinderSyntaxTreePass>(feature),
|
||||
feature => Assert.IsType<DefaultDocumentClassifier>(feature),
|
||||
feature => Assert.IsType<DefaultDirectiveIRPass>(feature));
|
||||
}
|
||||
|
||||
|
|
@ -160,6 +161,7 @@ namespace Microsoft.AspNetCore.Razor.Evolution
|
|||
feature => Assert.IsType<DefaultDirectiveSyntaxTreePass>(feature),
|
||||
feature => Assert.IsType<HtmlNodeOptimizationPass>(feature),
|
||||
feature => Assert.IsType<TagHelperBinderSyntaxTreePass>(feature),
|
||||
feature => Assert.IsType<DefaultDocumentClassifier>(feature),
|
||||
feature => Assert.IsType<DefaultDirectiveIRPass>(feature),
|
||||
feature => Assert.IsType<RazorEngine.ConfigureDesignTimeOptions>(feature),
|
||||
feature => Assert.IsType<RazorDesignTimeIRPass>(feature));
|
||||
|
|
|
|||
|
|
@ -14,7 +14,8 @@ namespace Microsoft.AspNetCore.Razor.Evolution.IntegrationTests.TestFiles
|
|||
#pragma warning disable 1998
|
||||
public async System.Threading.Tasks.Task ExecuteAsync()
|
||||
{
|
||||
WriteLiteral("\r\n\r\n<p>Path\'s full type name is ");
|
||||
WriteLiteral("\r\n");
|
||||
WriteLiteral("\r\n<p>Path\'s full type name is ");
|
||||
#line 9 "TestFiles/IntegrationTests/CodeGenerationIntegrationTest/Imports.cshtml"
|
||||
Write(typeof(Path).FullName);
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue