diff --git a/src/Microsoft.AspNetCore.Mvc.Razor.Extensions.Version1_X/IViewComponentTagHelperTargetExtension.cs b/src/Microsoft.AspNetCore.Mvc.Razor.Extensions.Version1_X/IViewComponentTagHelperTargetExtension.cs new file mode 100644 index 0000000000..45a0d581a5 --- /dev/null +++ b/src/Microsoft.AspNetCore.Mvc.Razor.Extensions.Version1_X/IViewComponentTagHelperTargetExtension.cs @@ -0,0 +1,12 @@ +// 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.Language.CodeGeneration; + +namespace Microsoft.AspNetCore.Mvc.Razor.Extensions.Version1_X +{ + public interface IViewComponentTagHelperTargetExtension : ICodeTargetExtension + { + void WriteViewComponentTagHelper(CodeRenderingContext context, ViewComponentTagHelperIntermediateNode node); + } +} diff --git a/src/Microsoft.AspNetCore.Mvc.Razor.Extensions.Version1_X/RazorExtensions.cs b/src/Microsoft.AspNetCore.Mvc.Razor.Extensions.Version1_X/RazorExtensions.cs index 10db898bac..341bb5d47a 100644 --- a/src/Microsoft.AspNetCore.Mvc.Razor.Extensions.Version1_X/RazorExtensions.cs +++ b/src/Microsoft.AspNetCore.Mvc.Razor.Extensions.Version1_X/RazorExtensions.cs @@ -38,6 +38,7 @@ namespace Microsoft.AspNetCore.Mvc.Razor.Extensions.Version1_X EnsureDesignTime(builder); builder.Features.Add(new ViewComponentTagHelperPass()); + builder.AddTargetExtension(new ViewComponentTagHelperTargetExtension()); } private static void EnsureDesignTime(IRazorEngineBuilder builder) diff --git a/src/Microsoft.AspNetCore.Mvc.Razor.Extensions.Version1_X/ViewComponentTagHelperIntermediateNode.cs b/src/Microsoft.AspNetCore.Mvc.Razor.Extensions.Version1_X/ViewComponentTagHelperIntermediateNode.cs new file mode 100644 index 0000000000..bfe937aaa8 --- /dev/null +++ b/src/Microsoft.AspNetCore.Mvc.Razor.Extensions.Version1_X/ViewComponentTagHelperIntermediateNode.cs @@ -0,0 +1,51 @@ +// 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 Microsoft.AspNetCore.Razor.Language; +using Microsoft.AspNetCore.Razor.Language.CodeGeneration; +using Microsoft.AspNetCore.Razor.Language.Intermediate; + +namespace Microsoft.AspNetCore.Mvc.Razor.Extensions.Version1_X +{ + public sealed class ViewComponentTagHelperIntermediateNode : ExtensionIntermediateNode + { + public override IntermediateNodeCollection Children { get; } = IntermediateNodeCollection.ReadOnly; + + public string ClassName { get; set; } + + public TagHelperDescriptor TagHelper { get; set; } + + public override void Accept(IntermediateNodeVisitor visitor) + { + if (visitor == null) + { + throw new ArgumentNullException(nameof(visitor)); + } + + AcceptExtensionNode(this, visitor); + } + + public override void WriteNode(CodeTarget target, CodeRenderingContext context) + { + if (target == null) + { + throw new ArgumentNullException(nameof(target)); + } + + if (context == null) + { + throw new ArgumentNullException(nameof(context)); + } + + var extension = target.GetExtension(); + if (extension == null) + { + ReportMissingCodeTargetExtension(context); + return; + } + + extension.WriteViewComponentTagHelper(context, this); + } + } +} diff --git a/src/Microsoft.AspNetCore.Mvc.Razor.Extensions.Version1_X/ViewComponentTagHelperPass.cs b/src/Microsoft.AspNetCore.Mvc.Razor.Extensions.Version1_X/ViewComponentTagHelperPass.cs index 8fdfb8a6a1..ba9938a123 100644 --- a/src/Microsoft.AspNetCore.Mvc.Razor.Extensions.Version1_X/ViewComponentTagHelperPass.cs +++ b/src/Microsoft.AspNetCore.Mvc.Razor.Extensions.Version1_X/ViewComponentTagHelperPass.cs @@ -1,13 +1,8 @@ // 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 System.Diagnostics; -using System.Linq; -using System.Threading.Tasks; using Microsoft.AspNetCore.Razor.Language; -using Microsoft.AspNetCore.Razor.Language.CodeGeneration; using Microsoft.AspNetCore.Razor.Language.Extensions; using Microsoft.AspNetCore.Razor.Language.Intermediate; @@ -18,8 +13,6 @@ namespace Microsoft.AspNetCore.Mvc.Razor.Extensions.Version1_X // Run after the default taghelper pass public override int Order => IntermediateNodePassBase.DefaultFeatureOrder + 2000; - private static readonly string[] PublicModifiers = new[] { "public" }; - protected override void ExecuteCore(RazorCodeDocument codeDocument, DocumentIntermediateNode documentNode) { var @namespace = documentNode.FindPrimaryNamespace(); @@ -142,145 +135,13 @@ namespace Microsoft.AspNetCore.Mvc.Razor.Extensions.Version1_X private void AddTagHelperClass(Context context, TagHelperDescriptor tagHelper) { - var writer = new CodeWriter(); - WriteClass(context, writer, tagHelper); - - var code = new CSharpCodeIntermediateNode(); - code.Children.Add(new IntermediateToken() + var node = new ViewComponentTagHelperIntermediateNode() { - Kind = TokenKind.CSharp, - Content = writer.GenerateCode() - }); + ClassName = context.GetClassName(tagHelper), + TagHelper = tagHelper + }; - context.Class.Children.Add(code); - } - - private void WriteClass(Context context, CodeWriter writer, TagHelperDescriptor tagHelper) - { - // Add target element. - BuildTargetElementString(writer, tagHelper); - - // Initialize declaration. - var tagHelperTypeName = "Microsoft.AspNetCore.Razor.TagHelpers.TagHelper"; - var className = context.GetClassName(tagHelper); - - using (writer.BuildClassDeclaration(PublicModifiers, className, tagHelperTypeName, interfaces: null)) - { - // Add view component helper. - writer.WriteVariableDeclaration( - $"private readonly global::Microsoft.AspNetCore.Mvc.IViewComponentHelper", - "_helper", - value: null); - - // Add constructor. - BuildConstructorString(writer, className); - - // Add attributes. - BuildAttributeDeclarations(writer, tagHelper); - - // Add process method. - BuildProcessMethodString(writer, tagHelper); - } - } - - private void BuildConstructorString(CodeWriter writer, string className) - { - writer.Write("public ") - .Write(className) - .Write("(") - .Write("global::Microsoft.AspNetCore.Mvc.IViewComponentHelper helper") - .WriteLine(")"); - using (writer.BuildScope()) - { - writer.WriteStartAssignment("_helper") - .Write("helper") - .WriteLine(";"); - } - } - - private void BuildAttributeDeclarations(CodeWriter writer, TagHelperDescriptor tagHelper) - { - writer.Write("[") - .Write("Microsoft.AspNetCore.Razor.TagHelpers.HtmlAttributeNotBoundAttribute") - .WriteParameterSeparator() - .Write($"global::Microsoft.AspNetCore.Mvc.ViewFeatures.ViewContextAttribute") - .WriteLine("]"); - - writer.WriteAutoPropertyDeclaration( - PublicModifiers, - $"global::Microsoft.AspNetCore.Mvc.Rendering.ViewContext", - "ViewContext"); - - foreach (var attribute in tagHelper.BoundAttributes) - { - writer.WriteAutoPropertyDeclaration( - PublicModifiers, - attribute.TypeName, - attribute.GetPropertyName()); - - if (attribute.IndexerTypeName != null) - { - writer.Write(" = ") - .WriteStartNewObject(attribute.TypeName) - .WriteEndMethodInvocation(); - } - } - } - - private void BuildProcessMethodString(CodeWriter writer, TagHelperDescriptor tagHelper) - { - var contextVariable = "context"; - var outputVariable = "output"; - - using (writer.BuildMethodDeclaration( - $"public override async", - $"global::{typeof(Task).FullName}", - "ProcessAsync", - new Dictionary() - { - { "Microsoft.AspNetCore.Razor.TagHelpers.TagHelperContext", contextVariable }, - { "Microsoft.AspNetCore.Razor.TagHelpers.TagHelperOutput", outputVariable } - })) - { - writer.WriteInstanceMethodInvocation( - $"(_helper as global::Microsoft.AspNetCore.Mvc.ViewFeatures.IViewContextAware)?", - "Contextualize", - new[] { "ViewContext" }); - - var methodParameters = GetMethodParameters(tagHelper); - var contentVariable = "content"; - writer.Write("var ") - .WriteStartAssignment(contentVariable) - .WriteInstanceMethodInvocation($"await _helper", "InvokeAsync", methodParameters); - writer.WriteStartAssignment($"{outputVariable}.TagName") - .WriteLine("null;"); - writer.WriteInstanceMethodInvocation( - $"{outputVariable}.Content", - "SetHtmlContent", - new[] { contentVariable }); - } - } - - private string[] GetMethodParameters(TagHelperDescriptor tagHelper) - { - var propertyNames = tagHelper.BoundAttributes.Select(attribute => attribute.GetPropertyName()); - var joinedPropertyNames = string.Join(", ", propertyNames); - var parametersString = $"new {{ { joinedPropertyNames } }}"; - var viewComponentName = tagHelper.GetViewComponentName(); - var methodParameters = new[] { $"\"{viewComponentName}\"", parametersString }; - return methodParameters; - } - - private void BuildTargetElementString(CodeWriter writer, TagHelperDescriptor tagHelper) - { - Debug.Assert(tagHelper.TagMatchingRules.Count() == 1); - - var rule = tagHelper.TagMatchingRules.First(); - - writer.Write("[") - .WriteStartMethodInvocation("Microsoft.AspNetCore.Razor.TagHelpers.HtmlTargetElementAttribute") - .WriteStringLiteral(rule.TagName) - .WriteLine(")]"); + context.Class.Children.Add(node); } private struct Context diff --git a/src/Microsoft.AspNetCore.Mvc.Razor.Extensions.Version1_X/ViewComponentTagHelperTargetExtension.cs b/src/Microsoft.AspNetCore.Mvc.Razor.Extensions.Version1_X/ViewComponentTagHelperTargetExtension.cs new file mode 100644 index 0000000000..e810b2a087 --- /dev/null +++ b/src/Microsoft.AspNetCore.Mvc.Razor.Extensions.Version1_X/ViewComponentTagHelperTargetExtension.cs @@ -0,0 +1,178 @@ +// 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.Diagnostics; +using System.Linq; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Razor.Language; +using Microsoft.AspNetCore.Razor.Language.CodeGeneration; + +namespace Microsoft.AspNetCore.Mvc.Razor.Extensions.Version1_X +{ + internal class ViewComponentTagHelperTargetExtension : IViewComponentTagHelperTargetExtension + { + private static readonly string[] PublicModifiers = new[] { "public" }; + + public string TagHelperTypeName { get; set; } = "Microsoft.AspNetCore.Razor.TagHelpers.TagHelper"; + + public string ViewComponentHelperTypeName { get; set; } = "global::Microsoft.AspNetCore.Mvc.IViewComponentHelper"; + + public string ViewComponentHelperVariableName { get; set; } = "_helper"; + + public string ViewComponentInvokeMethodName { get; set; } = "InvokeAsync"; + + public string HtmlAttributeNotBoundAttributeTypeName { get; set; } = "Microsoft.AspNetCore.Razor.TagHelpers.HtmlAttributeNotBoundAttribute"; + + public string ViewContextAttributeTypeName { get; set; } = "global::Microsoft.AspNetCore.Mvc.ViewFeatures.ViewContextAttribute"; + + public string ViewContextTypeName { get; set; } = "global::Microsoft.AspNetCore.Mvc.Rendering.ViewContext"; + + public string ViewContextPropertyName { get; set; } = "ViewContext"; + + public string HtmlTargetElementAttributeTypeName { get; set; } = "Microsoft.AspNetCore.Razor.TagHelpers.HtmlTargetElementAttribute"; + + public string TagHelperProcessMethodName { get; set; } = "ProcessAsync"; + + public string TagHelperContextTypeName { get; set; } = "Microsoft.AspNetCore.Razor.TagHelpers.TagHelperContext"; + + public string TagHelperContextVariableName { get; set; } = "context"; + + public string TagHelperOutputTypeName { get; set; } = "Microsoft.AspNetCore.Razor.TagHelpers.TagHelperOutput"; + + public string TagHelperOutputVariableName { get; set; } = "output"; + + public string TagHelperOutputTagNamePropertyName { get; set; } = "TagName"; + + public string TagHelperOutputContentPropertyName { get; set; } = "Content"; + + public string TagHelperContentSetMethodName { get; set; } = "SetHtmlContent"; + + public string TagHelperContentVariableName { get; set; } = "content"; + + public string IViewContextAwareTypeName { get; set; } = "global::Microsoft.AspNetCore.Mvc.ViewFeatures.IViewContextAware"; + + public string IViewContextAwareContextualizeMethodName { get; set; } = "Contextualize"; + + public void WriteViewComponentTagHelper(CodeRenderingContext context, ViewComponentTagHelperIntermediateNode node) + { + // Add target element. + WriteTargetElementString(context.CodeWriter, node.TagHelper); + + // Initialize declaration. + using (context.CodeWriter.BuildClassDeclaration(PublicModifiers, node.ClassName, TagHelperTypeName, interfaces: null)) + { + // Add view component helper. + context.CodeWriter.WriteVariableDeclaration( + $"private readonly {ViewComponentHelperTypeName}", + ViewComponentHelperVariableName, + value: null); + + // Add constructor. + WriteConstructorString(context.CodeWriter, node.ClassName); + + // Add attributes. + WriteAttributeDeclarations(context.CodeWriter, node.TagHelper); + + // Add process method. + WriteProcessMethodString(context.CodeWriter, node.TagHelper); + } + } + + private void WriteConstructorString(CodeWriter writer, string className) + { + writer.Write("public ") + .Write(className) + .Write("(") + .Write($"{ViewComponentHelperTypeName} helper") + .WriteLine(")"); + using (writer.BuildScope()) + { + writer.WriteStartAssignment(ViewComponentHelperVariableName) + .Write("helper") + .WriteLine(";"); + } + } + + private void WriteAttributeDeclarations(CodeWriter writer, TagHelperDescriptor tagHelper) + { + writer.Write("[") + .Write(HtmlAttributeNotBoundAttributeTypeName) + .WriteParameterSeparator() + .Write(ViewContextAttributeTypeName) + .WriteLine("]"); + + writer.WriteAutoPropertyDeclaration( + PublicModifiers, + ViewContextTypeName, + ViewContextPropertyName); + + foreach (var attribute in tagHelper.BoundAttributes) + { + writer.WriteAutoPropertyDeclaration( + PublicModifiers, + attribute.TypeName, + attribute.GetPropertyName()); + + if (attribute.IndexerTypeName != null) + { + writer.Write(" = ") + .WriteStartNewObject(attribute.TypeName) + .WriteEndMethodInvocation(); + } + } + } + + private void WriteProcessMethodString(CodeWriter writer, TagHelperDescriptor tagHelper) + { + using (writer.BuildMethodDeclaration( + $"public override async", + $"global::{typeof(Task).FullName}", + TagHelperProcessMethodName, + new Dictionary() + { + { TagHelperContextTypeName, TagHelperContextVariableName }, + { TagHelperOutputTypeName, TagHelperOutputVariableName } + })) + { + writer.WriteInstanceMethodInvocation( + $"({ViewComponentHelperVariableName} as {IViewContextAwareTypeName})?", + IViewContextAwareContextualizeMethodName, + new[] { ViewContextPropertyName }); + + var methodParameters = GetMethodParameters(tagHelper); + writer.Write("var ") + .WriteStartAssignment(TagHelperContentVariableName) + .WriteInstanceMethodInvocation($"await {ViewComponentHelperVariableName}", ViewComponentInvokeMethodName, methodParameters); + writer.WriteStartAssignment($"{TagHelperOutputVariableName}.{TagHelperOutputTagNamePropertyName}") + .WriteLine("null;"); + writer.WriteInstanceMethodInvocation( + $"{TagHelperOutputVariableName}.{TagHelperOutputContentPropertyName}", + TagHelperContentSetMethodName, + new[] { TagHelperContentVariableName }); + } + } + + private string[] GetMethodParameters(TagHelperDescriptor tagHelper) + { + var propertyNames = tagHelper.BoundAttributes.Select(attribute => attribute.GetPropertyName()); + var joinedPropertyNames = string.Join(", ", propertyNames); + var parametersString = $"new {{ { joinedPropertyNames } }}"; + var viewComponentName = tagHelper.GetViewComponentName(); + var methodParameters = new[] { $"\"{viewComponentName}\"", parametersString }; + return methodParameters; + } + + private void WriteTargetElementString(CodeWriter writer, TagHelperDescriptor tagHelper) + { + Debug.Assert(tagHelper.TagMatchingRules.Count() == 1); + + var rule = tagHelper.TagMatchingRules.First(); + + writer.Write("[") + .WriteStartMethodInvocation(HtmlTargetElementAttributeTypeName) + .WriteStringLiteral(rule.TagName) + .WriteLine(")]"); + } + } +} diff --git a/src/Microsoft.AspNetCore.Mvc.Razor.Extensions/IViewComponentTagHelperTargetExtension.cs b/src/Microsoft.AspNetCore.Mvc.Razor.Extensions/IViewComponentTagHelperTargetExtension.cs new file mode 100644 index 0000000000..1f303e7422 --- /dev/null +++ b/src/Microsoft.AspNetCore.Mvc.Razor.Extensions/IViewComponentTagHelperTargetExtension.cs @@ -0,0 +1,12 @@ +// 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.Language.CodeGeneration; + +namespace Microsoft.AspNetCore.Mvc.Razor.Extensions +{ + public interface IViewComponentTagHelperTargetExtension : ICodeTargetExtension + { + void WriteViewComponentTagHelper(CodeRenderingContext context, ViewComponentTagHelperIntermediateNode node); + } +} diff --git a/src/Microsoft.AspNetCore.Mvc.Razor.Extensions/RazorExtensions.cs b/src/Microsoft.AspNetCore.Mvc.Razor.Extensions/RazorExtensions.cs index e0cc152b89..fc1ad0c162 100644 --- a/src/Microsoft.AspNetCore.Mvc.Razor.Extensions/RazorExtensions.cs +++ b/src/Microsoft.AspNetCore.Mvc.Razor.Extensions/RazorExtensions.cs @@ -19,6 +19,7 @@ namespace Microsoft.AspNetCore.Mvc.Razor.Extensions InheritsDirective.Register(builder); SectionDirective.Register(builder); + builder.AddTargetExtension(new ViewComponentTagHelperTargetExtension()); builder.AddTargetExtension(new TemplateTargetExtension() { TemplateTypeName = "global::Microsoft.AspNetCore.Mvc.Razor.HelperResult", diff --git a/src/Microsoft.AspNetCore.Mvc.Razor.Extensions/ViewComponentTagHelperIntermediateNode.cs b/src/Microsoft.AspNetCore.Mvc.Razor.Extensions/ViewComponentTagHelperIntermediateNode.cs new file mode 100644 index 0000000000..09b124970e --- /dev/null +++ b/src/Microsoft.AspNetCore.Mvc.Razor.Extensions/ViewComponentTagHelperIntermediateNode.cs @@ -0,0 +1,51 @@ +// 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 Microsoft.AspNetCore.Razor.Language; +using Microsoft.AspNetCore.Razor.Language.CodeGeneration; +using Microsoft.AspNetCore.Razor.Language.Intermediate; + +namespace Microsoft.AspNetCore.Mvc.Razor.Extensions +{ + public sealed class ViewComponentTagHelperIntermediateNode : ExtensionIntermediateNode + { + public override IntermediateNodeCollection Children { get; } = IntermediateNodeCollection.ReadOnly; + + public string ClassName { get; set; } + + public TagHelperDescriptor TagHelper { get; set; } + + public override void Accept(IntermediateNodeVisitor visitor) + { + if (visitor == null) + { + throw new ArgumentNullException(nameof(visitor)); + } + + AcceptExtensionNode(this, visitor); + } + + public override void WriteNode(CodeTarget target, CodeRenderingContext context) + { + if (target == null) + { + throw new ArgumentNullException(nameof(target)); + } + + if (context == null) + { + throw new ArgumentNullException(nameof(context)); + } + + var extension = target.GetExtension(); + if (extension == null) + { + ReportMissingCodeTargetExtension(context); + return; + } + + extension.WriteViewComponentTagHelper(context, this); + } + } +} diff --git a/src/Microsoft.AspNetCore.Mvc.Razor.Extensions/ViewComponentTagHelperPass.cs b/src/Microsoft.AspNetCore.Mvc.Razor.Extensions/ViewComponentTagHelperPass.cs index a7420abff0..0c3b14563e 100644 --- a/src/Microsoft.AspNetCore.Mvc.Razor.Extensions/ViewComponentTagHelperPass.cs +++ b/src/Microsoft.AspNetCore.Mvc.Razor.Extensions/ViewComponentTagHelperPass.cs @@ -1,13 +1,8 @@ // 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 System.Diagnostics; -using System.Linq; -using System.Threading.Tasks; using Microsoft.AspNetCore.Razor.Language; -using Microsoft.AspNetCore.Razor.Language.CodeGeneration; using Microsoft.AspNetCore.Razor.Language.Extensions; using Microsoft.AspNetCore.Razor.Language.Intermediate; @@ -18,8 +13,6 @@ namespace Microsoft.AspNetCore.Mvc.Razor.Extensions // Run after the default taghelper pass public override int Order => IntermediateNodePassBase.DefaultFeatureOrder + 2000; - private static readonly string[] PublicModifiers = new[] { "public" }; - protected override void ExecuteCore(RazorCodeDocument codeDocument, DocumentIntermediateNode documentNode) { var @namespace = documentNode.FindPrimaryNamespace(); @@ -142,145 +135,13 @@ namespace Microsoft.AspNetCore.Mvc.Razor.Extensions private void AddTagHelperClass(Context context, TagHelperDescriptor tagHelper) { - var writer = new CodeWriter(); - WriteClass(context, writer, tagHelper); - - var code = new CSharpCodeIntermediateNode(); - code.Children.Add(new IntermediateToken() + var node = new ViewComponentTagHelperIntermediateNode() { - Kind = TokenKind.CSharp, - Content = writer.GenerateCode() - }); + ClassName = context.GetClassName(tagHelper), + TagHelper = tagHelper + }; - context.Class.Children.Add(code); - } - - private void WriteClass(Context context, CodeWriter writer, TagHelperDescriptor tagHelper) - { - // Add target element. - BuildTargetElementString(writer, tagHelper); - - // Initialize declaration. - var tagHelperTypeName = "Microsoft.AspNetCore.Razor.TagHelpers.TagHelper"; - var className = context.GetClassName(tagHelper); - - using (writer.BuildClassDeclaration(PublicModifiers, className, tagHelperTypeName, interfaces: null)) - { - // Add view component helper. - writer.WriteVariableDeclaration( - $"private readonly global::Microsoft.AspNetCore.Mvc.IViewComponentHelper", - "_helper", - value: null); - - // Add constructor. - BuildConstructorString(writer, className); - - // Add attributes. - BuildAttributeDeclarations(writer, tagHelper); - - // Add process method. - BuildProcessMethodString(writer, tagHelper); - } - } - - private void BuildConstructorString(CodeWriter writer, string className) - { - writer.Write("public ") - .Write(className) - .Write("(") - .Write("global::Microsoft.AspNetCore.Mvc.IViewComponentHelper helper") - .WriteLine(")"); - using (writer.BuildScope()) - { - writer.WriteStartAssignment("_helper") - .Write("helper") - .WriteLine(";"); - } - } - - private void BuildAttributeDeclarations(CodeWriter writer, TagHelperDescriptor tagHelper) - { - writer.Write("[") - .Write("Microsoft.AspNetCore.Razor.TagHelpers.HtmlAttributeNotBoundAttribute") - .WriteParameterSeparator() - .Write($"global::Microsoft.AspNetCore.Mvc.ViewFeatures.ViewContextAttribute") - .WriteLine("]"); - - writer.WriteAutoPropertyDeclaration( - PublicModifiers, - $"global::Microsoft.AspNetCore.Mvc.Rendering.ViewContext", - "ViewContext"); - - foreach (var attribute in tagHelper.BoundAttributes) - { - writer.WriteAutoPropertyDeclaration( - PublicModifiers, - attribute.TypeName, - attribute.GetPropertyName()); - - if (attribute.IndexerTypeName != null) - { - writer.Write(" = ") - .WriteStartNewObject(attribute.TypeName) - .WriteEndMethodInvocation(); - } - } - } - - private void BuildProcessMethodString(CodeWriter writer, TagHelperDescriptor tagHelper) - { - var contextVariable = "context"; - var outputVariable = "output"; - - using (writer.BuildMethodDeclaration( - $"public override async", - $"global::{typeof(Task).FullName}", - "ProcessAsync", - new Dictionary() - { - { "Microsoft.AspNetCore.Razor.TagHelpers.TagHelperContext", contextVariable }, - { "Microsoft.AspNetCore.Razor.TagHelpers.TagHelperOutput", outputVariable } - })) - { - writer.WriteInstanceMethodInvocation( - $"(_helper as global::Microsoft.AspNetCore.Mvc.ViewFeatures.IViewContextAware)?", - "Contextualize", - new[] { "ViewContext" }); - - var methodParameters = GetMethodParameters(tagHelper); - var contentVariable = "content"; - writer.Write("var ") - .WriteStartAssignment(contentVariable) - .WriteInstanceMethodInvocation($"await _helper", "InvokeAsync", methodParameters); - writer.WriteStartAssignment($"{outputVariable}.TagName") - .WriteLine("null;"); - writer.WriteInstanceMethodInvocation( - $"{outputVariable}.Content", - "SetHtmlContent", - new[] { contentVariable }); - } - } - - private string[] GetMethodParameters(TagHelperDescriptor tagHelper) - { - var propertyNames = tagHelper.BoundAttributes.Select(attribute => attribute.GetPropertyName()); - var joinedPropertyNames = string.Join(", ", propertyNames); - var parametersString = $"new {{ { joinedPropertyNames } }}"; - var viewComponentName = tagHelper.GetViewComponentName(); - var methodParameters = new[] { $"\"{viewComponentName}\"", parametersString }; - return methodParameters; - } - - private void BuildTargetElementString(CodeWriter writer, TagHelperDescriptor tagHelper) - { - Debug.Assert(tagHelper.TagMatchingRules.Count() == 1); - - var rule = tagHelper.TagMatchingRules.First(); - - writer.Write("[") - .WriteStartMethodInvocation("Microsoft.AspNetCore.Razor.TagHelpers.HtmlTargetElementAttribute") - .WriteStringLiteral(rule.TagName) - .WriteLine(")]"); + context.Class.Children.Add(node); } private struct Context diff --git a/src/Microsoft.AspNetCore.Mvc.Razor.Extensions/ViewComponentTagHelperTargetExtension.cs b/src/Microsoft.AspNetCore.Mvc.Razor.Extensions/ViewComponentTagHelperTargetExtension.cs new file mode 100644 index 0000000000..298fe23e31 --- /dev/null +++ b/src/Microsoft.AspNetCore.Mvc.Razor.Extensions/ViewComponentTagHelperTargetExtension.cs @@ -0,0 +1,178 @@ +// 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.Diagnostics; +using System.Linq; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Razor.Language; +using Microsoft.AspNetCore.Razor.Language.CodeGeneration; + +namespace Microsoft.AspNetCore.Mvc.Razor.Extensions +{ + internal class ViewComponentTagHelperTargetExtension : IViewComponentTagHelperTargetExtension + { + private static readonly string[] PublicModifiers = new[] { "public" }; + + public string TagHelperTypeName { get; set; } = "Microsoft.AspNetCore.Razor.TagHelpers.TagHelper"; + + public string ViewComponentHelperTypeName { get; set; } = "global::Microsoft.AspNetCore.Mvc.IViewComponentHelper"; + + public string ViewComponentHelperVariableName { get; set; } = "_helper"; + + public string ViewComponentInvokeMethodName { get; set; } = "InvokeAsync"; + + public string HtmlAttributeNotBoundAttributeTypeName { get; set; } = "Microsoft.AspNetCore.Razor.TagHelpers.HtmlAttributeNotBoundAttribute"; + + public string ViewContextAttributeTypeName { get; set; } = "global::Microsoft.AspNetCore.Mvc.ViewFeatures.ViewContextAttribute"; + + public string ViewContextTypeName { get; set; } = "global::Microsoft.AspNetCore.Mvc.Rendering.ViewContext"; + + public string ViewContextPropertyName { get; set; } = "ViewContext"; + + public string HtmlTargetElementAttributeTypeName { get; set; } = "Microsoft.AspNetCore.Razor.TagHelpers.HtmlTargetElementAttribute"; + + public string TagHelperProcessMethodName { get; set; } = "ProcessAsync"; + + public string TagHelperContextTypeName { get; set; } = "Microsoft.AspNetCore.Razor.TagHelpers.TagHelperContext"; + + public string TagHelperContextVariableName { get; set; } = "context"; + + public string TagHelperOutputTypeName { get; set; } = "Microsoft.AspNetCore.Razor.TagHelpers.TagHelperOutput"; + + public string TagHelperOutputVariableName { get; set; } = "output"; + + public string TagHelperOutputTagNamePropertyName { get; set; } = "TagName"; + + public string TagHelperOutputContentPropertyName { get; set; } = "Content"; + + public string TagHelperContentSetMethodName { get; set; } = "SetHtmlContent"; + + public string TagHelperContentVariableName { get; set; } = "content"; + + public string IViewContextAwareTypeName { get; set; } = "global::Microsoft.AspNetCore.Mvc.ViewFeatures.IViewContextAware"; + + public string IViewContextAwareContextualizeMethodName { get; set; } = "Contextualize"; + + public void WriteViewComponentTagHelper(CodeRenderingContext context, ViewComponentTagHelperIntermediateNode node) + { + // Add target element. + WriteTargetElementString(context.CodeWriter, node.TagHelper); + + // Initialize declaration. + using (context.CodeWriter.BuildClassDeclaration(PublicModifiers, node.ClassName, TagHelperTypeName, interfaces: null)) + { + // Add view component helper. + context.CodeWriter.WriteVariableDeclaration( + $"private readonly {ViewComponentHelperTypeName}", + ViewComponentHelperVariableName, + value: null); + + // Add constructor. + WriteConstructorString(context.CodeWriter, node.ClassName); + + // Add attributes. + WriteAttributeDeclarations(context.CodeWriter, node.TagHelper); + + // Add process method. + WriteProcessMethodString(context.CodeWriter, node.TagHelper); + } + } + + private void WriteConstructorString(CodeWriter writer, string className) + { + writer.Write("public ") + .Write(className) + .Write("(") + .Write($"{ViewComponentHelperTypeName} helper") + .WriteLine(")"); + using (writer.BuildScope()) + { + writer.WriteStartAssignment(ViewComponentHelperVariableName) + .Write("helper") + .WriteLine(";"); + } + } + + private void WriteAttributeDeclarations(CodeWriter writer, TagHelperDescriptor tagHelper) + { + writer.Write("[") + .Write(HtmlAttributeNotBoundAttributeTypeName) + .WriteParameterSeparator() + .Write(ViewContextAttributeTypeName) + .WriteLine("]"); + + writer.WriteAutoPropertyDeclaration( + PublicModifiers, + ViewContextTypeName, + ViewContextPropertyName); + + foreach (var attribute in tagHelper.BoundAttributes) + { + writer.WriteAutoPropertyDeclaration( + PublicModifiers, + attribute.TypeName, + attribute.GetPropertyName()); + + if (attribute.IndexerTypeName != null) + { + writer.Write(" = ") + .WriteStartNewObject(attribute.TypeName) + .WriteEndMethodInvocation(); + } + } + } + + private void WriteProcessMethodString(CodeWriter writer, TagHelperDescriptor tagHelper) + { + using (writer.BuildMethodDeclaration( + $"public override async", + $"global::{typeof(Task).FullName}", + TagHelperProcessMethodName, + new Dictionary() + { + { TagHelperContextTypeName, TagHelperContextVariableName }, + { TagHelperOutputTypeName, TagHelperOutputVariableName } + })) + { + writer.WriteInstanceMethodInvocation( + $"({ViewComponentHelperVariableName} as {IViewContextAwareTypeName})?", + IViewContextAwareContextualizeMethodName, + new[] { ViewContextPropertyName }); + + var methodParameters = GetMethodParameters(tagHelper); + writer.Write("var ") + .WriteStartAssignment(TagHelperContentVariableName) + .WriteInstanceMethodInvocation($"await {ViewComponentHelperVariableName}", ViewComponentInvokeMethodName, methodParameters); + writer.WriteStartAssignment($"{TagHelperOutputVariableName}.{TagHelperOutputTagNamePropertyName}") + .WriteLine("null;"); + writer.WriteInstanceMethodInvocation( + $"{TagHelperOutputVariableName}.{TagHelperOutputContentPropertyName}", + TagHelperContentSetMethodName, + new[] { TagHelperContentVariableName }); + } + } + + private string[] GetMethodParameters(TagHelperDescriptor tagHelper) + { + var propertyNames = tagHelper.BoundAttributes.Select(attribute => attribute.GetPropertyName()); + var joinedPropertyNames = string.Join(", ", propertyNames); + var parametersString = $"new {{ { joinedPropertyNames } }}"; + var viewComponentName = tagHelper.GetViewComponentName(); + var methodParameters = new[] { $"\"{viewComponentName}\"", parametersString }; + return methodParameters; + } + + private void WriteTargetElementString(CodeWriter writer, TagHelperDescriptor tagHelper) + { + Debug.Assert(tagHelper.TagMatchingRules.Count() == 1); + + var rule = tagHelper.TagMatchingRules.First(); + + writer.Write("[") + .WriteStartMethodInvocation(HtmlTargetElementAttributeTypeName) + .WriteStringLiteral(rule.TagName) + .WriteLine(")]"); + } + } +} diff --git a/test/Microsoft.AspNetCore.Mvc.Razor.Extensions.Test/TestFiles/IntegrationTests/CodeGenerationIntegrationTest/ViewComponentTagHelper_DesignTime.codegen.cs b/test/Microsoft.AspNetCore.Mvc.Razor.Extensions.Test/TestFiles/IntegrationTests/CodeGenerationIntegrationTest/ViewComponentTagHelper_DesignTime.codegen.cs index 027acd82f3..3e793c429e 100644 --- a/test/Microsoft.AspNetCore.Mvc.Razor.Extensions.Test/TestFiles/IntegrationTests/CodeGenerationIntegrationTest/ViewComponentTagHelper_DesignTime.codegen.cs +++ b/test/Microsoft.AspNetCore.Mvc.Razor.Extensions.Test/TestFiles/IntegrationTests/CodeGenerationIntegrationTest/ViewComponentTagHelper_DesignTime.codegen.cs @@ -57,25 +57,24 @@ global::System.Object __typeHelper = "*, AppCode"; [global::Microsoft.AspNetCore.Mvc.Razor.Internal.RazorInjectAttribute] public global::Microsoft.AspNetCore.Mvc.Rendering.IHtmlHelper Html { get; private set; } [Microsoft.AspNetCore.Razor.TagHelpers.HtmlTargetElementAttribute("vc:test")] -public class __Generated__TestViewComponentTagHelper : Microsoft.AspNetCore.Razor.TagHelpers.TagHelper -{ - private readonly global::Microsoft.AspNetCore.Mvc.IViewComponentHelper _helper = null; - public __Generated__TestViewComponentTagHelper(global::Microsoft.AspNetCore.Mvc.IViewComponentHelper helper) - { - _helper = helper; - } - [Microsoft.AspNetCore.Razor.TagHelpers.HtmlAttributeNotBoundAttribute, global::Microsoft.AspNetCore.Mvc.ViewFeatures.ViewContextAttribute] - public global::Microsoft.AspNetCore.Mvc.Rendering.ViewContext ViewContext { get; set; } - public System.String firstName { get; set; } - public override async global::System.Threading.Tasks.Task ProcessAsync(Microsoft.AspNetCore.Razor.TagHelpers.TagHelperContext context, Microsoft.AspNetCore.Razor.TagHelpers.TagHelperOutput output) - { - (_helper as global::Microsoft.AspNetCore.Mvc.ViewFeatures.IViewContextAware)?.Contextualize(ViewContext); - var content = await _helper.InvokeAsync("Test", new { firstName }); - output.TagName = null; - output.Content.SetHtmlContent(content); - } -} - + public class __Generated__TestViewComponentTagHelper : Microsoft.AspNetCore.Razor.TagHelpers.TagHelper + { + private readonly global::Microsoft.AspNetCore.Mvc.IViewComponentHelper _helper = null; + public __Generated__TestViewComponentTagHelper(global::Microsoft.AspNetCore.Mvc.IViewComponentHelper helper) + { + _helper = helper; + } + [Microsoft.AspNetCore.Razor.TagHelpers.HtmlAttributeNotBoundAttribute, global::Microsoft.AspNetCore.Mvc.ViewFeatures.ViewContextAttribute] + public global::Microsoft.AspNetCore.Mvc.Rendering.ViewContext ViewContext { get; set; } + public System.String firstName { get; set; } + public override async global::System.Threading.Tasks.Task ProcessAsync(Microsoft.AspNetCore.Razor.TagHelpers.TagHelperContext context, Microsoft.AspNetCore.Razor.TagHelpers.TagHelperOutput output) + { + (_helper as global::Microsoft.AspNetCore.Mvc.ViewFeatures.IViewContextAware)?.Contextualize(ViewContext); + var content = await _helper.InvokeAsync("Test", new { firstName }); + output.TagName = null; + output.Content.SetHtmlContent(content); + } + } } } #pragma warning restore 1591 diff --git a/test/Microsoft.AspNetCore.Mvc.Razor.Extensions.Test/TestFiles/IntegrationTests/CodeGenerationIntegrationTest/ViewComponentTagHelper_DesignTime.ir.txt b/test/Microsoft.AspNetCore.Mvc.Razor.Extensions.Test/TestFiles/IntegrationTests/CodeGenerationIntegrationTest/ViewComponentTagHelper_DesignTime.ir.txt index 0e6e005998..a4644b8052 100644 --- a/test/Microsoft.AspNetCore.Mvc.Razor.Extensions.Test/TestFiles/IntegrationTests/CodeGenerationIntegrationTest/ViewComponentTagHelper_DesignTime.ir.txt +++ b/test/Microsoft.AspNetCore.Mvc.Razor.Extensions.Test/TestFiles/IntegrationTests/CodeGenerationIntegrationTest/ViewComponentTagHelper_DesignTime.ir.txt @@ -56,5 +56,4 @@ Document - Inject - Inject - Inject - - CSharpCode - - IntermediateToken - - CSharp - [Microsoft.AspNetCore.Razor.TagHelpers.HtmlTargetElementAttribute("vc:test")]\npublic class __Generated__TestViewComponentTagHelper : Microsoft.AspNetCore.Razor.TagHelpers.TagHelper\n{\n private readonly global::Microsoft.AspNetCore.Mvc.IViewComponentHelper _helper = null;\n public __Generated__TestViewComponentTagHelper(global::Microsoft.AspNetCore.Mvc.IViewComponentHelper helper)\n {\n _helper = helper;\n }\n [Microsoft.AspNetCore.Razor.TagHelpers.HtmlAttributeNotBoundAttribute, global::Microsoft.AspNetCore.Mvc.ViewFeatures.ViewContextAttribute]\n public global::Microsoft.AspNetCore.Mvc.Rendering.ViewContext ViewContext { get; set; }\n public System.String firstName { get; set; }\n public override async global::System.Threading.Tasks.Task ProcessAsync(Microsoft.AspNetCore.Razor.TagHelpers.TagHelperContext context, Microsoft.AspNetCore.Razor.TagHelpers.TagHelperOutput output)\n {\n (_helper as global::Microsoft.AspNetCore.Mvc.ViewFeatures.IViewContextAware)?.Contextualize(ViewContext);\n var content = await _helper.InvokeAsync("Test", new { firstName });\n output.TagName = null;\n output.Content.SetHtmlContent(content);\n }\n}\n + ViewComponentTagHelper - diff --git a/test/Microsoft.AspNetCore.Mvc.Razor.Extensions.Test/TestFiles/IntegrationTests/CodeGenerationIntegrationTest/ViewComponentTagHelper_Runtime.codegen.cs b/test/Microsoft.AspNetCore.Mvc.Razor.Extensions.Test/TestFiles/IntegrationTests/CodeGenerationIntegrationTest/ViewComponentTagHelper_Runtime.codegen.cs index 164b50d51d..fae9d8f97e 100644 --- a/test/Microsoft.AspNetCore.Mvc.Razor.Extensions.Test/TestFiles/IntegrationTests/CodeGenerationIntegrationTest/ViewComponentTagHelper_Runtime.codegen.cs +++ b/test/Microsoft.AspNetCore.Mvc.Razor.Extensions.Test/TestFiles/IntegrationTests/CodeGenerationIntegrationTest/ViewComponentTagHelper_Runtime.codegen.cs @@ -87,25 +87,24 @@ namespace AspNetCore [global::Microsoft.AspNetCore.Mvc.Razor.Internal.RazorInjectAttribute] public global::Microsoft.AspNetCore.Mvc.Rendering.IHtmlHelper Html { get; private set; } [Microsoft.AspNetCore.Razor.TagHelpers.HtmlTargetElementAttribute("vc:test")] -public class __Generated__TestViewComponentTagHelper : Microsoft.AspNetCore.Razor.TagHelpers.TagHelper -{ - private readonly global::Microsoft.AspNetCore.Mvc.IViewComponentHelper _helper = null; - public __Generated__TestViewComponentTagHelper(global::Microsoft.AspNetCore.Mvc.IViewComponentHelper helper) - { - _helper = helper; - } - [Microsoft.AspNetCore.Razor.TagHelpers.HtmlAttributeNotBoundAttribute, global::Microsoft.AspNetCore.Mvc.ViewFeatures.ViewContextAttribute] - public global::Microsoft.AspNetCore.Mvc.Rendering.ViewContext ViewContext { get; set; } - public System.String firstName { get; set; } - public override async global::System.Threading.Tasks.Task ProcessAsync(Microsoft.AspNetCore.Razor.TagHelpers.TagHelperContext context, Microsoft.AspNetCore.Razor.TagHelpers.TagHelperOutput output) - { - (_helper as global::Microsoft.AspNetCore.Mvc.ViewFeatures.IViewContextAware)?.Contextualize(ViewContext); - var content = await _helper.InvokeAsync("Test", new { firstName }); - output.TagName = null; - output.Content.SetHtmlContent(content); - } -} - + public class __Generated__TestViewComponentTagHelper : Microsoft.AspNetCore.Razor.TagHelpers.TagHelper + { + private readonly global::Microsoft.AspNetCore.Mvc.IViewComponentHelper _helper = null; + public __Generated__TestViewComponentTagHelper(global::Microsoft.AspNetCore.Mvc.IViewComponentHelper helper) + { + _helper = helper; + } + [Microsoft.AspNetCore.Razor.TagHelpers.HtmlAttributeNotBoundAttribute, global::Microsoft.AspNetCore.Mvc.ViewFeatures.ViewContextAttribute] + public global::Microsoft.AspNetCore.Mvc.Rendering.ViewContext ViewContext { get; set; } + public System.String firstName { get; set; } + public override async global::System.Threading.Tasks.Task ProcessAsync(Microsoft.AspNetCore.Razor.TagHelpers.TagHelperContext context, Microsoft.AspNetCore.Razor.TagHelpers.TagHelperOutput output) + { + (_helper as global::Microsoft.AspNetCore.Mvc.ViewFeatures.IViewContextAware)?.Contextualize(ViewContext); + var content = await _helper.InvokeAsync("Test", new { firstName }); + output.TagName = null; + output.Content.SetHtmlContent(content); + } + } } } #pragma warning restore 1591 diff --git a/test/Microsoft.AspNetCore.Mvc.Razor.Extensions.Test/TestFiles/IntegrationTests/CodeGenerationIntegrationTest/ViewComponentTagHelper_Runtime.ir.txt b/test/Microsoft.AspNetCore.Mvc.Razor.Extensions.Test/TestFiles/IntegrationTests/CodeGenerationIntegrationTest/ViewComponentTagHelper_Runtime.ir.txt index f169c671c4..1afbf3ebfd 100644 --- a/test/Microsoft.AspNetCore.Mvc.Razor.Extensions.Test/TestFiles/IntegrationTests/CodeGenerationIntegrationTest/ViewComponentTagHelper_Runtime.ir.txt +++ b/test/Microsoft.AspNetCore.Mvc.Razor.Extensions.Test/TestFiles/IntegrationTests/CodeGenerationIntegrationTest/ViewComponentTagHelper_Runtime.ir.txt @@ -41,5 +41,4 @@ Document - Inject - Inject - Inject - - CSharpCode - - IntermediateToken - - CSharp - [Microsoft.AspNetCore.Razor.TagHelpers.HtmlTargetElementAttribute("vc:test")]\npublic class __Generated__TestViewComponentTagHelper : Microsoft.AspNetCore.Razor.TagHelpers.TagHelper\n{\n private readonly global::Microsoft.AspNetCore.Mvc.IViewComponentHelper _helper = null;\n public __Generated__TestViewComponentTagHelper(global::Microsoft.AspNetCore.Mvc.IViewComponentHelper helper)\n {\n _helper = helper;\n }\n [Microsoft.AspNetCore.Razor.TagHelpers.HtmlAttributeNotBoundAttribute, global::Microsoft.AspNetCore.Mvc.ViewFeatures.ViewContextAttribute]\n public global::Microsoft.AspNetCore.Mvc.Rendering.ViewContext ViewContext { get; set; }\n public System.String firstName { get; set; }\n public override async global::System.Threading.Tasks.Task ProcessAsync(Microsoft.AspNetCore.Razor.TagHelpers.TagHelperContext context, Microsoft.AspNetCore.Razor.TagHelpers.TagHelperOutput output)\n {\n (_helper as global::Microsoft.AspNetCore.Mvc.ViewFeatures.IViewContextAware)?.Contextualize(ViewContext);\n var content = await _helper.InvokeAsync("Test", new { firstName });\n output.TagName = null;\n output.Content.SetHtmlContent(content);\n }\n}\n + ViewComponentTagHelper - diff --git a/test/Microsoft.AspNetCore.Mvc.Razor.Extensions.Test/ViewComponentTagHelperPassTest.cs b/test/Microsoft.AspNetCore.Mvc.Razor.Extensions.Test/ViewComponentTagHelperPassTest.cs index 24590d70be..ab70db8306 100644 --- a/test/Microsoft.AspNetCore.Mvc.Razor.Extensions.Test/ViewComponentTagHelperPassTest.cs +++ b/test/Microsoft.AspNetCore.Mvc.Razor.Extensions.Test/ViewComponentTagHelperPassTest.cs @@ -2,7 +2,6 @@ // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System.Linq; -using System.Text; using Microsoft.AspNetCore.Razor.Language; using Microsoft.AspNetCore.Razor.Language.Extensions; using Microsoft.AspNetCore.Razor.Language.Intermediate; @@ -47,7 +46,7 @@ namespace Microsoft.AspNetCore.Mvc.Razor.Extensions Assert.Equal(3, @class.Children.Count); // No class node created for a VCTH for (var i = 0; i < @class.Children.Count; i++) { - Assert.IsNotType(@class.Children[i]); + Assert.IsNotType(@class.Children[i]); } } @@ -94,32 +93,7 @@ namespace Microsoft.AspNetCore.Mvc.Razor.Extensions var @class = FindClassNode(irDocument); Assert.Equal(4, @class.Children.Count); - var vcthClass = Assert.IsType(@class.Children.Last()); - var tokenNode = vcthClass.Children[0] as IntermediateToken; - Assert.Equal( - @"[Microsoft.AspNetCore.Razor.TagHelpers.HtmlTargetElementAttribute(""tagcloud"")] -public class __Generated__TagCloudViewComponentTagHelper : Microsoft.AspNetCore.Razor.TagHelpers.TagHelper -{ - private readonly global::Microsoft.AspNetCore.Mvc.IViewComponentHelper _helper = null; - public __Generated__TagCloudViewComponentTagHelper(global::Microsoft.AspNetCore.Mvc.IViewComponentHelper helper) - { - _helper = helper; - } - [Microsoft.AspNetCore.Razor.TagHelpers.HtmlAttributeNotBoundAttribute, global::Microsoft.AspNetCore.Mvc.ViewFeatures.ViewContextAttribute] - public global::Microsoft.AspNetCore.Mvc.Rendering.ViewContext ViewContext { get; set; } - public System.Int32 Foo { get; set; } - public override async global::System.Threading.Tasks.Task ProcessAsync(Microsoft.AspNetCore.Razor.TagHelpers.TagHelperContext context, Microsoft.AspNetCore.Razor.TagHelpers.TagHelperOutput output) - { - (_helper as global::Microsoft.AspNetCore.Mvc.ViewFeatures.IViewContextAware)?.Contextualize(ViewContext); - var content = await _helper.InvokeAsync(""TagCloud"", new { Foo }); - output.TagName = null; - output.Content.SetHtmlContent(content); - } -} -", - tokenNode.Content, - ignoreLineEndingDifferences: true); - Assert.Equal(TokenKind.CSharp, tokenNode.Kind); + Assert.IsType(@class.Children.Last()); } [Fact] @@ -165,33 +139,7 @@ public class __Generated__TagCloudViewComponentTagHelper : Microsoft.AspNetCore. var @class = FindClassNode(irDocument); Assert.Equal(4, @class.Children.Count); - var vcthClass = Assert.IsType(@class.Children[3]); - var tokenNode = vcthClass.Children[0] as IntermediateToken; - Assert.Equal( - @"[Microsoft.AspNetCore.Razor.TagHelpers.HtmlTargetElementAttribute(""tagcloud"")] -public class __Generated__TagCloudViewComponentTagHelper : Microsoft.AspNetCore.Razor.TagHelpers.TagHelper -{ - private readonly global::Microsoft.AspNetCore.Mvc.IViewComponentHelper _helper = null; - public __Generated__TagCloudViewComponentTagHelper(global::Microsoft.AspNetCore.Mvc.IViewComponentHelper helper) - { - _helper = helper; - } - [Microsoft.AspNetCore.Razor.TagHelpers.HtmlAttributeNotBoundAttribute, global::Microsoft.AspNetCore.Mvc.ViewFeatures.ViewContextAttribute] - public global::Microsoft.AspNetCore.Mvc.Rendering.ViewContext ViewContext { get; set; } - public System.Collections.Generic.Dictionary Tags { get; set; } - = new System.Collections.Generic.Dictionary(); - public override async global::System.Threading.Tasks.Task ProcessAsync(Microsoft.AspNetCore.Razor.TagHelpers.TagHelperContext context, Microsoft.AspNetCore.Razor.TagHelpers.TagHelperOutput output) - { - (_helper as global::Microsoft.AspNetCore.Mvc.ViewFeatures.IViewContextAware)?.Contextualize(ViewContext); - var content = await _helper.InvokeAsync(""TagCloud"", new { Tags }); - output.TagName = null; - output.Content.SetHtmlContent(content); - } -} -", - tokenNode.Content, - ignoreLineEndingDifferences: true); - Assert.Equal(TokenKind.CSharp, tokenNode.Kind); + Assert.IsType(@class.Children[3]); } [Fact] @@ -249,32 +197,7 @@ public class __Generated__TagCloudViewComponentTagHelper : Microsoft.AspNetCore. var @class = FindClassNode(irDocument); Assert.Equal(5, @class.Children.Count); - var vcthClass = Assert.IsType(@class.Children.Last()); - var tokenNode = vcthClass.Children[0] as IntermediateToken; - Assert.Equal( - @"[Microsoft.AspNetCore.Razor.TagHelpers.HtmlTargetElementAttribute(""tagcloud"")] -public class __Generated__TagCloudViewComponentTagHelper : Microsoft.AspNetCore.Razor.TagHelpers.TagHelper -{ - private readonly global::Microsoft.AspNetCore.Mvc.IViewComponentHelper _helper = null; - public __Generated__TagCloudViewComponentTagHelper(global::Microsoft.AspNetCore.Mvc.IViewComponentHelper helper) - { - _helper = helper; - } - [Microsoft.AspNetCore.Razor.TagHelpers.HtmlAttributeNotBoundAttribute, global::Microsoft.AspNetCore.Mvc.ViewFeatures.ViewContextAttribute] - public global::Microsoft.AspNetCore.Mvc.Rendering.ViewContext ViewContext { get; set; } - public System.Int32 Foo { get; set; } - public override async global::System.Threading.Tasks.Task ProcessAsync(Microsoft.AspNetCore.Razor.TagHelpers.TagHelperContext context, Microsoft.AspNetCore.Razor.TagHelpers.TagHelperOutput output) - { - (_helper as global::Microsoft.AspNetCore.Mvc.ViewFeatures.IViewContextAware)?.Contextualize(ViewContext); - var content = await _helper.InvokeAsync(""TagCloud"", new { Foo }); - output.TagName = null; - output.Content.SetHtmlContent(content); - } -} -", - tokenNode.Content, - ignoreLineEndingDifferences: true); - Assert.Equal(TokenKind.CSharp, tokenNode.Kind); + Assert.IsType(@class.Children.Last()); } private RazorCodeDocument CreateDocument(string content) @@ -329,21 +252,6 @@ public class __Generated__TagCloudViewComponentTagHelper : Microsoft.AspNetCore. return visitor.Node; } - private string GetCSharpContent(IntermediateNode node) - { - var builder = new StringBuilder(); - for (var i = 0; i < node.Children.Count; i++) - { - var child = node.Children[i] as IntermediateToken; - if (child.Kind == TokenKind.CSharp) - { - builder.Append(child.Content); - } - } - - return builder.ToString(); - } - private class ClassDeclarationNodeVisitor : IntermediateNodeWalker { public ClassDeclarationIntermediateNode Node { get; set; } diff --git a/test/Microsoft.AspNetCore.Mvc.Razor.Extensions.Test/ViewComponentTagHelperTargetExtensionTest.cs b/test/Microsoft.AspNetCore.Mvc.Razor.Extensions.Test/ViewComponentTagHelperTargetExtensionTest.cs new file mode 100644 index 0000000000..b841a93583 --- /dev/null +++ b/test/Microsoft.AspNetCore.Mvc.Razor.Extensions.Test/ViewComponentTagHelperTargetExtensionTest.cs @@ -0,0 +1,120 @@ +// 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.Language; +using Microsoft.AspNetCore.Razor.Language.CodeGeneration; +using Xunit; + +namespace Microsoft.AspNetCore.Mvc.Razor.Extensions +{ + public class ViewComponentTagHelperTargetExtensionTest + { + [Fact] + public void WriteViewComponentTagHelper_GeneratesViewComponentTagHelper() + { + // Arrange + var tagHelper = TagHelperDescriptorBuilder + .Create(ViewComponentTagHelperConventions.Kind, "TestTagHelper", "TestAssembly") + .TypeName("__Generated__TagCloudViewComponentTagHelper") + .BoundAttributeDescriptor(attribute => attribute + .Name("Foo") + .TypeName("System.Int32") + .PropertyName("Foo")) + .TagMatchingRuleDescriptor(rule => rule.RequireTagName("tagcloud")) + .AddMetadata(ViewComponentTagHelperMetadata.Name, "TagCloud") + .Build(); + + var extension = new ViewComponentTagHelperTargetExtension(); + var context = TestCodeRenderingContext.CreateRuntime(); + var node = new ViewComponentTagHelperIntermediateNode() + { + ClassName = "__Generated__TagCloudViewComponentTagHelper", + TagHelper = tagHelper + }; + + // Act + extension.WriteViewComponentTagHelper(context, node); + + // Assert + var csharp = context.CodeWriter.GenerateCode(); + Assert.Equal( + @"[Microsoft.AspNetCore.Razor.TagHelpers.HtmlTargetElementAttribute(""tagcloud"")] +public class __Generated__TagCloudViewComponentTagHelper : Microsoft.AspNetCore.Razor.TagHelpers.TagHelper +{ + private readonly global::Microsoft.AspNetCore.Mvc.IViewComponentHelper _helper = null; + public __Generated__TagCloudViewComponentTagHelper(global::Microsoft.AspNetCore.Mvc.IViewComponentHelper helper) + { + _helper = helper; + } + [Microsoft.AspNetCore.Razor.TagHelpers.HtmlAttributeNotBoundAttribute, global::Microsoft.AspNetCore.Mvc.ViewFeatures.ViewContextAttribute] + public global::Microsoft.AspNetCore.Mvc.Rendering.ViewContext ViewContext { get; set; } + public System.Int32 Foo { get; set; } + public override async global::System.Threading.Tasks.Task ProcessAsync(Microsoft.AspNetCore.Razor.TagHelpers.TagHelperContext context, Microsoft.AspNetCore.Razor.TagHelpers.TagHelperOutput output) + { + (_helper as global::Microsoft.AspNetCore.Mvc.ViewFeatures.IViewContextAware)?.Contextualize(ViewContext); + var content = await _helper.InvokeAsync(""TagCloud"", new { Foo }); + output.TagName = null; + output.Content.SetHtmlContent(content); + } +} +", + csharp, + ignoreLineEndingDifferences: true); + } + + [Fact] + public void WriteViewComponentTagHelper_GeneratesViewComponentTagHelper_WithIndexer() + { + // Arrange + var tagHelper = TagHelperDescriptorBuilder + .Create(ViewComponentTagHelperConventions.Kind, "TestTagHelper", "TestAssembly") + .TypeName("__Generated__TagCloudViewComponentTagHelper") + .BoundAttributeDescriptor(attribute => attribute + .Name("Foo") + .TypeName("System.Collections.Generic.Dictionary") + .PropertyName("Tags") + .AsDictionaryAttribute("foo-", "System.Int32")) + .TagMatchingRuleDescriptor(rule => rule.RequireTagName("tagcloud")) + .AddMetadata(ViewComponentTagHelperMetadata.Name, "TagCloud") + .Build(); + + var extension = new ViewComponentTagHelperTargetExtension(); + var context = TestCodeRenderingContext.CreateRuntime(); + var node = new ViewComponentTagHelperIntermediateNode() + { + ClassName = "__Generated__TagCloudViewComponentTagHelper", + TagHelper = tagHelper + }; + + // Act + extension.WriteViewComponentTagHelper(context, node); + + // Assert + var csharp = context.CodeWriter.GenerateCode(); + Assert.Equal( + @"[Microsoft.AspNetCore.Razor.TagHelpers.HtmlTargetElementAttribute(""tagcloud"")] +public class __Generated__TagCloudViewComponentTagHelper : Microsoft.AspNetCore.Razor.TagHelpers.TagHelper +{ + private readonly global::Microsoft.AspNetCore.Mvc.IViewComponentHelper _helper = null; + public __Generated__TagCloudViewComponentTagHelper(global::Microsoft.AspNetCore.Mvc.IViewComponentHelper helper) + { + _helper = helper; + } + [Microsoft.AspNetCore.Razor.TagHelpers.HtmlAttributeNotBoundAttribute, global::Microsoft.AspNetCore.Mvc.ViewFeatures.ViewContextAttribute] + public global::Microsoft.AspNetCore.Mvc.Rendering.ViewContext ViewContext { get; set; } + public System.Collections.Generic.Dictionary Tags { get; set; } + = new System.Collections.Generic.Dictionary(); + public override async global::System.Threading.Tasks.Task ProcessAsync(Microsoft.AspNetCore.Razor.TagHelpers.TagHelperContext context, Microsoft.AspNetCore.Razor.TagHelpers.TagHelperOutput output) + { + (_helper as global::Microsoft.AspNetCore.Mvc.ViewFeatures.IViewContextAware)?.Contextualize(ViewContext); + var content = await _helper.InvokeAsync(""TagCloud"", new { Tags }); + output.TagName = null; + output.Content.SetHtmlContent(content); + } +} +", + csharp, + ignoreLineEndingDifferences: true); + } + } +} diff --git a/test/Microsoft.AspNetCore.Mvc.Razor.Extensions.Version1_X.Test/TestFiles/IntegrationTests/CodeGenerationIntegrationTest/ViewComponentTagHelper_DesignTime.codegen.cs b/test/Microsoft.AspNetCore.Mvc.Razor.Extensions.Version1_X.Test/TestFiles/IntegrationTests/CodeGenerationIntegrationTest/ViewComponentTagHelper_DesignTime.codegen.cs index 027acd82f3..3e793c429e 100644 --- a/test/Microsoft.AspNetCore.Mvc.Razor.Extensions.Version1_X.Test/TestFiles/IntegrationTests/CodeGenerationIntegrationTest/ViewComponentTagHelper_DesignTime.codegen.cs +++ b/test/Microsoft.AspNetCore.Mvc.Razor.Extensions.Version1_X.Test/TestFiles/IntegrationTests/CodeGenerationIntegrationTest/ViewComponentTagHelper_DesignTime.codegen.cs @@ -57,25 +57,24 @@ global::System.Object __typeHelper = "*, AppCode"; [global::Microsoft.AspNetCore.Mvc.Razor.Internal.RazorInjectAttribute] public global::Microsoft.AspNetCore.Mvc.Rendering.IHtmlHelper Html { get; private set; } [Microsoft.AspNetCore.Razor.TagHelpers.HtmlTargetElementAttribute("vc:test")] -public class __Generated__TestViewComponentTagHelper : Microsoft.AspNetCore.Razor.TagHelpers.TagHelper -{ - private readonly global::Microsoft.AspNetCore.Mvc.IViewComponentHelper _helper = null; - public __Generated__TestViewComponentTagHelper(global::Microsoft.AspNetCore.Mvc.IViewComponentHelper helper) - { - _helper = helper; - } - [Microsoft.AspNetCore.Razor.TagHelpers.HtmlAttributeNotBoundAttribute, global::Microsoft.AspNetCore.Mvc.ViewFeatures.ViewContextAttribute] - public global::Microsoft.AspNetCore.Mvc.Rendering.ViewContext ViewContext { get; set; } - public System.String firstName { get; set; } - public override async global::System.Threading.Tasks.Task ProcessAsync(Microsoft.AspNetCore.Razor.TagHelpers.TagHelperContext context, Microsoft.AspNetCore.Razor.TagHelpers.TagHelperOutput output) - { - (_helper as global::Microsoft.AspNetCore.Mvc.ViewFeatures.IViewContextAware)?.Contextualize(ViewContext); - var content = await _helper.InvokeAsync("Test", new { firstName }); - output.TagName = null; - output.Content.SetHtmlContent(content); - } -} - + public class __Generated__TestViewComponentTagHelper : Microsoft.AspNetCore.Razor.TagHelpers.TagHelper + { + private readonly global::Microsoft.AspNetCore.Mvc.IViewComponentHelper _helper = null; + public __Generated__TestViewComponentTagHelper(global::Microsoft.AspNetCore.Mvc.IViewComponentHelper helper) + { + _helper = helper; + } + [Microsoft.AspNetCore.Razor.TagHelpers.HtmlAttributeNotBoundAttribute, global::Microsoft.AspNetCore.Mvc.ViewFeatures.ViewContextAttribute] + public global::Microsoft.AspNetCore.Mvc.Rendering.ViewContext ViewContext { get; set; } + public System.String firstName { get; set; } + public override async global::System.Threading.Tasks.Task ProcessAsync(Microsoft.AspNetCore.Razor.TagHelpers.TagHelperContext context, Microsoft.AspNetCore.Razor.TagHelpers.TagHelperOutput output) + { + (_helper as global::Microsoft.AspNetCore.Mvc.ViewFeatures.IViewContextAware)?.Contextualize(ViewContext); + var content = await _helper.InvokeAsync("Test", new { firstName }); + output.TagName = null; + output.Content.SetHtmlContent(content); + } + } } } #pragma warning restore 1591 diff --git a/test/Microsoft.AspNetCore.Mvc.Razor.Extensions.Version1_X.Test/TestFiles/IntegrationTests/CodeGenerationIntegrationTest/ViewComponentTagHelper_DesignTime.ir.txt b/test/Microsoft.AspNetCore.Mvc.Razor.Extensions.Version1_X.Test/TestFiles/IntegrationTests/CodeGenerationIntegrationTest/ViewComponentTagHelper_DesignTime.ir.txt index 11b8d7c99c..c3f1fcf05d 100644 --- a/test/Microsoft.AspNetCore.Mvc.Razor.Extensions.Version1_X.Test/TestFiles/IntegrationTests/CodeGenerationIntegrationTest/ViewComponentTagHelper_DesignTime.ir.txt +++ b/test/Microsoft.AspNetCore.Mvc.Razor.Extensions.Version1_X.Test/TestFiles/IntegrationTests/CodeGenerationIntegrationTest/ViewComponentTagHelper_DesignTime.ir.txt @@ -54,5 +54,4 @@ Document - Inject - Inject - Inject - - CSharpCode - - IntermediateToken - - CSharp - [Microsoft.AspNetCore.Razor.TagHelpers.HtmlTargetElementAttribute("vc:test")]\npublic class __Generated__TestViewComponentTagHelper : Microsoft.AspNetCore.Razor.TagHelpers.TagHelper\n{\n private readonly global::Microsoft.AspNetCore.Mvc.IViewComponentHelper _helper = null;\n public __Generated__TestViewComponentTagHelper(global::Microsoft.AspNetCore.Mvc.IViewComponentHelper helper)\n {\n _helper = helper;\n }\n [Microsoft.AspNetCore.Razor.TagHelpers.HtmlAttributeNotBoundAttribute, global::Microsoft.AspNetCore.Mvc.ViewFeatures.ViewContextAttribute]\n public global::Microsoft.AspNetCore.Mvc.Rendering.ViewContext ViewContext { get; set; }\n public System.String firstName { get; set; }\n public override async global::System.Threading.Tasks.Task ProcessAsync(Microsoft.AspNetCore.Razor.TagHelpers.TagHelperContext context, Microsoft.AspNetCore.Razor.TagHelpers.TagHelperOutput output)\n {\n (_helper as global::Microsoft.AspNetCore.Mvc.ViewFeatures.IViewContextAware)?.Contextualize(ViewContext);\n var content = await _helper.InvokeAsync("Test", new { firstName });\n output.TagName = null;\n output.Content.SetHtmlContent(content);\n }\n}\n + ViewComponentTagHelper - diff --git a/test/Microsoft.AspNetCore.Mvc.Razor.Extensions.Version1_X.Test/ViewComponentTagHelperPassTest.cs b/test/Microsoft.AspNetCore.Mvc.Razor.Extensions.Version1_X.Test/ViewComponentTagHelperPassTest.cs index a8c4e730f0..8200131bbf 100644 --- a/test/Microsoft.AspNetCore.Mvc.Razor.Extensions.Version1_X.Test/ViewComponentTagHelperPassTest.cs +++ b/test/Microsoft.AspNetCore.Mvc.Razor.Extensions.Version1_X.Test/ViewComponentTagHelperPassTest.cs @@ -2,7 +2,6 @@ // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System.Linq; -using System.Text; using Microsoft.AspNetCore.Razor.Language; using Microsoft.AspNetCore.Razor.Language.Extensions; using Microsoft.AspNetCore.Razor.Language.Intermediate; @@ -47,7 +46,7 @@ namespace Microsoft.AspNetCore.Mvc.Razor.Extensions.Version1_X Assert.Equal(3, @class.Children.Count); // No class node created for a VCTH for (var i = 0; i < @class.Children.Count; i++) { - Assert.IsNotType(@class.Children[i]); + Assert.IsNotType(@class.Children[i]); } } @@ -94,32 +93,7 @@ namespace Microsoft.AspNetCore.Mvc.Razor.Extensions.Version1_X var @class = FindClassNode(irDocument); Assert.Equal(4, @class.Children.Count); - var vcthClass = Assert.IsType(@class.Children.Last()); - var tokenNode = vcthClass.Children[0] as IntermediateToken; - Assert.Equal( - @"[Microsoft.AspNetCore.Razor.TagHelpers.HtmlTargetElementAttribute(""tagcloud"")] -public class __Generated__TagCloudViewComponentTagHelper : Microsoft.AspNetCore.Razor.TagHelpers.TagHelper -{ - private readonly global::Microsoft.AspNetCore.Mvc.IViewComponentHelper _helper = null; - public __Generated__TagCloudViewComponentTagHelper(global::Microsoft.AspNetCore.Mvc.IViewComponentHelper helper) - { - _helper = helper; - } - [Microsoft.AspNetCore.Razor.TagHelpers.HtmlAttributeNotBoundAttribute, global::Microsoft.AspNetCore.Mvc.ViewFeatures.ViewContextAttribute] - public global::Microsoft.AspNetCore.Mvc.Rendering.ViewContext ViewContext { get; set; } - public System.Int32 Foo { get; set; } - public override async global::System.Threading.Tasks.Task ProcessAsync(Microsoft.AspNetCore.Razor.TagHelpers.TagHelperContext context, Microsoft.AspNetCore.Razor.TagHelpers.TagHelperOutput output) - { - (_helper as global::Microsoft.AspNetCore.Mvc.ViewFeatures.IViewContextAware)?.Contextualize(ViewContext); - var content = await _helper.InvokeAsync(""TagCloud"", new { Foo }); - output.TagName = null; - output.Content.SetHtmlContent(content); - } -} -", - tokenNode.Content, - ignoreLineEndingDifferences: true); - Assert.Equal(TokenKind.CSharp, tokenNode.Kind); + Assert.IsType(@class.Children.Last()); } [Fact] @@ -165,33 +139,7 @@ public class __Generated__TagCloudViewComponentTagHelper : Microsoft.AspNetCore. var @class = FindClassNode(irDocument); Assert.Equal(4, @class.Children.Count); - var vcthClass = Assert.IsType(@class.Children[3]); - var tokenNode = vcthClass.Children[0] as IntermediateToken; - Assert.Equal( - @"[Microsoft.AspNetCore.Razor.TagHelpers.HtmlTargetElementAttribute(""tagcloud"")] -public class __Generated__TagCloudViewComponentTagHelper : Microsoft.AspNetCore.Razor.TagHelpers.TagHelper -{ - private readonly global::Microsoft.AspNetCore.Mvc.IViewComponentHelper _helper = null; - public __Generated__TagCloudViewComponentTagHelper(global::Microsoft.AspNetCore.Mvc.IViewComponentHelper helper) - { - _helper = helper; - } - [Microsoft.AspNetCore.Razor.TagHelpers.HtmlAttributeNotBoundAttribute, global::Microsoft.AspNetCore.Mvc.ViewFeatures.ViewContextAttribute] - public global::Microsoft.AspNetCore.Mvc.Rendering.ViewContext ViewContext { get; set; } - public System.Collections.Generic.Dictionary Tags { get; set; } - = new System.Collections.Generic.Dictionary(); - public override async global::System.Threading.Tasks.Task ProcessAsync(Microsoft.AspNetCore.Razor.TagHelpers.TagHelperContext context, Microsoft.AspNetCore.Razor.TagHelpers.TagHelperOutput output) - { - (_helper as global::Microsoft.AspNetCore.Mvc.ViewFeatures.IViewContextAware)?.Contextualize(ViewContext); - var content = await _helper.InvokeAsync(""TagCloud"", new { Tags }); - output.TagName = null; - output.Content.SetHtmlContent(content); - } -} -", - tokenNode.Content, - ignoreLineEndingDifferences: true); - Assert.Equal(TokenKind.CSharp, tokenNode.Kind); + Assert.IsType(@class.Children[3]); } [Fact] @@ -230,7 +178,7 @@ public class __Generated__TagCloudViewComponentTagHelper : Microsoft.AspNetCore. }; var irDocument = CreateIRDocument(engine, codeDocument); - + var vcthFullName = "AspNetCore.test_cshtml.__Generated__TagCloudViewComponentTagHelper"; // Act @@ -249,32 +197,7 @@ public class __Generated__TagCloudViewComponentTagHelper : Microsoft.AspNetCore. var @class = FindClassNode(irDocument); Assert.Equal(5, @class.Children.Count); - var vcthClass = Assert.IsType(@class.Children.Last()); - var tokenNode = vcthClass.Children[0] as IntermediateToken; - Assert.Equal( - @"[Microsoft.AspNetCore.Razor.TagHelpers.HtmlTargetElementAttribute(""tagcloud"")] -public class __Generated__TagCloudViewComponentTagHelper : Microsoft.AspNetCore.Razor.TagHelpers.TagHelper -{ - private readonly global::Microsoft.AspNetCore.Mvc.IViewComponentHelper _helper = null; - public __Generated__TagCloudViewComponentTagHelper(global::Microsoft.AspNetCore.Mvc.IViewComponentHelper helper) - { - _helper = helper; - } - [Microsoft.AspNetCore.Razor.TagHelpers.HtmlAttributeNotBoundAttribute, global::Microsoft.AspNetCore.Mvc.ViewFeatures.ViewContextAttribute] - public global::Microsoft.AspNetCore.Mvc.Rendering.ViewContext ViewContext { get; set; } - public System.Int32 Foo { get; set; } - public override async global::System.Threading.Tasks.Task ProcessAsync(Microsoft.AspNetCore.Razor.TagHelpers.TagHelperContext context, Microsoft.AspNetCore.Razor.TagHelpers.TagHelperOutput output) - { - (_helper as global::Microsoft.AspNetCore.Mvc.ViewFeatures.IViewContextAware)?.Contextualize(ViewContext); - var content = await _helper.InvokeAsync(""TagCloud"", new { Foo }); - output.TagName = null; - output.Content.SetHtmlContent(content); - } -} -", - tokenNode.Content, - ignoreLineEndingDifferences: true); - Assert.Equal(TokenKind.CSharp, tokenNode.Kind); + Assert.IsType(@class.Children.Last()); } private RazorCodeDocument CreateDocument(string content) @@ -329,21 +252,6 @@ public class __Generated__TagCloudViewComponentTagHelper : Microsoft.AspNetCore. return visitor.Node; } - private string GetCSharpContent(IntermediateNode node) - { - var builder = new StringBuilder(); - for (var i = 0; i < node.Children.Count; i++) - { - var child = node.Children[i] as IntermediateToken; - if (child.Kind == TokenKind.CSharp) - { - builder.Append(child.Content); - } - } - - return builder.ToString(); - } - private class ClassDeclarationNodeVisitor : IntermediateNodeWalker { public ClassDeclarationIntermediateNode Node { get; set; } diff --git a/test/Microsoft.AspNetCore.Mvc.Razor.Extensions.Version1_X.Test/ViewComponentTagHelperTargetExtensionTest.cs b/test/Microsoft.AspNetCore.Mvc.Razor.Extensions.Version1_X.Test/ViewComponentTagHelperTargetExtensionTest.cs new file mode 100644 index 0000000000..2e3c476a36 --- /dev/null +++ b/test/Microsoft.AspNetCore.Mvc.Razor.Extensions.Version1_X.Test/ViewComponentTagHelperTargetExtensionTest.cs @@ -0,0 +1,120 @@ +// 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.Language; +using Microsoft.AspNetCore.Razor.Language.CodeGeneration; +using Xunit; + +namespace Microsoft.AspNetCore.Mvc.Razor.Extensions.Version1_X +{ + public class ViewComponentTagHelperTargetExtensionTest + { + [Fact] + public void WriteViewComponentTagHelper_GeneratesViewComponentTagHelper() + { + // Arrange + var tagHelper = TagHelperDescriptorBuilder + .Create(ViewComponentTagHelperConventions.Kind, "TestTagHelper", "TestAssembly") + .TypeName("__Generated__TagCloudViewComponentTagHelper") + .BoundAttributeDescriptor(attribute => attribute + .Name("Foo") + .TypeName("System.Int32") + .PropertyName("Foo")) + .TagMatchingRuleDescriptor(rule => rule.RequireTagName("tagcloud")) + .AddMetadata(ViewComponentTagHelperMetadata.Name, "TagCloud") + .Build(); + + var extension = new ViewComponentTagHelperTargetExtension(); + var context = TestCodeRenderingContext.CreateRuntime(); + var node = new ViewComponentTagHelperIntermediateNode() + { + ClassName = "__Generated__TagCloudViewComponentTagHelper", + TagHelper = tagHelper + }; + + // Act + extension.WriteViewComponentTagHelper(context, node); + + // Assert + var csharp = context.CodeWriter.GenerateCode(); + Assert.Equal( + @"[Microsoft.AspNetCore.Razor.TagHelpers.HtmlTargetElementAttribute(""tagcloud"")] +public class __Generated__TagCloudViewComponentTagHelper : Microsoft.AspNetCore.Razor.TagHelpers.TagHelper +{ + private readonly global::Microsoft.AspNetCore.Mvc.IViewComponentHelper _helper = null; + public __Generated__TagCloudViewComponentTagHelper(global::Microsoft.AspNetCore.Mvc.IViewComponentHelper helper) + { + _helper = helper; + } + [Microsoft.AspNetCore.Razor.TagHelpers.HtmlAttributeNotBoundAttribute, global::Microsoft.AspNetCore.Mvc.ViewFeatures.ViewContextAttribute] + public global::Microsoft.AspNetCore.Mvc.Rendering.ViewContext ViewContext { get; set; } + public System.Int32 Foo { get; set; } + public override async global::System.Threading.Tasks.Task ProcessAsync(Microsoft.AspNetCore.Razor.TagHelpers.TagHelperContext context, Microsoft.AspNetCore.Razor.TagHelpers.TagHelperOutput output) + { + (_helper as global::Microsoft.AspNetCore.Mvc.ViewFeatures.IViewContextAware)?.Contextualize(ViewContext); + var content = await _helper.InvokeAsync(""TagCloud"", new { Foo }); + output.TagName = null; + output.Content.SetHtmlContent(content); + } +} +", + csharp, + ignoreLineEndingDifferences: true); + } + + [Fact] + public void WriteViewComponentTagHelper_GeneratesViewComponentTagHelper_WithIndexer() + { + // Arrange + var tagHelper = TagHelperDescriptorBuilder + .Create(ViewComponentTagHelperConventions.Kind, "TestTagHelper", "TestAssembly") + .TypeName("__Generated__TagCloudViewComponentTagHelper") + .BoundAttributeDescriptor(attribute => attribute + .Name("Foo") + .TypeName("System.Collections.Generic.Dictionary") + .PropertyName("Tags") + .AsDictionaryAttribute("foo-", "System.Int32")) + .TagMatchingRuleDescriptor(rule => rule.RequireTagName("tagcloud")) + .AddMetadata(ViewComponentTagHelperMetadata.Name, "TagCloud") + .Build(); + + var extension = new ViewComponentTagHelperTargetExtension(); + var context = TestCodeRenderingContext.CreateRuntime(); + var node = new ViewComponentTagHelperIntermediateNode() + { + ClassName = "__Generated__TagCloudViewComponentTagHelper", + TagHelper = tagHelper + }; + + // Act + extension.WriteViewComponentTagHelper(context, node); + + // Assert + var csharp = context.CodeWriter.GenerateCode(); + Assert.Equal( + @"[Microsoft.AspNetCore.Razor.TagHelpers.HtmlTargetElementAttribute(""tagcloud"")] +public class __Generated__TagCloudViewComponentTagHelper : Microsoft.AspNetCore.Razor.TagHelpers.TagHelper +{ + private readonly global::Microsoft.AspNetCore.Mvc.IViewComponentHelper _helper = null; + public __Generated__TagCloudViewComponentTagHelper(global::Microsoft.AspNetCore.Mvc.IViewComponentHelper helper) + { + _helper = helper; + } + [Microsoft.AspNetCore.Razor.TagHelpers.HtmlAttributeNotBoundAttribute, global::Microsoft.AspNetCore.Mvc.ViewFeatures.ViewContextAttribute] + public global::Microsoft.AspNetCore.Mvc.Rendering.ViewContext ViewContext { get; set; } + public System.Collections.Generic.Dictionary Tags { get; set; } + = new System.Collections.Generic.Dictionary(); + public override async global::System.Threading.Tasks.Task ProcessAsync(Microsoft.AspNetCore.Razor.TagHelpers.TagHelperContext context, Microsoft.AspNetCore.Razor.TagHelpers.TagHelperOutput output) + { + (_helper as global::Microsoft.AspNetCore.Mvc.ViewFeatures.IViewContextAware)?.Contextualize(ViewContext); + var content = await _helper.InvokeAsync(""TagCloud"", new { Tags }); + output.TagName = null; + output.Content.SetHtmlContent(content); + } +} +", + csharp, + ignoreLineEndingDifferences: true); + } + } +}