Merge branch 'release' of github.com:aspnet/Razor into release

This commit is contained in:
Wei Wang 2015-01-28 18:25:49 -08:00
commit ba387a3a22
88 changed files with 3728 additions and 1816 deletions

View File

@ -19,10 +19,10 @@ IF EXIST packages\KoreBuild goto run
.nuget\NuGet.exe install KoreBuild -ExcludeVersion -o packages -nocache -pre
.nuget\NuGet.exe install Sake -version 0.2 -o packages -ExcludeVersion
IF "%SKIP_KRE_INSTALL%"=="1" goto run
CALL packages\KoreBuild\build\kvm upgrade -runtime CLR -x86
CALL packages\KoreBuild\build\kvm install default -runtime CoreCLR -x86
IF "%SKIP_DOTNET_INSTALL%"=="1" goto run
CALL packages\KoreBuild\build\dotnetsdk upgrade -runtime CLR -x86
CALL packages\KoreBuild\build\dotnetsdk install default -runtime CoreCLR -x86
:run
CALL packages\KoreBuild\build\kvm use default -runtime CLR -x86
CALL packages\KoreBuild\build\dotnetsdk use default -runtime CLR -x86
packages\Sake\tools\Sake.exe -I packages\KoreBuild\build -f makefile.shade %*

View File

@ -28,11 +28,11 @@ if test ! -d packages/KoreBuild; then
fi
if ! type k > /dev/null 2>&1; then
source packages/KoreBuild/build/kvm.sh
source packages/KoreBuild/build/dotnetsdk.sh
fi
if ! type k > /dev/null 2>&1; then
kvm upgrade
dotnetsdk upgrade
fi
mono packages/Sake/tools/Sake.exe -I packages/KoreBuild/build -f makefile.shade "$@"

View File

@ -81,17 +81,17 @@ namespace Microsoft.AspNet.Razor.Runtime
/// <summary>
/// Parameter {0} must not contain null tag names.
/// </summary>
internal static string TagNameAttribute_AdditionalTagsCannotContainNull
internal static string HtmlElementNameAttribute_AdditionalTagsCannotContainNull
{
get { return GetString("TagNameAttribute_AdditionalTagsCannotContainNull"); }
get { return GetString("HtmlElementNameAttribute_AdditionalTagsCannotContainNull"); }
}
/// <summary>
/// Parameter {0} must not contain null tag names.
/// </summary>
internal static string FormatTagNameAttribute_AdditionalTagsCannotContainNull(object p0)
internal static string FormatHtmlElementNameAttribute_AdditionalTagsCannotContainNull(object p0)
{
return string.Format(CultureInfo.CurrentCulture, GetString("TagNameAttribute_AdditionalTagsCannotContainNull"), p0);
return string.Format(CultureInfo.CurrentCulture, GetString("HtmlElementNameAttribute_AdditionalTagsCannotContainNull"), p0);
}
/// <summary>

View File

@ -131,7 +131,7 @@
<data name="ScopeManager_EndCannotBeCalledWithoutACallToBegin" xml:space="preserve">
<value>Must call '{2}.{1}' before calling '{2}.{0}'.</value>
</data>
<data name="TagNameAttribute_AdditionalTagsCannotContainNull" xml:space="preserve">
<data name="HtmlElementNameAttribute_AdditionalTagsCannotContainNull" xml:space="preserve">
<value>Parameter {0} must not contain null tag names.</value>
</data>
<data name="ArgumentCannotBeNullOrEmpty" xml:space="preserve">

View File

@ -1,31 +0,0 @@
// Copyright (c) Microsoft Open Technologies, Inc. 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.AspNet.Razor.TagHelpers;
namespace Microsoft.AspNet.Razor.Runtime.TagHelpers
{
/// <summary>
/// Used to override <see cref="ITagHelper"/>'s behavior when its
/// <see cref="ITagHelper.ProcessAsync"/> is invoked.
/// </summary>
[AttributeUsage(AttributeTargets.Class, AllowMultiple = false, Inherited = false)]
public sealed class ContentBehaviorAttribute : Attribute
{
/// <summary>
/// Instantiates a new instance of the <see cref="ContentBehaviorAttribute"/> class.
/// </summary>
/// <param name="contentBehavior">The <see cref="Razor.TagHelpers.ContentBehavior"/> for the
/// <see cref="ITagHelper"/>.</param>
public ContentBehaviorAttribute(ContentBehavior contentBehavior)
{
ContentBehavior = contentBehavior;
}
/// <summary>
/// <see cref="Razor.TagHelpers.ContentBehavior"/> for the <see cref="ITagHelper"/>.
/// </summary>
public ContentBehavior ContentBehavior { get; private set; }
}
}

View File

@ -11,29 +11,29 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers
/// Used to override a <see cref="ITagHelper"/>'s default tag name target.
/// </summary>
[AttributeUsage(AttributeTargets.Class, AllowMultiple = true, Inherited = false)]
public sealed class TagNameAttribute : Attribute
public sealed class HtmlElementNameAttribute : Attribute
{
/// <summary>
/// Instantiates a new instance of the <see cref="TagNameAttribute"/> class.
/// Instantiates a new instance of the <see cref="HtmlElementNameAttribute"/> class.
/// </summary>
/// <param name="tag">The HTML tag name for the <see cref="TagHelper"/> to target.</param>
public TagNameAttribute([NotNull] string tag)
public HtmlElementNameAttribute([NotNull] string tag)
{
Tags = new[] { tag };
}
/// <summary>
/// Instantiates a new instance of the <see cref="TagNameAttribute"/> class.
/// Instantiates a new instance of the <see cref="HtmlElementNameAttribute"/> class.
/// </summary>
/// <param name="tag">The HTML tag name for the <see cref="TagHelper"/> to target.</param>
/// <param name="additionalTags">Additional HTML tag names for the <see cref="TagHelper"/> to target.</param>
public TagNameAttribute([NotNull] string tag, [NotNull] params string[] additionalTags)
public HtmlElementNameAttribute([NotNull] string tag, [NotNull] params string[] additionalTags)
{
if (additionalTags.Contains(null))
{
throw new ArgumentNullException(
nameof(additionalTags),
Resources.FormatTagNameAttribute_AdditionalTagsCannotContainNull(nameof(additionalTags)));
Resources.FormatHtmlElementNameAttribute_AdditionalTagsCannotContainNull(nameof(additionalTags)));
};
var allTags = new List<string>(additionalTags);

View File

@ -1,7 +1,9 @@
// Copyright (c) Microsoft Open Technologies, Inc. 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.Threading.Tasks;
namespace Microsoft.AspNet.Razor.Runtime.TagHelpers
{
@ -10,18 +12,42 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers
/// </summary>
public class TagHelperContext
{
private readonly Func<Task<string>> _getChildContentAsync;
/// <summary>
/// Instantiates a new <see cref="TagHelperContext"/>.
/// </summary>
/// <param name="allAttributes">Every attribute associated with the current HTML element.</param>
public TagHelperContext([NotNull] IDictionary<string, object> allAttributes)
/// <param name="uniqueId">The unique identifier for the source element this <see cref="TagHelperContext" />
/// applies to.</param>
/// <param name="getChildContentAsync">A delegate used to execute and retrieve the rendered child content
/// asynchronously.</param>
public TagHelperContext([NotNull] IDictionary<string, object> allAttributes,
[NotNull] string uniqueId,
[NotNull] Func<Task<string>> getChildContentAsync)
{
AllAttributes = allAttributes;
UniqueId = uniqueId;
_getChildContentAsync = getChildContentAsync;
}
/// <summary>
/// Every attribute associated with the current HTML element.
/// </summary>
public IDictionary<string, object> AllAttributes { get; private set; }
public IDictionary<string, object> AllAttributes { get; }
/// <summary>
/// An identifier unique to the HTML element this context is for.
/// </summary>
public string UniqueId { get; }
/// <summary>
/// A delegate used to execute and retrieve the rendered child content asynchronously.
/// </summary>
/// <returns>A <see cref="Task"/> that when executed returns content rendered by children.</returns>
public Task<string> GetChildContentAsync()
{
return _getChildContentAsync();
}
}
}

View File

@ -5,6 +5,7 @@ using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text.RegularExpressions;
using Microsoft.AspNet.Razor.TagHelpers;
namespace Microsoft.AspNet.Razor.Runtime.TagHelpers
@ -15,6 +16,14 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers
public static class TagHelperDescriptorFactory
{
private const string TagHelperNameEnding = "TagHelper";
private const string HtmlCaseRegexReplacement = "-$1$2";
// This matches the following AFTER the start of the input string (MATCH).
// Any letter/number followed by an uppercase letter then lowercase letter: 1(Aa), a(Aa), A(Aa)
// Any lowercase letter followed by an uppercase letter: a(A)
// Each match is then prefixed by a "-" via the ToHtmlCase method.
private static readonly Regex HtmlCaseRegex =
new Regex("(?<!^)((?<=[a-zA-Z0-9])[A-Z][a-z])|((?<=[a-z])[A-Z])", RegexOptions.None);
// TODO: Investigate if we should cache TagHelperDescriptors for types:
// https://github.com/aspnet/Razor/issues/165
@ -29,21 +38,19 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers
var tagNames = GetTagNames(type);
var typeName = type.FullName;
var attributeDescriptors = GetAttributeDescriptors(type);
var contentBehavior = GetContentBehavior(type);
var assemblyName = type.GetTypeInfo().Assembly.GetName().Name;
return tagNames.Select(tagName =>
new TagHelperDescriptor(tagName,
typeName,
assemblyName,
contentBehavior,
attributeDescriptors));
}
private static IEnumerable<string> GetTagNames(Type tagHelperType)
{
var typeInfo = tagHelperType.GetTypeInfo();
var attributes = typeInfo.GetCustomAttributes<TagNameAttribute>(inherit: false);
var attributes = typeInfo.GetCustomAttributes<HtmlElementNameAttribute>(inherit: false);
// If there isn't an attribute specifying the tag name derive it from the name
if (!attributes.Any())
@ -55,7 +62,7 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers
name = name.Substring(0, name.Length - TagHelperNameEnding.Length);
}
return new[] { name };
return new[] { ToHtmlCase(name) };
}
// Remove duplicate tag names.
@ -75,21 +82,11 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers
var attributeNameAttribute = property.GetCustomAttribute<HtmlAttributeNameAttribute>(inherit: false);
var attributeName = attributeNameAttribute != null ?
attributeNameAttribute.Name :
property.Name;
ToHtmlCase(property.Name);
return new TagHelperAttributeDescriptor(attributeName, property.Name, property.PropertyType.FullName);
}
private static ContentBehavior GetContentBehavior(Type type)
{
var typeInfo = type.GetTypeInfo();
var contentBehaviorAttribute = typeInfo.GetCustomAttribute<ContentBehaviorAttribute>(inherit: false);
return contentBehaviorAttribute != null ?
contentBehaviorAttribute.ContentBehavior :
ContentBehavior.None;
}
private static bool IsValidProperty(PropertyInfo property)
{
return property.GetMethod != null &&
@ -97,5 +94,22 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers
property.SetMethod != null &&
property.SetMethod.IsPublic;
}
/// <summary>
/// Converts from pascal/camel case to lower kebab-case.
/// </summary>
/// <example>
/// SomeThing => some-thing
/// capsONInside => caps-on-inside
/// CAPSOnOUTSIDE => caps-on-outside
/// ALLCAPS => allcaps
/// One1Two2Three3 => one1-two2-three3
/// ONE1TWO2THREE3 => one1two2three3
/// First_Second_ThirdHi => first_second_third-hi
/// </example>
private static string ToHtmlCase(string name)
{
return HtmlCaseRegex.Replace(name, HtmlCaseRegexReplacement).ToLowerInvariant();
}
}
}

View File

@ -3,6 +3,8 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Threading.Tasks;
namespace Microsoft.AspNet.Razor.Runtime.TagHelpers
{
@ -12,28 +14,73 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers
public class TagHelperExecutionContext
{
private readonly List<ITagHelper> _tagHelpers;
private readonly Func<Task> _executeChildContentAsync;
private readonly Action _startWritingScope;
private readonly Func<TextWriter> _endWritingScope;
private string _childContent;
/// <summary>
/// Internal for testing purposes only.
/// </summary>
internal TagHelperExecutionContext(string tagName)
: this(tagName,
uniqueId: string.Empty,
executeChildContentAsync: async () => await Task.FromResult(result: true),
startWritingScope: () => { },
endWritingScope: () => new StringWriter())
{
}
/// <summary>
/// Instantiates a new <see cref="TagHelperExecutionContext"/>.
/// </summary>
/// <param name="tagName">The HTML tag name in the Razor source.</param>
public TagHelperExecutionContext([NotNull] string tagName)
/// <param name="uniqueId">An identifier unique to the HTML element this context is for.</param>
/// <param name="executeChildContentAsync">A delegate used to execute the child content asynchronously.</param>
/// <param name="startWritingScope">A delegate used to start a writing scope in a Razor page.</param>
/// <param name="endWritingScope">A delegate used to end a writing scope in a Razor page.</param>
public TagHelperExecutionContext([NotNull] string tagName,
[NotNull] string uniqueId,
[NotNull] Func<Task> executeChildContentAsync,
[NotNull] Action startWritingScope,
[NotNull] Func<TextWriter> endWritingScope)
{
_tagHelpers = new List<ITagHelper>();
_executeChildContentAsync = executeChildContentAsync;
_startWritingScope = startWritingScope;
_endWritingScope = endWritingScope;
AllAttributes = new Dictionary<string, object>(StringComparer.OrdinalIgnoreCase);
HTMLAttributes = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
_tagHelpers = new List<ITagHelper>();
TagName = tagName;
UniqueId = uniqueId;
}
/// <summary>
/// Indicates if <see cref="GetChildContentAsync"/> has been called.
/// </summary>
public bool ChildContentRetrieved
{
get
{
return _childContent != null;
}
}
/// <summary>
/// HTML attributes.
/// </summary>
public IDictionary<string, string> HTMLAttributes { get; private set; }
public IDictionary<string, string> HTMLAttributes { get; }
/// <summary>
/// <see cref="ITagHelper"/> bound attributes and HTML attributes.
/// </summary>
public IDictionary<string, object> AllAttributes { get; private set; }
public IDictionary<string, object> AllAttributes { get; }
/// <summary>
/// An identifier unique to the HTML element this context is for.
/// </summary>
public string UniqueId { get; }
/// <summary>
/// <see cref="ITagHelper"/>s that should be run.
@ -49,7 +96,7 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers
/// <summary>
/// The HTML tag name in the Razor source.
/// </summary>
public string TagName { get; private set; }
public string TagName { get; }
/// <summary>
/// The <see cref="ITagHelper"/>s' output.
@ -85,5 +132,34 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers
{
AllAttributes.Add(name, value);
}
/// <summary>
/// Executes the child content asynchronously.
/// </summary>
/// <returns>A <see cref="Task"/> which on completion executes all child content.</returns>
public Task ExecuteChildContentAsync()
{
return _executeChildContentAsync();
}
/// <summary>
/// Execute and retrieve the rendered child content asynchronously.
/// </summary>
/// <returns>A <see cref="Task"/> that on completion returns the rendered child content.</returns>
/// <remarks>
/// Child content is only executed once. Successive calls to this method or successive executions of the
/// returned <see cref="Task{string}"/> return a cached result.
/// </remarks>
public async Task<string> GetChildContentAsync()
{
if (_childContent == null)
{
_startWritingScope();
await _executeChildContentAsync();
_childContent = _endWritingScope().ToString();
}
return _childContent;
}
}
}

View File

@ -15,7 +15,7 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers
public class TagHelperOutput
{
private string _content;
private string _tagName;
private bool _contentSet;
// Internal for testing
internal TagHelperOutput(string tagName)
@ -24,48 +24,39 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers
Attributes = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
}
// Internal for testing
internal TagHelperOutput(string tagName, [NotNull] IDictionary<string, string> attributes)
: this(tagName, attributes, string.Empty)
{
}
/// <summary>
/// Instantiates a new instance of <see cref="TagHelperOutput"/>.
/// </summary>
/// <param name="tagName">The HTML element's tag name.</param>
/// <param name="attributes">The HTML attributes.</param>
/// <param name="content">The HTML element's content.</param>
public TagHelperOutput(string tagName,
[NotNull] IDictionary<string, string> attributes,
string content)
public TagHelperOutput(string tagName, [NotNull] IDictionary<string, string> attributes)
{
TagName = tagName;
Content = content;
Attributes = new Dictionary<string, string>(attributes, StringComparer.OrdinalIgnoreCase);
PreContent = string.Empty;
_content = string.Empty;
PostContent = string.Empty;
}
/// <summary>
/// The HTML element's tag name.
/// </summary>
/// <remarks>
/// A whitespace value results in no start or end tag being rendered.
/// A whitespace or <c>null</c> value results in no start or end tag being rendered.
/// </remarks>
public string TagName
{
get
{
return _tagName;
}
set
{
_tagName = value ?? string.Empty;
}
}
public string TagName { get; set; }
/// <summary>
/// The HTML element's content.
/// The HTML element's pre content.
/// </summary>
/// <remarks>Value is prepended to the <see cref="ITagHelper"/>'s final output.</remarks>
public string PreContent { get; set; }
/// <summary>
/// The HTML element's main content.
/// </summary>
/// <remarks>Value occurs in the <see cref="ITagHelper"/>'s final output after <see cref="PreContent"/> and
/// before <see cref="PostContent"/></remarks>
public string Content
{
get
@ -74,7 +65,25 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers
}
set
{
_content = value ?? string.Empty;
_contentSet = true;
_content = value;
}
}
/// <summary>
/// The HTML element's post content.
/// </summary>
/// <remarks>Value is appended to the <see cref="ITagHelper"/>'s final output.</remarks>
public string PostContent { get; set; }
/// <summary>
/// <c>true</c> if <see cref="Content"/> has been set, <c>false</c> otherwise.
/// </summary>
public bool ContentSet
{
get
{
return _contentSet;
}
}
@ -86,7 +95,7 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers
/// <summary>
/// The HTML element's attributes.
/// </summary>
public IDictionary<string, string> Attributes { get; private set; }
public IDictionary<string, string> Attributes { get; }
/// <summary>
/// Generates the <see cref="TagHelperOutput"/>'s start tag.
@ -126,6 +135,22 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers
return sb.ToString();
}
/// <summary>
/// Generates the <see cref="TagHelperOutput"/>'s <see cref="PreContent"/>.
/// </summary>
/// <returns><c>string.Empty</c> if <see cref="SelfClosing"/> is <c>true</c>. <see cref="PreContent"/>
/// otherwise.
/// </returns>
public string GeneratePreContent()
{
if (SelfClosing)
{
return string.Empty;
}
return PreContent;
}
/// <summary>
/// Generates the <see cref="TagHelperOutput"/>'s body.
/// </summary>
@ -141,6 +166,22 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers
return Content;
}
/// <summary>
/// Generates the <see cref="TagHelperOutput"/>'s <see cref="PostContent"/>.
/// </summary>
/// <returns><c>string.Empty</c> if <see cref="SelfClosing"/> is <c>true</c>. <see cref="PostContent"/>
/// otherwise.
/// </returns>
public string GeneratePostContent()
{
if (SelfClosing)
{
return string.Empty;
}
return PostContent;
}
/// <summary>
/// Generates the <see cref="TagHelperOutput"/>'s end tag.
/// </summary>
@ -155,5 +196,20 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers
return string.Format(CultureInfo.InvariantCulture, "</{0}>", TagName);
}
/// <summary>
/// Changes <see cref="TagHelperOutput"/> to generate nothing.
/// </summary>
/// <remarks>
/// Sets <see cref="TagName"/>, <see cref="PreContent"/>, <see cref="Content"/>, and <see cref="PostContent"/>
/// to <c>null</c> to suppress output.
/// </remarks>
public void SuppressOutput()
{
TagName = null;
PreContent = null;
Content = null;
PostContent = null;
}
}
}

View File

@ -1,7 +1,6 @@
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System.IO;
using System.Threading.Tasks;
namespace Microsoft.AspNet.Razor.Runtime.TagHelpers
@ -14,33 +13,17 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers
/// <summary>
/// Calls the <see cref="ITagHelper.ProcessAsync"/> method on <see cref="ITagHelper"/>s.
/// </summary>
/// <param name="context">Contains information associated with running <see cref="ITagHelper"/>s.</param>
/// <param name="executionContext">Contains information associated with running <see cref="ITagHelper"/>s.
/// </param>
/// <returns>Resulting <see cref="TagHelperOutput"/> from processing all of the
/// <paramref name="context"/>'s <see cref="ITagHelper"/>s.</returns>
public async Task<TagHelperOutput> RunAsync([NotNull] TagHelperExecutionContext context)
/// <paramref name="executionContext"/>'s <see cref="ITagHelper"/>s.</returns>
public async Task<TagHelperOutput> RunAsync([NotNull] TagHelperExecutionContext executionContext)
{
return await RunAsyncCore(context, string.Empty);
}
/// <summary>
/// Calls the <see cref="ITagHelper.ProcessAsync"/> method on <see cref="ITagHelper"/>s.
/// </summary>
/// <param name="context">Contains information associated with running <see cref="ITagHelper"/>s.</param>
/// <param name="bufferedBody">Contains the buffered content of the current HTML tag.</param>
/// <returns>Resulting <see cref="TagHelperOutput"/> from processing all of the
/// <paramref name="context"/>'s <see cref="ITagHelper"/>s.</returns>
public async Task<TagHelperOutput> RunAsync([NotNull] TagHelperExecutionContext context,
[NotNull] TextWriter bufferedBody)
{
return await RunAsyncCore(context, bufferedBody.ToString());
}
private async Task<TagHelperOutput> RunAsyncCore(TagHelperExecutionContext executionContext, string outputContent)
{
var tagHelperContext = new TagHelperContext(executionContext.AllAttributes);
var tagHelperOutput = new TagHelperOutput(executionContext.TagName,
executionContext.HTMLAttributes,
outputContent);
var tagHelperContext = new TagHelperContext(
executionContext.AllAttributes,
executionContext.UniqueId,
executionContext.GetChildContentAsync);
var tagHelperOutput = new TagHelperOutput(executionContext.TagName, executionContext.HTMLAttributes);
foreach (var tagHelper in executionContext.TagHelpers)
{

View File

@ -3,6 +3,8 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Threading.Tasks;
namespace Microsoft.AspNet.Razor.Runtime.TagHelpers
{
@ -25,10 +27,22 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers
/// Starts a <see cref="TagHelperExecutionContext"/> scope.
/// </summary>
/// <param name="tagName">The HTML tag name that the scope is associated with.</param>
/// <param name="uniqueId">An identifier unique to the HTML element this scope is for.</param>
/// <param name="executeChildContentAsync">A delegate used to execute the child content asynchronously.</param>
/// <param name="startWritingScope">A delegate used to start a writing scope in a Razor page.</param>
/// <param name="endWritingScope">A delegate used to end a writing scope in a Razor page.</param>
/// <returns>A <see cref="TagHelperExecutionContext"/> to use.</returns>
public TagHelperExecutionContext Begin(string tagName)
public TagHelperExecutionContext Begin([NotNull] string tagName,
[NotNull] string uniqueId,
[NotNull] Func<Task> executeChildContentAsync,
[NotNull] Action startWritingScope,
[NotNull] Func<TextWriter> endWritingScope)
{
var executionContext = new TagHelperExecutionContext(tagName);
var executionContext = new TagHelperExecutionContext(tagName,
uniqueId,
executeChildContentAsync,
startWritingScope,
endWritingScope);
_executionScopes.Push(executionContext);

View File

@ -53,7 +53,7 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers
IEnumerable<TypeInfo> libraryTypes;
try
{
libraryTypes = GetLibraryDefinedTypes(assemblyName);
libraryTypes = GetExportedTypes(assemblyName);
}
catch (Exception ex)
{
@ -72,8 +72,14 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers
return validTagHelpers.Select(type => type.AsType());
}
// Internal for testing, don't want to be loading assemblies during a test.
internal virtual IEnumerable<TypeInfo> GetLibraryDefinedTypes(AssemblyName assemblyName)
/// <summary>
/// Returns all exported types from the given <paramref name="assemblyName"/>
/// </summary>
/// <param name="assemblyName">The <see cref="AssemblyName"/> to get <see cref="TypeInfo"/>s from.</param>
/// <returns>
/// An <see cref="IEnumerable{TypeInfo}"/> of types exported from the given <paramref name="assemblyName"/>.
/// </returns>
protected virtual IEnumerable<TypeInfo> GetExportedTypes(AssemblyName assemblyName)
{
var assembly = Assembly.Load(assemblyName);

View File

@ -9,7 +9,8 @@
"aspnet50": { },
"aspnetcore50": {
"dependencies": {
"System.Reflection.Extensions": "4.0.0-beta-*"
"System.Reflection.Extensions": "4.0.0-beta-*",
"System.Text.RegularExpressions": "4.0.10-beta-*"
}
}
}

View File

@ -1,6 +1,8 @@
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using Microsoft.AspNet.Razor.Parser;
namespace Microsoft.AspNet.Razor.Generator
{
/// <summary>
@ -12,9 +14,14 @@ namespace Microsoft.AspNet.Razor.Generator
/// Instantiates a new instance of the <see cref="CodeBuilderContext"/> object.
/// </summary>
/// <param name="generatorContext">A <see cref="CodeGeneratorContext"/> to copy information from.</param>
public CodeBuilderContext(CodeGeneratorContext generatorContext)
/// <param name="errorSink">
/// The <see cref="ParserErrorSink"/> used to collect <see cref="Parser.SyntaxTree.RazorError"/>s encountered
/// when parsing the current Razor document.
/// </param>
public CodeBuilderContext(CodeGeneratorContext generatorContext, ParserErrorSink errorSink)
: base(generatorContext)
{
ErrorSink = errorSink;
ExpressionRenderingMode = ExpressionRenderingMode.WriteToOutput;
}
@ -23,9 +30,11 @@ namespace Microsoft.AspNet.Razor.Generator
string className,
string rootNamespace,
string sourceFile,
bool shouldGenerateLinePragmas)
bool shouldGenerateLinePragmas,
ParserErrorSink errorSink)
: base(host, className, rootNamespace, sourceFile, shouldGenerateLinePragmas)
{
ErrorSink = errorSink;
ExpressionRenderingMode = ExpressionRenderingMode.WriteToOutput;
}
@ -56,5 +65,10 @@ namespace Microsoft.AspNet.Razor.Generator
/// <see cref="CodeGeneratorContext.SourceFile"/>.
/// </summary>
public string Checksum { get; set; }
/// <summary>
/// Used to aggregate <see cref="Parser.SyntaxTree.RazorError"/>s.
/// </summary>
public ParserErrorSink ErrorSink { get; }
}
}

View File

@ -43,8 +43,6 @@ namespace Microsoft.AspNet.Razor.Generator.Compiler.CSharp
// Separate the usings and the class
writer.WriteLine();
new CSharpClassAttributeVisitor(writer, Context).Accept(Tree.Chunks);
using (BuildClassDeclaration(writer))
{
if (Host.DesignTimeMode)

View File

@ -5,6 +5,7 @@ using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using Microsoft.AspNet.Razor.Parser.SyntaxTree;
using Microsoft.AspNet.Razor.TagHelpers;
namespace Microsoft.AspNet.Razor.Generator.Compiler.CSharp
@ -57,14 +58,7 @@ namespace Microsoft.AspNet.Razor.Generator.Compiler.CSharp
{
var tagHelperDescriptors = chunk.Descriptors;
// Find the first content behavior that doesn't have a content behavior of None.
// The resolver restricts content behavior collisions so the first one that's not None will be
// the content behavior we need to abide by. None can work in unison with other ContentBehaviors.
var contentBehavior = tagHelperDescriptors.Select(descriptor => descriptor.ContentBehavior)
.FirstOrDefault(
behavior => behavior != ContentBehavior.None);
RenderBeginTagHelperScope(chunk.TagName);
RenderBeginTagHelperScope(chunk.TagName, chunk.Children);
RenderTagHelpersCreation(chunk);
@ -77,42 +71,15 @@ namespace Microsoft.AspNet.Razor.Generator.Compiler.CSharp
RenderUnboundHTMLAttributes(unboundHTMLAttributes);
switch (contentBehavior)
{
case ContentBehavior.None:
RenderRunTagHelpers(bufferedBody: false);
RenderTagOutput(_tagHelperContext.OutputGenerateStartTagMethodName);
RenderTagHelperBody(chunk.Children, bufferBody: false);
RenderTagOutput(_tagHelperContext.OutputGenerateEndTagMethodName);
break;
case ContentBehavior.Append:
RenderRunTagHelpers(bufferedBody: false);
RenderTagOutput(_tagHelperContext.OutputGenerateStartTagMethodName);
RenderTagHelperBody(chunk.Children, bufferBody: false);
RenderTagOutput(_tagHelperContext.OutputGenerateContentMethodName);
RenderTagOutput(_tagHelperContext.OutputGenerateEndTagMethodName);
break;
case ContentBehavior.Prepend:
RenderRunTagHelpers(bufferedBody: false);
RenderTagOutput(_tagHelperContext.OutputGenerateStartTagMethodName);
RenderTagOutput(_tagHelperContext.OutputGenerateContentMethodName);
RenderTagHelperBody(chunk.Children, bufferBody: false);
RenderTagOutput(_tagHelperContext.OutputGenerateEndTagMethodName);
break;
case ContentBehavior.Replace:
RenderRunTagHelpers(bufferedBody: false);
RenderTagOutput(_tagHelperContext.OutputGenerateStartTagMethodName);
RenderTagOutput(_tagHelperContext.OutputGenerateContentMethodName);
RenderTagOutput(_tagHelperContext.OutputGenerateEndTagMethodName);
break;
case ContentBehavior.Modify:
RenderTagHelperBody(chunk.Children, bufferBody: true);
RenderRunTagHelpers(bufferedBody: true);
RenderTagOutput(_tagHelperContext.OutputGenerateStartTagMethodName);
RenderTagOutput(_tagHelperContext.OutputGenerateContentMethodName);
RenderTagOutput(_tagHelperContext.OutputGenerateEndTagMethodName);
break;
}
RenderRunTagHelpers();
RenderTagOutput(_tagHelperContext.OutputGenerateStartTagMethodName);
RenderTagOutput(_tagHelperContext.OutputGeneratePreContentMethodName);
RenderTagHelperContent();
RenderTagOutput(_tagHelperContext.OutputGeneratePostContentMethodName);
RenderTagOutput(_tagHelperContext.OutputGenerateEndTagMethodName);
RenderEndTagHelpersScope();
}
@ -122,11 +89,13 @@ namespace Microsoft.AspNet.Razor.Generator.Compiler.CSharp
return "__" + descriptor.TypeName.Replace('.', '_');
}
private void RenderBeginTagHelperScope(string tagName)
private void RenderBeginTagHelperScope(string tagName, IList<Chunk> children)
{
// Scopes/execution contexts are a runtime feature.
if (_designTimeMode)
{
// Render all of the tag helper children inline for IntelliSense.
_bodyVisitor.Accept(children);
return;
}
@ -135,10 +104,50 @@ namespace Microsoft.AspNet.Razor.Generator.Compiler.CSharp
_writer.WriteStartAssignment(ExecutionContextVariableName)
.WriteStartInstanceMethodInvocation(ScopeManagerVariableName,
_tagHelperContext.ScopeManagerBeginMethodName);
// Assign a unique ID for this instance of the source HTML tag. This must be unique
// per call site, e.g. if the tag is on the view twice, there should be two IDs.
_writer.WriteStringLiteral(tagName)
.WriteParameterSeparator()
.WriteStringLiteral(GenerateUniqueId())
.WriteParameterSeparator();
// We remove the target writer so TagHelper authors can retrieve content.
var oldWriter = _context.TargetWriterName;
_context.TargetWriterName = null;
// Disabling instrumentation inside TagHelper bodies since we never know if it's accurate
var oldInstrumentation = _context.Host.EnableInstrumentation;
_context.Host.EnableInstrumentation = false;
using (_writer.BuildAsyncLambda(endLine: false))
{
// Render all of the tag helper children.
_bodyVisitor.Accept(children);
}
_context.Host.EnableInstrumentation = oldInstrumentation;
_context.TargetWriterName = oldWriter;
_writer.WriteParameterSeparator()
.Write(_tagHelperContext.StartWritingScopeMethodName)
.WriteParameterSeparator()
.Write(_tagHelperContext.EndWritingScopeMethodName)
.WriteEndMethodInvocation();
}
/// <summary>
/// Generates a unique ID for an HTML element.
/// </summary>
/// <returns>
/// A globally unique ID.
/// </returns>
protected virtual string GenerateUniqueId()
{
return Guid.NewGuid().ToString("N");
}
private void RenderTagHelpersCreation(TagHelperChunk chunk)
{
var tagHelperDescriptors = chunk.Descriptors;
@ -213,48 +222,67 @@ namespace Microsoft.AspNet.Razor.Generator.Compiler.CSharp
tagHelperVariableName,
attributeDescriptor.PropertyName);
_writer.WriteStartAssignment(valueAccessor);
// If we haven't recorded this attribute value before then we need to record its value.
if (!attributeValueRecorded)
{
// We only need to create attribute values once per HTML element (not once per tag helper).
// We're saving the value accessor so we can retrieve it later if there are more tag helpers that
// need the value.
// We're saving the value accessor so we can retrieve it later if there are more tag
// helpers that need the value.
htmlAttributeValues.Add(attributeDescriptor.Name, valueAccessor);
if (bufferableAttribute)
{
// If the attribute is bufferable but has a plain text value that means the value
// is a string which needs to be surrounded in quotes.
_writer.WriteStartAssignment(valueAccessor);
if (isPlainTextValue)
{
// If the attribute is bufferable but has a plain text value that means the value
// is a string which needs to be surrounded in quotes.
RenderQuotedAttributeValue(textValue, attributeDescriptor);
}
else
{
// The value contains more than plain text. e.g. someAttribute="Time: @DateTime.Now"
// The value contains more than plain text e.g.
// stringAttribute ="Time: @DateTime.Now"
RenderBufferedAttributeValue(attributeDescriptor);
}
_writer.WriteLine(";");
}
else
{
// TODO: Make complex types in non-bufferable attributes work in
// https://github.com/aspnet/Razor/issues/129
if (!isPlainTextValue)
// Write out simple assignment for non-string property value. Try to keep the whole
// statement together and the #line pragma correct to make debugging possible.
using (var lineMapper = new CSharpLineMappingWriter(
_writer,
attributeValueChunk.Association.Start,
_context.SourceFile))
{
// Place the assignment LHS to align RHS with original attribute value's indentation.
// Unfortunately originalIndent is incorrect if original line contains tabs. Unable to
// use a CSharpPaddingBuilder because the Association has no Previous node; lost the
// original Span sequence when the parse tree was rewritten.
var originalIndent = attributeValueChunk.Start.CharacterIndex;
var generatedLength = valueAccessor.Length + " = ".Length;
var newIndent = originalIndent - generatedLength;
if (newIndent > 0)
{
_writer.Indent(newIndent);
}
_writer.WriteStartAssignment(valueAccessor);
lineMapper.MarkLineMappingStart();
// Write out bare expression for this attribute value. Property is not a string.
// So quoting or buffering are not helpful.
RenderRawAttributeValue(attributeValueChunk, attributeDescriptor, isPlainTextValue);
// End the assignment to the attribute.
lineMapper.MarkLineMappingEnd();
_writer.WriteLine(";");
return;
}
// We aren't a bufferable attribute which means we have no Razor code in our value.
// Therefore we can just use the "textValue" as the attribute value.
RenderRawAttributeValue(textValue, attributeDescriptor);
}
// End the assignment to the attribute.
_writer.WriteLine(";");
// Execution contexts are a runtime feature.
if (_designTimeMode)
{
@ -262,20 +290,23 @@ namespace Microsoft.AspNet.Razor.Generator.Compiler.CSharp
}
// We need to inform the context of the attribute value.
_writer.WriteStartInstanceMethodInvocation(
ExecutionContextVariableName,
_tagHelperContext.ExecutionContextAddTagHelperAttributeMethodName);
_writer.WriteStringLiteral(attributeDescriptor.Name)
.WriteParameterSeparator()
.Write(valueAccessor)
.WriteEndMethodInvocation();
_writer
.WriteStartInstanceMethodInvocation(
ExecutionContextVariableName,
_tagHelperContext.ExecutionContextAddTagHelperAttributeMethodName)
.WriteStringLiteral(attributeDescriptor.Name)
.WriteParameterSeparator()
.Write(valueAccessor)
.WriteEndMethodInvocation();
}
else
{
// The attribute value has already been recorded, lets retrieve it from the stored value accessors.
_writer.Write(htmlAttributeValues[attributeDescriptor.Name])
.WriteLine(";");
// The attribute value has already been recorded, lets retrieve it from the stored value
// accessors.
_writer
.WriteStartAssignment(valueAccessor)
.Write(htmlAttributeValues[attributeDescriptor.Name])
.WriteLine(";");
}
}
}
@ -323,18 +354,74 @@ namespace Microsoft.AspNet.Razor.Generator.Compiler.CSharp
}
}
private void RenderTagHelperBody(IList<Chunk> children, bool bufferBody)
private void RenderTagHelperContent()
{
// If we want to buffer the body we need to create a writing scope to capture the body content.
if (bufferBody)
// Rendering output is a runtime feature.
if (_designTimeMode)
{
// Render all of the tag helper children in a buffered writing scope.
BuildBufferedWritingScope(children);
return;
}
else
_writer.Write("if (")
.Write(ExecutionContextVariableName)
.Write(".")
.Write(_tagHelperContext.ExecutionContextOutputPropertyName)
.Write(".")
.Write(_tagHelperContext.OutputContentSetPropertyName)
.WriteLine(")");
// At this point in the codegen, TagHelperOutput.Content is set. We need to use this to render the Content
// instead of executing the child content
using (_writer.BuildScope())
{
// Render all of the tag helper children.
_bodyVisitor.Accept(children);
RenderTagOutput(_tagHelperContext.OutputGenerateContentMethodName);
}
_writer.Write("else if (")
.Write(ExecutionContextVariableName)
.Write(".")
.Write(_tagHelperContext.ExecutionContextChildContentRetrievedPropertyName)
.WriteLine(")");
// Render the body of the else if statement, at this point in the codegen the GetChildContentAsync method
// was invoked but the TagHelperOutput's Content was not set. Call into GetChildContentAsync to retrieve
// the cached value of the content so we don't execute the child content twice.
using (_writer.BuildScope())
{
CSharpCodeVisitor.RenderPreWriteStart(_writer, _context);
_writer.WriteInstanceMethodInvocation(ExecutionContextVariableName,
_tagHelperContext.ExecutionContextGetChildContentAsyncMethodName,
endLine: false);
_writer.Write(".Result")
.WriteEndMethodInvocation();
}
_writer.WriteLine("else");
// Render the body of the else statement, at this point in the codegen the GetChildContentAsync method
// was not invoked and the TagHelperOutput's Content was not set. Call into ExecuteChildContentAsync to
// to execute and render child content.
using (_writer.BuildScope())
{
if (!string.IsNullOrEmpty(_context.TargetWriterName))
{
_writer.WriteMethodInvocation(
_tagHelperContext.StartWritingScopeMethodName,
_context.TargetWriterName);
}
_writer.WriteInstanceMethodInvocation(
ExecutionContextVariableName,
_tagHelperContext.ExecutionContextExecuteChildContentAsyncMethodName,
endLine: false);
_writer.WriteLine(".Wait();");
if (!string.IsNullOrEmpty(_context.TargetWriterName))
{
_writer.WriteMethodInvocation(_tagHelperContext.EndWritingScopeMethodName);
}
}
}
@ -369,7 +456,7 @@ namespace Microsoft.AspNet.Razor.Generator.Compiler.CSharp
.WriteEndMethodInvocation();
}
private void RenderRunTagHelpers(bool bufferedBody)
private void RenderRunTagHelpers()
{
// No need to run anything in design time mode.
if (_designTimeMode)
@ -383,36 +470,38 @@ namespace Microsoft.AspNet.Razor.Generator.Compiler.CSharp
.Write(" = ")
.WriteStartInstanceMethodInvocation(RunnerVariableName,
_tagHelperContext.RunnerRunAsyncMethodName);
_writer.Write(ExecutionContextVariableName);
if (bufferedBody)
{
_writer.WriteParameterSeparator()
.Write(StringValueBufferVariableName);
}
_writer.WriteEndMethodInvocation(endLine: false)
_writer.Write(ExecutionContextVariableName)
.WriteEndMethodInvocation(endLine: false)
.WriteLine(".Result;");
}
private void RenderBufferedAttributeValue(TagHelperAttributeDescriptor attributeDescriptor)
{
// Pass complexValue: false because variable.ToString() replaces any original complexity in the expression.
RenderAttributeValue(
attributeDescriptor,
valueRenderer: (writer) =>
{
RenderBufferedAttributeValueAccessor(writer);
});
},
complexValue: false);
}
private void RenderRawAttributeValue(string value, TagHelperAttributeDescriptor attributeDescriptor)
private void RenderRawAttributeValue(
Chunk attributeValueChunk,
TagHelperAttributeDescriptor attributeDescriptor,
bool isPlainTextValue)
{
RenderAttributeValue(
attributeDescriptor,
valueRenderer: (writer) =>
{
writer.Write(value);
});
var visitor =
new CSharpTagHelperAttributeValueVisitor(writer, _context, attributeDescriptor.TypeName);
visitor.Accept(attributeValueChunk);
},
complexValue: !isPlainTextValue);
}
private void RenderQuotedAttributeValue(string value, TagHelperAttributeDescriptor attributeDescriptor)
@ -422,7 +511,8 @@ namespace Microsoft.AspNet.Razor.Generator.Compiler.CSharp
valueRenderer: (writer) =>
{
writer.WriteStringLiteral(value);
});
},
complexValue: false);
}
private void BuildBufferedWritingScope(Chunk htmlAttributeChunk)
@ -473,9 +563,15 @@ namespace Microsoft.AspNet.Razor.Generator.Compiler.CSharp
}
private void RenderAttributeValue(TagHelperAttributeDescriptor attributeDescriptor,
Action<CSharpCodeWriter> valueRenderer)
Action<CSharpCodeWriter> valueRenderer,
bool complexValue)
{
AttributeValueCodeRenderer.RenderAttributeValue(attributeDescriptor, _writer, _context, valueRenderer);
AttributeValueCodeRenderer.RenderAttributeValue(
attributeDescriptor,
_writer,
_context,
valueRenderer,
complexValue);
}
private void RenderBufferedAttributeValueAccessor(CSharpCodeWriter writer)

View File

@ -1,25 +0,0 @@
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using Microsoft.AspNet.Razor.Parser;
namespace Microsoft.AspNet.Razor.Generator.Compiler.CSharp
{
public class CSharpClassAttributeVisitor : CodeVisitor<CSharpCodeWriter>
{
public CSharpClassAttributeVisitor(CSharpCodeWriter writer, CodeBuilderContext context)
: base(writer, context)
{ }
protected override void Visit(SessionStateChunk chunk)
{
Writer.Write("[")
.Write(typeof(RazorDirectiveAttribute).FullName)
.Write("(")
.WriteStringLiteral(SyntaxConstants.CSharp.SessionStateKeyword)
.WriteParameterSeparator()
.WriteStringLiteral(chunk.Value)
.WriteLine(")]");
}
}
}

View File

@ -0,0 +1,179 @@
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using Microsoft.AspNet.Razor.Parser;
using Microsoft.AspNet.Razor.Parser.SyntaxTree;
namespace Microsoft.AspNet.Razor.Generator.Compiler.CSharp
{
/// <summary>
/// <see cref="CodeVisitor{CSharpCodeWriter}"/> that writes code for a non-<see langword="string"/> tag helper
/// bound attribute value.
/// </summary>
/// <remarks>
/// Since attribute value is not written out as HTML, does not emit instrumentation. Further this
/// <see cref="CodeVisitor{CSharpCodeWriter}"/> writes identical code at design- and runtime.
/// </remarks>
public class CSharpTagHelperAttributeValueVisitor : CodeVisitor<CSharpCodeWriter>
{
private string _attributeTypeName;
private bool _firstChild;
/// <summary>
/// Initializes a new instance of the <see cref="CSharpTagHelperAttributeValueVisitor"/> class.
/// </summary>
/// <param name="writer">The <see cref="CSharpCodeWriter"/> used to write code.</param>
/// <param name="context">
/// A <see cref="CodeBuilderContext"/> instance that contains information about the current code generation
/// process.
/// </param>
/// <param name="attributeTypeName">
/// Full name of the property <see cref="System.Type"/> for which this
/// <see cref="CSharpTagHelperAttributeValueVisitor"/> is writing the value.
/// </param>
public CSharpTagHelperAttributeValueVisitor(
CSharpCodeWriter writer,
CodeBuilderContext context,
string attributeTypeName)
: base(writer, context)
{
_attributeTypeName = attributeTypeName;
}
/// <summary>
/// Writes code for the given <paramref name="chunk"/>.
/// </summary>
/// <param name="chunk">The <see cref="ChunkBlock"/> to render.</param>
/// <remarks>
/// Tracks code mappings for all children while writing.
/// </remarks>
protected override void Visit(ChunkBlock chunk)
{
// Line mappings are captured in RenderCode(), not this method.
_firstChild = true;
Accept(chunk.Children);
if (_firstChild)
{
// Attribute value was empty.
Context.ErrorSink.OnError(
chunk.Association.Start,
RazorResources.TagHelpers_AttributeExpressionRequired,
chunk.Association.Length);
}
}
/// <summary>
/// Writes code for the given <paramref name="chunk"/>.
/// </summary>
/// <param name="chunk">The <see cref="ExpressionBlockChunk"/> to render.</param>
protected override void Visit(ExpressionBlockChunk chunk)
{
Accept(chunk.Children);
}
/// <summary>
/// Writes code for the given <paramref name="chunk"/>.
/// </summary>
/// <param name="chunk">The <see cref="ExpressionChunk"/> to render.</param>
protected override void Visit(ExpressionChunk chunk)
{
RenderCode(chunk.Code, (Span)chunk.Association);
}
/// <summary>
/// Writes code for the given <paramref name="chunk"/>.
/// </summary>
/// <param name="chunk">The <see cref="LiteralChunk"/> to render.</param>
protected override void Visit(LiteralChunk chunk)
{
RenderCode(chunk.Text, (Span)chunk.Association);
}
/// <summary>
/// Writes code for the given <paramref name="chunk"/>.
/// </summary>
/// <param name="chunk">The <see cref="ResolveUrlChunk"/> to render.</param>
/// <remarks>
/// Allowed to support future C# extensions. Likely "~/..." will lead to a C# compilation error but that is up
/// to the compiler.
/// </remarks>
protected override void Visit(ResolveUrlChunk chunk)
{
RenderCode(chunk.Url, (Span)chunk.Association);
}
/// <summary>
/// Writes code for the given <paramref name="chunk"/>.
/// </summary>
/// <param name="chunk">The <see cref="SectionChunk"/> to render.</param>
/// <remarks>
/// Unconditionally adds a <see cref="RazorError"/> to inform user of unexpected <c>@section</c> directive.
/// </remarks>
protected override void Visit(SectionChunk chunk)
{
Context.ErrorSink.OnError(
chunk.Association.Start,
RazorResources.FormatTagHelpers_Directives_NotSupported_InAttributes(
SyntaxConstants.CSharp.SectionKeyword),
chunk.Association.Length);
}
/// <summary>
/// Writes code for the given <paramref name="chunk"/>.
/// </summary>
/// <param name="chunk">The <see cref="SetLayoutChunk"/> to render.</param>
/// <remarks>
/// Unconditionally adds a <see cref="RazorError"/> to inform user of unexpected <c>@layout</c> directive.
/// </remarks>
protected override void Visit(SetLayoutChunk chunk)
{
Context.ErrorSink.OnError(
chunk.Association.Start,
RazorResources.FormatTagHelpers_Directives_NotSupported_InAttributes(
SyntaxConstants.CSharp.LayoutKeyword),
chunk.Association.Length);
}
/// <summary>
/// Writes code for the given <paramref name="chunk"/>.
/// </summary>
/// <param name="chunk">The <see cref="StatementChunk"/> to render.</param>
/// <remarks>
/// Unconditionally adds a <see cref="RazorError"/> to inform user of unexpected code block.
/// </remarks>
protected override void Visit(StatementChunk chunk)
{
Context.ErrorSink.OnError(
chunk.Association.Start,
RazorResources.TagHelpers_CodeBlocks_NotSupported_InAttributes,
chunk.Association.Length);
}
/// <summary>
/// Writes code for the given <paramref name="chunk"/>.
/// </summary>
/// <param name="chunk">The <see cref="TemplateChunk"/> to render.</param>
/// <remarks>
/// Unconditionally adds a <see cref="RazorError"/> to inform user of unexpected template e.g.
/// <c>@&lt;p&gt;paragraph@&lt;/p&gt;</c>.
/// </remarks>
protected override void Visit(TemplateChunk chunk)
{
Context.ErrorSink.OnError(
chunk.Association.Start,
RazorResources.FormatTagHelpers_InlineMarkupBlocks_NotSupported_InAttributes(_attributeTypeName),
chunk.Association.Length);
}
// Tracks the code mapping and writes code for a leaf node in the attribute value Chunk tree.
private void RenderCode(string code, Span association)
{
_firstChild = false;
using (new CSharpLineMappingWriter(Writer, association.Start, code.Length))
{
Writer.Write(code);
}
}
}
}

View File

@ -34,9 +34,13 @@ namespace Microsoft.AspNet.Razor.Generator.Compiler.CSharp
// Runtime fields aren't useful during design time.
if (!Context.Host.DesignTimeMode)
{
// Need to disable the warning "X is assigned to but never used." for the value buffer since
// whether it's used depends on how a TagHelper is used.
Writer.WritePragma("warning disable 0414");
WritePrivateField(typeof(TextWriter).FullName,
CSharpTagHelperCodeRenderer.StringValueBufferVariableName,
value: null);
Writer.WritePragma("warning restore 0414");
WritePrivateField(_tagHelperContext.ExecutionContextTypeName,
CSharpTagHelperCodeRenderer.ExecutionContextVariableName,

View File

@ -113,10 +113,6 @@ namespace Microsoft.AspNet.Razor.Generator.Compiler
{
Visit((ChunkBlock)chunk);
}
else if (chunk is SessionStateChunk)
{
Visit((SessionStateChunk)chunk);
}
}
protected abstract void Visit(LiteralChunk chunk);
@ -138,6 +134,5 @@ namespace Microsoft.AspNet.Razor.Generator.Compiler
protected abstract void Visit(TemplateChunk chunk);
protected abstract void Visit(SetLayoutChunk chunk);
protected abstract void Visit(ExpressionBlockChunk chunk);
protected abstract void Visit(SessionStateChunk chunk);
}
}

View File

@ -66,8 +66,5 @@ namespace Microsoft.AspNet.Razor.Generator.Compiler
protected override void Visit(SetLayoutChunk chunk)
{
}
protected override void Visit(SessionStateChunk chunk)
{
}
}
}

View File

@ -1,10 +0,0 @@
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
namespace Microsoft.AspNet.Razor.Generator.Compiler
{
public class SessionStateChunk : Chunk
{
public string Value { get; set; }
}
}

View File

@ -145,14 +145,6 @@ namespace Microsoft.AspNet.Razor.Generator.Compiler
}, association, topLevel: true);
}
public void AddSessionStateChunk(string value, SyntaxTreeNode association)
{
AddChunk(new SessionStateChunk
{
Value = value
}, association, topLevel: true);
}
public T StartChunkBlock<T>(SyntaxTreeNode association) where T : ChunkBlock, new()
{
return StartChunkBlock<T>(association, topLevel: false);

View File

@ -1,6 +1,8 @@
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System.Globalization;
namespace Microsoft.AspNet.Razor.Generator.Compiler
{
public class LineMapping
@ -40,5 +42,10 @@ namespace Microsoft.AspNet.Razor.Generator.Compiler
{
return !left.Equals(right);
}
public override string ToString()
{
return string.Format(CultureInfo.CurrentUICulture, "{0} -> {1}", DocumentLocation, GeneratedLocation);
}
}
}

View File

@ -1,6 +1,7 @@
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System.Globalization;
using Microsoft.AspNet.Razor.Text;
namespace Microsoft.AspNet.Razor.Generator.Compiler
@ -37,6 +38,16 @@ namespace Microsoft.AspNet.Razor.Generator.Compiler
return base.GetHashCode();
}
public override string ToString()
{
return string.Format(
CultureInfo.CurrentCulture, "({0}:{1},{2} [{3}])",
AbsoluteIndex,
LineIndex,
CharacterIndex,
ContentLength);
}
public static bool operator ==(MappingLocation left, MappingLocation right)
{
return left.Equals(right);

View File

@ -17,9 +17,15 @@ namespace Microsoft.AspNet.Razor.Generator
RunnerRunAsyncMethodName = "RunAsync";
ScopeManagerBeginMethodName = "Begin";
ScopeManagerEndMethodName = "End";
OutputContentSetPropertyName = "ContentSet";
OutputGenerateStartTagMethodName = "GenerateStartTag";
OutputGeneratePreContentMethodName = "GeneratePreContent";
OutputGenerateContentMethodName = "GenerateContent";
OutputGeneratePostContentMethodName = "GeneratePostContent";
OutputGenerateEndTagMethodName = "GenerateEndTag";
ExecutionContextChildContentRetrievedPropertyName = "ChildContentRetrieved";
ExecutionContextExecuteChildContentAsyncMethodName = "ExecuteChildContentAsync";
ExecutionContextGetChildContentAsyncMethodName = "GetChildContentAsync";
ExecutionContextAddMethodName = "Add";
ExecutionContextAddTagHelperAttributeMethodName = "AddTagHelperAttribute";
ExecutionContextAddHtmlAttributeMethodName = "AddHtmlAttribute";
@ -51,21 +57,52 @@ namespace Microsoft.AspNet.Razor.Generator
/// </summary>
public string ScopeManagerEndMethodName { get; set; }
/// <summary>
/// The name of the property used to determine if a tag helper output's content was set.
/// </summary>
public string OutputContentSetPropertyName { get; set; }
/// <summary>
/// The name of the method used to generate a tag helper output's start tag.
/// </summary>
public string OutputGenerateStartTagMethodName { get; set; }
/// <summary>
/// The name of the method used to generate a tag helper output's pre content.
/// </summary>
public string OutputGeneratePreContentMethodName { get; set; }
/// <summary>
/// The name of the method used to generate a tag helper output's content.
/// </summary>
public string OutputGenerateContentMethodName { get; set; }
/// <summary>
/// The name of the method used to generate a tag helper output's post-content.
/// </summary>
public string OutputGeneratePostContentMethodName { get; set; }
/// <summary>
/// The name of the method used to generate a tag helper output's end tag.
/// </summary>
public string OutputGenerateEndTagMethodName { get; set; }
/// <summary>
/// The name of the <see cref="ExecutionContextTypeName"/> method used to get a
/// <see cref="System.Threading.Tasks.Task"/> that executes tag helper child content.
/// </summary>
public string ExecutionContextChildContentRetrievedPropertyName { get; set; }
/// <summary>
/// </summary>
public string ExecutionContextExecuteChildContentAsyncMethodName { get; set; }
/// <summary>
/// The name of the <see cref="ExecutionContextTypeName"/> method used to execute and retrieve tag helper
/// child content.
/// </summary>
public string ExecutionContextGetChildContentAsyncMethodName { get; set; }
/// <summary>
/// The name of the <see cref="ExecutionContextTypeName"/> method used to add tag helper attributes.
/// </summary>

View File

@ -1,53 +0,0 @@
// Copyright (c) Microsoft Open Technologies, Inc. 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.AspNet.Razor.Parser;
using Microsoft.AspNet.Razor.Parser.SyntaxTree;
namespace Microsoft.AspNet.Razor.Generator
{
public class RazorDirectiveAttributeCodeGenerator : SpanCodeGenerator
{
public RazorDirectiveAttributeCodeGenerator(string name, string value)
{
if (String.IsNullOrEmpty(name))
{
throw new ArgumentException(CommonResources.Argument_Cannot_Be_Null_Or_Empty, "name");
}
Name = name;
Value = value ?? String.Empty; // Coerce to empty string if it was null.
}
public string Name { get; private set; }
public string Value { get; private set; }
public override void GenerateCode(Span target, CodeGeneratorContext context)
{
if (Name == SyntaxConstants.CSharp.SessionStateKeyword)
{
context.CodeTreeBuilder.AddSessionStateChunk(Value, target);
}
}
public override string ToString()
{
return "Directive: " + Name + ", Value: " + Value;
}
public override bool Equals(object obj)
{
var other = obj as RazorDirectiveAttributeCodeGenerator;
return other != null &&
Name.Equals(other.Name, StringComparison.OrdinalIgnoreCase) &&
Value.Equals(other.Value, StringComparison.OrdinalIgnoreCase);
}
public override int GetHashCode()
{
return Tuple.Create(Name.ToUpperInvariant(), Value.ToUpperInvariant())
.GetHashCode();
}
}
}

View File

@ -3,10 +3,12 @@
using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.AspNet.Razor.Generator.Compiler;
using Microsoft.AspNet.Razor.Parser.SyntaxTree;
using Microsoft.AspNet.Razor.Parser.TagHelpers;
using Microsoft.AspNet.Razor.TagHelpers;
using Microsoft.AspNet.Razor.Text;
namespace Microsoft.AspNet.Razor.Generator
{
@ -60,10 +62,13 @@ namespace Microsoft.AspNet.Razor.Generator
attribute.Value.Accept(codeGenerator);
var chunks = codeGenerator.Context.CodeTreeBuilder.CodeTree.Chunks;
var first = chunks.FirstOrDefault();
attributes[attribute.Key] = new ChunkBlock
{
Children = chunks
Association = first?.Association,
Children = chunks,
Start = first == null ? SourceLocation.Zero : first.Start
};
// Reset the code tree builder so we can build a new one for the next attribute

View File

@ -3,6 +3,7 @@
using System.Collections.Generic;
using Microsoft.AspNet.Razor.Generator.Compiler;
using Microsoft.AspNet.Razor.Parser;
using Microsoft.AspNet.Razor.Parser.SyntaxTree;
using Microsoft.AspNet.Razor.TagHelpers;
@ -24,7 +25,7 @@ namespace Microsoft.AspNet.Razor
[NotNull] CodeTree codeTree)
: this(parserResults.Document,
parserResults.TagHelperDescriptors,
parserResults.ParserErrors,
parserResults.ErrorSink,
codeBuilderResult,
codeTree)
{
@ -34,35 +35,21 @@ namespace Microsoft.AspNet.Razor
/// Instantiates a new <see cref="GeneratorResults"/> instance.
/// </summary>
/// <param name="document">The <see cref="Block"/> for the syntax tree.</param>
/// <param name="tagHelperDescriptors"><see cref="TagHelperDescriptor"/>s for the document.</param>
/// <param name="parserErrors"><see cref="RazorError"/>s encountered when parsing the document.</param>
/// <param name="tagHelperDescriptors">
/// The <see cref="TagHelperDescriptor"/>s that apply to the current Razor document.
/// </param>
/// <param name="errorSink">
/// The <see cref="ParserErrorSink"/> used to collect <see cref="RazorError"/>s encountered when parsing the
/// current Razor document.
/// </param>
/// <param name="codeBuilderResult">The results of generating code for the document.</param>
/// <param name="codeTree">A <see cref="CodeTree"/> for the document.</param>
public GeneratorResults([NotNull] Block document,
[NotNull] IEnumerable<TagHelperDescriptor> tagHelperDescriptors,
[NotNull] IList<RazorError> parserErrors,
[NotNull] ParserErrorSink errorSink,
[NotNull] CodeBuilderResult codeBuilderResult,
[NotNull] CodeTree codeTree)
: this(parserErrors.Count == 0, document, tagHelperDescriptors, parserErrors, codeBuilderResult, codeTree)
{
}
/// <summary>
/// Instantiates a new <see cref="GeneratorResults"/> instance.
/// </summary>
/// <param name="success"><c>true</c> if parsing was successful, <c>false</c> otherwise.</param>
/// <param name="document">The <see cref="Block"/> for the syntax tree.</param>
/// <param name="tagHelperDescriptors"><see cref="TagHelperDescriptor"/>s for the document.</param>
/// <param name="parserErrors"><see cref="RazorError"/>s encountered when parsing the document.</param>
/// <param name="codeBuilderResult">The results of generating code for the document.</param>
/// <param name="codeTree">A <see cref="CodeTree"/> for the document.</param>
protected GeneratorResults(bool success,
[NotNull] Block document,
[NotNull] IEnumerable<TagHelperDescriptor> tagHelperDescriptors,
[NotNull] IList<RazorError> parserErrors,
[NotNull] CodeBuilderResult codeBuilderResult,
[NotNull] CodeTree codeTree)
: base(success, document, tagHelperDescriptors, parserErrors)
: base(document, tagHelperDescriptors, errorSink)
{
GeneratedCode = codeBuilderResult.Code;
DesignTimeLineMappings = codeBuilderResult.DesignTimeLineMappings;

View File

@ -25,7 +25,6 @@ namespace Microsoft.AspNet.Razor.Parser
MapDirectives(SectionDirective, SyntaxConstants.CSharp.SectionKeyword);
MapDirectives(HelperDirective, SyntaxConstants.CSharp.HelperKeyword);
MapDirectives(LayoutDirective, SyntaxConstants.CSharp.LayoutKeyword);
MapDirectives(SessionStateDirective, SyntaxConstants.CSharp.SessionStateKeyword);
}
protected virtual void AddTagHelperDirective()
@ -58,65 +57,6 @@ namespace Microsoft.AspNet.Razor.Parser
Output(SpanKind.MetaCode, foundNewline ? AcceptedCharacters.None : AcceptedCharacters.Any);
}
protected virtual void SessionStateDirective()
{
AssertDirective(SyntaxConstants.CSharp.SessionStateKeyword);
AcceptAndMoveNext();
SessionStateDirectiveCore();
}
protected void SessionStateDirectiveCore()
{
SessionStateTypeDirective(RazorResources.ParserEror_SessionDirectiveMissingValue, (key, value) => new RazorDirectiveAttributeCodeGenerator(key, value));
}
protected void SessionStateTypeDirective(string noValueError, Func<string, string, SpanCodeGenerator> createCodeGenerator)
{
// Set the block type
Context.CurrentBlock.Type = BlockType.Directive;
// Accept whitespace
var remainingWs = AcceptSingleWhiteSpaceCharacter();
if (Span.Symbols.Count > 1)
{
Span.EditHandler.AcceptedCharacters = AcceptedCharacters.None;
}
Output(SpanKind.MetaCode);
if (remainingWs != null)
{
Accept(remainingWs);
}
AcceptWhile(IsSpacingToken(includeNewLines: false, includeComments: true));
// Parse a Type Name
if (!ValidSessionStateValue())
{
Context.OnError(CurrentLocation, noValueError);
}
// Pull out the type name
var sessionStateValue = String.Concat(
Span.Symbols
.Cast<CSharpSymbol>()
.Select(sym => sym.Content)).Trim();
// Set up code generation
Span.CodeGenerator = createCodeGenerator(SyntaxConstants.CSharp.SessionStateKeyword, sessionStateValue);
// Output the span and finish the block
CompleteBlock();
Output(SpanKind.Code);
}
protected virtual bool ValidSessionStateValue()
{
return Optional(CSharpSymbolType.Identifier);
}
[SuppressMessage("Microsoft.Maintainability", "CA1506:AvoidExcessiveClassCoupling", Justification = "Coupling will be reviewed at a later date")]
[SuppressMessage("Microsoft.Globalization", "CA1308:NormalizeStringsToUppercase", Justification = "C# Keywords are always lower-case")]
protected virtual void HelperDirective()

View File

@ -37,7 +37,6 @@ namespace Microsoft.AspNet.Razor.Parser
"namespace",
"class",
"layout",
"sessionstate"
};
private Dictionary<string, Action> _directiveParsers = new Dictionary<string, Action>();

View File

@ -230,7 +230,7 @@ namespace Microsoft.AspNet.Razor.Parser
// TagHelperDescriptors are not found by default. The RazorParser is responsible
// for identifying TagHelperDescriptors and rebuilding ParserResults.
tagHelperDescriptors: Enumerable.Empty<TagHelperDescriptor>(),
parserErrors: _errorSink.Errors.ToList());
errorSink: _errorSink);
}
[Conditional("DEBUG")]

View File

@ -197,7 +197,7 @@ namespace Microsoft.AspNet.Razor.Parser
}
// Return the new result
return new ParserResults(syntaxTree, descriptors, errorSink.Errors.ToList());
return new ParserResults(syntaxTree, descriptors, errorSink);
}
/// <summary>

View File

@ -28,7 +28,6 @@ namespace Microsoft.AspNet.Razor.Parser
public static readonly string NamespaceKeyword = "namespace";
public static readonly string ClassKeyword = "class";
public static readonly string LayoutKeyword = "layout";
public static readonly string SessionStateKeyword = "sessionstate";
}
}
}

View File

@ -6,6 +6,7 @@ using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using Microsoft.AspNet.Razor.Parser.SyntaxTree;
using Microsoft.AspNet.Razor.TagHelpers;
using Microsoft.AspNet.Razor.Text;
using Microsoft.Internal.Web.Utils;
@ -27,6 +28,7 @@ namespace Microsoft.AspNet.Razor.Parser.TagHelpers
: base(source.Type, source.Children, source.CodeGenerator)
{
TagName = source.TagName;
Descriptors = source.Descriptors;
Attributes = new Dictionary<string, SyntaxTreeNode>(source.Attributes);
_start = source.Start;
@ -38,6 +40,11 @@ namespace Microsoft.AspNet.Razor.Parser.TagHelpers
}
}
/// <summary>
/// <see cref="TagHelperDescriptor"/>s for the HTML element.
/// </summary>
public IEnumerable<TagHelperDescriptor> Descriptors { get; }
/// <summary>
/// The HTML attributes.
/// </summary>

View File

@ -1,14 +1,11 @@
// Copyright (c) Microsoft Open Technologies, Inc. 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.Linq;
using Microsoft.AspNet.Razor.Generator;
using Microsoft.AspNet.Razor.Parser.SyntaxTree;
using Microsoft.AspNet.Razor.TagHelpers;
using Microsoft.AspNet.Razor.Text;
using Microsoft.AspNet.Razor.Tokenizer.Symbols;
namespace Microsoft.AspNet.Razor.Parser.TagHelpers
{
@ -18,7 +15,7 @@ namespace Microsoft.AspNet.Razor.Parser.TagHelpers
public class TagHelperBlockBuilder : BlockBuilder
{
/// <summary>
/// Instantiates a new <see cref="TagHelperBlockBuilder"/> instance based on given the
/// Instantiates a new <see cref="TagHelperBlockBuilder"/> instance based on the given
/// <paramref name="original"/>.
/// </summary>
/// <param name="original">The original <see cref="TagHelperBlock"/> to copy data from.</param>
@ -26,6 +23,7 @@ namespace Microsoft.AspNet.Razor.Parser.TagHelpers
: base(original)
{
TagName = original.TagName;
Descriptors = original.Descriptors;
Attributes = new Dictionary<string, SyntaxTreeNode>(original.Attributes);
}
@ -35,19 +33,21 @@ namespace Microsoft.AspNet.Razor.Parser.TagHelpers
/// and <see cref="BlockBuilder.Type"/> from the <paramref name="startTag"/>.
/// </summary>
/// <param name="tagName">An HTML tag name.</param>
/// <param name="start">Starting location of the <see cref="TagHelperBlock"/>.</param>
/// <param name="attributes">Attributes of the <see cref="TagHelperBlock"/>.</param>
/// <param name="descriptors">The <see cref="TagHelperDescriptor"/>s associated with the current HTML
/// tag.</param>
/// <param name="startTag">The <see cref="Block"/> that contains all information about the start
/// of the HTML element.</param>
public TagHelperBlockBuilder(string tagName, IEnumerable<TagHelperDescriptor> descriptors, Block startTag)
public TagHelperBlockBuilder(string tagName,
SourceLocation start,
IDictionary<string, SyntaxTreeNode> attributes,
IEnumerable<TagHelperDescriptor> descriptors)
{
TagName = tagName;
Start = start;
Descriptors = descriptors;
Type = BlockType.Tag;
CodeGenerator = new TagHelperCodeGenerator(descriptors);
Type = startTag.Type;
Attributes = GetTagAttributes(startTag, descriptors);
// There will always be at least one child for the '<'.
Start = startTag.Children.First().Start;
Attributes = new Dictionary<string, SyntaxTreeNode>(attributes);
}
// Internal for testing
@ -67,6 +67,11 @@ namespace Microsoft.AspNet.Razor.Parser.TagHelpers
}
}
/// <summary>
/// <see cref="TagHelperDescriptor"/>s for the HTML element.
/// </summary>
public IEnumerable<TagHelperDescriptor> Descriptors { get; }
/// <summary>
/// The HTML attributes.
/// </summary>
@ -106,280 +111,5 @@ namespace Microsoft.AspNet.Razor.Parser.TagHelpers
/// The starting <see cref="SourceLocation"/> of the tag helper.
/// </summary>
public SourceLocation Start { get; private set; }
private static IDictionary<string, SyntaxTreeNode> GetTagAttributes(
Block tagBlock,
IEnumerable<TagHelperDescriptor> descriptors)
{
var attributes = new Dictionary<string, SyntaxTreeNode>(StringComparer.OrdinalIgnoreCase);
// Build a dictionary so we can easily lookup expected attribute value lookups
IReadOnlyDictionary<string, string> attributeValueTypes =
descriptors.SelectMany(descriptor => descriptor.Attributes)
.Distinct(TagHelperAttributeDescriptorComparer.Default)
.ToDictionary(descriptor => descriptor.Name,
descriptor => descriptor.TypeName,
StringComparer.OrdinalIgnoreCase);
// We skip the first child "<tagname" and take everything up to the "ending" portion of the tag ">" or "/>".
// The -2 accounts for both the start and end tags.
var attributeChildren = tagBlock.Children.Skip(1).Take(tagBlock.Children.Count() - 2);
foreach (var child in attributeChildren)
{
KeyValuePair<string, SyntaxTreeNode> attribute;
if (child.IsBlock)
{
attribute = ParseBlock((Block)child, attributeValueTypes);
}
else
{
attribute = ParseSpan((Span)child, attributeValueTypes);
}
attributes.Add(attribute.Key, attribute.Value);
}
return attributes;
}
// This method handles cases when the attribute is a simple span attribute such as
// class="something moresomething". This does not handle complex attributes such as
// class="@myclass". Therefore the span.Content is equivalent to the entire attribute.
private static KeyValuePair<string, SyntaxTreeNode> ParseSpan(
Span span,
IReadOnlyDictionary<string, string> attributeValueTypes)
{
var afterEquals = false;
var builder = new SpanBuilder
{
CodeGenerator = span.CodeGenerator,
EditHandler = span.EditHandler,
Kind = span.Kind
};
var htmlSymbols = span.Symbols.OfType<HtmlSymbol>().ToArray();
var symbolOffset = 1;
string name = null;
// Iterate down through the symbols to find the name and the start of the value.
// We subtract the symbolOffset so we don't accept an ending quote of a span.
for (var i = 0; i < htmlSymbols.Length - symbolOffset; i++)
{
var symbol = htmlSymbols[i];
if (name == null && symbol.Type == HtmlSymbolType.Text)
{
name = symbol.Content;
}
else if (afterEquals)
{
builder.Accept(symbol);
}
else if (symbol.Type == HtmlSymbolType.Equals)
{
// We've found an '=' symbol, this means that the coming symbols will either be a quote
// or value (in the case that the value is unquoted).
// Spaces after/before the equal symbol are not yet supported:
// https://github.com/aspnet/Razor/issues/123
// TODO: Handle malformed tags, if there's an '=' then there MUST be a value.
// https://github.com/aspnet/Razor/issues/104
// Check for attribute start values, aka single or double quote
if (IsQuote(htmlSymbols[i + 1]))
{
// Move past the attribute start so we can accept the true value.
i++;
}
else
{
// Set the symbol offset to 0 so we don't attempt to skip an end quote that doesn't exist.
symbolOffset = 0;
}
afterEquals = true;
}
}
return CreateMarkupAttribute(name, builder, attributeValueTypes);
}
private static KeyValuePair<string, SyntaxTreeNode> ParseBlock(
Block block,
IReadOnlyDictionary<string, string> attributeValueTypes)
{
// TODO: Accept more than just spans: https://github.com/aspnet/Razor/issues/96.
// The first child will only ever NOT be a Span if a user is doing something like:
// <input @checked />
var childSpan = block.Children.First() as Span;
if (childSpan == null)
{
throw new InvalidOperationException(RazorResources.TagHelpers_CannotHaveCSharpInTagDeclaration);
}
var builder = new BlockBuilder(block);
// If there's only 1 child it means that it's plain text inside of the attribute.
// i.e. <div class="plain text in attribute">
if (builder.Children.Count == 1)
{
return ParseSpan(childSpan, attributeValueTypes);
}
var textSymbol = childSpan.Symbols.FirstHtmlSymbolAs(HtmlSymbolType.Text);
var name = textSymbol != null ? textSymbol.Content : null;
if (name == null)
{
throw new InvalidOperationException(RazorResources.TagHelpers_AttributesMustHaveAName);
}
// Remove first child i.e. foo="
builder.Children.RemoveAt(0);
// Grabbing last child to check if the attribute value is quoted.
var endNode = block.Children.Last();
if (!endNode.IsBlock)
{
var endSpan = (Span)endNode;
var endSymbol = (HtmlSymbol)endSpan.Symbols.Last();
// Checking to see if it's a quoted attribute, if so we should remove end quote
if (IsQuote(endSymbol))
{
builder.Children.RemoveAt(builder.Children.Count - 1);
}
}
// We need to rebuild the code generators of the builder and its children (this is needed to
// ensure we don't do special attribute code generation since this is a tag helper).
block = RebuildCodeGenerators(builder.Build());
// If there's only 1 child at this point its value could be a simple markup span (treated differently than
// block level elements for attributes).
if (block.Children.Count() == 1)
{
var child = block.Children.First() as Span;
if (child != null)
{
// After pulling apart the block we just have a value span.
var spanBuilder = new SpanBuilder(child);
return CreateMarkupAttribute(name, spanBuilder, attributeValueTypes);
}
}
return new KeyValuePair<string, SyntaxTreeNode>(name, block);
}
private static Block RebuildCodeGenerators(Block block)
{
var builder = new BlockBuilder(block);
var isDynamic = builder.CodeGenerator is DynamicAttributeBlockCodeGenerator;
// We don't want any attribute specific logic here, null out the block code generator.
if (isDynamic || builder.CodeGenerator is AttributeBlockCodeGenerator)
{
builder.CodeGenerator = BlockCodeGenerator.Null;
}
for (var i = 0; i < builder.Children.Count; i++)
{
var child = builder.Children[i];
if (child.IsBlock)
{
// The child is a block, recurse down into the block to rebuild its children
builder.Children[i] = RebuildCodeGenerators((Block)child);
}
else
{
var childSpan = (Span)child;
ISpanCodeGenerator newCodeGenerator = null;
var literalGenerator = childSpan.CodeGenerator as LiteralAttributeCodeGenerator;
if (literalGenerator != null)
{
if (literalGenerator.ValueGenerator == null || literalGenerator.ValueGenerator.Value == null)
{
newCodeGenerator = new MarkupCodeGenerator();
}
else
{
newCodeGenerator = literalGenerator.ValueGenerator.Value;
}
}
else if (isDynamic && childSpan.CodeGenerator == SpanCodeGenerator.Null)
{
// Usually the dynamic code generator handles rendering the null code generators underneath
// it. This doesn't make sense in terms of tag helpers though, we need to change null code
// generators to markup code generators.
newCodeGenerator = new MarkupCodeGenerator();
}
// If we have a new code generator we'll need to re-build the child
if (newCodeGenerator != null)
{
var childSpanBuilder = new SpanBuilder(childSpan)
{
CodeGenerator = newCodeGenerator
};
builder.Children[i] = childSpanBuilder.Build();
}
}
}
return builder.Build();
}
private static KeyValuePair<string, SyntaxTreeNode> CreateMarkupAttribute(
string name,
SpanBuilder builder,
IReadOnlyDictionary<string, string> attributeValueTypes)
{
string attributeTypeName;
// If the attribute was requested by the tag helper and doesn't happen to be a string then we need to treat
// its value as code. Any non-string value can be any C# value so we need to ensure the SyntaxTreeNode
// reflects that.
if (attributeValueTypes.TryGetValue(name, out attributeTypeName) &&
!string.Equals(attributeTypeName, typeof(string).FullName, StringComparison.OrdinalIgnoreCase))
{
builder.Kind = SpanKind.Code;
}
return new KeyValuePair<string, SyntaxTreeNode>(name, builder.Build());
}
private static bool IsQuote(HtmlSymbol htmlSymbol)
{
return htmlSymbol.Type == HtmlSymbolType.DoubleQuote ||
htmlSymbol.Type == HtmlSymbolType.SingleQuote;
}
// This class is used to compare tag helper attributes by comparing only the HTML attribute name.
private class TagHelperAttributeDescriptorComparer : IEqualityComparer<TagHelperAttributeDescriptor>
{
public static readonly TagHelperAttributeDescriptorComparer Default =
new TagHelperAttributeDescriptorComparer();
public bool Equals(TagHelperAttributeDescriptor descriptorX, TagHelperAttributeDescriptor descriptorY)
{
return string.Equals(descriptorX.Name, descriptorY.Name, StringComparison.OrdinalIgnoreCase);
}
public int GetHashCode(TagHelperAttributeDescriptor descriptor)
{
return StringComparer.OrdinalIgnoreCase.GetHashCode(descriptor.Name);
}
}
}
}

View File

@ -0,0 +1,375 @@
// Copyright (c) Microsoft Open Technologies, Inc. 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.Linq;
using Microsoft.AspNet.Razor.Generator;
using Microsoft.AspNet.Razor.Parser.SyntaxTree;
using Microsoft.AspNet.Razor.TagHelpers;
using Microsoft.AspNet.Razor.Text;
using Microsoft.AspNet.Razor.Tokenizer.Symbols;
namespace Microsoft.AspNet.Razor.Parser.TagHelpers.Internal
{
public static class TagHelperBlockRewriter
{
public static TagHelperBlockBuilder Rewrite(string tagName,
bool validStructure,
Block tag,
IEnumerable<TagHelperDescriptor> descriptors,
ParserErrorSink errorSink)
{
// There will always be at least one child for the '<'.
var start = tag.Children.First().Start;
var attributes = GetTagAttributes(tagName, validStructure, tag, descriptors, errorSink);
return new TagHelperBlockBuilder(tagName, start, attributes, descriptors);
}
private static IDictionary<string, SyntaxTreeNode> GetTagAttributes(
string tagName,
bool validStructure,
Block tagBlock,
IEnumerable<TagHelperDescriptor> descriptors,
ParserErrorSink errorSink)
{
var attributes = new Dictionary<string, SyntaxTreeNode>(StringComparer.OrdinalIgnoreCase);
// Build a dictionary so we can easily lookup expected attribute value lookups
IReadOnlyDictionary<string, string> attributeValueTypes =
descriptors.SelectMany(descriptor => descriptor.Attributes)
.Distinct(TagHelperAttributeDescriptorComparer.Default)
.ToDictionary(descriptor => descriptor.Name,
descriptor => descriptor.TypeName,
StringComparer.OrdinalIgnoreCase);
// We skip the first child "<tagname" and take everything up to the ending portion of the tag ">" or "/>".
// The -2 accounts for both the start and end tags. If the tag does not have a valid structure then there's
// no end tag to ignore.
var symbolOffset = validStructure ? 2 : 1;
var attributeChildren = tagBlock.Children.Skip(1).Take(tagBlock.Children.Count() - symbolOffset);
foreach (var child in attributeChildren)
{
KeyValuePair<string, SyntaxTreeNode> attribute;
bool succeeded = true;
if (child.IsBlock)
{
succeeded = TryParseBlock(tagName, (Block)child, attributeValueTypes, errorSink, out attribute);
}
else
{
succeeded = TryParseSpan((Span)child, attributeValueTypes, errorSink, out attribute);
}
// Only want to track the attribute if we succeeded in parsing its corresponding Block/Span.
if (succeeded)
{
attributes[attribute.Key] = attribute.Value;
}
}
return attributes;
}
// This method handles cases when the attribute is a simple span attribute such as
// class="something moresomething". This does not handle complex attributes such as
// class="@myclass". Therefore the span.Content is equivalent to the entire attribute.
private static bool TryParseSpan(
Span span,
IReadOnlyDictionary<string, string> attributeValueTypes,
ParserErrorSink errorSink,
out KeyValuePair<string, SyntaxTreeNode> attribute)
{
var afterEquals = false;
var builder = new SpanBuilder
{
CodeGenerator = span.CodeGenerator,
EditHandler = span.EditHandler,
Kind = span.Kind
};
var htmlSymbols = span.Symbols.OfType<HtmlSymbol>().ToArray();
var capturedAttributeValueStart = false;
var attributeValueStartLocation = span.Start;
var symbolOffset = 1;
string name = null;
// Iterate down through the symbols to find the name and the start of the value.
// We subtract the symbolOffset so we don't accept an ending quote of a span.
for (var i = 0; i < htmlSymbols.Length - symbolOffset; i++)
{
var symbol = htmlSymbols[i];
if (afterEquals)
{
// When symbols are accepted into SpanBuilders, their locations get altered to be offset by the
// parent which is why we need to mark our start location prior to adding the symbol.
// This is needed to know the location of the attribute value start within the document.
if (!capturedAttributeValueStart)
{
capturedAttributeValueStart = true;
attributeValueStartLocation = span.Start + symbol.Start;
}
builder.Accept(symbol);
}
else if (name == null && symbol.Type == HtmlSymbolType.Text)
{
name = symbol.Content;
attributeValueStartLocation = SourceLocation.Advance(span.Start, name);
}
else if (symbol.Type == HtmlSymbolType.Equals)
{
// We've found an '=' symbol, this means that the coming symbols will either be a quote
// or value (in the case that the value is unquoted).
// Spaces after/before the equal symbol are not yet supported:
// https://github.com/aspnet/Razor/issues/123
// TODO: Handle malformed tags, if there's an '=' then there MUST be a value.
// https://github.com/aspnet/Razor/issues/104
SourceLocation symbolStartLocation;
// Check for attribute start values, aka single or double quote
if (IsQuote(htmlSymbols[i + 1]))
{
// Move past the attribute start so we can accept the true value.
i++;
symbolStartLocation = htmlSymbols[i + 1].Start;
}
else
{
symbolStartLocation = symbol.Start;
// Set the symbol offset to 0 so we don't attempt to skip an end quote that doesn't exist.
symbolOffset = 0;
}
attributeValueStartLocation = symbolStartLocation +
span.Start +
new SourceLocation(absoluteIndex: 1,
lineIndex: 0,
characterIndex: 1);
afterEquals = true;
}
}
// After all symbols have been added we need to set the builders start position so we do not indirectly
// modify each symbol's Start location.
builder.Start = attributeValueStartLocation;
if (name == null)
{
errorSink.OnError(span.Start,
RazorResources.TagHelperBlockRewriter_TagHelperAttributesMustBeWelformed,
span.Content.Length);
attribute = default(KeyValuePair<string, SyntaxTreeNode>);
return false;
}
attribute = CreateMarkupAttribute(name, builder, attributeValueTypes);
return true;
}
private static bool TryParseBlock(
string tagName,
Block block,
IReadOnlyDictionary<string, string> attributeValueTypes,
ParserErrorSink errorSink,
out KeyValuePair<string, SyntaxTreeNode> attribute)
{
// TODO: Accept more than just spans: https://github.com/aspnet/Razor/issues/96.
// The first child will only ever NOT be a Span if a user is doing something like:
// <input @checked />
var childSpan = block.Children.First() as Span;
if (childSpan == null || childSpan.Kind != SpanKind.Markup)
{
errorSink.OnError(block.Children.First().Start,
RazorResources.FormatTagHelpers_CannotHaveCSharpInTagDeclaration(tagName));
attribute = default(KeyValuePair<string, SyntaxTreeNode>);
return false;
}
var builder = new BlockBuilder(block);
// If there's only 1 child it means that it's plain text inside of the attribute.
// i.e. <div class="plain text in attribute">
if (builder.Children.Count == 1)
{
return TryParseSpan(childSpan, attributeValueTypes, errorSink, out attribute);
}
var textSymbol = childSpan.Symbols.FirstHtmlSymbolAs(HtmlSymbolType.Text);
var name = textSymbol != null ? textSymbol.Content : null;
if (name == null)
{
errorSink.OnError(childSpan.Start, RazorResources.FormatTagHelpers_AttributesMustHaveAName(tagName));
attribute = default(KeyValuePair<string, SyntaxTreeNode>);
return false;
}
// TODO: Support no attribute values: https://github.com/aspnet/Razor/issues/220
// Remove first child i.e. foo="
builder.Children.RemoveAt(0);
// Grabbing last child to check if the attribute value is quoted.
var endNode = block.Children.Last();
if (!endNode.IsBlock)
{
var endSpan = (Span)endNode;
var endSymbol = (HtmlSymbol)endSpan.Symbols.Last();
// Checking to see if it's a quoted attribute, if so we should remove end quote
if (IsQuote(endSymbol))
{
builder.Children.RemoveAt(builder.Children.Count - 1);
}
}
// We need to rebuild the code generators of the builder and its children (this is needed to
// ensure we don't do special attribute code generation since this is a tag helper).
block = RebuildCodeGenerators(builder.Build());
// If there's only 1 child at this point its value could be a simple markup span (treated differently than
// block level elements for attributes).
if (block.Children.Count() == 1)
{
var child = block.Children.First() as Span;
if (child != null)
{
// After pulling apart the block we just have a value span.
var spanBuilder = new SpanBuilder(child);
attribute = CreateMarkupAttribute(name, spanBuilder, attributeValueTypes);
return true;
}
}
attribute = new KeyValuePair<string, SyntaxTreeNode>(name, block);
return true;
}
private static Block RebuildCodeGenerators(Block block)
{
var builder = new BlockBuilder(block);
var isDynamic = builder.CodeGenerator is DynamicAttributeBlockCodeGenerator;
// We don't want any attribute specific logic here, null out the block code generator.
if (isDynamic || builder.CodeGenerator is AttributeBlockCodeGenerator)
{
builder.CodeGenerator = BlockCodeGenerator.Null;
}
for (var i = 0; i < builder.Children.Count; i++)
{
var child = builder.Children[i];
if (child.IsBlock)
{
// The child is a block, recurse down into the block to rebuild its children
builder.Children[i] = RebuildCodeGenerators((Block)child);
}
else
{
var childSpan = (Span)child;
ISpanCodeGenerator newCodeGenerator = null;
var literalGenerator = childSpan.CodeGenerator as LiteralAttributeCodeGenerator;
if (literalGenerator != null)
{
if (literalGenerator.ValueGenerator == null || literalGenerator.ValueGenerator.Value == null)
{
newCodeGenerator = new MarkupCodeGenerator();
}
else
{
newCodeGenerator = literalGenerator.ValueGenerator.Value;
}
}
else if (isDynamic && childSpan.CodeGenerator == SpanCodeGenerator.Null)
{
// Usually the dynamic code generator handles rendering the null code generators underneath
// it. This doesn't make sense in terms of tag helpers though, we need to change null code
// generators to markup code generators.
newCodeGenerator = new MarkupCodeGenerator();
}
// If we have a new code generator we'll need to re-build the child
if (newCodeGenerator != null)
{
var childSpanBuilder = new SpanBuilder(childSpan)
{
CodeGenerator = newCodeGenerator
};
builder.Children[i] = childSpanBuilder.Build();
}
}
}
return builder.Build();
}
private static KeyValuePair<string, SyntaxTreeNode> CreateMarkupAttribute(
string name,
SpanBuilder builder,
IReadOnlyDictionary<string, string> attributeValueTypes)
{
string attributeTypeName;
// If the attribute was requested by the tag helper and doesn't happen to be a string then we need to treat
// its value as code. Any non-string value can be any C# value so we need to ensure the SyntaxTreeNode
// reflects that.
if (attributeValueTypes.TryGetValue(name, out attributeTypeName) &&
!string.Equals(attributeTypeName, typeof(string).FullName, StringComparison.OrdinalIgnoreCase))
{
builder.Kind = SpanKind.Code;
}
return new KeyValuePair<string, SyntaxTreeNode>(name, builder.Build());
}
private static bool IsQuote(HtmlSymbol htmlSymbol)
{
return htmlSymbol.Type == HtmlSymbolType.DoubleQuote ||
htmlSymbol.Type == HtmlSymbolType.SingleQuote;
}
// This class is used to compare tag helper attributes by comparing only the HTML attribute name.
private class TagHelperAttributeDescriptorComparer : IEqualityComparer<TagHelperAttributeDescriptor>
{
public static readonly TagHelperAttributeDescriptorComparer Default =
new TagHelperAttributeDescriptorComparer();
public bool Equals(TagHelperAttributeDescriptor descriptorX, TagHelperAttributeDescriptor descriptorY)
{
return string.Equals(descriptorX.Name, descriptorY.Name, StringComparison.OrdinalIgnoreCase);
}
public int GetHashCode(TagHelperAttributeDescriptor descriptor)
{
return StringComparer.OrdinalIgnoreCase.GetHashCode(descriptor.Name);
}
}
}
}

View File

@ -27,14 +27,12 @@ namespace Microsoft.AspNet.Razor.Parser.TagHelpers.Internal
public void Rewrite(RewritingContext context)
{
RewriteTags(context.SyntaxTree);
ValidateRewrittenSyntaxTree(context);
RewriteTags(context.SyntaxTree, context);
context.SyntaxTree = _currentBlock.Build();
}
private void RewriteTags(Block input)
private void RewriteTags(Block input, RewritingContext context)
{
// We want to start a new block without the children from existing (we rebuild them).
TrackBlock(new BlockBuilder
@ -43,6 +41,8 @@ namespace Microsoft.AspNet.Razor.Parser.TagHelpers.Internal
CodeGenerator = input.CodeGenerator
});
var activeTagHelpers = _tagStack.Count;
foreach (var child in input.Children)
{
if (child.IsBlock)
@ -51,65 +51,18 @@ namespace Microsoft.AspNet.Razor.Parser.TagHelpers.Internal
if (childBlock.Type == BlockType.Tag)
{
// TODO: Fully handle malformed tags: https://github.com/aspnet/Razor/issues/104
// Get tag name of the current block (doesn't matter if it's an end or start tag)
var tagName = GetTagName(childBlock);
// Could not determine tag name, it can't be a TagHelper, continue on and track the element.
if (tagName == null)
if (TryRewriteTagHelper(childBlock, context))
{
_currentBlock.Children.Add(child);
continue;
}
if (!IsEndTag(childBlock))
{
// We're in a begin tag block
if (IsPotentialTagHelper(tagName, childBlock))
{
var descriptors = _provider.GetTagHelpers(tagName);
// We could be a tag helper, but only if we have descriptors registered
if (descriptors.Any())
{
// Found a new tag helper block
TrackTagHelperBlock(new TagHelperBlockBuilder(tagName, descriptors, childBlock));
// If it's a self closing block then we don't have to worry about nested children
// within the tag... complete it.
if (IsSelfClosing(childBlock))
{
BuildCurrentlyTrackedTagHelperBlock();
}
continue;
}
}
}
else
{
var currentTagHelper = _tagStack.Count > 0 ? _tagStack.Peek() : null;
// Check if it's an "end" tag helper that matches our current tag helper
if (currentTagHelper != null &&
string.Equals(currentTagHelper.TagName, tagName, StringComparison.OrdinalIgnoreCase))
{
BuildCurrentlyTrackedTagHelperBlock();
continue;
}
// We're in an end tag, there won't be anymore tag helpers nested.
}
// If we get to here it means that we're a normal html tag. No need to iterate
// any deeper into the children of it because they wont be tag helpers.
// If we get to here it means that we're a normal html tag. No need to iterate any deeper into
// the children of it because they wont be tag helpers.
}
else
{
// We're not an Html tag so iterate through children recursively.
RewriteTags(childBlock);
RewriteTags(childBlock, context);
continue;
}
}
@ -117,42 +70,141 @@ namespace Microsoft.AspNet.Razor.Parser.TagHelpers.Internal
// At this point the child is a Span or Block with Type BlockType.Tag that doesn't happen to be a
// tag helper.
// Add the child to current block.
// Add the child to current block.
_currentBlock.Children.Add(child);
}
// We captured the number of active tag helpers at the start of our logic, it should be the same. If not
// it means that there are malformed tag helpers at the top of our stack.
if (activeTagHelpers != _tagStack.Count)
{
// Malformed tag helpers built here will be tag helpers that do not have end tags in the current block
// scope. Block scopes are special cases in Razor such as @<p> would cause an error because there's no
// matching end </p> tag in the template block scope and therefore doesn't make sense as a tag helper.
BuildMalformedTagHelpers(_tagStack.Count - activeTagHelpers, context);
Debug.Assert(activeTagHelpers == _tagStack.Count);
}
BuildCurrentlyTrackedBlock();
}
private void ValidateRewrittenSyntaxTree(RewritingContext context)
private bool TryRewriteTagHelper(Block tagBlock, RewritingContext context)
{
// If the blockStack still has elements in it that means there's at least one malformed TagHelper block in
// the document, that's the only way we can have a non-zero _blockStack.Count.
if (_blockStack.Count != 0)
// TODO: Fully handle malformed tags: https://github.com/aspnet/Razor/issues/104
// Get tag name of the current block (doesn't matter if it's an end or start tag)
var tagName = GetTagName(tagBlock);
// Could not determine tag name, it can't be a TagHelper, continue on and track the element.
if (tagName == null)
{
// We reverse the children so we can search from the back to the front for the TagHelper that is
// malformed.
var candidateChildren = _currentBlock.Children.Reverse();
var malformedTagHelper = candidateChildren.OfType<TagHelperBlock>().FirstOrDefault();
return false;
}
// If the malformed tag helper is null that means something other than a TagHelper caused the
// unbalancing of the syntax tree (should never happen).
Debug.Assert(malformedTagHelper != null);
var descriptors = Enumerable.Empty<TagHelperDescriptor>();
// We only create a single error because we can't reasonably determine other invalid tag helpers in the
// document; having one malformed tag helper puts the document into an invalid state.
context.ErrorSink.OnError(
malformedTagHelper.Start,
RazorResources.FormatTagHelpersParseTreeRewriter_FoundMalformedTagHelper(
malformedTagHelper.TagName));
if (IsPotentialTagHelper(tagName, tagBlock))
{
descriptors = _provider.GetTagHelpers(tagName);
}
// We need to build the remaining blocks in the stack to ensure we don't return an invalid syntax tree.
do
// If there aren't any TagHelperDescriptors registered then we aren't a TagHelper
if (!descriptors.Any())
{
return false;
}
if (!IsEndTag(tagBlock))
{
// We're in a begin tag helper block
var validTagStructure = ValidTagStructure(tagName, tagBlock, context);
var builder = TagHelperBlockRewriter.Rewrite(tagName,
validTagStructure,
tagBlock,
descriptors,
context.ErrorSink);
// Found a new tag helper block
TrackTagHelperBlock(builder);
// If it's a self closing block then we don't have to worry about nested children
// within the tag... complete it.
if (IsSelfClosing(tagBlock))
{
BuildCurrentlyTrackedTagHelperBlock();
}
while (_blockStack.Count != 0);
}
else
{
// We're in an end tag helper block.
var tagNameScope = _tagStack.Count > 0 ? _tagStack.Peek().TagName : string.Empty;
// Validate that our end tag helper matches the currently scoped tag helper, if not we
// need to error.
if (tagNameScope.Equals(tagName, StringComparison.OrdinalIgnoreCase))
{
ValidTagStructure(tagName, tagBlock, context);
BuildCurrentlyTrackedTagHelperBlock();
}
else
{
// Current tag helper scope does not match the end tag. Attempt to recover the tag
// helper by looking up the previous tag helper scopes for a matching tag. If we
// can't recover it means there was no corresponding tag helper begin tag.
if (TryRecoverTagHelper(tagName, context))
{
ValidTagStructure(tagName, tagBlock, context);
// Successfully recovered, move onto the next element.
}
else
{
// Could not recover, the end tag helper has no corresponding begin tag, create
// an error based on the current childBlock.
context.ErrorSink.OnError(
tagBlock.Start,
RazorResources.FormatTagHelpersParseTreeRewriter_FoundMalformedTagHelper(tagName));
return false;
}
}
}
return true;
}
private static bool ValidTagStructure(string tagName, Block tag, RewritingContext context)
{
// We assume an invalid structure until we verify that the tag meets all of our "valid structure" criteria.
var invalidStructure = true;
// No need to validate the tag end because in order to be a tag block it must start with '<'.
var tagEnd = tag.Children.Last() as Span;
// If our tag end is not a markup span it means it's some sort of code SyntaxTreeNode (not a valid format)
if (tagEnd != null && tagEnd.Kind == SpanKind.Markup)
{
var endSymbol = tagEnd.Symbols.LastOrDefault() as HtmlSymbol;
if (endSymbol != null && endSymbol.Type == HtmlSymbolType.CloseAngle)
{
invalidStructure = false;
}
}
if (invalidStructure)
{
context.ErrorSink.OnError(
tag.Start,
RazorResources.FormatTagHelpersParseTreeRewriter_MissingCloseAngle(tagName));
}
return !invalidStructure;
}
private void BuildCurrentlyTrackedBlock()
@ -216,6 +268,52 @@ namespace Microsoft.AspNet.Razor.Parser.TagHelpers.Internal
TrackBlock(builder);
}
private bool TryRecoverTagHelper(string tagName, RewritingContext context)
{
var malformedTagHelperCount = 0;
foreach (var tag in _tagStack)
{
if (tag.TagName.Equals(tagName, StringComparison.OrdinalIgnoreCase))
{
break;
}
malformedTagHelperCount++;
}
// If the malformedTagHelperCount == _tagStack.Count it means we couldn't find a begin tag for the tag
// helper, can't recover.
if (malformedTagHelperCount != _tagStack.Count)
{
BuildMalformedTagHelpers(malformedTagHelperCount, context);
// One final build, this is the build that completes our target tag helper block which is not malformed.
BuildCurrentlyTrackedTagHelperBlock();
// We were able to recover
return true;
}
// Could not recover tag helper. Aka we found a tag helper end tag without a corresponding begin tag.
return false;
}
private void BuildMalformedTagHelpers(int count, RewritingContext context)
{
for (var i = 0; i < count; i++)
{
var malformedTagHelper = _tagStack.Peek();
context.ErrorSink.OnError(
malformedTagHelper.Start,
RazorResources.FormatTagHelpersParseTreeRewriter_FoundMalformedTagHelper(
malformedTagHelper.TagName));
BuildCurrentlyTrackedTagHelperBlock();
}
}
private static string GetTagName(Block tagBlock)
{
var child = tagBlock.Children.First();
@ -240,9 +338,9 @@ namespace Microsoft.AspNet.Razor.Parser.TagHelpers.Internal
{
EnsureTagBlock(beginTagBlock);
var childSpan = (Span)beginTagBlock.Children.Last();
var childSpan = beginTagBlock.Children.Last() as Span;
return childSpan.Content.EndsWith("/>");
return childSpan?.Content.EndsWith("/>") ?? false;
}
private static bool IsEndTag(Block tagBlock)

View File

@ -2,6 +2,8 @@
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System.Collections.Generic;
using System.Linq;
using Microsoft.AspNet.Razor.Parser;
using Microsoft.AspNet.Razor.Parser.SyntaxTree;
using Microsoft.AspNet.Razor.TagHelpers;
@ -15,15 +17,18 @@ namespace Microsoft.AspNet.Razor
/// <summary>
/// Instantiates a new <see cref="ParserResults"/> instance.
/// </summary>
/// <param name="document">The Razor syntax tree.</param>
/// <param name="tagHelperDescriptors"><see cref="TagHelperDescriptor"/>s that apply to the current Razor
/// document.</param>
/// <param name="parserErrors"><see cref="RazorError"/>s encountered when parsing the current Razor
/// document.</param>
/// <param name="document">The <see cref="Block"/> for the syntax tree.</param>
/// <param name="tagHelperDescriptors">
/// The <see cref="TagHelperDescriptor"/>s that apply to the current Razor document.
/// </param>
/// <param name="errorSink">
/// The <see cref="ParserErrorSink"/> used to collect <see cref="RazorError"/>s encountered when parsing the
/// current Razor document.
/// </param>
public ParserResults([NotNull] Block document,
[NotNull] IEnumerable<TagHelperDescriptor> tagHelperDescriptors,
[NotNull] IList<RazorError> parserErrors)
: this(parserErrors == null || parserErrors.Count == 0, document, tagHelperDescriptors, parserErrors)
[NotNull] ParserErrorSink errorSink)
: this(!errorSink.Errors.Any(), document, tagHelperDescriptors, errorSink)
{
}
@ -31,40 +36,50 @@ namespace Microsoft.AspNet.Razor
/// Instantiates a new <see cref="ParserResults"/> instance.
/// </summary>
/// <param name="success"><c>true</c> if parsing was successful, <c>false</c> otherwise.</param>
/// <param name="document">The Razor syntax tree.</param>
/// <param name="tagHelperDescriptors"><see cref="TagHelperDescriptor"/>s that apply to the current Razor
/// document.</param>
/// <param name="errors"><see cref="RazorError"/>s encountered when parsing the current Razor
/// document.</param>
/// <param name="document">The <see cref="Block"/> for the syntax tree.</param>
/// <param name="tagHelperDescriptors">
/// The <see cref="TagHelperDescriptor"/>s that apply to the current Razor document.
/// </param>
/// <param name="errorSink">
/// The <see cref="ParserErrorSink"/> used to collect <see cref="RazorError"/>s encountered when parsing the
/// current Razor document.
/// </param>
protected ParserResults(bool success,
[NotNull] Block document,
[NotNull] IEnumerable<TagHelperDescriptor> tagHelperDescriptors,
[NotNull] IList<RazorError> errors)
[NotNull] ParserErrorSink errorSink)
{
Success = success;
Document = document;
TagHelperDescriptors = tagHelperDescriptors;
ParserErrors = errors ?? new List<RazorError>();
ErrorSink = errorSink;
ParserErrors = errorSink.Errors;
}
/// <summary>
/// Indicates if parsing was successful (no errors)
/// Indicates if parsing was successful (no errors).
/// </summary>
public bool Success { get; private set; }
/// <value><c>true</c> if parsing was successful, <c>false</c> otherwise.</value>
public bool Success { get; }
/// <summary>
/// The root node in the document's syntax tree
/// The root node in the document's syntax tree.
/// </summary>
public Block Document { get; private set; }
public Block Document { get; }
/// <summary>
/// Used to aggregate <see cref="RazorError"/>s.
/// </summary>
public ParserErrorSink ErrorSink { get; }
/// <summary>
/// The list of errors which occurred during parsing.
/// </summary>
public IList<RazorError> ParserErrors { get; private set; }
public IEnumerable<RazorError> ParserErrors { get; }
/// <summary>
/// The <see cref="TagHelperDescriptor"/>s found for the current Razor document.
/// </summary>
public IEnumerable<TagHelperDescriptor> TagHelperDescriptors { get; private set; }
public IEnumerable<TagHelperDescriptor> TagHelperDescriptors { get; }
}
}

View File

@ -92,7 +92,7 @@ namespace Microsoft.AspNet.Razor
/// <summary>
/// The "@" character must be followed by a ":", "(", or a C# identifier. If you intended to switch to markup, use an HTML start tag, for example:
///
///
/// @if(isLoggedIn) {
/// &lt;p&gt;Hello, @user!&lt;/p&gt;
/// }
@ -104,7 +104,7 @@ namespace Microsoft.AspNet.Razor
/// <summary>
/// The "@" character must be followed by a ":", "(", or a C# identifier. If you intended to switch to markup, use an HTML start tag, for example:
///
///
/// @if(isLoggedIn) {
/// &lt;p&gt;Hello, @user!&lt;/p&gt;
/// }
@ -228,7 +228,7 @@ namespace Microsoft.AspNet.Razor
/// <summary>
/// Sections cannot be empty. The "@section" keyword must be followed by a block of markup surrounded by "{}". For example:
///
///
/// @section Sidebar {
/// &lt;!-- Markup and text goes here --&gt;
/// }
@ -240,7 +240,7 @@ namespace Microsoft.AspNet.Razor
/// <summary>
/// Sections cannot be empty. The "@section" keyword must be followed by a block of markup surrounded by "{}". For example:
///
///
/// @section Sidebar {
/// &lt;!-- Markup and text goes here --&gt;
/// }
@ -252,7 +252,7 @@ namespace Microsoft.AspNet.Razor
/// <summary>
/// Namespace imports and type aliases cannot be placed within code blocks. They must immediately follow an "@" character in markup. It is recommended that you put them at the top of the page, as in the following example:
///
///
/// @using System.Drawing;
/// @{
/// // OK here to use types from System.Drawing in the page.
@ -265,7 +265,7 @@ namespace Microsoft.AspNet.Razor
/// <summary>
/// Namespace imports and type aliases cannot be placed within code blocks. They must immediately follow an "@" character in markup. It is recommended that you put them at the top of the page, as in the following example:
///
///
/// @using System.Drawing;
/// @{
/// // OK here to use types from System.Drawing in the page.
@ -278,12 +278,12 @@ namespace Microsoft.AspNet.Razor
/// <summary>
/// Expected a "{0}" but found a "{1}". Block statements must be enclosed in "{{" and "}}". You cannot use single-statement control-flow statements in CSHTML pages. For example, the following is not allowed:
///
///
/// @if(isLoggedIn)
/// &lt;p&gt;Hello, @user&lt;/p&gt;
///
///
/// Instead, wrap the contents of the block in "{{}}":
///
///
/// @if(isLoggedIn) {{
/// &lt;p&gt;Hello, @user&lt;/p&gt;
/// }}
@ -295,12 +295,12 @@ namespace Microsoft.AspNet.Razor
/// <summary>
/// Expected a "{0}" but found a "{1}". Block statements must be enclosed in "{{" and "}}". You cannot use single-statement control-flow statements in CSHTML pages. For example, the following is not allowed:
///
///
/// @if(isLoggedIn)
/// &lt;p&gt;Hello, @user&lt;/p&gt;
///
///
/// Instead, wrap the contents of the block in "{{}}":
///
///
/// @if(isLoggedIn) {{
/// &lt;p&gt;Hello, @user&lt;/p&gt;
/// }}
@ -390,38 +390,6 @@ namespace Microsoft.AspNet.Razor
return GetString("ParseError_Unterminated_String_Literal");
}
/// <summary>
/// Unknown option: "{0}".
/// </summary>
internal static string ParseError_UnknownOption
{
get { return GetString("ParseError_UnknownOption"); }
}
/// <summary>
/// Unknown option: "{0}".
/// </summary>
internal static string FormatParseError_UnknownOption(object p0)
{
return string.Format(CultureInfo.CurrentCulture, GetString("ParseError_UnknownOption"), p0);
}
/// <summary>
/// The "{0}" block was not terminated. All "{0}" statements must be terminated with a matching "{1}".
/// </summary>
internal static string ParseError_BlockNotTerminated
{
get { return GetString("ParseError_BlockNotTerminated"); }
}
/// <summary>
/// The "{0}" block was not terminated. All "{0}" statements must be terminated with a matching "{1}".
/// </summary>
internal static string FormatParseError_BlockNotTerminated(object p0, object p1)
{
return string.Format(CultureInfo.CurrentCulture, GetString("ParseError_BlockNotTerminated"), p0, p1);
}
/// <summary>
/// @section Header { ... }
/// </summary>
@ -454,22 +422,6 @@ namespace Microsoft.AspNet.Razor
return GetString("ParseError_TextTagCannotContainAttributes");
}
/// <summary>
/// The "Imports" keyword must be followed by a namespace or a type alias on the same line.
/// </summary>
internal static string ParseError_NamespaceOrTypeAliasExpected
{
get { return GetString("ParseError_NamespaceOrTypeAliasExpected"); }
}
/// <summary>
/// The "Imports" keyword must be followed by a namespace or a type alias on the same line.
/// </summary>
internal static string FormatParseError_NamespaceOrTypeAliasExpected()
{
return GetString("ParseError_NamespaceOrTypeAliasExpected");
}
/// <summary>
/// A space or line break was encountered after the "@" character. Only valid identifiers, keywords, comments, "(" and "{" are valid at the start of a code block and they must occur immediately following "@" with no space in between.
/// </summary>
@ -998,22 +950,6 @@ namespace Microsoft.AspNet.Razor
return string.Format(CultureInfo.CurrentCulture, GetString("TokenizerView_CannotPutBack"), p0, p1);
}
/// <summary>
/// Unexpected "{0}"
/// </summary>
internal static string ParseError_Unexpected
{
get { return GetString("ParseError_Unexpected"); }
}
/// <summary>
/// Unexpected "{0}"
/// </summary>
internal static string FormatParseError_Unexpected(object p0)
{
return string.Format(CultureInfo.CurrentCulture, GetString("ParseError_Unexpected"), p0);
}
/// <summary>
/// Unexpected "{" after "@" character. Once inside the body of a code block (@if {}, @{}, etc.) you do not need to use "@{" to switch to code.
/// </summary>
@ -1142,38 +1078,6 @@ namespace Microsoft.AspNet.Razor
return GetString("Language_Does_Not_Support_RazorComment");
}
/// <summary>
/// Missing value for session state directive.
/// </summary>
internal static string ParserEror_SessionDirectiveMissingValue
{
get { return GetString("ParserEror_SessionDirectiveMissingValue"); }
}
/// <summary>
/// Missing value for session state directive.
/// </summary>
internal static string FormatParserEror_SessionDirectiveMissingValue()
{
return GetString("ParserEror_SessionDirectiveMissingValue");
}
/// <summary>
/// Cannot call CreateCodeWriter, a CodeWriter was not provided to the Create method
/// </summary>
internal static string CreateCodeWriter_NoCodeWriter
{
get { return GetString("CreateCodeWriter_NoCodeWriter"); }
}
/// <summary>
/// Cannot call CreateCodeWriter, a CodeWriter was not provided to the Create method
/// </summary>
internal static string FormatCreateCodeWriter_NoCodeWriter()
{
return GetString("CreateCodeWriter_NoCodeWriter");
}
/// <summary>
/// [BG][{0}] Shutdown
/// </summary>
@ -1431,7 +1335,7 @@ namespace Microsoft.AspNet.Razor
}
/// <summary>
/// Tag Helper attributes must have a name.
/// Tag Helper '{0}'s attributes must have names.
/// </summary>
internal static string TagHelpers_AttributesMustHaveAName
{
@ -1439,15 +1343,15 @@ namespace Microsoft.AspNet.Razor
}
/// <summary>
/// Tag Helper attributes must have a name.
/// Tag Helper '{0}'s attributes must have names.
/// </summary>
internal static string FormatTagHelpers_AttributesMustHaveAName()
internal static string FormatTagHelpers_AttributesMustHaveAName(object p0)
{
return GetString("TagHelpers_AttributesMustHaveAName");
return string.Format(CultureInfo.CurrentCulture, GetString("TagHelpers_AttributesMustHaveAName"), p0);
}
/// <summary>
/// Tag Helpers cannot have C# in an HTML tag element's attribute declaration area.
/// The tag helper '{0}' must not have C# in the element's attribute declaration area.
/// </summary>
internal static string TagHelpers_CannotHaveCSharpInTagDeclaration
{
@ -1455,11 +1359,11 @@ namespace Microsoft.AspNet.Razor
}
/// <summary>
/// Tag Helpers cannot have C# in an HTML tag element's attribute declaration area.
/// The tag helper '{0}' must not have C# in the element's attribute declaration area.
/// </summary>
internal static string FormatTagHelpers_CannotHaveCSharpInTagDeclaration()
internal static string FormatTagHelpers_CannotHaveCSharpInTagDeclaration(object p0)
{
return GetString("TagHelpers_CannotHaveCSharpInTagDeclaration");
return string.Format(CultureInfo.CurrentCulture, GetString("TagHelpers_CannotHaveCSharpInTagDeclaration"), p0);
}
/// <summary>
@ -1478,22 +1382,6 @@ namespace Microsoft.AspNet.Razor
return GetString("TagHelpers_TagHelperCodeGeneartorMustBeAssociatedWithATagHelperBlock");
}
/// <summary>
/// TagHelper attributes that do not expect strings must not have @ symbols within them. Found attribute '{0}' with an invalid value.
/// </summary>
internal static string TagHelpers_AttributesThatAreNotStringsMustNotContainAtSymbols
{
get { return GetString("TagHelpers_AttributesThatAreNotStringsMustNotContainAtSymbols"); }
}
/// <summary>
/// TagHelper attributes that do not expect strings must not have @ symbols within them. Found attribute '{0}' with an invalid value.
/// </summary>
internal static string FormatTagHelpers_AttributesThatAreNotStringsMustNotContainAtSymbols(object p0)
{
return string.Format(CultureInfo.CurrentCulture, GetString("TagHelpers_AttributesThatAreNotStringsMustNotContainAtSymbols"), p0);
}
/// <summary>
/// Directive '{0}' must have a value.
/// </summary>
@ -1542,6 +1430,106 @@ namespace Microsoft.AspNet.Razor
return string.Format(CultureInfo.CurrentCulture, GetString("TagHelpersParseTreeRewriter_FoundMalformedTagHelper"), p0);
}
/// <summary>
/// Missing close angle for tag helper '{0}'.
/// </summary>
internal static string TagHelpersParseTreeRewriter_MissingCloseAngle
{
get { return GetString("TagHelpersParseTreeRewriter_MissingCloseAngle"); }
}
/// <summary>
/// Missing close angle for tag helper '{0}'.
/// </summary>
internal static string FormatTagHelpersParseTreeRewriter_MissingCloseAngle(object p0)
{
return string.Format(CultureInfo.CurrentCulture, GetString("TagHelpersParseTreeRewriter_MissingCloseAngle"), p0);
}
/// <summary>
/// TagHelper attributes must be welformed.
/// </summary>
internal static string TagHelperBlockRewriter_TagHelperAttributesMustBeWelformed
{
get { return GetString("TagHelperBlockRewriter_TagHelperAttributesMustBeWelformed"); }
}
/// <summary>
/// TagHelper attributes must be welformed.
/// </summary>
internal static string FormatTagHelperBlockRewriter_TagHelperAttributesMustBeWelformed()
{
return GetString("TagHelperBlockRewriter_TagHelperAttributesMustBeWelformed");
}
/// <summary>
/// Non-string tag helper attribute values must not be empty. Add an expression to this attribute value.
/// </summary>
internal static string TagHelpers_AttributeExpressionRequired
{
get { return GetString("TagHelpers_AttributeExpressionRequired"); }
}
/// <summary>
/// Non-string tag helper attribute values must not be empty. Add an expression to this attribute value.
/// </summary>
internal static string FormatTagHelpers_AttributeExpressionRequired()
{
return GetString("TagHelpers_AttributeExpressionRequired");
}
/// <summary>
/// Code blocks (e.g. @{{var variable = 23;}}) must not appear in non-string tag helper attribute values.
/// Already in an expression (code) context. If necessary an explicit expression (e.g. @(@readonly)) may be used.
/// </summary>
internal static string TagHelpers_CodeBlocks_NotSupported_InAttributes
{
get { return GetString("TagHelpers_CodeBlocks_NotSupported_InAttributes"); }
}
/// <summary>
/// Code blocks (e.g. @{{var variable = 23;}}) must not appear in non-string tag helper attribute values.
/// Already in an expression (code) context. If necessary an explicit expression (e.g. @(@readonly)) may be used.
/// </summary>
internal static string FormatTagHelpers_CodeBlocks_NotSupported_InAttributes()
{
return GetString("TagHelpers_CodeBlocks_NotSupported_InAttributes");
}
/// <summary>
/// @'{0}' directives must not appear in non-string tag helper attribute values.
/// </summary>
internal static string TagHelpers_Directives_NotSupported_InAttributes
{
get { return GetString("TagHelpers_Directives_NotSupported_InAttributes"); }
}
/// <summary>
/// @'{0}' directives must not appear in non-string tag helper attribute values.
/// </summary>
internal static string FormatTagHelpers_Directives_NotSupported_InAttributes(object p0)
{
return string.Format(CultureInfo.CurrentCulture, GetString("TagHelpers_Directives_NotSupported_InAttributes"), p0);
}
/// <summary>
/// Inline markup blocks (e.g. @&lt;p&gt;content&lt;/p&gt;) must not appear in non-string tag helper attribute values.
/// Expected a '{0}' attribute value, not a string.
/// </summary>
internal static string TagHelpers_InlineMarkupBlocks_NotSupported_InAttributes
{
get { return GetString("TagHelpers_InlineMarkupBlocks_NotSupported_InAttributes"); }
}
/// <summary>
/// Inline markup blocks (e.g. @&lt;p&gt;content&lt;/p&gt;) must not appear in non-string tag helper attribute values.
/// Expected a '{0}' attribute value, not a string.
/// </summary>
internal static string FormatTagHelpers_InlineMarkupBlocks_NotSupported_InAttributes(object p0)
{
return string.Format(CultureInfo.CurrentCulture, GetString("TagHelpers_InlineMarkupBlocks_NotSupported_InAttributes"), p0);
}
private static string GetString(string name, params string[] formatterNames)
{
var value = _resourceManager.GetString(name);

View File

@ -1,17 +1,17 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
@ -26,36 +26,36 @@
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
@ -206,12 +206,6 @@ Instead, wrap the contents of the block in "{{}}":
<data name="ParseError_Unterminated_String_Literal" xml:space="preserve">
<value>Unterminated string literal. Strings that start with a quotation mark (") must be terminated before the end of the line. However, strings that start with @ and a quotation mark (@") can span multiple lines.</value>
</data>
<data name="ParseError_UnknownOption" xml:space="preserve">
<value>Unknown option: "{0}".</value>
</data>
<data name="ParseError_BlockNotTerminated" xml:space="preserve">
<value>The "{0}" block was not terminated. All "{0}" statements must be terminated with a matching "{1}".</value>
</data>
<data name="SectionExample_CS" xml:space="preserve">
<value>@section Header { ... }</value>
<comment>In CSHTML, the @section keyword is case-sensitive and lowercase (as with all C# keywords)</comment>
@ -219,9 +213,6 @@ Instead, wrap the contents of the block in "{{}}":
<data name="ParseError_TextTagCannotContainAttributes" xml:space="preserve">
<value>"&lt;text&gt;" and "&lt;/text&gt;" tags cannot contain attributes.</value>
</data>
<data name="ParseError_NamespaceOrTypeAliasExpected" xml:space="preserve">
<value>The "Imports" keyword must be followed by a namespace or a type alias on the same line.</value>
</data>
<data name="ParseError_Unexpected_WhiteSpace_At_Start_Of_CodeBlock_CS" xml:space="preserve">
<value>A space or line break was encountered after the "@" character. Only valid identifiers, keywords, comments, "(" and "{" are valid at the start of a code block and they must occur immediately following "@" with no space in between.</value>
</data>
@ -321,9 +312,6 @@ Instead, wrap the contents of the block in "{{}}":
<data name="TokenizerView_CannotPutBack" xml:space="preserve">
<value>In order to put a symbol back, it must have been the symbol which ended at the current position. The specified symbol ends at {0}, but the current position is {1}</value>
</data>
<data name="ParseError_Unexpected" xml:space="preserve">
<value>Unexpected "{0}"</value>
</data>
<data name="ParseError_Unexpected_Nested_CodeBlock" xml:space="preserve">
<value>Unexpected "{" after "@" character. Once inside the body of a code block (@if {}, @{}, etc.) you do not need to use "@{" to switch to code.</value>
</data>
@ -348,13 +336,6 @@ Instead, wrap the contents of the block in "{{}}":
<data name="Language_Does_Not_Support_RazorComment" xml:space="preserve">
<value>Cannot use built-in RazorComment handler, language characteristics does not define the CommentStart, CommentStar and CommentBody known symbol types or parser does not override TokenizerBackedParser.OutputSpanBeforeRazorComment</value>
</data>
<data name="ParserEror_SessionDirectiveMissingValue" xml:space="preserve">
<value>Missing value for session state directive.</value>
</data>
<data name="CreateCodeWriter_NoCodeWriter" xml:space="preserve">
<value>Cannot call CreateCodeWriter, a CodeWriter was not provided to the Create method</value>
<comment>This error should not be seen by users, it should only appear to internal developers, but I'm putting it in resources just in case</comment>
</data>
<data name="Trace_BackgroundThreadShutdown" xml:space="preserve">
<value>[BG][{0}] Shutdown</value>
</data>
@ -404,17 +385,14 @@ Instead, wrap the contents of the block in "{{}}":
<value>Section blocks ("{0}") cannot be nested. Only one level of section blocks are allowed.</value>
</data>
<data name="TagHelpers_AttributesMustHaveAName" xml:space="preserve">
<value>Tag Helper attributes must have a name.</value>
<value>Tag Helper '{0}'s attributes must have names.</value>
</data>
<data name="TagHelpers_CannotHaveCSharpInTagDeclaration" xml:space="preserve">
<value>Tag Helpers cannot have C# in an HTML tag element's attribute declaration area.</value>
<value>The tag helper '{0}' must not have C# in the element's attribute declaration area.</value>
</data>
<data name="TagHelpers_TagHelperCodeGeneartorMustBeAssociatedWithATagHelperBlock" xml:space="preserve">
<value>A TagHelperCodeGenerator must only be used with TagHelperBlocks.</value>
</data>
<data name="TagHelpers_AttributesThatAreNotStringsMustNotContainAtSymbols" xml:space="preserve">
<value>TagHelper attributes that do not expect strings must not have @ symbols within them. Found attribute '{0}' with an invalid value.</value>
</data>
<data name="ParseError_DirectiveMustHaveValue" xml:space="preserve">
<value>Directive '{0}' must have a value.</value>
</data>
@ -424,4 +402,24 @@ Instead, wrap the contents of the block in "{{}}":
<data name="TagHelpersParseTreeRewriter_FoundMalformedTagHelper" xml:space="preserve">
<value>Found a malformed '{0}' tag helper. Tag helpers must have a start and end tag or be self closing.</value>
</data>
<data name="TagHelpersParseTreeRewriter_MissingCloseAngle" xml:space="preserve">
<value>Missing close angle for tag helper '{0}'.</value>
</data>
<data name="TagHelperBlockRewriter_TagHelperAttributesMustBeWelformed" xml:space="preserve">
<value>TagHelper attributes must be welformed.</value>
</data>
<data name="TagHelpers_AttributeExpressionRequired" xml:space="preserve">
<value>Non-string tag helper attribute values must not be empty. Add an expression to this attribute value.</value>
</data>
<data name="TagHelpers_CodeBlocks_NotSupported_InAttributes" xml:space="preserve">
<value>Code blocks (e.g. @{{var variable = 23;}}) must not appear in non-string tag helper attribute values.
Already in an expression (code) context. If necessary an explicit expression (e.g. @(@readonly)) may be used.</value>
</data>
<data name="TagHelpers_Directives_NotSupported_InAttributes" xml:space="preserve">
<value>@'{0}' directives must not appear in non-string tag helper attribute values.</value>
</data>
<data name="TagHelpers_InlineMarkupBlocks_NotSupported_InAttributes" xml:space="preserve">
<value>Inline markup blocks (e.g. @&lt;p&gt;content&lt;/p&gt;) must not appear in non-string tag helper attribute values.
Expected a '{0}' attribute value, not a string.</value>
</data>
</root>

View File

@ -252,7 +252,7 @@ namespace Microsoft.AspNet.Razor
generator.DesignTimeMode = Host.DesignTimeMode;
generator.Visit(results);
var codeBuilderContext = new CodeBuilderContext(generator.Context);
var codeBuilderContext = new CodeBuilderContext(generator.Context, results.ErrorSink);
codeBuilderContext.Checksum = checksum;
var builder = CreateCodeBuilder(codeBuilderContext);
var builderResult = builder.Build();

View File

@ -1,43 +0,0 @@
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
namespace Microsoft.AspNet.Razor.TagHelpers
{
/// <summary>
/// Defines how a tag helper will utilize its inner HTML.
/// </summary>
public enum ContentBehavior
{
/// <summary>
/// Indicates that a tag helper will not modify its content in any way. This is the default
/// <see cref="ContentBehavior"/>.
/// </summary>
/// <remarks>Children of the current tag helper will execute after the current tag helper.</remarks>
None,
/// <summary>
/// Indicates the tag helper's content should be appended to what its children generate.
/// </summary>
/// <remarks>Children of the current tag helper will execute before the current tag helper.</remarks>
Append,
/// <summary>
/// Indicates that the tag helper will modify its HTML content. Therefore this <see cref="ContentBehavior"/>
/// enables the tag helper to examine the content its children generate.
/// </summary>
/// <remarks>Children of the current tag helper will execute before the current tag helper.</remarks>
Modify,
/// <summary>
/// Indicates the tag helper's content should be prepended to what its children generate.
/// </summary>
/// <remarks>Children of the current tag helper will execute after the current tag helper.</remarks>
Prepend,
/// <summary>
/// Indicates the tag helper's content should replace the HTML its children generate.
/// </summary>
/// <remarks>Children of the current tag helper will not execute.</remarks>
Replace,
}
}

View File

@ -16,15 +16,25 @@ namespace Microsoft.AspNet.Razor.TagHelpers
/// Called during Razor's code generation process to generate code that instantiates the value of the tag
/// helper's property. Last value written should not be or end with a semicolon.
/// </summary>
/// <param name="attributeDescriptor">The <see cref="TagHelperAttributeDescriptor"/> to generate code for.</param>
/// <param name="attributeDescriptor">
/// The <see cref="TagHelperAttributeDescriptor"/> to generate code for.
/// </param>
/// <param name="writer">The <see cref="CSharpCodeWriter"/> that's used to write code.</param>
/// <param name="context">A <see cref="CodeGeneratorContext"/> instance that contains information about
/// the current code generation process.</param>
/// <param name="renderAttributeValue"><see cref="Action"/> that renders the raw value of the HTML attribute.</param>
/// <param name="renderAttributeValue">
/// <see cref="Action"/> that renders the raw value of the HTML attribute.
/// </param>
/// <param name="complexValue">
/// Indicates whether or not the source attribute value contains more than simple text. <c>false</c> for plain
/// C# expressions e.g. <c>"PropertyName"</c>. <c>true</c> if the attribute value contain at least one in-line
/// Razor construct e.g. <c>"@(@readonly)"</c>.
/// </param>
public virtual void RenderAttributeValue([NotNull] TagHelperAttributeDescriptor attributeDescriptor,
[NotNull] CSharpCodeWriter writer,
[NotNull] CodeBuilderContext context,
[NotNull] Action<CSharpCodeWriter> renderAttributeValue)
[NotNull] Action<CSharpCodeWriter> renderAttributeValue,
bool complexValue)
{
renderAttributeValue(writer);
}

View File

@ -16,12 +16,10 @@ namespace Microsoft.AspNet.Razor.TagHelpers
/// </summary>
internal TagHelperDescriptor([NotNull] string tagName,
[NotNull] string typeName,
[NotNull] string assemblyName,
ContentBehavior contentBehavior)
[NotNull] string assemblyName)
: this(tagName,
typeName,
assemblyName,
contentBehavior,
Enumerable.Empty<TagHelperAttributeDescriptor>())
{
}
@ -34,21 +32,17 @@ namespace Microsoft.AspNet.Razor.TagHelpers
/// <see cref="TagHelperDescriptor"/> which applies to every HTML tag.</param>
/// <param name="typeName">The full name of the tag helper class.</param>
/// <param name="assemblyName">The name of the assembly containing the tag helper class.</param>
/// <param name="contentBehavior">The <see cref="TagHelpers.ContentBehavior"/>
/// of the tag helper.</param>
/// <param name="attributes">
/// The <see cref="TagHelperAttributeDescriptor"/>s to request from the HTML tag.
/// </param>
public TagHelperDescriptor([NotNull] string tagName,
[NotNull] string typeName,
[NotNull] string assemblyName,
ContentBehavior contentBehavior,
[NotNull] IEnumerable<TagHelperAttributeDescriptor> attributes)
{
TagName = tagName;
TypeName = typeName;
AssemblyName = assemblyName;
ContentBehavior = contentBehavior;
Attributes = new List<TagHelperAttributeDescriptor>(attributes);
}
@ -67,11 +61,6 @@ namespace Microsoft.AspNet.Razor.TagHelpers
/// </summary>
public string AssemblyName { get; private set; }
/// <summary>
/// The <see cref="TagHelpers.ContentBehavior"/> of the tag helper.
/// </summary>
public ContentBehavior ContentBehavior { get; private set; }
/// <summary>
/// The list of attributes the tag helper expects.
/// </summary>

View File

@ -29,15 +29,13 @@ namespace Microsoft.AspNet.Razor.TagHelpers
/// <c>false</c> otherwise.</returns>
/// <remarks>
/// Determines equality based on <see cref="TagHelperDescriptor.TypeName"/>,
/// <see cref="TagHelperDescriptor.AssemblyName"/>, <see cref="TagHelperDescriptor.TagName"/> and
/// <see cref="TagHelperDescriptor.ContentBehavior"/>.
/// <see cref="TagHelperDescriptor.AssemblyName"/> and <see cref="TagHelperDescriptor.TagName"/>.
/// </remarks>
public bool Equals(TagHelperDescriptor descriptorX, TagHelperDescriptor descriptorY)
{
return string.Equals(descriptorX.TypeName, descriptorY.TypeName, StringComparison.Ordinal) &&
string.Equals(descriptorX.TagName, descriptorY.TagName, StringComparison.OrdinalIgnoreCase) &&
string.Equals(descriptorX.AssemblyName, descriptorY.AssemblyName, StringComparison.Ordinal) &&
descriptorX.ContentBehavior == descriptorY.ContentBehavior;
string.Equals(descriptorX.AssemblyName, descriptorY.AssemblyName, StringComparison.Ordinal);
}
/// <summary>
@ -51,7 +49,6 @@ namespace Microsoft.AspNet.Razor.TagHelpers
.Add(descriptor.TagName, StringComparer.OrdinalIgnoreCase)
.Add(descriptor.TypeName, StringComparer.Ordinal)
.Add(descriptor.AssemblyName, StringComparer.Ordinal)
.Add(descriptor.ContentBehavior)
.CombinedHash;
}
}

View File

@ -9,12 +9,13 @@
"System.Collections": "4.0.10-beta-*",
"System.Diagnostics.Debug": "4.0.10-beta-*",
"System.Diagnostics.Tools": "4.0.0-beta-*",
"System.IO": "4.0.10-beta-*",
"System.IO.FileSystem": "4.0.0-beta-*",
"System.Linq": "4.0.0-beta-*",
"System.Reflection": "4.0.10-beta-*",
"System.Resources.ResourceManager": "4.0.0-beta-*",
"System.Runtime.Extensions": "4.0.10-beta-*",
"System.Threading": "4.0.0-beta-*",
"System.Threading": "4.0.10-beta-*",
"System.Threading.Tasks": "4.0.10-beta-*",
"System.Threading.Thread": "4.0.0-beta-*",
"System.Security.Cryptography.Hashing.Algorithms": "4.0.0-beta-*"

View File

@ -1,6 +1,7 @@
// Copyright (c) Microsoft Open Technologies, Inc. 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.Linq;
using Microsoft.AspNet.Razor.TagHelpers;
@ -20,6 +21,8 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers
bool IEqualityComparer<TagHelperDescriptor>.Equals(TagHelperDescriptor descriptorX, TagHelperDescriptor descriptorY)
{
return base.Equals(descriptorX, descriptorY) &&
// Tests should be exact casing
string.Equals(descriptorX.TagName, descriptorY.TagName, StringComparison.Ordinal) &&
descriptorX.Attributes.SequenceEqual(descriptorY.Attributes,
CompleteTagHelperAttributeDescriptorComparer.Default);
}
@ -43,17 +46,17 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers
public bool Equals(TagHelperAttributeDescriptor descriptorX, TagHelperAttributeDescriptor descriptorY)
{
return descriptorX.Name == descriptorY.Name &&
descriptorX.PropertyName == descriptorY.PropertyName &&
descriptorX.TypeName == descriptorY.TypeName;
return string.Equals(descriptorX.Name, descriptorY.Name, StringComparison.Ordinal) &&
string.Equals(descriptorX.PropertyName, descriptorY.PropertyName, StringComparison.Ordinal) &&
string.Equals(descriptorX.TypeName, descriptorY.TypeName, StringComparison.Ordinal);
}
public int GetHashCode(TagHelperAttributeDescriptor descriptor)
{
return HashCodeCombiner.Start()
.Add(descriptor.Name)
.Add(descriptor.PropertyName)
.Add(descriptor.TypeName)
.Add(descriptor.Name, StringComparer.Ordinal)
.Add(descriptor.PropertyName, StringComparer.Ordinal)
.Add(descriptor.TypeName, StringComparer.Ordinal)
.CombinedHash;
}
}

View File

@ -1,6 +1,7 @@
// Copyright (c) Microsoft Open Technologies, Inc. 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.Reflection;
using Microsoft.AspNet.Razor.TagHelpers;
using Xunit;
@ -12,6 +13,42 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers
private static readonly string AssemblyName =
typeof(TagHelperDescriptorFactoryTest).GetTypeInfo().Assembly.GetName().Name;
public static TheoryData HtmlCaseData
{
get
{
// tagHelperType, expectedTagName, expectedAttributeName
return new TheoryData<Type, string, string>
{
{ typeof(SingleAttributeTagHelper), "single-attribute", "int-attribute" },
{ typeof(ALLCAPSTAGHELPER), "allcaps", "allcapsattribute" },
{ typeof(CAPSOnOUTSIDETagHelper), "caps-on-outside", "caps-on-outsideattribute" },
{ typeof(capsONInsideTagHelper), "caps-on-inside", "caps-on-insideattribute" },
{ typeof(One1Two2Three3TagHelper), "one1-two2-three3", "one1-two2-three3-attribute" },
{ typeof(ONE1TWO2THREE3TagHelper), "one1two2three3", "one1two2three3-attribute" },
{ typeof(First_Second_ThirdHiTagHelper), "first_second_third-hi", "first_second_third-attribute" },
{ typeof(UNSuffixedCLASS), "un-suffixed-class", "un-suffixed-attribute" },
};
}
}
[Theory]
[MemberData(nameof(HtmlCaseData))]
public void CreateDescriptor_HtmlCasesTagNameAndAttributeName(
Type tagHelperType,
string expectedTagName,
string expectedAttributeName)
{
// Arrange & Act
var descriptors = TagHelperDescriptorFactory.CreateDescriptors(tagHelperType);
// Assert
var descriptor = Assert.Single(descriptors);
Assert.Equal(expectedTagName, descriptor.TagName, StringComparer.Ordinal);
var attributeDescriptor = Assert.Single(descriptor.Attributes);
Assert.Equal(expectedAttributeName, attributeDescriptor.Name);
}
[Fact]
public void CreateDescriptor_OverridesAttributeNameFromAttribute()
{
@ -22,10 +59,9 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers
nameof(OverriddenAttributeTagHelper.ValidAttribute2));
var expectedDescriptors = new[] {
new TagHelperDescriptor(
"OverriddenAttribute",
"overridden-attribute",
typeof(OverriddenAttributeTagHelper).FullName,
AssemblyName,
ContentBehavior.None,
new[] {
new TagHelperAttributeDescriptor("SomethingElse", validProperty1),
new TagHelperAttributeDescriptor("Something-Else", validProperty2)
@ -49,12 +85,11 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers
nameof(InheritedOverriddenAttributeTagHelper.ValidAttribute2));
var expectedDescriptors = new[] {
new TagHelperDescriptor(
"InheritedOverriddenAttribute",
"inherited-overridden-attribute",
typeof(InheritedOverriddenAttributeTagHelper).FullName,
AssemblyName,
ContentBehavior.None,
new[] {
new TagHelperAttributeDescriptor(nameof(InheritedOverriddenAttributeTagHelper.ValidAttribute1),
new TagHelperAttributeDescriptor("valid-attribute1",
validProperty1),
new TagHelperAttributeDescriptor("Something-Else", validProperty2)
})
@ -77,10 +112,9 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers
nameof(InheritedNotOverriddenAttributeTagHelper.ValidAttribute2));
var expectedDescriptors = new[] {
new TagHelperDescriptor(
"InheritedNotOverriddenAttribute",
"inherited-not-overridden-attribute",
typeof(InheritedNotOverriddenAttributeTagHelper).FullName,
AssemblyName,
ContentBehavior.None,
new[] {
new TagHelperAttributeDescriptor("SomethingElse", validProperty1),
new TagHelperAttributeDescriptor("Something-Else", validProperty2)
@ -100,7 +134,7 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers
// Arrange
var objectAssemblyName = typeof(object).GetTypeInfo().Assembly.GetName().Name;
var expectedDescriptor =
new TagHelperDescriptor("Object", "System.Object", objectAssemblyName, ContentBehavior.None);
new TagHelperDescriptor("object", "System.Object", objectAssemblyName);
// Act
var descriptors = TagHelperDescriptorFactory.CreateDescriptors(typeof(object));
@ -117,12 +151,11 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers
var intProperty = typeof(InheritedSingleAttributeTagHelper).GetProperty(
nameof(InheritedSingleAttributeTagHelper.IntAttribute));
var expectedDescriptor = new TagHelperDescriptor(
"InheritedSingleAttribute",
"inherited-single-attribute",
typeof(InheritedSingleAttributeTagHelper).FullName,
AssemblyName,
ContentBehavior.None,
new[] {
new TagHelperAttributeDescriptor(nameof(InheritedSingleAttributeTagHelper.IntAttribute), intProperty)
new TagHelperAttributeDescriptor("int-attribute", intProperty)
});
// Act
@ -139,12 +172,11 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers
// Arrange
var intProperty = typeof(SingleAttributeTagHelper).GetProperty(nameof(SingleAttributeTagHelper.IntAttribute));
var expectedDescriptor = new TagHelperDescriptor(
"SingleAttribute",
"single-attribute",
typeof(SingleAttributeTagHelper).FullName,
AssemblyName,
ContentBehavior.None,
new[] {
new TagHelperAttributeDescriptor(nameof(SingleAttributeTagHelper.IntAttribute), intProperty)
new TagHelperAttributeDescriptor("int-attribute", intProperty)
});
// Act
@ -162,12 +194,11 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers
var validProperty = typeof(MissingAccessorTagHelper).GetProperty(
nameof(MissingAccessorTagHelper.ValidAttribute));
var expectedDescriptor = new TagHelperDescriptor(
"MissingAccessor",
"missing-accessor",
typeof(MissingAccessorTagHelper).FullName,
AssemblyName,
ContentBehavior.None,
new[] {
new TagHelperAttributeDescriptor(nameof(MissingAccessorTagHelper.ValidAttribute), validProperty)
new TagHelperAttributeDescriptor("valid-attribute", validProperty)
});
// Act
@ -185,13 +216,12 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers
var validProperty = typeof(PrivateAccessorTagHelper).GetProperty(
nameof(PrivateAccessorTagHelper.ValidAttribute));
var expectedDescriptor = new TagHelperDescriptor(
"PrivateAccessor",
"private-accessor",
typeof(PrivateAccessorTagHelper).FullName,
AssemblyName,
ContentBehavior.None,
new[] {
new TagHelperAttributeDescriptor(
nameof(PrivateAccessorTagHelper.ValidAttribute), validProperty)
"valid-attribute", validProperty)
});
// Act
@ -202,43 +232,6 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers
Assert.Equal(expectedDescriptor, descriptor, CompleteTagHelperDescriptorComparer.Default);
}
[Fact]
public void CreateDescriptor_ResolvesCustomContentBehavior()
{
// Arrange
var expectedDescriptor = new TagHelperDescriptor(
"CustomContentBehavior",
typeof(CustomContentBehaviorTagHelper).FullName,
AssemblyName,
ContentBehavior.Append);
// Act
var descriptors = TagHelperDescriptorFactory.CreateDescriptors(typeof(CustomContentBehaviorTagHelper));
// Assert
var descriptor = Assert.Single(descriptors);
Assert.Equal(expectedDescriptor, descriptor, CompleteTagHelperDescriptorComparer.Default);
}
[Fact]
public void CreateDescriptor_DoesNotResolveInheritedCustomContentBehavior()
{
// Arrange
var expectedDescriptor = new TagHelperDescriptor(
"InheritedCustomContentBehavior",
typeof(InheritedCustomContentBehaviorTagHelper).FullName,
AssemblyName,
ContentBehavior.None);
// Act
var descriptors = TagHelperDescriptorFactory.CreateDescriptors(
typeof(InheritedCustomContentBehaviorTagHelper));
// Assert
var descriptor = Assert.Single(descriptors);
Assert.Equal(expectedDescriptor, descriptor, CompleteTagHelperDescriptorComparer.Default);
}
[Fact]
public void CreateDescriptor_ResolvesMultipleTagHelperDescriptorsFromSingleType()
{
@ -249,17 +242,15 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers
"div",
typeof(MultiTagTagHelper).FullName,
AssemblyName,
ContentBehavior.None,
new[] {
new TagHelperAttributeDescriptor(nameof(MultiTagTagHelper.ValidAttribute), validProp)
new TagHelperAttributeDescriptor("valid-attribute", validProp)
}),
new TagHelperDescriptor(
"p",
typeof(MultiTagTagHelper).FullName,
AssemblyName,
ContentBehavior.None,
new[] {
new TagHelperAttributeDescriptor(nameof(MultiTagTagHelper.ValidAttribute), validProp)
new TagHelperAttributeDescriptor("valid-attribute", validProp)
})
};
@ -276,12 +267,11 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers
// Arrange
var validProp = typeof(InheritedMultiTagTagHelper).GetProperty(nameof(InheritedMultiTagTagHelper.ValidAttribute));
var expectedDescriptor = new TagHelperDescriptor(
"InheritedMultiTag",
"inherited-multi-tag",
typeof(InheritedMultiTagTagHelper).FullName,
AssemblyName,
ContentBehavior.None,
new[] {
new TagHelperAttributeDescriptor(nameof(InheritedMultiTagTagHelper.ValidAttribute), validProp)
new TagHelperAttributeDescriptor("valid-attribute", validProp)
});
// Act
@ -300,13 +290,11 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers
new TagHelperDescriptor(
"p",
typeof(DuplicateTagNameTagHelper).FullName,
AssemblyName,
ContentBehavior.None),
AssemblyName),
new TagHelperDescriptor(
"div",
typeof(DuplicateTagNameTagHelper).FullName,
AssemblyName,
ContentBehavior.None)
AssemblyName)
};
// Act
@ -323,8 +311,7 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers
var expectedDescriptors = new[] {
new TagHelperDescriptor("data-condition",
typeof(OverrideNameTagHelper).FullName,
AssemblyName,
ContentBehavior.None),
AssemblyName),
};
// Act
@ -342,18 +329,15 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers
new TagHelperDescriptor(
"span",
typeof(MultipleAttributeTagHelper).FullName,
AssemblyName,
ContentBehavior.None),
AssemblyName),
new TagHelperDescriptor(
"p",
typeof(MultipleAttributeTagHelper).FullName,
AssemblyName,
ContentBehavior.None),
AssemblyName),
new TagHelperDescriptor(
"div",
typeof(MultipleAttributeTagHelper).FullName,
AssemblyName,
ContentBehavior.None)
AssemblyName)
};
// Act
@ -363,16 +347,7 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers
Assert.Equal(expectedDescriptors, descriptors, CompleteTagHelperDescriptorComparer.Default);
}
[ContentBehavior(ContentBehavior.Append)]
private class CustomContentBehaviorTagHelper
{
}
private class InheritedCustomContentBehaviorTagHelper : CustomContentBehaviorTagHelper
{
}
[TagName("p", "div")]
[HtmlElementName("p", "div")]
private class MultiTagTagHelper
{
public string ValidAttribute { get; set; }
@ -382,18 +357,18 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers
{
}
[TagName("p", "p", "div", "div")]
[HtmlElementName("p", "p", "div", "div")]
private class DuplicateTagNameTagHelper
{
}
[TagName("data-condition")]
[HtmlElementName("data-condition")]
private class OverrideNameTagHelper
{
}
[TagName("span")]
[TagName("div", "p")]
[HtmlElementName("span")]
[HtmlElementName("div", "p")]
private class MultipleAttributeTagHelper
{
}
@ -419,5 +394,41 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers
private class InheritedNotOverriddenAttributeTagHelper : OverriddenAttributeTagHelper
{
}
private class ALLCAPSTAGHELPER : TagHelper
{
public int ALLCAPSATTRIBUTE { get; set; }
}
private class CAPSOnOUTSIDETagHelper : TagHelper
{
public int CAPSOnOUTSIDEATTRIBUTE { get; set; }
}
private class capsONInsideTagHelper : TagHelper
{
public int capsONInsideattribute { get; set; }
}
private class One1Two2Three3TagHelper : TagHelper
{
public int One1Two2Three3Attribute { get; set; }
}
private class ONE1TWO2THREE3TagHelper : TagHelper
{
public int ONE1TWO2THREE3Attribute { get; set; }
}
private class First_Second_ThirdHiTagHelper : TagHelper
{
public int First_Second_ThirdAttribute { get; set; }
}
private class UNSuffixedCLASS : TagHelper
{
public int UNSuffixedATTRIBUTE { get; set; }
}
}
}

View File

@ -25,10 +25,9 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers
{
get
{
return new TagHelperDescriptor("Valid_Plain",
return new TagHelperDescriptor("valid_plain",
Valid_PlainTagHelperType.FullName,
AssemblyName,
ContentBehavior.None);
AssemblyName);
}
}
@ -36,10 +35,9 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers
{
get
{
return new TagHelperDescriptor("Valid_Inherited",
return new TagHelperDescriptor("valid_inherited",
Valid_InheritedTagHelperType.FullName,
AssemblyName,
ContentBehavior.None);
AssemblyName);
}
}
@ -75,8 +73,7 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers
var stringTagHelperDescriptor =
new TagHelperDescriptor("string",
"System.String",
assemblyB,
ContentBehavior.None);
assemblyB);
return new TheoryData<Dictionary<string, IEnumerable<Type>>, // descriptorAssemblyLookups
IEnumerable<TagHelperDirectiveDescriptor>, // directiveDescriptors
@ -230,8 +227,7 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers
var stringTagHelperDescriptor =
new TagHelperDescriptor("string",
"System.String",
assemblyB,
ContentBehavior.None);
assemblyB);
return new TheoryData<Dictionary<string, IEnumerable<Type>>, // descriptorAssemblyLookups
IEnumerable<TagHelperDirectiveDescriptor>> // directiveDescriptors
@ -358,7 +354,7 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers
// Arrange
var tagHelperTypeResolver = new TestTagHelperTypeResolver(TestableTagHelpers)
{
OnGetLibraryDefinedTypes = (assemblyName) =>
OnGetExportedTypes = (assemblyName) =>
{
Assert.Equal("MyAssembly", assemblyName.Name);
}
@ -523,7 +519,7 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers
_lookupValues = lookupValues;
}
internal override IEnumerable<TypeInfo> GetLibraryDefinedTypes(AssemblyName assemblyName)
protected override IEnumerable<TypeInfo> GetExportedTypes(AssemblyName assemblyName)
{
IEnumerable<Type> types;

View File

@ -1,14 +1,76 @@
// Copyright (c) Microsoft Open Technologies, Inc. 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.IO;
using System.Linq;
using System.Threading.Tasks;
using Xunit;
namespace Microsoft.AspNet.Razor.Runtime.TagHelpers
{
public class TagHelperExecutionContextTest
{
[Fact]
public async Task GetChildContentAsync_CachesValue()
{
// Arrange
var writer = new StringWriter();
var expectedContent = string.Empty;
var executionContext = new TagHelperExecutionContext(
"p",
uniqueId: string.Empty,
executeChildContentAsync: () =>
{
if (string.IsNullOrEmpty(expectedContent))
{
expectedContent = "Hello from child content: " + Guid.NewGuid().ToString();
}
writer.Write(expectedContent);
return Task.FromResult(result: true);
},
startWritingScope: () => { },
endWritingScope: () => writer);
// Act
var content1 = await executionContext.GetChildContentAsync();
var content2 = await executionContext.GetChildContentAsync();
// Assert
Assert.Same(content1, content2);
Assert.Equal(expectedContent, content1);
Assert.Equal(expectedContent, content2);
}
[Fact]
public async Task ExecuteChildContentAsync_IsNotMemoized()
{
// Arrange
var childContentExecutionCount = 0;
var executionContext = new TagHelperExecutionContext(
"p",
uniqueId: string.Empty,
executeChildContentAsync: () =>
{
childContentExecutionCount++;
return Task.FromResult(result: true);
},
startWritingScope: () => { },
endWritingScope: () => new StringWriter());
// Act
await executionContext.ExecuteChildContentAsync();
await executionContext.ExecuteChildContentAsync();
await executionContext.ExecuteChildContentAsync();
// Assert
Assert.Equal(3, childContentExecutionCount);
}
public static TheoryData<string, string> DictionaryCaseTestingData
{
get

View File

@ -9,39 +9,65 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers
public class TagHelperOutputTest
{
[Fact]
public void TagName_CannotSetToNullInCtor()
public void TagName_CanSetToNullInCtor()
{
// Arrange & Act
var tagHelperOutput = new TagHelperOutput(null);
// Assert
Assert.Empty(tagHelperOutput.TagName);
Assert.Null(tagHelperOutput.TagName);
}
[Fact]
public void TagName_CannotSetToNull()
public void TagName_CanSetToNull()
{
// Arrange
var tagHelperOutput = new TagHelperOutput("p");
// Act
tagHelperOutput.TagName = null;
// Arrange & Act
var tagHelperOutput = new TagHelperOutput("p")
{
TagName = null
};
// Assert
Assert.Empty(tagHelperOutput.TagName);
Assert.Null(tagHelperOutput.TagName);
}
[Fact]
public void Content_CannotSetToNull()
public void Content_CanSetToNull()
{
// Arrange
var tagHelperOutput = new TagHelperOutput("p");
// Act
tagHelperOutput.Content = null;
// Arrange & Act
var tagHelperOutput = new TagHelperOutput("p")
{
Content = null
};
// Assert
Assert.Empty(tagHelperOutput.Content);
Assert.Null(tagHelperOutput.Content);
}
[Fact]
public void PreContent_CanSetToNull()
{
// Arrange & Act
var tagHelperOutput = new TagHelperOutput("p")
{
PreContent = null
};
// Assert
Assert.Null(tagHelperOutput.PreContent);
}
[Fact]
public void PostContent_CanSetToNull()
{
// Arrange & Act
var tagHelperOutput = new TagHelperOutput("p")
{
PostContent = null
};
// Assert
Assert.Null(tagHelperOutput.PostContent);
}
[Fact]
@ -119,9 +145,10 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers
{
{ "class", "btn" },
{ "something", " spaced " }
});
tagHelperOutput.SelfClosing = true;
})
{
SelfClosing = true
};
// Act
var output = tagHelperOutput.GenerateStartTag();
@ -135,9 +162,10 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers
public void GenerateEndTag_ReturnsNothingIfWhitespaceTagName()
{
// Arrange
var tagHelperOutput = new TagHelperOutput(" "); ;
tagHelperOutput.Content = "Hello World";
var tagHelperOutput = new TagHelperOutput(" ")
{
Content = "Hello World"
};
// Act
var output = tagHelperOutput.GenerateEndTag();
@ -146,13 +174,47 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers
Assert.Empty(output);
}
[Fact]
public void GeneratePreContent_ReturnsPreContent()
{
// Arrange
var tagHelperOutput = new TagHelperOutput("p")
{
PreContent = "Hello World"
};
// Act
var output = tagHelperOutput.GeneratePreContent();
// Assert
Assert.Equal("Hello World", output);
}
[Fact]
public void GeneratePreContent_ReturnsNothingIfSelfClosing()
{
// Arrange
var tagHelperOutput = new TagHelperOutput("p")
{
SelfClosing = true,
PreContent = "Hello World"
};
// Act
var output = tagHelperOutput.GeneratePreContent();
// Assert
Assert.Empty(output);
}
[Fact]
public void GenerateContent_ReturnsContent()
{
// Arrange
var tagHelperOutput = new TagHelperOutput("p");
tagHelperOutput.Content = "Hello World";
var tagHelperOutput = new TagHelperOutput("p")
{
Content = "Hello World"
};
// Act
var output = tagHelperOutput.GenerateContent();
@ -168,11 +230,10 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers
// Arrange
var tagHelperOutput = new TagHelperOutput("p")
{
SelfClosing = true
SelfClosing = true,
Content = "Hello World"
};
tagHelperOutput.Content = "Hello World";
// Act
var output = tagHelperOutput.GenerateContent();
@ -180,6 +241,39 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers
Assert.Empty(output);
}
[Fact]
public void GeneratePostContent_ReturnsPostContent()
{
// Arrange
var tagHelperOutput = new TagHelperOutput("p")
{
PostContent = "Hello World"
};
// Act
var output = tagHelperOutput.GeneratePostContent();
// Assert
Assert.Equal("Hello World", output);
}
[Fact]
public void GeneratePostContent_ReturnsNothingIfSelfClosing()
{
// Arrange
var tagHelperOutput = new TagHelperOutput("p")
{
SelfClosing = true,
PostContent = "Hello World"
};
// Act
var output = tagHelperOutput.GeneratePostContent();
// Assert
Assert.Empty(output);
}
[Fact]
public void GenerateEndTag_ReturnsEndTag()
{
@ -209,6 +303,54 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers
Assert.Empty(output);
}
[Fact]
public void SuppressOutput_Sets_TagName_Content_PreContent_PostContent_ToNull()
{
// Arrange
var tagHelperOutput = new TagHelperOutput("p")
{
PreContent = "Pre Content",
Content = "Content",
PostContent = "Post Content"
};
// Act
tagHelperOutput.SuppressOutput();
// Assert
Assert.Null(tagHelperOutput.TagName);
Assert.Null(tagHelperOutput.PreContent);
Assert.Null(tagHelperOutput.Content);
Assert.Null(tagHelperOutput.PostContent);
}
[Fact]
public void SuppressOutput_PreventsTagOutput()
{
// Arrange
var tagHelperOutput = new TagHelperOutput("p",
attributes: new Dictionary<string, string>
{
{ "class", "btn" },
{ "something", " spaced " }
})
{
PreContent = "Pre Content",
Content = "Content",
PostContent = "Post Content"
};
// Act
tagHelperOutput.SuppressOutput();
// Assert
Assert.Empty(tagHelperOutput.GenerateStartTag());
Assert.Null(tagHelperOutput.GeneratePreContent());
Assert.Null(tagHelperOutput.GenerateContent());
Assert.Null(tagHelperOutput.GeneratePostContent());
Assert.Empty(tagHelperOutput.GenerateEndTag());
}
[Theory]
[InlineData("class", "ClASs")]
[InlineData("CLaSs", "class")]

View File

@ -66,23 +66,6 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers
Assert.Equal("True", output.Attributes["foo"]);
}
[Fact]
public async Task RunAsync_WithContentSetsOutputsContent()
{
// Arrange
var runner = new TagHelperRunner();
var executionContext = new TagHelperExecutionContext("p");
var tagHelper = new ExecutableTagHelper();
var contentWriter = new StringWriter(new StringBuilder("Hello World"));
// Act
executionContext.Add(tagHelper);
var output = await runner.RunAsync(executionContext, contentWriter);
// Assert
Assert.Equal(output.Content, "Hello World");
}
private class ExecutableTagHelper : TagHelper
{
public bool Processed { get; set; }

View File

@ -2,6 +2,8 @@
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using System.IO;
using System.Threading.Tasks;
using Microsoft.AspNet.Razor.Runtime.TagHelpers;
using Xunit;
@ -9,6 +11,11 @@ namespace Microsoft.AspNet.Razor.Runtime.Test.TagHelpers
{
public class TagHelperScopeManagerTest
{
private static readonly Action DefaultStartWritingScope = () => { };
private static readonly Func<TextWriter> DefaultEndWritingScope = () => new StringWriter();
private static readonly Func<Task> DefaultExecuteChildContentAsync =
async () => await Task.FromResult(result: true);
[Fact]
public void Begin_CreatesContextWithAppropriateTagName()
{
@ -16,7 +23,11 @@ namespace Microsoft.AspNet.Razor.Runtime.Test.TagHelpers
var scopeManager = new TagHelperScopeManager();
// Act
var executionContext = scopeManager.Begin("p");
var executionContext = scopeManager.Begin("p",
string.Empty,
DefaultExecuteChildContentAsync,
DefaultStartWritingScope,
DefaultEndWritingScope);
// Assert
Assert.Equal("p", executionContext.TagName);
@ -29,8 +40,16 @@ namespace Microsoft.AspNet.Razor.Runtime.Test.TagHelpers
var scopeManager = new TagHelperScopeManager();
// Act
var executionContext = scopeManager.Begin("p");
executionContext = scopeManager.Begin("div");
var executionContext = scopeManager.Begin("p",
string.Empty,
DefaultExecuteChildContentAsync,
DefaultStartWritingScope,
DefaultEndWritingScope);
executionContext = scopeManager.Begin("div",
string.Empty,
DefaultExecuteChildContentAsync,
DefaultStartWritingScope,
DefaultEndWritingScope);
// Assert
Assert.Equal("div", executionContext.TagName);
@ -43,8 +62,16 @@ namespace Microsoft.AspNet.Razor.Runtime.Test.TagHelpers
var scopeManager = new TagHelperScopeManager();
// Act
var executionContext = scopeManager.Begin("p");
executionContext = scopeManager.Begin("div");
var executionContext = scopeManager.Begin("p",
string.Empty,
DefaultExecuteChildContentAsync,
DefaultStartWritingScope,
DefaultEndWritingScope);
executionContext = scopeManager.Begin("div",
string.Empty,
DefaultExecuteChildContentAsync,
DefaultStartWritingScope,
DefaultEndWritingScope);
executionContext = scopeManager.End();
// Assert
@ -58,8 +85,16 @@ namespace Microsoft.AspNet.Razor.Runtime.Test.TagHelpers
var scopeManager = new TagHelperScopeManager();
// Act
var executionContext = scopeManager.Begin("p");
executionContext = scopeManager.Begin("div");
var executionContext = scopeManager.Begin("p",
string.Empty,
DefaultExecuteChildContentAsync,
DefaultStartWritingScope,
DefaultEndWritingScope);
executionContext = scopeManager.Begin("div",
string.Empty,
DefaultExecuteChildContentAsync,
DefaultStartWritingScope,
DefaultEndWritingScope);
executionContext = scopeManager.End();
executionContext = scopeManager.End();
@ -85,7 +120,6 @@ namespace Microsoft.AspNet.Razor.Runtime.Test.TagHelpers
});
Assert.Equal(expectedError, ex.Message);
}
}
}

View File

@ -114,14 +114,14 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers
public TestTagHelperTypeResolver(IEnumerable<Type> assemblyTypes)
{
_assemblyTypeInfos = assemblyTypes.Select(type => type.GetTypeInfo());
OnGetLibraryDefinedTypes = (_) => { };
OnGetExportedTypes = (_) => { };
}
public Action<AssemblyName> OnGetLibraryDefinedTypes { get; set; }
public Action<AssemblyName> OnGetExportedTypes { get; set; }
internal override IEnumerable<TypeInfo> GetLibraryDefinedTypes(AssemblyName assemblyName)
protected override IEnumerable<TypeInfo> GetExportedTypes(AssemblyName assemblyName)
{
OnGetLibraryDefinedTypes(assemblyName);
OnGetExportedTypes(assemblyName);
return _assemblyTypeInfos;
}

View File

@ -3,15 +3,16 @@
"dependencies": {
"Microsoft.AspNet.Razor.Runtime": "4.0.0-*",
"Microsoft.AspNet.Testing": "1.0.0-*",
"Xunit.KRunner": "1.0.0-*"
"xunit.runner.kre": "1.0.0-*"
},
"commands": {
"test": "Xunit.KRunner"
"test": "xunit.runner.kre"
},
"frameworks": {
"aspnet50": { },
"aspnetcore50": {
"dependencies": {
"System.Reflection.TypeExtensions": "4.0.0-beta-*",
"System.Runtime.Extensions": "4.0.10-beta-*"
}
}

View File

@ -54,7 +54,8 @@ namespace Microsoft.AspNet.Razor.Test
"myclass",
"myns",
string.Empty,
shouldGenerateLinePragmas: false);
shouldGenerateLinePragmas: false,
errorSink: new ParserErrorSink());
// Act
var generator = language.CreateCodeBuilder(codeBuilderContext);

View File

@ -434,28 +434,30 @@ namespace Microsoft.AspNet.Razor.Test.Framework
collector.AddError("{0} - FAILED :: Actual: << Null >>", expected);
}
public static void EvaluateRazorErrors(IList<RazorError> actualErrors, IList<RazorError> expectedErrors)
public static void EvaluateRazorErrors(IEnumerable<RazorError> actualErrors, IList<RazorError> expectedErrors)
{
var realCount = actualErrors.Count();
// Evaluate the errors
if (expectedErrors == null || expectedErrors.Count == 0)
{
Assert.True(actualErrors.Count == 0,
Assert.True(realCount == 0,
String.Format("Expected that no errors would be raised, but the following errors were:\r\n{0}", FormatErrors(actualErrors)));
}
else
{
Assert.True(expectedErrors.Count == actualErrors.Count,
Assert.True(expectedErrors.Count == realCount,
String.Format("Expected that {0} errors would be raised, but {1} errors were.\r\nExpected Errors: \r\n{2}\r\nActual Errors: \r\n{3}",
expectedErrors.Count,
actualErrors.Count,
realCount,
FormatErrors(expectedErrors),
FormatErrors(actualErrors)));
Assert.Equal(expectedErrors.ToArray(), actualErrors.ToArray());
Assert.Equal(expectedErrors, actualErrors);
}
WriteTraceLine("Expected Errors were raised:\r\n{0}", FormatErrors(expectedErrors));
}
public static string FormatErrors(IList<RazorError> errors)
public static string FormatErrors(IEnumerable<RazorError> errors)
{
if (errors == null)
{

View File

@ -300,11 +300,6 @@ namespace Microsoft.AspNet.Razor.Test.Framework
return _self.With(new SetBaseTypeCodeGenerator(baseType));
}
public SpanConstructor AsRazorDirectiveAttribute(string key, string value)
{
return _self.With(new RazorDirectiveAttributeCodeGenerator(key, value));
}
public SpanConstructor AsAddTagHelper(string lookupText)
{
return _self.With(

View File

@ -26,21 +26,18 @@ namespace Microsoft.AspNet.Razor.Test.Generator
new TagHelperDescriptor("p",
"PTagHelper",
"SomeAssembly",
ContentBehavior.None,
new [] {
new TagHelperAttributeDescriptor("age", pAgePropertyInfo)
}),
new TagHelperDescriptor("input",
"InputTagHelper",
"SomeAssembly",
ContentBehavior.None,
new TagHelperAttributeDescriptor[] {
new TagHelperAttributeDescriptor("type", inputTypePropertyInfo)
}),
new TagHelperDescriptor("input",
"InputTagHelper2",
"SomeAssembly",
ContentBehavior.None,
new TagHelperAttributeDescriptor[] {
new TagHelperAttributeDescriptor("type", inputTypePropertyInfo),
new TagHelperAttributeDescriptor("checked", checkedPropertyInfo)
@ -49,21 +46,6 @@ namespace Microsoft.AspNet.Razor.Test.Generator
}
}
private static IEnumerable<TagHelperDescriptor> ContentBehaviorTagHelperDescriptors
{
get
{
return new[]
{
new TagHelperDescriptor("modify", "ModifyTagHelper", "SomeAssembly", ContentBehavior.Modify),
new TagHelperDescriptor("none", "NoneTagHelper", "SomeAssembly", ContentBehavior.None),
new TagHelperDescriptor("append", "AppendTagHelper", "SomeAssembly", ContentBehavior.Append),
new TagHelperDescriptor("prepend", "PrependTagHelper", "SomeAssembly", ContentBehavior.Prepend),
new TagHelperDescriptor("replace", "ReplaceTagHelper", "SomeAssembly", ContentBehavior.Replace)
};
}
}
public static TheoryData TagHelperDescriptorFlowTestData
{
get
@ -109,13 +91,6 @@ namespace Microsoft.AspNet.Razor.Test.Generator
Enumerable.Empty<TagHelperDescriptor>(),
false
},
{
"ContentBehaviorTagHelpers",
"ContentBehaviorTagHelpers",
ContentBehaviorTagHelperDescriptors,
ContentBehaviorTagHelperDescriptors,
false
},
{
"ComplexTagHelpers",
"ComplexTagHelpers",
@ -144,7 +119,7 @@ namespace Microsoft.AspNet.Razor.Test.Generator
bool designTimeMode)
{
RunTagHelperTest(
testName,
testName,
baseLineName: baselineName,
tagHelperDescriptors: tagHelperDescriptors,
onResults: (results) =>
@ -174,7 +149,13 @@ namespace Microsoft.AspNet.Razor.Test.Generator
generatedAbsoluteIndex: 475,
generatedLineIndex: 15,
characterOffsetIndex: 14,
contentLength: 11)
contentLength: 11),
BuildLineMapping(documentAbsoluteIndex: 57,
documentLineIndex: 2,
generatedAbsoluteIndex: 958,
generatedLineIndex: 34,
characterOffsetIndex: 28,
contentLength: 4)
}
},
{
@ -188,21 +169,13 @@ namespace Microsoft.AspNet.Razor.Test.Generator
generatedAbsoluteIndex: 475,
generatedLineIndex: 15,
characterOffsetIndex: 14,
contentLength: 11)
}
},
{
"ContentBehaviorTagHelpers",
"ContentBehaviorTagHelpers.DesignTime",
ContentBehaviorTagHelperDescriptors,
new List<LineMapping>
{
BuildLineMapping(documentAbsoluteIndex: 14,
documentLineIndex: 0,
generatedAbsoluteIndex: 495,
generatedLineIndex: 15,
characterOffsetIndex: 14,
contentLength: 11)
contentLength: 11),
BuildLineMapping(documentAbsoluteIndex: 189,
documentLineIndex: 6,
generatedAbsoluteIndex: 1574,
generatedLineIndex: 44,
characterOffsetIndex: 40,
contentLength: 4)
}
},
{
@ -213,17 +186,32 @@ namespace Microsoft.AspNet.Razor.Test.Generator
{
BuildLineMapping(14, 0, 479, 15, 14, 11),
BuildLineMapping(30, 2, 1, 995, 35, 0, 48),
BuildLineMapping(157, 7, 32, 1177, 45, 6, 12),
BuildLineMapping(205, 9, 1260, 50, 0, 12),
BuildLineMapping(218, 9, 13, 1356, 56, 12, 27),
BuildLineMapping(346, 12, 1754, 68, 0, 48),
BuildLineMapping(440, 15, 46, 2004, 78, 6, 8),
BuildLineMapping(501, 16, 31, 2384, 88, 6, 30),
BuildLineMapping(568, 17, 30, 2733, 97, 0, 10),
BuildLineMapping(601, 17, 63, 2815, 103, 0, 8),
BuildLineMapping(632, 17, 94, 2895, 109, 0, 1),
BuildLineMapping(639, 18, 3149, 118, 0, 15),
BuildLineMapping(680, 21, 3234, 124, 0, 1)
BuildLineMapping(205, 9, 1113, 44, 0, 12),
BuildLineMapping(218, 9, 13, 1209, 50, 12, 27),
BuildLineMapping(346, 12, 1607, 62, 0, 48),
BuildLineMapping(440, 15, 46, 1798, 71, 6, 8),
BuildLineMapping(457, 15, 2121, 79, 63, 4),
BuildLineMapping(501, 16, 31, 2328, 86, 6, 30),
BuildLineMapping(568, 17, 30, 2677, 95, 0, 10),
BuildLineMapping(601, 17, 63, 2759, 101, 0, 8),
BuildLineMapping(632, 17, 94, 2839, 107, 0, 1),
BuildLineMapping(639, 18, 3093, 116, 0, 15),
BuildLineMapping(157, 7, 32, 3242, 123, 6, 12),
BuildLineMapping(719, 21, 3325, 128, 0, 12),
BuildLineMapping(733, 21, 3423, 134, 14, 21),
BuildLineMapping(787, 22, 30, 3680, 142, 28, 7),
BuildLineMapping(685, 20, 17, 3836, 148, 19, 23),
BuildLineMapping(708, 20, 40, 3859, 148, 42, 7),
BuildLineMapping(897, 25, 30, 4101, 155, 28, 30),
BuildLineMapping(831, 24, 16, 4280, 161, 19, 8),
BuildLineMapping(840, 24, 25, 4288, 161, 27, 23),
BuildLineMapping(1026, 28, 4546, 168, 28, 30),
BuildLineMapping(964, 27, 16, 4725, 174, 19, 30),
BuildLineMapping(1156, 31, 4990, 181, 28, 3),
BuildLineMapping(1161, 31, 33, 4993, 181, 31, 27),
BuildLineMapping(1189, 31, 61, 5020, 181, 58, 10),
BuildLineMapping(1094, 30, 18, 5179, 187, 19, 29),
BuildLineMapping(1231, 34, 5279, 192, 0, 1),
}
}
};
@ -256,7 +244,6 @@ namespace Microsoft.AspNet.Razor.Test.Generator
{ "SingleTagHelper", PAndInputTagHelperDescriptors },
{ "BasicTagHelpers", PAndInputTagHelperDescriptors },
{ "BasicTagHelpers.RemoveTagHelper", PAndInputTagHelperDescriptors },
{ "ContentBehaviorTagHelpers", ContentBehaviorTagHelperDescriptors },
{ "ComplexTagHelpers", PAndInputTagHelperDescriptors },
};
}
@ -312,7 +299,7 @@ namespace Microsoft.AspNet.Razor.Test.Generator
RunTagHelperTest("AddTagHelperDirective",
designTimeMode: true,
tagHelperDescriptors: new[] {
new TagHelperDescriptor("p", "pTagHelper", "SomeAssembly", ContentBehavior.None)
new TagHelperDescriptor("p", "pTagHelper", "SomeAssembly")
});
}
@ -328,12 +315,11 @@ namespace Microsoft.AspNet.Razor.Test.Generator
new TagHelperDescriptor("MyTagHelper",
"MyTagHelper",
"SomeAssembly",
ContentBehavior.None,
new [] {
new TagHelperAttributeDescriptor("BoundProperty",
propertyInfo)
}),
new TagHelperDescriptor("NestedTagHelper", "NestedTagHelper", "SomeAssembly", ContentBehavior.Modify)
new TagHelperDescriptor("NestedTagHelper", "NestedTagHelper", "SomeAssembly")
};
// Act & Assert

View File

@ -0,0 +1,188 @@
using System.Collections.Generic;
using Microsoft.AspNet.Razor.Generator;
using Microsoft.AspNet.Razor.Generator.Compiler;
using Microsoft.AspNet.Razor.Generator.Compiler.CSharp;
using Microsoft.AspNet.Razor.Parser;
using Microsoft.AspNet.Razor.TagHelpers;
using Xunit;
namespace Microsoft.AspNet.Razor.Test.Generator
{
public class CSharpTagHelperRenderingUnitTest
{
[Fact]
public void CreatesAUniqueIdForSingleTagHelperChunk()
{
// Arrange
var chunk = CreateTagHelperChunk("div", new[] {
new TagHelperDescriptor("div", "DivTagHelper", "FakeAssemblyName")
});
var codeRenderer = CreateCodeRenderer();
// Act
codeRenderer.RenderTagHelper(chunk);
// Assert
Assert.Equal(1, codeRenderer.GenerateUniqueIdCount);
}
[Fact]
public void UsesTheSameUniqueIdForTagHelperChunkWithMultipleTagHelpers()
{
// Arrange
var chunk = CreateTagHelperChunk("div", new[] {
new TagHelperDescriptor("div", "DivTagHelper", "FakeAssemblyName"),
new TagHelperDescriptor("div", "Div2TagHelper", "FakeAssemblyName")
});
var codeRenderer = CreateCodeRenderer();
// Act
codeRenderer.RenderTagHelper(chunk);
// Assert
Assert.Equal(1, codeRenderer.GenerateUniqueIdCount);
}
[Fact]
public void UsesDifferentUniqueIdForMultipleTagHelperChunksForSameTagHelper()
{
// Arrange
var chunk1 = CreateTagHelperChunk("div", new[] {
new TagHelperDescriptor("div", "DivTagHelper", "FakeAssemblyName")
});
var chunk2 = CreateTagHelperChunk("div", new[] {
new TagHelperDescriptor("div", "DivTagHelper", "FakeAssemblyName")
});
var codeRenderer = CreateCodeRenderer();
// Act
codeRenderer.RenderTagHelper(chunk1);
codeRenderer.RenderTagHelper(chunk2);
// Assert
Assert.Equal(2, codeRenderer.GenerateUniqueIdCount);
}
[Fact]
public void UsesDifferentUniqueIdForNestedTagHelperChunksForSameTagHelper()
{
// Arrange
var parentChunk = CreateTagHelperChunk("div", new[] {
new TagHelperDescriptor("div", "DivTagHelper", "FakeAssemblyName")
});
var childChunk = CreateTagHelperChunk("div", new[] {
new TagHelperDescriptor("div", "DivTagHelper", "FakeAssemblyName")
});
parentChunk.Children.Add(childChunk);
var codeRenderer = CreateCodeRenderer();
// Act
codeRenderer.RenderTagHelper(parentChunk);
// Assert
Assert.Equal(2, codeRenderer.GenerateUniqueIdCount);
}
[Fact]
public void UsesDifferentUniqueIdForMultipleTagHelperChunksForDifferentTagHelpers()
{
// Arrange
var divChunk = CreateTagHelperChunk("div", new[] {
new TagHelperDescriptor("div", "DivTagHelper", "FakeAssemblyName")
});
var spanChunk = CreateTagHelperChunk("span", new[] {
new TagHelperDescriptor("span", "SpanTagHelper", "FakeAssemblyName")
});
var codeRenderer = CreateCodeRenderer();
// Act
codeRenderer.RenderTagHelper(divChunk);
codeRenderer.RenderTagHelper(spanChunk);
// Assert
Assert.Equal(2, codeRenderer.GenerateUniqueIdCount);
}
[Fact]
public void UsesCorrectUniqueIdForMultipleTagHelperChunksSomeWithSameSameTagHelpersSomeWithDifferentTagHelpers()
{
// Arrange
var chunk1 = CreateTagHelperChunk("div", new[] {
new TagHelperDescriptor("div", "DivTagHelper", "FakeAssemblyName"),
new TagHelperDescriptor("div", "Div2TagHelper", "FakeAssemblyName")
});
var chunk2 = CreateTagHelperChunk("span", new[] {
new TagHelperDescriptor("span", "SpanTagHelper", "FakeAssemblyName")
});
var chunk3 = CreateTagHelperChunk("span", new[] {
new TagHelperDescriptor("span", "SpanTagHelper", "FakeAssemblyName"),
new TagHelperDescriptor("span", "Span2TagHelper", "FakeAssemblyName")
});
var codeRenderer = CreateCodeRenderer();
// Act
codeRenderer.RenderTagHelper(chunk1);
codeRenderer.RenderTagHelper(chunk2);
codeRenderer.RenderTagHelper(chunk3);
// Assert
Assert.Equal(3, codeRenderer.GenerateUniqueIdCount);
}
private static TagHelperChunk CreateTagHelperChunk(string tagName, IEnumerable<TagHelperDescriptor> tagHelperDescriptors)
{
return new TagHelperChunk
{
TagName = tagName,
Descriptors = tagHelperDescriptors,
Children = new List<Chunk>(),
Attributes = new Dictionary<string, Chunk>()
};
}
private static TrackingUniqueIdsTagHelperCodeRenderer CreateCodeRenderer()
{
var writer = new CSharpCodeWriter();
var codeBuilderContext = CreateContext();
var visitor = new CSharpCodeVisitor(writer, codeBuilderContext);
var codeRenderer = new TrackingUniqueIdsTagHelperCodeRenderer(
visitor,
writer,
codeBuilderContext);
visitor.TagHelperRenderer = codeRenderer;
return codeRenderer;
}
private static CodeBuilderContext CreateContext()
{
return new CodeBuilderContext(
new CodeGeneratorContext(
new RazorEngineHost(new CSharpRazorCodeLanguage()),
"MyClass",
"MyNamespace",
string.Empty,
shouldGenerateLinePragmas: true),
new ParserErrorSink());
}
private class TrackingUniqueIdsTagHelperCodeRenderer : CSharpTagHelperCodeRenderer
{
public TrackingUniqueIdsTagHelperCodeRenderer(
IChunkVisitor bodyVisitor,
CSharpCodeWriter writer,
CodeBuilderContext context)
: base(bodyVisitor, writer, context)
{
}
protected override string GenerateUniqueId()
{
GenerateUniqueIdCount++;
return "test";
}
public int GenerateUniqueIdCount { get; private set; }
}
}
}

View File

@ -3,6 +3,7 @@
#if !ASPNETCORE50
using Microsoft.AspNet.Razor.Generator;
using Microsoft.AspNet.Razor.Parser;
using Microsoft.AspNet.Razor.Parser.SyntaxTree;
using Microsoft.AspNet.Razor.Test.Utils;
using Moq;
@ -23,7 +24,8 @@ namespace Microsoft.AspNet.Razor.Test.Generator.CodeTree
"TestClass",
"TestNamespace",
"Foo.cs",
shouldGenerateLinePragmas: false);
shouldGenerateLinePragmas: false,
errorSink: new ParserErrorSink());
codeBuilderContext.CodeTreeBuilder.AddUsingChunk("FakeNamespace1", syntaxTreeNode.Object);
codeBuilderContext.CodeTreeBuilder.AddUsingChunk("FakeNamespace2.SubNamespace", syntaxTreeNode.Object);
var codeBuilder = language.CreateCodeBuilder(codeBuilderContext);

View File

@ -4,6 +4,7 @@
#if !ASPNETCORE50
using Microsoft.AspNet.Razor.Generator;
using Microsoft.AspNet.Razor.Generator.Compiler;
using Microsoft.AspNet.Razor.Parser;
using Moq;
using Moq.Protected;
using Xunit;
@ -34,7 +35,8 @@ namespace Microsoft.AspNet.Razor
"myclass",
"myns",
string.Empty,
shouldGenerateLinePragmas: false);
shouldGenerateLinePragmas: false,
errorSink: new ParserErrorSink());
var writer = Mock.Of<CodeWriter>();
return new Mock<ChunkVisitor<CodeWriter>>(writer, codeBuilderContext);
}

View File

@ -181,17 +181,13 @@ namespace Microsoft.AspNet.Razor.Test.Generator
if (expectedDesignTimePragmas != null)
{
Assert.True(results.DesignTimeLineMappings != null && results.DesignTimeLineMappings.Count > 0);
Assert.True(results.DesignTimeLineMappings != null); // Guard
for (var i = 0; i < expectedDesignTimePragmas.Count && i < results.DesignTimeLineMappings.Count; i++)
{
Assert.Equal(expectedDesignTimePragmas[i], results.DesignTimeLineMappings[i]);
}
Assert.Equal(expectedDesignTimePragmas.Count, results.DesignTimeLineMappings.Count);
for (var i = 0; i < expectedDesignTimePragmas.Count; i++)
{
if (!expectedDesignTimePragmas[i].Equals(results.DesignTimeLineMappings[i]))
{
Assert.True(false, String.Format("Line mapping {0} is not equivalent.", i));
}
}
}
}
}

View File

@ -23,18 +23,16 @@ namespace Microsoft.AspNet.Razor.Test.Generator
var checkedPropertyInfo = typeof(TestType).GetProperty("Checked");
var tagHelperDescriptors = new TagHelperDescriptor[]
{
new TagHelperDescriptor("p", "PTagHelper", "SomeAssembly", ContentBehavior.None),
new TagHelperDescriptor("p", "PTagHelper", "SomeAssembly"),
new TagHelperDescriptor("input",
"InputTagHelper",
"SomeAssembly",
ContentBehavior.None,
new TagHelperAttributeDescriptor[] {
new TagHelperAttributeDescriptor("type", inputTypePropertyInfo)
}),
new TagHelperDescriptor("input",
"InputTagHelper2",
"SomeAssembly",
ContentBehavior.None,
new TagHelperAttributeDescriptor[] {
new TagHelperAttributeDescriptor("type", inputTypePropertyInfo),
new TagHelperAttributeDescriptor("checked", checkedPropertyInfo)
@ -65,7 +63,7 @@ namespace Microsoft.AspNet.Razor.Test.Generator
}
}
private class AttributeCodeGeneratorReplacingCodeBuilder : CSharpCodeBuilder
private class AttributeCodeGeneratorReplacingCodeBuilder : TestCSharpCodeBuilder
{
public AttributeCodeGeneratorReplacingCodeBuilder(CodeBuilderContext context)
: base(context)
@ -88,11 +86,12 @@ namespace Microsoft.AspNet.Razor.Test.Generator
public override void RenderAttributeValue([NotNull] TagHelperAttributeDescriptor attributeInfo,
[NotNull] CSharpCodeWriter writer,
[NotNull] CodeBuilderContext context,
[NotNull] Action<CSharpCodeWriter> renderAttributeValue)
[NotNull] Action<CSharpCodeWriter> renderAttributeValue,
bool complexValue)
{
writer.Write("**From custom attribute code renderer**: ");
base.RenderAttributeValue(attributeInfo, writer, context, renderAttributeValue);
base.RenderAttributeValue(attributeInfo, writer, context, renderAttributeValue, complexValue);
}
}

View File

@ -5,7 +5,9 @@ using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using Microsoft.AspNet.Razor.Generator;
using Microsoft.AspNet.Razor.Generator.Compiler;
using Microsoft.AspNet.Razor.Generator.Compiler.CSharp;
using Microsoft.AspNet.Razor.Parser;
using Microsoft.AspNet.Razor.TagHelpers;
using Xunit;
@ -78,6 +80,11 @@ namespace Microsoft.AspNet.Razor.Test.Generator
_tagHelperDescriptors = tagHelperDescriptors;
}
protected internal override CodeBuilder CreateCodeBuilder(CodeBuilderContext context)
{
return Host.DecorateCodeBuilder(new TestCSharpCodeBuilder(context), context);
}
protected internal override RazorParser CreateParser(string fileName)
{
var parser = base.CreateParser(fileName);
@ -87,5 +94,37 @@ namespace Microsoft.AspNet.Razor.Test.Generator
new CustomTagHelperDescriptorResolver(_tagHelperDescriptors));
}
}
protected class TestCSharpCodeBuilder : CSharpCodeBuilder
{
public TestCSharpCodeBuilder(CodeBuilderContext context)
: base(context)
{
}
protected override CSharpCodeVisitor CreateCSharpCodeVisitor(CSharpCodeWriter writer, CodeBuilderContext context)
{
var visitor = base.CreateCSharpCodeVisitor(writer, context);
visitor.TagHelperRenderer = new NoUniqueIdsTagHelperCodeRenderer(visitor, writer, context);
return visitor;
}
private class NoUniqueIdsTagHelperCodeRenderer : CSharpTagHelperCodeRenderer
{
public NoUniqueIdsTagHelperCodeRenderer(IChunkVisitor bodyVisitor,
CSharpCodeWriter writer,
CodeBuilderContext context)
: base(bodyVisitor, writer, context)
{
}
protected override string GenerateUniqueId()
{
return "test";
}
}
}
}
}

View File

@ -247,32 +247,6 @@ namespace Microsoft.AspNet.Razor.Test.Parser.CSharp
.AsBaseType("$rootnamespace$.MyBase")));
}
[Fact]
public void SessionStateDirectiveWorks()
{
ParseBlockTest("@sessionstate InProc",
new DirectiveBlock(
Factory.CodeTransition(),
Factory.MetaCode(SyntaxConstants.CSharp.SessionStateKeyword + " ")
.Accepts(AcceptedCharacters.None),
Factory.Code("InProc")
.AsRazorDirectiveAttribute("sessionstate", "InProc")
));
}
[Fact]
public void SessionStateDirectiveParsesInvalidSessionValue()
{
ParseBlockTest("@sessionstate Blah",
new DirectiveBlock(
Factory.CodeTransition(),
Factory.MetaCode(SyntaxConstants.CSharp.SessionStateKeyword + " ")
.Accepts(AcceptedCharacters.None),
Factory.Code("Blah")
.AsRazorDirectiveAttribute("sessionstate", "Blah")
));
}
[Fact]
public void FunctionsDirective()
{

View File

@ -190,7 +190,7 @@ namespace Microsoft.AspNet.Razor.Test.Parser.Html
var rewritten = rewritingContext.SyntaxTree;
// Assert
Assert.Equal(0, results.ParserErrors.Count);
Assert.Equal(0, results.ParserErrors.Count());
EvaluateParseTree(rewritten,
new MarkupBlock(
new MarkupTagBlock(
@ -277,7 +277,7 @@ namespace Microsoft.AspNet.Razor.Test.Parser.Html
var rewritten = rewritingContext.SyntaxTree;
// Assert
Assert.Equal(0, results.ParserErrors.Count);
Assert.Equal(0, results.ParserErrors.Count());
Assert.Equal(rewritten.Children.Count(), results.Document.Children.Count());
}

View File

@ -19,9 +19,10 @@ namespace Microsoft.AspNet.Razor.Test.Parser
public void VisitThrowsOnNullVisitor()
{
ParserVisitor target = null;
var errorSink = new ParserErrorSink();
var results = new ParserResults(new BlockBuilder() { Type = BlockType.Comment }.Build(),
Enumerable.Empty<TagHelperDescriptor>(),
parserErrors: new List<RazorError>());
errorSink);
Assert.Throws<ArgumentNullException>("self", () => target.Visit(results));
}
@ -39,9 +40,10 @@ namespace Microsoft.AspNet.Razor.Test.Parser
// Arrange
Mock<ParserVisitor> targetMock = new Mock<ParserVisitor>();
var root = new BlockBuilder() { Type = BlockType.Comment }.Build();
var errorSink = new ParserErrorSink();
var results = new ParserResults(root,
Enumerable.Empty<TagHelperDescriptor>(),
parserErrors: new List<RazorError>());
errorSink);
// Act
targetMock.Object.Visit(results);
@ -56,11 +58,17 @@ namespace Microsoft.AspNet.Razor.Test.Parser
// Arrange
Mock<ParserVisitor> targetMock = new Mock<ParserVisitor>();
var root = new BlockBuilder() { Type = BlockType.Comment }.Build();
List<RazorError> errors = new List<RazorError>() {
var errorSink = new ParserErrorSink();
List<RazorError> errors = new List<RazorError>
{
new RazorError("Foo", 1, 0, 1),
new RazorError("Bar", 2, 0, 2)
new RazorError("Bar", 2, 0, 2),
};
var results = new ParserResults(root, Enumerable.Empty<TagHelperDescriptor>(), errors);
foreach (var error in errors)
{
errorSink.OnError(error);
}
var results = new ParserResults(root, Enumerable.Empty<TagHelperDescriptor>(), errorSink);
// Act
targetMock.Object.Visit(results);
@ -76,11 +84,10 @@ namespace Microsoft.AspNet.Razor.Test.Parser
// Arrange
Mock<ParserVisitor> targetMock = new Mock<ParserVisitor>();
var root = new BlockBuilder() { Type = BlockType.Comment }.Build();
List<RazorError> errors = new List<RazorError>() {
new RazorError("Foo", 1, 0, 1),
new RazorError("Bar", 2, 0, 2)
};
var results = new ParserResults(root, Enumerable.Empty<TagHelperDescriptor>(), errors);
var errorSink = new ParserErrorSink();
errorSink.OnError(new RazorError("Foo", 1, 0, 1));
errorSink.OnError(new RazorError("Bar", 2, 0, 2));
var results = new ParserResults(root, Enumerable.Empty<TagHelperDescriptor>(), errorSink);
// Act
targetMock.Object.Visit(results);

View File

@ -119,7 +119,8 @@ namespace Microsoft.AspNet.Razor.Test
"different-class",
"different-ns",
string.Empty,
shouldGenerateLinePragmas: true);
shouldGenerateLinePragmas: true,
errorSink: new ParserErrorSink());
var expected = new CSharpCodeBuilder(codeBuilderContext);

View File

@ -168,8 +168,10 @@ namespace Microsoft.AspNet.Razor.TagHelpers
new ParserErrorSink());
var document = new MarkupBlock(Factory.Markup("Hello World"));
// Act & Assert
Assert.DoesNotThrow(() => addOrRemoveTagHelperSpanVisitor.GetDescriptors(document));
// Act
var descriptors = addOrRemoveTagHelperSpanVisitor.GetDescriptors(document);
Assert.Empty(descriptors);
}
private class TestTagHelperDescriptorResolver : ITagHelperDescriptorResolver

View File

@ -13,8 +13,8 @@ namespace Microsoft.AspNet.Razor.Test.TagHelpers
public void TagHelperDescriptorProvider_GetTagHelpersReturnsNothingForUnregisteredTags()
{
// Arrange
var divDescriptor = new TagHelperDescriptor("div", "foo1", "SomeAssembly", ContentBehavior.None);
var spanDescriptor = new TagHelperDescriptor("span", "foo2", "SomeAssembly", ContentBehavior.None);
var divDescriptor = new TagHelperDescriptor("div", "foo1", "SomeAssembly");
var spanDescriptor = new TagHelperDescriptor("span", "foo2", "SomeAssembly");
var descriptors = new TagHelperDescriptor[] { divDescriptor, spanDescriptor };
var provider = new TagHelperDescriptorProvider(descriptors);
@ -29,9 +29,9 @@ namespace Microsoft.AspNet.Razor.Test.TagHelpers
public void TagHelperDescriptorProvider_GetTagHelpersDoesNotReturnNonCatchAllTagsForCatchAll()
{
// Arrange
var divDescriptor = new TagHelperDescriptor("div", "foo1", "SomeAssembly", ContentBehavior.None);
var spanDescriptor = new TagHelperDescriptor("span", "foo2", "SomeAssembly", ContentBehavior.None);
var catchAllDescriptor = new TagHelperDescriptor("*", "foo3", "SomeAssembly", ContentBehavior.None);
var divDescriptor = new TagHelperDescriptor("div", "foo1", "SomeAssembly");
var spanDescriptor = new TagHelperDescriptor("span", "foo2", "SomeAssembly");
var catchAllDescriptor = new TagHelperDescriptor("*", "foo3", "SomeAssembly");
var descriptors = new TagHelperDescriptor[] { divDescriptor, spanDescriptor, catchAllDescriptor };
var provider = new TagHelperDescriptorProvider(descriptors);
@ -47,9 +47,9 @@ namespace Microsoft.AspNet.Razor.Test.TagHelpers
public void TagHelperDescriptorProvider_GetTagHelpersReturnsCatchAllsWithEveryTagName()
{
// Arrange
var divDescriptor = new TagHelperDescriptor("div", "foo1", "SomeAssembly", ContentBehavior.None);
var spanDescriptor = new TagHelperDescriptor("span", "foo2", "SomeAssembly", ContentBehavior.None);
var catchAllDescriptor = new TagHelperDescriptor("*", "foo3", "SomeAssembly", ContentBehavior.None);
var divDescriptor = new TagHelperDescriptor("div", "foo1", "SomeAssembly");
var spanDescriptor = new TagHelperDescriptor("span", "foo2", "SomeAssembly");
var catchAllDescriptor = new TagHelperDescriptor("*", "foo3", "SomeAssembly");
var descriptors = new TagHelperDescriptor[] { divDescriptor, spanDescriptor, catchAllDescriptor };
var provider = new TagHelperDescriptorProvider(descriptors);
@ -73,7 +73,7 @@ namespace Microsoft.AspNet.Razor.Test.TagHelpers
public void TagHelperDescriptorProvider_DuplicateDescriptorsAreNotPartOfTagHelperDescriptorPool()
{
// Arrange
var divDescriptor = new TagHelperDescriptor("div", "foo1", "SomeAssembly", ContentBehavior.None);
var divDescriptor = new TagHelperDescriptor("div", "foo1", "SomeAssembly");
var descriptors = new TagHelperDescriptor[] { divDescriptor, divDescriptor };
var provider = new TagHelperDescriptorProvider(descriptors);

View File

@ -19,6 +19,430 @@ namespace Microsoft.AspNet.Razor.Test.TagHelpers
{
public class TagHelperParseTreeRewriterTest : CsHtmlMarkupParserTestBase
{
public static TheoryData<string, MarkupBlock, RazorError[]> MalformedTagHelperAttributeBlockData
{
get
{
var factory = CreateDefaultSpanFactory();
var blockFactory = new BlockFactory(factory);
var errorFormatUnclosed = "Found a malformed '{0}' tag helper. Tag helpers must have a start and " +
"end tag or be self closing.";
var errorFormatNoCloseAngle = "Missing close angle for tag helper '{0}'.";
var errorFormatNoCSharp = "The tag helper '{0}' must not have C# in the element's attribute " +
"declaration area.";
Func<string, Block> createInvalidDoBlock = extraCode =>
{
return new MarkupBlock(
new MarkupBlock(
new StatementBlock(
factory.CodeTransition(),
factory.Code("do {" + extraCode).AsStatement())));
};
var dateTimeNow = new MarkupBlock(
new MarkupBlock(
new ExpressionBlock(
factory.CodeTransition(),
factory.Code("DateTime.Now")
.AsImplicitExpression(CSharpCodeParser.DefaultKeywords)
.Accepts(AcceptedCharacters.NonWhiteSpace))));
return new TheoryData<string, MarkupBlock, RazorError[]>
{
{
"<p =\"false\"\" ></p>",
new MarkupBlock(
new MarkupTagHelperBlock("p",
new Dictionary<string, SyntaxTreeNode>())),
new []
{
new RazorError(
string.Format(CultureInfo.InvariantCulture, errorFormatUnclosed, "p"),
SourceLocation.Zero)
}
},
{
"<p bar=\"false\"\" <strong>",
new MarkupBlock(
new MarkupTagHelperBlock("p",
new Dictionary<string, SyntaxTreeNode>
{
{ "bar", factory.Markup("false") }
})),
new []
{
new RazorError(
string.Format(CultureInfo.InvariantCulture, errorFormatUnclosed, "p"),
SourceLocation.Zero)
}
},
{
"<p bar='false <strong>",
new MarkupBlock(
new MarkupTagHelperBlock("p",
new Dictionary<string, SyntaxTreeNode>
{
{ "bar", new MarkupBlock(factory.Markup("false"), factory.Markup(" <strong>")) }
})),
new []
{
new RazorError(
string.Format(CultureInfo.InvariantCulture, errorFormatNoCloseAngle, "p"),
SourceLocation.Zero),
new RazorError(
string.Format(CultureInfo.InvariantCulture, errorFormatUnclosed, "p"),
SourceLocation.Zero)
}
},
{
"<p foo bar<strong>",
new MarkupBlock(
new MarkupTagHelperBlock("p",
new MarkupTagHelperBlock("strong"))),
new []
{
new RazorError(
string.Format(CultureInfo.InvariantCulture, errorFormatNoCloseAngle, "p"),
SourceLocation.Zero),
new RazorError(
string.Format(CultureInfo.InvariantCulture, errorFormatUnclosed, "p"),
SourceLocation.Zero),
new RazorError(
string.Format(CultureInfo.InvariantCulture, errorFormatUnclosed, "strong"),
absoluteIndex: 10, lineIndex: 0, columnIndex: 10)
}
},
{
"<p class=btn\" bar<strong>",
new MarkupBlock(
new MarkupTagHelperBlock("p",
new Dictionary<string, SyntaxTreeNode>
{
{ "class", factory.Markup("btn") }
})),
new []
{
new RazorError(
string.Format(CultureInfo.InvariantCulture, errorFormatUnclosed, "p"),
SourceLocation.Zero)
}
},
{
"<p class=btn\" bar=\"foo\"<strong>",
new MarkupBlock(
new MarkupTagHelperBlock("p",
new Dictionary<string, SyntaxTreeNode>
{
{ "class", factory.Markup("btn") }
})),
new []
{
new RazorError(
string.Format(CultureInfo.InvariantCulture, errorFormatUnclosed, "p"),
SourceLocation.Zero)
}
},
{
"<p class=\"btn bar=\"foo\"<strong>",
new MarkupBlock(
new MarkupTagHelperBlock("p",
new Dictionary<string, SyntaxTreeNode>
{
{ "class", new MarkupBlock(factory.Markup("btn"), factory.Markup(" bar=")) },
{ "foo", factory.Markup(string.Empty) }
},
new MarkupTagHelperBlock("strong"))),
new []
{
new RazorError(
string.Format(CultureInfo.InvariantCulture, errorFormatNoCloseAngle, "p"),
SourceLocation.Zero),
new RazorError(
string.Format(CultureInfo.InvariantCulture, errorFormatUnclosed, "p"),
SourceLocation.Zero),
new RazorError(
string.Format(CultureInfo.InvariantCulture, errorFormatUnclosed, "strong"),
absoluteIndex: 23, lineIndex: 0, columnIndex: 23)
}
},
{
"<p class=\"btn bar=\"foo\"></p>",
new MarkupBlock(
new MarkupTagHelperBlock("p",
new Dictionary<string, SyntaxTreeNode>
{
{ "class", new MarkupBlock(factory.Markup("btn"), factory.Markup(" bar=")) },
})),
new RazorError[0]
},
{
"<p @DateTime.Now class=\"btn\"></p>",
new MarkupBlock(
new MarkupTagHelperBlock("p")),
new []
{
new RazorError(
string.Format(CultureInfo.InvariantCulture, errorFormatNoCSharp, "p"),
absoluteIndex: 3, lineIndex: 0 , columnIndex: 3)
}
},
{
"<p @DateTime.Now=\"btn\"></p>",
new MarkupBlock(
new MarkupTagHelperBlock("p")),
new []
{
new RazorError(
string.Format(CultureInfo.InvariantCulture, errorFormatNoCSharp, "p"),
absoluteIndex: 3, lineIndex: 0 , columnIndex: 3)
}
},
{
"<p class=@DateTime.Now\"></p>",
new MarkupBlock(
new MarkupTagHelperBlock("p",
new Dictionary<string, SyntaxTreeNode>
{
{ "class", dateTimeNow }
})),
new []
{
new RazorError(
string.Format(CultureInfo.InvariantCulture, errorFormatUnclosed, "p"),
SourceLocation.Zero)
}
},
{
"<p class=\"@do {",
new MarkupBlock(
new MarkupTagHelperBlock("p",
new Dictionary<string, SyntaxTreeNode>
{
{ "class", createInvalidDoBlock(string.Empty) }
})),
new []
{
new RazorError(
string.Format(CultureInfo.InvariantCulture, errorFormatNoCloseAngle, "p"),
SourceLocation.Zero),
new RazorError(
string.Format(CultureInfo.InvariantCulture, errorFormatUnclosed, "p"),
SourceLocation.Zero),
new RazorError(
RazorResources.FormatParseError_Expected_EndOfBlock_Before_EOF("do", "}", "{"),
absoluteIndex: 11, lineIndex: 0, columnIndex: 11)
}
},
{
"<p class=\"@do {\"></p>",
new MarkupBlock(
new MarkupTagHelperBlock("p",
new Dictionary<string, SyntaxTreeNode>
{
{ "class", createInvalidDoBlock("\"></p>") }
})),
new []
{
new RazorError(
string.Format(CultureInfo.InvariantCulture, errorFormatNoCloseAngle, "p"),
SourceLocation.Zero),
new RazorError(
string.Format(CultureInfo.InvariantCulture, errorFormatUnclosed, "p"),
SourceLocation.Zero),
new RazorError(
RazorResources.FormatParseError_Expected_EndOfBlock_Before_EOF("do", "}", "{"),
absoluteIndex: 11, lineIndex: 0, columnIndex: 11),
new RazorError(
RazorResources.ParseError_Unterminated_String_Literal,
absoluteIndex: 15, lineIndex: 0, columnIndex: 15)
}
},
{
"<p @do { someattribute=\"btn\"></p>",
new MarkupBlock(
new MarkupTagHelperBlock("p")),
new []
{
new RazorError(
string.Format(CultureInfo.InvariantCulture, errorFormatNoCloseAngle, "p"),
SourceLocation.Zero),
new RazorError(
string.Format(CultureInfo.InvariantCulture, errorFormatUnclosed, "p"),
SourceLocation.Zero),
new RazorError(
string.Format(CultureInfo.InvariantCulture, errorFormatNoCSharp, "p"),
absoluteIndex: 3, lineIndex: 0 , columnIndex: 3),
new RazorError(
RazorResources.FormatParseError_Expected_EndOfBlock_Before_EOF("do", "}", "{"),
absoluteIndex: 4, lineIndex: 0, columnIndex: 4),
new RazorError(
RazorResources.FormatParseError_UnexpectedEndTag("p"),
absoluteIndex: 29, lineIndex: 0, columnIndex: 29)
}
}
};
}
}
[Theory]
[MemberData(nameof(MalformedTagHelperAttributeBlockData))]
public void Rewrite_CreatesErrorForMalformedTagHelpersWithAttributes(
string documentContent,
MarkupBlock expectedOutput,
RazorError[] expectedErrors)
{
RunParseTreeRewriterTest(documentContent, expectedOutput, expectedErrors, "strong", "p");
}
public static TheoryData<string, MarkupBlock, RazorError[]> MalformedTagHelperBlockData
{
get
{
var factory = CreateDefaultSpanFactory();
var blockFactory = new BlockFactory(factory);
var errorFormatUnclosed = "Found a malformed '{0}' tag helper. Tag helpers must have a start and " +
"end tag or be self closing.";
var errorFormatNoCloseAngle = "Missing close angle for tag helper '{0}'.";
return new TheoryData<string, MarkupBlock, RazorError[]>
{
{
"<p",
new MarkupBlock(
new MarkupTagHelperBlock("p")),
new []
{
new RazorError(
string.Format(CultureInfo.InvariantCulture, errorFormatNoCloseAngle, "p"),
SourceLocation.Zero),
new RazorError(
string.Format(CultureInfo.InvariantCulture, errorFormatUnclosed, "p"),
SourceLocation.Zero)
}
},
{
"<p></p",
new MarkupBlock(
new MarkupTagHelperBlock("p")),
new []
{
new RazorError(
string.Format(CultureInfo.InvariantCulture, errorFormatNoCloseAngle, "p"),
absoluteIndex: 3, lineIndex: 0, columnIndex: 3)
}
},
{
"<p><strong",
new MarkupBlock(
new MarkupTagHelperBlock("p",
new MarkupTagHelperBlock("strong"))),
new []
{
new RazorError(
string.Format(CultureInfo.InvariantCulture, errorFormatUnclosed, "p"),
SourceLocation.Zero),
new RazorError(
string.Format(CultureInfo.InvariantCulture, errorFormatNoCloseAngle, "strong"),
absoluteIndex: 3, lineIndex: 0, columnIndex: 3),
new RazorError(
string.Format(CultureInfo.InvariantCulture, errorFormatUnclosed, "strong"),
absoluteIndex: 3, lineIndex: 0, columnIndex: 3)
}
},
{
"<strong <p>",
new MarkupBlock(
new MarkupTagHelperBlock("strong",
new MarkupTagHelperBlock("p"))),
new []
{
new RazorError(
string.Format(CultureInfo.InvariantCulture, errorFormatNoCloseAngle, "strong"),
SourceLocation.Zero),
new RazorError(
string.Format(CultureInfo.InvariantCulture, errorFormatUnclosed, "strong"),
SourceLocation.Zero),
new RazorError(
string.Format(CultureInfo.InvariantCulture, errorFormatUnclosed, "p"),
absoluteIndex: 8, lineIndex: 0, columnIndex: 8)
}
},
{
"<strong </strong",
new MarkupBlock(
new MarkupTagHelperBlock("strong")),
new []
{
new RazorError(
string.Format(CultureInfo.InvariantCulture, errorFormatNoCloseAngle, "strong"),
SourceLocation.Zero),
new RazorError(
string.Format(CultureInfo.InvariantCulture, errorFormatNoCloseAngle, "strong"),
absoluteIndex: 8, lineIndex: 0, columnIndex: 8)
}
},
{
"<<</strong> <<p>",
new MarkupBlock(
blockFactory.MarkupTagBlock("<"),
blockFactory.MarkupTagBlock("<"),
blockFactory.MarkupTagBlock("</strong>"),
factory.Markup(" "),
blockFactory.MarkupTagBlock("<"),
new MarkupTagHelperBlock("p")),
new []
{
new RazorError(
string.Format(CultureInfo.InvariantCulture, errorFormatUnclosed, "strong"),
absoluteIndex: 2, lineIndex: 0, columnIndex: 2),
new RazorError(
string.Format(CultureInfo.InvariantCulture, errorFormatUnclosed, "p"),
absoluteIndex: 13, lineIndex: 0, columnIndex: 13)
}
},
{
"<<<strong>> <<>>",
new MarkupBlock(
blockFactory.MarkupTagBlock("<"),
blockFactory.MarkupTagBlock("<"),
new MarkupTagHelperBlock("strong",
factory.Markup("> "),
blockFactory.MarkupTagBlock("<"),
blockFactory.MarkupTagBlock("<>"),
factory.Markup(">"))),
new []
{
new RazorError(
string.Format(CultureInfo.InvariantCulture, errorFormatUnclosed, "strong"),
absoluteIndex: 2, lineIndex: 0, columnIndex: 2)
}
},
{
"<str<strong></p></strong>",
new MarkupBlock(
blockFactory.MarkupTagBlock("<str"),
new MarkupTagHelperBlock("strong",
blockFactory.MarkupTagBlock("</p>"))),
new []
{
new RazorError(
string.Format(CultureInfo.InvariantCulture, errorFormatUnclosed, "p"),
absoluteIndex: 12, lineIndex: 0, columnIndex: 12)
}
}
};
}
}
[Theory]
[MemberData(nameof(MalformedTagHelperBlockData))]
public void Rewrite_CreatesErrorForMalformedTagHelper(
string documentContent,
MarkupBlock expectedOutput,
RazorError[] expectedErrors)
{
RunParseTreeRewriterTest(documentContent, expectedOutput, expectedErrors, "strong", "p");
}
public static TheoryData CodeTagHelperAttributesData
{
get
@ -94,7 +518,7 @@ namespace Microsoft.AspNet.Razor.Test.TagHelpers
// Arrange
var descriptors = new TagHelperDescriptor[]
{
new TagHelperDescriptor("person", "PersonTagHelper", "personAssembly", ContentBehavior.None,
new TagHelperDescriptor("person", "PersonTagHelper", "personAssembly",
attributes: new[]
{
new TagHelperAttributeDescriptor("age", "Age", typeof(int).FullName),
@ -105,9 +529,9 @@ namespace Microsoft.AspNet.Razor.Test.TagHelpers
var providerContext = new TagHelperDescriptorProvider(descriptors);
// Act & Assert
EvaluateData(providerContext,
documentContent,
expectedOutput,
EvaluateData(providerContext,
documentContent,
expectedOutput,
expectedErrors: Enumerable.Empty<RazorError>());
}
@ -117,8 +541,8 @@ namespace Microsoft.AspNet.Razor.Test.TagHelpers
{
var factory = CreateDefaultSpanFactory();
var blockFactory = new BlockFactory(factory);
var errorFormat = "Found a malformed '{0}' tag helper. Tag helpers must have a start and end tag or " +
"be self closing.";
var malformedErrorFormat = "Found a malformed '{0}' tag helper. Tag helpers must have a start and " +
"end tag or be self closing.";
var dateTimeNow = new MarkupBlock(
new ExpressionBlock(
factory.CodeTransition(),
@ -130,16 +554,23 @@ namespace Microsoft.AspNet.Razor.Test.TagHelpers
"<p class=foo dynamic=@DateTime.Now style=color:red;><strong></p></strong>",
new MarkupBlock(
new MarkupTagHelperBlock("p",
new Dictionary<string, SyntaxTreeNode>
{
{ "class", factory.Markup("foo") },
{ "dynamic", new MarkupBlock(dateTimeNow) },
{ "style", factory.Markup("color:red;") }
},
new MarkupTagHelperBlock("strong",
blockFactory.MarkupTagBlock("</p>")))),
new RazorError(string.Format(CultureInfo.InvariantCulture, errorFormat, "p"),
SourceLocation.Zero)
new Dictionary<string, SyntaxTreeNode>
{
{ "class", factory.Markup("foo") },
{ "dynamic", new MarkupBlock(dateTimeNow) },
{ "style", factory.Markup("color:red;") }
},
new MarkupTagHelperBlock("strong")),
blockFactory.MarkupTagBlock("</strong>")),
new RazorError[]
{
new RazorError(
string.Format(CultureInfo.InvariantCulture, malformedErrorFormat, "strong"),
absoluteIndex: 52, lineIndex: 0, columnIndex: 52),
new RazorError(
string.Format(CultureInfo.InvariantCulture, malformedErrorFormat, "strong"),
absoluteIndex: 64, lineIndex: 0, columnIndex: 64)
}
};
yield return new object[] {
"<div><p>Hello <strong>World</strong></div>",
@ -150,8 +581,12 @@ namespace Microsoft.AspNet.Razor.Test.TagHelpers
new MarkupTagHelperBlock("strong",
factory.Markup("World")),
blockFactory.MarkupTagBlock("</div>"))),
new RazorError(string.Format(CultureInfo.InvariantCulture, errorFormat, "p"),
absoluteIndex: 5, lineIndex: 0, columnIndex: 5)
new RazorError[]
{
new RazorError(
string.Format(CultureInfo.InvariantCulture, malformedErrorFormat, "p"),
absoluteIndex: 5, lineIndex: 0, columnIndex: 5)
}
};
yield return new object[] {
"<div><p>Hello <strong>World</div>",
@ -162,8 +597,15 @@ namespace Microsoft.AspNet.Razor.Test.TagHelpers
new MarkupTagHelperBlock("strong",
factory.Markup("World"),
blockFactory.MarkupTagBlock("</div>")))),
new RazorError(string.Format(CultureInfo.InvariantCulture, errorFormat, "strong"),
absoluteIndex: 14, lineIndex: 0, columnIndex: 14)
new RazorError[]
{
new RazorError(
string.Format(CultureInfo.InvariantCulture, malformedErrorFormat, "p"),
absoluteIndex: 5, lineIndex: 0, columnIndex: 5),
new RazorError(
string.Format(CultureInfo.InvariantCulture, malformedErrorFormat, "strong"),
absoluteIndex: 14, lineIndex: 0, columnIndex: 14)
}
};
yield return new object[] {
"<p class=\"foo\">Hello <p style=\"color:red;\">World</p>",
@ -180,8 +622,12 @@ namespace Microsoft.AspNet.Razor.Test.TagHelpers
{ "style", factory.Markup("color:red;") }
},
factory.Markup("World")))),
new RazorError(string.Format(CultureInfo.InvariantCulture, errorFormat, "p"),
SourceLocation.Zero)
new RazorError[]
{
new RazorError(
string.Format(CultureInfo.InvariantCulture, malformedErrorFormat, "p"),
SourceLocation.Zero)
}
};
}
}
@ -191,9 +637,9 @@ namespace Microsoft.AspNet.Razor.Test.TagHelpers
public void TagHelperParseTreeRewriter_CreatesErrorForIncompleteTagHelper(
string documentContent,
MarkupBlock expectedOutput,
RazorError expectedError)
RazorError[] expectedErrors)
{
RunParseTreeRewriterTest(documentContent, expectedOutput, new[] { expectedError }, "strong", "p");
RunParseTreeRewriterTest(documentContent, expectedOutput, expectedErrors, "strong", "p");
}
public static TheoryData<string, MarkupBlock> InvalidHtmlBlockData
@ -1268,7 +1714,7 @@ namespace Microsoft.AspNet.Razor.Test.TagHelpers
foreach (var tagName in tagNames)
{
descriptors.Add(
new TagHelperDescriptor(tagName, tagName + "taghelper", "SomeAssembly", ContentBehavior.None));
new TagHelperDescriptor(tagName, tagName + "taghelper", "SomeAssembly"));
}
return new TagHelperDescriptorProvider(descriptors);
@ -1292,8 +1738,10 @@ namespace Microsoft.AspNet.Razor.Test.TagHelpers
var rewritingContext = new RewritingContext(results.Document, errorSink);
new TagHelperParseTreeRewriter(provider).Rewrite(rewritingContext);
var rewritten = rewritingContext.SyntaxTree;
var actualErrors = errorSink.Errors.OrderBy(error => error.Location.AbsoluteIndex)
.ToList();
EvaluateRazorErrors(errorSink.Errors.ToList(), expectedErrors.ToList());
EvaluateRazorErrors(actualErrors, expectedErrors.ToList());
EvaluateParseTree(rewritten, expectedOutput);
}

View File

@ -7,7 +7,9 @@ namespace TestOutput
public class BasicTagHelpers
{
#line hidden
#pragma warning disable 0414
private System.IO.TextWriter __tagHelperStringValueBuffer = null;
#pragma warning restore 0414
private TagHelperExecutionContext __tagHelperExecutionContext = null;
private TagHelperRunner __tagHelperRunner = new TagHelperRunner();
private TagHelperScopeManager __tagHelperScopeManager = new TagHelperScopeManager();
@ -25,57 +27,117 @@ namespace TestOutput
Instrumentation.BeginContext(27, 49, true);
WriteLiteral("\r\n<div class=\"randomNonTagHelperAttribute\">\r\n ");
Instrumentation.EndContext();
__tagHelperExecutionContext = __tagHelperScopeManager.Begin("p");
__tagHelperExecutionContext = __tagHelperScopeManager.Begin("p", "test", async() => {
WriteLiteral("\r\n ");
__tagHelperExecutionContext = __tagHelperScopeManager.Begin("p", "test", async() => {
}
, StartWritingScope, EndWritingScope);
__PTagHelper = CreateTagHelper<PTagHelper>();
__tagHelperExecutionContext.Add(__PTagHelper);
__tagHelperExecutionContext.Output = __tagHelperRunner.RunAsync(__tagHelperExecutionContext).Result;
WriteLiteral(__tagHelperExecutionContext.Output.GenerateStartTag());
WriteLiteral(__tagHelperExecutionContext.Output.GeneratePreContent());
if (__tagHelperExecutionContext.Output.ContentSet)
{
WriteLiteral(__tagHelperExecutionContext.Output.GenerateContent());
}
else if (__tagHelperExecutionContext.ChildContentRetrieved)
{
WriteLiteral(__tagHelperExecutionContext.GetChildContentAsync().Result);
}
else
{
__tagHelperExecutionContext.ExecuteChildContentAsync().Wait();
}
WriteLiteral(__tagHelperExecutionContext.Output.GeneratePostContent());
WriteLiteral(__tagHelperExecutionContext.Output.GenerateEndTag());
__tagHelperExecutionContext = __tagHelperScopeManager.End();
WriteLiteral("\r\n ");
__tagHelperExecutionContext = __tagHelperScopeManager.Begin("input", "test", async() => {
}
, StartWritingScope, EndWritingScope);
__InputTagHelper = CreateTagHelper<InputTagHelper>();
__tagHelperExecutionContext.Add(__InputTagHelper);
__InputTagHelper.Type = **From custom attribute code renderer**: "text";
__tagHelperExecutionContext.AddTagHelperAttribute("type", __InputTagHelper.Type);
__InputTagHelper2 = CreateTagHelper<InputTagHelper2>();
__tagHelperExecutionContext.Add(__InputTagHelper2);
__InputTagHelper2.Type = __InputTagHelper.Type;
__tagHelperExecutionContext.Output = __tagHelperRunner.RunAsync(__tagHelperExecutionContext).Result;
WriteLiteral(__tagHelperExecutionContext.Output.GenerateStartTag());
WriteLiteral(__tagHelperExecutionContext.Output.GeneratePreContent());
if (__tagHelperExecutionContext.Output.ContentSet)
{
WriteLiteral(__tagHelperExecutionContext.Output.GenerateContent());
}
else if (__tagHelperExecutionContext.ChildContentRetrieved)
{
WriteLiteral(__tagHelperExecutionContext.GetChildContentAsync().Result);
}
else
{
__tagHelperExecutionContext.ExecuteChildContentAsync().Wait();
}
WriteLiteral(__tagHelperExecutionContext.Output.GeneratePostContent());
WriteLiteral(__tagHelperExecutionContext.Output.GenerateEndTag());
__tagHelperExecutionContext = __tagHelperScopeManager.End();
WriteLiteral("\r\n ");
__tagHelperExecutionContext = __tagHelperScopeManager.Begin("input", "test", async() => {
}
, StartWritingScope, EndWritingScope);
__InputTagHelper = CreateTagHelper<InputTagHelper>();
__tagHelperExecutionContext.Add(__InputTagHelper);
__InputTagHelper.Type = **From custom attribute code renderer**: "checkbox";
__tagHelperExecutionContext.AddTagHelperAttribute("type", __InputTagHelper.Type);
__InputTagHelper2 = CreateTagHelper<InputTagHelper2>();
__tagHelperExecutionContext.Add(__InputTagHelper2);
__InputTagHelper2.Type = __InputTagHelper.Type;
#line 7 "BasicTagHelpers.cshtml"
__InputTagHelper2.Checked = **From custom attribute code renderer**: true;
#line default
#line hidden
__tagHelperExecutionContext.AddTagHelperAttribute("checked", __InputTagHelper2.Checked);
__tagHelperExecutionContext.Output = __tagHelperRunner.RunAsync(__tagHelperExecutionContext).Result;
WriteLiteral(__tagHelperExecutionContext.Output.GenerateStartTag());
WriteLiteral(__tagHelperExecutionContext.Output.GeneratePreContent());
if (__tagHelperExecutionContext.Output.ContentSet)
{
WriteLiteral(__tagHelperExecutionContext.Output.GenerateContent());
}
else if (__tagHelperExecutionContext.ChildContentRetrieved)
{
WriteLiteral(__tagHelperExecutionContext.GetChildContentAsync().Result);
}
else
{
__tagHelperExecutionContext.ExecuteChildContentAsync().Wait();
}
WriteLiteral(__tagHelperExecutionContext.Output.GeneratePostContent());
WriteLiteral(__tagHelperExecutionContext.Output.GenerateEndTag());
__tagHelperExecutionContext = __tagHelperScopeManager.End();
WriteLiteral("\r\n ");
}
, StartWritingScope, EndWritingScope);
__PTagHelper = CreateTagHelper<PTagHelper>();
__tagHelperExecutionContext.Add(__PTagHelper);
__tagHelperExecutionContext.AddHtmlAttribute("class", "Hello World");
__tagHelperExecutionContext.Output = __tagHelperRunner.RunAsync(__tagHelperExecutionContext).Result;
WriteLiteral(__tagHelperExecutionContext.Output.GenerateStartTag());
Instrumentation.BeginContext(99, 10, true);
WriteLiteral("\r\n ");
Instrumentation.EndContext();
__tagHelperExecutionContext = __tagHelperScopeManager.Begin("p");
__PTagHelper = CreateTagHelper<PTagHelper>();
__tagHelperExecutionContext.Add(__PTagHelper);
__tagHelperExecutionContext.Output = __tagHelperRunner.RunAsync(__tagHelperExecutionContext).Result;
WriteLiteral(__tagHelperExecutionContext.Output.GenerateStartTag());
WriteLiteral(__tagHelperExecutionContext.Output.GenerateEndTag());
__tagHelperExecutionContext = __tagHelperScopeManager.End();
Instrumentation.BeginContext(116, 10, true);
WriteLiteral("\r\n ");
Instrumentation.EndContext();
__tagHelperExecutionContext = __tagHelperScopeManager.Begin("input");
__InputTagHelper = CreateTagHelper<InputTagHelper>();
__tagHelperExecutionContext.Add(__InputTagHelper);
__InputTagHelper.Type = **From custom attribute code renderer**: "text";
__tagHelperExecutionContext.AddTagHelperAttribute("type", __InputTagHelper.Type);
__InputTagHelper2 = CreateTagHelper<InputTagHelper2>();
__tagHelperExecutionContext.Add(__InputTagHelper2);
__InputTagHelper2.Type = __InputTagHelper.Type;
__tagHelperExecutionContext.Output = __tagHelperRunner.RunAsync(__tagHelperExecutionContext).Result;
WriteLiteral(__tagHelperExecutionContext.Output.GenerateStartTag());
WriteLiteral(__tagHelperExecutionContext.Output.GenerateEndTag());
__tagHelperExecutionContext = __tagHelperScopeManager.End();
Instrumentation.BeginContext(147, 10, true);
WriteLiteral("\r\n ");
Instrumentation.EndContext();
__tagHelperExecutionContext = __tagHelperScopeManager.Begin("input");
__InputTagHelper = CreateTagHelper<InputTagHelper>();
__tagHelperExecutionContext.Add(__InputTagHelper);
__InputTagHelper.Type = **From custom attribute code renderer**: "checkbox";
__tagHelperExecutionContext.AddTagHelperAttribute("type", __InputTagHelper.Type);
__InputTagHelper2 = CreateTagHelper<InputTagHelper2>();
__tagHelperExecutionContext.Add(__InputTagHelper2);
__InputTagHelper2.Type = __InputTagHelper.Type;
__InputTagHelper2.Checked = **From custom attribute code renderer**: true;
__tagHelperExecutionContext.AddTagHelperAttribute("checked", __InputTagHelper2.Checked);
__tagHelperExecutionContext.Output = __tagHelperRunner.RunAsync(__tagHelperExecutionContext).Result;
WriteLiteral(__tagHelperExecutionContext.Output.GenerateStartTag());
WriteLiteral(__tagHelperExecutionContext.Output.GenerateEndTag());
__tagHelperExecutionContext = __tagHelperScopeManager.End();
Instrumentation.BeginContext(196, 6, true);
WriteLiteral("\r\n ");
Instrumentation.EndContext();
WriteLiteral(__tagHelperExecutionContext.Output.GeneratePreContent());
if (__tagHelperExecutionContext.Output.ContentSet)
{
WriteLiteral(__tagHelperExecutionContext.Output.GenerateContent());
}
else if (__tagHelperExecutionContext.ChildContentRetrieved)
{
WriteLiteral(__tagHelperExecutionContext.GetChildContentAsync().Result);
}
else
{
__tagHelperExecutionContext.ExecuteChildContentAsync().Wait();
}
WriteLiteral(__tagHelperExecutionContext.Output.GeneratePostContent());
WriteLiteral(__tagHelperExecutionContext.Output.GenerateEndTag());
__tagHelperExecutionContext = __tagHelperScopeManager.End();
Instrumentation.BeginContext(206, 8, true);

View File

@ -32,7 +32,6 @@ namespace TestOutput
#pragma warning disable 1998
public override async Task ExecuteAsync()
{
__PTagHelper = CreateTagHelper<PTagHelper>();
__PTagHelper = CreateTagHelper<PTagHelper>();
__InputTagHelper = CreateTagHelper<InputTagHelper>();
__InputTagHelper.Type = "text";
@ -42,7 +41,12 @@ namespace TestOutput
__InputTagHelper.Type = "checkbox";
__InputTagHelper2 = CreateTagHelper<InputTagHelper2>();
__InputTagHelper2.Type = __InputTagHelper.Type;
#line 7 "BasicTagHelpers.cshtml"
__InputTagHelper2.Checked = true;
#line default
#line hidden
__PTagHelper = CreateTagHelper<PTagHelper>();
}
#pragma warning restore 1998
}

View File

@ -8,7 +8,9 @@ namespace TestOutput
public class BasicTagHelpers
{
#line hidden
#pragma warning disable 0414
private System.IO.TextWriter __tagHelperStringValueBuffer = null;
#pragma warning restore 0414
private TagHelperExecutionContext __tagHelperExecutionContext = null;
private TagHelperRunner __tagHelperRunner = new TagHelperRunner();
private TagHelperScopeManager __tagHelperScopeManager = new TagHelperScopeManager();
@ -26,57 +28,117 @@ namespace TestOutput
Instrumentation.BeginContext(27, 49, true);
WriteLiteral("\r\n<div class=\"randomNonTagHelperAttribute\">\r\n ");
Instrumentation.EndContext();
__tagHelperExecutionContext = __tagHelperScopeManager.Begin("p");
__tagHelperExecutionContext = __tagHelperScopeManager.Begin("p", "test", async() => {
WriteLiteral("\r\n ");
__tagHelperExecutionContext = __tagHelperScopeManager.Begin("p", "test", async() => {
}
, StartWritingScope, EndWritingScope);
__PTagHelper = CreateTagHelper<PTagHelper>();
__tagHelperExecutionContext.Add(__PTagHelper);
__tagHelperExecutionContext.Output = __tagHelperRunner.RunAsync(__tagHelperExecutionContext).Result;
WriteLiteral(__tagHelperExecutionContext.Output.GenerateStartTag());
WriteLiteral(__tagHelperExecutionContext.Output.GeneratePreContent());
if (__tagHelperExecutionContext.Output.ContentSet)
{
WriteLiteral(__tagHelperExecutionContext.Output.GenerateContent());
}
else if (__tagHelperExecutionContext.ChildContentRetrieved)
{
WriteLiteral(__tagHelperExecutionContext.GetChildContentAsync().Result);
}
else
{
__tagHelperExecutionContext.ExecuteChildContentAsync().Wait();
}
WriteLiteral(__tagHelperExecutionContext.Output.GeneratePostContent());
WriteLiteral(__tagHelperExecutionContext.Output.GenerateEndTag());
__tagHelperExecutionContext = __tagHelperScopeManager.End();
WriteLiteral("\r\n ");
__tagHelperExecutionContext = __tagHelperScopeManager.Begin("input", "test", async() => {
}
, StartWritingScope, EndWritingScope);
__InputTagHelper = CreateTagHelper<InputTagHelper>();
__tagHelperExecutionContext.Add(__InputTagHelper);
__InputTagHelper.Type = "text";
__tagHelperExecutionContext.AddTagHelperAttribute("type", __InputTagHelper.Type);
__InputTagHelper2 = CreateTagHelper<InputTagHelper2>();
__tagHelperExecutionContext.Add(__InputTagHelper2);
__InputTagHelper2.Type = __InputTagHelper.Type;
__tagHelperExecutionContext.Output = __tagHelperRunner.RunAsync(__tagHelperExecutionContext).Result;
WriteLiteral(__tagHelperExecutionContext.Output.GenerateStartTag());
WriteLiteral(__tagHelperExecutionContext.Output.GeneratePreContent());
if (__tagHelperExecutionContext.Output.ContentSet)
{
WriteLiteral(__tagHelperExecutionContext.Output.GenerateContent());
}
else if (__tagHelperExecutionContext.ChildContentRetrieved)
{
WriteLiteral(__tagHelperExecutionContext.GetChildContentAsync().Result);
}
else
{
__tagHelperExecutionContext.ExecuteChildContentAsync().Wait();
}
WriteLiteral(__tagHelperExecutionContext.Output.GeneratePostContent());
WriteLiteral(__tagHelperExecutionContext.Output.GenerateEndTag());
__tagHelperExecutionContext = __tagHelperScopeManager.End();
WriteLiteral("\r\n ");
__tagHelperExecutionContext = __tagHelperScopeManager.Begin("input", "test", async() => {
}
, StartWritingScope, EndWritingScope);
__InputTagHelper = CreateTagHelper<InputTagHelper>();
__tagHelperExecutionContext.Add(__InputTagHelper);
__InputTagHelper.Type = "checkbox";
__tagHelperExecutionContext.AddTagHelperAttribute("type", __InputTagHelper.Type);
__InputTagHelper2 = CreateTagHelper<InputTagHelper2>();
__tagHelperExecutionContext.Add(__InputTagHelper2);
__InputTagHelper2.Type = __InputTagHelper.Type;
#line 7 "BasicTagHelpers.cshtml"
__InputTagHelper2.Checked = true;
#line default
#line hidden
__tagHelperExecutionContext.AddTagHelperAttribute("checked", __InputTagHelper2.Checked);
__tagHelperExecutionContext.Output = __tagHelperRunner.RunAsync(__tagHelperExecutionContext).Result;
WriteLiteral(__tagHelperExecutionContext.Output.GenerateStartTag());
WriteLiteral(__tagHelperExecutionContext.Output.GeneratePreContent());
if (__tagHelperExecutionContext.Output.ContentSet)
{
WriteLiteral(__tagHelperExecutionContext.Output.GenerateContent());
}
else if (__tagHelperExecutionContext.ChildContentRetrieved)
{
WriteLiteral(__tagHelperExecutionContext.GetChildContentAsync().Result);
}
else
{
__tagHelperExecutionContext.ExecuteChildContentAsync().Wait();
}
WriteLiteral(__tagHelperExecutionContext.Output.GeneratePostContent());
WriteLiteral(__tagHelperExecutionContext.Output.GenerateEndTag());
__tagHelperExecutionContext = __tagHelperScopeManager.End();
WriteLiteral("\r\n ");
}
, StartWritingScope, EndWritingScope);
__PTagHelper = CreateTagHelper<PTagHelper>();
__tagHelperExecutionContext.Add(__PTagHelper);
__tagHelperExecutionContext.AddHtmlAttribute("class", "Hello World");
__tagHelperExecutionContext.Output = __tagHelperRunner.RunAsync(__tagHelperExecutionContext).Result;
WriteLiteral(__tagHelperExecutionContext.Output.GenerateStartTag());
Instrumentation.BeginContext(99, 10, true);
WriteLiteral("\r\n ");
Instrumentation.EndContext();
__tagHelperExecutionContext = __tagHelperScopeManager.Begin("p");
__PTagHelper = CreateTagHelper<PTagHelper>();
__tagHelperExecutionContext.Add(__PTagHelper);
__tagHelperExecutionContext.Output = __tagHelperRunner.RunAsync(__tagHelperExecutionContext).Result;
WriteLiteral(__tagHelperExecutionContext.Output.GenerateStartTag());
WriteLiteral(__tagHelperExecutionContext.Output.GenerateEndTag());
__tagHelperExecutionContext = __tagHelperScopeManager.End();
Instrumentation.BeginContext(116, 10, true);
WriteLiteral("\r\n ");
Instrumentation.EndContext();
__tagHelperExecutionContext = __tagHelperScopeManager.Begin("input");
__InputTagHelper = CreateTagHelper<InputTagHelper>();
__tagHelperExecutionContext.Add(__InputTagHelper);
__InputTagHelper.Type = "text";
__tagHelperExecutionContext.AddTagHelperAttribute("type", __InputTagHelper.Type);
__InputTagHelper2 = CreateTagHelper<InputTagHelper2>();
__tagHelperExecutionContext.Add(__InputTagHelper2);
__InputTagHelper2.Type = __InputTagHelper.Type;
__tagHelperExecutionContext.Output = __tagHelperRunner.RunAsync(__tagHelperExecutionContext).Result;
WriteLiteral(__tagHelperExecutionContext.Output.GenerateStartTag());
WriteLiteral(__tagHelperExecutionContext.Output.GenerateEndTag());
__tagHelperExecutionContext = __tagHelperScopeManager.End();
Instrumentation.BeginContext(147, 10, true);
WriteLiteral("\r\n ");
Instrumentation.EndContext();
__tagHelperExecutionContext = __tagHelperScopeManager.Begin("input");
__InputTagHelper = CreateTagHelper<InputTagHelper>();
__tagHelperExecutionContext.Add(__InputTagHelper);
__InputTagHelper.Type = "checkbox";
__tagHelperExecutionContext.AddTagHelperAttribute("type", __InputTagHelper.Type);
__InputTagHelper2 = CreateTagHelper<InputTagHelper2>();
__tagHelperExecutionContext.Add(__InputTagHelper2);
__InputTagHelper2.Type = __InputTagHelper.Type;
__InputTagHelper2.Checked = true;
__tagHelperExecutionContext.AddTagHelperAttribute("checked", __InputTagHelper2.Checked);
__tagHelperExecutionContext.Output = __tagHelperRunner.RunAsync(__tagHelperExecutionContext).Result;
WriteLiteral(__tagHelperExecutionContext.Output.GenerateStartTag());
WriteLiteral(__tagHelperExecutionContext.Output.GenerateEndTag());
__tagHelperExecutionContext = __tagHelperScopeManager.End();
Instrumentation.BeginContext(196, 6, true);
WriteLiteral("\r\n ");
Instrumentation.EndContext();
WriteLiteral(__tagHelperExecutionContext.Output.GeneratePreContent());
if (__tagHelperExecutionContext.Output.ContentSet)
{
WriteLiteral(__tagHelperExecutionContext.Output.GenerateContent());
}
else if (__tagHelperExecutionContext.ChildContentRetrieved)
{
WriteLiteral(__tagHelperExecutionContext.GetChildContentAsync().Result);
}
else
{
__tagHelperExecutionContext.ExecuteChildContentAsync().Wait();
}
WriteLiteral(__tagHelperExecutionContext.Output.GeneratePostContent());
WriteLiteral(__tagHelperExecutionContext.Output.GenerateEndTag());
__tagHelperExecutionContext = __tagHelperScopeManager.End();
Instrumentation.BeginContext(206, 8, true);

View File

@ -41,12 +41,6 @@ if (true)
#line default
#line hidden
__PTagHelper = CreateTagHelper<PTagHelper>();
#line 8 "ComplexTagHelpers.cshtml"
__o = DateTime.Now;
#line default
#line hidden
#line 10 "ComplexTagHelpers.cshtml"
@ -60,11 +54,11 @@ __o = DateTime.Now;
#line default
#line hidden
__PTagHelper = CreateTagHelper<PTagHelper>();
__InputTagHelper = CreateTagHelper<InputTagHelper>();
__InputTagHelper.Type = "text";
__InputTagHelper2 = CreateTagHelper<InputTagHelper2>();
__InputTagHelper2.Type = __InputTagHelper.Type;
__PTagHelper = CreateTagHelper<PTagHelper>();
#line 13 "ComplexTagHelpers.cshtml"
}
else
@ -73,7 +67,6 @@ __o = DateTime.Now;
#line default
#line hidden
__PTagHelper = CreateTagHelper<PTagHelper>();
__InputTagHelper = CreateTagHelper<InputTagHelper>();
#line 16 "ComplexTagHelpers.cshtml"
__o = checkbox;
@ -83,7 +76,12 @@ __o = checkbox;
__InputTagHelper.Type = string.Empty;
__InputTagHelper2 = CreateTagHelper<InputTagHelper2>();
__InputTagHelper2.Type = __InputTagHelper.Type;
__InputTagHelper2.Checked = true;
#line 16 "ComplexTagHelpers.cshtml"
__InputTagHelper2.Checked = true;
#line default
#line hidden
__PTagHelper = CreateTagHelper<PTagHelper>();
__InputTagHelper = CreateTagHelper<InputTagHelper>();
#line 17 "ComplexTagHelpers.cshtml"
__o = true ? "checkbox" : "anything";
@ -121,7 +119,77 @@ if(true) {
#line default
#line hidden
__PTagHelper = CreateTagHelper<PTagHelper>();
#line 8 "ComplexTagHelpers.cshtml"
__o = DateTime.Now;
#line default
#line hidden
#line 22 "ComplexTagHelpers.cshtml"
#line default
#line hidden
#line 22 "ComplexTagHelpers.cshtml"
var @object = false;
#line default
#line hidden
__InputTagHelper = CreateTagHelper<InputTagHelper>();
__InputTagHelper2 = CreateTagHelper<InputTagHelper2>();
#line 23 "ComplexTagHelpers.cshtml"
__InputTagHelper2.Checked = @object;
#line default
#line hidden
__PTagHelper = CreateTagHelper<PTagHelper>();
#line 21 "ComplexTagHelpers.cshtml"
__PTagHelper.Age = DateTimeOffset.Now.Year - 1970;
#line default
#line hidden
__InputTagHelper = CreateTagHelper<InputTagHelper>();
__InputTagHelper2 = CreateTagHelper<InputTagHelper2>();
#line 26 "ComplexTagHelpers.cshtml"
__InputTagHelper2.Checked = DateTimeOffset.Now.Year > 2014;
#line default
#line hidden
__PTagHelper = CreateTagHelper<PTagHelper>();
#line 25 "ComplexTagHelpers.cshtml"
__PTagHelper.Age = -1970 + DateTimeOffset.Now.Year;
#line default
#line hidden
__InputTagHelper = CreateTagHelper<InputTagHelper>();
__InputTagHelper2 = CreateTagHelper<InputTagHelper2>();
#line 29 "ComplexTagHelpers.cshtml"
__InputTagHelper2.Checked = DateTimeOffset.Now.Year > 2014;
#line default
#line hidden
__PTagHelper = CreateTagHelper<PTagHelper>();
#line 28 "ComplexTagHelpers.cshtml"
__PTagHelper.Age = DateTimeOffset.Now.Year - 1970;
#line default
#line hidden
__InputTagHelper = CreateTagHelper<InputTagHelper>();
__InputTagHelper2 = CreateTagHelper<InputTagHelper2>();
#line 32 "ComplexTagHelpers.cshtml"
__InputTagHelper2.Checked = DateTimeOffset.Now.Year > 2014 ;
#line default
#line hidden
__PTagHelper = CreateTagHelper<PTagHelper>();
#line 31 "ComplexTagHelpers.cshtml"
__PTagHelper.Age = "My age is this long.".Length;
#line default
#line hidden
#line 35 "ComplexTagHelpers.cshtml"
}
#line default

View File

@ -1,4 +1,4 @@
#pragma checksum "ComplexTagHelpers.cshtml" "{ff1816ec-aa5e-4d10-87f7-6f4963833460}" "cce31144cd1c3c35d241b49e41c4fc04ff044565"
#pragma checksum "ComplexTagHelpers.cshtml" "{ff1816ec-aa5e-4d10-87f7-6f4963833460}" "7158abc69d261099393d49d82670ec64a94d9770"
namespace TestOutput
{
using Microsoft.AspNet.Razor.Runtime.TagHelpers;
@ -8,7 +8,9 @@ namespace TestOutput
public class ComplexTagHelpers
{
#line hidden
#pragma warning disable 0414
private System.IO.TextWriter __tagHelperStringValueBuffer = null;
#pragma warning restore 0414
private TagHelperExecutionContext __tagHelperExecutionContext = null;
private TagHelperRunner __tagHelperRunner = new TagHelperRunner();
private TagHelperScopeManager __tagHelperScopeManager = new TagHelperScopeManager();
@ -38,23 +40,8 @@ namespace TestOutput
Instrumentation.BeginContext(78, 55, true);
WriteLiteral(" <div class=\"randomNonTagHelperAttribute\">\r\n ");
Instrumentation.EndContext();
__tagHelperExecutionContext = __tagHelperScopeManager.Begin("p");
__PTagHelper = CreateTagHelper<PTagHelper>();
__tagHelperExecutionContext.Add(__PTagHelper);
StartWritingScope();
WriteLiteral("Current Time: ");
#line 8 "ComplexTagHelpers.cshtml"
Write(DateTime.Now);
#line default
#line hidden
__tagHelperStringValueBuffer = EndWritingScope();
__tagHelperExecutionContext.AddHtmlAttribute("time", __tagHelperStringValueBuffer.ToString());
__tagHelperExecutionContext.Output = __tagHelperRunner.RunAsync(__tagHelperExecutionContext).Result;
WriteLiteral(__tagHelperExecutionContext.Output.GenerateStartTag());
Instrumentation.BeginContext(171, 34, true);
WriteLiteral("\r\n <h1>Set Time:</h1>\r\n");
Instrumentation.EndContext();
__tagHelperExecutionContext = __tagHelperScopeManager.Begin("p", "test", async() => {
WriteLiteral("\r\n <h1>Set Time:</h1>\r\n");
#line 10 "ComplexTagHelpers.cshtml"
@ -68,36 +55,62 @@ Write(DateTime.Now);
#line default
#line hidden
Instrumentation.BeginContext(245, 16, true);
WriteLiteral(" ");
Instrumentation.EndContext();
__tagHelperExecutionContext = __tagHelperScopeManager.Begin("p");
__PTagHelper = CreateTagHelper<PTagHelper>();
__tagHelperExecutionContext.Add(__PTagHelper);
__tagHelperExecutionContext.Output = __tagHelperRunner.RunAsync(__tagHelperExecutionContext).Result;
WriteLiteral(__tagHelperExecutionContext.Output.GenerateStartTag());
Instrumentation.BeginContext(264, 10, true);
WriteLiteral("New Time: ");
Instrumentation.EndContext();
__tagHelperExecutionContext = __tagHelperScopeManager.Begin("input");
__InputTagHelper = CreateTagHelper<InputTagHelper>();
__tagHelperExecutionContext.Add(__InputTagHelper);
__InputTagHelper.Type = "text";
__tagHelperExecutionContext.AddTagHelperAttribute("type", __InputTagHelper.Type);
__InputTagHelper2 = CreateTagHelper<InputTagHelper2>();
__tagHelperExecutionContext.Add(__InputTagHelper2);
__InputTagHelper2.Type = __InputTagHelper.Type;
__tagHelperExecutionContext.AddHtmlAttribute("value", "");
__tagHelperExecutionContext.AddHtmlAttribute("placeholder", "Enter in a new time...");
__tagHelperExecutionContext.Output = __tagHelperRunner.RunAsync(__tagHelperExecutionContext).Result;
WriteLiteral(__tagHelperExecutionContext.Output.GenerateStartTag());
WriteLiteral(__tagHelperExecutionContext.Output.GenerateEndTag());
__tagHelperExecutionContext = __tagHelperScopeManager.End();
WriteLiteral(__tagHelperExecutionContext.Output.GenerateEndTag());
__tagHelperExecutionContext = __tagHelperScopeManager.End();
Instrumentation.BeginContext(344, 2, true);
WriteLiteral("\r\n");
Instrumentation.EndContext();
WriteLiteral(" ");
__tagHelperExecutionContext = __tagHelperScopeManager.Begin("p", "test", async() => {
WriteLiteral("New Time: ");
__tagHelperExecutionContext = __tagHelperScopeManager.Begin("input", "test", async() => {
}
, StartWritingScope, EndWritingScope);
__InputTagHelper = CreateTagHelper<InputTagHelper>();
__tagHelperExecutionContext.Add(__InputTagHelper);
__InputTagHelper.Type = "text";
__tagHelperExecutionContext.AddTagHelperAttribute("type", __InputTagHelper.Type);
__InputTagHelper2 = CreateTagHelper<InputTagHelper2>();
__tagHelperExecutionContext.Add(__InputTagHelper2);
__InputTagHelper2.Type = __InputTagHelper.Type;
__tagHelperExecutionContext.AddHtmlAttribute("value", "");
__tagHelperExecutionContext.AddHtmlAttribute("placeholder", "Enter in a new time...");
__tagHelperExecutionContext.Output = __tagHelperRunner.RunAsync(__tagHelperExecutionContext).Result;
WriteLiteral(__tagHelperExecutionContext.Output.GenerateStartTag());
WriteLiteral(__tagHelperExecutionContext.Output.GeneratePreContent());
if (__tagHelperExecutionContext.Output.ContentSet)
{
WriteLiteral(__tagHelperExecutionContext.Output.GenerateContent());
}
else if (__tagHelperExecutionContext.ChildContentRetrieved)
{
WriteLiteral(__tagHelperExecutionContext.GetChildContentAsync().Result);
}
else
{
__tagHelperExecutionContext.ExecuteChildContentAsync().Wait();
}
WriteLiteral(__tagHelperExecutionContext.Output.GeneratePostContent());
WriteLiteral(__tagHelperExecutionContext.Output.GenerateEndTag());
__tagHelperExecutionContext = __tagHelperScopeManager.End();
}
, StartWritingScope, EndWritingScope);
__PTagHelper = CreateTagHelper<PTagHelper>();
__tagHelperExecutionContext.Add(__PTagHelper);
__tagHelperExecutionContext.Output = __tagHelperRunner.RunAsync(__tagHelperExecutionContext).Result;
WriteLiteral(__tagHelperExecutionContext.Output.GenerateStartTag());
WriteLiteral(__tagHelperExecutionContext.Output.GeneratePreContent());
if (__tagHelperExecutionContext.Output.ContentSet)
{
WriteLiteral(__tagHelperExecutionContext.Output.GenerateContent());
}
else if (__tagHelperExecutionContext.ChildContentRetrieved)
{
WriteLiteral(__tagHelperExecutionContext.GetChildContentAsync().Result);
}
else
{
__tagHelperExecutionContext.ExecuteChildContentAsync().Wait();
}
WriteLiteral(__tagHelperExecutionContext.Output.GeneratePostContent());
WriteLiteral(__tagHelperExecutionContext.Output.GenerateEndTag());
__tagHelperExecutionContext = __tagHelperScopeManager.End();
WriteLiteral("\r\n");
#line 13 "ComplexTagHelpers.cshtml"
}
else
@ -106,117 +119,475 @@ Write(DateTime.Now);
#line default
#line hidden
Instrumentation.BeginContext(394, 16, true);
WriteLiteral(" ");
Instrumentation.EndContext();
__tagHelperExecutionContext = __tagHelperScopeManager.Begin("p");
__PTagHelper = CreateTagHelper<PTagHelper>();
__tagHelperExecutionContext.Add(__PTagHelper);
__tagHelperExecutionContext.Output = __tagHelperRunner.RunAsync(__tagHelperExecutionContext).Result;
WriteLiteral(__tagHelperExecutionContext.Output.GenerateStartTag());
Instrumentation.BeginContext(413, 14, true);
WriteLiteral("Current Time: ");
Instrumentation.EndContext();
__tagHelperExecutionContext = __tagHelperScopeManager.Begin("input");
__InputTagHelper = CreateTagHelper<InputTagHelper>();
__tagHelperExecutionContext.Add(__InputTagHelper);
StartWritingScope();
WriteLiteral(" ");
__tagHelperExecutionContext = __tagHelperScopeManager.Begin("p", "test", async() => {
WriteLiteral("Current Time: ");
__tagHelperExecutionContext = __tagHelperScopeManager.Begin("input", "test", async() => {
}
, StartWritingScope, EndWritingScope);
__InputTagHelper = CreateTagHelper<InputTagHelper>();
__tagHelperExecutionContext.Add(__InputTagHelper);
StartWritingScope();
#line 16 "ComplexTagHelpers.cshtml"
Write(checkbox);
#line default
#line hidden
__tagHelperStringValueBuffer = EndWritingScope();
__InputTagHelper.Type = __tagHelperStringValueBuffer.ToString();
__tagHelperExecutionContext.AddTagHelperAttribute("type", __InputTagHelper.Type);
__InputTagHelper2 = CreateTagHelper<InputTagHelper2>();
__tagHelperExecutionContext.Add(__InputTagHelper2);
__InputTagHelper2.Type = __InputTagHelper.Type;
__InputTagHelper2.Checked = true;
__tagHelperExecutionContext.AddTagHelperAttribute("checked", __InputTagHelper2.Checked);
__tagHelperExecutionContext.Output = __tagHelperRunner.RunAsync(__tagHelperExecutionContext).Result;
WriteLiteral(__tagHelperExecutionContext.Output.GenerateStartTag());
WriteLiteral(__tagHelperExecutionContext.Output.GenerateEndTag());
__tagHelperExecutionContext = __tagHelperScopeManager.End();
WriteLiteral(__tagHelperExecutionContext.Output.GenerateEndTag());
__tagHelperExecutionContext = __tagHelperScopeManager.End();
Instrumentation.BeginContext(468, 18, true);
WriteLiteral("\r\n ");
Instrumentation.EndContext();
__tagHelperExecutionContext = __tagHelperScopeManager.Begin("input");
__InputTagHelper = CreateTagHelper<InputTagHelper>();
__tagHelperExecutionContext.Add(__InputTagHelper);
StartWritingScope();
__tagHelperStringValueBuffer = EndWritingScope();
__InputTagHelper.Type = __tagHelperStringValueBuffer.ToString();
__tagHelperExecutionContext.AddTagHelperAttribute("type", __InputTagHelper.Type);
__InputTagHelper2 = CreateTagHelper<InputTagHelper2>();
__tagHelperExecutionContext.Add(__InputTagHelper2);
__InputTagHelper2.Type = __InputTagHelper.Type;
#line 16 "ComplexTagHelpers.cshtml"
__InputTagHelper2.Checked = true;
#line default
#line hidden
__tagHelperExecutionContext.AddTagHelperAttribute("checked", __InputTagHelper2.Checked);
__tagHelperExecutionContext.Output = __tagHelperRunner.RunAsync(__tagHelperExecutionContext).Result;
WriteLiteral(__tagHelperExecutionContext.Output.GenerateStartTag());
WriteLiteral(__tagHelperExecutionContext.Output.GeneratePreContent());
if (__tagHelperExecutionContext.Output.ContentSet)
{
WriteLiteral(__tagHelperExecutionContext.Output.GenerateContent());
}
else if (__tagHelperExecutionContext.ChildContentRetrieved)
{
WriteLiteral(__tagHelperExecutionContext.GetChildContentAsync().Result);
}
else
{
__tagHelperExecutionContext.ExecuteChildContentAsync().Wait();
}
WriteLiteral(__tagHelperExecutionContext.Output.GeneratePostContent());
WriteLiteral(__tagHelperExecutionContext.Output.GenerateEndTag());
__tagHelperExecutionContext = __tagHelperScopeManager.End();
}
, StartWritingScope, EndWritingScope);
__PTagHelper = CreateTagHelper<PTagHelper>();
__tagHelperExecutionContext.Add(__PTagHelper);
__tagHelperExecutionContext.Output = __tagHelperRunner.RunAsync(__tagHelperExecutionContext).Result;
WriteLiteral(__tagHelperExecutionContext.Output.GenerateStartTag());
WriteLiteral(__tagHelperExecutionContext.Output.GeneratePreContent());
if (__tagHelperExecutionContext.Output.ContentSet)
{
WriteLiteral(__tagHelperExecutionContext.Output.GenerateContent());
}
else if (__tagHelperExecutionContext.ChildContentRetrieved)
{
WriteLiteral(__tagHelperExecutionContext.GetChildContentAsync().Result);
}
else
{
__tagHelperExecutionContext.ExecuteChildContentAsync().Wait();
}
WriteLiteral(__tagHelperExecutionContext.Output.GeneratePostContent());
WriteLiteral(__tagHelperExecutionContext.Output.GenerateEndTag());
__tagHelperExecutionContext = __tagHelperScopeManager.End();
WriteLiteral("\r\n ");
__tagHelperExecutionContext = __tagHelperScopeManager.Begin("input", "test", async() => {
}
, StartWritingScope, EndWritingScope);
__InputTagHelper = CreateTagHelper<InputTagHelper>();
__tagHelperExecutionContext.Add(__InputTagHelper);
StartWritingScope();
#line 17 "ComplexTagHelpers.cshtml"
Write(true ? "checkbox" : "anything");
#line default
#line hidden
__tagHelperStringValueBuffer = EndWritingScope();
__InputTagHelper.Type = __tagHelperStringValueBuffer.ToString();
__tagHelperExecutionContext.AddTagHelperAttribute("type", __InputTagHelper.Type);
__InputTagHelper2 = CreateTagHelper<InputTagHelper2>();
__tagHelperExecutionContext.Add(__InputTagHelper2);
__InputTagHelper2.Type = __InputTagHelper.Type;
__tagHelperExecutionContext.Output = __tagHelperRunner.RunAsync(__tagHelperExecutionContext).Result;
WriteLiteral(__tagHelperExecutionContext.Output.GenerateStartTag());
WriteLiteral(__tagHelperExecutionContext.Output.GenerateEndTag());
__tagHelperExecutionContext = __tagHelperScopeManager.End();
Instrumentation.BeginContext(536, 18, true);
WriteLiteral("\r\n ");
Instrumentation.EndContext();
__tagHelperExecutionContext = __tagHelperScopeManager.Begin("input");
__InputTagHelper = CreateTagHelper<InputTagHelper>();
__tagHelperExecutionContext.Add(__InputTagHelper);
StartWritingScope();
__tagHelperStringValueBuffer = EndWritingScope();
__InputTagHelper.Type = __tagHelperStringValueBuffer.ToString();
__tagHelperExecutionContext.AddTagHelperAttribute("type", __InputTagHelper.Type);
__InputTagHelper2 = CreateTagHelper<InputTagHelper2>();
__tagHelperExecutionContext.Add(__InputTagHelper2);
__InputTagHelper2.Type = __InputTagHelper.Type;
__tagHelperExecutionContext.Output = __tagHelperRunner.RunAsync(__tagHelperExecutionContext).Result;
WriteLiteral(__tagHelperExecutionContext.Output.GenerateStartTag());
WriteLiteral(__tagHelperExecutionContext.Output.GeneratePreContent());
if (__tagHelperExecutionContext.Output.ContentSet)
{
WriteLiteral(__tagHelperExecutionContext.Output.GenerateContent());
}
else if (__tagHelperExecutionContext.ChildContentRetrieved)
{
WriteLiteral(__tagHelperExecutionContext.GetChildContentAsync().Result);
}
else
{
__tagHelperExecutionContext.ExecuteChildContentAsync().Wait();
}
WriteLiteral(__tagHelperExecutionContext.Output.GeneratePostContent());
WriteLiteral(__tagHelperExecutionContext.Output.GenerateEndTag());
__tagHelperExecutionContext = __tagHelperScopeManager.End();
WriteLiteral("\r\n ");
__tagHelperExecutionContext = __tagHelperScopeManager.Begin("input", "test", async() => {
}
, StartWritingScope, EndWritingScope);
__InputTagHelper = CreateTagHelper<InputTagHelper>();
__tagHelperExecutionContext.Add(__InputTagHelper);
StartWritingScope();
#line 18 "ComplexTagHelpers.cshtml"
if(true) {
#line default
#line hidden
WriteLiteral(" checkbox ");
WriteLiteral(" checkbox ");
#line 18 "ComplexTagHelpers.cshtml"
} else {
#line default
#line hidden
WriteLiteral(" anything ");
WriteLiteral(" anything ");
#line 18 "ComplexTagHelpers.cshtml"
}
#line default
#line hidden
__tagHelperStringValueBuffer = EndWritingScope();
__InputTagHelper.Type = __tagHelperStringValueBuffer.ToString();
__tagHelperExecutionContext.AddTagHelperAttribute("type", __InputTagHelper.Type);
__InputTagHelper2 = CreateTagHelper<InputTagHelper2>();
__tagHelperExecutionContext.Add(__InputTagHelper2);
__InputTagHelper2.Type = __InputTagHelper.Type;
__tagHelperExecutionContext.Output = __tagHelperRunner.RunAsync(__tagHelperExecutionContext).Result;
WriteLiteral(__tagHelperExecutionContext.Output.GenerateStartTag());
WriteLiteral(__tagHelperExecutionContext.Output.GenerateEndTag());
__tagHelperExecutionContext = __tagHelperScopeManager.End();
Instrumentation.BeginContext(637, 2, true);
WriteLiteral("\r\n");
Instrumentation.EndContext();
__tagHelperStringValueBuffer = EndWritingScope();
__InputTagHelper.Type = __tagHelperStringValueBuffer.ToString();
__tagHelperExecutionContext.AddTagHelperAttribute("type", __InputTagHelper.Type);
__InputTagHelper2 = CreateTagHelper<InputTagHelper2>();
__tagHelperExecutionContext.Add(__InputTagHelper2);
__InputTagHelper2.Type = __InputTagHelper.Type;
__tagHelperExecutionContext.Output = __tagHelperRunner.RunAsync(__tagHelperExecutionContext).Result;
WriteLiteral(__tagHelperExecutionContext.Output.GenerateStartTag());
WriteLiteral(__tagHelperExecutionContext.Output.GeneratePreContent());
if (__tagHelperExecutionContext.Output.ContentSet)
{
WriteLiteral(__tagHelperExecutionContext.Output.GenerateContent());
}
else if (__tagHelperExecutionContext.ChildContentRetrieved)
{
WriteLiteral(__tagHelperExecutionContext.GetChildContentAsync().Result);
}
else
{
__tagHelperExecutionContext.ExecuteChildContentAsync().Wait();
}
WriteLiteral(__tagHelperExecutionContext.Output.GeneratePostContent());
WriteLiteral(__tagHelperExecutionContext.Output.GenerateEndTag());
__tagHelperExecutionContext = __tagHelperScopeManager.End();
WriteLiteral("\r\n");
#line 19 "ComplexTagHelpers.cshtml"
}
#line default
#line hidden
Instrumentation.BeginContext(654, 8, true);
WriteLiteral(" ");
Instrumentation.EndContext();
WriteLiteral(" ");
}
, StartWritingScope, EndWritingScope);
__PTagHelper = CreateTagHelper<PTagHelper>();
__tagHelperExecutionContext.Add(__PTagHelper);
StartWritingScope();
WriteLiteral("Current Time: ");
#line 8 "ComplexTagHelpers.cshtml"
Write(DateTime.Now);
#line default
#line hidden
__tagHelperStringValueBuffer = EndWritingScope();
__tagHelperExecutionContext.AddHtmlAttribute("time", __tagHelperStringValueBuffer.ToString());
__tagHelperExecutionContext.Output = __tagHelperRunner.RunAsync(__tagHelperExecutionContext).Result;
WriteLiteral(__tagHelperExecutionContext.Output.GenerateStartTag());
WriteLiteral(__tagHelperExecutionContext.Output.GeneratePreContent());
if (__tagHelperExecutionContext.Output.ContentSet)
{
WriteLiteral(__tagHelperExecutionContext.Output.GenerateContent());
}
else if (__tagHelperExecutionContext.ChildContentRetrieved)
{
WriteLiteral(__tagHelperExecutionContext.GetChildContentAsync().Result);
}
else
{
__tagHelperExecutionContext.ExecuteChildContentAsync().Wait();
}
WriteLiteral(__tagHelperExecutionContext.Output.GeneratePostContent());
WriteLiteral(__tagHelperExecutionContext.Output.GenerateEndTag());
__tagHelperExecutionContext = __tagHelperScopeManager.End();
Instrumentation.BeginContext(666, 14, true);
Instrumentation.BeginContext(666, 10, true);
WriteLiteral("\r\n ");
Instrumentation.EndContext();
__tagHelperExecutionContext = __tagHelperScopeManager.Begin("p", "test", async() => {
WriteLiteral("\r\n");
#line 22 "ComplexTagHelpers.cshtml"
#line default
#line hidden
#line 22 "ComplexTagHelpers.cshtml"
var @object = false;
#line default
#line hidden
WriteLiteral("\r\n ");
__tagHelperExecutionContext = __tagHelperScopeManager.Begin("input", "test", async() => {
}
, StartWritingScope, EndWritingScope);
__InputTagHelper = CreateTagHelper<InputTagHelper>();
__tagHelperExecutionContext.Add(__InputTagHelper);
__InputTagHelper2 = CreateTagHelper<InputTagHelper2>();
__tagHelperExecutionContext.Add(__InputTagHelper2);
#line 23 "ComplexTagHelpers.cshtml"
__InputTagHelper2.Checked = @object;
#line default
#line hidden
__tagHelperExecutionContext.AddTagHelperAttribute("checked", __InputTagHelper2.Checked);
__tagHelperExecutionContext.Output = __tagHelperRunner.RunAsync(__tagHelperExecutionContext).Result;
WriteLiteral(__tagHelperExecutionContext.Output.GenerateStartTag());
WriteLiteral(__tagHelperExecutionContext.Output.GeneratePreContent());
if (__tagHelperExecutionContext.Output.ContentSet)
{
WriteLiteral(__tagHelperExecutionContext.Output.GenerateContent());
}
else if (__tagHelperExecutionContext.ChildContentRetrieved)
{
WriteLiteral(__tagHelperExecutionContext.GetChildContentAsync().Result);
}
else
{
__tagHelperExecutionContext.ExecuteChildContentAsync().Wait();
}
WriteLiteral(__tagHelperExecutionContext.Output.GeneratePostContent());
WriteLiteral(__tagHelperExecutionContext.Output.GenerateEndTag());
__tagHelperExecutionContext = __tagHelperScopeManager.End();
WriteLiteral("\r\n ");
}
, StartWritingScope, EndWritingScope);
__PTagHelper = CreateTagHelper<PTagHelper>();
__tagHelperExecutionContext.Add(__PTagHelper);
#line 21 "ComplexTagHelpers.cshtml"
__PTagHelper.Age = DateTimeOffset.Now.Year - 1970;
#line default
#line hidden
__tagHelperExecutionContext.AddTagHelperAttribute("age", __PTagHelper.Age);
__tagHelperExecutionContext.Output = __tagHelperRunner.RunAsync(__tagHelperExecutionContext).Result;
WriteLiteral(__tagHelperExecutionContext.Output.GenerateStartTag());
WriteLiteral(__tagHelperExecutionContext.Output.GeneratePreContent());
if (__tagHelperExecutionContext.Output.ContentSet)
{
WriteLiteral(__tagHelperExecutionContext.Output.GenerateContent());
}
else if (__tagHelperExecutionContext.ChildContentRetrieved)
{
WriteLiteral(__tagHelperExecutionContext.GetChildContentAsync().Result);
}
else
{
__tagHelperExecutionContext.ExecuteChildContentAsync().Wait();
}
WriteLiteral(__tagHelperExecutionContext.Output.GeneratePostContent());
WriteLiteral(__tagHelperExecutionContext.Output.GenerateEndTag());
__tagHelperExecutionContext = __tagHelperScopeManager.End();
Instrumentation.BeginContext(813, 10, true);
WriteLiteral("\r\n ");
Instrumentation.EndContext();
__tagHelperExecutionContext = __tagHelperScopeManager.Begin("p", "test", async() => {
WriteLiteral("\r\n ");
__tagHelperExecutionContext = __tagHelperScopeManager.Begin("input", "test", async() => {
}
, StartWritingScope, EndWritingScope);
__InputTagHelper = CreateTagHelper<InputTagHelper>();
__tagHelperExecutionContext.Add(__InputTagHelper);
__InputTagHelper2 = CreateTagHelper<InputTagHelper2>();
__tagHelperExecutionContext.Add(__InputTagHelper2);
#line 26 "ComplexTagHelpers.cshtml"
__InputTagHelper2.Checked = DateTimeOffset.Now.Year > 2014;
#line default
#line hidden
__tagHelperExecutionContext.AddTagHelperAttribute("checked", __InputTagHelper2.Checked);
__tagHelperExecutionContext.Output = __tagHelperRunner.RunAsync(__tagHelperExecutionContext).Result;
WriteLiteral(__tagHelperExecutionContext.Output.GenerateStartTag());
WriteLiteral(__tagHelperExecutionContext.Output.GeneratePreContent());
if (__tagHelperExecutionContext.Output.ContentSet)
{
WriteLiteral(__tagHelperExecutionContext.Output.GenerateContent());
}
else if (__tagHelperExecutionContext.ChildContentRetrieved)
{
WriteLiteral(__tagHelperExecutionContext.GetChildContentAsync().Result);
}
else
{
__tagHelperExecutionContext.ExecuteChildContentAsync().Wait();
}
WriteLiteral(__tagHelperExecutionContext.Output.GeneratePostContent());
WriteLiteral(__tagHelperExecutionContext.Output.GenerateEndTag());
__tagHelperExecutionContext = __tagHelperScopeManager.End();
WriteLiteral("\r\n ");
}
, StartWritingScope, EndWritingScope);
__PTagHelper = CreateTagHelper<PTagHelper>();
__tagHelperExecutionContext.Add(__PTagHelper);
#line 25 "ComplexTagHelpers.cshtml"
__PTagHelper.Age = -1970 + DateTimeOffset.Now.Year;
#line default
#line hidden
__tagHelperExecutionContext.AddTagHelperAttribute("age", __PTagHelper.Age);
__tagHelperExecutionContext.Output = __tagHelperRunner.RunAsync(__tagHelperExecutionContext).Result;
WriteLiteral(__tagHelperExecutionContext.Output.GenerateStartTag());
WriteLiteral(__tagHelperExecutionContext.Output.GeneratePreContent());
if (__tagHelperExecutionContext.Output.ContentSet)
{
WriteLiteral(__tagHelperExecutionContext.Output.GenerateContent());
}
else if (__tagHelperExecutionContext.ChildContentRetrieved)
{
WriteLiteral(__tagHelperExecutionContext.GetChildContentAsync().Result);
}
else
{
__tagHelperExecutionContext.ExecuteChildContentAsync().Wait();
}
WriteLiteral(__tagHelperExecutionContext.Output.GeneratePostContent());
WriteLiteral(__tagHelperExecutionContext.Output.GenerateEndTag());
__tagHelperExecutionContext = __tagHelperScopeManager.End();
Instrumentation.BeginContext(946, 10, true);
WriteLiteral("\r\n ");
Instrumentation.EndContext();
__tagHelperExecutionContext = __tagHelperScopeManager.Begin("p", "test", async() => {
WriteLiteral("\r\n ");
__tagHelperExecutionContext = __tagHelperScopeManager.Begin("input", "test", async() => {
}
, StartWritingScope, EndWritingScope);
__InputTagHelper = CreateTagHelper<InputTagHelper>();
__tagHelperExecutionContext.Add(__InputTagHelper);
__InputTagHelper2 = CreateTagHelper<InputTagHelper2>();
__tagHelperExecutionContext.Add(__InputTagHelper2);
#line 29 "ComplexTagHelpers.cshtml"
__InputTagHelper2.Checked = DateTimeOffset.Now.Year > 2014;
#line default
#line hidden
__tagHelperExecutionContext.AddTagHelperAttribute("checked", __InputTagHelper2.Checked);
__tagHelperExecutionContext.Output = __tagHelperRunner.RunAsync(__tagHelperExecutionContext).Result;
WriteLiteral(__tagHelperExecutionContext.Output.GenerateStartTag());
WriteLiteral(__tagHelperExecutionContext.Output.GeneratePreContent());
if (__tagHelperExecutionContext.Output.ContentSet)
{
WriteLiteral(__tagHelperExecutionContext.Output.GenerateContent());
}
else if (__tagHelperExecutionContext.ChildContentRetrieved)
{
WriteLiteral(__tagHelperExecutionContext.GetChildContentAsync().Result);
}
else
{
__tagHelperExecutionContext.ExecuteChildContentAsync().Wait();
}
WriteLiteral(__tagHelperExecutionContext.Output.GeneratePostContent());
WriteLiteral(__tagHelperExecutionContext.Output.GenerateEndTag());
__tagHelperExecutionContext = __tagHelperScopeManager.End();
WriteLiteral("\r\n ");
}
, StartWritingScope, EndWritingScope);
__PTagHelper = CreateTagHelper<PTagHelper>();
__tagHelperExecutionContext.Add(__PTagHelper);
#line 28 "ComplexTagHelpers.cshtml"
__PTagHelper.Age = DateTimeOffset.Now.Year - 1970;
#line default
#line hidden
__tagHelperExecutionContext.AddTagHelperAttribute("age", __PTagHelper.Age);
__tagHelperExecutionContext.Output = __tagHelperRunner.RunAsync(__tagHelperExecutionContext).Result;
WriteLiteral(__tagHelperExecutionContext.Output.GenerateStartTag());
WriteLiteral(__tagHelperExecutionContext.Output.GeneratePreContent());
if (__tagHelperExecutionContext.Output.ContentSet)
{
WriteLiteral(__tagHelperExecutionContext.Output.GenerateContent());
}
else if (__tagHelperExecutionContext.ChildContentRetrieved)
{
WriteLiteral(__tagHelperExecutionContext.GetChildContentAsync().Result);
}
else
{
__tagHelperExecutionContext.ExecuteChildContentAsync().Wait();
}
WriteLiteral(__tagHelperExecutionContext.Output.GeneratePostContent());
WriteLiteral(__tagHelperExecutionContext.Output.GenerateEndTag());
__tagHelperExecutionContext = __tagHelperScopeManager.End();
Instrumentation.BeginContext(1074, 10, true);
WriteLiteral("\r\n ");
Instrumentation.EndContext();
__tagHelperExecutionContext = __tagHelperScopeManager.Begin("p", "test", async() => {
WriteLiteral("\r\n ");
__tagHelperExecutionContext = __tagHelperScopeManager.Begin("input", "test", async() => {
}
, StartWritingScope, EndWritingScope);
__InputTagHelper = CreateTagHelper<InputTagHelper>();
__tagHelperExecutionContext.Add(__InputTagHelper);
__InputTagHelper2 = CreateTagHelper<InputTagHelper2>();
__tagHelperExecutionContext.Add(__InputTagHelper2);
#line 32 "ComplexTagHelpers.cshtml"
__InputTagHelper2.Checked = DateTimeOffset.Now.Year > 2014 ;
#line default
#line hidden
__tagHelperExecutionContext.AddTagHelperAttribute("checked", __InputTagHelper2.Checked);
__tagHelperExecutionContext.Output = __tagHelperRunner.RunAsync(__tagHelperExecutionContext).Result;
WriteLiteral(__tagHelperExecutionContext.Output.GenerateStartTag());
WriteLiteral(__tagHelperExecutionContext.Output.GeneratePreContent());
if (__tagHelperExecutionContext.Output.ContentSet)
{
WriteLiteral(__tagHelperExecutionContext.Output.GenerateContent());
}
else if (__tagHelperExecutionContext.ChildContentRetrieved)
{
WriteLiteral(__tagHelperExecutionContext.GetChildContentAsync().Result);
}
else
{
__tagHelperExecutionContext.ExecuteChildContentAsync().Wait();
}
WriteLiteral(__tagHelperExecutionContext.Output.GeneratePostContent());
WriteLiteral(__tagHelperExecutionContext.Output.GenerateEndTag());
__tagHelperExecutionContext = __tagHelperScopeManager.End();
WriteLiteral("\r\n ");
}
, StartWritingScope, EndWritingScope);
__PTagHelper = CreateTagHelper<PTagHelper>();
__tagHelperExecutionContext.Add(__PTagHelper);
#line 31 "ComplexTagHelpers.cshtml"
__PTagHelper.Age = "My age is this long.".Length;
#line default
#line hidden
__tagHelperExecutionContext.AddTagHelperAttribute("age", __PTagHelper.Age);
__tagHelperExecutionContext.Output = __tagHelperRunner.RunAsync(__tagHelperExecutionContext).Result;
WriteLiteral(__tagHelperExecutionContext.Output.GenerateStartTag());
WriteLiteral(__tagHelperExecutionContext.Output.GeneratePreContent());
if (__tagHelperExecutionContext.Output.ContentSet)
{
WriteLiteral(__tagHelperExecutionContext.Output.GenerateContent());
}
else if (__tagHelperExecutionContext.ChildContentRetrieved)
{
WriteLiteral(__tagHelperExecutionContext.GetChildContentAsync().Result);
}
else
{
__tagHelperExecutionContext.ExecuteChildContentAsync().Wait();
}
WriteLiteral(__tagHelperExecutionContext.Output.GeneratePostContent());
WriteLiteral(__tagHelperExecutionContext.Output.GenerateEndTag());
__tagHelperExecutionContext = __tagHelperScopeManager.End();
Instrumentation.BeginContext(1217, 14, true);
WriteLiteral("\r\n </div>\r\n");
Instrumentation.EndContext();
#line 22 "ComplexTagHelpers.cshtml"
#line 35 "ComplexTagHelpers.cshtml"
}
#line default

View File

@ -1,45 +0,0 @@
namespace TestOutput
{
using Microsoft.AspNet.Razor.Runtime.TagHelpers;
using System;
using System.Threading.Tasks;
public class ContentBehaviorTagHelpers
{
private static object @__o;
private void @__RazorDesignTimeHelpers__()
{
#pragma warning disable 219
string __tagHelperDirectiveSyntaxHelper = null;
__tagHelperDirectiveSyntaxHelper =
#line 1 "ContentBehaviorTagHelpers.cshtml"
"something"
#line default
#line hidden
;
#pragma warning restore 219
}
#line hidden
private ModifyTagHelper __ModifyTagHelper = null;
private NoneTagHelper __NoneTagHelper = null;
private AppendTagHelper __AppendTagHelper = null;
private PrependTagHelper __PrependTagHelper = null;
private ReplaceTagHelper __ReplaceTagHelper = null;
#line hidden
public ContentBehaviorTagHelpers()
{
}
#pragma warning disable 1998
public override async Task ExecuteAsync()
{
__ModifyTagHelper = CreateTagHelper<ModifyTagHelper>();
__NoneTagHelper = CreateTagHelper<NoneTagHelper>();
__AppendTagHelper = CreateTagHelper<AppendTagHelper>();
__PrependTagHelper = CreateTagHelper<PrependTagHelper>();
__ReplaceTagHelper = CreateTagHelper<ReplaceTagHelper>();
}
#pragma warning restore 1998
}
}

View File

@ -1,83 +0,0 @@
#pragma checksum "ContentBehaviorTagHelpers.cshtml" "{ff1816ec-aa5e-4d10-87f7-6f4963833460}" "5aeeb0a2b5283b353efaff2cd2fb0c739020b899"
namespace TestOutput
{
using Microsoft.AspNet.Razor.Runtime.TagHelpers;
using System;
using System.Threading.Tasks;
public class ContentBehaviorTagHelpers
{
#line hidden
private System.IO.TextWriter __tagHelperStringValueBuffer = null;
private TagHelperExecutionContext __tagHelperExecutionContext = null;
private TagHelperRunner __tagHelperRunner = new TagHelperRunner();
private TagHelperScopeManager __tagHelperScopeManager = new TagHelperScopeManager();
private ModifyTagHelper __ModifyTagHelper = null;
private NoneTagHelper __NoneTagHelper = null;
private AppendTagHelper __AppendTagHelper = null;
private PrependTagHelper __PrependTagHelper = null;
private ReplaceTagHelper __ReplaceTagHelper = null;
#line hidden
public ContentBehaviorTagHelpers()
{
}
#pragma warning disable 1998
public override async Task ExecuteAsync()
{
Instrumentation.BeginContext(27, 2, true);
WriteLiteral("\r\n");
Instrumentation.EndContext();
__tagHelperExecutionContext = __tagHelperScopeManager.Begin("modify");
__ModifyTagHelper = CreateTagHelper<ModifyTagHelper>();
__tagHelperExecutionContext.Add(__ModifyTagHelper);
StartWritingScope();
WriteLiteral("\r\n ");
__tagHelperExecutionContext = __tagHelperScopeManager.Begin("none");
__NoneTagHelper = CreateTagHelper<NoneTagHelper>();
__tagHelperExecutionContext.Add(__NoneTagHelper);
__tagHelperExecutionContext.Output = __tagHelperRunner.RunAsync(__tagHelperExecutionContext).Result;
WriteLiteral(__tagHelperExecutionContext.Output.GenerateStartTag());
WriteLiteral("\r\n ");
__tagHelperExecutionContext = __tagHelperScopeManager.Begin("append");
__AppendTagHelper = CreateTagHelper<AppendTagHelper>();
__tagHelperExecutionContext.Add(__AppendTagHelper);
__tagHelperExecutionContext.Output = __tagHelperRunner.RunAsync(__tagHelperExecutionContext).Result;
WriteLiteral(__tagHelperExecutionContext.Output.GenerateStartTag());
WriteLiteral("\r\n ");
__tagHelperExecutionContext = __tagHelperScopeManager.Begin("prepend");
__PrependTagHelper = CreateTagHelper<PrependTagHelper>();
__tagHelperExecutionContext.Add(__PrependTagHelper);
__tagHelperExecutionContext.Output = __tagHelperRunner.RunAsync(__tagHelperExecutionContext).Result;
WriteLiteral(__tagHelperExecutionContext.Output.GenerateStartTag());
WriteLiteral(__tagHelperExecutionContext.Output.GenerateContent());
WriteLiteral("\r\n ");
__tagHelperExecutionContext = __tagHelperScopeManager.Begin("replace");
__ReplaceTagHelper = CreateTagHelper<ReplaceTagHelper>();
__tagHelperExecutionContext.Add(__ReplaceTagHelper);
__tagHelperExecutionContext.Output = __tagHelperRunner.RunAsync(__tagHelperExecutionContext).Result;
WriteLiteral(__tagHelperExecutionContext.Output.GenerateStartTag());
WriteLiteral(__tagHelperExecutionContext.Output.GenerateContent());
WriteLiteral(__tagHelperExecutionContext.Output.GenerateEndTag());
__tagHelperExecutionContext = __tagHelperScopeManager.End();
WriteLiteral("\r\n ");
WriteLiteral(__tagHelperExecutionContext.Output.GenerateEndTag());
__tagHelperExecutionContext = __tagHelperScopeManager.End();
WriteLiteral("\r\n ");
WriteLiteral(__tagHelperExecutionContext.Output.GenerateContent());
WriteLiteral(__tagHelperExecutionContext.Output.GenerateEndTag());
__tagHelperExecutionContext = __tagHelperScopeManager.End();
WriteLiteral("\r\n ");
WriteLiteral(__tagHelperExecutionContext.Output.GenerateEndTag());
__tagHelperExecutionContext = __tagHelperScopeManager.End();
WriteLiteral("\r\n");
__tagHelperStringValueBuffer = EndWritingScope();
__tagHelperExecutionContext.Output = __tagHelperRunner.RunAsync(__tagHelperExecutionContext, __tagHelperStringValueBuffer).Result;
WriteLiteral(__tagHelperExecutionContext.Output.GenerateStartTag());
WriteLiteral(__tagHelperExecutionContext.Output.GenerateContent());
WriteLiteral(__tagHelperExecutionContext.Output.GenerateEndTag());
__tagHelperExecutionContext = __tagHelperScopeManager.End();
}
#pragma warning restore 1998
}
}

View File

@ -31,7 +31,11 @@ namespace TestOutput
public override async Task ExecuteAsync()
{
__PTagHelper = CreateTagHelper<PTagHelper>();
__PTagHelper.Age = 1337;
#line 3 "SingleTagHelper.cshtml"
__PTagHelper.Age = 1337;
#line default
#line hidden
}
#pragma warning restore 1998
}

View File

@ -8,7 +8,9 @@ namespace TestOutput
public class SingleTagHelper
{
#line hidden
#pragma warning disable 0414
private System.IO.TextWriter __tagHelperStringValueBuffer = null;
#pragma warning restore 0414
private TagHelperExecutionContext __tagHelperExecutionContext = null;
private TagHelperRunner __tagHelperRunner = new TagHelperRunner();
private TagHelperScopeManager __tagHelperScopeManager = new TagHelperScopeManager();
@ -24,17 +26,35 @@ namespace TestOutput
Instrumentation.BeginContext(27, 2, true);
WriteLiteral("\r\n");
Instrumentation.EndContext();
__tagHelperExecutionContext = __tagHelperScopeManager.Begin("p");
__tagHelperExecutionContext = __tagHelperScopeManager.Begin("p", "test", async() => {
WriteLiteral("Body of Tag");
}
, StartWritingScope, EndWritingScope);
__PTagHelper = CreateTagHelper<PTagHelper>();
__tagHelperExecutionContext.Add(__PTagHelper);
__PTagHelper.Age = 1337;
#line 3 "SingleTagHelper.cshtml"
__PTagHelper.Age = 1337;
#line default
#line hidden
__tagHelperExecutionContext.AddTagHelperAttribute("age", __PTagHelper.Age);
__tagHelperExecutionContext.AddHtmlAttribute("class", "Hello World");
__tagHelperExecutionContext.Output = __tagHelperRunner.RunAsync(__tagHelperExecutionContext).Result;
WriteLiteral(__tagHelperExecutionContext.Output.GenerateStartTag());
Instrumentation.BeginContext(63, 11, true);
WriteLiteral("Body of Tag");
Instrumentation.EndContext();
WriteLiteral(__tagHelperExecutionContext.Output.GeneratePreContent());
if (__tagHelperExecutionContext.Output.ContentSet)
{
WriteLiteral(__tagHelperExecutionContext.Output.GenerateContent());
}
else if (__tagHelperExecutionContext.ChildContentRetrieved)
{
WriteLiteral(__tagHelperExecutionContext.GetChildContentAsync().Result);
}
else
{
__tagHelperExecutionContext.ExecuteChildContentAsync().Wait();
}
WriteLiteral(__tagHelperExecutionContext.Output.GeneratePostContent());
WriteLiteral(__tagHelperExecutionContext.Output.GenerateEndTag());
__tagHelperExecutionContext = __tagHelperScopeManager.End();
}

View File

@ -24,7 +24,40 @@ MyHelper(string val)
Instrumentation.BeginContext(62, 19, true);
WriteLiteralTo(__razor_helper_writer, " <div>\r\n ");
Instrumentation.EndContext();
__tagHelperExecutionContext = __tagHelperScopeManager.Begin("mytaghelper");
__tagHelperExecutionContext = __tagHelperScopeManager.Begin("mytaghelper", "test", async() => {
WriteLiteral("\r\n In None ContentBehavior.\r\n ");
__tagHelperExecutionContext = __tagHelperScopeManager.Begin("nestedtaghelper", "test", async() => {
WriteLiteral("Some buffered values with a value of ");
#line 8 "TagHelpersInHelper.cshtml"
Write(val);
#line default
#line hidden
}
, StartWritingScope, EndWritingScope);
__NestedTagHelper = CreateTagHelper<NestedTagHelper>();
__tagHelperExecutionContext.Add(__NestedTagHelper);
__tagHelperExecutionContext.Output = __tagHelperRunner.RunAsync(__tagHelperExecutionContext).Result;
WriteLiteral(__tagHelperExecutionContext.Output.GenerateStartTag());
WriteLiteral(__tagHelperExecutionContext.Output.GeneratePreContent());
if (__tagHelperExecutionContext.Output.ContentSet)
{
WriteLiteral(__tagHelperExecutionContext.Output.GenerateContent());
}
else if (__tagHelperExecutionContext.ChildContentRetrieved)
{
WriteLiteral(__tagHelperExecutionContext.GetChildContentAsync().Result);
}
else
{
__tagHelperExecutionContext.ExecuteChildContentAsync().Wait();
}
WriteLiteral(__tagHelperExecutionContext.Output.GeneratePostContent());
WriteLiteral(__tagHelperExecutionContext.Output.GenerateEndTag());
__tagHelperExecutionContext = __tagHelperScopeManager.End();
WriteLiteral("\r\n ");
}
, StartWritingScope, EndWritingScope);
__MyTagHelper = CreateTagHelper<MyTagHelper>();
__tagHelperExecutionContext.Add(__MyTagHelper);
StartWritingScope();
@ -48,28 +81,22 @@ Write(DateTime.Now);
__tagHelperExecutionContext.AddHtmlAttribute("unboundproperty", __tagHelperStringValueBuffer.ToString());
__tagHelperExecutionContext.Output = __tagHelperRunner.RunAsync(__tagHelperExecutionContext).Result;
WriteLiteralTo(__razor_helper_writer, __tagHelperExecutionContext.Output.GenerateStartTag());
Instrumentation.BeginContext(184, 52, true);
WriteLiteralTo(__razor_helper_writer, "\r\n In None ContentBehavior.\r\n ");
Instrumentation.EndContext();
__tagHelperExecutionContext = __tagHelperScopeManager.Begin("nestedtaghelper");
__NestedTagHelper = CreateTagHelper<NestedTagHelper>();
__tagHelperExecutionContext.Add(__NestedTagHelper);
StartWritingScope();
WriteLiteral("Some buffered values with a value of ");
#line 8 "TagHelpersInHelper.cshtml"
Write(val);
#line default
#line hidden
__tagHelperStringValueBuffer = EndWritingScope();
__tagHelperExecutionContext.Output = __tagHelperRunner.RunAsync(__tagHelperExecutionContext, __tagHelperStringValueBuffer).Result;
WriteLiteralTo(__razor_helper_writer, __tagHelperExecutionContext.Output.GenerateStartTag());
WriteLiteralTo(__razor_helper_writer, __tagHelperExecutionContext.Output.GenerateContent());
WriteLiteralTo(__razor_helper_writer, __tagHelperExecutionContext.Output.GenerateEndTag());
__tagHelperExecutionContext = __tagHelperScopeManager.End();
Instrumentation.BeginContext(312, 10, true);
WriteLiteralTo(__razor_helper_writer, "\r\n ");
Instrumentation.EndContext();
WriteLiteralTo(__razor_helper_writer, __tagHelperExecutionContext.Output.GeneratePreContent());
if (__tagHelperExecutionContext.Output.ContentSet)
{
WriteLiteralTo(__razor_helper_writer, __tagHelperExecutionContext.Output.GenerateContent());
}
else if (__tagHelperExecutionContext.ChildContentRetrieved)
{
WriteLiteralTo(__razor_helper_writer, __tagHelperExecutionContext.GetChildContentAsync().Result);
}
else
{
StartWritingScope(__razor_helper_writer);
__tagHelperExecutionContext.ExecuteChildContentAsync().Wait();
EndWritingScope();
}
WriteLiteralTo(__razor_helper_writer, __tagHelperExecutionContext.Output.GeneratePostContent());
WriteLiteralTo(__razor_helper_writer, __tagHelperExecutionContext.Output.GenerateEndTag());
__tagHelperExecutionContext = __tagHelperScopeManager.End();
Instrumentation.BeginContext(336, 14, true);
@ -89,7 +116,9 @@ Write(DateTime.Now);
#line hidden
#line hidden
#pragma warning disable 0414
private System.IO.TextWriter __tagHelperStringValueBuffer = null;
#pragma warning restore 0414
private TagHelperExecutionContext __tagHelperExecutionContext = null;
private TagHelperRunner __tagHelperRunner = new TagHelperRunner();
private TagHelperScopeManager __tagHelperScopeManager = new TagHelperScopeManager();
@ -106,23 +135,33 @@ Write(DateTime.Now);
Instrumentation.BeginContext(27, 2, true);
WriteLiteral("\r\n");
Instrumentation.EndContext();
__tagHelperExecutionContext = __tagHelperScopeManager.Begin("mytaghelper");
__MyTagHelper = CreateTagHelper<MyTagHelper>();
__tagHelperExecutionContext.Add(__MyTagHelper);
__tagHelperExecutionContext.Output = __tagHelperRunner.RunAsync(__tagHelperExecutionContext).Result;
WriteLiteral(__tagHelperExecutionContext.Output.GenerateStartTag());
Instrumentation.BeginContext(367, 9, false);
__tagHelperExecutionContext = __tagHelperScopeManager.Begin("mytaghelper", "test", async() => {
#line 12 "TagHelpersInHelper.cshtml"
Write(MyHelper(item => new Template((__razor_template_writer) => {
__tagHelperExecutionContext = __tagHelperScopeManager.Begin("nestedtaghelper");
__tagHelperExecutionContext = __tagHelperScopeManager.Begin("nestedtaghelper", "test", async() => {
WriteLiteral("Custom Value");
}
, StartWritingScope, EndWritingScope);
__NestedTagHelper = CreateTagHelper<NestedTagHelper>();
__tagHelperExecutionContext.Add(__NestedTagHelper);
StartWritingScope();
WriteLiteral("Custom Value");
__tagHelperStringValueBuffer = EndWritingScope();
__tagHelperExecutionContext.Output = __tagHelperRunner.RunAsync(__tagHelperExecutionContext, __tagHelperStringValueBuffer).Result;
__tagHelperExecutionContext.Output = __tagHelperRunner.RunAsync(__tagHelperExecutionContext).Result;
WriteLiteralTo(__razor_template_writer, __tagHelperExecutionContext.Output.GenerateStartTag());
WriteLiteralTo(__razor_template_writer, __tagHelperExecutionContext.Output.GenerateContent());
WriteLiteralTo(__razor_template_writer, __tagHelperExecutionContext.Output.GeneratePreContent());
if (__tagHelperExecutionContext.Output.ContentSet)
{
WriteLiteralTo(__razor_template_writer, __tagHelperExecutionContext.Output.GenerateContent());
}
else if (__tagHelperExecutionContext.ChildContentRetrieved)
{
WriteLiteralTo(__razor_template_writer, __tagHelperExecutionContext.GetChildContentAsync().Result);
}
else
{
StartWritingScope(__razor_template_writer);
__tagHelperExecutionContext.ExecuteChildContentAsync().Wait();
EndWritingScope();
}
WriteLiteralTo(__razor_template_writer, __tagHelperExecutionContext.Output.GeneratePostContent());
WriteLiteralTo(__razor_template_writer, __tagHelperExecutionContext.Output.GenerateEndTag());
__tagHelperExecutionContext = __tagHelperScopeManager.End();
}
@ -131,7 +170,26 @@ Write(MyHelper(item => new Template((__razor_template_writer) => {
#line default
#line hidden
Instrumentation.EndContext();
}
, StartWritingScope, EndWritingScope);
__MyTagHelper = CreateTagHelper<MyTagHelper>();
__tagHelperExecutionContext.Add(__MyTagHelper);
__tagHelperExecutionContext.Output = __tagHelperRunner.RunAsync(__tagHelperExecutionContext).Result;
WriteLiteral(__tagHelperExecutionContext.Output.GenerateStartTag());
WriteLiteral(__tagHelperExecutionContext.Output.GeneratePreContent());
if (__tagHelperExecutionContext.Output.ContentSet)
{
WriteLiteral(__tagHelperExecutionContext.Output.GenerateContent());
}
else if (__tagHelperExecutionContext.ChildContentRetrieved)
{
WriteLiteral(__tagHelperExecutionContext.GetChildContentAsync().Result);
}
else
{
__tagHelperExecutionContext.ExecuteChildContentAsync().Wait();
}
WriteLiteral(__tagHelperExecutionContext.Output.GeneratePostContent());
WriteLiteral(__tagHelperExecutionContext.Output.GenerateEndTag());
__tagHelperExecutionContext = __tagHelperScopeManager.End();
Instrumentation.BeginContext(439, 2, true);

View File

@ -7,7 +7,9 @@ namespace TestOutput
public class TagHelpersInSection
{
#line hidden
#pragma warning disable 0414
private System.IO.TextWriter __tagHelperStringValueBuffer = null;
#pragma warning restore 0414
private TagHelperExecutionContext __tagHelperExecutionContext = null;
private TagHelperRunner __tagHelperRunner = new TagHelperRunner();
private TagHelperScopeManager __tagHelperScopeManager = new TagHelperScopeManager();
@ -38,7 +40,40 @@ namespace TestOutput
Instrumentation.BeginContext(87, 21, true);
WriteLiteralTo(__razor_template_writer, "\r\n <div>\r\n ");
Instrumentation.EndContext();
__tagHelperExecutionContext = __tagHelperScopeManager.Begin("mytaghelper");
__tagHelperExecutionContext = __tagHelperScopeManager.Begin("mytaghelper", "test", async() => {
WriteLiteral("\r\n In None ContentBehavior.\r\n ");
__tagHelperExecutionContext = __tagHelperScopeManager.Begin("nestedtaghelper", "test", async() => {
WriteLiteral("Some buffered values with ");
#line 11 "TagHelpersInSection.cshtml"
Write(code);
#line default
#line hidden
}
, StartWritingScope, EndWritingScope);
__NestedTagHelper = CreateTagHelper<NestedTagHelper>();
__tagHelperExecutionContext.Add(__NestedTagHelper);
__tagHelperExecutionContext.Output = __tagHelperRunner.RunAsync(__tagHelperExecutionContext).Result;
WriteLiteral(__tagHelperExecutionContext.Output.GenerateStartTag());
WriteLiteral(__tagHelperExecutionContext.Output.GeneratePreContent());
if (__tagHelperExecutionContext.Output.ContentSet)
{
WriteLiteral(__tagHelperExecutionContext.Output.GenerateContent());
}
else if (__tagHelperExecutionContext.ChildContentRetrieved)
{
WriteLiteral(__tagHelperExecutionContext.GetChildContentAsync().Result);
}
else
{
__tagHelperExecutionContext.ExecuteChildContentAsync().Wait();
}
WriteLiteral(__tagHelperExecutionContext.Output.GeneratePostContent());
WriteLiteral(__tagHelperExecutionContext.Output.GenerateEndTag());
__tagHelperExecutionContext = __tagHelperScopeManager.End();
WriteLiteral("\r\n ");
}
, StartWritingScope, EndWritingScope);
__MyTagHelper = CreateTagHelper<MyTagHelper>();
__tagHelperExecutionContext.Add(__MyTagHelper);
StartWritingScope();
@ -62,28 +97,22 @@ Write(DateTime.Now);
__tagHelperExecutionContext.AddHtmlAttribute("unboundproperty", __tagHelperStringValueBuffer.ToString());
__tagHelperExecutionContext.Output = __tagHelperRunner.RunAsync(__tagHelperExecutionContext).Result;
WriteLiteralTo(__razor_template_writer, __tagHelperExecutionContext.Output.GenerateStartTag());
Instrumentation.BeginContext(211, 52, true);
WriteLiteralTo(__razor_template_writer, "\r\n In None ContentBehavior.\r\n ");
Instrumentation.EndContext();
__tagHelperExecutionContext = __tagHelperScopeManager.Begin("nestedtaghelper");
__NestedTagHelper = CreateTagHelper<NestedTagHelper>();
__tagHelperExecutionContext.Add(__NestedTagHelper);
StartWritingScope();
WriteLiteral("Some buffered values with ");
#line 11 "TagHelpersInSection.cshtml"
Write(code);
#line default
#line hidden
__tagHelperStringValueBuffer = EndWritingScope();
__tagHelperExecutionContext.Output = __tagHelperRunner.RunAsync(__tagHelperExecutionContext, __tagHelperStringValueBuffer).Result;
WriteLiteralTo(__razor_template_writer, __tagHelperExecutionContext.Output.GenerateStartTag());
WriteLiteralTo(__razor_template_writer, __tagHelperExecutionContext.Output.GenerateContent());
WriteLiteralTo(__razor_template_writer, __tagHelperExecutionContext.Output.GenerateEndTag());
__tagHelperExecutionContext = __tagHelperScopeManager.End();
Instrumentation.BeginContext(329, 10, true);
WriteLiteralTo(__razor_template_writer, "\r\n ");
Instrumentation.EndContext();
WriteLiteralTo(__razor_template_writer, __tagHelperExecutionContext.Output.GeneratePreContent());
if (__tagHelperExecutionContext.Output.ContentSet)
{
WriteLiteralTo(__razor_template_writer, __tagHelperExecutionContext.Output.GenerateContent());
}
else if (__tagHelperExecutionContext.ChildContentRetrieved)
{
WriteLiteralTo(__razor_template_writer, __tagHelperExecutionContext.GetChildContentAsync().Result);
}
else
{
StartWritingScope(__razor_template_writer);
__tagHelperExecutionContext.ExecuteChildContentAsync().Wait();
EndWritingScope();
}
WriteLiteralTo(__razor_template_writer, __tagHelperExecutionContext.Output.GeneratePostContent());
WriteLiteralTo(__razor_template_writer, __tagHelperExecutionContext.Output.GenerateEndTag());
__tagHelperExecutionContext = __tagHelperScopeManager.End();
Instrumentation.BeginContext(353, 14, true);

View File

@ -18,5 +18,18 @@
<input type='@if(true) { <text>checkbox</text> } else { <text>anything</text> }' />
}
</p>
<p age="@DateTimeOffset.Now.Year - 1970">
@{ var @object = false;}
<input checked="@(@object)" />
</p>
<p age="-1970 + @DateTimeOffset.Now.Year">
<input checked="@(DateTimeOffset.Now.Year > 2014)" />
</p>
<p age="DateTimeOffset.Now.Year - 1970">
<input checked="DateTimeOffset.Now.Year > 2014" />
</p>
<p age="@("My age is this long.".Length)">
<input checked=" @( DateTimeOffset.Now.Year ) > 2014 " />
</p>
</div>
}

View File

@ -1,11 +0,0 @@
@addtaghelper "something"
<modify>
<none>
<append>
<prepend>
<replace>This should not be in the output</replace>
</prepend>
</append>
</none>
</modify>

View File

@ -5,17 +5,21 @@
"Moq": "4.2.1312.1622",
"Microsoft.AspNet.Razor": "4.0.0-*",
"Microsoft.AspNet.Testing": "1.0.0-*",
"Xunit.KRunner": "1.0.0-*"
"xunit.runner.kre": "1.0.0-*"
},
"commands": {
"test": "Xunit.KRunner"
"test": "xunit.runner.kre"
},
"frameworks": {
"aspnet50": { },
"aspnetcore50": {
"dependencies": {
"System.Diagnostics.TraceSource": "4.0.0-beta-*"
"System.Diagnostics.TraceSource": "4.0.0-beta-*",
"System.Reflection.TypeExtensions": "4.0.0-beta-*"
}
}
},
"compilationOptions": {
"define": [ "__RemoveThisBitTo__GENERATE_BASELINES" ]
}
}