Add RazorIRNodeReference for manipulating nodes
This commit is contained in:
parent
1fb3c8c26f
commit
6ce71c24e5
|
|
@ -8,7 +8,7 @@ namespace Microsoft.AspNetCore.Mvc.Razor.Extensions
|
||||||
internal static class ViewComponentResources
|
internal static class ViewComponentResources
|
||||||
{
|
{
|
||||||
private static readonly ResourceManager _resourceManager
|
private static readonly ResourceManager _resourceManager
|
||||||
= new ResourceManager("Microsoft.CodeAnalysis.Razor.ViewComponentResources", typeof(ViewComponentResources).GetTypeInfo().Assembly);
|
= new ResourceManager("Microsoft.AspNetCore.Mvc.Razor.Extensions.ViewComponentResources", typeof(ViewComponentResources).GetTypeInfo().Assembly);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// View component '{0}' must have exactly one public method named '{1}' or '{2}'.
|
/// View component '{0}' must have exactly one public method named '{1}' or '{2}'.
|
||||||
|
|
|
||||||
|
|
@ -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 System;
|
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
|
@ -9,7 +8,6 @@ using System.Threading.Tasks;
|
||||||
using Microsoft.AspNetCore.Razor.Language;
|
using Microsoft.AspNetCore.Razor.Language;
|
||||||
using Microsoft.AspNetCore.Razor.Language.Intermediate;
|
using Microsoft.AspNetCore.Razor.Language.Intermediate;
|
||||||
using Microsoft.AspNetCore.Razor.Language.Legacy;
|
using Microsoft.AspNetCore.Razor.Language.Legacy;
|
||||||
using Microsoft.CodeAnalysis.Razor;
|
|
||||||
|
|
||||||
namespace Microsoft.AspNetCore.Mvc.Razor.Extensions
|
namespace Microsoft.AspNetCore.Mvc.Razor.Extensions
|
||||||
{
|
{
|
||||||
|
|
@ -37,9 +35,9 @@ namespace Microsoft.AspNetCore.Mvc.Razor.Extensions
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach (var (node, parent) in visitor.CreateTagHelpers)
|
foreach (var (parent, node) in visitor.CreateTagHelpers)
|
||||||
{
|
{
|
||||||
RewriteCreateNode(visitor.Namespace, visitor.Class, node, parent);
|
RewriteCreateNode(visitor.Namespace, visitor.Class, (CreateTagHelperIRNode)node, parent);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -230,7 +228,7 @@ namespace Microsoft.AspNetCore.Mvc.Razor.Extensions
|
||||||
|
|
||||||
public NamespaceDeclarationIRNode Namespace { get; private set; }
|
public NamespaceDeclarationIRNode Namespace { get; private set; }
|
||||||
|
|
||||||
public List<(CreateTagHelperIRNode node, RazorIRNode parent)> CreateTagHelpers { get; } = new List<(CreateTagHelperIRNode node, RazorIRNode parent)>();
|
public List<RazorIRNodeReference> CreateTagHelpers { get; } = new List<RazorIRNodeReference>();
|
||||||
|
|
||||||
public Dictionary<string, TagHelperDescriptor> TagHelpers { get; } = new Dictionary<string, TagHelperDescriptor>();
|
public Dictionary<string, TagHelperDescriptor> TagHelpers { get; } = new Dictionary<string, TagHelperDescriptor>();
|
||||||
|
|
||||||
|
|
@ -243,7 +241,7 @@ namespace Microsoft.AspNetCore.Mvc.Razor.Extensions
|
||||||
var vcName = tagHelper.Metadata[ViewComponentTagHelperDescriptorConventions.ViewComponentNameKey];
|
var vcName = tagHelper.Metadata[ViewComponentTagHelperDescriptorConventions.ViewComponentNameKey];
|
||||||
TagHelpers[vcName] = tagHelper;
|
TagHelpers[vcName] = tagHelper;
|
||||||
|
|
||||||
CreateTagHelpers.Add((node, Parent));
|
CreateTagHelpers.Add(new RazorIRNodeReference(Parent, node));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -16,25 +16,28 @@ namespace Microsoft.AspNetCore.Razor.Language
|
||||||
var parserOptions = irDocument.Options;
|
var parserOptions = irDocument.Options;
|
||||||
|
|
||||||
var designTime = parserOptions.DesignTime;
|
var designTime = parserOptions.DesignTime;
|
||||||
var walker = new DirectiveWalker();
|
|
||||||
walker.VisitDocument(irDocument);
|
|
||||||
|
|
||||||
var classNode = walker.ClassNode;
|
var classNode = irDocument.FindPrimaryClass();
|
||||||
foreach (var (node, parent) in walker.FunctionsDirectiveNodes)
|
if (classNode == null)
|
||||||
{
|
{
|
||||||
parent.Children.Remove(node);
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
foreach (var child in node.Children.Except(node.Tokens))
|
foreach (var functions in irDocument.FindDirectiveReferences(CSharpCodeParser.FunctionsDirectiveDescriptor))
|
||||||
|
{
|
||||||
|
functions.Remove();
|
||||||
|
|
||||||
|
for (var i =0; i < functions.Node.Children.Count; i++)
|
||||||
{
|
{
|
||||||
classNode.Children.Add(child);
|
classNode.Children.Add(functions.Node.Children[i]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach (var (node, parent) in walker.InheritsDirectiveNodes.Reverse())
|
foreach (var inherits in irDocument.FindDirectiveReferences(CSharpCodeParser.InheritsDirectiveDescriptor).Reverse())
|
||||||
{
|
{
|
||||||
parent.Children.Remove(node);
|
inherits.Remove();
|
||||||
|
|
||||||
var token = node.Tokens.FirstOrDefault();
|
var token = ((DirectiveIRNode)inherits.Node).Tokens.FirstOrDefault();
|
||||||
if (token != null)
|
if (token != null)
|
||||||
{
|
{
|
||||||
classNode.BaseType = token.Content;
|
classNode.BaseType = token.Content;
|
||||||
|
|
@ -42,74 +45,30 @@ namespace Microsoft.AspNetCore.Razor.Language
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach (var (node, parent) in walker.SectionDirectiveNodes)
|
foreach (var section in irDocument.FindDirectiveReferences(CSharpCodeParser.SectionDirectiveDescriptor))
|
||||||
{
|
{
|
||||||
var sectionIndex = parent.Children.IndexOf(node);
|
|
||||||
parent.Children.Remove(node);
|
|
||||||
|
|
||||||
var defineSectionEndStatement = new CSharpCodeIRNode();
|
|
||||||
RazorIRBuilder.Create(defineSectionEndStatement)
|
|
||||||
.Add(new RazorIRToken()
|
|
||||||
{
|
|
||||||
Kind = RazorIRToken.TokenKind.CSharp,
|
|
||||||
Content = "});"
|
|
||||||
});
|
|
||||||
|
|
||||||
parent.Children.Insert(sectionIndex, defineSectionEndStatement);
|
|
||||||
|
|
||||||
foreach (var child in node.Children.Except(node.Tokens).Reverse())
|
|
||||||
{
|
|
||||||
parent.Children.Insert(sectionIndex, child);
|
|
||||||
}
|
|
||||||
|
|
||||||
var lambdaContent = designTime ? "__razor_section_writer" : string.Empty;
|
var lambdaContent = designTime ? "__razor_section_writer" : string.Empty;
|
||||||
var sectionName = node.Tokens.FirstOrDefault()?.Content;
|
var sectionName = ((DirectiveIRNode)section.Node).Tokens.FirstOrDefault()?.Content;
|
||||||
var defineSectionStartStatement = new CSharpCodeIRNode();
|
|
||||||
RazorIRBuilder.Create(defineSectionStartStatement)
|
|
||||||
.Add(new RazorIRToken()
|
|
||||||
{
|
|
||||||
Kind = RazorIRToken.TokenKind.CSharp,
|
|
||||||
Content = $"DefineSection(\"{sectionName}\", async ({lambdaContent}) => {{"
|
|
||||||
});
|
|
||||||
|
|
||||||
parent.Children.Insert(sectionIndex, defineSectionStartStatement);
|
var builder = RazorIRBuilder.Create(new CSharpCodeIRNode());
|
||||||
}
|
builder.Add(new RazorIRToken()
|
||||||
}
|
|
||||||
|
|
||||||
private class DirectiveWalker : RazorIRNodeWalker
|
|
||||||
{
|
|
||||||
public ClassDeclarationIRNode ClassNode { get; private set; }
|
|
||||||
|
|
||||||
public IList<(DirectiveIRNode node, RazorIRNode parent)> FunctionsDirectiveNodes { get; } = new List<(DirectiveIRNode node, RazorIRNode parent)>();
|
|
||||||
|
|
||||||
public IList<(DirectiveIRNode node, RazorIRNode parent)> InheritsDirectiveNodes { get; } = new List<(DirectiveIRNode node, RazorIRNode parent)>();
|
|
||||||
|
|
||||||
public IList<(DirectiveIRNode node, RazorIRNode parent)> SectionDirectiveNodes { get; } = new List<(DirectiveIRNode node, RazorIRNode parent)>();
|
|
||||||
|
|
||||||
public override void VisitClassDeclaration(ClassDeclarationIRNode node)
|
|
||||||
{
|
|
||||||
if (ClassNode == null)
|
|
||||||
{
|
{
|
||||||
ClassNode = node;
|
Kind = RazorIRToken.TokenKind.CSharp,
|
||||||
}
|
Content = $"DefineSection(\"{sectionName}\", async ({lambdaContent}) => {{"
|
||||||
|
});
|
||||||
|
section.InsertBefore(builder.Build());
|
||||||
|
|
||||||
|
section.InsertBefore(section.Node.Children.Except(((DirectiveIRNode)section.Node).Tokens));
|
||||||
|
|
||||||
VisitDefault(node);
|
builder = RazorIRBuilder.Create(new CSharpCodeIRNode());
|
||||||
}
|
builder.Add(new RazorIRToken()
|
||||||
|
{
|
||||||
|
Kind = RazorIRToken.TokenKind.CSharp,
|
||||||
|
Content = "});"
|
||||||
|
});
|
||||||
|
section.InsertAfter(builder.Build());
|
||||||
|
|
||||||
public override void VisitDirective(DirectiveIRNode node)
|
section.Remove();
|
||||||
{
|
|
||||||
if (string.Equals(node.Name, CSharpCodeParser.FunctionsDirectiveDescriptor.Directive, StringComparison.Ordinal))
|
|
||||||
{
|
|
||||||
FunctionsDirectiveNodes.Add((node, Parent));
|
|
||||||
}
|
|
||||||
else if (string.Equals(node.Name, CSharpCodeParser.InheritsDirectiveDescriptor.Directive, StringComparison.Ordinal))
|
|
||||||
{
|
|
||||||
InheritsDirectiveNodes.Add((node, Parent));
|
|
||||||
}
|
|
||||||
else if (string.Equals(node.Name, CSharpCodeParser.SectionDirectiveDescriptor.Directive, StringComparison.Ordinal))
|
|
||||||
{
|
|
||||||
SectionDirectiveNodes.Add((node, Parent));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,7 @@
|
||||||
// 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;
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
|
||||||
namespace Microsoft.AspNetCore.Razor.Language.Intermediate
|
namespace Microsoft.AspNetCore.Razor.Language.Intermediate
|
||||||
{
|
{
|
||||||
|
|
@ -37,6 +38,23 @@ namespace Microsoft.AspNetCore.Razor.Language.Intermediate
|
||||||
return FindWithAnnotation<NamespaceDeclarationIRNode>(node, CommonAnnotations.PrimaryNamespace);
|
return FindWithAnnotation<NamespaceDeclarationIRNode>(node, CommonAnnotations.PrimaryNamespace);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static IReadOnlyList<RazorIRNodeReference> FindDirectiveReferences(this DocumentIRNode node, DirectiveDescriptor directive)
|
||||||
|
{
|
||||||
|
if (node == null)
|
||||||
|
{
|
||||||
|
throw new ArgumentNullException(nameof(node));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (directive == null)
|
||||||
|
{
|
||||||
|
throw new ArgumentNullException(nameof(directive));
|
||||||
|
}
|
||||||
|
|
||||||
|
var visitor = new DirectiveVisitor(directive);
|
||||||
|
visitor.Visit(node);
|
||||||
|
return visitor.Directives;
|
||||||
|
}
|
||||||
|
|
||||||
private static T FindWithAnnotation<T>(RazorIRNode node, object annotation) where T : RazorIRNode
|
private static T FindWithAnnotation<T>(RazorIRNode node, object annotation) where T : RazorIRNode
|
||||||
{
|
{
|
||||||
if (node is T target && object.ReferenceEquals(target.Annotations[annotation], annotation))
|
if (node is T target && object.ReferenceEquals(target.Annotations[annotation], annotation))
|
||||||
|
|
@ -55,5 +73,27 @@ namespace Microsoft.AspNetCore.Razor.Language.Intermediate
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private class DirectiveVisitor : RazorIRNodeWalker
|
||||||
|
{
|
||||||
|
private readonly DirectiveDescriptor _directive;
|
||||||
|
|
||||||
|
public DirectiveVisitor(DirectiveDescriptor directive)
|
||||||
|
{
|
||||||
|
_directive = directive;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<RazorIRNodeReference> Directives = new List<RazorIRNodeReference>();
|
||||||
|
|
||||||
|
public override void VisitDirective(DirectiveIRNode node)
|
||||||
|
{
|
||||||
|
if (_directive == node.Descriptor)
|
||||||
|
{
|
||||||
|
Directives.Add(new RazorIRNodeReference(Parent, node));
|
||||||
|
}
|
||||||
|
|
||||||
|
base.VisitDirective(node);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,209 @@
|
||||||
|
// 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;
|
||||||
|
|
||||||
|
namespace Microsoft.AspNetCore.Razor.Language.Intermediate
|
||||||
|
{
|
||||||
|
public struct RazorIRNodeReference
|
||||||
|
{
|
||||||
|
public RazorIRNodeReference(RazorIRNode parent, RazorIRNode node)
|
||||||
|
{
|
||||||
|
if (parent == null)
|
||||||
|
{
|
||||||
|
throw new ArgumentNullException(nameof(parent));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (node == null)
|
||||||
|
{
|
||||||
|
throw new ArgumentNullException(nameof(node));
|
||||||
|
}
|
||||||
|
|
||||||
|
Parent = parent;
|
||||||
|
Node = node;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Deconstruct(out RazorIRNode parent, out RazorIRNode node)
|
||||||
|
{
|
||||||
|
parent = Parent;
|
||||||
|
node = Node;
|
||||||
|
}
|
||||||
|
|
||||||
|
public RazorIRNode Node { get; }
|
||||||
|
|
||||||
|
public RazorIRNode Parent { get; }
|
||||||
|
|
||||||
|
public RazorIRNodeReference InsertAfter(RazorIRNode node)
|
||||||
|
{
|
||||||
|
if (node == null)
|
||||||
|
{
|
||||||
|
throw new ArgumentNullException(nameof(node));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Parent == null)
|
||||||
|
{
|
||||||
|
throw new InvalidOperationException(Resources.IRNodeReference_NotInitialized);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Parent.Children.IsReadOnly)
|
||||||
|
{
|
||||||
|
throw new InvalidOperationException(Resources.FormatIRNodeReference_CollectionIsReadOnly(Parent));
|
||||||
|
}
|
||||||
|
|
||||||
|
var index = Parent.Children.IndexOf(Node);
|
||||||
|
if (index == -1)
|
||||||
|
{
|
||||||
|
throw new InvalidOperationException(Resources.FormatIRNodeReference_NodeNotFound(
|
||||||
|
Node,
|
||||||
|
Parent));
|
||||||
|
}
|
||||||
|
|
||||||
|
Parent.Children.Insert(index + 1, node);
|
||||||
|
return new RazorIRNodeReference(Parent, node);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void InsertAfter(IEnumerable<RazorIRNode> nodes)
|
||||||
|
{
|
||||||
|
if (nodes == null)
|
||||||
|
{
|
||||||
|
throw new ArgumentNullException(nameof(nodes));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Parent == null)
|
||||||
|
{
|
||||||
|
throw new InvalidOperationException(Resources.IRNodeReference_NotInitialized);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Parent.Children.IsReadOnly)
|
||||||
|
{
|
||||||
|
throw new InvalidOperationException(Resources.FormatIRNodeReference_CollectionIsReadOnly(Parent));
|
||||||
|
}
|
||||||
|
|
||||||
|
var index = Parent.Children.IndexOf(Node);
|
||||||
|
if (index == -1)
|
||||||
|
{
|
||||||
|
throw new InvalidOperationException(Resources.FormatIRNodeReference_NodeNotFound(
|
||||||
|
Node,
|
||||||
|
Parent));
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (var node in nodes)
|
||||||
|
{
|
||||||
|
Parent.Children.Insert(++index, node);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public RazorIRNodeReference InsertBefore(RazorIRNode node)
|
||||||
|
{
|
||||||
|
if (node == null)
|
||||||
|
{
|
||||||
|
throw new ArgumentNullException(nameof(node));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Parent == null)
|
||||||
|
{
|
||||||
|
throw new InvalidOperationException(Resources.IRNodeReference_NotInitialized);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Parent.Children.IsReadOnly)
|
||||||
|
{
|
||||||
|
throw new InvalidOperationException(Resources.FormatIRNodeReference_CollectionIsReadOnly(Parent));
|
||||||
|
}
|
||||||
|
|
||||||
|
var index = Parent.Children.IndexOf(Node);
|
||||||
|
if (index == -1)
|
||||||
|
{
|
||||||
|
throw new InvalidOperationException(Resources.FormatIRNodeReference_NodeNotFound(
|
||||||
|
Node,
|
||||||
|
Parent));
|
||||||
|
}
|
||||||
|
|
||||||
|
Parent.Children.Insert(index, node);
|
||||||
|
return new RazorIRNodeReference(Parent, node);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void InsertBefore(IEnumerable<RazorIRNode> nodes)
|
||||||
|
{
|
||||||
|
if (nodes == null)
|
||||||
|
{
|
||||||
|
throw new ArgumentNullException(nameof(nodes));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Parent == null)
|
||||||
|
{
|
||||||
|
throw new InvalidOperationException(Resources.IRNodeReference_NotInitialized);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Parent.Children.IsReadOnly)
|
||||||
|
{
|
||||||
|
throw new InvalidOperationException(Resources.FormatIRNodeReference_CollectionIsReadOnly(Parent));
|
||||||
|
}
|
||||||
|
|
||||||
|
var index = Parent.Children.IndexOf(Node);
|
||||||
|
if (index == -1)
|
||||||
|
{
|
||||||
|
throw new InvalidOperationException(Resources.FormatIRNodeReference_NodeNotFound(
|
||||||
|
Node,
|
||||||
|
Parent));
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (var node in nodes)
|
||||||
|
{
|
||||||
|
Parent.Children.Insert(index++, node);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Remove()
|
||||||
|
{
|
||||||
|
if (Parent == null)
|
||||||
|
{
|
||||||
|
throw new InvalidOperationException(Resources.IRNodeReference_NotInitialized);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Parent.Children.IsReadOnly)
|
||||||
|
{
|
||||||
|
throw new InvalidOperationException(Resources.FormatIRNodeReference_CollectionIsReadOnly(Parent));
|
||||||
|
}
|
||||||
|
|
||||||
|
var index = Parent.Children.IndexOf(Node);
|
||||||
|
if (index == -1)
|
||||||
|
{
|
||||||
|
throw new InvalidOperationException(Resources.FormatIRNodeReference_NodeNotFound(
|
||||||
|
Node,
|
||||||
|
Parent));
|
||||||
|
}
|
||||||
|
|
||||||
|
Parent.Children.RemoveAt(index);
|
||||||
|
}
|
||||||
|
|
||||||
|
public RazorIRNodeReference Replace(RazorIRNode node)
|
||||||
|
{
|
||||||
|
if (node == null)
|
||||||
|
{
|
||||||
|
throw new ArgumentNullException(nameof(node));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Parent == null)
|
||||||
|
{
|
||||||
|
throw new InvalidOperationException(Resources.IRNodeReference_NotInitialized);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Parent.Children.IsReadOnly)
|
||||||
|
{
|
||||||
|
throw new InvalidOperationException(Resources.FormatIRNodeReference_CollectionIsReadOnly(Parent));
|
||||||
|
}
|
||||||
|
|
||||||
|
var index = Parent.Children.IndexOf(Node);
|
||||||
|
if (index == -1)
|
||||||
|
{
|
||||||
|
throw new InvalidOperationException(Resources.FormatIRNodeReference_NodeNotFound(
|
||||||
|
Node,
|
||||||
|
Parent));
|
||||||
|
}
|
||||||
|
|
||||||
|
Parent.Children[index] = node;
|
||||||
|
return new RazorIRNodeReference(Parent, node);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -458,6 +458,48 @@ namespace Microsoft.AspNetCore.Razor.Language
|
||||||
internal static string FormatKeyMustNotBeNull()
|
internal static string FormatKeyMustNotBeNull()
|
||||||
=> GetString("KeyMustNotBeNull");
|
=> GetString("KeyMustNotBeNull");
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The reference is invalid. The node '{0}' could not be found as a child of '{1}'.
|
||||||
|
/// </summary>
|
||||||
|
internal static string IRNodeReference_NodeNotFound
|
||||||
|
{
|
||||||
|
get => GetString("IRNodeReference_NodeNotFound");
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The reference is invalid. The node '{0}' could not be found as a child of '{1}'.
|
||||||
|
/// </summary>
|
||||||
|
internal static string FormatIRNodeReference_NodeNotFound(object p0, object p1)
|
||||||
|
=> string.Format(CultureInfo.CurrentCulture, GetString("IRNodeReference_NodeNotFound"), p0, p1);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The reference is invalid. References initialized with the default constructor cannot modify nodes.
|
||||||
|
/// </summary>
|
||||||
|
internal static string IRNodeReference_NotInitialized
|
||||||
|
{
|
||||||
|
get => GetString("IRNodeReference_NotInitialized");
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The reference is invalid. References initialized with the default constructor cannot modify nodes.
|
||||||
|
/// </summary>
|
||||||
|
internal static string FormatIRNodeReference_NotInitialized()
|
||||||
|
=> GetString("IRNodeReference_NotInitialized");
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The node '{0}' has a read-only child collection and cannot be modified.
|
||||||
|
/// </summary>
|
||||||
|
internal static string IRNodeReference_CollectionIsReadOnly
|
||||||
|
{
|
||||||
|
get => GetString("IRNodeReference_CollectionIsReadOnly");
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The node '{0}' has a read-only child collection and cannot be modified.
|
||||||
|
/// </summary>
|
||||||
|
internal static string FormatIRNodeReference_CollectionIsReadOnly(object p0)
|
||||||
|
=> string.Format(CultureInfo.CurrentCulture, GetString("IRNodeReference_CollectionIsReadOnly"), p0);
|
||||||
|
|
||||||
private static string GetString(string name, params string[] formatterNames)
|
private static string GetString(string name, params string[] formatterNames)
|
||||||
{
|
{
|
||||||
var value = _resourceManager.GetString(name);
|
var value = _resourceManager.GetString(name);
|
||||||
|
|
|
||||||
|
|
@ -213,4 +213,13 @@
|
||||||
<data name="KeyMustNotBeNull" xml:space="preserve">
|
<data name="KeyMustNotBeNull" xml:space="preserve">
|
||||||
<value>The key must not be null.</value>
|
<value>The key must not be null.</value>
|
||||||
</data>
|
</data>
|
||||||
|
<data name="IRNodeReference_NodeNotFound" xml:space="preserve">
|
||||||
|
<value>The reference is invalid. The node '{0}' could not be found as a child of '{1}'.</value>
|
||||||
|
</data>
|
||||||
|
<data name="IRNodeReference_NotInitialized" xml:space="preserve">
|
||||||
|
<value>The reference is invalid. References initialized with the default constructor cannot modify nodes.</value>
|
||||||
|
</data>
|
||||||
|
<data name="IRNodeReference_CollectionIsReadOnly" xml:space="preserve">
|
||||||
|
<value>The node '{0}' has a read-only child collection and cannot be modified.</value>
|
||||||
|
</data>
|
||||||
</root>
|
</root>
|
||||||
|
|
@ -60,5 +60,54 @@ namespace Microsoft.AspNetCore.Razor.Language.Intermediate
|
||||||
// Assert
|
// Assert
|
||||||
Assert.Same(@namespace, result);
|
Assert.Same(@namespace, result);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void FindDirectiveReferences_FindsMatchingDirectives()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var directive = DirectiveDescriptor.CreateSingleLineDirective("test");
|
||||||
|
var directive2 = DirectiveDescriptor.CreateSingleLineDirective("test");
|
||||||
|
|
||||||
|
var document = new DocumentIRNode();
|
||||||
|
var @namespace = new NamespaceDeclarationIRNode();
|
||||||
|
|
||||||
|
var builder = RazorIRBuilder.Create(document);
|
||||||
|
builder.Push(@namespace);
|
||||||
|
|
||||||
|
var match1 = new DirectiveIRNode()
|
||||||
|
{
|
||||||
|
Descriptor = directive,
|
||||||
|
};
|
||||||
|
builder.Add(match1);
|
||||||
|
|
||||||
|
var nonMatch = new DirectiveIRNode()
|
||||||
|
{
|
||||||
|
Descriptor = directive2,
|
||||||
|
};
|
||||||
|
builder.Add(nonMatch);
|
||||||
|
|
||||||
|
var match2 = new DirectiveIRNode()
|
||||||
|
{
|
||||||
|
Descriptor = directive,
|
||||||
|
};
|
||||||
|
builder.Add(match2);
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var results = document.FindDirectiveReferences(directive);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.Collection(
|
||||||
|
results,
|
||||||
|
r =>
|
||||||
|
{
|
||||||
|
Assert.Same(@namespace, r.Parent);
|
||||||
|
Assert.Same(match1, r.Node);
|
||||||
|
},
|
||||||
|
r =>
|
||||||
|
{
|
||||||
|
Assert.Same(@namespace, r.Parent);
|
||||||
|
Assert.Same(match2, r.Node);
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,514 @@
|
||||||
|
// 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 Xunit;
|
||||||
|
|
||||||
|
namespace Microsoft.AspNetCore.Razor.Language.Intermediate
|
||||||
|
{
|
||||||
|
public class RazorIRNodeReferenceTest
|
||||||
|
{
|
||||||
|
[Fact]
|
||||||
|
public void InsertAfter_SingleNode_AddsNodeAfterNode()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var parent = new BasicIRNode("Parent");
|
||||||
|
|
||||||
|
var node1 = new BasicIRNode("Node1");
|
||||||
|
var node2 = new BasicIRNode("Node2");
|
||||||
|
var node3 = new BasicIRNode("Node3");
|
||||||
|
|
||||||
|
parent.Children.Add(node1);
|
||||||
|
parent.Children.Add(node3);
|
||||||
|
|
||||||
|
var reference = new RazorIRNodeReference(parent, node1);
|
||||||
|
|
||||||
|
// Act
|
||||||
|
reference.InsertAfter(node2);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.Equal(new[] { node1, node2, node3, }, parent.Children);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void InsertAfter_SingleNode_AddsNodeAfterNode_AtEnd()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var parent = new BasicIRNode("Parent");
|
||||||
|
|
||||||
|
var node1 = new BasicIRNode("Node1");
|
||||||
|
var node2 = new BasicIRNode("Node2");
|
||||||
|
var node3 = new BasicIRNode("Node3");
|
||||||
|
|
||||||
|
parent.Children.Add(node1);
|
||||||
|
parent.Children.Add(node2);
|
||||||
|
|
||||||
|
var reference = new RazorIRNodeReference(parent, node2);
|
||||||
|
|
||||||
|
// Act
|
||||||
|
reference.InsertAfter(node3);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.Equal(new[] { node1, node2, node3, }, parent.Children);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void InsertAfter_MultipleNodes_AddsNodesAfterNode()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var parent = new BasicIRNode("Parent");
|
||||||
|
|
||||||
|
var node1 = new BasicIRNode("Node1");
|
||||||
|
var node2 = new BasicIRNode("Node2");
|
||||||
|
var node3 = new BasicIRNode("Node3");
|
||||||
|
var node4 = new BasicIRNode("Node4");
|
||||||
|
|
||||||
|
parent.Children.Add(node1);
|
||||||
|
parent.Children.Add(node4);
|
||||||
|
|
||||||
|
var reference = new RazorIRNodeReference(parent, node1);
|
||||||
|
|
||||||
|
// Act
|
||||||
|
reference.InsertAfter(new[] { node2, node3 });
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.Equal(new[] { node1, node2, node3, node4, }, parent.Children);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void InsertAfter_MultipleNodes_AddsNodesAfterNode_AtEnd()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var parent = new BasicIRNode("Parent");
|
||||||
|
|
||||||
|
var node1 = new BasicIRNode("Node1");
|
||||||
|
var node2 = new BasicIRNode("Node2");
|
||||||
|
var node3 = new BasicIRNode("Node3");
|
||||||
|
var node4 = new BasicIRNode("Node4");
|
||||||
|
|
||||||
|
parent.Children.Add(node1);
|
||||||
|
parent.Children.Add(node2);
|
||||||
|
|
||||||
|
var reference = new RazorIRNodeReference(parent, node2);
|
||||||
|
|
||||||
|
// Act
|
||||||
|
reference.InsertAfter(new[] { node3, node4 });
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.Equal(new[] { node1, node2, node3, node4, }, parent.Children);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void InsertBefore_SingleNode_AddsNodeBeforeNode()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var parent = new BasicIRNode("Parent");
|
||||||
|
|
||||||
|
var node1 = new BasicIRNode("Node1");
|
||||||
|
var node2 = new BasicIRNode("Node2");
|
||||||
|
var node3 = new BasicIRNode("Node3");
|
||||||
|
|
||||||
|
parent.Children.Add(node1);
|
||||||
|
parent.Children.Add(node3);
|
||||||
|
|
||||||
|
var reference = new RazorIRNodeReference(parent, node3);
|
||||||
|
|
||||||
|
// Act
|
||||||
|
reference.InsertBefore(node2);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.Equal(new[] { node1, node2, node3, }, parent.Children);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void InsertBefore_SingleNode_AddsNodeBeforeNode_AtBeginning()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var parent = new BasicIRNode("Parent");
|
||||||
|
|
||||||
|
var node1 = new BasicIRNode("Node1");
|
||||||
|
var node2 = new BasicIRNode("Node2");
|
||||||
|
var node3 = new BasicIRNode("Node3");
|
||||||
|
|
||||||
|
parent.Children.Add(node2);
|
||||||
|
parent.Children.Add(node3);
|
||||||
|
|
||||||
|
var reference = new RazorIRNodeReference(parent, node2);
|
||||||
|
|
||||||
|
// Act
|
||||||
|
reference.InsertBefore(node1);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.Equal(new[] { node1, node2, node3, }, parent.Children);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void InsertBefore_MultipleNodes_AddsNodesBeforeNode()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var parent = new BasicIRNode("Parent");
|
||||||
|
|
||||||
|
var node1 = new BasicIRNode("Node1");
|
||||||
|
var node2 = new BasicIRNode("Node2");
|
||||||
|
var node3 = new BasicIRNode("Node3");
|
||||||
|
var node4 = new BasicIRNode("Node4");
|
||||||
|
|
||||||
|
parent.Children.Add(node1);
|
||||||
|
parent.Children.Add(node4);
|
||||||
|
|
||||||
|
var reference = new RazorIRNodeReference(parent, node4);
|
||||||
|
|
||||||
|
// Act
|
||||||
|
reference.InsertBefore(new[] { node2, node3 });
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.Equal(new[] { node1, node2, node3, node4, }, parent.Children);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void InsertAfter_MultipleNodes_AddsNodesBeforeNode_AtBeginning()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var parent = new BasicIRNode("Parent");
|
||||||
|
|
||||||
|
var node1 = new BasicIRNode("Node1");
|
||||||
|
var node2 = new BasicIRNode("Node2");
|
||||||
|
var node3 = new BasicIRNode("Node3");
|
||||||
|
var node4 = new BasicIRNode("Node4");
|
||||||
|
|
||||||
|
parent.Children.Add(node3);
|
||||||
|
parent.Children.Add(node4);
|
||||||
|
|
||||||
|
var reference = new RazorIRNodeReference(parent, node3);
|
||||||
|
|
||||||
|
// Act
|
||||||
|
reference.InsertBefore(new[] { node1, node2 });
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.Equal(new[] { node1, node2, node3, node4, }, parent.Children);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void Remove_RemovesNode()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var parent = new BasicIRNode("Parent");
|
||||||
|
|
||||||
|
var node1 = new BasicIRNode("Node1");
|
||||||
|
var node2 = new BasicIRNode("Node2");
|
||||||
|
var node3 = new BasicIRNode("Node3");
|
||||||
|
|
||||||
|
parent.Children.Add(node1);
|
||||||
|
parent.Children.Add(node3);
|
||||||
|
parent.Children.Add(node2);
|
||||||
|
|
||||||
|
var reference = new RazorIRNodeReference(parent, node3);
|
||||||
|
|
||||||
|
// Act
|
||||||
|
reference.Remove();
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.Equal(new[] { node1, node2,}, parent.Children);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void Replace_ReplacesNode()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var parent = new BasicIRNode("Parent");
|
||||||
|
|
||||||
|
var node1 = new BasicIRNode("Node1");
|
||||||
|
var node2 = new BasicIRNode("Node2");
|
||||||
|
var node3 = new BasicIRNode("Node3");
|
||||||
|
var node4 = new BasicIRNode("Node4");
|
||||||
|
|
||||||
|
parent.Children.Add(node1);
|
||||||
|
parent.Children.Add(node4);
|
||||||
|
parent.Children.Add(node3);
|
||||||
|
|
||||||
|
var reference = new RazorIRNodeReference(parent, node4);
|
||||||
|
|
||||||
|
// Act
|
||||||
|
reference.Replace(node2);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.Equal(new[] { node1, node2, node3, }, parent.Children);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void InsertAfter_SingleNode_ThrowsForReferenceNotInitialized()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var reference = new RazorIRNodeReference();
|
||||||
|
|
||||||
|
// Act & Assert
|
||||||
|
var exception = Assert.Throws<InvalidOperationException>(() => reference.InsertAfter(new BasicIRNode("_")));
|
||||||
|
Assert.Equal("The reference is invalid. References initialized with the default constructor cannot modify nodes.", exception.Message);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void InsertAfter_MulipleNodes_ThrowsForReferenceNotInitialized()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var reference = new RazorIRNodeReference();
|
||||||
|
|
||||||
|
// Act & Assert
|
||||||
|
var exception = Assert.Throws<InvalidOperationException>(() => reference.InsertAfter(new[] { new BasicIRNode("_") }));
|
||||||
|
Assert.Equal("The reference is invalid. References initialized with the default constructor cannot modify nodes.", exception.Message);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void InsertBefore_SingleNode_ThrowsForReferenceNotInitialized()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var reference = new RazorIRNodeReference();
|
||||||
|
|
||||||
|
// Act & Assert
|
||||||
|
var exception = Assert.Throws<InvalidOperationException>(() => reference.InsertBefore(new BasicIRNode("_")));
|
||||||
|
Assert.Equal("The reference is invalid. References initialized with the default constructor cannot modify nodes.", exception.Message);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void InsertBefore_MulipleNodes_ThrowsForReferenceNotInitialized()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var reference = new RazorIRNodeReference();
|
||||||
|
|
||||||
|
// Act & Assert
|
||||||
|
var exception = Assert.Throws<InvalidOperationException>(() => reference.InsertBefore(new[] { new BasicIRNode("_") }));
|
||||||
|
Assert.Equal("The reference is invalid. References initialized with the default constructor cannot modify nodes.", exception.Message);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void Remove_ThrowsForReferenceNotInitialized()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var reference = new RazorIRNodeReference();
|
||||||
|
|
||||||
|
// Act & Assert
|
||||||
|
var exception = Assert.Throws<InvalidOperationException>(() => reference.Remove());
|
||||||
|
Assert.Equal("The reference is invalid. References initialized with the default constructor cannot modify nodes.", exception.Message);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void Replace_ThrowsForReferenceNotInitialized()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var reference = new RazorIRNodeReference();
|
||||||
|
|
||||||
|
// Act & Assert
|
||||||
|
var exception = Assert.Throws<InvalidOperationException>(() => reference.Replace(new BasicIRNode("_")));
|
||||||
|
Assert.Equal("The reference is invalid. References initialized with the default constructor cannot modify nodes.", exception.Message);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void InsertAfter_SingleNode_ThrowsForReadOnlyCollection()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var parent = new BasicIRNode("Parent", ReadOnlyIRNodeCollection.Instance);
|
||||||
|
|
||||||
|
var node1 = new BasicIRNode("Node1");
|
||||||
|
|
||||||
|
var reference = new RazorIRNodeReference(parent, node1);
|
||||||
|
|
||||||
|
// Act & Assert
|
||||||
|
var exception = Assert.Throws<InvalidOperationException>(() => reference.InsertAfter(new BasicIRNode("_")));
|
||||||
|
Assert.Equal("The node 'Parent' has a read-only child collection and cannot be modified.", exception.Message);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void InsertAfter_MulipleNodes_ThrowsForReadOnlyCollection()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var parent = new BasicIRNode("Parent", ReadOnlyIRNodeCollection.Instance);
|
||||||
|
|
||||||
|
var node1 = new BasicIRNode("Node1");
|
||||||
|
|
||||||
|
var reference = new RazorIRNodeReference(parent, node1);
|
||||||
|
|
||||||
|
// Act & Assert
|
||||||
|
var exception = Assert.Throws<InvalidOperationException>(() => reference.InsertAfter(new[] { new BasicIRNode("_") }));
|
||||||
|
Assert.Equal("The node 'Parent' has a read-only child collection and cannot be modified.", exception.Message);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void InsertBefore_SingleNode_ThrowsForReadOnlyCollection()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var parent = new BasicIRNode("Parent", ReadOnlyIRNodeCollection.Instance);
|
||||||
|
|
||||||
|
var node1 = new BasicIRNode("Node1");
|
||||||
|
|
||||||
|
var reference = new RazorIRNodeReference(parent, node1);
|
||||||
|
|
||||||
|
// Act & Assert
|
||||||
|
var exception = Assert.Throws<InvalidOperationException>(() => reference.InsertBefore(new BasicIRNode("_")));
|
||||||
|
Assert.Equal("The node 'Parent' has a read-only child collection and cannot be modified.", exception.Message);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void InsertBefore_MulipleNodes_ThrowsForReadOnlyCollection()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var parent = new BasicIRNode("Parent", ReadOnlyIRNodeCollection.Instance);
|
||||||
|
|
||||||
|
var node1 = new BasicIRNode("Node1");
|
||||||
|
|
||||||
|
var reference = new RazorIRNodeReference(parent, node1);
|
||||||
|
|
||||||
|
// Act & Assert
|
||||||
|
var exception = Assert.Throws<InvalidOperationException>(() => reference.InsertBefore(new[] { new BasicIRNode("_") }));
|
||||||
|
Assert.Equal("The node 'Parent' has a read-only child collection and cannot be modified.", exception.Message);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void Remove_ThrowsForReadOnlyCollection()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var parent = new BasicIRNode("Parent", ReadOnlyIRNodeCollection.Instance);
|
||||||
|
|
||||||
|
var node1 = new BasicIRNode("Node1");
|
||||||
|
|
||||||
|
var reference = new RazorIRNodeReference(parent, node1);
|
||||||
|
|
||||||
|
// Act & Assert
|
||||||
|
var exception = Assert.Throws<InvalidOperationException>(() => reference.Remove());
|
||||||
|
Assert.Equal("The node 'Parent' has a read-only child collection and cannot be modified.", exception.Message);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void Replace_ThrowsForReadOnlyCollection()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var parent = new BasicIRNode("Parent", ReadOnlyIRNodeCollection.Instance);
|
||||||
|
|
||||||
|
var node1 = new BasicIRNode("Node1");
|
||||||
|
|
||||||
|
var reference = new RazorIRNodeReference(parent, node1);
|
||||||
|
|
||||||
|
// Act & Assert
|
||||||
|
var exception = Assert.Throws<InvalidOperationException>(() => reference.Replace(new BasicIRNode("_")));
|
||||||
|
Assert.Equal("The node 'Parent' has a read-only child collection and cannot be modified.", exception.Message);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void InsertAfter_SingleNode_ThrowsForNodeNotFound()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var parent = new BasicIRNode("Parent");
|
||||||
|
|
||||||
|
var node1 = new BasicIRNode("Node1");
|
||||||
|
|
||||||
|
var reference = new RazorIRNodeReference(parent, node1);
|
||||||
|
|
||||||
|
// Act & Assert
|
||||||
|
var exception = Assert.Throws<InvalidOperationException>(() => reference.InsertAfter(new BasicIRNode("_")));
|
||||||
|
Assert.Equal("The reference is invalid. The node 'Node1' could not be found as a child of 'Parent'.", exception.Message);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void InsertAfter_MulipleNodes_ThrowsForNodeNotFound()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var parent = new BasicIRNode("Parent");
|
||||||
|
|
||||||
|
var node1 = new BasicIRNode("Node1");
|
||||||
|
|
||||||
|
var reference = new RazorIRNodeReference(parent, node1);
|
||||||
|
|
||||||
|
// Act & Assert
|
||||||
|
var exception = Assert.Throws<InvalidOperationException>(() => reference.InsertAfter(new[] { new BasicIRNode("_") }));
|
||||||
|
Assert.Equal("The reference is invalid. The node 'Node1' could not be found as a child of 'Parent'.", exception.Message);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void InsertBefore_SingleNode_ThrowsForNodeNotFound()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var parent = new BasicIRNode("Parent");
|
||||||
|
|
||||||
|
var node1 = new BasicIRNode("Node1");
|
||||||
|
|
||||||
|
var reference = new RazorIRNodeReference(parent, node1);
|
||||||
|
|
||||||
|
// Act & Assert
|
||||||
|
var exception = Assert.Throws<InvalidOperationException>(() => reference.InsertBefore(new BasicIRNode("_")));
|
||||||
|
Assert.Equal("The reference is invalid. The node 'Node1' could not be found as a child of 'Parent'.", exception.Message);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void InsertBefore_MulipleNodes_ThrowsForNodeNotFound()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var parent = new BasicIRNode("Parent");
|
||||||
|
|
||||||
|
var node1 = new BasicIRNode("Node1");
|
||||||
|
|
||||||
|
var reference = new RazorIRNodeReference(parent, node1);
|
||||||
|
|
||||||
|
// Act & Assert
|
||||||
|
var exception = Assert.Throws<InvalidOperationException>(() => reference.InsertBefore(new[] { new BasicIRNode("_") }));
|
||||||
|
Assert.Equal("The reference is invalid. The node 'Node1' could not be found as a child of 'Parent'.", exception.Message);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void Remove_ThrowsForNodeNotFound()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var parent = new BasicIRNode("Parent");
|
||||||
|
|
||||||
|
var node1 = new BasicIRNode("Node1");
|
||||||
|
|
||||||
|
var reference = new RazorIRNodeReference(parent, node1);
|
||||||
|
|
||||||
|
// Act & Assert
|
||||||
|
var exception = Assert.Throws<InvalidOperationException>(() => reference.Remove());
|
||||||
|
Assert.Equal("The reference is invalid. The node 'Node1' could not be found as a child of 'Parent'.", exception.Message);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void Replace_ThrowsForNodeNotFound()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var parent = new BasicIRNode("Parent");
|
||||||
|
|
||||||
|
var node1 = new BasicIRNode("Node1");
|
||||||
|
|
||||||
|
var reference = new RazorIRNodeReference(parent, node1);
|
||||||
|
|
||||||
|
// Act & Assert
|
||||||
|
var exception = Assert.Throws<InvalidOperationException>(() => reference.Replace(new BasicIRNode("_")));
|
||||||
|
Assert.Equal("The reference is invalid. The node 'Node1' could not be found as a child of 'Parent'.", exception.Message);
|
||||||
|
}
|
||||||
|
|
||||||
|
private class BasicIRNode : RazorIRNode
|
||||||
|
{
|
||||||
|
public BasicIRNode(string name)
|
||||||
|
: this(name, new DefaultIRNodeCollection())
|
||||||
|
{
|
||||||
|
Name = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public BasicIRNode(string name, RazorIRNodeCollection children)
|
||||||
|
{
|
||||||
|
Name = name;
|
||||||
|
Children = children;
|
||||||
|
}
|
||||||
|
|
||||||
|
public string Name { get; }
|
||||||
|
|
||||||
|
public override ItemCollection Annotations { get; } = new DefaultItemCollection();
|
||||||
|
|
||||||
|
public override RazorIRNodeCollection Children { get; }
|
||||||
|
|
||||||
|
public override SourceSpan? Source { get; set; }
|
||||||
|
|
||||||
|
public override void Accept(RazorIRNodeVisitor visitor)
|
||||||
|
{
|
||||||
|
throw new System.NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public override string ToString() => Name;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -3,6 +3,7 @@
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
using Xunit;
|
using Xunit;
|
||||||
|
|
||||||
namespace Microsoft.AspNetCore.Razor.Language.Intermediate
|
namespace Microsoft.AspNetCore.Razor.Language.Intermediate
|
||||||
|
|
@ -43,14 +44,68 @@ namespace Microsoft.AspNetCore.Razor.Language.Intermediate
|
||||||
Assert.Equal(nodes, walker.Visited.ToArray());
|
Assert.Equal(nodes, walker.Visited.ToArray());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void IRNodeWalker_Visit_SetsParentAndAncestors()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var walker = new DerivedIRNodeWalker();
|
||||||
|
|
||||||
|
var nodes = new RazorIRNode[]
|
||||||
|
{
|
||||||
|
new BasicIRNode("Root"),
|
||||||
|
new BasicIRNode("Root->A"),
|
||||||
|
new BasicIRNode("Root->B"),
|
||||||
|
new BasicIRNode("Root->B->1"),
|
||||||
|
new BasicIRNode("Root->B->2"),
|
||||||
|
new BasicIRNode("Root->C"),
|
||||||
|
};
|
||||||
|
|
||||||
|
var ancestors = new Dictionary<string, string[]>()
|
||||||
|
{
|
||||||
|
{ "Root", new string[]{ } },
|
||||||
|
{ "Root->A", new string[] { "Root" } },
|
||||||
|
{ "Root->B", new string[] { "Root" } },
|
||||||
|
{ "Root->B->1", new string[] { "Root->B", "Root" } },
|
||||||
|
{ "Root->B->2", new string[] { "Root->B", "Root" } },
|
||||||
|
{ "Root->C", new string[] { "Root" } },
|
||||||
|
};
|
||||||
|
|
||||||
|
walker.OnVisiting = (n) =>
|
||||||
|
{
|
||||||
|
Assert.Equal(ancestors[((BasicIRNode)n).Name], walker.Ancestors.Cast<BasicIRNode>().Select(b => b.Name));
|
||||||
|
Assert.Equal(ancestors[((BasicIRNode)n).Name].FirstOrDefault(), ((BasicIRNode)walker.Parent)?.Name);
|
||||||
|
};
|
||||||
|
|
||||||
|
var builder = new DefaultRazorIRBuilder();
|
||||||
|
builder.Push(nodes[0]);
|
||||||
|
builder.Add(nodes[1]);
|
||||||
|
builder.Push(nodes[2]);
|
||||||
|
builder.Add(nodes[3]);
|
||||||
|
builder.Add(nodes[4]);
|
||||||
|
builder.Pop();
|
||||||
|
builder.Add(nodes[5]);
|
||||||
|
|
||||||
|
var root = builder.Pop();
|
||||||
|
|
||||||
|
// Act & Assert
|
||||||
|
walker.Visit(root);
|
||||||
|
}
|
||||||
|
|
||||||
private class DerivedIRNodeWalker : RazorIRNodeWalker
|
private class DerivedIRNodeWalker : RazorIRNodeWalker
|
||||||
{
|
{
|
||||||
|
public new IEnumerable<RazorIRNode> Ancestors => base.Ancestors;
|
||||||
|
|
||||||
|
public new RazorIRNode Parent => base.Parent;
|
||||||
|
|
||||||
public List<RazorIRNode> Visited { get; } = new List<RazorIRNode>();
|
public List<RazorIRNode> Visited { get; } = new List<RazorIRNode>();
|
||||||
|
|
||||||
|
public Action<RazorIRNode> OnVisiting { get; set; }
|
||||||
|
|
||||||
public override void VisitDefault(RazorIRNode node)
|
public override void VisitDefault(RazorIRNode node)
|
||||||
{
|
{
|
||||||
Visited.Add(node);
|
Visited.Add(node);
|
||||||
|
|
||||||
|
OnVisiting?.Invoke(node);
|
||||||
base.VisitDefault(node);
|
base.VisitDefault(node);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -60,7 +115,6 @@ namespace Microsoft.AspNetCore.Razor.Language.Intermediate
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private class BasicIRNode : RazorIRNode
|
private class BasicIRNode : RazorIRNode
|
||||||
{
|
{
|
||||||
public BasicIRNode(string name)
|
public BasicIRNode(string name)
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue